176 lines
5.9 KiB
HLSL
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
|