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