You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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;
}