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

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