2026-03-30 21:54:55 +02:00
|
|
|
// BVLE Voxels - AO Apply + Sky + Tone Mapping Compute Shader (Phase 6.3 + 7)
|
|
|
|
|
// Final post-process pass: sky gradient for empty pixels, AO, saturation, tone mapping.
|
2026-03-29 09:31:19 +02:00
|
|
|
|
|
|
|
|
#include "voxelCommon.hlsli"
|
|
|
|
|
|
|
|
|
|
Texture2D<float> aoBlurred : register(t0);
|
2026-03-30 21:54:55 +02:00
|
|
|
Texture2D<float> depthTexture : register(t1);
|
2026-03-29 09:31:19 +02:00
|
|
|
RWTexture2D<float4> colorOutput : register(u0);
|
|
|
|
|
|
|
|
|
|
struct ApplyPush {
|
|
|
|
|
uint width;
|
|
|
|
|
uint height;
|
|
|
|
|
uint debugMode; // 0=normal, 2=debug AO (show AO as grayscale)
|
|
|
|
|
uint pad[9];
|
|
|
|
|
};
|
|
|
|
|
[[vk::push_constant]] ConstantBuffer<ApplyPush> push : register(b999);
|
|
|
|
|
|
2026-03-29 15:00:12 +02:00
|
|
|
// Soft clamp tone mapping: linear up to shoulder, gentle roll-off to prevent harsh clipping
|
|
|
|
|
float3 softClampToneMap(float3 color, float exposure) {
|
|
|
|
|
color *= exposure;
|
2026-03-30 21:54:55 +02:00
|
|
|
return 1.0 - exp(-color);
|
2026-03-29 15:00:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Saturation adjustment in linear space
|
|
|
|
|
float3 adjustSaturation(float3 color, float saturation) {
|
|
|
|
|
float luma = dot(color, float3(0.2126, 0.7152, 0.0722));
|
|
|
|
|
return lerp(float3(luma, luma, luma), color, saturation);
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-30 21:54:55 +02:00
|
|
|
// Procedural sky gradient (Wonderbox-inspired warm atmosphere)
|
|
|
|
|
float3 computeSky(float2 uv) {
|
|
|
|
|
// Reconstruct view direction from screen UV
|
|
|
|
|
float2 ndc = float2(uv.x * 2.0 - 1.0, (1.0 - uv.y) * 2.0 - 1.0);
|
|
|
|
|
float4 clipDir = float4(ndc, 0.5, 1.0);
|
|
|
|
|
float4 worldDir4 = mul(inverseViewProjection, clipDir);
|
|
|
|
|
float3 viewDir = normalize(worldDir4.xyz / worldDir4.w - cameraPosition.xyz);
|
|
|
|
|
|
|
|
|
|
// Vertical gradient: viewDir.y = +1 (zenith) to -1 (nadir)
|
|
|
|
|
float t = viewDir.y * 0.5 + 0.5; // 0=horizon/below, 1=zenith
|
|
|
|
|
|
|
|
|
|
// Wonderbox palette: warm sandy horizon → soft blue-grey zenith
|
|
|
|
|
float3 horizonColor = float3(0.85, 0.75, 0.58); // warm sand/beige
|
|
|
|
|
float3 zenithColor = float3(0.55, 0.62, 0.72); // muted blue-grey
|
|
|
|
|
float3 nadirColor = float3(0.70, 0.62, 0.48); // darker warm below horizon
|
|
|
|
|
|
|
|
|
|
float3 sky;
|
|
|
|
|
if (t > 0.5) {
|
|
|
|
|
// Above horizon: sand → blue
|
|
|
|
|
float h = (t - 0.5) * 2.0; // 0=horizon, 1=zenith
|
|
|
|
|
h = pow(h, 0.7); // non-linear: more horizon color in the lower sky
|
|
|
|
|
sky = lerp(horizonColor, zenithColor, h);
|
|
|
|
|
} else {
|
|
|
|
|
// Below horizon: sand → darker warm
|
|
|
|
|
float h = (0.5 - t) * 2.0; // 0=horizon, 1=nadir
|
|
|
|
|
sky = lerp(horizonColor, nadirColor, h);
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-31 14:58:44 +02:00
|
|
|
// Sun glow near sun direction (compact disc + subtle haze)
|
2026-03-30 21:54:55 +02:00
|
|
|
float3 L = normalize(-sunDirection.xyz);
|
|
|
|
|
float sunDot = saturate(dot(viewDir, L));
|
2026-03-31 14:58:44 +02:00
|
|
|
float sunDisc = pow(sunDot, 256.0) * 0.6; // tight bright disc
|
|
|
|
|
float sunGlow = pow(sunDot, 64.0) * 0.2; // narrow glow ring
|
|
|
|
|
float sunHaze = pow(sunDot, 8.0) * 0.08; // subtle atmospheric haze
|
|
|
|
|
sky += float3(1.0, 0.85, 0.5) * (sunDisc + sunGlow + sunHaze);
|
2026-03-30 21:54:55 +02:00
|
|
|
|
|
|
|
|
return sky;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-29 09:31:19 +02:00
|
|
|
[RootSignature(VOXEL_ROOTSIG)]
|
|
|
|
|
[numthreads(8, 8, 1)]
|
|
|
|
|
void main(uint3 DTid : SV_DispatchThreadID) {
|
|
|
|
|
if (DTid.x >= push.width || DTid.y >= push.height) return;
|
|
|
|
|
|
2026-03-30 21:54:55 +02:00
|
|
|
float depth = depthTexture[DTid.xy];
|
2026-03-29 09:31:19 +02:00
|
|
|
float ao = aoBlurred[DTid.xy];
|
|
|
|
|
|
|
|
|
|
if (push.debugMode == 2) {
|
|
|
|
|
colorOutput[DTid.xy] = float4(ao, ao, ao, 1);
|
2026-03-30 21:54:55 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2026-03-29 15:00:12 +02:00
|
|
|
|
2026-03-30 21:54:55 +02:00
|
|
|
// Sky pixels: depth == 0 in reverse-Z = far plane
|
|
|
|
|
if (depth == 0.0) {
|
|
|
|
|
float2 uv = (float2(DTid.xy) + 0.5) / float2(push.width, push.height);
|
|
|
|
|
float3 sky = computeSky(uv);
|
|
|
|
|
colorOutput[DTid.xy] = float4(sky, 1.0);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2026-03-29 15:00:12 +02:00
|
|
|
|
2026-03-30 21:54:55 +02:00
|
|
|
float4 color = colorOutput[DTid.xy];
|
2026-03-29 15:00:12 +02:00
|
|
|
|
2026-03-30 21:54:55 +02:00
|
|
|
// Apply AO
|
|
|
|
|
color.rgb *= ao;
|
2026-03-29 15:00:12 +02:00
|
|
|
|
2026-03-30 21:54:55 +02:00
|
|
|
// Saturation boost (toneMapParams.x)
|
|
|
|
|
color.rgb = adjustSaturation(color.rgb, toneMapParams.x);
|
|
|
|
|
|
|
|
|
|
// Tone mapping (toneMapParams.y = exposure)
|
|
|
|
|
color.rgb = softClampToneMap(color.rgb, toneMapParams.y);
|
|
|
|
|
|
|
|
|
|
colorOutput[DTid.xy] = color;
|
2026-03-29 09:31:19 +02:00
|
|
|
}
|