You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
145 lines
6.5 KiB
145 lines
6.5 KiB
//--------------------------------------------------------------------------------------------------
|
|
// Definitions
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
// #pragma enable_d3d11_debug_symbols
|
|
#pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch switch2
|
|
|
|
#pragma kernel VolumeVoxelization
|
|
|
|
#pragma multi_compile _ SUPPORT_WATER_ABSORPTION
|
|
|
|
#define GROUP_SIZE_1D 8
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
// Included headers
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/GeometricTools.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/VolumeRendering.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Core/Utilities/GeometryUtils.cs.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/VolumetricLighting/HDRenderPipeline.VolumetricLighting.cs.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoopDef.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Water/Shaders/UnderWaterUtilities.hlsl"
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
// Inputs & outputs
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
StructuredBuffer<OrientedBBox> _VolumeBounds;
|
|
StructuredBuffer<LocalVolumetricFogEngineData> _VolumeData;
|
|
|
|
RW_TEXTURE3D(float4, _VBufferDensity); // RGB = sqrt(scattering), A = sqrt(extinction)
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
// Implementation
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
// Jittered ray with screen-space derivatives.
|
|
struct JitteredRay
|
|
{
|
|
float3 originWS;
|
|
float3 centerDirWS;
|
|
float3 jitterDirWS;
|
|
float3 xDirDerivWS;
|
|
float3 yDirDerivWS;
|
|
};
|
|
|
|
void FillVolumetricDensityBuffer(uint2 voxelCoord2D, JitteredRay ray)
|
|
{
|
|
float t0 = DecodeLogarithmicDepthGeneralized(0, _VBufferDistanceDecodingParams);
|
|
float de = _VBufferRcpSliceCount; // Log-encoded distance between slices
|
|
|
|
#ifdef SUPPORT_WATER_ABSORPTION
|
|
float waterDistance = FLT_MIN;
|
|
float2 positionSS = voxelCoord2D * _VBufferViewportSize.zw * _ScreenSize.xy;
|
|
bool underWater = ray.originWS.y < _UnderWaterUpHeight.w || IsUnderWater(positionSS);
|
|
if (underWater && (GetStencilValue(LOAD_TEXTURE2D_X(_StencilTexture, positionSS)) & STENCILUSAGE_WATER_SURFACE) != 0)
|
|
{
|
|
waterDistance = LinearEyeDepth(LOAD_TEXTURE2D_X(_RefractiveDepthBuffer, positionSS).r, _ZBufferParams);
|
|
waterDistance = waterDistance * rcp(dot(ray.centerDirWS, GetViewForwardDir()));
|
|
}
|
|
else
|
|
waterDistance = underWater ? FLT_MAX : 0.0f;
|
|
#endif
|
|
|
|
|
|
for (uint slice = 0; slice < _VBufferSliceCount; slice++)
|
|
{
|
|
uint3 voxelCoord = uint3(voxelCoord2D, slice + _VBufferSliceCount * unity_StereoEyeIndex);
|
|
|
|
float e1 = slice * de + de; // (slice + 1) / sliceCount
|
|
float t1 = DecodeLogarithmicDepthGeneralized(e1, _VBufferDistanceDecodingParams);
|
|
float dt = t1 - t0;
|
|
float t = t0 + 0.5 * dt;
|
|
|
|
float3 voxelCenterWS = ray.originWS + t * ray.centerDirWS;
|
|
|
|
// TODO: the fog value at the center is likely different from the average value across the voxel.
|
|
// Compute the average value.
|
|
float fragmentHeight = voxelCenterWS.y;
|
|
float heightMultiplier = ComputeHeightFogMultiplier(fragmentHeight, _HeightFogBaseHeight, _HeightFogExponents);
|
|
|
|
// Start by sampling the height fog.
|
|
float3 voxelScattering = _HeightFogBaseScattering.xyz * heightMultiplier;
|
|
float voxelExtinction = _HeightFogBaseExtinction * heightMultiplier;
|
|
|
|
#if SUPPORT_WATER_ABSORPTION
|
|
if (t < waterDistance)
|
|
{
|
|
voxelScattering = _UnderWaterScatteringExtinction.xyz;
|
|
voxelExtinction = _UnderWaterScatteringExtinction.w * (1 - ray.centerDirWS.y);
|
|
}
|
|
#endif
|
|
|
|
_VBufferDensity[voxelCoord] = float4(voxelScattering, voxelExtinction);
|
|
|
|
t0 = t1;
|
|
}
|
|
}
|
|
|
|
[numthreads(GROUP_SIZE_1D, GROUP_SIZE_1D, 1)]
|
|
void VolumeVoxelization(uint3 dispatchThreadId : SV_DispatchThreadID,
|
|
uint2 groupId : SV_GroupID,
|
|
uint2 groupThreadId : SV_GroupThreadID)
|
|
{
|
|
UNITY_XR_ASSIGN_VIEW_INDEX(dispatchThreadId.z);
|
|
|
|
// Reminder: our voxels are sphere-capped right frustums (truncated right pyramids).
|
|
// The curvature of the front and back faces is quite gentle, so we can use
|
|
// the right frustum approximation (thus the front and the back faces are squares).
|
|
// Note, that since we still rely on the perspective camera model, pixels at the center
|
|
// of the screen correspond to larger solid angles than those at the edges.
|
|
// Basically, sizes of front and back faces depend on the XY coordinate.
|
|
// https://www.desmos.com/calculator/i3rkesvidk
|
|
|
|
float3 F = GetViewForwardDir();
|
|
float3 U = GetViewUpDir();
|
|
|
|
uint2 voxelCoord = dispatchThreadId.xy;
|
|
float2 centerCoord = voxelCoord + float2(0.5, 0.5);
|
|
|
|
// Compute a ray direction s.t. ViewSpace(rayDirWS).z = 1.
|
|
float3 rayDirWS = mul(-float4(centerCoord, 1, 1), _VBufferCoordToViewDirWS[unity_StereoEyeIndex]).xyz;
|
|
float3 rightDirWS = cross(rayDirWS, U);
|
|
float rcpLenRayDir = rsqrt(dot(rayDirWS, rayDirWS));
|
|
float rcpLenRightDir = rsqrt(dot(rightDirWS, rightDirWS));
|
|
|
|
JitteredRay ray;
|
|
ray.originWS = GetCurrentViewPosition();
|
|
ray.centerDirWS = rayDirWS * rcpLenRayDir; // Normalize
|
|
|
|
float FdotD = dot(F, ray.centerDirWS);
|
|
float unitDistFaceSize = _VBufferUnitDepthTexelSpacing * FdotD * rcpLenRayDir;
|
|
|
|
ray.xDirDerivWS = rightDirWS * (rcpLenRightDir * unitDistFaceSize); // Normalize & rescale
|
|
ray.yDirDerivWS = cross(ray.xDirDerivWS, ray.centerDirWS); // Will have the length of 'unitDistFaceSize' by construction
|
|
ray.jitterDirWS = ray.centerDirWS; // TODO
|
|
|
|
ApplyCameraRelativeXR(ray.originWS);
|
|
|
|
FillVolumetricDensityBuffer(voxelCoord, ray);
|
|
}
|