utkuatlastuzcu/tst / Engine /Shaders /FogIntegralPixelShader.usf
utkuatlastuzcu's picture
download
raw
9.74 kB
/*=============================================================================
FogIntegralPixelShader.usf: Computes the line integral for fog volumes
Copyright 1998-2008 Epic Games, Inc. All Rights Reserved.
=============================================================================*/
#include "Common.usf"
#include "FogVolumeCommon.usf"
#include "Material.usf"
#include "VertexFactory.usf"
/* transform from post projective space to world space */
float4x4 ScreenToWorld;
/* world space camera position */
float4 FogCameraPosition;
/* set to 1.0f for backfaces, and -1.0f for frontfaces */
float FaceScale;
/* offsets for filtering scene depth */
float4 DepthFilterSampleOffsets[2];
/* 1 / MaxIntegral estimate for the density function */
float InvMaxIntegral;
/*
* Filters scene depth by taking 4 samples and averaging the results
* which helps to antialias it when rendering to a downsampled integral buffer.
*/
half PreviousFilteredDepth(float4 ScreenPosition)
{
float2 PersCorrectScreenPos = ScreenPosition.xy / ScreenPosition.w * ScreenPositionScaleBias.xy + ScreenPositionScaleBias.wz;
half4 Depths;
float4 FirstOffsetPos = DepthFilterSampleOffsets[0] + PersCorrectScreenPos.xyxy;
float4 SecondOffsetPos = DepthFilterSampleOffsets[1] + PersCorrectScreenPos.xyxy;
#if SUPPORTS_DEPTH_TEXTURES
Depths.x = texDepth2D(SceneDepthTexture, FirstOffsetPos.xy).r;
Depths.y = texDepth2D(SceneDepthTexture, FirstOffsetPos.zw).r;
Depths.z = texDepth2D(SceneDepthTexture, SecondOffsetPos.xy).r;
Depths.w = texDepth2D(SceneDepthTexture, SecondOffsetPos.zw).r;
Depths = 1.f / (Depths * MinZ_MaxZRatio.zzzz - MinZ_MaxZRatio.wwww);
#else
Depths.x = CalcSceneDepth(FirstOffsetPos.xy);
Depths.y = CalcSceneDepth(FirstOffsetPos.zw);
Depths.z = CalcSceneDepth(SecondOffsetPos.xy);
Depths.w = CalcSceneDepth(SecondOffsetPos.zw);
#endif
half SampleWeight = 1.0f / 4.0f;
float AverageDepth = dot(Depths, SampleWeight.xxxx);
//sample the current position if desired, doesn't make a big visual difference
//AverageDepth = AverageDepth + 1.0f / 3.0f * tex2D(SceneColorTexture, PersCorrectScreenPos.xy).w;
return AverageDepth;
}
/*
* Returns the filtered world space position of ScreenPosition or the closest opaque object.
*/
float3 GetClosestFilteredWorldPos(float4 ScreenPosition)
{
half SceneW = PreviousFilteredDepth(ScreenPosition);
//clamp scene depth to a reasonable range
SceneW = min(SceneW, 65535.0f);
//use whichever is closest, this pixel or the nearest opaque object
half ClosestDistance = min(SceneW, ScreenPosition.z);
//transform into worldspace
return MulMatrix(ScreenToWorld, float4(ScreenPosition.xy / ScreenPosition.w * ClosestDistance, ClosestDistance, 1)).xyz;
}
/*
* Returns the world space position of ScreenPosition or the closest opaque object.
*/
float3 GetClosestWorldPos(float4 ScreenPosition)
{
half SceneW = PreviousDepth(ScreenPosition);
//clamp scene depth to a reasonable range
SceneW = min(SceneW, 65535.0f);
//use whichever is closest, this pixel or the nearest opaque object
half ClosestDistance = min(SceneW, ScreenPosition.z);
//transform into worldspace
return MulMatrix(ScreenToWorld, float4(ScreenPosition.xy / ScreenPosition.w * ClosestDistance, ClosestDistance, 1)).xyz;
}
/*
* Encodes the floating point integral based on what the current platform needs.
* Platforms that can do high precision fp blending negate the integral for frontfaces,
* Platforms without fp blending pack the integral into a fixed point buffer.
*/
float4 EncodeIntegral(float Integral)
{
#if XBOX || SM2_PROFILE
/*
//pack the integral into G16R16
float NormalizedIntegral = Integral * InvMaxIntegral;
float2 Shift = float2(65536.0f, 1.0f);
float2 Mask = float2(0.0f, 1.0f / 65536.0f);
float2 ClampedIntegral = frac(NormalizedIntegral.xx * Shift);
float2 EncodedIntegral = ClampedIntegral - ClampedIntegral.xx * Mask;
return float4(EncodedIntegral.x, EncodedIntegral.y, 0.0f, 0.0f);
*/
//24bits, from the lowest 6 bits of RGBA8. 2 are left over for overflow in each channel, for a max of 4 additive blends
//normalize the integral
float NormalizedIntegral = saturate(Integral * InvMaxIntegral);
//shift up 18, 12, 6, 0 bits
//x will store the lowest value 6 bits of the integral, w will store the highest 6 bits
float4 Shift = float4(262144.0f, 4096.0f, 64.0f, 1.0f);
//shift the values and clamp off anything greater than 1
float4 ClampedIntegral = frac(NormalizedIntegral.xxxx * Shift);
//6 bit shift down, converts between channels
float ChannelShift = 1.0f / 64.0f;
//clamp off anything lower than what can be stored in the channel's 6 bits to avoid rounding by the hardware
//this is done by subtracting the lower channels after shifting them into the same space
ClampedIntegral.yzw = ClampedIntegral.yzw - ClampedIntegral.xyz * ChannelShift.xxx;
//shift every channel down 2 bits, so additive blends will overflow into these bits
return ClampedIntegral / 4.0f;
#else
//add backface integral results, subtract frontface results
return float4(Integral * FaceScale, 0.0f, 0.0f, 0.0f);
#endif
}
/*
* Constant density - constant density factor stored in FirstDensityFunctionParameters.x
*
* Computes the line integral from the camera to the current face of the fog volume being rendered
* or an intersecting opaque object.
*/
void ConstantDensityMain(
FVertexFactoryInterpolants Interpolants,
float4 ScreenPosition : TEXCOORD5,
out float4 OutColor : COLOR0
)
{
half SceneW = PreviousFilteredDepth(ScreenPosition);
SceneW = min(SceneW, 65535.0f);
//use whichever is closest, this pixel or the nearest opaque object
half ClosestDistance = min(SceneW, ScreenPosition.z);
ClosestDistance = max(ClosestDistance - StartDistance, 0.0f);
//constant density
float LineIntegral = ClosestDistance * FirstDensityFunctionParameters.x;
OutColor = EncodeIntegral(LineIntegral);
}
/*
* Entry point for LinearHalfspace Density
*/
void LinearHalfspaceDensityMain(
FVertexFactoryInterpolants Interpolants,
float4 ScreenPosition : TEXCOORD5,
out float4 OutColor : COLOR0
)
{
float3 WorldReceiverPos = GetClosestFilteredWorldPos(ScreenPosition);
OutColor = EncodeIntegral(LinearHalfspaceLineIntegral(WorldReceiverPos, FogCameraPosition.xyz));
}
/*
* Entry point for Spherical Density
*/
void SphericalDensityMain(
FVertexFactoryInterpolants Interpolants,
float4 ScreenPosition : TEXCOORD5,
out float4 OutColor : COLOR0
)
{
#if SM2_PROFILE
//try to minimize instructions on SM2 so use the unfiltered version
float3 WorldReceiverPos = GetClosestWorldPos(ScreenPosition);
#else
float3 WorldReceiverPos = GetClosestFilteredWorldPos(ScreenPosition);
#endif
OutColor = EncodeIntegral(SphericalLineIntegral(WorldReceiverPos, FogCameraPosition.xyz));
}
/*
* Not fully implemented
*
* Computes the line integral from the camera to the current face of the fog volume being rendered
* or an intersecting opaque object.
*/
void ConeDensityMain(
FVertexFactoryInterpolants Interpolants,
float4 ScreenPosition : TEXCOORD5,
out float4 OutColor : COLOR0
)
{
float LineIntegral = 0;
float3 WorldReceiverPos = GetClosestFilteredWorldPos(ScreenPosition);
float3 ConeVertex = FirstDensityFunctionParameters.xyz;
float MaxDensity = FirstDensityFunctionParameters.w;
float3 ConeAxis = SecondDensityFunctionParameters.xyz;
float ConeRadius = SecondDensityFunctionParameters.w;
/*
float3 ConeVertex = FirstDensityFunctionParameters.xyz;
float MaxDensity = .01;
float3 ConeAxis = float3(1,0,0);
float ConeRadius = 600.0f;
*/
float CosSqTheta = cos(3.1415926535f / 4.0f) * cos(3.1415926535f / 4.0f);
//float CosSqTheta = .5;
float3 View = WorldReceiverPos - FogCameraPosition.xyz;
//@todo: eliminate the reflection
{
//find intersections with the cone
//Point along Ray from camera to receiver = X = FogCameraPosition + View * t
//Cone Equation => dot(ConeAxis, (X - ConeVertex) / length(X - ConeVertex)) = cos(theta)
//Solve for 2 intersections
float3 QuadraticCoef;
float ConeAxisDotView = dot(ConeAxis, View);
QuadraticCoef.x = ConeAxisDotView * ConeAxisDotView - CosSqTheta * dot(View, View);
float ConeAxisDotVertex = dot(ConeAxis, ConeVertex);
float AxisDotCameraPos = dot(ConeAxis, FogCameraPosition);
QuadraticCoef.y = 2.0f * AxisDotCameraPos * ConeAxisDotView - 2.0f * ConeAxisDotView * ConeAxisDotVertex
- CosSqTheta * 2.0f * dot(FogCameraPosition - ConeVertex, View);
QuadraticCoef.z = AxisDotCameraPos * AxisDotCameraPos - 2.0f * AxisDotCameraPos * ConeAxisDotVertex + ConeAxisDotVertex * ConeAxisDotVertex
- CosSqTheta * dot(FogCameraPosition - ConeVertex, FogCameraPosition - ConeVertex);
//b^2 - 4 * a * c
float Discriminant = QuadraticCoef.y * QuadraticCoef.y - 4.0f * QuadraticCoef.x * QuadraticCoef.z;
if (Discriminant >= 0)
{
float InvTwoA = 1.0f / (2.0f * QuadraticCoef.x);
float SqrtDiscriminant = sqrt(Discriminant);
//closest intersection stored in x, furthest in y
float2 Intersections = (-QuadraticCoef.yy + float2(SqrtDiscriminant, -SqrtDiscriminant)) * InvTwoA;
//handle special case where the ray only intersects the near side of the cone
if (Intersections.y < Intersections.x)
{
Intersections = float2(Intersections.x, 1);
}
//clamp intersections to [0, 1]
Intersections = saturate(Intersections);
LineIntegral = MaxDensity * (Intersections.y - Intersections.x) * length(View);
}
}
OutColor = EncodeIntegral(LineIntegral);
}

Xet Storage Details

Size:
9.74 kB
·
Xet hash:
ac6675c071eb44771e8d50060773b90f42fa419e9859bdb7fb200c966c3e3267

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.