Phase 5.1: Naive Surface Nets smooth rendering
Implement CPU-side Naive Surface Nets for smooth voxel surfaces (SmoothStone,
Snow) coexisting with blocky voxels (Grass, Dirt, Stone, Sand).
Key features:
- SmoothMesher with binary SDF, centroid vertex placement, per-axis boundary
clamping to align with blocky grid at smooth↔blocky transitions
- Cross-chunk connectivity: PAD=2 SDF grid, vertex range [-1, CHUNK_SIZE),
canonical edge ownership (no duplicate triangles, no z-fighting)
- Face normals oriented by edge axis+sign (robust with binary SDF, unlike
SDF gradient dot or centroid sampling approaches)
- Y-axis winding fix: sharing cells have different spatial arrangement,
requiring opposite winding from X and Z axes
- GPU mesher treats smooth neighbors as solid (no blocky faces toward smooth)
- Material blending: primary (smooth-only) + secondary (all counts) per vertex
- Dedicated shaders: voxelSmoothVS (vertex pulling t6) + voxelSmoothPS
(triplanar + lerp blending between two materials)
- Separate render pass with LoadOp::LOAD after voxels+topings
- New materials: SmoothStone (mat 6), blocky Stone (mat 3) and Dirt patches
added to world generation for boundary testing
2026-03-27 13:03:55 +01:00
|
|
|
// BVLE Voxels - Smooth Surface Nets Pixel Shader (Phase 5.1)
|
2026-03-27 14:21:35 +01:00
|
|
|
// Per-pixel heightmap blending using the SAME neighbor verification as voxelPS.hlsl.
|
|
|
|
|
// Derives a dominant face axis from the smooth normal, then uses identical
|
|
|
|
|
// faceU/faceV/stair-priority logic as the blocky pixel shader.
|
Phase 5.1: Naive Surface Nets smooth rendering
Implement CPU-side Naive Surface Nets for smooth voxel surfaces (SmoothStone,
Snow) coexisting with blocky voxels (Grass, Dirt, Stone, Sand).
Key features:
- SmoothMesher with binary SDF, centroid vertex placement, per-axis boundary
clamping to align with blocky grid at smooth↔blocky transitions
- Cross-chunk connectivity: PAD=2 SDF grid, vertex range [-1, CHUNK_SIZE),
canonical edge ownership (no duplicate triangles, no z-fighting)
- Face normals oriented by edge axis+sign (robust with binary SDF, unlike
SDF gradient dot or centroid sampling approaches)
- Y-axis winding fix: sharing cells have different spatial arrangement,
requiring opposite winding from X and Z axes
- GPU mesher treats smooth neighbors as solid (no blocky faces toward smooth)
- Material blending: primary (smooth-only) + secondary (all counts) per vertex
- Dedicated shaders: voxelSmoothVS (vertex pulling t6) + voxelSmoothPS
(triplanar + lerp blending between two materials)
- Separate render pass with LoadOp::LOAD after voxels+topings
- New materials: SmoothStone (mat 6), blocky Stone (mat 3) and Dirt patches
added to world generation for boundary testing
2026-03-27 13:03:55 +01:00
|
|
|
|
|
|
|
|
#include "voxelCommon.hlsli"
|
|
|
|
|
|
|
|
|
|
Texture2DArray<float4> materialTextures : register(t1);
|
2026-03-27 14:21:35 +01:00
|
|
|
StructuredBuffer<GPUChunkInfo> chunkInfoBuffer : register(t2);
|
|
|
|
|
StructuredBuffer<uint> voxelData : register(t3);
|
Phase 5.1: Naive Surface Nets smooth rendering
Implement CPU-side Naive Surface Nets for smooth voxel surfaces (SmoothStone,
Snow) coexisting with blocky voxels (Grass, Dirt, Stone, Sand).
Key features:
- SmoothMesher with binary SDF, centroid vertex placement, per-axis boundary
clamping to align with blocky grid at smooth↔blocky transitions
- Cross-chunk connectivity: PAD=2 SDF grid, vertex range [-1, CHUNK_SIZE),
canonical edge ownership (no duplicate triangles, no z-fighting)
- Face normals oriented by edge axis+sign (robust with binary SDF, unlike
SDF gradient dot or centroid sampling approaches)
- Y-axis winding fix: sharing cells have different spatial arrangement,
requiring opposite winding from X and Z axes
- GPU mesher treats smooth neighbors as solid (no blocky faces toward smooth)
- Material blending: primary (smooth-only) + secondary (all counts) per vertex
- Dedicated shaders: voxelSmoothVS (vertex pulling t6) + voxelSmoothPS
(triplanar + lerp blending between two materials)
- Separate render pass with LoadOp::LOAD after voxels+topings
- New materials: SmoothStone (mat 6), blocky Stone (mat 3) and Dirt patches
added to world generation for boundary testing
2026-03-27 13:03:55 +01:00
|
|
|
SamplerState texSampler : register(s0);
|
|
|
|
|
|
|
|
|
|
struct PSInput {
|
|
|
|
|
float4 position : SV_POSITION;
|
|
|
|
|
float3 worldPos : WORLDPOS;
|
|
|
|
|
float3 normal : NORMAL;
|
2026-03-27 14:21:35 +01:00
|
|
|
nointerpolation uint primaryMat : PRIMARYMAT;
|
|
|
|
|
nointerpolation uint chunkIndex : CHUNKINDEX;
|
Phase 5.1: Naive Surface Nets smooth rendering
Implement CPU-side Naive Surface Nets for smooth voxel surfaces (SmoothStone,
Snow) coexisting with blocky voxels (Grass, Dirt, Stone, Sand).
Key features:
- SmoothMesher with binary SDF, centroid vertex placement, per-axis boundary
clamping to align with blocky grid at smooth↔blocky transitions
- Cross-chunk connectivity: PAD=2 SDF grid, vertex range [-1, CHUNK_SIZE),
canonical edge ownership (no duplicate triangles, no z-fighting)
- Face normals oriented by edge axis+sign (robust with binary SDF, unlike
SDF gradient dot or centroid sampling approaches)
- Y-axis winding fix: sharing cells have different spatial arrangement,
requiring opposite winding from X and Z axes
- GPU mesher treats smooth neighbors as solid (no blocky faces toward smooth)
- Material blending: primary (smooth-only) + secondary (all counts) per vertex
- Dedicated shaders: voxelSmoothVS (vertex pulling t6) + voxelSmoothPS
(triplanar + lerp blending between two materials)
- Separate render pass with LoadOp::LOAD after voxels+topings
- New materials: SmoothStone (mat 6), blocky Stone (mat 3) and Dirt patches
added to world generation for boundary testing
2026-03-27 13:03:55 +01:00
|
|
|
};
|
|
|
|
|
|
2026-03-27 14:21:35 +01:00
|
|
|
static const uint CSIZE = 32;
|
|
|
|
|
static const uint CVOL = CSIZE * CSIZE * CSIZE;
|
|
|
|
|
|
|
|
|
|
// ── Face direction tables (SAME as voxelPS.hlsl) ────────────────
|
|
|
|
|
// Face normals: +X, -X, +Y, -Y, +Z, -Z
|
|
|
|
|
static const int3 faceNormals[6] = {
|
|
|
|
|
int3( 1, 0, 0), int3(-1, 0, 0),
|
|
|
|
|
int3( 0, 1, 0), int3( 0,-1, 0),
|
|
|
|
|
int3( 0, 0, 1), int3( 0, 0,-1)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Face tangent axes (U, V) — must match voxelPS.hlsl
|
|
|
|
|
static const int3 faceUDirs[6] = {
|
|
|
|
|
int3(0, 1, 0), int3(0, 1, 0),
|
|
|
|
|
int3(1, 0, 0), int3(1, 0, 0),
|
|
|
|
|
int3(1, 0, 0), int3(1, 0, 0)
|
|
|
|
|
};
|
|
|
|
|
static const int3 faceVDirs[6] = {
|
|
|
|
|
int3(0, 0, 1), int3(0, 0, 1),
|
|
|
|
|
int3(0, 0, 1), int3(0, 0, 1),
|
|
|
|
|
int3(0, 1, 0), int3(0, 1, 0)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// ── Voxel data read (same as voxelPS.hlsl) ───────────────────────
|
|
|
|
|
uint readVoxelMat(int3 coord, uint chunkIdx) {
|
|
|
|
|
GPUChunkInfo info = chunkInfoBuffer[chunkIdx];
|
|
|
|
|
int3 local = coord - (int3)info.worldPos.xyz;
|
|
|
|
|
if (any(local < 0) || any(local >= (int3)CSIZE))
|
|
|
|
|
return 0;
|
|
|
|
|
uint flatIdx = (uint)local.x + (uint)local.y * CSIZE + (uint)local.z * CSIZE * CSIZE;
|
|
|
|
|
uint pairIndex = flatIdx >> 1;
|
|
|
|
|
uint shift = (flatIdx & 1) * 16;
|
|
|
|
|
uint voxel = (voxelData[chunkIdx * (CVOL / 2) + pairIndex] >> shift) & 0xFFFF;
|
|
|
|
|
return voxel >> 8;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ── Stair-priority neighbor lookup (SAME as voxelPS.hlsl) ────────
|
|
|
|
|
uint getNeighborMat(int3 voxelCoord, int3 edgeDir, int3 normalDir, uint chunkIdx) {
|
|
|
|
|
// Stair neighbor (priority): block at edge AND offset by normal
|
|
|
|
|
int3 stairPos = voxelCoord + edgeDir + normalDir;
|
|
|
|
|
uint stairMat = readVoxelMat(stairPos, chunkIdx);
|
|
|
|
|
if (stairMat > 0)
|
|
|
|
|
return stairMat;
|
|
|
|
|
|
|
|
|
|
// Planar neighbor (fallback): adjacent block in face plane
|
|
|
|
|
int3 planarPos = voxelCoord + edgeDir;
|
|
|
|
|
return readVoxelMat(planarPos, chunkIdx);
|
Phase 5.1: Naive Surface Nets smooth rendering
Implement CPU-side Naive Surface Nets for smooth voxel surfaces (SmoothStone,
Snow) coexisting with blocky voxels (Grass, Dirt, Stone, Sand).
Key features:
- SmoothMesher with binary SDF, centroid vertex placement, per-axis boundary
clamping to align with blocky grid at smooth↔blocky transitions
- Cross-chunk connectivity: PAD=2 SDF grid, vertex range [-1, CHUNK_SIZE),
canonical edge ownership (no duplicate triangles, no z-fighting)
- Face normals oriented by edge axis+sign (robust with binary SDF, unlike
SDF gradient dot or centroid sampling approaches)
- Y-axis winding fix: sharing cells have different spatial arrangement,
requiring opposite winding from X and Z axes
- GPU mesher treats smooth neighbors as solid (no blocky faces toward smooth)
- Material blending: primary (smooth-only) + secondary (all counts) per vertex
- Dedicated shaders: voxelSmoothVS (vertex pulling t6) + voxelSmoothPS
(triplanar + lerp blending between two materials)
- Separate render pass with LoadOp::LOAD after voxels+topings
- New materials: SmoothStone (mat 6), blocky Stone (mat 3) and Dirt patches
added to world generation for boundary testing
2026-03-27 13:03:55 +01:00
|
|
|
}
|
|
|
|
|
|
2026-03-27 14:21:35 +01:00
|
|
|
// ── Triplanar helpers ────────────────────────────────────────────
|
|
|
|
|
float3 triplanarWeights(float3 n, float sharpness) {
|
|
|
|
|
float3 w = abs(n);
|
|
|
|
|
w = pow(w, (float3)sharpness);
|
|
|
|
|
return w / (w.x + w.y + w.z + 0.0001);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float3 sampleTriplanar(float3 wp, float3 n, uint texIdx, float tiling) {
|
|
|
|
|
float3 w = triplanarWeights(n, 4.0);
|
|
|
|
|
float3 cx = materialTextures.Sample(texSampler, float3(wp.yz * tiling, (float)texIdx)).rgb;
|
|
|
|
|
float3 cy = materialTextures.Sample(texSampler, float3(wp.xz * tiling, (float)texIdx)).rgb;
|
|
|
|
|
float3 cz = materialTextures.Sample(texSampler, float3(wp.xy * tiling, (float)texIdx)).rgb;
|
|
|
|
|
return cx * w.x + cy * w.y + cz * w.z;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float4 sampleTriplanarRGBA(float3 wp, float3 n, uint texIdx, float tiling) {
|
|
|
|
|
float3 w = triplanarWeights(n, 4.0);
|
|
|
|
|
float4 cx = materialTextures.Sample(texSampler, float3(wp.yz * tiling, (float)texIdx));
|
|
|
|
|
float4 cy = materialTextures.Sample(texSampler, float3(wp.xz * tiling, (float)texIdx));
|
|
|
|
|
float4 cz = materialTextures.Sample(texSampler, float3(wp.xy * tiling, (float)texIdx));
|
|
|
|
|
return cx * w.x + cy * w.y + cz * w.z;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-28 14:48:11 +01:00
|
|
|
// ── MRT Output ──────────────────────────────────────────────────
|
|
|
|
|
struct PSOutput {
|
|
|
|
|
float4 color : SV_TARGET0;
|
|
|
|
|
float4 normal : SV_TARGET1;
|
|
|
|
|
};
|
|
|
|
|
|
2026-03-27 14:21:35 +01:00
|
|
|
// ── Main PS ──────────────────────────────────────────────────────
|
Phase 5.1: Naive Surface Nets smooth rendering
Implement CPU-side Naive Surface Nets for smooth voxel surfaces (SmoothStone,
Snow) coexisting with blocky voxels (Grass, Dirt, Stone, Sand).
Key features:
- SmoothMesher with binary SDF, centroid vertex placement, per-axis boundary
clamping to align with blocky grid at smooth↔blocky transitions
- Cross-chunk connectivity: PAD=2 SDF grid, vertex range [-1, CHUNK_SIZE),
canonical edge ownership (no duplicate triangles, no z-fighting)
- Face normals oriented by edge axis+sign (robust with binary SDF, unlike
SDF gradient dot or centroid sampling approaches)
- Y-axis winding fix: sharing cells have different spatial arrangement,
requiring opposite winding from X and Z axes
- GPU mesher treats smooth neighbors as solid (no blocky faces toward smooth)
- Material blending: primary (smooth-only) + secondary (all counts) per vertex
- Dedicated shaders: voxelSmoothVS (vertex pulling t6) + voxelSmoothPS
(triplanar + lerp blending between two materials)
- Separate render pass with LoadOp::LOAD after voxels+topings
- New materials: SmoothStone (mat 6), blocky Stone (mat 3) and Dirt patches
added to world generation for boundary testing
2026-03-27 13:03:55 +01:00
|
|
|
[RootSignature(VOXEL_ROOTSIG)]
|
2026-03-28 14:48:11 +01:00
|
|
|
PSOutput main(PSInput input) {
|
|
|
|
|
PSOutput output;
|
2026-03-27 15:08:35 +01:00
|
|
|
float3 N = normalize(input.normal); // smooth normal (for lighting)
|
|
|
|
|
|
|
|
|
|
// Geometric normal from screen-space derivatives of worldPos.
|
|
|
|
|
// This is the true triangle face normal — use it for triplanar weights
|
|
|
|
|
// to avoid texture stretching caused by smooth normal interpolation.
|
|
|
|
|
float3 dpx = ddx(input.worldPos);
|
|
|
|
|
float3 dpy = ddy(input.worldPos);
|
|
|
|
|
float3 geoN = normalize(cross(dpx, dpy));
|
|
|
|
|
// Ensure geometric normal faces same hemisphere as smooth normal
|
|
|
|
|
if (dot(geoN, N) < 0.0) geoN = -geoN;
|
|
|
|
|
|
Phase 5.1: Naive Surface Nets smooth rendering
Implement CPU-side Naive Surface Nets for smooth voxel surfaces (SmoothStone,
Snow) coexisting with blocky voxels (Grass, Dirt, Stone, Sand).
Key features:
- SmoothMesher with binary SDF, centroid vertex placement, per-axis boundary
clamping to align with blocky grid at smooth↔blocky transitions
- Cross-chunk connectivity: PAD=2 SDF grid, vertex range [-1, CHUNK_SIZE),
canonical edge ownership (no duplicate triangles, no z-fighting)
- Face normals oriented by edge axis+sign (robust with binary SDF, unlike
SDF gradient dot or centroid sampling approaches)
- Y-axis winding fix: sharing cells have different spatial arrangement,
requiring opposite winding from X and Z axes
- GPU mesher treats smooth neighbors as solid (no blocky faces toward smooth)
- Material blending: primary (smooth-only) + secondary (all counts) per vertex
- Dedicated shaders: voxelSmoothVS (vertex pulling t6) + voxelSmoothPS
(triplanar + lerp blending between two materials)
- Separate render pass with LoadOp::LOAD after voxels+topings
- New materials: SmoothStone (mat 6), blocky Stone (mat 3) and Dirt patches
added to world generation for boundary testing
2026-03-27 13:03:55 +01:00
|
|
|
float tiling = textureTiling;
|
|
|
|
|
|
2026-03-27 14:21:35 +01:00
|
|
|
// ── Derive dominant face from smooth normal (same tables as blocky PS) ──
|
|
|
|
|
// Find the axis with the largest absolute normal component
|
|
|
|
|
float3 absN = abs(N);
|
|
|
|
|
uint dominantAxis;
|
|
|
|
|
if (absN.x >= absN.y && absN.x >= absN.z)
|
|
|
|
|
dominantAxis = 0; // X
|
|
|
|
|
else if (absN.y >= absN.z)
|
|
|
|
|
dominantAxis = 1; // Y
|
|
|
|
|
else
|
|
|
|
|
dominantAxis = 2; // Z
|
|
|
|
|
|
|
|
|
|
// Map to face index: axis*2 + (negative ? 1 : 0)
|
|
|
|
|
uint face = dominantAxis * 2;
|
|
|
|
|
if (N[dominantAxis] < 0.0) face += 1;
|
|
|
|
|
|
|
|
|
|
int3 normalDir = faceNormals[face];
|
|
|
|
|
int3 uDir = faceUDirs[face];
|
|
|
|
|
int3 vDir = faceVDirs[face];
|
|
|
|
|
|
|
|
|
|
// ── Compute voxel coordinate (SAME as blocky PS) ──
|
|
|
|
|
// Tiny offset inward along dominant normal to handle integer boundaries
|
|
|
|
|
float3 samplePos = input.worldPos - (float3)normalDir * 0.001;
|
|
|
|
|
int3 voxelCoord = (int3)floor(samplePos);
|
|
|
|
|
|
|
|
|
|
// Read actual material at this voxel position
|
|
|
|
|
uint selfMat = readVoxelMat(voxelCoord, input.chunkIndex);
|
|
|
|
|
if (selfMat == 0u) selfMat = input.primaryMat; // air fallback
|
|
|
|
|
|
|
|
|
|
// ── Face-aligned fractional position (SAME as blocky PS) ──
|
|
|
|
|
float faceFracU = frac(dot(input.worldPos, (float3)uDir));
|
|
|
|
|
float faceFracV = frac(dot(input.worldPos, (float3)vDir));
|
|
|
|
|
|
|
|
|
|
// Distance from nearest edge (0 = at edge, 0.5 = at center)
|
|
|
|
|
float uDist = 0.5 - abs(faceFracU - 0.5);
|
|
|
|
|
float vDist = 0.5 - abs(faceFracV - 0.5);
|
|
|
|
|
|
|
|
|
|
// Nearest edge direction
|
|
|
|
|
int uSign = (faceFracU >= 0.5) ? 1 : -1;
|
|
|
|
|
int vSign = (faceFracV >= 0.5) ? 1 : -1;
|
|
|
|
|
int3 uEdgeDir = uDir * uSign;
|
|
|
|
|
int3 vEdgeDir = vDir * vSign;
|
|
|
|
|
|
|
|
|
|
// ── Stair-priority neighbor lookup (SAME as blocky PS) ──
|
|
|
|
|
uint uNeighborMat = getNeighborMat(voxelCoord, uEdgeDir, normalDir, input.chunkIndex);
|
|
|
|
|
uint vNeighborMat = getNeighborMat(voxelCoord, vEdgeDir, normalDir, input.chunkIndex);
|
|
|
|
|
|
|
|
|
|
// ── Blend weights (SAME params as blocky PS) ──
|
|
|
|
|
float blendZone = 0.25;
|
|
|
|
|
float uEdge = abs(faceFracU - 0.5) * 2.0;
|
|
|
|
|
float vEdge = abs(faceFracV - 0.5) * 2.0;
|
|
|
|
|
|
|
|
|
|
// Corner attenuation — subtractive (same as blocky PS)
|
|
|
|
|
float blendStart = 1.0 - blendZone * 2.0;
|
|
|
|
|
float uAdj = uEdge - saturate(vEdge - 0.80);
|
|
|
|
|
float vAdj = vEdge - saturate(uEdge - 0.80);
|
|
|
|
|
float uWeight = saturate((uAdj - blendStart) / (1.0 - blendStart)) * 0.5;
|
|
|
|
|
float vWeight = saturate((vAdj - blendStart) / (1.0 - blendStart)) * 0.5;
|
|
|
|
|
|
|
|
|
|
// Blend conditions (same as blocky PS, with bleed mask checks)
|
|
|
|
|
bool mainResists = (resistBleedMask >> selfMat) & 1u;
|
|
|
|
|
bool uNeighCanBleed = (bleedMask >> uNeighborMat) & 1u;
|
|
|
|
|
bool vNeighCanBleed = (bleedMask >> vNeighborMat) & 1u;
|
|
|
|
|
bool uBlend = (uNeighborMat > 0u && uNeighborMat != selfMat && uWeight > 0.001
|
|
|
|
|
&& !mainResists && uNeighCanBleed);
|
|
|
|
|
bool vBlend = (vNeighborMat > 0u && vNeighborMat != selfMat && vWeight > 0.001
|
|
|
|
|
&& !mainResists && vNeighCanBleed);
|
|
|
|
|
|
|
|
|
|
// ── Texturing ──
|
|
|
|
|
uint selfTexIdx = clamp(selfMat - 1u, 0u, 5u);
|
|
|
|
|
float3 albedo;
|
|
|
|
|
|
|
|
|
|
if (uBlend || vBlend) {
|
2026-03-27 15:08:35 +01:00
|
|
|
float4 mainTex = sampleTriplanarRGBA(input.worldPos, geoN, selfTexIdx, tiling);
|
2026-03-27 14:21:35 +01:00
|
|
|
float3 result = mainTex.rgb;
|
|
|
|
|
float sharpness = 16.0;
|
|
|
|
|
|
|
|
|
|
if (uBlend) {
|
|
|
|
|
uint uTexIdx = clamp(uNeighborMat - 1u, 0u, 5u);
|
2026-03-27 15:08:35 +01:00
|
|
|
float4 uTex = sampleTriplanarRGBA(input.worldPos, geoN, uTexIdx, tiling);
|
2026-03-27 14:21:35 +01:00
|
|
|
float bias = 0.5 - uWeight;
|
|
|
|
|
float mainScore = mainTex.a + bias;
|
|
|
|
|
float neighScore = uTex.a - bias;
|
|
|
|
|
float blend = saturate((neighScore - mainScore) * sharpness + 0.5);
|
|
|
|
|
result = lerp(result, uTex.rgb, blend);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (vBlend) {
|
|
|
|
|
uint vTexIdx = clamp(vNeighborMat - 1u, 0u, 5u);
|
2026-03-27 15:08:35 +01:00
|
|
|
float4 vTex = sampleTriplanarRGBA(input.worldPos, geoN, vTexIdx, tiling);
|
2026-03-27 14:21:35 +01:00
|
|
|
float bias = 0.5 - vWeight;
|
|
|
|
|
float mainScore = mainTex.a + bias;
|
|
|
|
|
float neighScore = vTex.a - bias;
|
|
|
|
|
float blend = saturate((neighScore - mainScore) * sharpness + 0.5);
|
|
|
|
|
result = lerp(result, vTex.rgb, blend);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
albedo = result;
|
Phase 5.1: Naive Surface Nets smooth rendering
Implement CPU-side Naive Surface Nets for smooth voxel surfaces (SmoothStone,
Snow) coexisting with blocky voxels (Grass, Dirt, Stone, Sand).
Key features:
- SmoothMesher with binary SDF, centroid vertex placement, per-axis boundary
clamping to align with blocky grid at smooth↔blocky transitions
- Cross-chunk connectivity: PAD=2 SDF grid, vertex range [-1, CHUNK_SIZE),
canonical edge ownership (no duplicate triangles, no z-fighting)
- Face normals oriented by edge axis+sign (robust with binary SDF, unlike
SDF gradient dot or centroid sampling approaches)
- Y-axis winding fix: sharing cells have different spatial arrangement,
requiring opposite winding from X and Z axes
- GPU mesher treats smooth neighbors as solid (no blocky faces toward smooth)
- Material blending: primary (smooth-only) + secondary (all counts) per vertex
- Dedicated shaders: voxelSmoothVS (vertex pulling t6) + voxelSmoothPS
(triplanar + lerp blending between two materials)
- Separate render pass with LoadOp::LOAD after voxels+topings
- New materials: SmoothStone (mat 6), blocky Stone (mat 3) and Dirt patches
added to world generation for boundary testing
2026-03-27 13:03:55 +01:00
|
|
|
} else {
|
2026-03-27 15:08:35 +01:00
|
|
|
albedo = sampleTriplanar(input.worldPos, geoN, selfTexIdx, tiling);
|
Phase 5.1: Naive Surface Nets smooth rendering
Implement CPU-side Naive Surface Nets for smooth voxel surfaces (SmoothStone,
Snow) coexisting with blocky voxels (Grass, Dirt, Stone, Sand).
Key features:
- SmoothMesher with binary SDF, centroid vertex placement, per-axis boundary
clamping to align with blocky grid at smooth↔blocky transitions
- Cross-chunk connectivity: PAD=2 SDF grid, vertex range [-1, CHUNK_SIZE),
canonical edge ownership (no duplicate triangles, no z-fighting)
- Face normals oriented by edge axis+sign (robust with binary SDF, unlike
SDF gradient dot or centroid sampling approaches)
- Y-axis winding fix: sharing cells have different spatial arrangement,
requiring opposite winding from X and Z axes
- GPU mesher treats smooth neighbors as solid (no blocky faces toward smooth)
- Material blending: primary (smooth-only) + secondary (all counts) per vertex
- Dedicated shaders: voxelSmoothVS (vertex pulling t6) + voxelSmoothPS
(triplanar + lerp blending between two materials)
- Separate render pass with LoadOp::LOAD after voxels+topings
- New materials: SmoothStone (mat 6), blocky Stone (mat 3) and Dirt patches
added to world generation for boundary testing
2026-03-27 13:03:55 +01:00
|
|
|
}
|
|
|
|
|
|
2026-03-27 14:21:35 +01:00
|
|
|
// Lighting
|
Phase 5.1: Naive Surface Nets smooth rendering
Implement CPU-side Naive Surface Nets for smooth voxel surfaces (SmoothStone,
Snow) coexisting with blocky voxels (Grass, Dirt, Stone, Sand).
Key features:
- SmoothMesher with binary SDF, centroid vertex placement, per-axis boundary
clamping to align with blocky grid at smooth↔blocky transitions
- Cross-chunk connectivity: PAD=2 SDF grid, vertex range [-1, CHUNK_SIZE),
canonical edge ownership (no duplicate triangles, no z-fighting)
- Face normals oriented by edge axis+sign (robust with binary SDF, unlike
SDF gradient dot or centroid sampling approaches)
- Y-axis winding fix: sharing cells have different spatial arrangement,
requiring opposite winding from X and Z axes
- GPU mesher treats smooth neighbors as solid (no blocky faces toward smooth)
- Material blending: primary (smooth-only) + secondary (all counts) per vertex
- Dedicated shaders: voxelSmoothVS (vertex pulling t6) + voxelSmoothPS
(triplanar + lerp blending between two materials)
- Separate render pass with LoadOp::LOAD after voxels+topings
- New materials: SmoothStone (mat 6), blocky Stone (mat 3) and Dirt patches
added to world generation for boundary testing
2026-03-27 13:03:55 +01:00
|
|
|
float3 L = normalize(-sunDirection.xyz);
|
|
|
|
|
float NdotL = max(dot(N, L), 0.0);
|
|
|
|
|
float3 ambient = float3(0.15, 0.18, 0.25);
|
2026-03-27 14:21:35 +01:00
|
|
|
float3 color = albedo * (sunColor.rgb * NdotL + ambient);
|
|
|
|
|
|
|
|
|
|
// Distance fog
|
|
|
|
|
float dist = length(input.worldPos - cameraPosition.xyz);
|
|
|
|
|
float fog = 1.0 - exp(-dist * 0.003);
|
|
|
|
|
float3 fogColor = float3(0.55, 0.70, 0.90);
|
|
|
|
|
color = lerp(color, fogColor, saturate(fog));
|
Phase 5.1: Naive Surface Nets smooth rendering
Implement CPU-side Naive Surface Nets for smooth voxel surfaces (SmoothStone,
Snow) coexisting with blocky voxels (Grass, Dirt, Stone, Sand).
Key features:
- SmoothMesher with binary SDF, centroid vertex placement, per-axis boundary
clamping to align with blocky grid at smooth↔blocky transitions
- Cross-chunk connectivity: PAD=2 SDF grid, vertex range [-1, CHUNK_SIZE),
canonical edge ownership (no duplicate triangles, no z-fighting)
- Face normals oriented by edge axis+sign (robust with binary SDF, unlike
SDF gradient dot or centroid sampling approaches)
- Y-axis winding fix: sharing cells have different spatial arrangement,
requiring opposite winding from X and Z axes
- GPU mesher treats smooth neighbors as solid (no blocky faces toward smooth)
- Material blending: primary (smooth-only) + secondary (all counts) per vertex
- Dedicated shaders: voxelSmoothVS (vertex pulling t6) + voxelSmoothPS
(triplanar + lerp blending between two materials)
- Separate render pass with LoadOp::LOAD after voxels+topings
- New materials: SmoothStone (mat 6), blocky Stone (mat 3) and Dirt patches
added to world generation for boundary testing
2026-03-27 13:03:55 +01:00
|
|
|
|
2026-03-28 14:48:11 +01:00
|
|
|
output.color = float4(color, 1.0);
|
|
|
|
|
output.normal = float4(N, 0.0);
|
|
|
|
|
return output;
|
Phase 5.1: Naive Surface Nets smooth rendering
Implement CPU-side Naive Surface Nets for smooth voxel surfaces (SmoothStone,
Snow) coexisting with blocky voxels (Grass, Dirt, Stone, Sand).
Key features:
- SmoothMesher with binary SDF, centroid vertex placement, per-axis boundary
clamping to align with blocky grid at smooth↔blocky transitions
- Cross-chunk connectivity: PAD=2 SDF grid, vertex range [-1, CHUNK_SIZE),
canonical edge ownership (no duplicate triangles, no z-fighting)
- Face normals oriented by edge axis+sign (robust with binary SDF, unlike
SDF gradient dot or centroid sampling approaches)
- Y-axis winding fix: sharing cells have different spatial arrangement,
requiring opposite winding from X and Z axes
- GPU mesher treats smooth neighbors as solid (no blocky faces toward smooth)
- Material blending: primary (smooth-only) + secondary (all counts) per vertex
- Dedicated shaders: voxelSmoothVS (vertex pulling t6) + voxelSmoothPS
(triplanar + lerp blending between two materials)
- Separate render pass with LoadOp::LOAD after voxels+topings
- New materials: SmoothStone (mat 6), blocky Stone (mat 3) and Dirt patches
added to world generation for boundary testing
2026-03-27 13:03:55 +01:00
|
|
|
}
|