128 lines
3.6 KiB
GLSL
128 lines
3.6 KiB
GLSL
// Copyright (c) Wojciech Figat. All rights reserved.
|
|
|
|
#include "./Flax/Common.hlsl"
|
|
#include "./Flax/MeshAccelerationStructure.hlsl"
|
|
|
|
META_CB_BEGIN(0, Data)
|
|
int3 Resolution;
|
|
uint ResolutionSize;
|
|
float MaxDistance;
|
|
uint VertexStride;
|
|
float BackfacesThreshold;
|
|
uint TriangleCount;
|
|
float3 VoxelToPosMul;
|
|
float WorldUnitsPerVoxel;
|
|
float3 VoxelToPosAdd;
|
|
uint ThreadGroupsX;
|
|
META_CB_END
|
|
|
|
uint GetVoxelIndex(uint3 groupId, uint groupIndex, uint groupSize)
|
|
{
|
|
return groupIndex + (groupId.x + groupId.y * ThreadGroupsX) * groupSize;
|
|
}
|
|
|
|
float3 GetVoxelPos(int3 coord)
|
|
{
|
|
return float3((float)coord.x, (float)coord.y, (float)coord.z) * VoxelToPosMul + VoxelToPosAdd;
|
|
}
|
|
|
|
int3 GetVoxelCoord(uint index)
|
|
{
|
|
uint sizeX = (uint)Resolution.x;
|
|
uint sizeY = (uint)(Resolution.x * Resolution.y);
|
|
uint coordZ = index / sizeY;
|
|
uint coordXY = index % sizeY;
|
|
uint coordY = coordXY / sizeX;
|
|
uint coordX = coordXY % sizeX;
|
|
return int3((int)coordX, (int)coordY, (int)coordZ);
|
|
}
|
|
|
|
#ifdef _CS_Init
|
|
|
|
#define THREAD_GROUP_SIZE 64
|
|
|
|
RWTexture3D<unorm half> SDFtex : register(u0);
|
|
|
|
// Clears SDF texture with the maximum distance.
|
|
META_CS(true, FEATURE_LEVEL_SM5)
|
|
[numthreads(THREAD_GROUP_SIZE, 1, 1)]
|
|
void CS_Init(uint3 GroupId : SV_GroupID, uint GroupIndex : SV_GroupIndex)
|
|
{
|
|
uint voxelIndex = GetVoxelIndex(GroupId, GroupIndex, THREAD_GROUP_SIZE);
|
|
if (voxelIndex >= ResolutionSize)
|
|
return;
|
|
int3 voxelCoord = GetVoxelCoord(voxelIndex);
|
|
SDFtex[voxelCoord] = 1.0f;
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef _CS_RasterizeTriangles
|
|
|
|
#define THREAD_GROUP_SIZE 64
|
|
|
|
RWTexture3D<unorm half> SDFtex : register(u0);
|
|
ByteAddressBuffer VertexBuffer : register(t0);
|
|
ByteAddressBuffer IndexBuffer : register(t1);
|
|
StructuredBuffer<BVHNode> BVHBuffer : register(t2);
|
|
|
|
// Renders triangle mesh into the SDF texture by writing minimum distance to the triangle into all intersecting voxels.
|
|
META_CS(true, FEATURE_LEVEL_SM5)
|
|
[numthreads(THREAD_GROUP_SIZE, 1, 1)]
|
|
void CS_RasterizeTriangles(uint3 GroupId : SV_GroupID, uint3 GroupThreadID : SV_GroupThreadID, uint GroupIndex : SV_GroupIndex)
|
|
{
|
|
uint voxelIndex = GetVoxelIndex(GroupId, GroupIndex, THREAD_GROUP_SIZE);
|
|
if (voxelIndex >= ResolutionSize)
|
|
return;
|
|
int3 voxelCoord = GetVoxelCoord(voxelIndex);
|
|
float3 voxelPos = GetVoxelPos(voxelCoord);
|
|
|
|
BVHBuffers bvh;
|
|
bvh.BVHBuffer = BVHBuffer;
|
|
bvh.VertexBuffer = VertexBuffer;
|
|
bvh.IndexBuffer = IndexBuffer;
|
|
bvh.VertexStride = VertexStride;
|
|
|
|
// Point query to find the distance to the closest surface
|
|
BVHHit hit;
|
|
PointQueryBVH(bvh, voxelPos, hit, MaxDistance);
|
|
float sdf = hit.Distance;
|
|
|
|
// Raycast triangles around voxel to count triangle backfaces hit
|
|
#define CLOSEST_CACHE_SIZE 6
|
|
float3 closestDirections[CLOSEST_CACHE_SIZE] =
|
|
{
|
|
float3(+1, 0, 0),
|
|
float3(-1, 0, 0),
|
|
float3(0, +1, 0),
|
|
float3(0, -1, 0),
|
|
float3(0, 0, +1),
|
|
float3(0, 0, -1),
|
|
};
|
|
uint hitBackCount = 0;
|
|
uint minBackfaceHitCount = (uint)(CLOSEST_CACHE_SIZE * BackfacesThreshold);
|
|
for (uint i = 0; i < CLOSEST_CACHE_SIZE; i++)
|
|
{
|
|
float3 rayDir = closestDirections[i];
|
|
if (RayCastBVH(bvh, voxelPos, rayDir, hit, MaxDistance))
|
|
{
|
|
sdf = min(sdf, hit.Distance);
|
|
if (hit.IsBackface)
|
|
hitBackCount++;
|
|
}
|
|
}
|
|
if (hitBackCount >= minBackfaceHitCount)
|
|
{
|
|
// Voxel is inside the geometry so turn it into negative distance to the surface
|
|
sdf *= -1;
|
|
}
|
|
|
|
// Pack from range [-MaxDistance; +MaxDistance] to [0; 1]
|
|
sdf = clamp(sdf, -MaxDistance, MaxDistance);
|
|
sdf = (sdf / MaxDistance) * 0.5f + 0.5f;
|
|
|
|
SDFtex[voxelCoord] = sdf;
|
|
}
|
|
|
|
#endif
|