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
57 lines
2.1 KiB
HLSL
57 lines
2.1 KiB
HLSL
// BVLE Voxels - Smooth Surface Nets Pixel Shader (Phase 5.1)
|
|
// Triplanar texture sampling + material blending + same lighting as voxel PS.
|
|
|
|
#include "voxelCommon.hlsli"
|
|
|
|
Texture2DArray<float4> materialTextures : register(t1);
|
|
SamplerState texSampler : register(s0);
|
|
|
|
struct PSInput {
|
|
float4 position : SV_POSITION;
|
|
float3 worldPos : WORLDPOS;
|
|
float3 normal : NORMAL;
|
|
nointerpolation uint matPacked : MATERIALID;
|
|
};
|
|
|
|
// Sample triplanar texture for a given material index
|
|
float3 sampleTriplanar(float3 worldPos, float3 blend, float tiling, uint matIdx) {
|
|
uint texIdx = clamp(matIdx - 1u, 0u, 5u);
|
|
float4 xS = materialTextures.Sample(texSampler, float3(worldPos.yz * tiling, (float)texIdx));
|
|
float4 yS = materialTextures.Sample(texSampler, float3(worldPos.xz * tiling, (float)texIdx));
|
|
float4 zS = materialTextures.Sample(texSampler, float3(worldPos.xy * tiling, (float)texIdx));
|
|
return xS.rgb * blend.x + yS.rgb * blend.y + zS.rgb * blend.z;
|
|
}
|
|
|
|
[RootSignature(VOXEL_ROOTSIG)]
|
|
float4 main(PSInput input) : SV_TARGET0 {
|
|
float3 N = normalize(input.normal);
|
|
float tiling = textureTiling;
|
|
|
|
// Unpack materials: materialID(8) | secondaryMat(8) | blendWeight(8) | pad(8)
|
|
uint primaryMat = input.matPacked & 0xFF;
|
|
uint secondaryMat = (input.matPacked >> 8) & 0xFF;
|
|
float blendWeight = ((input.matPacked >> 16) & 0xFF) / 255.0;
|
|
|
|
// Triplanar blend weights
|
|
float3 blend = abs(N);
|
|
blend = blend / (blend.x + blend.y + blend.z + 0.001);
|
|
|
|
// Sample primary and secondary materials
|
|
float3 primaryColor = sampleTriplanar(input.worldPos, blend, tiling, primaryMat);
|
|
float3 texColor;
|
|
if (blendWeight > 0.01 && secondaryMat != primaryMat) {
|
|
float3 secondaryColor = sampleTriplanar(input.worldPos, blend, tiling, secondaryMat);
|
|
texColor = lerp(primaryColor, secondaryColor, blendWeight);
|
|
} else {
|
|
texColor = primaryColor;
|
|
}
|
|
|
|
// Lighting (same model as voxel PS)
|
|
float3 L = normalize(-sunDirection.xyz);
|
|
float NdotL = max(dot(N, L), 0.0);
|
|
|
|
float3 ambient = float3(0.15, 0.18, 0.25);
|
|
float3 lit = texColor * (sunColor.rgb * NdotL + ambient);
|
|
|
|
return float4(lit, 1.0);
|
|
}
|