651 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
		
		
			
		
	
	
			651 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
|   | /******************************************************************************/ | ||
|  | /* | ||
|  |   Project   - MudBun | ||
|  |   Publisher - Long Bunny Labs | ||
|  |               http://LongBunnyLabs.com | ||
|  |   Author    - Ming-Lun "Allen" Chou | ||
|  |               http://AllenChou.net | ||
|  | */ | ||
|  | /******************************************************************************/ | ||
|  | 
 | ||
|  | #pragma kernel generate_dual_quads | ||
|  | #pragma kernel generate_dual_quads_2d | ||
|  | #pragma kernel update_dual_meshing_indirect_dispatch_args | ||
|  | #pragma kernel dual_meshing_flat_mesh_normal | ||
|  | #pragma kernel dual_meshing_smooth_mesh_normal | ||
|  | #pragma kernel dual_meshing_flat_mesh_normal_2d | ||
|  | #pragma kernel dual_meshing_smooth_mesh_normal_2d | ||
|  | #pragma kernel dual_meshing_update_auto_smooth | ||
|  | #pragma kernel dual_meshing_compute_auto_smooth | ||
|  | #pragma kernel dual_meshing_udpate_auto_smooth_SmoothCorner_indirect_dispatch_args | ||
|  | #pragma kernel dual_meshing_auto_smooth_smooth_corner | ||
|  | #pragma kernel update_dual_meshing_splats_indirect_args | ||
|  | #pragma kernel convert_dual_meshing_splats | ||
|  | 
 | ||
|  | #include "../../Shader/ComputeCommon.cginc" | ||
|  | 
 | ||
|  | #include "../../Shader/AutoSmoothFuncs.cginc" | ||
|  | #include "../../Shader/BrushFuncs.cginc" | ||
|  | #include "../../Shader/DualMeshingFuncs.cginc" | ||
|  | #include "../../Shader/GenPointDefs.cginc" | ||
|  | #include "../../Shader/IndirectArgsDefs.cginc" | ||
|  | #include "../../Shader/Math/Codec.cginc" | ||
|  | #include "../../Shader/Math/MathConst.cginc" | ||
|  | #include "../../Shader/MeshingModeDefs.cginc" | ||
|  | #include "../../Shader/NormalFuncs.cginc" | ||
|  | #include "../../Shader/RenderModeDefs.cginc" | ||
|  | 
 | ||
