wip(standalone): GPU field step 2 -- far-field shapes/strata/relief in shared C++/HLSL, GPU field+mesh

Seven LOD2-8 tiles: RX 7900 XTX field+meshing 0.335 ms vs CPU generateTile 15.81 ms; repeat runs
bit-identical; CPU W1/W8 44/44 hashes unchanged. Not yet a real gain: rock/air signs still come from
CPU masks for every sample. Viewer does not draw GPU tiles yet; no whole-view timing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ
This commit is contained in:
Fr0zkaandClaude Opus 5.5 committed 2026-10-06 08:02:02 +02:00
1 parent d4b4377d30
commit b61ccff549
11 files changed
+2361 -9

No files matched your search

@@ -126,6 +126,73 @@ RWStructuredBuffer<uint> CellCases : register(u0);
RWStructuredBuffer<uint> CellLocalOffsets : register(u1);
RWStructuredBuffer<uint> GroupVertexCounts : register(u2);
struct FarFieldSampleRange { uint offset; uint count; };
StructuredBuffer<VF_FieldPrimitive> FarShapes : register(t10);
StructuredBuffer<FarFieldSampleRange> FarSampleShapeRanges : register(t11);
StructuredBuffer<uint> FarSampleShapeIds : register(t12);
StructuredBuffer<uint> FarRockAirSigns : register(t13);
StructuredBuffer<uint> FarProtectedAir : register(t14);
RWStructuredBuffer<float> FarFieldDensity : register(u7);
cbuffer FarFieldConstants : register(b1)
{
float FarStrataLo;
float FarStrataHi;
float FarStrataBlend;
uint FarSampleCount;
};
[numthreads(64,1,1)]
void EvaluateFarFieldCS(uint3 dispatchId : SV_DispatchThreadID)
{
const uint index = dispatchId.x;
if (index >= FarSampleCount) return;
const uint x = index % SampleDim;
const uint y = (index / SampleDim) % SampleDim;
const uint z = index / (SampleDim * SampleDim);
const float3 position = float3(OriginX, OriginY, OriginZ)
+ float3(int(x) - 1, int(y) - 1, int(z) - 1) * StepVoxels;
const FarFieldSampleRange range = FarSampleShapeRanges[index];
float cave = 100000.0f;
float overlay = -100000.0f;
[loop]
for (uint item = 0; item < range.count; ++item)
{
const VF_FieldPrimitive shape = FarShapes[FarSampleShapeIds[range.offset + item]];
if ((shape.flags & VF_FIELD_PRIMITIVE_CARVE) != 0)
{
if (position.x < shape.minVoxel[0] - 6 || position.x > shape.maxVoxel[0] + 6
|| position.y < shape.minVoxel[1] - 6 || position.y > shape.maxVoxel[1] + 6
|| position.z < shape.minVoxel[2] - 6 || position.z > shape.maxVoxel[2] + 6)
continue;
float distance = VF_FieldPrimitiveDistance(shape,
position.x, position.y, position.z);
if ((shape.flags & VF_FIELD_PRIMITIVE_HAS_FLOOR) != 0)
{
const float floorZ = VF_FieldPrimitiveFloorAt(shape, position.x, position.y);
distance = VF_FieldSmoothMax(distance, floorZ - position.z,
shape.floorBlendRadius);
}
cave = VF_FieldSmoothMin(cave, distance, shape.blendRadius);
}
else if (position.x >= shape.minVoxel[0] && position.x <= shape.maxVoxel[0]
&& position.y >= shape.minVoxel[1] && position.y <= shape.maxVoxel[1]
&& position.z >= shape.minVoxel[2] && position.z <= shape.maxVoxel[2])
{
overlay = max(overlay, -VF_FieldPrimitiveDistance(shape,
position.x, position.y, position.z));
}
}
const float base = min(position.z - FarStrataLo, FarStrataHi - position.z);
float rockDistance = VF_FieldSmoothMin(base, max(cave, overlay), FarStrataBlend);
const uint protectedAir = (FarProtectedAir[index >> 5] >> (index & 31)) & 1;
if (protectedAir != 0) rockDistance = min(rockDistance, -0.0625f);
const float rawDensity = -rockDistance;
const uint air = (FarRockAirSigns[index >> 5] >> (index & 31)) & 1;
const float magnitude = max(abs(rawDensity), 0.05f);
FarFieldDensity[index] = air != 0 ? magnitude : -magnitude;
}
groupshared uint ScanValues[256];
[numthreads(256,1,1)]