From c7a8b50149316b6f1b4995c29b0c30cab8a32135 Mon Sep 17 00:00:00 2001 From: ssdfasd <2156608475@qq.com> Date: Thu, 12 Mar 2026 01:38:23 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BD=93=E7=A7=AF=E9=98=B4?= =?UTF-8?q?=E5=BD=B1=E5=92=8C=E5=85=89=E7=85=A7=EF=BC=9A=E7=BB=9F=E4=B8=80?= =?UTF-8?q?=E4=B8=8EUnity=E7=89=88=E6=9C=AC=E4=B8=80=E8=87=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Res/Shader/volume.hlsl | 81 ++++++++++++++++++++++++++++++++++-------- main.cpp | 13 +++++-- 2 files changed, 77 insertions(+), 17 deletions(-) diff --git a/Res/Shader/volume.hlsl b/Res/Shader/volume.hlsl index e2f05418..8af2ea6d 100644 --- a/Res/Shader/volume.hlsl +++ b/Res/Shader/volume.hlsl @@ -4,14 +4,12 @@ cbuffer CB0 : register(b1) { - float4x4 _InverseViewProjection; - float3 _CameraPos; - float _DensityScale; - float3 _BBoxMin; - float _StepSize; - float3 _BBoxMax; - uint _MaxSteps; - float _RotationY; + float4x4 _InverseViewProjection; // 64 bytes + float4 _CameraPos_Density; // xyz = CameraPos, w = DensityScale + float4 _BBoxMin_Step; // xyz = BBoxMin, w = StepSize + float4 _BBoxMax_MaxSteps; // xyz = BBoxMax, w = MaxSteps + float4 _Rotation_Pad_LightSamples; // x = RotationY, yzw = pad, but we'll use differently + float4 _LightDir_Samples; // xyz = LightDir, w = LightSamples }; StructuredBuffer buf : register(t1); @@ -90,6 +88,47 @@ float phase_function() return 1.0; } +uint rand_xorshift(uint seed) +{ + seed ^= (seed << 13); + seed ^= (seed >> 17); + seed ^= (seed << 5); + return seed; +} + +float random_float(float3 pos) +{ + uint seed = asuint(pos.x + pos.y + pos.z); + float res = float(rand_xorshift(seed)) * (1.0 / 4294967296.0); + res = float(rand_xorshift(asuint(res))) * (1.0 / 4294967296.0); + return res; +} + +float volumetric_shadow(float3 pos, float densityScale, inout pnanovdb_readaccessor_t acc) +{ + float lightSamples = _LightDir_Samples.w; + if (lightSamples < 1) { return 0.0; } + + float3 light_dir = _LightDir_Samples.xyz; + + float shadow = 1.0; + float step_size = 1.0; + + int steps = 10; + for (int step = 0; step < steps; step++) + { + float3 sample_pos = pos + step_size * light_dir; + + float sigmaS = get_value_coord(acc, sample_pos) * densityScale; + float sigmaE = max(0.000001, sigmaS) * 2.0; + shadow *= exp(-sigmaE * step_size); + + step_size *= (2.0 + random_float(sample_pos)); + } + + return shadow; +} + PSInput MainVS(VSInput input) { PSInput output; @@ -116,7 +155,7 @@ bool intersectBox(float3 origin, float3 dir, float3 boxMin, float3 boxMax, out f float4 MainPS(PSInput input) : SV_TARGET { - float3 rayDir = normalize(input.worldPos - _CameraPos); + float3 rayDir = normalize(input.worldPos - _CameraPos_Density.xyz); float tmin = 0.01; float tmax = 5000.0; @@ -126,6 +165,14 @@ float4 MainPS(PSInput input) : SV_TARGET float3 color = float3(0, 0, 0); float transmittance = 1.0; + float acc_density = 0.0; + float3 ambient_light = 0.005; + + float _DensityScale = _CameraPos_Density.w; + float _StepSize = _BBoxMin_Step.w; + float _MaxSteps = _BBoxMax_MaxSteps.w; + float _RotationY = _Rotation_Pad_LightSamples.x; + float _LightSamples = _LightDir_Samples.w; float cosR = cos(_RotationY); float sinR = sin(_RotationY); @@ -135,7 +182,7 @@ float4 MainPS(PSInput input) : SV_TARGET -sinR, 0, cosR ); - float3 localCameraPos = mul(invRotY, _CameraPos); + float3 localCameraPos = mul(invRotY, _CameraPos_Density.xyz); float3 localRayDir = mul(invRotY, rayDir); float not_used; @@ -144,7 +191,7 @@ float4 MainPS(PSInput input) : SV_TARGET float skip = 0; - for (uint i = 0; i < _MaxSteps; i++) { + for (int i = 0; i < (int)_MaxSteps; i++) { if (tmin >= tmax || transmittance < 0.01) break; float3 localPos = localCameraPos + localRayDir * tmin; @@ -174,14 +221,20 @@ float4 MainPS(PSInput input) : SV_TARGET float sigmaS = density; float sigmaE = max(0.000001, sigmaS); - float3 S = sigmaS * phase_function() * float3(1, 1, 1); + acc_density += sigmaS; + + float shadow = volumetric_shadow(localPos, _DensityScale, volume.acc); + float3 S = sigmaS * phase_function() * shadow * float3(1, 1, 1); float3 Sint = (S - S * exp(-sigmaE * _StepSize)) / sigmaE; color += transmittance * Sint; transmittance *= exp(-sigmaE * _StepSize); + if (acc_density > 1.0) break; + tmin += _StepSize; } - float alpha = 1.0 - transmittance; - return float4(color, alpha); + float3 final_color = (color + ambient_light) * acc_density; + final_color = pow(final_color, 1.0 / 2.2); + return float4(final_color, acc_density); } \ No newline at end of file diff --git a/main.cpp b/main.cpp index 0ba02ae6..b432b7ef 100644 --- a/main.cpp +++ b/main.cpp @@ -290,7 +290,7 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLi DirectX::XMFLOAT4X4 invViewProjMat; DirectX::XMStoreFloat4x4(&invViewProjMat, invViewProj); - float volumeCBData[32]; + float volumeCBData[36]; memcpy(volumeCBData, &invViewProjMat, sizeof(float) * 16); volumeCBData[16] = -10.0f; volumeCBData[17] = 73.0f; @@ -303,9 +303,16 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLi volumeCBData[24] = (float)nanoVDBData.worldBBox[3]; volumeCBData[25] = (float)nanoVDBData.worldBBox[4]; volumeCBData[26] = (float)nanoVDBData.worldBBox[5]; - volumeCBData[27] = 2000; + volumeCBData[27] = 2000.0f; // MaxSteps as float volumeCBData[28] = timeSinceAppStartInSecond * 0.3f; // RotationY - UpdateConstantBuffer(volumeCB, volumeCBData, sizeof(float) * 29); + volumeCBData[29] = 0.0f; // Pad0 + volumeCBData[30] = 0.0f; // Pad1 + volumeCBData[31] = 0.0f; // Pad2 + volumeCBData[32] = 0.5f; // LightDir X + volumeCBData[33] = 0.8f; // LightDir Y + volumeCBData[34] = 0.3f; // LightDir Z + volumeCBData[35] = 8.0f; // LightSamples as float + UpdateConstantBuffer(volumeCB, volumeCBData, sizeof(float) * 36); if (frameCount == 1) { printf("Volume BBox: [%.2f, %.2f, %.2f] - [%.2f, %.2f, %.2f]\n", volumeCBData[20], volumeCBData[21], volumeCBData[22],