You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

135 lines
5.6 KiB

// #pragma enable_d3d11_debug_symbols
#pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch
#pragma kernel main
#define _PlanetaryRadius _GroundAlbedo_PlanetRadius.w
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightDefinition.cs.hlsl"
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl"
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Sky/PhysicallyBasedSky/PhysicallyBasedSkyEvaluation.hlsl"
#define TABLE_SIZE uint3(PBRSKYCONFIG_IN_SCATTERED_RADIANCE_TABLE_SIZE_X, \
PBRSKYCONFIG_IN_SCATTERED_RADIANCE_TABLE_SIZE_Y, \
PBRSKYCONFIG_IN_SCATTERED_RADIANCE_TABLE_SIZE_Z)
// Emulate a 4D texture with a "deep" 3D texture.
RW_TEXTURE3D(float3, _AirSingleScatteringTable);
RW_TEXTURE3D(float3, _AerosolSingleScatteringTable);
RW_TEXTURE3D(float3, _MultipleScatteringTable);
[numthreads(4, 4, 4)]
void main(uint3 dispatchThreadId : SV_DispatchThreadID)
{
const float A = _AtmosphericRadius;
const float R = _PlanetaryRadius;
const uint zTexSize = PBRSKYCONFIG_IN_SCATTERED_RADIANCE_TABLE_SIZE_Z;
const uint zTexCnt = PBRSKYCONFIG_IN_SCATTERED_RADIANCE_TABLE_SIZE_W;
// We don't care about the extremal points for XY, but need the full range of Z values.
const float3 scale = rcp(float3(TABLE_SIZE.xy, 1));
const float3 bias = float3(0.5 * scale.xy, 0);
// Let the hardware and the driver handle the ordering of the computation.
uint3 tableCoord = dispatchThreadId;
uint texId = tableCoord.z / zTexSize; // [0, zTexCnt - 1]
uint texCoord = tableCoord.z & (zTexSize - 1); // [0, zTexSize - 1]
float3 uvw = tableCoord * scale + bias;
// Convention:
// V points towards the camera.
// The normal vector N points upwards (local Z).
// The view vector V spans the local XZ plane.
// The light vector is represented as {phiL, cosThataL} w.r.t. the XZ plane.
float cosChi = UnmapAerialPerspective(uvw.xy).x; // [-1, 1]
float height = UnmapAerialPerspective(uvw.xy).y; // [0, _AtmosphericDepth]
float phiL = PI * saturate(texCoord * rcp(zTexSize - 1)); // [-Pi, Pi]
float NdotL = UnmapCosineOfZenithAngle(saturate(texId * rcp(zTexCnt - 1))); // [-0.5, 1]
float NdotV = -cosChi;
float r = height + R;
float cosHor = ComputeCosineOfHorizonAngle(r);
bool lookAboveHorizon = (cosChi >= cosHor);
bool viewAboveHorizon = (NdotV >= cosHor);
float3 N = float3(0, 0, 1);
float3 V = SphericalToCartesian(0, NdotV);
float3 L = SphericalToCartesian(phiL, NdotL);
float LdotV = dot(L, V);
// float LdotV = SphericalDot(NdotL, phiL, NdotV, 0);
// Set up the ray...
float h = height;
float3 O = r * N;
// Determine the region of integration.
float tMax;
if (lookAboveHorizon)
{
tMax = IntersectSphere(A, cosChi, r).y; // Max root
}
else
{
tMax = IntersectSphere(R, cosChi, r).x; // Min root
}
// Integrate in-scattered radiance along -V.
// Note that we have to evaluate the transmittance integral along -V as well.
// The transmittance integral is pretty smooth (I plotted it in Mathematica).
// However, using a non-linear distribution of samples is still a good idea both
// when looking up (due to the exponential falloff of the coefficients)
// and for horizontal rays (due to the exponential transmittance term).
// It's easy enough to use a simple quadratic remap.
float3 airTableEntry = 0;
float3 aerosolTableEntry = 0;
float3 msTableEntry = 0;
float3 transmittance = 1.0f;
// Eye-balled number of samples.
const int numSamples = 16;
for (int i = 0; i < numSamples; i++)
{
float t, dt;
GetSample(i, numSamples, tMax, t, dt);
float3 P = O + t * -V;
// Update these for the step along the ray...
r = max(length(P), R);
height = r - R;
NdotV = dot(normalize(P), V);
NdotL = dot(normalize(P), L);
const float3 sigmaE = AtmosphereExtinction(height);
const float3 transmittanceOverSegment = TransmittanceFromOpticalDepth(sigmaE * dt);
// Apply the phase function at runtime.
float3 sunTransmittance = EvaluateSunColorAttenuation(NdotL, r);
float3 airTerm = sunTransmittance * AirScatter(height);
float3 aerosolTerm = sunTransmittance * AerosolScatter(height);
float3 scatteringMS = AirScatter(height) + AerosolScatter(height);
float3 msTerm = EvaluateMultipleScattering(NdotL, height) * scatteringMS;
airTableEntry += IntegrateOverSegment(airTerm, transmittanceOverSegment, transmittance, sigmaE);
aerosolTableEntry += IntegrateOverSegment(aerosolTerm, transmittanceOverSegment, transmittance, sigmaE);
msTableEntry += IntegrateOverSegment(msTerm, transmittanceOverSegment, transmittance, sigmaE);
transmittance *= transmittanceOverSegment;
}
// TODO: deep compositing.
// Note: ground reflection is computed at runtime.
_AirSingleScatteringTable[tableCoord] = airTableEntry; // One order
_AerosolSingleScatteringTable[tableCoord] = aerosolTableEntry; // One order
_MultipleScatteringTable[tableCoord] = msTableEntry * MS_EXPOSURE;
}