Buckets:
| /*============================================================================= | |
| FogVolumeCommon.usf: | |
| Copyright 1998-2008 Epic Games, Inc. All Rights Reserved. | |
| =============================================================================*/ | |
| /* parameters specific to the density function */ | |
| const float4 FirstDensityFunctionParameters; | |
| const float4 SecondDensityFunctionParameters; | |
| /* Distance from the camera that fog should start, in world units. */ | |
| float StartDistance; | |
| /* Used to avoid divide by zero */ | |
| const static float Epsilon = .0001; | |
| /* | |
| * Clips a ray to an AABB. Does not handle rays parallel to any of the planes. | |
| * | |
| * @param RayOrigin - The origin of the ray in world space. | |
| * @param RayEnd - The end of the ray in world space. | |
| * @param BoxMin - The minimum extrema of the box. | |
| * @param BoxMax - The maximum extrema of the box. | |
| * @return - Returns the closest intersection along the ray in x, and furthest in y. | |
| * If the ray did not intersect the box, then the furthest intersection <= the closest intersection. | |
| * The intersections will always be in the range [0,1], which corresponds to [RayOrigin, RayEnd] in worldspace. | |
| * To find the world space position of either intersection, simply plug it back into the ray equation: | |
| * WorldPos = RayOrigin + (RayEnd - RayOrigin) * Intersection; | |
| */ | |
| float2 RayBoxIntersect(float3 RayOrigin, float3 RayEnd, float3 BoxMin, float3 BoxMax) | |
| { | |
| float3 InvRayDir = 1.0f / (RayEnd - RayOrigin); | |
| //find the ray intersection with each of the 3 planes defined by the minimum extrema. | |
| float3 FirstPlaneIntersections = (BoxMin - RayOrigin) * InvRayDir; | |
| //find the ray intersection with each of the 3 planes defined by the maximum extrema. | |
| float3 SecondPlaneIntersections = (BoxMax - RayOrigin) * InvRayDir; | |
| //get the closest of these intersections along the ray | |
| float3 ClosestPlaneIntersections = min(FirstPlaneIntersections, SecondPlaneIntersections); | |
| //get the furthest of these intersections along the ray | |
| float3 FurthestPlaneIntersections = max(FirstPlaneIntersections, SecondPlaneIntersections); | |
| float2 BoxIntersections; | |
| //find the furthest near intersection | |
| BoxIntersections.x = max(ClosestPlaneIntersections.x, max(ClosestPlaneIntersections.y, ClosestPlaneIntersections.z)); | |
| //find the closest far intersection | |
| BoxIntersections.y = min(FurthestPlaneIntersections.x, min(FurthestPlaneIntersections.y, FurthestPlaneIntersections.z)); | |
| //clamp the intersections to be between RayOrigin and RayEnd on the ray | |
| return saturate(BoxIntersections); | |
| } | |
| /* | |
| * 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. | |
| */ | |
| float ConstantDensityLineIntegral(float3 WorldReceiverPos, float3 InCameraPosition, float2 IntersectionRange) | |
| { | |
| float3 V = InCameraPosition - WorldReceiverPos; | |
| float CameraToReceiverDistance = max(length(V) - StartDistance, 0.0f); | |
| return CameraToReceiverDistance * saturate(IntersectionRange.y - IntersectionRange.x) * FirstDensityFunctionParameters.x; | |
| } | |
| /* | |
| * A halfspace of fog with density increasing linearly away from the plane, | |
| * linear density factor stored in FirstDensityFunctionParameters.x, plane stored in SecondDensityFunctionParameters | |
| * | |
| * Computes the line integral from the camera to the current face of the fog volume being rendered | |
| * or an intersecting opaque object. | |
| */ | |
| float LinearHalfspaceLineIntegral(float3 WorldReceiverPos, float3 InCameraPosition) | |
| { | |
| //parametrize the ray as R = WorldPos + V * t; | |
| //so ray origin is WorldPos, ray direction is V | |
| float3 V = InCameraPosition - WorldReceiverPos; | |
| //linear halfspace density | |
| float FDotC = dot(SecondDensityFunctionParameters, float4(InCameraPosition, 1)); | |
| float FDotP = dot(SecondDensityFunctionParameters, float4(WorldReceiverPos, 1)); | |
| float FDotV = dot(SecondDensityFunctionParameters, float4(V, 0)); | |
| //@todo: implement StartDistance | |
| float CameraOutsideMask = FDotC <= 0; | |
| float IntersectionMask = min((1 - 2 * CameraOutsideMask) * FDotP, 0); | |
| float IntersectionPortion = IntersectionMask * IntersectionMask / (abs(FDotV) + Epsilon); | |
| float InsideVolumePortion = CameraOutsideMask * (FDotP + FDotC); | |
| return -.5 * FirstDensityFunctionParameters.x * .0001f * length(V) * (InsideVolumePortion - IntersectionPortion); | |
| } | |
| /* | |
| * A halfspace of fog with density increasing linearly away from the plane, | |
| * Density function = -FirstDensityFunctionParameters.x * DistanceToPlane | |
| * linear density factor stored in FirstDensityFunctionParameters.x, plane stored in SecondDensityFunctionParameters | |
| * Clamps the ray to the range [IntersectionRange.x, IntersectionRange.y] | |
| * | |
| * Computes the line integral from the camera to the current face of the fog volume being rendered | |
| * or an intersecting opaque object. | |
| */ | |
| float LinearHalfspaceLineIntegral(float3 WorldReceiverPos, float3 InCameraPosition, float2 IntersectionRange) | |
| { | |
| //parametrize the ray as R = WorldPos + V * t; | |
| //so ray origin is WorldPos, ray direction is V | |
| float3 V = InCameraPosition - WorldReceiverPos; | |
| float ReceiverToCameraDistance = length(V); | |
| //plane dot WorldReceiverPos is stored in x, plane dot InCameraPosition in y | |
| //these are used to handle the 4 cases: | |
| // FDotReceiver FDotCamera MinIntersection MaxIntersection | |
| //A) Ray does not intersect plane (both CameraPos and WorldPos are above the plane) | |
| // + + 0 0 | |
| //B) Camera above plane, WorldPos below | |
| // - + 0 RayPlaneIntersect | |
| //C) WorldPos above plane, camera below | |
| // + - RayPlaneIntersect 1 | |
| //D) Both below | |
| // - - 0 1 | |
| float3 PlaneDots; | |
| PlaneDots.x = dot(SecondDensityFunctionParameters, float4(WorldReceiverPos, 1)); | |
| PlaneDots.y = dot(SecondDensityFunctionParameters, float4(InCameraPosition, 1)); | |
| PlaneDots.z = dot(SecondDensityFunctionParameters, float4(V, 0)); | |
| //find the intersection between the ray and the plane | |
| //t = - dot(Plane, float4(WorldPos, 1)) / dot(Plane, float4(V, 0)); | |
| float RayPlaneIntersect = -PlaneDots.x / (PlaneDots.z + Epsilon); | |
| //setup masks based on the 4 cases | |
| float2 IntersectionMasks = PlaneDots.xy < 0.0f; | |
| //use those masks to setup the correct MinIntersection and MaxIntersection for each case | |
| float2 Intersections = lerp(RayPlaneIntersect.xx, float2(0,1), IntersectionMasks); | |
| //use the passed in range if it is more restrictive | |
| Intersections.x = max(Intersections.x, IntersectionRange.x); | |
| Intersections.y = min(Intersections.y, IntersectionRange.y); | |
| //clamp the closest intersection to the camera to StartDistance | |
| Intersections.y = min(1.0f - StartDistance / ReceiverToCameraDistance, Intersections.y); | |
| //this can only happen if the passed in Intersections is invalid | |
| //and indicates that the ray doesn't intersect anything | |
| //set the Intersections to be equal so the line integral will be 0 | |
| if (Intersections.y <= Intersections.x) | |
| { | |
| Intersections = float2(0,0); | |
| } | |
| //evaluate the line integral at both intersections | |
| float2 IntegralEvaluations = Intersections * PlaneDots.xx + 0.5f * Intersections * Intersections * PlaneDots.zz; | |
| return -(IntegralEvaluations.y - IntegralEvaluations.x) * ReceiverToCameraDistance * FirstDensityFunctionParameters.x * .0001f; | |
| } | |
| const static float PI_2 = 1.57079632f; | |
| float ArcTan(float value) | |
| { | |
| //close enough | |
| float ValueSign = sign(value); | |
| return ValueSign * (-PI_2 * exp2(-ValueSign * value) + PI_2); | |
| //funky | |
| //return sin(value * 5.0f); | |
| //slow | |
| //return atan2(value, 1.0f); | |
| } | |
| /* | |
| * A sphere shaped density function with G1 continuity at the center and smooth quadratic falloff at the edges. | |
| * Spherical Density = MaximumDensity * (1 - distanceToCenter^2 / SphereRadius^2), where MaximumDensity is the maximum density at the center of the sphere. | |
| * This density function has its zeroes at SphereRadius and -SphereRadius, so the edges of the sphere fade out smoothly. | |
| * MaxDensity stored in FirstDensityFunctionParameters.x, sphere center in SecondDensityFunctionParameters.xyz, sphere radius in SecondDensityFunctionParameters.w | |
| * | |
| * Computes the line integral from the camera to the current face of the fog volume being rendered | |
| * or an intersecting opaque object. | |
| */ | |
| float SphericalLineIntegral(float3 WorldReceiverPos, float3 InCameraPosition) | |
| { | |
| float LineIntegral = 0; | |
| float3 V = InCameraPosition - WorldReceiverPos; | |
| float ReceiverToCameraDistance = length(V); | |
| float SphereRadiusSquared = SecondDensityFunctionParameters.w * SecondDensityFunctionParameters.w; | |
| float3 ReceiverToSphereCenter = WorldReceiverPos - SecondDensityFunctionParameters.xyz; | |
| float ReceiverToSphereCenterSq = dot(ReceiverToSphereCenter, ReceiverToSphereCenter); | |
| //find the intersection between the ray from the receiver to the camera and the sphere | |
| //x, y and z correspond to a, b and c in a * x^2 + b * x + c = 0 | |
| //except c has the -SphereRadiusSquared term left out for reuse in the integral | |
| float3 QuadraticCoef; | |
| QuadraticCoef.x = dot(V, V); | |
| QuadraticCoef.y = 2 * dot(V, ReceiverToSphereCenter); | |
| QuadraticCoef.z = ReceiverToSphereCenterSq; | |
| //b^2 - 4 * a * c | |
| float Determinant = QuadraticCoef.y * QuadraticCoef.y - 4 * QuadraticCoef.x * (QuadraticCoef.z - SphereRadiusSquared); | |
| //only continue if the ray intersects the sphere | |
| //@todo - try to optimize this using dynamic branching | |
| if (Determinant >= 0) | |
| { | |
| float InvTwoA = .5 / (QuadraticCoef.x + Epsilon); | |
| float SqrtDeterminant = sqrt(Determinant); | |
| //clamp intersections to [0, 1]. 0 on the ray is the receiver position, 1 is the camera position. | |
| //closest stored in x, furthest in y | |
| float2 Intersections = saturate(-(float2(SqrtDeterminant, -SqrtDeterminant) + QuadraticCoef.yy) * InvTwoA); | |
| //not enabled for SM2 to keep from breaking existing materials which are close to the ALU limit | |
| #if !SM2_PROFILE | |
| //clamp the closest intersection to the camera to StartDistance | |
| Intersections.y = min(1.0f - StartDistance / ReceiverToCameraDistance, Intersections.y); | |
| Intersections.y = max(Intersections.y, Intersections.x); | |
| #endif | |
| //spherical density = MaximumDensity * (1 - distanceToCenter^2 / SphereRadius^2), where MaximumDensity is the maximum density at the center of the sphere | |
| //distanceToCenter is squared which cancels out the sqrt in the distance calculation and greatly simplifies the line integral | |
| float3 IntegralCoefficients = QuadraticCoef * float3(1.0f / 3.0f, 1.0f / 2.0f, 1.0f); | |
| float2 IntersectionsSquared = Intersections * Intersections; | |
| float2 IntersectionsCubed = IntersectionsSquared * Intersections; | |
| float3 ClosestVector = float3(IntersectionsCubed.x, IntersectionsSquared.x, Intersections.x); | |
| float3 FurthestVector = float3(IntersectionsCubed.y, IntersectionsSquared.y, Intersections.y); | |
| float2 IntegralPolynomials = float2(dot(IntegralCoefficients, ClosestVector), dot(IntegralCoefficients, FurthestVector)); | |
| //evaluation at the closest intersection in x, furthest in y | |
| float2 Evaluations = FirstDensityFunctionParameters.xx * (Intersections - IntegralPolynomials / SphereRadiusSquared.xx); | |
| LineIntegral = (Evaluations.y - Evaluations.x) * ReceiverToCameraDistance; | |
| /* | |
| //spherical density = 1 / r^2 | |
| //looks like the inscattering from a bright lamp on a foggy night | |
| float QuadraticFalloffCoef = .02; | |
| float3 SphereCenterToReceiver = -ReceiverToSphereCenter; | |
| float A2 = QuadraticCoef.x * QuadraticFalloffCoef; | |
| float B2 = -2 * dot(V, SphereCenterToReceiver) * QuadraticFalloffCoef; | |
| float C2 = dot(SphereCenterToReceiver, SphereCenterToReceiver) * QuadraticFalloffCoef; | |
| float IntegralDeterminant = 4 * A2 * C2 - B2 * B2; | |
| float SqrtIntegralDeterminant = sqrt(abs(IntegralDeterminant)); | |
| float InvSqrtIntegralDeterminant = 1 / (SqrtIntegralDeterminant + Epsilon); | |
| float FurthestValue = (2 * A2 * Intersections.y + B2) * InvSqrtIntegralDeterminant; | |
| float ClosestValue = (2 * A2 * Intersections.x + B2) * InvSqrtIntegralDeterminant; | |
| if (IntegralDeterminant > 0) | |
| { | |
| LineIntegral = 2 * InvSqrtIntegralDeterminant * (ArcTan(FurthestValue) - ArcTan(ClosestValue)) * length(V); | |
| } | |
| */ | |
| } | |
| return LineIntegral; | |
| } |
Xet Storage Details
- Size:
- 12.3 kB
- Xet hash:
- a1593e46f71f74180bebe219de437527fcf3f2fc0089a607bec5931e1555cb62
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.