Adding basic CBT Terrain implementation

This commit is contained in:
Dynamitos
2024-10-10 20:36:59 +02:00
parent c89fd405b8
commit 98a7e16756
38 changed files with 3779 additions and 373 deletions
+60 -181
View File
@@ -1,198 +1,77 @@
import Common;
import Bounding;
import Scene;
import MaterialParameter;
import Parameters;
struct TerrainPayload
// Vertex input
struct VertexInput
{
float3 offset;
float extent;
uint numMeshes;
uint instanceID : SV_InstanceID;
uint vertexID : SV_VertexID;
};
struct TerrainTile
// Vertex output
struct VertexOutput
{
int2 location;
float extent;
float height;
float4 positionCS : SV_POSITION;
uint triangleID : TRIANGLE_ID;
};
struct TerrainVertex
[shader("vertex")]
VertexOutput vert(VertexInput input)
{
float4 position_CS : SV_Position;
float3 position_WS : POSITION0;
float2 texCoord : TEXCOORD0;
float depth : DEPTH;
uint lod : BONEINDEX;
};
// Initialize the output structure
VertexOutput output;
output = (VertexOutput)0;
struct TerrainData
{
StructuredBuffer<TerrainTile> tiles;
Texture2D<float> displacement;
Texture2D<float3> colorMap;
SamplerState sampler;
};
ParameterBlock<TerrainData> pTerrainData;
// Evaluate the properties of this triangle
uint triangle_id = input.vertexID / 3;
uint local_vert_id = input.vertexID % 3;
[numthreads(1, 1, 1)]
[shader("amplification")]
void taskMain(
uint threadID: SV_GroupThreadID,
uint3 groupID: SV_GroupID
) {
TerrainTile tile = pTerrainData.tiles[groupID.x];
GroupMemoryBarrierWithGroupSync();
AABB bounding;
bounding.minCorner = float3(tile.location.x, tile.height, tile.location.y) * tile.extent;
bounding.maxCorner = float3(tile.location.x + tile.extent, tile.height, tile.location.y + tile.extent) * tile.extent;
float3 origin = viewToWorld(float4(0, 0, 0, 1)).xyz;
const float offset = 0.0f;
float3 corners[4] = {
screenToWorld(float4(offset, offset, -1.0f, 1.0f)).xyz,
screenToWorld(float4(pViewParams.screenDimensions.x - offset, offset, -1.0f, 1.0f)).xyz,
screenToWorld(float4(offset, pViewParams.screenDimensions.y - offset, -1.0f, 1.0f)).xyz,
screenToWorld(float4(pViewParams.screenDimensions - float2(offset, offset), -1.0f, 1.0f)).xyz
};
Frustum viewFrustum;
viewFrustum.sides[0] = computePlane(origin, corners[2], corners[0]);
viewFrustum.sides[1] = computePlane(origin, corners[1], corners[3]);
viewFrustum.sides[2] = computePlane(origin, corners[0], corners[1]);
viewFrustum.sides[3] = computePlane(origin, corners[3], corners[2]);
if(!bounding.insideFrustum(viewFrustum))
{
return;
}
float3 median = (bounding.minCorner + bounding.maxCorner) / 2;
float distance = distance(median, pViewParams.cameraPos_WS.xyz);
float tileDistance = distance / tile.extent;
uint numMeshes = groupID.y + 1;
if(numMeshes == 4 && tileDistance > 2)
{
return;
}
if(numMeshes == 3 && (tileDistance > 4 || tileDistance < 1))
{
return;
}
if(numMeshes == 2 && (tileDistance > 8 || tileDistance < 3))
{
return;
}
if(numMeshes == 1 && tileDistance < 7)
{
return;
}
TerrainPayload payload;
payload.offset = bounding.minCorner;
payload.extent = tile.extent / numMeshes;
payload.numMeshes = numMeshes;
DispatchMesh(numMeshes, numMeshes, 1, payload);
// Operate the indirection
output.triangleID = pParams.indexedBisectorBuffer[triangle_id];
// Which vertex should be read?
local_vert_id = local_vert_id == 0 ? 2 : (local_vert_id == 2 ? 0 : 1);
float3 positionRWS = pParams.currentVertexBuffer[output.triangleID * 3 + local_vert_id];
// Apply the view projection
output.positionCS = mul(pViewParams.projectionMatrix, mul(pViewParams.viewMatrix, float4(positionRWS, 1.0)));
return output;
}
const static uint64_t TILE_VERTS = 144;
const static uint64_t TILE_PRIMS = 242;
const static float2 VERT[TILE_VERTS] = {float2(0.0f / 11, 0.0f / 11), float2(0.0f / 11, 1.0f / 11), float2(0.0f / 11, 2.0f / 11), float2(0.0f / 11, 3.0f / 11), float2(0.0f / 11, 4.0f / 11), float2(0.0f / 11, 5.0f / 11), float2(0.0f / 11,
6.0f / 11), float2(0.0f / 11, 7.0f / 11), float2(0.0f / 11, 8.0f / 11), float2(0.0f / 11, 9.0f / 11), float2(0.0f / 11, 10.0f / 11), float2(0.0f / 11, 11.0f / 11), float2(1.0f / 11, 0.0f / 11), float2(1.0f / 11, 1.0f / 11), float2(1.0f / 11, 2.0f / 11), float2(1.0f / 11, 3.0f / 11), float2(1.0f /
11, 4.0f / 11), float2(1.0f / 11, 5.0f / 11), float2(1.0f / 11, 6.0f / 11), float2(1.0f / 11, 7.0f / 11), float2(1.0f / 11, 8.0f / 11), float2(1.0f / 11, 9.0f / 11), float2(1.0f / 11, 10.0f / 11), float2(1.0f / 11, 11.0f / 11), float2(2.0f / 11, 0.0f / 11), float2(2.0f / 11, 1.0f / 11), float2(2.0f / 11, 2.0f / 11), float2(2.0f / 11, 3.0f / 11), float2(2.0f / 11, 4.0f / 11), float2(2.0f / 11, 5.0f / 11), float2(2.0f / 11, 6.0f / 11), float2(2.0f / 11, 7.0f / 11), float2(2.0f / 11, 8.0f / 11), float2(2.0f / 11, 9.0f / 11), float2(2.0f / 11, 10.0f / 11), float2(2.0f / 11, 11.0f / 11), float2(3.0f / 11, 0.0f / 11), float2(3.0f / 11, 1.0f / 11), float2(3.0f / 11, 2.0f / 11), float2(3.0f / 11, 3.0f / 11), float2(3.0f / 11, 4.0f / 11), float2(3.0f / 11, 5.0f / 11), float2(3.0f / 11, 6.0f / 11), float2(3.0f / 11, 7.0f / 11), float2(3.0f / 11, 8.0f / 11), float2(3.0f / 11, 9.0f / 11), float2(3.0f / 11, 10.0f / 11), float2(3.0f / 11, 11.0f / 11), float2(4.0f / 11, 0.0f / 11), float2(4.0f
/ 11, 1.0f / 11), float2(4.0f / 11, 2.0f / 11), float2(4.0f / 11, 3.0f / 11), float2(4.0f / 11, 4.0f / 11), float2(4.0f / 11, 5.0f / 11), float2(4.0f / 11, 6.0f / 11), float2(4.0f / 11, 7.0f / 11), float2(4.0f / 11, 8.0f / 11), float2(4.0f / 11, 9.0f / 11), float2(4.0f / 11, 10.0f / 11), float2(4.0f / 11, 11.0f / 11), float2(5.0f / 11, 0.0f / 11), float2(5.0f / 11, 1.0f / 11), float2(5.0f / 11,
2.0f / 11), float2(5.0f / 11, 3.0f / 11), float2(5.0f / 11, 4.0f / 11), float2(5.0f / 11, 5.0f / 11), float2(5.0f / 11, 6.0f / 11), float2(5.0f / 11, 7.0f / 11), float2(5.0f / 11, 8.0f / 11), float2(5.0f / 11, 9.0f / 11), float2(5.0f / 11, 10.0f / 11), float2(5.0f / 11, 11.0f / 11), float2(6.0f /
11, 0.0f / 11), float2(6.0f / 11, 1.0f / 11), float2(6.0f / 11, 2.0f / 11), float2(6.0f / 11, 3.0f / 11), float2(6.0f / 11, 4.0f / 11), float2(6.0f / 11, 5.0f / 11), float2(6.0f / 11, 6.0f / 11), float2(6.0f / 11, 7.0f / 11), float2(6.0f / 11, 8.0f / 11), float2(6.0f / 11, 9.0f / 11), float2(6.0f
/ 11, 10.0f / 11), float2(6.0f / 11, 11.0f / 11), float2(7.0f / 11, 0.0f / 11), float2(7.0f / 11, 1.0f / 11), float2(7.0f / 11, 2.0f / 11), float2(7.0f / 11, 3.0f / 11), float2(7.0f / 11, 4.0f / 11), float2(7.0f / 11, 5.0f / 11), float2(7.0f / 11, 6.0f / 11), float2(7.0f / 11, 7.0f / 11), float2(7.0f / 11, 8.0f / 11), float2(7.0f / 11, 9.0f / 11), float2(7.0f / 11, 10.0f / 11), float2(7.0f / 11, 11.0f / 11), float2(8.0f / 11, 0.0f / 11), float2(8.0f / 11, 1.0f / 11), float2(8.0f / 11, 2.0f / 11), float2(8.0f / 11, 3.0f / 11), float2(8.0f / 11, 4.0f / 11), float2(8.0f / 11, 5.0f / 11), float2(8.0f / 11, 6.0f / 11), float2(8.0f / 11, 7.0f / 11), float2(8.0f / 11, 8.0f / 11), float2(8.0f /
11, 9.0f / 11), float2(8.0f / 11, 10.0f / 11), float2(8.0f / 11, 11.0f / 11), float2(9.0f / 11, 0.0f / 11), float2(9.0f / 11, 1.0f / 11), float2(9.0f / 11, 2.0f / 11), float2(9.0f / 11, 3.0f / 11), float2(9.0f / 11, 4.0f / 11), float2(9.0f / 11, 5.0f / 11), float2(9.0f / 11, 6.0f / 11), float2(9.0f / 11, 7.0f / 11), float2(9.0f / 11, 8.0f / 11), float2(9.0f / 11, 9.0f / 11), float2(9.0f / 11, 10.0f / 11), float2(9.0f / 11, 11.0f / 11), float2(10.0f / 11, 0.0f / 11), float2(10.0f / 11, 1.0f / 11), float2(10.0f / 11, 2.0f / 11), float2(10.0f / 11, 3.0f / 11), float2(10.0f / 11, 4.0f / 11), float2(10.0f / 11, 5.0f / 11), float2(10.0f / 11, 6.0f / 11), float2(10.0f / 11, 7.0f / 11), float2(10.0f / 11, 8.0f / 11), float2(10.0f / 11, 9.0f / 11), float2(10.0f / 11, 10.0f / 11), float2(10.0f / 11, 11.0f / 11), float2(11.0f / 11, 0.0f / 11), float2(11.0f / 11, 1.0f / 11), float2(11.0f / 11, 2.0f / 11), float2(11.0f / 11, 3.0f / 11), float2(11.0f / 11, 4.0f / 11), float2(11.0f / 11, 5.0f / 11), float2(11.0f / 11, 6.0f / 11), float2(11.0f / 11, 7.0f / 11), float2(11.0f / 11, 8.0f / 11), float2(11.0f / 11, 9.0f / 11), float2(11.0f / 11, 10.0f / 11), float2(11.0f / 11, 11.0f / 11)};
const static uint3 IND[TILE_PRIMS] = {uint3(0, 1, 12), uint3(12, 1, 13), uint3(1, 2, 13), uint3(13, 2, 14), uint3(2, 3, 14), uint3(14, 3, 15), uint3(3, 4, 15), uint3(15, 4, 16), uint3(4, 5, 16), uint3(16, 5, 17), uint3(5, 6, 17), uint3(17, 6, 18), uint3(6, 7, 18), uint3(18, 7, 19), uint3(7, 8, 19), uint3(19, 8, 20), uint3(8, 9, 20), uint3(20, 9, 21), uint3(9, 10, 21), uint3(21, 10, 22), uint3(10, 11, 22), uint3(22, 11, 23), uint3(12, 13, 24), uint3(24, 13, 25), uint3(13, 14, 25), uint3(25, 14, 26), uint3(14,
15, 26), uint3(26, 15, 27), uint3(15, 16, 27), uint3(27, 16, 28), uint3(16, 17, 28), uint3(28, 17, 29), uint3(17, 18, 29), uint3(29, 18, 30), uint3(18, 19, 30), uint3(30, 19, 31), uint3(19, 20, 31), uint3(31, 20, 32), uint3(20, 21, 32), uint3(32, 21, 33), uint3(21, 22, 33), uint3(33, 22, 34), uint3(22, 23, 34), uint3(34, 23, 35), uint3(24, 25, 36), uint3(36, 25, 37), uint3(25, 26,
37), uint3(37, 26, 38), uint3(26, 27, 38), uint3(38, 27, 39), uint3(27, 28, 39), uint3(39, 28, 40), uint3(28, 29, 40), uint3(40, 29, 41), uint3(29, 30, 41), uint3(41, 30, 42), uint3(30, 31, 42), uint3(42, 31, 43), uint3(31, 32, 43), uint3(43, 32, 44), uint3(32, 33, 44), uint3(44, 33, 45), uint3(33, 34, 45), uint3(45, 34, 46), uint3(34, 35, 46), uint3(46, 35, 47), uint3(36, 37, 48), uint3(48, 37, 49), uint3(37, 38, 49), uint3(49, 38, 50), uint3(38, 39, 50), uint3(50, 39, 51), uint3(39, 40, 51), uint3(51, 40, 52), uint3(40, 41, 52), uint3(52, 41, 53), uint3(41, 42, 53),
uint3(53, 42, 54), uint3(42, 43, 54), uint3(54, 43, 55), uint3(43, 44, 55), uint3(55, 44, 56), uint3(44, 45, 56), uint3(56, 45, 57), uint3(45, 46, 57), uint3(57, 46, 58), uint3(46, 47, 58), uint3(58, 47, 59), uint3(48, 49, 60), uint3(60, 49, 61), uint3(49, 50, 61), uint3(61, 50, 62), uint3(50, 51, 62), uint3(62, 51, 63), uint3(51, 52, 63), uint3(63, 52, 64), uint3(52, 53, 64), uint3(64, 53, 65), uint3(53, 54, 65), uint3(65, 54, 66), uint3(54, 55, 66), uint3(66, 55, 67), uint3(55, 56, 67), uint3(67, 56, 68), uint3(56, 57, 68), uint3(68, 57, 69), uint3(57, 58, 69), uint3(69, 58, 70), uint3(58, 59, 70), uint3(70, 59, 71), uint3(60, 61, 72), uint3(72, 61, 73), uint3(61, 62, 73), uint3(73, 62, 74), uint3(62, 63, 74), uint3(74, 63, 75), uint3(63, 64, 75), uint3(75, 64, 76), uint3(64, 65, 76), uint3(76, 65, 77), uint3(65, 66, 77), uint3(77, 66, 78), uint3(66, 67, 78), uint3(78, 67, 79), uint3(67, 68, 79), uint3(79, 68, 80), uint3(68, 69, 80), uint3(80, 69, 81), uint3(69, 70, 81), uint3(81, 70, 82), uint3(70, 71, 82), uint3(82, 71, 83), uint3(72,
73, 84), uint3(84, 73, 85), uint3(73, 74, 85), uint3(85, 74, 86), uint3(74, 75, 86), uint3(86, 75, 87), uint3(75, 76, 87), uint3(87, 76, 88), uint3(76, 77, 88), uint3(88, 77, 89), uint3(77, 78, 89), uint3(89, 78, 90), uint3(78, 79, 90), uint3(90, 79, 91), uint3(79, 80, 91), uint3(91, 80, 92), uint3(80, 81, 92), uint3(92, 81, 93), uint3(81, 82, 93), uint3(93, 82, 94), uint3(82, 83,
94), uint3(94, 83, 95), uint3(84, 85, 96), uint3(96, 85, 97), uint3(85, 86, 97), uint3(97, 86, 98), uint3(86, 87, 98), uint3(98, 87, 99), uint3(87, 88, 99), uint3(99, 88, 100), uint3(88, 89, 100), uint3(100, 89, 101), uint3(89, 90, 101), uint3(101, 90, 102), uint3(90, 91, 102), uint3(102, 91, 103), uint3(91, 92, 103), uint3(103, 92, 104), uint3(92, 93, 104), uint3(104, 93, 105), uint3(93, 94, 105), uint3(105, 94, 106), uint3(94, 95, 106), uint3(106, 95, 107), uint3(96, 97, 108), uint3(108, 97, 109), uint3(97, 98, 109), uint3(109, 98, 110), uint3(98, 99, 110), uint3(110, 99, 111), uint3(99, 100, 111), uint3(111, 100, 112), uint3(100, 101, 112), uint3(112, 101, 113), uint3(101, 102, 113), uint3(113, 102, 114), uint3(102, 103, 114), uint3(114, 103, 115), uint3(103, 104, 115), uint3(115, 104, 116), uint3(104, 105, 116), uint3(116, 105, 117), uint3(105, 106, 117), uint3(117, 106, 118), uint3(106, 107, 118), uint3(118, 107, 119), uint3(108, 109, 120), uint3(120, 109, 121), uint3(109, 110, 121), uint3(121, 110, 122), uint3(110, 111, 122), uint3(122, 111,
123), uint3(111, 112, 123), uint3(123, 112, 124), uint3(112, 113, 124), uint3(124, 113, 125), uint3(113, 114, 125), uint3(125, 114, 126), uint3(114, 115, 126), uint3(126, 115, 127), uint3(115, 116, 127), uint3(127, 116, 128), uint3(116, 117, 128), uint3(128, 117, 129), uint3(117, 118, 129), uint3(129, 118, 130), uint3(118, 119, 130), uint3(130, 119, 131), uint3(120, 121, 132), uint3(132, 121, 133), uint3(121, 122, 133), uint3(133, 122, 134), uint3(122, 123, 134), uint3(134, 123, 135), uint3(123, 124, 135), uint3(135, 124, 136), uint3(124, 125, 136), uint3(136, 125, 137), uint3(125, 126, 137), uint3(137, 126, 138), uint3(126, 127, 138), uint3(138, 127, 139), uint3(127, 128, 139), uint3(139, 128, 140), uint3(128, 129, 140), uint3(140, 129, 141), uint3(129, 130, 141), uint3(141, 130, 142), uint3(130, 131, 142), uint3(142, 131, 143)};
[numthreads(MESH_GROUP_SIZE, 1, 1)]
[outputtopology("triangle")]
[shader("mesh")]
void meshMain(
in uint threadID: SV_GroupThreadID,
in uint3 groupID: SV_GroupID,
in payload TerrainPayload params,
out vertices TerrainVertex vertices[TILE_VERTS],
out indices uint3 indices[TILE_PRIMS],
) {
float4x4 vp = mul(pViewParams.projectionMatrix, pViewParams.viewMatrix);
SetMeshOutputCounts(TILE_VERTS, TILE_PRIMS);
for(uint i = threadID; i < TILE_PRIMS; i += MESH_GROUP_SIZE)
{
indices[i] = IND[i];
}
for(uint i = threadID; i < TILE_VERTS; i += MESH_GROUP_SIZE)
{
float2 base = VERT[i];
float3 objectPos = float3(base.x, 0, base.y);
float3 worldPos = params.offset + objectPos * params.extent + float3(groupID.x * params.extent, 0, groupID.y * params.extent);
float lodDisplacement = 0;
float3 camPos = pViewParams.cameraPos_WS.xyz;
float cameraDistance = distance(worldPos, camPos);
float threshold = 0;
if(params.numMeshes == 3)
{
threshold = 10;
}
if(params.numMeshes == 2)
{
threshold = 30;
}
if(params.numMeshes == 1)
{
threshold = 70;
}
if(params.numMeshes < 4)
{
if(cameraDistance > threshold)
{
lodDisplacement = clamp(exp(-(1 / (cameraDistance + threshold))), 0, 1) - 1;
}
else
{
lodDisplacement = -1;
}
}
// float3 displacement1 = pWaterMaterial.displacementTextures.Sample(pWaterMaterial.sampler, float3(worldPos.xz * pWaterMaterial.tile1, 0)).xyz * pWaterMaterial.contributeDisplacement1;
// float3 displacement2 = pWaterMaterial.displacementTextures.Sample(pWaterMaterial.sampler, float3(worldPos.xz * pWaterMaterial.tile2, 1)).xyz * pWaterMaterial.contributeDisplacement2;
// float3 displacement3 = pWaterMaterial.displacementTextures.Sample(pWaterMaterial.sampler, float3(worldPos.xz * pWaterMaterial.tile3, 2)).xyz * pWaterMaterial.contributeDisplacement3;
// float3 displacement4 = pWaterMaterial.displacementTextures.Sample(pWaterMaterial.sampler, float3(worldPos.xz * pWaterMaterial.tile4, 3)).xyz * pWaterMaterial.contributeDisplacement4;
float displacement = pTerrainData.displacement.SampleLevel(pTerrainData.sampler, worldPos.xz / 1000, 0) * 10;
float4 clipPos = mul(vp, float4(worldPos, 1));
float ndcDepth = clipPos.z / clipPos.w;
float depth = 1 - (-ndcDepth + 1.0f) / 2.0f;
// displacement = lerp(0.0f, displacement, pow(saturate(depth), pTerrainData.displacementDepthAttenuation));
worldPos.y += displacement;
worldPos.y += lodDisplacement;
TerrainVertex v;
v.position_WS = worldPos;
v.position_CS = mul(vp, float4(worldPos, 1));
v.texCoord = worldPos.xz;
v.depth = depth;
v.lod = params.numMeshes;
vertices[i] = v;
}
}
// Pixel input
struct PixelInput
{
float4 positionCS : SV_POSITION;
uint triangleID : TRIANGLE_ID;
};
[shader("pixel")]
float4 fragmentMain(TerrainVertex vertex)
float4 frag(PixelInput input) : SV_Target
{
return float4(pTerrainData.colorMap.Sample(pTerrainData.sampler, vertex.position_WS.xz / 1000), 1);
return float4(0, 1, 0, 1);
}
[shader("compute")]
[numthreads(64, 1, 1)]
void deform(uint currentID: SV_DispatchThreadID)
{
if(currentID > pParams.indirectDrawBuffer[9] * 4)
return;
uint bisectorID = currentID / 4;
uint localVertexID = currentID % 4;
bisectorID = pParams.indexedBisectorBuffer[bisectorID];
currentID = localVertexID < 3 ? bisectorID * 3 + localVertexID : 3 * pParams.geometry.totalNumElements + bisectorID;
float3 positionWS = pParams.lebPositionBuffer[currentID];
float3 positionPS = positionWS;
float3 normalPS = float3(0, 1, 0);
float2 sampleUV = float2(0, 0);
pParams.currentVertexBuffer[currentID] = positionWS;
}
+4 -4
View File
@@ -87,7 +87,7 @@ void taskMain(
bounding.minCorner = float3(tile.location.x, tile.height, tile.location.y) * tile.extent;
bounding.maxCorner = float3(tile.location.x + 1, tile.height, tile.location.y + 1) * tile.extent;
float3 median = (bounding.minCorner + bounding.maxCorner) / 2;
float distance = distance(median, pViewParams.cameraPos_WS.xyz);
float distance = distance(median, pViewParams.cameraPosition_WS.xyz);
float tileDistance = distance / tile.extent;
uint numMeshes = groupID.y + 1;
@@ -179,7 +179,7 @@ void meshMain(
float3 worldPos = params.offset + objectPos * params.extent + float3(groupID.x * params.extent, 0, groupID.y * params.extent);
float lodDisplacement = 0;
float3 camPos = pViewParams.ameraPos_WS.xyz;
float3 camPos = pViewParams.cameraPosition_WS.xyz;
float cameraDistance = distance(worldPos, camPos);
float threshold = 0;
if(params.numMeshes == 3)
@@ -207,7 +207,7 @@ void meshMain(
}
}
// TODO: LOD load
float3 displacement1 = pWaterMaterial.displacementTextures.Sample(pWaterMaterial.sampler, float3(worldPos.xz * pWaterMaterial.tile1, 0)).xyz * pWaterMaterial.contributeDisplacement1;
float3 displacement2 = pWaterMaterial.displacementTextures.Sample(pWaterMaterial.sampler, float3(worldPos.xz * pWaterMaterial.tile2, 1)).xyz * pWaterMaterial.contributeDisplacement2;
float3 displacement3 = pWaterMaterial.displacementTextures.Sample(pWaterMaterial.sampler, float3(worldPos.xz * pWaterMaterial.tile3, 2)).xyz * pWaterMaterial.contributeDisplacement3;
@@ -237,7 +237,7 @@ void meshMain(
[shader("pixel")]
float4 fragmentMain(WaterVertex vert) : SV_TARGET {
float3 lightDir = -normalize(pWaterMaterial.sunDirection);
float3 viewDir = normalize(pViewParams.cameraPos_WS.xyz - vert.position_WS);
float3 viewDir = normalize(pViewParams.cameraPosition_WS.xyz - vert.position_WS);
float3 halfwayDir = normalize(lightDir + viewDir);
float depth = vert.depth;
float LdotH = clamp(dot(lightDir, halfwayDir), 0, 1);
+6 -1
View File
@@ -6,12 +6,17 @@ static const uint32_t MESH_GROUP_SIZE = 32;
struct ViewParameter
{
Frustum viewFrustum;
float4x4 viewMatrix;
float4x4 inverseViewMatrix;
float4x4 projectionMatrix;
float4x4 inverseProjection;
float4 cameraPos_WS;
float4 cameraPosition_WS;
float4 cameraForward_WS;
float2 screenDimensions;
float2 invScreenDimensions;
uint frameIndex;
float time;
};
layout(set = 0)
ParameterBlock<ViewParameter> pViewParams;
+1 -1
View File
@@ -51,7 +51,7 @@ struct FragmentParameter
float3x3 tbn = float3x3(normalize(tangent_WS), normalize(biTangent_WS), normalize(normal_WS));
result.tbn = tbn;
result.position_TS = mul(tbn, position_WS);
result.viewDir_TS = mul(tbn, normalize(pViewParams.cameraPos_WS.xyz - position_WS));
result.viewDir_TS = mul(tbn, normalize(pViewParams.cameraPosition_WS.xyz - position_WS));
result.normal_TS = mul(tbn, normal_WS);
return result;
}
+46
View File
@@ -0,0 +1,46 @@
// Pointer to an invalid neighbor or index
const static int INVALID_POINTER = 4294967295;
// Possible culling state
const static int BACK_FACE_CULLED =-3;
const static int FRUSTUM_CULLED =-2;
const static int TOO_SMALL =-1;
const static int UNCHANGED_ELEMENT= 0;
const static int BISECT_ELEMENT= 1;
const static int SIMPLIFY_ELEMENT= 2;
const static int MERGED_ELEMENT= 3;
// Bisector flags
const static int VISIBLE_BISECTOR = 0x1;
const static int MODIFIED_BISECTOR = 0x2;
struct BisectorData
{
// Subvision that should be applied to this bisector
uint32_t subdivisionPattern;
// Allocated indices for this bisector
uint32_t indices[3];
// Neighbor that should be processed
uint32_t problematicNeighbor;
// State of this bisector (split, merge, etc)
uint32_t bisectorState;
// Visibility and modification flags of a bisector
uint32_t flags;
// ID used for the propagation
uint32_t propagationID;
};
uint heapIDDepth(uint64_t x)
{
uint depth = 0;
while (x > 0u) {
++depth;
x >>= 1u;
}
return depth;
}
+617
View File
@@ -0,0 +1,617 @@
import Parameters;
#ifndef WORKGROUP_SIZE
#define WORKGROUP_SIZE 64
#endif
// Num elements
#define OCBT_NUM_ELEMENTS 1048576
// Tree sizes
#define OCBT_TREE_SIZE_BITS (32 * 1 + 32 * 2 + 32 * 4 + 32 * 8 + 32 * 16 + 32 * 32 + 32 * 64 + 16 * 128 + 16 * 256 + 16 * 512 + 16 * 1024 + 16* 2048 + 16 * 4096 + 8 * 8192)
#define OCBT_TREE_NUM_SLOTS (OCBT_TREE_SIZE_BITS / 32)
#define OCBT_BITFIELD_NUM_SLOTS (OCBT_NUM_ELEMENTS / 64)
#define OCBT_LAST_LEVEL_SIZE 8192
// Tree last level
#define TREE_LAST_LEVEL 13
// First virtual level
#define FIRST_VIRTUAL_LEVEL 14
// Leaf level
#define LEAF_LEVEL 20
// per level offset
static const uint32_t OCBT_depth_offset[21] = { 0, // Level 0
32 * 1, // level 1
32 * 1 + 32 * 2, // level 2
32 * 1 + 32 * 2 + 32 * 4, // level 3
32 * 1 + 32 * 2 + 32 * 4 + 32 * 8, // Level 4
32 * 1 + 32 * 2 + 32 * 4 + 32 * 8 + 32 * 16, // Level 5
32 * 1 + 32 * 2 + 32 * 4 + 32 * 8 + 32 * 16 + 32 * 32, // Level 6
32 * 1 + 32 * 2 + 32 * 4 + 32 * 8 + 32 * 16 + 32 * 32 + 32 * 64, // Level 7
32 * 1 + 32 * 2 + 32 * 4 + 32 * 8 + 32 * 16 + 32 * 32 + 32 * 64 + 16 * 128, // Level 8
32 * 1 + 32 * 2 + 32 * 4 + 32 * 8 + 32 * 16 + 32 * 32 + 32 * 64 + 16 * 128 + 16 * 256, // Level 9
32 * 1 + 32 * 2 + 32 * 4 + 32 * 8 + 32 * 16 + 32 * 32 + 32 * 64 + 16 * 128 + 16 * 256 + 16 * 512, // Level 10
32 * 1 + 32 * 2 + 32 * 4 + 32 * 8 + 32 * 16 + 32 * 32 + 32 * 64 + 16 * 128 + 16 * 256 + 16 * 512 + 16 * 1024, // Level 11
32 * 1 + 32 * 2 + 32 * 4 + 32 * 8 + 32 * 16 + 32 * 32 + 32 * 64 + 16 * 128 + 16 * 256 + 16 * 512 + 16 * 1024 + 16 * 2048, // Level 12
32 * 1 + 32 * 2 + 32 * 4 + 32 * 8 + 32 * 16 + 32 * 32 + 32 * 64 + 16 * 128 + 16 * 256 + 16 * 512 + 16 * 1024 + 16 * 2048 + 16 * 4096, // Level 13
0, // Level 14
0, // Level 15
0, // Level 16
0, // Level 17
0, // Level 18
0, // Level 19
0, // Level 20
};
static const uint64_t OCBT_bit_mask[21] = { 0xffffffff, // Root 17
0xffffffff, // Level 16
0xffffffff, // level 15
0xffffffff, // level 14
0xffffffff, // level 13
0xffffffff, // level 12
0xffffffff, // level 11
0xffff, // level 10
0xffff, // level 9
0xffff, // level 8
0xffff, // level 8
0xffff, // level 8
0xffff, // level 8
0xff, // level 8
0xffffffffffffffff, // level 7
0xffffffff, // Level 6
0xffff, // level 5
0xff, // level 4
0xf, // level 3
0x3, // level 2
0x1, // level 1
};
static const uint32_t OCBT_bit_count[21] = { 32, // Root 17
32, // Level 16
32, // level 15
32, // level 14
32, // level 13
32, // level 12
32, // level 11
16, // level 10
16, // level 9
16, // level 8
16, // level 8
16, // level 8
16, // level 8
8, // level 8
64, // Level 5
32, // Level 5
16, // Level 4
8, // level 3
4, // level 2
2, // level 1
1, // level 0
};
// Define the remaining values
#define BUFFER_ELEMENT_PER_LANE ((OCBT_TREE_NUM_SLOTS + WORKGROUP_SIZE - 1) / WORKGROUP_SIZE)
#define BUFFER_ELEMENT_PER_LANE_NO_BITFIELD ((OCBT_TREE_NUM_SLOTS + WORKGROUP_SIZE - 1) / WORKGROUP_SIZE)
#define BITFIELD_ELEMENT_PER_LANE ((OCBT_BITFIELD_NUM_SLOTS + WORKGROUP_SIZE - 1) / WORKGROUP_SIZE)
#define WAVE_TREE_DEPTH uint(log2(OCBT_NUM_ELEMENTS))
uint32_t cbt_size()
{
return OCBT_NUM_ELEMENTS;
}
uint32_t last_level_offset()
{
return OCBT_depth_offset[TREE_LAST_LEVEL] / 32;
}
groupshared uint gs_cbtTree[OCBT_TREE_NUM_SLOTS];
// Function that sets a given bit
void set_bit(uint bitID, bool state)
{
// Coordinates of the bit
uint32_t slot = bitID / 64;
uint32_t local_id = bitID % 64;
if (state)
pParams.bitFieldBuffer[slot] |= 1uLL << local_id;
else
pParams.bitFieldBuffer[slot] &= ~(1uLL << local_id);
}
void set_bit_atomic(uint bitID, bool state)
{
// Coordinates of the bit
uint32_t slot = bitID / 64;
uint32_t local_id = bitID % 64;
if (state)
InterlockedOr(pParams.bitFieldBuffer[slot], 1uLL << local_id);
else
InterlockedAnd(pParams.bitFieldBuffer[slot], ~(1uLL << local_id));
}
uint get_bit(uint bitID)
{
uint32_t slot = bitID / 64;
uint32_t local_id = bitID % 64;
return uint((pParams.bitFieldBuffer[slot] & (1uLL << local_id)) >> local_id);
}
uint get_heap_element(uint id)
{
// Figure out the location of the first bit of this element
uint32_t real_heap_id = id - 1;
uint32_t depth = uint32_t(log2(real_heap_id + 1));
uint32_t level_first_element = (1u << depth) - 1;
uint32_t id_in_level = real_heap_id - level_first_element;
uint32_t first_bit = OCBT_depth_offset[depth] + OCBT_bit_count[depth] * id_in_level;
if (depth < FIRST_VIRTUAL_LEVEL)
{
uint32_t slot = first_bit / 32;
uint32_t local_id = first_bit % 32;
uint32_t target_bits = (gs_cbtTree[slot] >> local_id) & uint32_t(OCBT_bit_mask[depth]);
return (gs_cbtTree[slot] >> local_id) & uint32_t(OCBT_bit_mask[depth]);
}
else
{
uint32_t slot = first_bit / 64;
uint32_t local_id = first_bit % 64;
uint64_t target_bits = (pParams.bitFieldBuffer[slot] >> local_id) & OCBT_bit_mask[depth];
uint32_t high = uint(target_bits >> 32);
uint32_t low = uint(target_bits);
return countbits(high) + countbits(low);
}
}
// Should not be called if depth > TREE_LAST_LEVEL
void set_heap_element(uint id, uint value)
{
// Figure out the location of the first bit of this element
uint real_heap_id = id - 1;
uint depth = uint(log2(real_heap_id + 1));
uint level_first_element = (1u << depth) - 1;
uint first_bit = OCBT_depth_offset[depth] + OCBT_bit_count[depth] * (real_heap_id - level_first_element);
// Find the slot and the local first bit
uint slot = first_bit / 32;
uint local_id = first_bit % 32;
// Extract the relevant bits
gs_cbtTree[slot] &= ~(uint32_t(OCBT_bit_mask[depth]) << local_id);
gs_cbtTree[slot] |= ((uint32_t(OCBT_bit_mask[depth]) & value) << local_id);
}
// Should not be called if depth > TREE_LAST_LEVEL
void set_heap_element_atomic(uint id, uint value)
{
// Figure out the location of the first bit of this element
uint real_heap_id = id - 1;
uint depth = uint(log2(real_heap_id + 1));
uint level_first_element = (1u << depth) - 1;
uint first_bit = OCBT_depth_offset[depth] + OCBT_bit_count[depth] * (real_heap_id - level_first_element);
// Find the slot and the local first bit
uint slot = first_bit / 32;
uint local_id = first_bit % 32;
// Extract the relevant bits
InterlockedAnd(gs_cbtTree[slot], ~(uint32_t(OCBT_bit_mask[depth]) << local_id));
InterlockedOr(gs_cbtTree[slot], ((uint32_t(OCBT_bit_mask[depth]) & value) << local_id));
}
// Function that returns the number of active bits
uint bit_count()
{
return gs_cbtTree[0];
}
uint bit_count(uint depth, uint element)
{
return get_heap_element((1u << depth) + element);
}
// decodes the position of the i-th one in the bitfield
uint decode_bit(uint handle)
{
#if defined(NAIVE_DECODE)
uint bitID = 1;
for (uint currentDepth = 0; currentDepth < WAVE_TREE_DEPTH; ++currentDepth)
{
uint heapValue = get_heap_element(2 * bitID);
uint b = handle < heapValue ? 0 : 1;
bitID = 2 * bitID + b;
handle -= heapValue * b;
}
return (bitID ^ OCBT_NUM_ELEMENTS);
#else
uint currentDepth = 0;
uint heapElementID = 1u;
for (currentDepth = 0; currentDepth < FIRST_VIRTUAL_LEVEL; ++currentDepth)
{
// Read the left element
uint heapValue = get_heap_element(2u * heapElementID);
// Does it fall in the right or left subtree?
uint b = handle < heapValue ? 0u : 1u;
// Pick a subtree
heapElementID = 2u * heapElementID + b;
// Move the iterator to exclude the right subtree if required
handle -= heapValue * b;
}
// Align with the internal depth
currentDepth++;
// Ok we have our subtree, now we need to pick the right bit
uint64_t heapValue = pParams.bitFieldBuffer[heapElementID - OCBT_LAST_LEVEL_SIZE * 2];
uint64_t mask = 0xffffffff;
uint32_t bitCount = 32;
for (; currentDepth < (WAVE_TREE_DEPTH + 1); ++currentDepth)
{
// Figure out the location of the first bit of this element
uint real_heap_id = 2 * heapElementID - 1;
uint level_first_element = (1u << currentDepth) - 1;
uint id_in_level = real_heap_id - level_first_element;
uint first_bit = bitCount * id_in_level;
uint local_id = first_bit % 64;
uint64_t target_bits = (heapValue >> local_id) & mask;
uint32_t high = uint(target_bits >> 32);
uint32_t low = uint(target_bits);
uint heapValue = countbits(high) + countbits(low);
// Does it fall in the right or left subtree?
uint b = handle < heapValue ? 0u : 1u;
// Pick a subtree
heapElementID = 2u * heapElementID + b;
// Move the iterator to exclude the right subtree if required
handle -= heapValue * b;
// Adjust the mask and bitcount
bitCount /= 2;
mask = mask >> bitCount;
}
return (heapElementID ^ OCBT_NUM_ELEMENTS);
#endif
}
// decodes the position of the i-th zero in the bitfield
uint decode_bit_complement(uint handle)
{
#if defined(NAIVE_DECODE)
uint bitID = 1u;
uint c = OCBT_NUM_ELEMENTS / 2u;
while (bitID < OCBT_NUM_ELEMENTS) {
uint heapValue = c - get_heap_element(2u * bitID);
uint b = handle < heapValue ? 0u : 1u;
bitID = 2u * bitID + b;
handle -= heapValue * b;
c /= 2u;
}
return (bitID ^ OCBT_NUM_ELEMENTS);
#else
uint heapElementID = 1u;
uint c = OCBT_NUM_ELEMENTS / 2u;
uint currentDepth = 0;
for (currentDepth = 0; currentDepth < FIRST_VIRTUAL_LEVEL; ++currentDepth)
{
uint heapValue = c - get_heap_element(2u * heapElementID);
uint b = handle < heapValue ? 0u : 1u;
heapElementID = 2u * heapElementID + b;
handle -= heapValue * b;
c /= 2u;
}
// Align with the internal depth
currentDepth++;
// Ok we have our subtree, now we need to pick the right bit
uint64_t heapValue = pParams.bitFieldBuffer[heapElementID - OCBT_LAST_LEVEL_SIZE * 2];
uint64_t mask = 0xffffffff;
uint32_t bitCount = 32;
for (; currentDepth < (WAVE_TREE_DEPTH + 1); ++currentDepth)
{
// Figure out the location of the first bit of this element
uint real_heap_id = 2 * heapElementID - 1;
uint level_first_element = (1u << currentDepth) - 1;
uint id_in_level = real_heap_id - level_first_element;
uint first_bit = bitCount * id_in_level;
uint local_id = first_bit % 64;
uint64_t target_bits = (heapValue >> local_id) & mask;
uint32_t high = uint(target_bits >> 32);
uint32_t low = uint(target_bits);
uint heapValue = c - (countbits(high) + countbits(low));
uint b = handle < heapValue ? 0u : 1u;
heapElementID = 2u * heapElementID + b;
handle -= heapValue * b;
c /= 2u;
// Adjust the mask and bitcount
bitCount /= 2;
mask = mask >> bitCount;
}
return (heapElementID ^ OCBT_NUM_ELEMENTS);
#endif
}
void reduce(uint groupIndex)
{
// First we do a reduction until each lane has exactly one element to process
uint initial_pass_size = OCBT_NUM_ELEMENTS / WORKGROUP_SIZE;
for (uint it = initial_pass_size / 64, offset = OCBT_NUM_ELEMENTS / 64; it > 0 ; it >>=1, offset >>=1)
{
uint minHeapID = offset + (groupIndex * it);
uint maxHeapID = offset + ((groupIndex + 1) * it);
for (uint heapID = minHeapID; heapID < maxHeapID; ++heapID)
{
set_heap_element(heapID, get_heap_element(heapID * 2) + get_heap_element(heapID * 2 + 1));
}
}
GroupMemoryBarrierWithGroupSync();
for(uint s = WORKGROUP_SIZE / 2; s > 0u; s >>= 1)
{
if (groupIndex < s)
{
uint v = s + groupIndex;
set_heap_element(v, get_heap_element(v * 2) + get_heap_element(v * 2 + 1));
}
GroupMemoryBarrierWithGroupSync();
}
}
void reduce_prepass(uint dispatchThreadID)
{
// Initialize the packed sum
uint packedSum = 0;
// Loop through the 4 pairs to process
for (uint pairIdx = 0; pairIdx < 4; ++pairIdx)
{
// First element of the pair
uint64_t target_bits = pParams.bitFieldBuffer[dispatchThreadID * 8 + 2 * pairIdx];
uint32_t high = uint(target_bits >> 32);
uint32_t low = uint(target_bits);
uint elementC = countbits(high) + countbits(low);
// Second element of the pair
target_bits = pParams.bitFieldBuffer[dispatchThreadID * 8 + 2 * pairIdx + 1];
high = uint(target_bits >> 32);
low = uint(target_bits);
elementC += countbits(high) + countbits(low);
// Store in the right bits
packedSum |= (elementC << pairIdx * 8);
}
// Offset of the last level of the tree
const uint bufferOffset = last_level_offset();
// Store the result into the bitfield
pParams.cbtBuffer[bufferOffset + dispatchThreadID] = packedSum;
}
void reduce_first_pass(uint dispatchThreadID, uint groupIndex)
{
// Load the lowest level (and only the last level)
const uint level0Offset = OCBT_depth_offset[TREE_LAST_LEVEL] / 32;
for (uint e = 0; e < 4; ++e)
{
uint target_element = 4 * dispatchThreadID + e;
gs_cbtTree[level0Offset + target_element] = pParams.cbtBuffer[level0Offset + target_element];
}
GroupMemoryBarrierWithGroupSync();
// First we do a reduction until each lane has exactly one element to process
uint initial_pass_size = OCBT_LAST_LEVEL_SIZE / 2;
uint it, offset;
for (it = initial_pass_size / 512, offset = initial_pass_size; it > 1; it >>=1, offset >>=1)
{
uint minHeapID = offset + (dispatchThreadID * it);
uint maxHeapID = offset + ((dispatchThreadID + 1) * it);
for (uint heapID = minHeapID; heapID < maxHeapID; ++heapID)
{
set_heap_element(heapID, get_heap_element(heapID * 2) + get_heap_element(heapID * 2 + 1));
}
}
// Last pass needs to be atomic
uint heapID = offset + (dispatchThreadID * it);
set_heap_element_atomic(heapID, get_heap_element(heapID * 2) + get_heap_element(heapID * 2 + 1));
GroupMemoryBarrierWithGroupSync();
// Load the first reduced level
const uint level2Offset = OCBT_depth_offset[TREE_LAST_LEVEL - 1] / 32;
for (uint e = 0; e < 4; ++e)
{
uint target_element = 4 * dispatchThreadID + e;
pParams.cbtBuffer[level2Offset + target_element] = gs_cbtTree[level2Offset + target_element];
}
// Load the first reduced level
const uint level3Offset = OCBT_depth_offset[TREE_LAST_LEVEL - 2] / 32;
for (uint e = 0; e < 2; ++e)
{
uint target_element = 2 * dispatchThreadID + e;
pParams.cbtBuffer[level3Offset + target_element] = gs_cbtTree[level3Offset + target_element];
}
const uint level4Offset = OCBT_depth_offset[TREE_LAST_LEVEL - 3] / 32;
pParams.cbtBuffer[level4Offset + dispatchThreadID] = gs_cbtTree[level4Offset + dispatchThreadID];
const uint level5Offset = OCBT_depth_offset[TREE_LAST_LEVEL - 4] / 32;
if (groupIndex % 2 == 0)
pParams.cbtBuffer[level5Offset + dispatchThreadID / 2] = gs_cbtTree[level5Offset + dispatchThreadID / 2];
}
void reduce_second_pass(uint groupIndex)
{
// Load the lowest level (and only the last level)
const uint level0Offset = OCBT_depth_offset[9] / 32;
for (uint e = 0; e < 4; ++e)
{
uint target_element = 4 * groupIndex + e;
gs_cbtTree[level0Offset + target_element] = pParams.cbtBuffer[level0Offset + target_element];
}
GroupMemoryBarrierWithGroupSync();
// First we do a reduction until each lane has exactly one element to process
uint initial_pass_size = 256;
for (uint it = initial_pass_size / 64, offset = initial_pass_size; it > 0 ; it >>=1, offset >>=1)
{
uint minHeapID = offset + (groupIndex * it);
uint maxHeapID = offset + ((groupIndex + 1) * it);
for (uint heapID = minHeapID; heapID < maxHeapID; ++heapID)
{
set_heap_element(heapID, get_heap_element(heapID * 2) + get_heap_element(heapID * 2 + 1));
}
}
GroupMemoryBarrierWithGroupSync();
for(uint s = WORKGROUP_SIZE / 2; s > 0u; s >>= 1)
{
if (groupIndex < s)
{
uint v = s + groupIndex;
set_heap_element(v, get_heap_element(v * 2) + get_heap_element(v * 2 + 1));
}
GroupMemoryBarrierWithGroupSync();
}
// Make sure all the previous operations are done
GroupMemoryBarrierWithGroupSync();
// Load the bitfield to the LDS
for (uint e = 0; e < 5; ++e)
{
uint target_element = 5 * groupIndex + e;
if (target_element < 319)
pParams.cbtBuffer[target_element] = gs_cbtTree[target_element];
}
}
void reduce_no_bitfield(uint groupIndex)
{
// First we do a reduction until each lane has exactly one element to process
uint initial_pass_size = OCBT_NUM_ELEMENTS / WORKGROUP_SIZE;
for (uint it = initial_pass_size / 128, offset = OCBT_NUM_ELEMENTS / 128; it > 0 ; it >>=1, offset >>=1)
{
uint minHeapID = offset + (groupIndex * it);
uint maxHeapID = offset + ((groupIndex + 1) * it);
for (uint heapID = minHeapID; heapID < maxHeapID; ++heapID)
{
set_heap_element(heapID, get_heap_element(heapID * 2) + get_heap_element(heapID * 2 + 1));
}
}
GroupMemoryBarrierWithGroupSync();
for(uint s = WORKGROUP_SIZE / 2; s > 0u; s >>= 1)
{
if (groupIndex < s)
{
uint v = s + groupIndex;
set_heap_element(v, get_heap_element(v * 2) + get_heap_element(v * 2 + 1));
}
GroupMemoryBarrierWithGroupSync();
}
}
void clear_cbt(uint groupIndex)
{
for (uint v = 0; v < BUFFER_ELEMENT_PER_LANE; ++v)
{
uint target_element = BUFFER_ELEMENT_PER_LANE * groupIndex + v;
if (target_element < OCBT_TREE_NUM_SLOTS)
gs_cbtTree[target_element] = 0;
}
for (uint b = 0; b < BITFIELD_ELEMENT_PER_LANE; ++b)
{
uint target_element = BITFIELD_ELEMENT_PER_LANE * groupIndex + b;
if (target_element < OCBT_BITFIELD_NUM_SLOTS)
pParams.bitFieldBuffer[target_element] = 0;
}
GroupMemoryBarrierWithGroupSync();
}
// Importante note
// Depending on your target GPU architecture, the pattern used to load has a different performance behavior
// here is the best performant based on our tests:
// NVIDIA uint target_element = groupIndex + WORKGROUP_SIZE * e;
// AMD uint target_element = BUFFER_ELEMENT_PER_LANE * groupIndex + e;
void load_buffer_to_shared_memory(uint groupIndex)
{
// Load the bitfield to the LDS
for (uint e = 0; e < BUFFER_ELEMENT_PER_LANE; ++e)
{
#ifdef AMD
uint target_element = BUFFER_ELEMENT_PER_LANE * groupIndex + e;
#else
uint target_element = groupIndex + WORKGROUP_SIZE * e;
#endif
if (target_element < OCBT_TREE_NUM_SLOTS)
gs_cbtTree[target_element] = pParams.cbtBuffer[target_element];
}
GroupMemoryBarrierWithGroupSync();
}
void load_shared_memory_to_buffer(uint groupIndex)
{
// Make sure all the previous operations are done
GroupMemoryBarrierWithGroupSync();
// Load the bitfield to the LDS
for (uint e = 0; e < BUFFER_ELEMENT_PER_LANE; ++e)
{
#ifdef AMD
uint target_element = BUFFER_ELEMENT_PER_LANE * groupIndex + e;
#else
uint target_element = groupIndex + WORKGROUP_SIZE * e;
#endif
if (target_element < OCBT_TREE_NUM_SLOTS)
pParams.cbtBuffer[target_element] = gs_cbtTree[target_element];
}
}
void set_bit_atomic_buffer(uint bitID, bool state)
{
// Coordinates of the bit
uint32_t slot = bitID / 64;
uint32_t local_id = bitID % 64;
if (state)
InterlockedOr(pParams.bitFieldBuffer[slot], 1uLL << local_id);
else
InterlockedAnd(pParams.bitFieldBuffer[slot], ~(1uLL << local_id));
}
uint32_t bit_count_buffer()
{
return pParams.cbtBuffer[0];
}
File diff suppressed because it is too large Load Diff
+56
View File
@@ -0,0 +1,56 @@
import Common;
import Bisector;
struct GeometryCB
{
uint32_t totalNumElements;
uint32_t baseDepth;
uint32_t totalNumVertices;
};
struct DeformationCB
{
float4 patchSize;
float4 patchRoughness;
float choppiness;
int attenuation;
float amplification;
uint32_t patchFlags;
};
struct UpdateCB
{
float triangleSize;
uint32_t maxSubdivisionDepth;
float fov;
float farPlaneDistance;
}
struct ComputeParams
{
ConstantBuffer<GeometryCB> geometry;
ConstantBuffer<UpdateCB> update;
RWStructuredBuffer<float3> currentVertexBuffer;
StructuredBuffer<uint> indexedBisectorBuffer;
RWStructuredBuffer<uint> indirectDrawBuffer;
RWStructuredBuffer<uint64_t> heapIDBuffer;
RWStructuredBuffer<BisectorData> bisectorDataBuffer;
RWStructuredBuffer<uint> classificationBuffer;
RWStructuredBuffer<int> allocateBuffer;
RWStructuredBuffer<uint> indirectDispatchBuffer;
RWStructuredBuffer<uint3> neighboursBuffer;
RWStructuredBuffer<uint3> neighboursOutputBuffer;
RWStructuredBuffer<int> memoryBuffer;
RWStructuredBuffer<uint> cbtBuffer;
RWStructuredBuffer<uint64_t> bitFieldBuffer;
RWStructuredBuffer<int> propagateBuffer;
RWStructuredBuffer<uint> simplifyBuffer;
RWStructuredBuffer<uint> validationBuffer;
RWStructuredBuffer<uint> bisectorIndicesBuffer;
RWStructuredBuffer<uint> visibleBisectorIndices;
RWStructuredBuffer<uint> modifiedBisectorIndices;
RWStructuredBuffer<float3> lebPositionBuffer;
StructuredBuffer<float3x3> lebMatrixCache;
};
ParameterBlock<ComputeParams> pParams;