You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
710 lines
22 KiB
710 lines
22 KiB
#pragma kernel InBucketSum
|
|
#pragma kernel BlockSums
|
|
#pragma kernel FinalSum
|
|
#pragma kernel ToTextureNormalized
|
|
#pragma kernel CopyTextures
|
|
#pragma kernel JFA
|
|
#pragma kernel DistanceTransform
|
|
#pragma kernel CopyBuffers
|
|
#pragma kernel GenerateRayMapLocal
|
|
#pragma kernel RayMapScanX
|
|
#pragma kernel RayMapScanY
|
|
#pragma kernel RayMapScanZ
|
|
#pragma kernel SignPass6Rays
|
|
#pragma kernel SignPassNeighbors
|
|
#pragma kernel ToBlockSumBuffer
|
|
#pragma kernel ClearTexturesAndBuffers
|
|
#pragma kernel CopyToBuffer
|
|
#pragma kernel GenerateTrianglesUV
|
|
#pragma kernel ConservativeRasterization
|
|
#pragma kernel ChooseDirectionTriangleOnly
|
|
#pragma kernel SurfaceClosing
|
|
|
|
#pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch glcore webgpu
|
|
|
|
#include "Packages/com.unity.visualeffectgraph/Shaders/SDFBaker/SdfUtils.hlsl"
|
|
|
|
RWByteAddressBuffer indices;
|
|
RWByteAddressBuffer vertices;
|
|
RWStructuredBuffer<uint> coordFlip;
|
|
RWStructuredBuffer<float4> verticesOut;
|
|
RWStructuredBuffer<float4> aabb;
|
|
float4x4 worldToClip;
|
|
uint currentAxis;
|
|
RWStructuredBuffer<float4> voxelsBuffer;
|
|
|
|
|
|
RWStructuredBuffer<Tri> rw_trianglesUV;
|
|
StructuredBuffer<Tri> trianglesUV;
|
|
RWTexture3D<float4> voxels, voxelsTmp;
|
|
RWTexture3D<float4> rayMap;
|
|
|
|
CBUFFER_START(VoxelParams)
|
|
uint nTriangles;
|
|
float3 minBoundsExtended;
|
|
float3 maxBoundsExtended;
|
|
float maxExtent;
|
|
uint3 size;
|
|
uint upperBoundCount;
|
|
CBUFFER_END
|
|
|
|
|
|
|
|
uint id3(uint i, uint j, uint k)
|
|
{
|
|
return (uint)(i + size.x * j + size.x * size.y * k);
|
|
}
|
|
uint id3(int3 coord)
|
|
{
|
|
return id3(coord.x, coord.y, coord.z);
|
|
}
|
|
int vertexPositionOffset;
|
|
int vertexStride;
|
|
int indexStride;
|
|
|
|
uint LoadIndex16(uint idx)
|
|
{
|
|
uint entryOffset = idx & 1u;
|
|
idx = idx >> 1;
|
|
uint read = indices.Load(idx << 2);
|
|
return entryOffset == 1 ? read >> 16 : read & 0xffff;
|
|
}
|
|
|
|
uint LoadIndex32(uint idx)
|
|
{
|
|
return indices.Load(idx << 2);
|
|
}
|
|
|
|
float3 GetVertexObj(uint idThread, uint idVertex)
|
|
{
|
|
uint idIndex = (3 * idThread + idVertex);
|
|
uint index = indexStride == 2 ? LoadIndex16(idIndex) : LoadIndex32(idIndex);
|
|
uint vertIdx = vertexPositionOffset + index * vertexStride;
|
|
uint3 vRaw = vertices.Load3(vertIdx);
|
|
return asfloat(vRaw);
|
|
}
|
|
|
|
[numthreads(64, 1, 1)]
|
|
void GenerateTrianglesUV(uint3 id: SV_DispatchThreadID)
|
|
{
|
|
if (id.x >= nTriangles)
|
|
return;
|
|
|
|
float3 half_extents = 0.5f * (maxBoundsExtended - minBoundsExtended) / maxExtent;
|
|
float3 center = 0.5f * (maxBoundsExtended + minBoundsExtended);
|
|
Tri triUV;
|
|
triUV.a = (GetVertexObj(id.x, 0) - center) / maxExtent + half_extents;
|
|
triUV.b = (GetVertexObj(id.x, 1) - center) / maxExtent + half_extents;
|
|
triUV.c = (GetVertexObj(id.x, 2) - center) / maxExtent + half_extents;
|
|
|
|
rw_trianglesUV[id.x] = triUV;
|
|
}
|
|
|
|
[numthreads(64,1,1)]
|
|
void ConservativeRasterization(uint3 id: SV_DispatchThreadID)
|
|
{
|
|
if (id.x >= nTriangles)
|
|
return;
|
|
if(coordFlip[id.x] != currentAxis)
|
|
return;
|
|
|
|
uint i;
|
|
|
|
float4 vertex[3];
|
|
for ( i = 0; i < 3; i++)
|
|
{
|
|
vertex[i] = mul(worldToClip, float4(GetVertexObj(id.x, i), 1.0f));
|
|
}
|
|
float3 triangleNormal = normalize(cross(vertex[1].xyz - vertex[0].xyz, vertex[2].xyz - vertex[0].xyz));
|
|
|
|
if (dot(triangleNormal, float3(0.0, 0.0, 1.0)) < 0.0)
|
|
{
|
|
float4 vertexTemp = vertex[2];
|
|
vertex[2] = vertex[1];
|
|
vertex[1] = vertexTemp;
|
|
}
|
|
float4 trianglePlane;
|
|
trianglePlane.xyz = normalize(cross(vertex[1].xyz - vertex[0].xyz, vertex[2].xyz - vertex[0].xyz));
|
|
trianglePlane.w = -dot(vertex[0].xyz, trianglePlane.xyz);
|
|
|
|
float2 hPixel;
|
|
if(currentAxis == 0)
|
|
{
|
|
hPixel = float2(1.0f/size.x, 1.0f/size.y);
|
|
}
|
|
else if (currentAxis == 1)
|
|
{
|
|
hPixel = float2(1.0f/size.z, 1.0f/size.x);
|
|
}
|
|
else
|
|
{
|
|
hPixel = float2(1.0f/size.y, 1.0f/size.z);
|
|
}
|
|
float4 _aabb = float4(1.0, 1.0, -1.0, -1.0);
|
|
// Get AABB of the triangle.
|
|
_aabb.xy = min(_aabb.xy, min(vertex[0].xy, min(vertex[1].xy, vertex[2].xy)));
|
|
_aabb.zw = max(_aabb.xy, max(vertex[0].xy, max(vertex[1].xy, vertex[2].xy)));
|
|
|
|
// Add offset of half pixel size to AABB.
|
|
aabb[id.x] = _aabb + float4(-hPixel.x, -hPixel.y, hPixel.x, hPixel.y);
|
|
|
|
// //conservative rast
|
|
float4 vertexCons[3];
|
|
float3 plane[3];
|
|
for ( i = 0; i < 3; i++)
|
|
{
|
|
plane[i] = cross(vertex[i].xyw, vertex[(i + 2) % 3].xyw);
|
|
plane[i].z -= dot(hPixel, abs(plane[i].xy));
|
|
}
|
|
for ( i = 0; i < 3; i++)
|
|
{
|
|
vertexCons[i].xyw = cross(plane[i], plane[(i + 1) % 3]);
|
|
if (abs(vertexCons[i].w) < CONSERVATIVE_RASTER_EPS)
|
|
{
|
|
return;
|
|
}
|
|
vertexCons[i] /= vertexCons[i].w;
|
|
}
|
|
|
|
for ( i = 0; i < 3; i++)
|
|
{
|
|
// Calculate the new z-Coordinate derived from a point on a plane.
|
|
vertexCons[i].z = -(trianglePlane.x * vertexCons[i].x + trianglePlane.y * vertexCons[i].y + trianglePlane.w) / trianglePlane.z;
|
|
}
|
|
for ( i = 0; i < 3; i++)
|
|
{
|
|
verticesOut[3 * id.x + i] = vertexCons[i];
|
|
}
|
|
}
|
|
|
|
[numthreads(64, 1, 1)]
|
|
void ChooseDirectionTriangleOnly(uint3 id: SV_DispatchThreadID)
|
|
{
|
|
if (id.x >= nTriangles)
|
|
return;
|
|
|
|
float3 n = computeNormalUnnormalized(GetVertexObj(id.x, 0), GetVertexObj(id.x, 1), GetVertexObj(id.x, 2));
|
|
n = abs(n);
|
|
if (n.x > max(n.y, n.z))
|
|
{
|
|
coordFlip[id.x] = 2;
|
|
}
|
|
else if (n.y > max(n.x, n.z))
|
|
{
|
|
coordFlip[id.x] = 1;
|
|
}
|
|
else
|
|
{
|
|
coordFlip[id.x] = 0;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
RWStructuredBuffer<uint> Input;
|
|
StructuredBuffer<uint> inputCounter;
|
|
StructuredBuffer<uint> auxBuffer;
|
|
RWStructuredBuffer<uint> Result ;
|
|
|
|
#define groupthreads 512
|
|
groupshared uint2 bucket[groupthreads];
|
|
|
|
void PrefixSum(uint id, uint gid, uint x)
|
|
{
|
|
uint thid = id;
|
|
//load input into shared memory
|
|
bucket[gid].x = x;
|
|
bucket[gid].y = 0;
|
|
|
|
uint stride;
|
|
for (stride = 2; stride <= groupthreads; stride <<= 1)
|
|
{
|
|
GroupMemoryBarrierWithGroupSync();
|
|
|
|
if ((gid & (stride - 1)) == (stride - 1))
|
|
{
|
|
bucket[gid].x += bucket[gid - stride / 2].x;
|
|
}
|
|
// clear the last element
|
|
if (gid == (groupthreads - 1))
|
|
{
|
|
bucket[gid].x = 0;
|
|
}
|
|
}
|
|
|
|
// Down sweep
|
|
bool n = true;
|
|
[unroll] for (stride = groupthreads / 2; stride >= 1; stride >>= 1)
|
|
{
|
|
GroupMemoryBarrierWithGroupSync();
|
|
|
|
uint a = stride - 1;
|
|
uint b = stride | a;
|
|
|
|
if (n) // ping-pong between passes
|
|
{
|
|
if ((gid & b) == b)
|
|
{
|
|
bucket[gid].y = bucket[gid - stride].x + bucket[gid].x;
|
|
}
|
|
else if ((gid & a) == a)
|
|
{
|
|
bucket[gid].y = bucket[gid + stride].x;
|
|
}
|
|
else
|
|
{
|
|
bucket[gid].y = bucket[gid].x;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ((gid & b) == b)
|
|
{
|
|
bucket[gid].x = bucket[gid - stride].y + bucket[gid].y;
|
|
}
|
|
else if ((gid & a) == a)
|
|
{
|
|
bucket[gid].x = bucket[gid + stride].y;
|
|
}
|
|
else
|
|
{
|
|
bucket[gid].x = bucket[gid].y;
|
|
}
|
|
}
|
|
n = !n;
|
|
}
|
|
Result[thid] = bucket[gid].y; //Careful, works for groupthreads = 512 (2^(2n+1))
|
|
}
|
|
uint numElem;
|
|
uint dispatchWidth;
|
|
[numthreads(groupthreads, 1, 1)]
|
|
void InBucketSum(uint3 GTid: SV_GroupThreadID, uint GI: SV_GroupIndex, uint3 groupId: SV_GroupID)
|
|
{
|
|
uint x;
|
|
const uint id = GTid.x + groupId.x * groupthreads + groupId.y * dispatchWidth * groupthreads;
|
|
|
|
if(id >= numElem)
|
|
{
|
|
x = 0u;
|
|
}
|
|
else{
|
|
x = Input[id];
|
|
}
|
|
PrefixSum(id, GI, x);
|
|
}
|
|
|
|
[numthreads(groupthreads, 1, 1)]
|
|
void BlockSums(uint3 DTid: SV_DispatchThreadID, uint GI: SV_GroupIndex)
|
|
{
|
|
uint x ;
|
|
if((DTid.x + 1) * groupthreads -1 >= numElem )
|
|
{
|
|
x = 0u;
|
|
}
|
|
else
|
|
{
|
|
uint id = (DTid.x + 1) * groupthreads - 1;
|
|
x = Input[id] + inputCounter[id]; // Change the type of x here if scan other types
|
|
}
|
|
PrefixSum(DTid.x, GI, x);
|
|
}
|
|
|
|
bool exclusive;
|
|
// add the bucket scanned result to each bucket to get the final result
|
|
[numthreads(groupthreads, 1, 1)]
|
|
void FinalSum(uint3 GTid: SV_GroupThreadID, uint3 groupId: SV_GroupID) {
|
|
const uint id = GTid.x + groupId.x * groupthreads + groupId.y * dispatchWidth * groupthreads;
|
|
const uint flattenedGroupID = groupId.x + dispatchWidth * groupId.y;
|
|
|
|
if(id >= numElem)
|
|
return;
|
|
if(exclusive)
|
|
Result[id] = Input[id] + auxBuffer[flattenedGroupID] - inputCounter[id]; //Exclusive prefix sum by subtracting the initial value of the counter
|
|
else
|
|
{
|
|
Result[id] = Input[id] + auxBuffer[flattenedGroupID];
|
|
}
|
|
|
|
}
|
|
|
|
[numthreads(groupthreads, 1, 1)]
|
|
void ToBlockSumBuffer(uint3 DTid : SV_DispatchThreadID)
|
|
{
|
|
if ((DTid.x + 1) * groupthreads - 1 >= numElem)
|
|
return;
|
|
uint id = (DTid.x + 1) * groupthreads - 1;
|
|
Result[DTid.x] = Input[id] + inputCounter[id];
|
|
}
|
|
|
|
[numthreads(4, 4, 4)]
|
|
void ToTextureNormalized(uint3 id: SV_DispatchThreadID)
|
|
{
|
|
if (id.x >= size.x || id.y >= size.y || id.z >= size.z)
|
|
return;
|
|
if (voxelsBuffer[id3(id.xyz)].w != 0.0f)
|
|
{
|
|
voxels[id.xyz] = voxelsBuffer[id3(id.xyz)];
|
|
}
|
|
}
|
|
|
|
|
|
StructuredBuffer<float4> src;
|
|
RWStructuredBuffer<float4> dest;
|
|
[numthreads(64, 1, 1)]
|
|
void CopyBuffers(uint3 id: SV_DispatchThreadID) {
|
|
if (id.x >= size.x * size.y * size.z)
|
|
return;
|
|
dest[id.x] = src[id.x];
|
|
}
|
|
|
|
[numthreads(4, 4, 4)]
|
|
void CopyTextures(uint3 id: SV_DispatchThreadID)
|
|
{
|
|
if (id.x >= (uint)size.x || id.y >= (uint)size.y || id.z >= (uint)size.z)
|
|
return;
|
|
voxels[int3(id.x, id.y, id.z)] = voxelsTmp[int3(id.x, id.y, id.z)];
|
|
}
|
|
|
|
|
|
RWTexture3D<float> signMap;
|
|
float threshold;
|
|
|
|
[numthreads(4, 4, 4)]
|
|
void SurfaceClosing(uint3 id : SV_DispatchThreadID)
|
|
{
|
|
if (id.x >= size.x || id.y >= size.y || id.z >= size.z)
|
|
return;
|
|
const uint size_max = Max3(size.x, size.y, size.z);
|
|
const float currentSignScore = signMap[id.xyz]-threshold;
|
|
const float3 halfTexel = float3(0.5f, 0.5f, 0.5f);
|
|
//Close on open borders
|
|
if(currentSignScore > 0)
|
|
{
|
|
if(any(size - id == 1) || any(id == 0))
|
|
{
|
|
const bool3 borderUp = size - id == 1;
|
|
const bool3 borderDown = id == 0;
|
|
const float3 offset = borderUp * halfTexel - borderDown * halfTexel + halfTexel;
|
|
voxels[id.xyz] = float4( (float3(id.xyz) + offset) / size_max, 1.0f);
|
|
}
|
|
}
|
|
if(any(id - size == 1))
|
|
return;
|
|
//Close on sign switch
|
|
if(abs(currentSignScore/threshold) < 0.1f)
|
|
{
|
|
if(currentSignScore*(signMap[id.xyz + uint3(1,0,0)] - threshold) < 0)
|
|
{
|
|
const uint3 writeCoord = id.xyz + (currentSignScore < 0 ? uint3(1,0,0) : uint3(0,0,0));
|
|
voxels[writeCoord.xyz] = float4 ((float3(writeCoord) + halfTexel) / size_max, 1.0f);
|
|
}
|
|
if(currentSignScore*(signMap[id.xyz + uint3(0,1,0)] - threshold) < 0)
|
|
{
|
|
const uint3 writeCoord = id.xyz + (currentSignScore < 0 ? uint3(0,1,0) : uint3(0,0,0));
|
|
voxels[writeCoord.xyz] = float4 ((float3(writeCoord) + halfTexel) / size_max, 1.0f);
|
|
}
|
|
if(currentSignScore*(signMap[id.xyz + uint3(0,0,1)] - threshold) < 0)
|
|
{
|
|
const uint3 writeCoord = id.xyz + (currentSignScore < 0 ? uint3(0,0,1) : uint3(0,0,0));
|
|
voxels[writeCoord.xyz] = float4 ((float3(writeCoord) + halfTexel) / size_max, 1.0f);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
uint offset;
|
|
[numthreads(4,4,4)]
|
|
void JFA(uint3 id: SV_DispatchThreadID)
|
|
{
|
|
if (id.x >= size.x || id.y >= size.y || id.z >= size.z)
|
|
return;
|
|
uint size_max = Max3(size.x, size.y, size.z);
|
|
float bestDistance = 9999.0f;
|
|
float3 bestCoord = float3(0.0f, 0.0f, 0.0f);
|
|
[unroll(3)]
|
|
for (int z = -1; z <= 1; z++)
|
|
{
|
|
[unroll(3)]
|
|
for (int y = -1; y <= 1; y++)
|
|
{
|
|
[unroll(3)]
|
|
for (int x = -1; x <= 1; x++)
|
|
{
|
|
int3 sampleCoord;
|
|
sampleCoord.x = min((int)(size.x-1), max(0, (int)id.x + x * (int)offset));
|
|
sampleCoord.y = min((int)(size.y-1), max(0, (int)id.y + y * (int)offset));
|
|
sampleCoord.z = min((int)(size.z-1), max(0, (int)id.z + z * (int)offset));
|
|
|
|
float3 seedCoord = voxels[sampleCoord].xyz;
|
|
float dist = length(seedCoord - (float3(id.xyz) + float3(0.5f, 0.5f, 0.5f)) / size_max);
|
|
if ((seedCoord.x != 0.0f || seedCoord.y != 0.0f || seedCoord.z != 0.0f) && dist < bestDistance)
|
|
{
|
|
bestCoord = seedCoord;
|
|
bestDistance = dist;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
voxelsTmp[id.xyz] = float4(bestCoord, bestDistance);
|
|
}
|
|
|
|
|
|
void TestIntersection6Rays(in Tri tri, in int3 voxelId, out float3 intersectForward, out float3 intersectBackward)
|
|
{
|
|
Tri tri_ccw;
|
|
tri_ccw.a = tri.c;
|
|
tri_ccw.b = tri.b;
|
|
tri_ccw.c = tri.a;
|
|
|
|
uint size_max = Max3(size.x, size.y, size.z);
|
|
intersectForward = float3(0.0f, 0.0f, 0.0f);
|
|
intersectBackward = float3(0.0f, 0.0f, 0.0f);
|
|
//check x direction
|
|
float3 p = (float3(voxelId) + float3(0.0f, 0.5f, 0.5f)) / size_max;
|
|
float3 q = (float3(voxelId) + float3(1.0f, 0.5f, 0.5f)) / size_max;
|
|
float t1 = 1, t2 = -1, t3 = -1, t1ccw = -1, t2ccw = -1, t3ccw = -1;
|
|
float intersect = -1.0f * IntersectSegmentTriangle(p, q, tri, t1);
|
|
intersect += IntersectSegmentTriangle(p, q, tri_ccw, t1ccw);
|
|
t1 = min(t1,t1ccw);
|
|
if (t1 < 0.5f)
|
|
{
|
|
intersectBackward.x += float(intersect);
|
|
}
|
|
else
|
|
{
|
|
intersectForward.x += float(intersect);
|
|
}
|
|
// y direction
|
|
p = (float3(voxelId) + float3(0.5f, 0.0f, 0.5f)) / size_max;
|
|
q = (float3(voxelId) + float3(0.5f, 1.0f, 0.5f)) / size_max;
|
|
intersect = -1.0f * IntersectSegmentTriangle(p, q, tri, t2);
|
|
intersect += IntersectSegmentTriangle(p, q, tri_ccw, t2ccw);
|
|
t2 = min(t2,t2ccw);
|
|
|
|
if (t2 < 0.5f)
|
|
{
|
|
intersectBackward.y += float(intersect);
|
|
}
|
|
else
|
|
{
|
|
intersectForward.y += float(intersect);
|
|
}
|
|
|
|
// z direction
|
|
p = (float3(voxelId) + float3(0.5f, 0.5f, 0.0f)) / size_max;
|
|
q = (float3(voxelId) + float3(0.5f, 0.5f, 1.0f)) / size_max;
|
|
intersect = -1.0f * IntersectSegmentTriangle(p, q, tri, t3);
|
|
intersect += IntersectSegmentTriangle(p, q, tri_ccw, t3ccw);
|
|
t3 = min(t3,t3ccw);
|
|
if (t3 < 0.5f)
|
|
{
|
|
intersectBackward.z += float(intersect);
|
|
}
|
|
else
|
|
{
|
|
intersectForward.z += float(intersect);
|
|
}
|
|
}
|
|
|
|
int3 offsetRayMap; //(0,0,0), (0,0,1),(0,1,0), etc...
|
|
|
|
RWStructuredBuffer<uint> triangleIDs, accumCounter;
|
|
|
|
[numthreads(8, 8, 8)]
|
|
void GenerateRayMapLocal(uint3 id: SV_DispatchThreadID) {
|
|
id = 2 * id + offsetRayMap;
|
|
if (id.x >= (uint)size.x || id.y >= (uint)size.y || id.z >= (uint)size.z)
|
|
return;
|
|
|
|
uint startId = 0;
|
|
[branch] if(id3(id) > 0)
|
|
{
|
|
startId = accumCounter[id3(id) - 1];
|
|
}
|
|
uint endId = accumCounter[id3(id)];
|
|
for (uint i = startId; i < endId && (i < upperBoundCount - 1); i++)
|
|
{
|
|
uint idTri = triangleIDs[i];
|
|
Tri tri = trianglesUV[idTri];
|
|
float3 intersectForward, intersectBackward;
|
|
TestIntersection6Rays(tri, int3(id.xyz), intersectForward, intersectBackward);
|
|
|
|
rayMap[id.xyz] += float4(intersectForward, 1.0f);
|
|
|
|
if (id.x > 0)
|
|
{
|
|
rayMap[int3(id.x - 1, id.y, id.z)] += float4(intersectBackward.x, 0.0f, 0.0f, 1.0f);
|
|
}
|
|
if (id.y > 0)
|
|
{
|
|
rayMap[int3(id.x, id.y - 1, id.z)] += float4(0.0f, intersectBackward.y, 0.0f, 1.0f);
|
|
}
|
|
if (id.z > 0)
|
|
{
|
|
rayMap[int3(id.x, id.y, id.z - 1)] += float4(0.0f, 0.0f, intersectBackward.z, 1.0f);
|
|
}
|
|
}
|
|
}
|
|
|
|
[numthreads(1, 8, 8)]
|
|
void RayMapScanX(uint3 id: SV_DispatchThreadID)
|
|
{
|
|
if (id.y >= (uint)size.y || id.z >= (uint)size.z)
|
|
return;
|
|
for (int t = size.x - 2; t >= 0; t--)
|
|
{
|
|
rayMap[int3(t, id.y, id.z)] += float4(rayMap[int3(t + 1, id.y, id.z)].x, 0, 0, 1.0f);
|
|
}
|
|
}
|
|
|
|
[numthreads(8, 1, 8)]
|
|
void RayMapScanY(uint3 id: SV_DispatchThreadID) {
|
|
if (id.x >= (uint)size.x || id.z >= (uint)size.z)
|
|
return;
|
|
for (int t = size.y - 2; t >= 0; t--)
|
|
{
|
|
rayMap[int3(id.x, t, id.z)] += float4(0, rayMap[int3(id.x, t + 1, id.z)].y, 0, 1.0f);
|
|
}
|
|
}
|
|
|
|
[numthreads(8, 8, 1)]
|
|
void RayMapScanZ(uint3 id: SV_DispatchThreadID)
|
|
{
|
|
if (id.x >= (uint)size.x || id.y >= (uint)size.y)
|
|
return;
|
|
for (int t = size.z - 2; t >= 0; t--)
|
|
{
|
|
rayMap[int3(id.x, id.y, t)] += float4(0, 0, rayMap[int3(id.x, id.y, t + 1)].z, 1.0f);
|
|
}
|
|
}
|
|
|
|
RWTexture3D<float> signMapTmp;
|
|
|
|
[numthreads(4, 4, 4)]
|
|
void SignPass6Rays(uint3 id: SV_DispatchThreadID) {
|
|
if (id.x >= (uint)size.x || id.y >= (uint)size.y || id.z >= (uint)size.z)
|
|
return;
|
|
signMap[id.xyz] = (rayMap[id.xyz].x +
|
|
rayMap[id.xyz].y +
|
|
rayMap[id.xyz].z +
|
|
(rayMap[id.xyz].x - rayMap[int3(0, id.y, id.z)].x) +
|
|
(rayMap[id.xyz].y - rayMap[int3(id.x, 0, id.z)].y) +
|
|
(rayMap[id.xyz].z - rayMap[int3(id.x, id.y, 0)].z));
|
|
}
|
|
|
|
|
|
bool needNormalize;
|
|
float normalizeFactor;
|
|
uint numNeighbours;
|
|
uint passId;
|
|
[numthreads(4, 4, 4)]
|
|
void SignPassNeighbors(uint3 id: SV_DispatchThreadID) {
|
|
if (id.x >= (uint)size.x || id.y >= (uint)size.y || id.z >= (uint)size.z)
|
|
return;
|
|
uint maxSize = Max3(size.x, size.y, size.z);
|
|
float4 selfRayMap = rayMap[id.xyz];
|
|
for (uint i = 0; i < numNeighbours; i++)
|
|
{
|
|
int3 neighborsOffset = GenerateNeighborOffset( (i * numNeighbours) + passId, maxSize, 0.05f);
|
|
int3 neighborsIndex;
|
|
neighborsIndex.x = min((int)(size.x - 1), max(0, (int)id.x + neighborsOffset.x));
|
|
neighborsIndex.y = min((int)(size.y - 1), max(0, (int)id.y + neighborsOffset.y));
|
|
neighborsIndex.z = min((int)(size.z - 1), max(0, (int)id.z + neighborsOffset.z));
|
|
|
|
float accumSign = 0.0f;
|
|
//////xyz,
|
|
accumSign += (selfRayMap.x - rayMap[int3(neighborsIndex.x, id.y, id.z)].x);
|
|
accumSign += (rayMap[int3(neighborsIndex.x, id.y, id.z)].y - rayMap[int3(neighborsIndex.x, neighborsIndex.y, id.z)].y);
|
|
accumSign += (rayMap[int3(neighborsIndex.x, neighborsIndex.y, id.z)].z - rayMap[neighborsIndex].z);
|
|
|
|
|
|
////// xzy
|
|
accumSign += (selfRayMap.x - rayMap[int3(neighborsIndex.x, id.y, id.z)].x);
|
|
accumSign += (rayMap[int3(neighborsIndex.x, id.y, id.z)].z - rayMap[int3(neighborsIndex.x, id.y, neighborsIndex.z)].z);
|
|
accumSign += (rayMap[int3(neighborsIndex.x, id.y, neighborsIndex.z)].y - rayMap[neighborsIndex].y);
|
|
|
|
//////yxz,
|
|
accumSign += (selfRayMap.y - rayMap[int3(id.x, neighborsIndex.y, id.z)].y);
|
|
accumSign += (rayMap[int3(id.x, neighborsIndex.y, id.z)].x - rayMap[int3(neighborsIndex.x, neighborsIndex.y, id.z)].x);
|
|
accumSign += (rayMap[int3(neighborsIndex.x, neighborsIndex.y, id.z)].z - rayMap[neighborsIndex].z);
|
|
|
|
////yzx,
|
|
accumSign += (selfRayMap.y - rayMap[int3(id.x, neighborsIndex.y, id.z)].y);
|
|
accumSign += (rayMap[int3(id.x, neighborsIndex.y, id.z)].z - rayMap[int3(id.x, neighborsIndex.y, neighborsIndex.z)].z);
|
|
accumSign += (rayMap[int3(id.x, neighborsIndex.y, neighborsIndex.z)].x - rayMap[neighborsIndex].x);
|
|
|
|
////zyx
|
|
accumSign += (selfRayMap.z - rayMap[int3(id.x, id.y, neighborsIndex.z)].z);
|
|
accumSign += (rayMap[int3(id.x, id.y, neighborsIndex.z)].y - rayMap[int3(id.x, neighborsIndex.y, neighborsIndex.z)].y);
|
|
accumSign += (rayMap[int3(id.x, neighborsIndex.y, neighborsIndex.z)].x - rayMap[neighborsIndex].x);
|
|
|
|
//zxy
|
|
accumSign += (selfRayMap.z - rayMap[int3(id.x, id.y, neighborsIndex.z)].z);
|
|
accumSign += (rayMap[int3(id.x, id.y, neighborsIndex.z)].x - rayMap[int3(neighborsIndex.x, id.y, neighborsIndex.z)].x);
|
|
accumSign += (rayMap[int3(neighborsIndex.x, id.y, neighborsIndex.z)].y - rayMap[neighborsIndex].y);
|
|
|
|
signMap[id.xyz] += normalizeFactor * accumSign + 6 * signMapTmp[neighborsIndex];
|
|
|
|
}
|
|
if (needNormalize)
|
|
{
|
|
float normalizeFactorFinal = normalizeFactor + numNeighbours * 6 * normalizeFactor;
|
|
signMap[id.xyz] /= normalizeFactorFinal;
|
|
|
|
}
|
|
}
|
|
|
|
RWTexture3D<float> distanceTexture;
|
|
float sdfOffset;
|
|
[numthreads(8, 8, 8)]
|
|
void DistanceTransform(uint3 id: SV_DispatchThreadID) {
|
|
if (id.x >= size.x || id.y >= size.y || id.z >= size.z)
|
|
return;
|
|
uint size_max = Max3(size.x, size.y, size.z);
|
|
float3 seedCoord = voxels[int3(id.x, id.y, id.z)].xyz;
|
|
float3 voxelCoord = (float3(id.xyz) + float3(0.5f, 0.5f, 0.5f)) / size_max;
|
|
float signD = signMap[id.xyz] > threshold ? -1 : 1;
|
|
// float signD = 1;
|
|
int3 idSeed = int3(seedCoord * size_max);
|
|
uint startId = 0;
|
|
[branch] if(id3(idSeed) > 0)
|
|
{
|
|
startId = accumCounter[id3(idSeed) - 1];
|
|
}
|
|
uint endId = accumCounter[id3(idSeed)];
|
|
float dist = 9999;
|
|
for (uint i = startId; (i < endId) && (i < upperBoundCount-1); i++)
|
|
{
|
|
uint idTri = triangleIDs[i];
|
|
Tri tri = trianglesUV[idTri];
|
|
dist = min(dist,ComputeDistancePointTri(voxelCoord, tri));
|
|
}
|
|
if(dist == 9999)
|
|
{
|
|
dist = length(seedCoord - voxelCoord);
|
|
}
|
|
distanceTexture[id.xyz] = signD * dist - sdfOffset;
|
|
}
|
|
|
|
RWStructuredBuffer<uint> counter;
|
|
[numthreads(8, 8, 8)]
|
|
void ClearTexturesAndBuffers(uint3 id : SV_DispatchThreadID)
|
|
{
|
|
if (id.x >= (uint)size.x || id.y >= (uint)size.y || id.z >= (uint)size.z) return;
|
|
voxels[int3(id.x, id.y, id.z)] = float4(0.0f,0.0f,0.0f,1.0f);
|
|
voxelsTmp[int3(id.x, id.y, id.z)] = float4(0.0f,0.0f,0.0f,0.0f);
|
|
rayMap[int3(id.x, id.y, id.z)]= float4(0.0f,0.0f,0.0f,0.0f);
|
|
signMap[int3(id.x, id.y, id.z)] = 0.0f;
|
|
signMapTmp[int3(id.x, id.y, id.z)] = 0.0f;
|
|
accumCounter[id3(id.xyz)] = 0u;
|
|
counter[id3(id.xyz)] = 0u;
|
|
voxelsBuffer[id3(id.xyz)] = float4(0.0f,0.0f,0.0f,0.0f);
|
|
}
|
|
|
|
|
|
[numthreads(8, 8, 8)]
|
|
void CopyToBuffer(uint3 id : SV_DispatchThreadID)
|
|
{
|
|
if (id.x >= (uint)size.x || id.y >= (uint)size.y || id.z >= (uint)size.z) return;
|
|
voxelsBuffer[id3(id.x, id.y, id.z)] = voxels[int3(id.x, id.y, id.z)];
|
|
}
|