|  | [numthreads(kThreadGroupSize, 1, 1)] | ||
|  | void generate_dual_quads(int3 id : SV_DispatchThreadID) | ||
|  | { | ||
|  | #if defined(MUDBUN_DISABLE_DUAL_MESHING_ALL) || defined(MUDBUN_FAST_ITERATION) | ||
|  |   return; | ||
|  | #endif | ||
|  | 
 | ||
|  |   uint iNode = uint(id.x); | ||
|  |   if (iNode >= uint(aNumNodesAllocated[currentNodeDepth + 1])) | ||
|  |     return; | ||
|  | 
 | ||
|  |   for (int i = 1; i <= currentNodeDepth; ++i) | ||
|  |     iNode += aNumNodesAllocated[i]; | ||
|  |   if (iNode >= nodePoolSize) | ||
|  |     return; | ||
|  | 
 | ||
|  |   float3 nodeCenter = nodePool[iNode].center; | ||
|  |   float halfNodeSize = 0.5f * voxelSize; | ||
|  |   float halfNodeSizeInv = 1.0f / halfNodeSize; | ||
|  |   float3 minCorner = nodeCenter - halfNodeSize; | ||
|  |   int iBrushMask = get_brush_mask_index(iNode); | ||
|  | 
 | ||
|  |   float3 aAxis0[3] = { kUnitX, kUnitY, kUnitZ }; | ||
|  |   float3 aAxis1[3] = { kUnitY, kUnitZ, kUnitX }; | ||
|  |   float3 aAxis2[3] = { kUnitZ, kUnitX, kUnitY }; | ||
|  |   float3 aCornerOffset[3] = | ||
|  |   { | ||
|  |     float3(voxelSize, 0.0f, 0.0f), | ||
|  |     float3(0.0f, voxelSize, 0.0f), | ||
|  |     float3(0.0f, 0.0f, voxelSize), | ||
|  |   }; | ||
|  | 
 | ||
|  |   SdfBrushMaterial mat = init_brush_material(); | ||
|  |   SdfBrushMaterial matTemp = init_brush_material(); | ||
|  | 
 | ||
|  |   float3 aSamplePoint[8] = | ||
|  |   { | ||
|  |     nodeCenter,  | ||
|  |     minCorner,  | ||
|  |     minCorner + aCornerOffset[0],  | ||
|  |     minCorner + aCornerOffset[1],  | ||
|  |     minCorner + aCornerOffset[2],  | ||
|  |     minCorner + aCornerOffset[0] + 1e-2f * aAxis0[0],  | ||
|  |     minCorner + aCornerOffset[1] + 1e-2f * aAxis0[1],  | ||
|  |     minCorner + aCornerOffset[2] + 1e-2f * aAxis0[2],  | ||
|  |   }; | ||
|  |   float aRes[8]; | ||
|  |   [loop] for (int iSample = 0; iSample < 8; ++iSample) | ||
|  |   { | ||
|  |     if (iSample < 5 | ||
|  |         || aRes[1] == 0.0f      // min corner res | ||
|  |         || aRes[clamp(iSample - 3, 0, 7)] == 0.0f) // axis corner res) | ||
|  |     { | ||
|  |       // doubles generated assemblies, but gets better performance in return | ||
|  |       aRes[iSample] = sdf_masked_brushes(aSamplePoint[iSample], iBrushMask, matTemp); | ||
|  |       if (iSample == 0) | ||
|  |         mat = matTemp; | ||
|  |     } | ||
|  |   } | ||
|  | 
 | ||
|  |   bool emitSplats = | ||
|  |     meshingMode == kMeshingModeDualQuads | ||
|  |     && (renderMode == kRenderModeCircleSplats || renderMode == kRenderModeQuadSplats); | ||
|  | 
 | ||
|  |   if (emitSplats && renderMode == kRenderModeQuadSplats) | ||
|  |       mat.metallicSmoothnessSizeTightness.z *= 0.70711f; | ||
|  | 
 | ||
|  |   float centerRes = aRes[0]; | ||
|  |   SdfBrushMaterialCompressed packedMat = pack_material(mat); | ||
|  | 
 | ||
|  |   float minCornerRes = aRes[1]; | ||
|  | 
 | ||
|  |   int iGenPoint = 0; | ||
|  | 
 | ||
|  |   float aCornerRes[3] = { aRes[2], aRes[3], aRes[4] }; | ||
|  |   float aMinCornerDeltaRes[3] = { aRes[5], aRes[6], aRes[7] }; | ||
|  |   | ||
|  |   [loop] for (int iAxis = 0; iAxis < 3; ++iAxis) | ||
|  |   { | ||
|  |     float3 axis = aAxis0[iAxis]; | ||
|  |     float3 corner = minCorner + aCornerOffset[iAxis]; | ||
|  |     float cornerRes = aCornerRes[iAxis]; | ||
|  |     float s = sign(minCornerRes * cornerRes); | ||
|  |     if (s <= 0.0f) | ||
|  |     { | ||
|  |       // quad center & extent vectors | ||
|  |       float3 c = 0.5f * (minCorner + corner); | ||
|  |       float3 h1 = halfNodeSize * aAxis1[iAxis]; | ||
|  |       float3 h2 = halfNodeSize * (minCornerRes <= 0.0f ? 1 : -1) * aAxis2[iAxis]; | ||
|  |       float packedNorm = pack_normal((minCornerRes <= 0.0f ? 1 : -1) * axis * (invertNormals ? -1.0f : 1.0f)); | ||
|  |       if (s == 0.0f) | ||
|  |       { | ||
|  |         float nRes = aMinCornerDeltaRes[iAxis]; | ||
|  |         packedNorm = pack_normal((dot(nRes - minCornerRes, axis) > 0.0f ? axis : -axis) * (invertNormals ? -1.0f : 1.0f)); | ||
|  |       } | ||
|  | 
 | ||
|  |       if (!emitSplats) | ||
|  |       { | ||
|  |         // regular dual quads | ||
|  |         InterlockedAdd(indirectDrawArgs[0], 6, iGenPoint); | ||
|  |         float3 aQuadVertOffset[2][6] =  | ||
|  |         { | ||
|  |           { - h1 - h2, + h1 - h2, + h1 + h2, - h1 - h2, + h1 + h2, - h1 + h2, },  | ||
|  |           { + h1 - h2, + h1 + h2, - h1 + h2, + h1 - h2, - h1 + h2, - h1 - h2, },  | ||
|  |         }; | ||
|  |         float3 qCenter = round((nodeCenter - 0.5f * voxelSize) / voxelSize); | ||
|  |         int iaQuadVertOffset = 0;//(uint(int(qCenter.x + qCenter.y + qCenter.z) + 0x80000000) % 2 == 0) ? 0 : 1; | ||
|  |         for (int iVert = 0; iVert < 6; ++iVert, ++iGenPoint) | ||
|  |         { | ||
|  |           float3 pos = c + aQuadVertOffset[iaQuadVertOffset][iVert]; | ||
|  |           pos = round(pos * halfNodeSizeInv) * halfNodeSize; // quantize vertices to prevent seams | ||
|  |           aGenPoint[iGenPoint].posNorm = float4(pos, packedNorm); | ||
|  |           aGenPoint[iGenPoint].iBrushMask = iBrushMask; | ||
|  |           aGenPoint[iGenPoint].material = packedMat; | ||
|  |           aGenPoint[iGenPoint].vertId = auto_smooth_vert_data_id(pos); | ||
|  |           aGenPoint[iGenPoint].sdfValue = surfaceShift; | ||
|  |         } | ||
|  |       } | ||
|  |       else | ||
|  |       { | ||
|  |         // splats | ||
|  |         int iVertBase; | ||
|  |         switch (renderMode) | ||
|  |         { | ||
|  |         case kRenderModeCircleSplats: | ||
|  |           InterlockedAdd(indirectDrawArgs[0], 3, iVertBase); | ||
|  |           iGenPoint = uint(iVertBase) / 3; | ||
|  |           break; | ||
|  |         case kRenderModeQuadSplats: | ||
|  |           InterlockedAdd(indirectDrawArgs[0], 6, iVertBase); | ||
|  |           iGenPoint = uint(iVertBase) / 6; | ||
|  |           break; | ||
|  |         } | ||
|  |         aGenPoint[iGenPoint].posNorm = float4(c, packedNorm); | ||
|  |         aGenPoint[iGenPoint].iBrushMask = iBrushMask; | ||
|  |         aGenPoint[iGenPoint].material = packedMat; | ||
|  |         aGenPoint[iGenPoint].sdfValue = surfaceShift; | ||
|  |       } | ||
|  |     } | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | [numthreads(kThreadGroupSize, 1, 1)] | ||
|  | void generate_dual_quads_2d(int3 id : SV_DispatchThreadID) | ||
|  | { | ||
|  | #if defined(MUDBUN_DISABLE_DUAL_MESHING_ALL) || defined(MUDBUN_FAST_ITERATION) | ||
|  |   return; | ||
|  | #endif | ||
|  | 
 | ||
|  |   uint iNode = uint(id.x); | ||
|  |   if (iNode >= uint(aNumNodesAllocated[currentNodeDepth + 1])) | ||
|  |     return; | ||
|  | 
 | ||
|  |   for (int i = 1; i <= currentNodeDepth; ++i) | ||
|  |     iNode += aNumNodesAllocated[i]; | ||
|  |   if (iNode >= nodePoolSize) | ||
|  |     return; | ||
|  | 
 | ||
|  |   float3 nodeCenter = nodePool[iNode].center; | ||
|  |   float halfNodeSize = 0.5f * voxelSize; | ||
|  |   int iBrushMask = get_brush_mask_index(iNode); | ||
|  | 
 | ||
|  |   SdfBrushMaterial mat = init_brush_material(); | ||
|  |   float d = sdf_masked_brushes(nodeCenter, iBrushMask, mat); | ||
|  |   if (d > 0.0f) | ||
|  |     return; | ||
|  | 
 | ||
|  |   bool emitSplats = | ||
|  |     meshingMode == kMeshingModeDualQuads | ||
|  |     && (renderMode == kRenderModeCircleSplats || renderMode == kRenderModeQuadSplats); | ||
|  | 
 | ||
|  |   if (emitSplats && renderMode == kRenderModeQuadSplats) | ||
|  |       mat.metallicSmoothnessSizeTightness.z *= 0.70711f; | ||
|  | 
 | ||
|  |   SdfBrushMaterialCompressed packedMat = pack_material(mat); | ||
|  | 
 | ||
|  |   float3 n = float3(0.0f, 0.0f, -1.0f); | ||
|  |   float packedNorm = pack_normal(n); | ||
|  | 
 | ||
|  |   int iGenPoint = 0; | ||
|  |   { | ||
|  |     // quad center & extent vectors | ||
|  |     float3 h1 = float3(halfNodeSize, 0.0f, 0.0f); | ||
|  |     float3 h2 = float3(0.0f, halfNodeSize, 0.0f); | ||
|  | 
 | ||
|  |     if (!emitSplats) | ||
|  |     { | ||
|  |       // regular dual quads | ||
|  |       InterlockedAdd(indirectDrawArgs[0], 6, iGenPoint); | ||
|  |       float3 aQuadVertOffset[2][3] =  | ||
|  |       { | ||
|  |         { - h1 - h2, + h1 + h2, + h1 - h2 },  | ||
|  |         { - h1 - h2, - h1 + h2, + h1 + h2 },  | ||
|  |       }; | ||
|  |       for (int iTri = 0; iTri < 2; ++iTri) | ||
|  |       { | ||
|  |         for (int iVert = 0; iVert < 3; ++iVert, ++iGenPoint) | ||
|  |         { | ||
|  |           float3 pos = nodeCenter + aQuadVertOffset[iTri][iVert]; | ||
|  |           float cornerRes = sdf_masked_brushes(pos, iBrushMask, mat); | ||
|  |           if (renderMode == kRenderModeSmoothMesh) | ||
|  |           { | ||
|  |             packedMat = pack_material(mat); | ||
|  |           } | ||
|  |           aGenPoint[iGenPoint].posNorm = float4(pos, packedNorm); | ||
|  |           aGenPoint[iGenPoint].iBrushMask = iBrushMask; | ||
|  |           aGenPoint[iGenPoint].material = packedMat; | ||
|  |           aGenPoint[iGenPoint].sdfValue = cornerRes + surfaceShift; | ||
|  |         } | ||
|  |       } | ||
|  |     } | ||
|  |     else | ||
|  |     { | ||
|  |       // splats | ||
|  |       int iVertBase; | ||
|  |       switch (renderMode) | ||
|  |       { | ||
|  |       case kRenderModeCircleSplats: | ||
|  |         InterlockedAdd(indirectDrawArgs[0], 3, iVertBase); | ||
|  |         iGenPoint = uint(iVertBase) / 3; | ||
|  |         break; | ||
|  |       case kRenderModeQuadSplats: | ||
|  |         InterlockedAdd(indirectDrawArgs[0], 6, iVertBase); | ||
|  |         iGenPoint = uint(iVertBase) / 6; | ||
|  |         break; | ||
|  |       } | ||
|  |       aGenPoint[iGenPoint].posNorm = float4(nodeCenter, packedNorm); | ||
|  |       aGenPoint[iGenPoint].iBrushMask = iBrushMask; | ||
|  |       aGenPoint[iGenPoint].material = packedMat; | ||
|  |       aGenPoint[iGenPoint].sdfValue = d + surfaceShift; | ||
|  |     } | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | [numthreads(1, 1, 1)] | ||
|  | void update_dual_meshing_indirect_dispatch_args(int3 id : SV_DispatchThreadID) | ||
|  | { | ||
|  |   indirectDispatchArgs[0] = max(1, uint(indirectDrawArgs[0] + kThreadGroupSize - 1) / kThreadGroupSize); | ||
|  | } | ||
|  | 
 | ||
|  | [numthreads(kThreadGroupSize, 1, 1)] | ||
|  | void dual_meshing_flat_mesh_normal(int3 id : SV_DispatchThreadID) | ||
|  | { | ||
|  | #if defined(MUDBUN_DISABLE_DUAL_MESHING_FLAT_MESH) || defined(MUDBUN_FAST_ITERATION) | ||
|  |   return; | ||
|  | #endif | ||
|  | 
 | ||
|  |   if (id.x >= indirectDrawArgs[0]) | ||
|  |     return; | ||
|  | 
 | ||
|  |   uint iGenPoint = uint(id.x); | ||
|  |   uint iTriBase = iGenPoint - (iGenPoint % 3); | ||
|  | 
 | ||
|  |   float3 pos0 = aGenPoint[iTriBase    ].posNorm.xyz; | ||
|  |   float3 pos1 = aGenPoint[iTriBase + 1].posNorm.xyz; | ||
|  |   float3 pos2 = aGenPoint[iTriBase + 2].posNorm.xyz; | ||
|  | 
 | ||
|  |   float3 v01 = pos1 - pos0; | ||
|  |   float3 v02 = pos2 - pos0; | ||
|  |   float3 n = normalize_safe(cross(v01, v02), 0.0f); | ||
|  |   float pn = pack_normal(n * (invertNormals ? -1.0f : 1.0f)); | ||
|  | 
 | ||
|  |   aGenPoint[iGenPoint].posNorm.w = pn; | ||
|  | } | ||
|  | 
 | ||
|  | [numthreads(kThreadGroupSize, 1, 1)] | ||
|  | void dual_meshing_smooth_mesh_normal(int3 id : SV_DispatchThreadID) | ||
|  | { | ||
|  | #if defined(MUDBUN_DISABLE_DUAL_MESHING_SMOOTH_MESH) || defined(MUDBUN_FAST_ITERATION) | ||
|  |   return; | ||
|  | #endif | ||
|  | 
 | ||
|  |   if (id.x >= indirectDrawArgs[0]) | ||
|  |     return; | ||
|  | 
 | ||
|  |   uint iGenPoint = uint(id.x); | ||
|  |   float3 pos = aGenPoint[iGenPoint].posNorm.xyz; | ||
|  |   int iBrushMask = aGenPoint[iGenPoint].iBrushMask; | ||
|  | 
 | ||
|  |   SdfBrushMaterial mat; | ||
|  |   sdf_masked_brushes(pos, iBrushMask, mat); | ||
|  | 
 | ||
|  |   float3 n; | ||
|  |   SDF_NORMAL(n, pos, sdf_masked_brushes, iBrushMask, normalDifferentiationStep); | ||
|  | 
 | ||
|  |   aGenPoint[iGenPoint].posNorm.w = pack_normal(n * (invertNormals ? -1.0f : 1.0f)); | ||
|  |   aGenPoint[iGenPoint].material = pack_material(mat); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | [numthreads(kThreadGroupSize, 1, 1)] | ||
|  | void dual_meshing_flat_mesh_normal_2d(int3 id : SV_DispatchThreadID) | ||
|  | { | ||
|  | #if defined(MUDBUN_DISABLE_DUAL_MESHING_FLAT_MESH) || defined(MUDBUN_FAST_ITERATION) | ||
|  |   return; | ||
|  | #endif | ||
|  | 
 | ||
|  |   if (id.x >= indirectDrawArgs[0]) | ||
|  |     return; | ||
|  | 
 | ||
|  |   uint iGenPoint = uint(id.x); | ||
|  | 
 | ||
|  |   uint iTriBase = iGenPoint - (iGenPoint % 3); | ||
|  |   float3 pos0 = aGenPoint[iTriBase].posNorm.xyz; | ||
|  |   float3 pos1 = aGenPoint[iTriBase + 1].posNorm.xyz; | ||
|  |   float3 pos2 = aGenPoint[iTriBase + 2].posNorm.xyz; | ||
|  |   float3 pos = (pos0 + pos1 + pos2) * 0.333333333f; | ||
|  |   int iBrushMask = aGenPoint[iGenPoint].iBrushMask; | ||
|  |   float3 normal2d; | ||
|  |   SDF_NORMAL_2D(normal2d, pos, sdf_masked_brushes, iBrushMask, normalDifferentiationStep); | ||
|  |   SdfBrushMaterial mat; | ||
|  |   float d = sdf_masked_brushes(pos, iBrushMask, mat); | ||
|  |   float3 n = normal_2d_blend(normal2d, d); | ||
|  | 
 | ||
|  |   aGenPoint[iGenPoint].posNorm.w = pack_normal(n); | ||
|  |   aGenPoint[iGenPoint].norm2d = pack_normal(normal2d); | ||
|  | } | ||
|  | 
 | ||
|  | [numthreads(kThreadGroupSize, 1, 1)] | ||
|  | void dual_meshing_smooth_mesh_normal_2d(int3 id : SV_DispatchThreadID) | ||
|  | { | ||
|  | #if defined(MUDBUN_DISABLE_DUAL_MESHING_SMOOTH_MESH) || defined(MUDBUN_FAST_ITERATION) | ||
|  |   return; | ||
|  | #endif | ||
|  | 
 | ||
|  |   if (id.x >= indirectDrawArgs[0]) | ||
|  |     return; | ||
|  | 
 | ||
|  |   uint iGenPoint = uint(id.x); | ||
|  |   float3 pos = aGenPoint[iGenPoint].posNorm.xyz; | ||
|  |   int iBrushMask = aGenPoint[iGenPoint].iBrushMask; | ||
|  | 
 | ||
|  |   SdfBrushMaterial mat; | ||
|  |   float d = sdf_masked_brushes(pos, iBrushMask, mat); | ||
|  | 
 | ||
|  |   float3 norm2d; | ||
|  |   SDF_NORMAL_2D(norm2d, pos, sdf_masked_brushes, iBrushMask, normalDifferentiationStep); | ||
|  |   float3 n = normal_2d_blend(norm2d, d); | ||
|  | 
 | ||
|  |   aGenPoint[iGenPoint].posNorm.w = pack_normal(n); | ||
|  |   aGenPoint[iGenPoint].material = pack_material(mat); | ||
|  | } | ||
|  | 
 | ||
|  | [numthreads(kThreadGroupSize, 1, 1)] | ||
|  | void dual_meshing_update_auto_smooth(int3 id : SV_DispatchThreadID) | ||
|  | { | ||
|  | #if defined(MUDBUN_DISABLE_DUAL_MESHING_ALL) || defined(MUDBUN_FAST_ITERATION) | ||
|  |   return; | ||
|  | #endif | ||
|  | 
 | ||
|  |   if (id.x >= indirectDrawArgs[0]) | ||
|  |     return; | ||
|  | 
 | ||
|  |   uint iGenPoint = uint(id.x); | ||
|  |   uint iTriBase = iGenPoint - (iGenPoint % 3); | ||
|  | 
 | ||
|  |   float3 pos0 = aGenPoint[iTriBase].posNorm.xyz; | ||
|  |   float3 pos1 = aGenPoint[iTriBase + 1].posNorm.xyz; | ||
|  |   float3 pos2 = aGenPoint[iTriBase + 2].posNorm.xyz; | ||
|  | 
 | ||
|  |   float3 v01 = pos1 - pos0; | ||
|  |   float3 v02 = pos2 - pos0; | ||
|  |   float3 c = cross(v01, v02); | ||
|  |   float3 n = normalize_safe(c, 0.0f); | ||
|  |   float pn = pack_normal(n * (invertNormals ? -1.0f : 1.0f)); | ||
|  |   float area = length(c); | ||
|  | 
 | ||
|  |   aGenPoint[iGenPoint].posNorm.w = pn; | ||
|  |   update_auto_smooth_vert_data(aGenPoint[iGenPoint].vertId, pn, area); | ||
|  | } | ||
|  | 
 | ||
|  | [numthreads(kThreadGroupSize, 1, 1)] | ||
|  | void dual_meshing_compute_auto_smooth(int3 id : SV_DispatchThreadID) | ||
|  | { | ||
|  | #if defined(MUDBUN_DISABLE_DUAL_MESHING_ALL) || defined(MUDBUN_FAST_ITERATION) | ||
|  |   return; | ||
|  | #endif | ||
|  | 
 | ||
|  |   if (id.x >= indirectDrawArgs[0]) | ||
|  |     return; | ||
|  | 
 | ||
|  |   uint iGenPoint = uint(id.x); | ||
|  |   float3 pos = aGenPoint[iGenPoint].posNorm.xyz; | ||
|  |   int iBrushMask = aGenPoint[iGenPoint].iBrushMask; | ||
|  | 
 | ||
|  |   SdfBrushMaterial mat; | ||
|  |   sdf_masked_brushes(pos, iBrushMask, mat); | ||
|  | 
 | ||
|  |   float3 autoSmoothNormal = compute_auto_smooth_normal(aGenPoint[iGenPoint].vertId, unpack_normal(aGenPoint[iGenPoint].posNorm.w)); | ||
|  |   bool atSmoothEdge = false; | ||
|  |   if (enableSmoothCorner) | ||
|  |   { | ||
|  |     float3 blurredNormal; | ||
|  |     SDF_NORMAL(blurredNormal, aGenPoint[iGenPoint].posNorm.xyz, sdf_masked_brushes, iBrushMask, smoothCornerNormalBlur); | ||
|  |     atSmoothEdge = abs(angle_between(blurredNormal, autoSmoothNormal)) < 0.25f * autoSmoothMaxAngle; | ||
|  |   } | ||
|  | 
 | ||
|  |   aGenPoint[iGenPoint].posNorm.w = pack_normal(autoSmoothNormal); | ||
|  |   aGenPoint[iGenPoint].atSmoothEdge = int(atSmoothEdge); | ||
|  |   aGenPoint[iGenPoint].material = pack_material(mat); | ||
|  |   //aGenPoint[iGenPoint].material.color = pack_rgba(float4(n, 1.0f)); | ||
|  | } | ||
|  | 
 | ||
|  | [numthreads(1, 1, 1)] | ||
|  | void dual_meshing_udpate_auto_smooth_SmoothCorner_indirect_dispatch_args(int3 id : SV_DispatchThreadID) | ||
|  | { | ||
|  |   indirectDispatchArgs[0] = max(1, uint(uint(indirectDrawArgs[0]) / 3 + kThreadGroupSize - 1) / kThreadGroupSize); | ||
|  | } | ||
|  | 
 | ||
|  | [numthreads(kThreadGroupSize, 1, 1)] | ||
|  | void dual_meshing_auto_smooth_smooth_corner(int3 id : SV_DispatchThreadID) | ||
|  | { | ||
|  | #if defined(MUDBUN_DISABLE_DUAL_MESHING_ALL) || defined(MUDBUN_FAST_ITERATION) | ||
|  |   return; | ||
|  | #endif | ||
|  | 
 | ||
|  |   if (uint(id.x) >= uint(indirectDrawArgs[0]) / 3) | ||
|  |     return; | ||
|  | 
 | ||
|  |   uint iTriBase = uint(id.x) * 3; | ||
|  |   bool smooth0 = (aGenPoint[iTriBase + 0].atSmoothEdge != 0); | ||
|  |   bool smooth1 = (aGenPoint[iTriBase + 1].atSmoothEdge != 0); | ||
|  |   bool smooth2 = (aGenPoint[iTriBase + 2].atSmoothEdge != 0); | ||
|  |   if (smooth0 && smooth1 && smooth2) | ||
|  |     return; | ||
|  | 
 | ||
|  |   int iBrushMask = aGenPoint[iTriBase].iBrushMask; | ||
|  | 
 | ||
|  |   uint iTri0 = iTriBase; | ||
|  |   uint iTri1 = iTriBase + 1; | ||
|  |   uint iTri2 = iTriBase + 2; | ||
|  | 
 | ||
|  |   GenPoint gpCopy = aGenPoint[iTri0]; | ||
|  |   float3 p0 = aGenPoint[iTri0].posNorm.xyz; | ||
|  |   float3 p1 = aGenPoint[iTri1].posNorm.xyz; | ||
|  |   float3 p2 = aGenPoint[iTri2].posNorm.xyz; | ||
|  |   float3 n0 = unpack_normal(aGenPoint[iTri0].posNorm.w); | ||
|  |   float3 n1 = unpack_normal(aGenPoint[iTri1].posNorm.w); | ||
|  |   float3 n2 = unpack_normal(aGenPoint[iTri2].posNorm.w); | ||
|  |   float4 c0 = unpack_rgba(aGenPoint[iTri0].material.color); | ||
|  |   float4 c1 = unpack_rgba(aGenPoint[iTri1].material.color); | ||
|  |   float4 c2 = unpack_rgba(aGenPoint[iTri2].material.color); | ||
|  |   float4 e0 = unpack_rgba(aGenPoint[iTri0].material.emissionTightness); | ||
|  |   float4 e1 = unpack_rgba(aGenPoint[iTri1].material.emissionTightness); | ||
|  |   float4 e2 = unpack_rgba(aGenPoint[iTri2].material.emissionTightness); | ||
|  |   float2 m0 = unpack_saturated(aGenPoint[iTri0].material.metallicSmoothness); | ||
|  |   float2 m1 = unpack_saturated(aGenPoint[iTri1].material.metallicSmoothness); | ||
|  |   float2 m2 = unpack_saturated(aGenPoint[iTri2].material.metallicSmoothness); | ||
|  |   float3 p01 = p1 - p0; | ||
|  |   float3 p02 = p2 - p0; | ||
|  |   float3 p12 = p2 - p1; | ||
|  |   float3 n01 = n1 - n0; | ||
|  |   float3 n02 = n2 - n0; | ||
|  |   float3 n12 = n2 - n1; | ||
|  |   float4 c01 = c1 - c0; | ||
|  |   float4 c02 = c2 - c0; | ||
|  |   float4 c12 = c2 - c1; | ||
|  |   float4 e01 = e1 - e0; | ||
|  |   float4 e02 = e2 - e0; | ||
|  |   float4 e12 = e2 - e1; | ||
|  |   float2 m01 = m1 - m0; | ||
|  |   float2 m02 = m2 - m0; | ||
|  |   float2 m12 = m2 - m1; | ||
|  | 
 | ||
|  |   int n = smoothCornerSubdivision; | ||
|  |   float dt = 1.0f / n; | ||
|  |   float3 dtp02 = dt * p02; | ||
|  |   float3 dtp12 = dt * p12; | ||
|  |   float3 dtn02 = dt * n02; | ||
|  |   float3 dtn12 = dt * n12; | ||
|  |   float4 dtc02 = dt * c02; | ||
|  |   float4 dtc12 = dt * c12; | ||
|  |   float4 dte02 = dt * e02; | ||
|  |   float4 dte12 = dt * e12; | ||
|  |   float2 dtm02 = dt * m02; | ||
|  |   float2 dtm12 = dt * m12; | ||
|  |   [loop] for (int i = 0; i < n; ++i) | ||
|  |   { | ||
|  |     int iNewTriBase = iTriBase; | ||
|  |     float3 aVert[3]; | ||
|  |     float3 aNorm[3]; | ||
|  |     float4 aC[3]; | ||
|  |     float4 aE[3]; | ||
|  |     float2 aM[3]; | ||
|  |     float idt = float(i) / n; | ||
|  |     aVert[0] = p0 + idt * p01; | ||
|  |     aVert[1] = aVert[0] + dt * p01; | ||
|  |     aVert[2] = aVert[0] + dt * p02; | ||
|  |     aNorm[0] = n0 + idt * n01; | ||
|  |     aNorm[1] = aNorm[0] + dt * n01; | ||
|  |     aNorm[2] = aNorm[0] + dt * n02; | ||
|  |     aC[0] = c0 + idt * c01; | ||
|  |     aC[1] = aC[0] + dt * c01; | ||
|  |     aC[2] = aC[0] + dt * c02; | ||
|  |     aE[0] = e0 + idt * e01; | ||
|  |     aE[1] = aE[0] + dt * e01; | ||
|  |     aE[2] = aE[0] + dt * e02; | ||
|  |     aM[0] = m0 + idt * m01; | ||
|  |     aM[1] = aM[0] + dt * m01; | ||
|  |     aM[2] = aM[0] + dt * m02; | ||
|  |     int jn = 2 * i + 1; | ||
|  |     [loop] for (int j = 0; j < jn; ++j) | ||
|  |     { | ||
|  |       bool odd = (uint(j) % 2 > 0); | ||
|  |       if (j > 0) | ||
|  |       { | ||
|  |         uint iVertChange = uint(2 + i * 3 - j) % 3; | ||
|  |         float s12 = (odd ? 2.0f : 1.0f); | ||
|  |         float s02 = (odd ? -1.0f : 1.0f); | ||
|  |         aVert[iVertChange] += s12 * dtp12 + s02 * dtp02; | ||
|  |         aNorm[iVertChange] += s12 * dtn12 + s02 * dtn02; | ||
|  |         aC[iVertChange] += s12 * dtc12 + s02 * dtc02; | ||
|  |         aE[iVertChange] += s12 * dte12 + s02 * dte02; | ||
|  |         aM[iVertChange] += s12 * dtm12 + s02 * dtm02; | ||
|  |       } | ||
|  |       if (i > 0) | ||
|  |       { | ||
|  |         InterlockedAdd(indirectDrawArgs[0], 3, iNewTriBase); | ||
|  |       } | ||
|  |       int aiProp[2][3] = { { 0, 1, 2}, {0, 2, 1 } }; | ||
|  |       [loop] for (int m = 0; m < 3; ++m) | ||
|  |       { | ||
|  |         int iProp = aiProp[odd ? 1 : 0][m]; | ||
|  |         int iNewGenPoint = iNewTriBase + m; | ||
|  |         aGenPoint[iNewGenPoint] = gpCopy; | ||
|  |         aGenPoint[iNewGenPoint].posNorm.xyz = aVert[iProp]; | ||
|  |         aGenPoint[iNewGenPoint].posNorm.w = pack_normal(normalize(aNorm[iProp])); | ||
|  |         aGenPoint[iNewGenPoint].material.color = pack_rgba(aC[iProp]); | ||
|  |         aGenPoint[iNewGenPoint].material.emissionTightness = pack_rgba(aE[iProp]); | ||
|  |         aGenPoint[iNewGenPoint].material.metallicSmoothness = pack_saturated(aM[iProp]); | ||
|  |       } | ||
|  |       [loop] for (int k = 0; k < 3; ++k) | ||
|  |       { | ||
|  |         float3 blurredNormal; | ||
|  |         SDF_NORMAL(blurredNormal, aGenPoint[iNewTriBase + k].posNorm.xyz, sdf_masked_brushes, iBrushMask, smoothCornerNormalBlur); | ||
|  |         float3 vertNormal = unpack_normal(aGenPoint[iNewTriBase + k].posNorm.w); | ||
|  |         if (autoSmoothMaxAngle > kEpsilon) | ||
|  |         { | ||
|  |           float t = saturate((abs(angle_between(vertNormal, blurredNormal))) / max(kEpsilon, kPi * smoothCornerFade)); | ||
|  |           float3 smoothCornerNormal = normalize(lerp(vertNormal, blurredNormal, t)); | ||
|  |           aGenPoint[iNewTriBase + k].posNorm.w = pack_normal(smoothCornerNormal); | ||
|  |         } | ||
|  |       } | ||
|  |     } | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | [numthreads(1, 1, 1)] | ||
|  | void update_dual_meshing_splats_indirect_args(int3 id : SV_DispatchThreadID) | ||
|  | { | ||
|  |   int numSplats = uint(indirectDrawArgs[0]) / 6; | ||
|  |   switch (renderMode) | ||
|  |   { | ||
|  |     case kRenderModeCircleSplats: | ||
|  |       indirectDrawArgs[0] = numSplats * 3; | ||
|  |       break; | ||
|  |   } | ||
|  | 
 | ||
|  |   indirectDispatchArgs[0] = max(1, uint(numSplats + kThreadGroupSize - 1) / kThreadGroupSize); | ||
|  | } | ||
|  | 
 | ||
|  | [numthreads(kThreadGroupSize, 1, 1)] | ||
|  | void convert_dual_meshing_splats(int3 id : SV_DispatchThreadID) | ||
|  | { | ||
|  | #if defined(MUDBUN_DISABLE_DUAL_MESHING_SPLATS) || defined(MUDBUN_FAST_ITERATION) | ||
|  |   return; | ||
|  | #endif | ||
|  | 
 | ||
|  |   int maxSplats = 0; | ||
|  |   switch (renderMode) | ||
|  |   { | ||
|  |     case kRenderModeCircleSplats: | ||
|  |       maxSplats = uint(indirectDrawArgs[0]) / 3; | ||
|  |       break; | ||
|  |     case kRenderModeQuadSplats: | ||
|  |       maxSplats = uint(indirectDrawArgs[0]) / 6; | ||
|  |       break; | ||
|  |   } | ||
|  | 
 | ||
|  |   int iSplat = id.x; | ||
|  |   if (id.x >= maxSplats) | ||
|  |     return; | ||
|  | 
 | ||
|  |   int iDualQuadBase = iSplat * 6; | ||
|  | 
 | ||
|  |   float3 v0 = aGenPoint[iDualQuadBase    ].posNorm.xyz; | ||
|  |   float3 v1 = aGenPoint[iDualQuadBase + 1].posNorm.xyz; | ||
|  |   float3 v2 = aGenPoint[iDualQuadBase + 2].posNorm.xyz; | ||
|  |   float3 v3 = aGenPoint[iDualQuadBase + 3].posNorm.xyz; | ||
|  |   float3 v4 = aGenPoint[iDualQuadBase + 4].posNorm.xyz; | ||
|  |   float3 v5 = aGenPoint[iDualQuadBase + 5].posNorm.xyz; | ||
|  | 
 | ||
|  |   float3 v01 = v1 - v0; | ||
|  |   float3 v02 = v2 - v0; | ||
|  |   float3 v34 = v4 - v3; | ||
|  |   float3 v35 = v5 - v3; | ||
|  |   float3 c012 = cross(v01, v02); | ||
|  |   float3 c345 = cross(v34, v35); | ||
|  |   float3 n012 = normalize_safe(c012); | ||
|  |   float3 n345 = normalize_safe(c345); | ||
|  |   float a012 = max(kEpsilon, abs(length(c012))); | ||
|  |   float a345 = max(kEpsilon, abs(length(c345))); | ||
|  |   float aTotal = a012 + a345; | ||
|  | 
 | ||
|  |   float3 pos = (a012 * (v0 + v1 + v2) + a345 * (v3 + v4 + v5)) / (3.0f * aTotal); | ||
|  |   float3 norm = normalize_safe(a012 * n012 + a345 * n345) / aTotal; | ||
|  | 
 | ||
|  |   aGenPoint[iDualQuadBase].posNorm = float4(pos, pack_normal(norm * (invertNormals ? -1.0f : 1.0f))); | ||
|  | 
 | ||
|  |   float scaleMult = pow(saturate(aTotal / (0.2f * voxelSize * voxelSize)), 0.1f); | ||
|  |   aGenPoint[iDualQuadBase].material.size *= scaleMult; | ||
|  | } | ||
|  | 
 |