// BVLE Voxels - AO Apply + Tone Mapping Compute Shader (Phase 6.3 + 7) // Final post-process pass: applies AO, saturation boost, and tone mapping. #include "voxelCommon.hlsli" Texture2D aoBlurred : register(t0); RWTexture2D 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 push : register(b999); // Soft clamp tone mapping: linear up to shoulder, gentle roll-off to prevent harsh clipping float3 softClampToneMap(float3 color, float exposure) { color *= exposure; // Soft exponential curve: gentler than Reinhard, preserves bright midtones return 1.0 - exp(-color); // natural 1-e^-x curve } // 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); } [RootSignature(VOXEL_ROOTSIG)] [numthreads(8, 8, 1)] void main(uint3 DTid : SV_DispatchThreadID) { if (DTid.x >= push.width || DTid.y >= push.height) return; float ao = aoBlurred[DTid.xy]; if (push.debugMode == 2) { // Debug AO: grayscale visualization of blurred AO colorOutput[DTid.xy] = float4(ao, ao, ao, 1); } else { float4 color = colorOutput[DTid.xy]; // Apply AO color.rgb *= ao; // 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; } }