Buckets:
| /*============================================================================= | |
| 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.