Rasagar/Library/PackageCache/com.unity.render-pipelines.high-definition/Runtime/Sky/PhysicallyBasedSky/PhysicallyBasedSkyEvaluation.hlsl
2024-08-26 23:07:20 +03:00

176 lines
5.9 KiB
HLSL

#ifndef UNITY_PHYSICALLY_BASED_SKY_EVALUATION_INCLUDED
#define UNITY_PHYSICALLY_BASED_SKY_EVALUATION_INCLUDED
#ifdef OUTPUT_MULTISCATTERING
#define _PlanetaryRadius _GroundAlbedo_PlanetRadius.w
#endif
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Sky/PhysicallyBasedSky/PhysicallyBasedSkyCommon.hlsl"
TEXTURE2D(_SkyViewLUT);
SAMPLER(sampler_SkyViewLUT);
TEXTURE2D(_MultiScatteringLUT);
TEXTURE3D(_AtmosphericScatteringLUT);
// Integration utilities
float3 IntegrateOverSegment(float3 S, float3 transmittanceOverSegment, float3 transmittance, float3 sigmaE)
{
// https://www.shadertoy.com/view/XlBSRz
// See slide 28 at http://www.frostbite.com/2015/08/physically-based-unified-volumetric-rendering-in-frostbite
// Assumes homogeneous medium along the interval
float3 Sint = (S - S * transmittanceOverSegment) / sigmaE; // integrate along the current step segment
return transmittance * Sint; // accumulate and also take into account the transmittance from previous steps
}
void GetSample(uint s, uint sampleCount, float tExit, out float t, out float dt)
{
//dt = tMax / sampleCount;
//t += dt;
float t0 = (s) / (float)sampleCount;
float t1 = (s + 1.0f) / (float)sampleCount;
// Non linear distribution of sample within the range.
t0 = t0 * t0 * tExit;
t1 = t1 * t1 * tExit;
t = lerp(t0, t1, 0.5f); // 0.5 gives the closest result to reference
dt = t1 - t0;
}
// LUT uv convertion utilities
float2 MapSkyView(float cosChi, float3 V)
{
float2 uv;
float coord = FastACos(cosChi) / HALF_PI;
uv.y = sqrt(1.0 - coord); // quadratic transformation to preserve details at horizon
// Convert view vector to spherical coordinates
float phi = FastACos(normalize(V.xz).x);
if (V.z < 0.0f) phi = TWO_PI - phi;
uv.x = phi / TWO_PI;
return uv;
}
void UnmapSkyView(uint2 coord, out float3 V)
{
const float2 res = float2(PBRSKYCONFIG_SKY_VIEW_LUT_WIDTH, PBRSKYCONFIG_SKY_VIEW_LUT_HEIGHT);
const float2 uv = coord / float2(res.x, res.y - 1);
float remapped = 1.0 - uv.y * uv.y; // quadratic transformation to preserve details at horizon
float cosChi = saturate(cos(remapped * HALF_PI));
float sinChi = SinFromCos(cosChi);
V = float3(sinChi, cosChi, sinChi);
float phi = TWO_PI * uv.x;
V.xz *= float2(cos(phi), sin(phi));
}
float2 MapMultipleScattering(float cosChi, float height)
{
return saturate(float2(cosChi*0.5f + 0.5f, height / _AtmosphericDepth));
}
void UnmapMultipleScattering(uint2 coord, out float cosChi, out float height)
{
const float2 res = float2(PBRSKYCONFIG_MULTI_SCATTERING_LUT_WIDTH, PBRSKYCONFIG_MULTI_SCATTERING_LUT_HEIGHT);
const float2 uv = coord / (res - 1);
cosChi = uv.x * 2.0 - 1.0;
height = lerp(_PlanetaryRadius, _AtmosphericRadius, uv.y);
}
// Might need better heuristic for non-earth planets
// Should roughly represent the longest line of sight you can have trough the atmosphere
// Higher values increse coverage of each slice which decreases quality
#define ATMOSPHERIC_SCATTERING_MAX_DISTANCE 128000.0f
float3 MapAtmosphericScattering(float2 positionNDC, float t, float cosChi)
{
const float offset = rcp(2 * PBRSKYCONFIG_ATMOSPHERIC_SCATTERING_LUT_DEPTH);
float r = _PlanetaryRadius + _CameraAltitude;
// Move to atmosphere entry point
t -= max(IntersectSphere(_AtmosphericRadius, cosChi, r).x, 0);
t /= ATMOSPHERIC_SCATTERING_MAX_DISTANCE;
float s = sqrt(max(t - offset * offset, 0.0f)) - offset; // inverse of GetSample()
return float3(positionNDC, s);
}
void UnmapAtmosphericScattering(uint s, inout float3 V, out float3 O, out float t, out float dt)
{
O = GetCameraPositionWS() - _PlanetCenterPosition;
#ifdef CAMERA_SPACE
V.y = max(V.y, 0.0f); // we can't see below the horizon
#else
// Make sure camera is not below the ground (offset by 1 for precision)
if (_CameraAltitude < 1.0f)
O -= (_CameraAltitude - 1.0f) * _PlanetUp;
else
{
// Move to atmosphere entry point
float r = _PlanetaryRadius + _CameraAltitude;
O += max(IntersectSphere(_AtmosphericRadius, dot(_PlanetUp, V), r).x, 0) * V;
}
#endif
GetSample(s, PBRSKYCONFIG_ATMOSPHERIC_SCATTERING_LUT_DEPTH, ATMOSPHERIC_SCATTERING_MAX_DISTANCE, t, dt);
}
// Evaluate using LUTs
void EvaluateDistantAtmosphere(float3 V, inout float3 skyColor, inout float3 skyOpacity)
{
float cosHor = 0.0f;
float cosChi = V.y;
float3 optDepth = ComputeAtmosphericOpticalDepth(_PlanetaryRadius, cosChi, true);
skyOpacity = 1 - TransmittanceFromOpticalDepth(optDepth);
float2 uv = MapSkyView(cosChi, V);
skyColor += SAMPLE_TEXTURE2D_LOD(_SkyViewLUT, sampler_SkyViewLUT, uv, 0).xyz * _CelestialLightExposure;
AtmosphereArtisticOverride(cosHor, cosChi, skyColor, skyOpacity);
}
float3 EvaluateMultipleScattering(float cosChi, float height)
{
float2 uv = MapMultipleScattering(cosChi, height);
return SAMPLE_TEXTURE2D_LOD(_MultiScatteringLUT, s_linear_clamp_sampler, uv, 0).rgb;
}
void EvaluateCameraAtmosphericScattering(float3 V, float2 positionNDC, float tFrag, out float3 skyColor, out float3 skyOpacity)
{
skyColor = skyOpacity = 0.0f;
float3 O = GetCameraPositionWS() - _PlanetCenterPosition;
float3 N = _PlanetUp;
float r = _PlanetaryRadius + _CameraAltitude;
float cosChi = dot(N, V);
float cosHor = ComputeCosineOfHorizonAngle(r);
float3 uvw = MapAtmosphericScattering(positionNDC, tFrag, cosChi);
skyColor = SAMPLE_TEXTURE3D_LOD(_AtmosphericScatteringLUT, s_linear_clamp_sampler, uvw, 0).rgb;
float entryPoint = max(IntersectSphere(_AtmosphericRadius, cosChi, tFrag).x, 0);
tFrag = min(tFrag, entryPoint + ATMOSPHERIC_SCATTERING_MAX_DISTANCE);
float3 optDepth = ComputeAtmosphericOpticalDepth(O, -V, tFrag);
skyOpacity = 1 - TransmittanceFromOpticalDepth(optDepth);
AtmosphereArtisticOverride(cosHor, cosChi, skyColor, skyOpacity, true);
}
#endif // UNITY_PHYSICALLY_BASED_SKY_EVALUATION_INCLUDED