Fix code style
This commit is contained in:
BIN
Content/Shaders/ColorGrading.flax
(Stored with Git LFS)
BIN
Content/Shaders/ColorGrading.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Shaders/DepthOfField.flax
(Stored with Git LFS)
BIN
Content/Shaders/DepthOfField.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Shaders/Fog.flax
(Stored with Git LFS)
BIN
Content/Shaders/Fog.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Shaders/ProbesFilter.flax
(Stored with Git LFS)
BIN
Content/Shaders/ProbesFilter.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Shaders/VolumetricFog.flax
(Stored with Git LFS)
BIN
Content/Shaders/VolumetricFog.flax
(Stored with Git LFS)
Binary file not shown.
@@ -25,9 +25,9 @@ float D_GGX(float roughness, float NoH)
|
||||
float Vis_Schlick(float roughness, float NoV, float NoL)
|
||||
{
|
||||
float k = Square(roughness) * 0.5;
|
||||
float vis_SchlickV = NoV * (1 - k) + k;
|
||||
float vis_SchlickL = NoL * (1 - k) + k;
|
||||
return 0.25 / (vis_SchlickV * vis_SchlickL);
|
||||
float visSchlickV = NoV * (1 - k) + k;
|
||||
float visSchlickL = NoL * (1 - k) + k;
|
||||
return 0.25 / (visSchlickV * visSchlickL);
|
||||
}
|
||||
|
||||
// Smith term for GGX
|
||||
@@ -36,9 +36,9 @@ float Vis_Smith(float roughness, float NoV, float NoL)
|
||||
{
|
||||
float a = Square(roughness);
|
||||
float a2 = a * a;
|
||||
float vis_SmithV = NoV + sqrt(NoV * (NoV - NoV * a2) + a2);
|
||||
float vis_SmithL = NoL + sqrt(NoL * (NoL - NoL * a2) + a2);
|
||||
return rcp(vis_SmithV * vis_SmithL);
|
||||
float visSmithV = NoV + sqrt(NoV * (NoV - NoV * a2) + a2);
|
||||
float visSmithL = NoL + sqrt(NoL * (NoL - NoL * a2) + a2);
|
||||
return rcp(visSmithV * visSmithL);
|
||||
}
|
||||
|
||||
// Appoximation of joint Smith term for GGX
|
||||
@@ -74,7 +74,7 @@ half SSRMipFromRoughness(half roughness)
|
||||
return max(1, 10 - mip1px);
|
||||
}
|
||||
|
||||
float ComputeReflectionCaptureRoughnessFromMip(float mip)
|
||||
float ProbeRoughnessFromMip(float mip)
|
||||
{
|
||||
float mip1px = REFLECTION_CAPTURE_NUM_MIPS - 1 - mip;
|
||||
return exp2((REFLECTION_CAPTURE_ROUGHEST_MIP - mip1px) / REFLECTION_CAPTURE_ROUGHNESS_MIP_SCALE);
|
||||
@@ -99,8 +99,6 @@ float3 EnvBRDF(Texture2D preIntegratedGF, float3 specularColor, float roughness,
|
||||
return specularColor * ab.x + saturate(50.0 * specularColor.g) * ab.y;
|
||||
}
|
||||
|
||||
#define MAX_SPECULAR_POWER 10000000000.0f
|
||||
|
||||
float RoughnessToSpecularPower(float roughness)
|
||||
{
|
||||
return pow(2, 13 * (1 - roughness));
|
||||
|
||||
@@ -264,37 +264,33 @@ META_VS(true, FEATURE_LEVEL_SM4)
|
||||
META_FLAG(VertexToGeometryShader)
|
||||
META_VS_IN_ELEMENT(POSITION, 0, R32G32_FLOAT, 0, ALIGN, PER_VERTEX, 0, true)
|
||||
META_VS_IN_ELEMENT(TEXCOORD, 0, R32G32_FLOAT, 0, ALIGN, PER_VERTEX, 0, true)
|
||||
Quad_VS2GS VS_WriteToSlice(float2 Position : POSITION0, float2 TexCoord : TEXCOORD0, uint LayerIndex : SV_InstanceID)
|
||||
Quad_VS2GS VS_WriteToSlice(float2 position : POSITION0, float2 texCoord : TEXCOORD0, uint layerIndex : SV_InstanceID)
|
||||
{
|
||||
Quad_VS2GS output;
|
||||
|
||||
output.Vertex.Position = float4(Position, 0, 1);
|
||||
output.Vertex.TexCoord = TexCoord;
|
||||
output.LayerIndex = LayerIndex;
|
||||
|
||||
output.Vertex.Position = float4(position, 0, 1);
|
||||
output.Vertex.TexCoord = texCoord;
|
||||
output.LayerIndex = layerIndex;
|
||||
return output;
|
||||
}
|
||||
|
||||
// Geometry shader that writes to a range of slices of a volume texture
|
||||
META_GS(true, FEATURE_LEVEL_SM4)
|
||||
[maxvertexcount(3)]
|
||||
void GS_WriteToSlice(triangle Quad_VS2GS input[3], inout TriangleStream<Quad_GS2PS> OutStream)
|
||||
void GS_WriteToSlice(triangle Quad_VS2GS input[3], inout TriangleStream<Quad_GS2PS> stream)
|
||||
{
|
||||
Quad_GS2PS vertex0;
|
||||
vertex0.Vertex = input[0].Vertex;
|
||||
vertex0.LayerIndex = input[0].LayerIndex;
|
||||
Quad_GS2PS vertex;
|
||||
|
||||
Quad_GS2PS vertex1;
|
||||
vertex1.Vertex = input[1].Vertex;
|
||||
vertex1.LayerIndex = input[1].LayerIndex;
|
||||
vertex.Vertex = input[0].Vertex;
|
||||
vertex.LayerIndex = input[0].LayerIndex;
|
||||
stream.Append(vertex);
|
||||
|
||||
Quad_GS2PS vertex2;
|
||||
vertex2.Vertex = input[2].Vertex;
|
||||
vertex2.LayerIndex = input[2].LayerIndex;
|
||||
vertex.Vertex = input[1].Vertex;
|
||||
vertex.LayerIndex = input[1].LayerIndex;
|
||||
stream.Append(vertex);
|
||||
|
||||
OutStream.Append(vertex0);
|
||||
OutStream.Append(vertex1);
|
||||
OutStream.Append(vertex2);
|
||||
vertex.Vertex = input[2].Vertex;
|
||||
vertex.LayerIndex = input[2].LayerIndex;
|
||||
stream.Append(vertex);
|
||||
}
|
||||
|
||||
META_PS(true, FEATURE_LEVEL_ES2)
|
||||
|
||||
@@ -571,9 +571,9 @@ StructuredBuffer<BokehPoint> BokehPointBuffer : register(t2);
|
||||
// Vertex Shader, positions and scales the bokeh point
|
||||
META_VS(true, FEATURE_LEVEL_SM5)
|
||||
META_FLAG(VertexToGeometryShader)
|
||||
BokehVSOutput VS_Bokeh(in uint VertexID : SV_VertexID)
|
||||
BokehVSOutput VS_Bokeh(in uint vertexID : SV_VertexID)
|
||||
{
|
||||
BokehPoint bPoint = BokehPointBuffer[VertexID];
|
||||
BokehPoint bPoint = BokehPointBuffer[vertexID];
|
||||
BokehVSOutput output;
|
||||
|
||||
// Position the vertex in normalized device coordinate space [-1, 1]
|
||||
@@ -599,7 +599,7 @@ BokehVSOutput VS_Bokeh(in uint VertexID : SV_VertexID)
|
||||
// Geometry Shader, expands a vertex into a quad with two triangles
|
||||
META_GS(true, FEATURE_LEVEL_SM5)
|
||||
[maxvertexcount(4)]
|
||||
void GS_Bokeh(point BokehVSOutput input[1], inout TriangleStream<BokehGSOutput> SpriteStream)
|
||||
void GS_Bokeh(point BokehVSOutput input[1], inout TriangleStream<BokehGSOutput> stream)
|
||||
{
|
||||
BokehGSOutput output;
|
||||
|
||||
@@ -613,9 +613,9 @@ void GS_Bokeh(point BokehVSOutput input[1], inout TriangleStream<BokehGSOutput>
|
||||
output.Color = input[0].Color;
|
||||
output.Depth = input[0].Depth;
|
||||
|
||||
SpriteStream.Append(output);
|
||||
stream.Append(output);
|
||||
}
|
||||
SpriteStream.RestartStrip();
|
||||
stream.RestartStrip();
|
||||
}
|
||||
|
||||
// Pixel Shader, applies the bokeh shape texture
|
||||
|
||||
@@ -29,29 +29,29 @@ struct ExponentialHeightFogData
|
||||
float StartDistance;
|
||||
};
|
||||
|
||||
half4 GetExponentialHeightFog(ExponentialHeightFogData exponentialHeightFog, float3 worldPosition, float3 cameraPosition, float excludeDistance)
|
||||
float4 GetExponentialHeightFog(ExponentialHeightFogData exponentialHeightFog, float3 posWS, float3 camWS, float skipDistance)
|
||||
{
|
||||
float3 cameraToReceiver = worldPosition - cameraPosition;
|
||||
float cameraToReceiverLengthSqr = dot(cameraToReceiver, cameraToReceiver);
|
||||
float cameraToReceiverLengthInv = rsqrt(cameraToReceiverLengthSqr);
|
||||
float cameraToReceiverLength = cameraToReceiverLengthSqr * cameraToReceiverLengthInv;
|
||||
half3 cameraToReceiverNormalized = cameraToReceiver * cameraToReceiverLengthInv;
|
||||
float3 cameraToPos = posWS - camWS;
|
||||
float cameraToPosSqr = dot(cameraToPos, cameraToPos);
|
||||
float cameraToPosLenInv = rsqrt(cameraToPosSqr);
|
||||
float cameraToPosLen = cameraToPosSqr * cameraToPosLenInv;
|
||||
float3 cameraToReceiverNorm = cameraToPos * cameraToPosLenInv;
|
||||
|
||||
float rayOriginTerms = exponentialHeightFog.FogAtViewPosition;
|
||||
float rayLength = cameraToReceiverLength;
|
||||
float rayDirectionY = cameraToReceiver.y;
|
||||
float rayLength = cameraToPosLen;
|
||||
float rayDirectionY = cameraToPos.y;
|
||||
|
||||
// Apply start distance offset
|
||||
excludeDistance = max(excludeDistance, exponentialHeightFog.StartDistance);
|
||||
if (excludeDistance > 0)
|
||||
skipDistance = max(skipDistance, exponentialHeightFog.StartDistance);
|
||||
if (skipDistance > 0)
|
||||
{
|
||||
float excludeIntersectionTime = excludeDistance * cameraToReceiverLengthInv;
|
||||
float cameraToExclusionIntersectionY = excludeIntersectionTime * cameraToReceiver.y;
|
||||
float exclusionIntersectionY = cameraPosition.y + cameraToExclusionIntersectionY;
|
||||
float exclusionIntersectionToReceiverY = cameraToReceiver.y - cameraToExclusionIntersectionY;
|
||||
float excludeIntersectionTime = skipDistance * cameraToPosLenInv;
|
||||
float cameraToExclusionIntersectionY = excludeIntersectionTime * cameraToPos.y;
|
||||
float exclusionIntersectionY = camWS.y + cameraToExclusionIntersectionY;
|
||||
float exclusionIntersectionToReceiverY = cameraToPos.y - cameraToExclusionIntersectionY;
|
||||
|
||||
// Calculate fog off of the ray starting from the exclusion distance, instead of starting from the camera
|
||||
rayLength = (1.0f - excludeIntersectionTime) * cameraToReceiverLength;
|
||||
rayLength = (1.0f - excludeIntersectionTime) * cameraToPosLen;
|
||||
rayDirectionY = exclusionIntersectionToReceiverY;
|
||||
|
||||
// Move off the viewer
|
||||
@@ -67,22 +67,22 @@ half4 GetExponentialHeightFog(ExponentialHeightFogData exponentialHeightFog, flo
|
||||
float exponentialHeightLineIntegral = exponentialHeightLineIntegralCalc * rayLength;
|
||||
|
||||
// Calculate the amount of light that made it through the fog using the transmission equation
|
||||
half expFogFactor = max(saturate(exp2(-exponentialHeightLineIntegral)), exponentialHeightFog.FogMinOpacity);
|
||||
float expFogFactor = max(saturate(exp2(-exponentialHeightLineIntegral)), exponentialHeightFog.FogMinOpacity);
|
||||
|
||||
// Calculate the directional light inscattering
|
||||
half3 inscatteringColor = exponentialHeightFog.FogInscatteringColor;
|
||||
half3 directionalInscattering = 0;
|
||||
float3 inscatteringColor = exponentialHeightFog.FogInscatteringColor;
|
||||
float3 directionalInscattering = 0;
|
||||
BRANCH
|
||||
if (exponentialHeightFog.ApplyDirectionalInscattering > 0)
|
||||
{
|
||||
// Setup a cosine lobe around the light direction to approximate inscattering from the directional light off of the ambient haze
|
||||
half3 directionalLightInscattering = exponentialHeightFog.DirectionalInscatteringColor * pow(saturate(dot(cameraToReceiverNormalized, exponentialHeightFog.InscatteringLightDirection)), exponentialHeightFog.DirectionalInscatteringExponent);
|
||||
float3 directionalLightInscattering = exponentialHeightFog.DirectionalInscatteringColor * pow(saturate(dot(cameraToReceiverNorm, exponentialHeightFog.InscatteringLightDirection)), exponentialHeightFog.DirectionalInscatteringExponent);
|
||||
|
||||
// Calculate the line integral of the eye ray through the haze, using a special starting distance to limit the inscattering to the distance
|
||||
float dirExponentialHeightLineIntegral = exponentialHeightLineIntegralCalc * max(rayLength - exponentialHeightFog.DirectionalInscatteringStartDistance, 0.0f);
|
||||
|
||||
// Calculate the amount of light that made it through the fog using the transmission equation
|
||||
half directionalInscatteringFogFactor = saturate(exp2(-dirExponentialHeightLineIntegral));
|
||||
float directionalInscatteringFogFactor = saturate(exp2(-dirExponentialHeightLineIntegral));
|
||||
|
||||
// Final inscattering from the light
|
||||
directionalInscattering = directionalLightInscattering * (1 - directionalInscatteringFogFactor);
|
||||
@@ -90,13 +90,13 @@ half4 GetExponentialHeightFog(ExponentialHeightFogData exponentialHeightFog, flo
|
||||
|
||||
// Disable fog after a certain distance
|
||||
FLATTEN
|
||||
if (exponentialHeightFog.FogCutoffDistance > 0 && cameraToReceiverLength > exponentialHeightFog.FogCutoffDistance)
|
||||
if (exponentialHeightFog.FogCutoffDistance > 0 && cameraToPosLen > exponentialHeightFog.FogCutoffDistance)
|
||||
{
|
||||
expFogFactor = 1;
|
||||
directionalInscattering = 0;
|
||||
}
|
||||
|
||||
return half4((inscatteringColor) * (1 - expFogFactor) + directionalInscattering, expFogFactor);
|
||||
return float4(inscatteringColor * (1.0f - expFogFactor) + directionalInscattering, expFogFactor);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -33,15 +33,15 @@ float3 GetWorldPos(float2 uv)
|
||||
return mul(float4(viewPos, 1), gBufferData.InvViewMatrix).xyz;
|
||||
}
|
||||
|
||||
float4 CalculateCombinedFog(float3 worldPosition, float sceneDepth, float3 volumeUV)
|
||||
float4 CalculateCombinedFog(float3 posWS, float sceneDepth, float3 volumeUV)
|
||||
{
|
||||
float excludeDistance = 0;
|
||||
float skipDistance = 0;
|
||||
|
||||
#if VOLUMETRIC_FOG
|
||||
excludeDistance = max(ExponentialHeightFog.VolumetricFogMaxDistance - 100, 0);
|
||||
skipDistance = max(ExponentialHeightFog.VolumetricFogMaxDistance - 100, 0);
|
||||
#endif
|
||||
|
||||
float4 fog = GetExponentialHeightFog(ExponentialHeightFog, worldPosition, GBuffer.ViewPos, excludeDistance);
|
||||
float4 fog = GetExponentialHeightFog(ExponentialHeightFog, posWS, GBuffer.ViewPos, skipDistance);
|
||||
|
||||
#if VOLUMETRIC_FOG
|
||||
float4 volumetricFog = IntegratedLightScattering.SampleLevel(SamplerLinearClamp, volumeUV, 0);
|
||||
@@ -57,8 +57,8 @@ META_PERMUTATION_1(VOLUMETRIC_FOG=1)
|
||||
float4 PS_Fog(Quad_VS2PS input) : SV_Target0
|
||||
{
|
||||
// Calculate pixel world space position
|
||||
float3 worldPosition = GetWorldPos(input.TexCoord);
|
||||
float3 viewVector = worldPosition - GBuffer.ViewPos;
|
||||
float3 posWS = GetWorldPos(input.TexCoord);
|
||||
float3 viewVector = posWS - GBuffer.ViewPos;
|
||||
float sceneDepth = length(viewVector);
|
||||
|
||||
// Calculate volumetric fog coordinates
|
||||
@@ -67,17 +67,17 @@ float4 PS_Fog(Quad_VS2PS input) : SV_Target0
|
||||
|
||||
// Debug code
|
||||
#if VOLUMETRIC_FOG && 0
|
||||
volumeUV = worldPosition / 1000;
|
||||
volumeUV = posWS / 1000;
|
||||
if (!all(volumeUV >= 0 && volumeUV <= 1))
|
||||
return 0;
|
||||
|
||||
return float4(IntegratedLightScattering.SampleLevel(SamplerLinearClamp, volumeUV, 0).rgb, 1);
|
||||
//return float4(volumeUV, 1);
|
||||
//return float4(worldPosition / 100, 1);
|
||||
//return float4(posWS / 100, 1);
|
||||
#endif
|
||||
|
||||
// Calculate fog color
|
||||
float4 fog = CalculateCombinedFog(worldPosition, sceneDepth, volumeUV);
|
||||
float4 fog = CalculateCombinedFog(posWS, sceneDepth, volumeUV);
|
||||
|
||||
return fog;
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ float4 PS_FilterFace(Quad_VS2PS input) : SV_Target
|
||||
#define NUM_FILTER_SAMPLES 512
|
||||
|
||||
float3 N = normalize(cubeCoordinates);
|
||||
float roughness = ComputeReflectionCaptureRoughnessFromMip(SourceMipIndex);
|
||||
float roughness = ProbeRoughnessFromMip(SourceMipIndex);
|
||||
|
||||
float4 filteredColor = 0;
|
||||
float weight = 0;
|
||||
|
||||
@@ -61,7 +61,7 @@ META_CB_END
|
||||
META_CB_BEGIN(1, PerLight)
|
||||
|
||||
float2 Dummy1;
|
||||
int MinZ; // Z index of the minimum slice in the range
|
||||
int MinZ;
|
||||
float LocalLightScatteringIntensity;
|
||||
|
||||
float4 ViewSpaceBoundingSphere;
|
||||
@@ -72,48 +72,44 @@ LightShadowData LocalLightShadow;
|
||||
|
||||
META_CB_END
|
||||
|
||||
float ComputeDepthFromZSlice(float zSlice)
|
||||
{
|
||||
return (zSlice / GridSize.z) * VolumetricFogMaxDistance;
|
||||
}
|
||||
|
||||
float3 ComputeCellWorldPosition(uint3 gridCoordinate, float3 cellOffset, out float sceneDepth)
|
||||
{
|
||||
float2 volumeUV = (gridCoordinate.xy + cellOffset.xy) / GridSize.xy;
|
||||
sceneDepth = ComputeDepthFromZSlice(gridCoordinate.z + cellOffset.z) / GBuffer.ViewFar;
|
||||
float deviceDepth = LinearZ2DeviceDepth(GBuffer, sceneDepth);
|
||||
return GetWorldPos(GBuffer, volumeUV, deviceDepth);
|
||||
}
|
||||
|
||||
float3 ComputeCellWorldPosition(uint3 gridCoordinate, float3 cellOffset)
|
||||
{
|
||||
float unused;
|
||||
return ComputeCellWorldPosition(gridCoordinate, cellOffset, unused);
|
||||
}
|
||||
|
||||
float ComputeNormalizedZSliceFromDepth(float sceneDepth)
|
||||
{
|
||||
return sceneDepth / VolumetricFogMaxDistance;
|
||||
}
|
||||
|
||||
float3 ComputeVolumeUV(float3 worldPosition, float4x4 worldToClip)
|
||||
{
|
||||
float4 ndcPosition = mul(float4(worldPosition, 1), worldToClip);
|
||||
ndcPosition.xy /= ndcPosition.w;
|
||||
return float3(ndcPosition.xy * float2(0.5f, -0.5f) + 0.5f, ComputeNormalizedZSliceFromDepth(ndcPosition.w));
|
||||
}
|
||||
|
||||
// The Henyey-Greenstein phase function
|
||||
// [Henyey and Greenstein 1941, https://www.astro.umd.edu/~jph/HG_note.pdf]
|
||||
float HenyeyGreensteinPhase(float g, float cosTheta)
|
||||
{
|
||||
return (1 - g * g) / (4 * PI * pow(1 + g * g + 2 * g * cosTheta, 1.5f));
|
||||
}
|
||||
|
||||
// +g = forward scattering, 0=g = isotropic, -g = backward scattering
|
||||
float PhaseFunction(float g, float cosTheta)
|
||||
float GetPhase(float g, float cosTheta)
|
||||
{
|
||||
return HenyeyGreensteinPhase(g, cosTheta);
|
||||
}
|
||||
|
||||
float GetSliceDepth(float zSlice)
|
||||
{
|
||||
return (zSlice / GridSize.z) * VolumetricFogMaxDistance;
|
||||
}
|
||||
|
||||
float3 GetCellPositionWS(uint3 gridCoordinate, float3 cellOffset, out float sceneDepth)
|
||||
{
|
||||
float2 volumeUV = (gridCoordinate.xy + cellOffset.xy) / GridSize.xy;
|
||||
sceneDepth = GetSliceDepth(gridCoordinate.z + cellOffset.z) / GBuffer.ViewFar;
|
||||
float deviceDepth = LinearZ2DeviceDepth(GBuffer, sceneDepth);
|
||||
return GetWorldPos(GBuffer, volumeUV, deviceDepth);
|
||||
}
|
||||
|
||||
float3 GetCellPositionWS(uint3 gridCoordinate, float3 cellOffset)
|
||||
{
|
||||
float temp;
|
||||
return GetCellPositionWS(gridCoordinate, cellOffset, temp);
|
||||
}
|
||||
|
||||
float3 GetVolumeUV(float3 worldPosition, float4x4 worldToClip)
|
||||
{
|
||||
float4 ndcPosition = mul(float4(worldPosition, 1), worldToClip);
|
||||
ndcPosition.xy /= ndcPosition.w;
|
||||
return float3(ndcPosition.xy * float2(0.5f, -0.5f) + 0.5f, ndcPosition.w / VolumetricFogMaxDistance);
|
||||
}
|
||||
|
||||
// Vertex shader that writes to a range of slices of a volume texture
|
||||
META_VS(true, FEATURE_LEVEL_SM5)
|
||||
META_FLAG(VertexToGeometryShader)
|
||||
@@ -123,22 +119,18 @@ Quad_VS2GS VS_WriteToSlice(float2 TexCoord : TEXCOORD0, uint LayerIndex : SV_Ins
|
||||
Quad_VS2GS output;
|
||||
|
||||
uint slice = LayerIndex + MinZ;
|
||||
float sliceDepth = ComputeDepthFromZSlice(slice);
|
||||
float sliceDepthOffset = abs(sliceDepth - ViewSpaceBoundingSphere.z);
|
||||
float depth = GetSliceDepth(slice);
|
||||
float depthOffset = abs(depth - ViewSpaceBoundingSphere.z);
|
||||
|
||||
if (sliceDepthOffset < ViewSpaceBoundingSphere.w)
|
||||
if (depthOffset < ViewSpaceBoundingSphere.w)
|
||||
{
|
||||
// Compute the radius of the circle formed by the intersection of the bounding sphere and the current depth slice
|
||||
float sliceRadius = sqrt(ViewSpaceBoundingSphere.w * ViewSpaceBoundingSphere.w - sliceDepthOffset * sliceDepthOffset);
|
||||
|
||||
// Place the quad vertex to tightly bound the circle
|
||||
float3 viewSpaceVertexPosition = float3(ViewSpaceBoundingSphere.xy + (TexCoord * 2 - 1) * sliceRadius, sliceDepth);
|
||||
output.Vertex.Position = mul(float4(viewSpaceVertexPosition, 1), ViewToVolumeClip);
|
||||
float radius = sqrt(ViewSpaceBoundingSphere.w * ViewSpaceBoundingSphere.w - depthOffset * depthOffset);
|
||||
float3 positionVS = float3(ViewSpaceBoundingSphere.xy + (TexCoord * 2 - 1) * radius, depth);
|
||||
output.Vertex.Position = mul(float4(positionVS, 1), ViewToVolumeClip);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Slice does not intersect bounding sphere, emit degenerate triangle
|
||||
output.Vertex.Position = 0;
|
||||
output.Vertex.Position = float4(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
output.Vertex.TexCoord = 0;
|
||||
@@ -150,23 +142,21 @@ Quad_VS2GS VS_WriteToSlice(float2 TexCoord : TEXCOORD0, uint LayerIndex : SV_Ins
|
||||
// Geometry shader that writes to a range of slices of a volume texture
|
||||
META_GS(true, FEATURE_LEVEL_SM5)
|
||||
[maxvertexcount(3)]
|
||||
void GS_WriteToSlice(triangle Quad_VS2GS input[3], inout TriangleStream<Quad_GS2PS> OutStream)
|
||||
void GS_WriteToSlice(triangle Quad_VS2GS input[3], inout TriangleStream<Quad_GS2PS> stream)
|
||||
{
|
||||
Quad_GS2PS vertex0;
|
||||
vertex0.Vertex = input[0].Vertex;
|
||||
vertex0.LayerIndex = input[0].LayerIndex;
|
||||
Quad_GS2PS vertex;
|
||||
|
||||
Quad_GS2PS vertex1;
|
||||
vertex1.Vertex = input[1].Vertex;
|
||||
vertex1.LayerIndex = input[1].LayerIndex;
|
||||
vertex.Vertex = input[0].Vertex;
|
||||
vertex.LayerIndex = input[0].LayerIndex;
|
||||
stream.Append(vertex);
|
||||
|
||||
Quad_GS2PS vertex2;
|
||||
vertex2.Vertex = input[2].Vertex;
|
||||
vertex2.LayerIndex = input[2].LayerIndex;
|
||||
vertex.Vertex = input[1].Vertex;
|
||||
vertex.LayerIndex = input[1].LayerIndex;
|
||||
stream.Append(vertex);
|
||||
|
||||
OutStream.Append(vertex0);
|
||||
OutStream.Append(vertex1);
|
||||
OutStream.Append(vertex2);
|
||||
vertex.Vertex = input[2].Vertex;
|
||||
vertex.LayerIndex = input[2].LayerIndex;
|
||||
stream.Append(vertex);
|
||||
}
|
||||
|
||||
#if USE_SHADOW
|
||||
@@ -208,18 +198,16 @@ float4 PS_InjectLight(Quad_GS2PS input) : SV_Target0
|
||||
return 0;
|
||||
|
||||
#if USE_TEMPORAL_REPROJECTION
|
||||
float3 historyUV = ComputeVolumeUV(ComputeCellWorldPosition(gridCoordinate, 0.5f), PrevWorldToClip);
|
||||
float3 historyUV = GetVolumeUV(GetCellPositionWS(gridCoordinate, 0.5f), PrevWorldToClip);
|
||||
float historyAlpha = HistoryWeight;
|
||||
|
||||
FLATTEN
|
||||
if (any(historyUV < 0) || any(historyUV > 1))
|
||||
{
|
||||
historyAlpha = 0;
|
||||
}
|
||||
|
||||
uint numSuperSamples = historyAlpha < .001f ? HistoryMissSuperSampleCount : 1;
|
||||
uint samplesCount = historyAlpha < 0.001f ? HistoryMissSuperSampleCount : 1;
|
||||
#else
|
||||
uint numSuperSamples = 1;
|
||||
uint samplesCount = 1;
|
||||
#endif
|
||||
|
||||
float3 L = 0;
|
||||
@@ -229,22 +217,19 @@ float4 PS_InjectLight(Quad_GS2PS input) : SV_Target0
|
||||
float lightRadiusMask = 1;
|
||||
float spotAttenuation = 1;
|
||||
bool isSpotLight = LocalLight.SpotAngles.x > -2.0f;
|
||||
|
||||
float4 scattering = 0;
|
||||
for (uint sampleIndex = 0; sampleIndex < numSuperSamples; sampleIndex++)
|
||||
for (uint sampleIndex = 0; sampleIndex < samplesCount; sampleIndex++)
|
||||
{
|
||||
float3 cellOffset = FrameJitterOffsets[sampleIndex].xyz;
|
||||
//float cellOffset = 0.5f;
|
||||
|
||||
float3 worldPosition = ComputeCellWorldPosition(gridCoordinate, cellOffset);
|
||||
float3 cameraVector = normalize(worldPosition - GBuffer.ViewPos);
|
||||
float cellRadius = length(worldPosition - ComputeCellWorldPosition(gridCoordinate + uint3(1, 1, 1), cellOffset));
|
||||
|
||||
// Bias the inverse squared light falloff based on voxel size to prevent aliasing near the light source
|
||||
float3 positionWS = GetCellPositionWS(gridCoordinate, cellOffset);
|
||||
float3 cameraVector = normalize(positionWS - GBuffer.ViewPos);
|
||||
float cellRadius = length(positionWS - GetCellPositionWS(gridCoordinate + uint3(1, 1, 1), cellOffset));
|
||||
float distanceBias = max(cellRadius * InverseSquaredLightDistanceBiasScale, 1);
|
||||
|
||||
// Get the light attenuation
|
||||
GetRadialLightAttenuation(LocalLight, isSpotLight, worldPosition, float3(0, 0, 1), distanceBias * distanceBias, toLight, L, NoL, distanceAttenuation, lightRadiusMask, spotAttenuation);
|
||||
// Calculate the light attenuation
|
||||
GetRadialLightAttenuation(LocalLight, isSpotLight, positionWS, float3(0, 0, 1), distanceBias * distanceBias, toLight, L, NoL, distanceAttenuation, lightRadiusMask, spotAttenuation);
|
||||
float combinedAttenuation = distanceAttenuation * lightRadiusMask * spotAttenuation;
|
||||
|
||||
// Peek the shadow
|
||||
@@ -252,16 +237,14 @@ float4 PS_InjectLight(Quad_GS2PS input) : SV_Target0
|
||||
#if USE_SHADOW
|
||||
if (combinedAttenuation > 0)
|
||||
{
|
||||
shadowFactor = ComputeVolumeShadowing(worldPosition, isSpotLight);
|
||||
shadowFactor = ComputeVolumeShadowing(positionWS, isSpotLight);
|
||||
}
|
||||
#endif
|
||||
|
||||
scattering.rgb += LocalLight.Color * (PhaseFunction(PhaseG, dot(L, -cameraVector)) * combinedAttenuation * shadowFactor * LocalLightScatteringIntensity);
|
||||
scattering.rgb += LocalLight.Color * (GetPhase(PhaseG, dot(L, -cameraVector)) * combinedAttenuation * shadowFactor * LocalLightScatteringIntensity);
|
||||
}
|
||||
|
||||
// Normalize
|
||||
scattering.rgb /= (float)numSuperSamples;
|
||||
|
||||
scattering.rgb /= (float)samplesCount;
|
||||
return scattering;
|
||||
}
|
||||
|
||||
@@ -280,7 +263,7 @@ void CS_Initialize(uint3 GroupId : SV_GroupID, uint3 DispatchThreadId : SV_Dispa
|
||||
|
||||
// Center of the voxel
|
||||
float voxelOffset = 0.5f;
|
||||
float3 worldPosition = ComputeCellWorldPosition(gridCoordinate, voxelOffset);
|
||||
float3 positionWS = GetCellPositionWS(gridCoordinate, voxelOffset);
|
||||
|
||||
// Unpack the fog parameters (packing done in C++ ExponentialHeightFog::GetVolumetricFogOptions)
|
||||
float fogDensity = FogParameters.x;
|
||||
@@ -288,7 +271,7 @@ void CS_Initialize(uint3 GroupId : SV_GroupID, uint3 DispatchThreadId : SV_Dispa
|
||||
float fogHeightFalloff = FogParameters.z;
|
||||
|
||||
// Calculate the global fog density that matches the exponential height fog density
|
||||
float globalDensity = fogDensity * exp2(-fogHeightFalloff * (worldPosition.y - fogHeight));
|
||||
float globalDensity = fogDensity * exp2(-fogHeightFalloff * (positionWS.y - fogHeight));
|
||||
float matchFactor = 0.24f;
|
||||
float extinction = max(globalDensity * GlobalExtinctionScale * matchFactor, 0);
|
||||
|
||||
@@ -326,7 +309,7 @@ void CS_LightScattering(uint3 GroupId : SV_GroupID, uint3 DispatchThreadId : SV_
|
||||
uint numSuperSamples = 1;
|
||||
|
||||
#if USE_TEMPORAL_REPROJECTION
|
||||
float3 historyUV = ComputeVolumeUV(ComputeCellWorldPosition(gridCoordinate, 0.5f), PrevWorldToClip);
|
||||
float3 historyUV = GetVolumeUV(GetCellPositionWS(gridCoordinate, 0.5f), PrevWorldToClip);
|
||||
float historyAlpha = HistoryWeight;
|
||||
|
||||
// Discard history if it lays outside the current view
|
||||
@@ -347,8 +330,8 @@ void CS_LightScattering(uint3 GroupId : SV_GroupID, uint3 DispatchThreadId : SV_
|
||||
//float3 cellOffset = 0.5f;
|
||||
|
||||
float sceneDepth;
|
||||
float3 worldPosition = ComputeCellWorldPosition(gridCoordinate, cellOffset, sceneDepth);
|
||||
float3 cameraVector = worldPosition - GBuffer.ViewPos;
|
||||
float3 positionWS = GetCellPositionWS(gridCoordinate, cellOffset, sceneDepth);
|
||||
float3 cameraVector = positionWS - GBuffer.ViewPos;
|
||||
float cameraVectorLength = length(cameraVector);
|
||||
float3 cameraVectorNormalized = cameraVector / cameraVectorLength;
|
||||
|
||||
@@ -360,10 +343,10 @@ void CS_LightScattering(uint3 GroupId : SV_GroupID, uint3 DispatchThreadId : SV_
|
||||
float shadow = 1;
|
||||
if (DirectionalLightShadow.NumCascades > 0)
|
||||
{
|
||||
shadow = SampleShadow(DirectionalLight, DirectionalLightShadow, ShadowMapCSM, worldPosition, cameraVectorLength);
|
||||
shadow = SampleShadow(DirectionalLight, DirectionalLightShadow, ShadowMapCSM, positionWS, cameraVectorLength);
|
||||
}
|
||||
|
||||
lightScattering += DirectionalLight.Color * (8 * shadow * PhaseFunction(PhaseG, dot(DirectionalLight.Direction, cameraVectorNormalized)));
|
||||
lightScattering += DirectionalLight.Color * (8 * shadow * GetPhase(PhaseG, dot(DirectionalLight.Direction, cameraVectorNormalized)));
|
||||
}
|
||||
|
||||
// Sky light
|
||||
@@ -414,38 +397,30 @@ META_CS(true, FEATURE_LEVEL_SM5)
|
||||
void CS_FinalIntegration(uint3 GroupId : SV_GroupID, uint3 DispatchThreadId : SV_DispatchThreadID, uint3 GroupThreadId : SV_GroupThreadID)
|
||||
{
|
||||
uint3 gridCoordinate = DispatchThreadId;
|
||||
|
||||
float4 accumulatedLightingAndTransmittance = float4(0, 0, 0, 1);
|
||||
float3 previousSliceWorldPosition = GBuffer.ViewPos;
|
||||
float4 acc = float4(0, 0, 0, 1);
|
||||
float3 prevPositionWS = GBuffer.ViewPos;
|
||||
|
||||
for (uint layerIndex = 0; layerIndex < GridSizeInt.z; layerIndex++)
|
||||
{
|
||||
uint3 layerCoordinate = uint3(gridCoordinate.xy, layerIndex);
|
||||
float4 scatteringAndExtinction = LightScattering[layerCoordinate];
|
||||
|
||||
float3 layerWorldPosition = ComputeCellWorldPosition(layerCoordinate, 0.5f);
|
||||
float stepLength = length(layerWorldPosition - previousSliceWorldPosition);
|
||||
previousSliceWorldPosition = layerWorldPosition;
|
||||
|
||||
float transmittance = exp(-scatteringAndExtinction.w * stepLength);
|
||||
uint3 coords = uint3(gridCoordinate.xy, layerIndex);
|
||||
float4 scatteringExtinction = LightScattering[coords];
|
||||
float3 positionWS = GetCellPositionWS(coords, 0.5f);
|
||||
|
||||
// Ref: "Physically Based and Unified Volumetric Rendering in Frostbite"
|
||||
#define ENERGY_CONSERVING_INTEGRATION 1
|
||||
#if ENERGY_CONSERVING_INTEGRATION
|
||||
float3 scatteringIntegratedOverSlice = (scatteringAndExtinction.rgb - scatteringAndExtinction.rgb * transmittance) / max(scatteringAndExtinction.w, .00001f);
|
||||
accumulatedLightingAndTransmittance.rgb += scatteringIntegratedOverSlice * accumulatedLightingAndTransmittance.a;
|
||||
#else
|
||||
accumulatedLightingAndTransmittance.rgb += scatteringAndExtinction.rgb * accumulatedLightingAndTransmittance.a;
|
||||
#endif
|
||||
accumulatedLightingAndTransmittance.a *= transmittance;
|
||||
|
||||
float transmittance = exp(-scatteringExtinction.w * length(positionWS - prevPositionWS));
|
||||
float3 scatteringIntegratedOverSlice = (scatteringExtinction.rgb - scatteringExtinction.rgb * transmittance) / max(scatteringExtinction.w, 0.00001f);
|
||||
acc.rgb += scatteringIntegratedOverSlice * acc.a;
|
||||
acc.a *= transmittance;
|
||||
|
||||
#if DEBUG_VOXELS
|
||||
RWIntegratedLightScattering[layerCoordinate] = float4(scatteringAndExtinction.rgb, 1.0f);
|
||||
RWIntegratedLightScattering[coords] = float4(scatteringExtinction.rgb, 1.0f);
|
||||
#elif DEBUG_VOXEL_WS_POS
|
||||
RWIntegratedLightScattering[layerCoordinate] = float4(layerWorldPosition.rgb, 1.0f);
|
||||
RWIntegratedLightScattering[coords] = float4(positionWS.rgb, 1.0f);
|
||||
#else
|
||||
RWIntegratedLightScattering[layerCoordinate] = accumulatedLightingAndTransmittance;
|
||||
RWIntegratedLightScattering[coords] = acc;
|
||||
#endif
|
||||
|
||||
prevPositionWS = positionWS;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user