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.
174 lines
7.0 KiB
174 lines
7.0 KiB
#if SHADERPASS != SHADERPASS_FOG_VOLUME_VOXELIZATION
|
|
#error SHADERPASS_is_not_correctly_define
|
|
#endif
|
|
|
|
#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/Editor/Material/FogVolume/ShaderGraph/VolumetricMaterialUtils.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/VolumetricLighting/HDRenderPipeline.VolumetricLighting.cs.hlsl"
|
|
|
|
uint _VolumetricFogGlobalIndex;
|
|
StructuredBuffer<VolumetricMaterialRenderingData> _VolumetricMaterialData;
|
|
ByteAddressBuffer _VolumetricGlobalIndirectionBuffer;
|
|
|
|
// Jittered ray with screen-space derivatives.
|
|
struct JitteredRay
|
|
{
|
|
float3 originWS;
|
|
float3 centerDirWS;
|
|
float3 jitterDirWS;
|
|
float3 xDirDerivWS;
|
|
float3 yDirDerivWS;
|
|
};
|
|
|
|
struct VertexToFragment
|
|
{
|
|
float4 positionCS : SV_POSITION;
|
|
float3 viewDirectionWS : TEXCOORD0;
|
|
float3 positionOS : TEXCOORD1;
|
|
nointerpolation float viewIndex : TEXCOORD2;
|
|
nointerpolation uint depthSlice : SV_RenderTargetArrayIndex;
|
|
};
|
|
|
|
float3 GetCubeVertexPosition(uint vertexIndex)
|
|
{
|
|
int index = _VolumetricGlobalIndirectionBuffer.Load(_VolumetricFogGlobalIndex << 2);
|
|
return _VolumetricMaterialData[index].obbVertexPositionWS[vertexIndex].xyz;
|
|
}
|
|
|
|
// VertexCubeSlicing needs GetCubeVertexPosition to be declared before
|
|
#define GET_CUBE_VERTEX_POSITION GetCubeVertexPosition
|
|
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/VertexCubeSlicing.hlsl"
|
|
|
|
VertexToFragment Vert(uint instanceId : INSTANCEID_SEMANTIC, uint vertexId : VERTEXID_SEMANTIC)
|
|
{
|
|
VertexToFragment output;
|
|
|
|
int materialDataIndex = _VolumetricGlobalIndirectionBuffer.Load(_VolumetricFogGlobalIndex << 2);
|
|
|
|
|
|
uint sliceCount = _VolumetricMaterialData[materialDataIndex].sliceCount;
|
|
uint viewIndex = instanceId / sliceCount;
|
|
// In VR sliceCount needs to be the same for each eye to be able to retrieve correctly the view index
|
|
// Patch the mater data index to read the correct view index dependent data
|
|
materialDataIndex += viewIndex * _VolumeCount;
|
|
|
|
uint sliceStartIndex = _VolumetricMaterialData[materialDataIndex].startSliceIndex;
|
|
|
|
#if defined(UNITY_STEREO_INSTANCING_ENABLED)
|
|
unity_StereoEyeIndex = viewIndex;
|
|
#endif
|
|
output.viewIndex = viewIndex;
|
|
|
|
uint sliceIndex = sliceStartIndex + (instanceId % sliceCount);
|
|
output.depthSlice = sliceIndex + viewIndex * _VBufferSliceCount;
|
|
|
|
float sliceDepth = VBufferDistanceToSliceIndex(sliceIndex);
|
|
|
|
#if USE_VERTEX_CUBE_SLICING
|
|
|
|
float3 cameraForward = -UNITY_MATRIX_V[2].xyz;
|
|
float3 sliceCubeVertexPosition = ComputeCubeSliceVertexPositionRWS(cameraForward, sliceDepth, vertexId);
|
|
output.positionCS = TransformWorldToHClip(float4(sliceCubeVertexPosition, 1.0));
|
|
output.viewDirectionWS = GetWorldSpaceViewDir(sliceCubeVertexPosition);
|
|
output.positionOS = mul(UNITY_MATRIX_I_M, sliceCubeVertexPosition);
|
|
|
|
#else
|
|
|
|
output.positionCS = GetQuadVertexPosition(vertexId);
|
|
output.positionCS.xy = output.positionCS.xy * _VolumetricMaterialData[materialDataIndex].viewSpaceBounds.zw + _VolumetricMaterialData[materialDataIndex].viewSpaceBounds.xy;
|
|
output.positionCS.z = EyeDepthToLinear(sliceDepth, _ZBufferParams);
|
|
output.positionCS.w = 1;
|
|
|
|
float3 positionWS = ComputeWorldSpacePosition(output.positionCS, _IsObliqueProjectionMatrix ? _CameraInverseViewProjection_NO : UNITY_MATRIX_I_VP);
|
|
output.viewDirectionWS = GetWorldSpaceViewDir(positionWS);
|
|
|
|
// Calculate object space position
|
|
output.positionOS = mul(UNITY_MATRIX_I_M, float4(positionWS, 1)).xyz;
|
|
|
|
#endif // USE_VERTEX_CUBE_SLICING
|
|
|
|
return output;
|
|
}
|
|
|
|
FragInputs BuildFragInputs(VertexToFragment v2f, float3 voxelPositionWS, float3 voxelClipSpace)
|
|
{
|
|
FragInputs output;
|
|
ZERO_INITIALIZE(FragInputs, output);
|
|
|
|
output.positionSS = v2f.positionCS;
|
|
output.positionRWS = output.positionPredisplacementRWS = voxelPositionWS;
|
|
output.positionPixel = uint2(v2f.positionCS.xy);
|
|
output.texCoord0 = float4(saturate(voxelClipSpace * 0.5 + 0.5), 0);
|
|
output.tangentToWorld = k_identity3x3;
|
|
|
|
return output;
|
|
}
|
|
|
|
float ComputeFadeFactor(float3 coordNDC, float distance)
|
|
{
|
|
bool exponential = uint(_VolumetricMaterialFalloffMode) == LOCALVOLUMETRICFOGFALLOFFMODE_EXPONENTIAL;
|
|
bool multiplyBlendMode = _FogVolumeBlendMode == LOCALVOLUMETRICFOGBLENDINGMODE_MULTIPLY;
|
|
|
|
return ComputeVolumeFadeFactor(
|
|
coordNDC, distance,
|
|
_VolumetricMaterialRcpPosFaceFade.xyz,
|
|
_VolumetricMaterialRcpNegFaceFade.xyz,
|
|
_VolumetricMaterialInvertFade,
|
|
_VolumetricMaterialRcpDistFadeLen,
|
|
_VolumetricMaterialEndTimesRcpDistFadeLen,
|
|
exponential,
|
|
multiplyBlendMode
|
|
);
|
|
}
|
|
|
|
void Frag(VertexToFragment v2f, out float4 outColor : SV_Target0)
|
|
{
|
|
// We don't need the stereo eye index in this shader and ShaderGraph don't have access to this
|
|
#if defined(UNITY_STEREO_INSTANCING_ENABLED)
|
|
unity_StereoEyeIndex = v2f.viewIndex;
|
|
#endif
|
|
|
|
float3 albedo;
|
|
float extinction;
|
|
|
|
float sliceDistance = VBufferDistanceToSliceIndex(v2f.depthSlice % _VBufferSliceCount);
|
|
|
|
// Compute voxel center position and test against volume OBB
|
|
float3 raycenterDirWS = normalize(-v2f.viewDirectionWS); // Normalize
|
|
float3 rayoriginWS = GetCurrentViewPosition();
|
|
float3 voxelCenterWS = rayoriginWS + sliceDistance * raycenterDirWS;
|
|
|
|
// Build rotation matrix from normalized OBB axes to transform the world space position
|
|
float3x3 obbFrame = float3x3(_VolumetricMaterialObbRight.xyz, _VolumetricMaterialObbUp.xyz, cross(_VolumetricMaterialObbRight.xyz, _VolumetricMaterialObbUp.xyz));
|
|
|
|
// Rotate world position around the center of the local fog OBB
|
|
float3 voxelCenterBS = mul(GetAbsolutePositionWS(voxelCenterWS - _VolumetricMaterialObbCenter.xyz), transpose(obbFrame));
|
|
float3 voxelCenterCS = (voxelCenterBS * rcp(_VolumetricMaterialObbExtents.xyz));
|
|
|
|
// Still need to clip pixels outside of the box because of the froxel buffer shape
|
|
bool overlap = Max3(abs(voxelCenterCS.x), abs(voxelCenterCS.y), abs(voxelCenterCS.z)) <= 1;
|
|
if (!overlap)
|
|
clip(-1);
|
|
|
|
FragInputs fragInputs = BuildFragInputs(v2f, voxelCenterWS, voxelCenterCS);
|
|
GetVolumeData(fragInputs, v2f.viewDirectionWS, albedo, extinction);
|
|
|
|
// Accumulate volume parameters
|
|
extinction *= ExtinctionFromMeanFreePath(_FogVolumeFogDistanceProperty);
|
|
albedo *= _FogVolumeSingleScatteringAlbedo.rgb;
|
|
|
|
float3 voxelCenterNDC = saturate(voxelCenterCS * 0.5 + 0.5);
|
|
float fade = ComputeFadeFactor(voxelCenterNDC, sliceDistance);
|
|
|
|
// When multiplying fog, we need to handle specifically the blend area to avoid creating gaps in the fog
|
|
if (_FogVolumeBlendMode == LOCALVOLUMETRICFOGBLENDINGMODE_MULTIPLY)
|
|
{
|
|
outColor = max(0, lerp(float4(1.0, 1.0, 1.0, 1.0), float4(albedo * extinction, extinction), fade.xxxx));
|
|
}
|
|
else
|
|
{
|
|
extinction *= fade;
|
|
outColor = max(0, float4(saturate(albedo * extinction), extinction));
|
|
}
|
|
}
|