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.
323 lines
8.0 KiB
Plaintext
323 lines
8.0 KiB
Plaintext
2 weeks ago
|
/******************************************************************************/
|
||
|
/*
|
||
|
Project - MudBun
|
||
|
Publisher - Long Bunny Labs
|
||
|
http://LongBunnyLabs.com
|
||
|
Author - Ming-Lun "Allen" Chou
|
||
|
http://AllenChou.net
|
||
|
*/
|
||
|
/******************************************************************************/
|
||
|
|
||
|
#pragma kernel surface_nets_move_point
|
||
|
#pragma kernel surface_nets_move_point_2d
|
||
|
|
||
|
#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/MathConst.cginc"
|
||
|
#include "../../Shader/MeshingModeDefs.cginc"
|
||
|
#include "../../Shader/NormalFuncs.cginc"
|
||
|
#include "../../Shader/RenderModeDefs.cginc"
|
||
|
|
||
|
// https://0fps.net/2012/07/12/smooth-voxel-terrain-part-2/
|
||
|
|
||
|
float surfaceNetsDualQuadsBlend;
|
||
|
int surfaceNetsBinarySearchIterations;
|
||
|
int surfaceNetsGradientDescentIterations;
|
||
|
float surfaceNetsGradientDescentFactor;
|
||
|
|
||
|
static int aEdgeVertIndex3d[12][2] =
|
||
|
{
|
||
|
{ 0, 1 },
|
||
|
{ 1, 5 },
|
||
|
{ 5, 4 },
|
||
|
{ 4, 0 },
|
||
|
{ 2, 3 },
|
||
|
{ 3, 7 },
|
||
|
{ 7, 6 },
|
||
|
{ 6, 2 },
|
||
|
{ 0, 2 },
|
||
|
{ 1, 3 },
|
||
|
{ 5, 7 },
|
||
|
{ 4, 6 },
|
||
|
};
|
||
|
|
||
|
static int aEdgeVertIndex2d[4][2] =
|
||
|
{
|
||
|
{ 0, 1 },
|
||
|
{ 1, 2 },
|
||
|
{ 2, 3 },
|
||
|
{ 3, 0 },
|
||
|
};
|
||
|
|
||
|
[numthreads(kThreadGroupSize, 1, 1)]
|
||
|
void surface_nets_move_point(int3 id : SV_DispatchThreadID)
|
||
|
{
|
||
|
#if defined(MUDBUN_DISABLE_SURFACE_NETS) || defined(MUDBUN_FAST_ITERATION)
|
||
|
return;
|
||
|
#endif
|
||
|
|
||
|
if (id.x >= indirectDrawArgs[0])
|
||
|
return;
|
||
|
|
||
|
int iGenPoint = id.x;
|
||
|
|
||
|
if (surfaceNetsDualQuadsBlend >= 1.0f)
|
||
|
{
|
||
|
if (renderMode == kRenderModeQuadSplats)
|
||
|
aGenPoint[iGenPoint].material.size *= 0.70711f;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
float h = 0.5f * voxelSize;
|
||
|
float3 center = aGenPoint[iGenPoint].posNorm.xyz;
|
||
|
float3 minCornerOffset = -h;
|
||
|
int iBrushMask = aGenPoint[iGenPoint].iBrushMask;
|
||
|
|
||
|
float3 aCornerOffset[8] =
|
||
|
{
|
||
|
float3(-h, -h, -h),
|
||
|
float3( h, -h, -h),
|
||
|
float3(-h, h, -h),
|
||
|
float3( h, h, -h),
|
||
|
float3(-h, -h, h),
|
||
|
float3( h, -h, h),
|
||
|
float3(-h, h, h),
|
||
|
float3( h, h, h),
|
||
|
};
|
||
|
|
||
|
float aCornerRes[8];
|
||
|
SdfBrushMaterial mat;
|
||
|
[loop] for (int iCorner = 0; iCorner < 8; ++iCorner)
|
||
|
{
|
||
|
aCornerRes[iCorner] = sdf_masked_brushes(center + aCornerOffset[iCorner], iBrushMask, mat);
|
||
|
}
|
||
|
|
||
|
float3 avgEdgeOffset = 0.0f;
|
||
|
int numEdges = 0;
|
||
|
[loop] for (int iEdge = 0; iEdge < 12; ++iEdge)
|
||
|
{
|
||
|
int iVert0 = aEdgeVertIndex3d[iEdge][0];
|
||
|
int iVert1 = aEdgeVertIndex3d[iEdge][1];
|
||
|
float res0 = aCornerRes[iVert0];
|
||
|
float res1 = aCornerRes[iVert1];
|
||
|
if (res0 * res1 > 0)
|
||
|
continue;
|
||
|
|
||
|
++numEdges;
|
||
|
|
||
|
float3 offset0 = aCornerOffset[iVert0];
|
||
|
float3 offset1 = aCornerOffset[iVert1];
|
||
|
|
||
|
float3 edgeOffset;
|
||
|
if (res0 == 0.0f && res1 == 0.0f)
|
||
|
{
|
||
|
edgeOffset = max(offset0, offset1);
|
||
|
}
|
||
|
else if (res0 == 0.0f)
|
||
|
{
|
||
|
edgeOffset = offset0;
|
||
|
}
|
||
|
else if (res1 == 0.0f)
|
||
|
{
|
||
|
edgeOffset = offset1;
|
||
|
}
|
||
|
else if (surfaceNetsBinarySearchIterations <= 0)
|
||
|
{
|
||
|
// lerp approximation
|
||
|
float t = -res0 / (res1 - res0);
|
||
|
edgeOffset = lerp(offset0, offset1, t);
|
||
|
}
|
||
|
/*
|
||
|
else
|
||
|
{
|
||
|
// binary search
|
||
|
edgeOffset = 0.5f * (offset0 + offset1);
|
||
|
[loop] for (int iSearch = 0; iSearch < surfaceNetsBinarySearchIterations; ++iSearch)
|
||
|
{
|
||
|
float resT = sdf_masked_brushes(center + edgeOffset, iBrushMask, mat);
|
||
|
if (res0 * resT < 0.0f)
|
||
|
{
|
||
|
res1 = resT;
|
||
|
offset1 = edgeOffset;
|
||
|
}
|
||
|
else if (resT * res1 < 0.0f)
|
||
|
{
|
||
|
res0 = resT;
|
||
|
offset0 = edgeOffset;
|
||
|
}
|
||
|
edgeOffset = 0.5f * (offset0 + offset1);
|
||
|
}
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
avgEdgeOffset += edgeOffset;
|
||
|
}
|
||
|
|
||
|
if (numEdges <= 0)
|
||
|
return;
|
||
|
|
||
|
avgEdgeOffset /= numEdges;
|
||
|
float3 avgEdgePos = center + avgEdgeOffset;
|
||
|
|
||
|
// gradient descent
|
||
|
/*
|
||
|
if (surfaceNetsGradientDescentIterations > 0)
|
||
|
{
|
||
|
float3 n;
|
||
|
SDF_NORMAL_FULL(n, avgEdgePos, sdf_masked_brushes, iBrushMask, 1e-2f * voxelSize);
|
||
|
[loop] for (int iDescent = 0; iDescent < surfaceNetsGradientDescentIterations; ++iDescent)
|
||
|
{
|
||
|
float d = sdf_masked_brushes(avgEdgePos, iBrushMask, mat);
|
||
|
avgEdgeOffset -= surfaceNetsGradientDescentFactor * n * d;
|
||
|
avgEdgePos = center + avgEdgeOffset;
|
||
|
}
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
aGenPoint[iGenPoint].posNorm.xyz = lerp(avgEdgePos, aGenPoint[iGenPoint].posNorm.xyz, surfaceNetsDualQuadsBlend);
|
||
|
|
||
|
if (renderMode == kRenderModeQuadSplats)
|
||
|
aGenPoint[iGenPoint].material.size *= 1.0f - (1.f - 0.70711f) * surfaceNetsDualQuadsBlend;
|
||
|
}
|
||
|
|
||
|
[numthreads(kThreadGroupSize, 1, 1)]
|
||
|
void surface_nets_move_point_2d(int3 id : SV_DispatchThreadID)
|
||
|
{
|
||
|
#if defined(MUDBUN_DISABLE_SURFACE_NETS) || defined(MUDBUN_FAST_ITERATION)
|
||
|
return;
|
||
|
#endif
|
||
|
|
||
|
if (id.x >= indirectDrawArgs[0])
|
||
|
return;
|
||
|
|
||
|
int iGenPoint = id.x;
|
||
|
|
||
|
if (surfaceNetsDualQuadsBlend >= 1.0f)
|
||
|
{
|
||
|
if (renderMode == kRenderModeQuadSplats)
|
||
|
aGenPoint[iGenPoint].material.size *= 0.70711f;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
float h = 0.5f * voxelSize;
|
||
|
float3 center = aGenPoint[iGenPoint].posNorm.xyz;
|
||
|
float3 minCornerOffset = -h;
|
||
|
int iBrushMask = aGenPoint[iGenPoint].iBrushMask;
|
||
|
|
||
|
float3 aCornerOffset[4] =
|
||
|
{
|
||
|
float3(-h, -h, 0.0f),
|
||
|
float3(-h, h, 0.0f),
|
||
|
float3( h, h, 0.0f),
|
||
|
float3( h, -h, 0.0f),
|
||
|
};
|
||
|
|
||
|
bool anyOutside = false;
|
||
|
float aCornerRes[4];
|
||
|
SdfBrushMaterial mat;
|
||
|
[loop] for (int iCorner = 0; iCorner < 4; ++iCorner)
|
||
|
{
|
||
|
float cornerRes = sdf_masked_brushes(center + aCornerOffset[iCorner], iBrushMask, mat);
|
||
|
aCornerRes[iCorner] = cornerRes;
|
||
|
if (cornerRes >= 0.0f)
|
||
|
anyOutside = true;
|
||
|
}
|
||
|
|
||
|
if (!anyOutside)
|
||
|
return;
|
||
|
|
||
|
float3 avgEdgeOffset = 0.0f;
|
||
|
int numEdges = 0;
|
||
|
[loop] for (int iEdge = 0; iEdge < 4; ++iEdge)
|
||
|
{
|
||
|
int iVert0 = aEdgeVertIndex2d[iEdge][0];
|
||
|
int iVert1 = aEdgeVertIndex2d[iEdge][1];
|
||
|
float res0 = aCornerRes[iVert0];
|
||
|
float res1 = aCornerRes[iVert1];
|
||
|
if (res0 * res1 > 0)
|
||
|
continue;
|
||
|
|
||
|
++numEdges;
|
||
|
|
||
|
float3 offset0 = aCornerOffset[iVert0];
|
||
|
float3 offset1 = aCornerOffset[iVert1];
|
||
|
|
||
|
float3 edgeOffset;
|
||
|
if (res0 == 0.0f && res1 == 0.0f)
|
||
|
{
|
||
|
edgeOffset = max(offset0, offset1);
|
||
|
}
|
||
|
else if (res0 == 0.0f)
|
||
|
{
|
||
|
edgeOffset = offset0;
|
||
|
}
|
||
|
else if (res1 == 0.0f)
|
||
|
{
|
||
|
edgeOffset = offset1;
|
||
|
}
|
||
|
else if (surfaceNetsBinarySearchIterations <= 0)
|
||
|
{
|
||
|
// lerp approximation
|
||
|
float t = -res0 / (res1 - res0);
|
||
|
edgeOffset = lerp(offset0, offset1, t);
|
||
|
}
|
||
|
/*
|
||
|
else
|
||
|
{
|
||
|
// binary search
|
||
|
edgeOffset = 0.5f * (offset0 + offset1);
|
||
|
[loop] for (int iSearch = 0; iSearch < surfaceNetsBinarySearchIterations; ++iSearch)
|
||
|
{
|
||
|
float resT = sdf_masked_brushes(center + edgeOffset, iBrushMask, mat);
|
||
|
if (res0 * resT < 0.0f)
|
||
|
{
|
||
|
res1 = resT;
|
||
|
offset1 = edgeOffset;
|
||
|
}
|
||
|
else if (resT * res1 < 0.0f)
|
||
|
{
|
||
|
res0 = resT;
|
||
|
offset0 = edgeOffset;
|
||
|
}
|
||
|
edgeOffset = 0.5f * (offset0 + offset1);
|
||
|
}
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
avgEdgeOffset += edgeOffset;
|
||
|
}
|
||
|
|
||
|
if (numEdges <= 0)
|
||
|
return;
|
||
|
|
||
|
avgEdgeOffset /= numEdges;
|
||
|
float3 avgEdgePos = center + avgEdgeOffset;
|
||
|
|
||
|
// gradient descent
|
||
|
/*
|
||
|
if (surfaceNetsGradientDescentIterations > 0)
|
||
|
{
|
||
|
float3 n;
|
||
|
SDF_NORMAL_2D(n, avgEdgePos, sdf_masked_brushes, iBrushMask, 1e-2f * voxelSize);
|
||
|
[loop] for (int iDescent = 0; iDescent < surfaceNetsGradientDescentIterations; ++iDescent)
|
||
|
{
|
||
|
float d = sdf_masked_brushes(avgEdgePos, iBrushMask, mat);
|
||
|
avgEdgeOffset -= surfaceNetsGradientDescentFactor * n * d;
|
||
|
avgEdgePos = center + avgEdgeOffset;
|
||
|
}
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
aGenPoint[iGenPoint].posNorm.xyz = lerp(avgEdgePos, aGenPoint[iGenPoint].posNorm.xyz, surfaceNetsDualQuadsBlend);
|
||
|
aGenPoint[iGenPoint].sdfValue = sdf_masked_brushes(avgEdgePos, iBrushMask, mat) + surfaceShift;
|
||
|
|
||
|
if (renderMode == kRenderModeQuadSplats)
|
||
|
aGenPoint[iGenPoint].material.size *= 1.0f - (1.f - 0.70711f) * surfaceNetsDualQuadsBlend;
|
||
|
}
|
||
|
|