301 lines
10 KiB
Plaintext
301 lines
10 KiB
Plaintext
Shader "Hidden/HDRP/Sky/PbrSky"
|
|
{
|
|
HLSLINCLUDE
|
|
|
|
#pragma vertex Vert
|
|
|
|
// #pragma enable_d3d11_debug_symbols
|
|
#pragma editor_sync_compilation
|
|
#pragma target 4.5
|
|
#pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch
|
|
|
|
#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/PhysicallyBasedSkyCommon.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Sky/SkyUtils.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/AtmosphericScattering/AtmosphericScattering.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/CookieSampling.hlsl"
|
|
|
|
int _HasGroundAlbedoTexture; // bool...
|
|
int _HasGroundEmissionTexture; // bool...
|
|
int _HasSpaceEmissionTexture; // bool...
|
|
int _RenderSunDisk; // bool...
|
|
|
|
float _GroundEmissionMultiplier;
|
|
float _SpaceEmissionMultiplier;
|
|
|
|
// Sky framework does not set up global shader variables (even per-view ones),
|
|
// so they can contain garbage. It's very difficult to not include them, however,
|
|
// since the sky framework includes them internally in many header files.
|
|
// Just don't use them. Ever.
|
|
float3 _WorldSpaceCameraPos1;
|
|
float4x4 _ViewMatrix1;
|
|
#undef UNITY_MATRIX_V
|
|
#define UNITY_MATRIX_V _ViewMatrix1
|
|
|
|
// 3x3, but Unity can only set 4x4...
|
|
float4x4 _PlanetRotation;
|
|
float4x4 _SpaceRotation;
|
|
|
|
TEXTURECUBE(_GroundAlbedoTexture);
|
|
TEXTURECUBE(_GroundEmissionTexture);
|
|
TEXTURECUBE(_SpaceEmissionTexture);
|
|
|
|
struct Attributes
|
|
{
|
|
uint vertexID : SV_VertexID;
|
|
UNITY_VERTEX_INPUT_INSTANCE_ID
|
|
};
|
|
|
|
struct Varyings
|
|
{
|
|
float4 positionCS : SV_POSITION;
|
|
UNITY_VERTEX_OUTPUT_STEREO
|
|
};
|
|
|
|
Varyings Vert(Attributes input)
|
|
{
|
|
Varyings output;
|
|
UNITY_SETUP_INSTANCE_ID(input);
|
|
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
|
|
output.positionCS = GetFullScreenTriangleVertexPosition(input.vertexID, UNITY_RAW_FAR_CLIP_VALUE);
|
|
return output;
|
|
}
|
|
|
|
float4 RenderSky(Varyings input)
|
|
{
|
|
const float R = _PlanetaryRadius;
|
|
|
|
// TODO: Not sure it's possible to precompute cam rel pos since variables
|
|
// in the two constant buffers may be set at a different frequency?
|
|
const float3 O = _WorldSpaceCameraPos1 - _PlanetCenterPosition.xyz;
|
|
const float3 V = GetSkyViewDirWS(input.positionCS.xy);
|
|
|
|
bool renderSunDisk = _RenderSunDisk != 0;
|
|
|
|
float3 N; float r; // These params correspond to the entry point
|
|
float tEntry = IntersectAtmosphere(O, V, N, r).x;
|
|
float tExit = IntersectAtmosphere(O, V, N, r).y;
|
|
|
|
float NdotV = dot(N, V);
|
|
float cosChi = -NdotV;
|
|
float cosHor = ComputeCosineOfHorizonAngle(r);
|
|
|
|
bool rayIntersectsAtmosphere = (tEntry >= 0);
|
|
bool lookAboveHorizon = (cosChi >= cosHor);
|
|
|
|
float tFrag = FLT_INF;
|
|
float3 radiance = 0;
|
|
|
|
if (renderSunDisk)
|
|
{
|
|
// Intersect and shade emissive celestial bodies.
|
|
// Unfortunately, they don't write depth.
|
|
for (uint i = 0; i < _DirectionalLightCount; i++)
|
|
{
|
|
DirectionalLightData light = _DirectionalLightDatas[i];
|
|
|
|
// Use scalar or integer cores (more efficient).
|
|
bool interactsWithSky = asint(light.distanceFromCamera) >= 0;
|
|
|
|
// Celestial body must be outside the atmosphere (request from Pierre D).
|
|
float lightDist = max(light.distanceFromCamera, tExit);
|
|
|
|
if (interactsWithSky && asint(light.angularDiameter) != 0 && lightDist < tFrag)
|
|
{
|
|
// We may be able to see the celestial body.
|
|
float3 L = -light.forward.xyz;
|
|
|
|
float LdotV = -dot(L, V);
|
|
float rad = acos(LdotV);
|
|
float radInner = 0.5 * light.angularDiameter;
|
|
float cosInner = cos(radInner);
|
|
float cosOuter = cos(radInner + light.flareSize);
|
|
|
|
float solidAngle = TWO_PI * (1 - cosInner);
|
|
|
|
if (LdotV >= cosOuter)
|
|
{
|
|
// Sun flare is visible. Sun disk may or may not be visible.
|
|
// Assume uniform emission.
|
|
float3 color = light.color.rgb;
|
|
float scale = rcp(solidAngle);
|
|
|
|
if (LdotV >= cosInner) // Sun disk.
|
|
{
|
|
tFrag = lightDist;
|
|
|
|
if (light.surfaceTextureScaleOffset.x > 0)
|
|
{
|
|
// The cookie code de-normalizes the axes.
|
|
float2 proj = float2(dot(-V, normalize(light.right)), dot(-V, normalize(light.up)));
|
|
float2 angles = HALF_PI - acos(proj);
|
|
float2 uv = angles * rcp(radInner) * 0.5 + 0.5;
|
|
|
|
color *= SampleCookie2D(uv, light.surfaceTextureScaleOffset);
|
|
// color *= SAMPLE_TEXTURE2D_ARRAY(_CookieTextures, s_linear_clamp_sampler, uv, light.surfaceTextureIndex).rgb;
|
|
}
|
|
|
|
color *= light.surfaceTint;
|
|
}
|
|
else // Flare region.
|
|
{
|
|
float r = max(0, rad - radInner);
|
|
float w = saturate(1 - r * rcp(light.flareSize));
|
|
|
|
color *= light.flareTint;
|
|
scale *= SafePositivePow(w, light.flareFalloff);
|
|
}
|
|
|
|
radiance += color * scale;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (rayIntersectsAtmosphere && !lookAboveHorizon) // See the ground?
|
|
{
|
|
float tGround = tEntry + IntersectSphere(R, cosChi, r).x;
|
|
|
|
if (tGround < tFrag)
|
|
{
|
|
// Closest so far.
|
|
// Make it negative to communicate to EvaluatePbrAtmosphere that we intersected the ground.
|
|
tFrag = -tGround;
|
|
|
|
radiance = 0;
|
|
|
|
float3 gP = O + tGround * -V;
|
|
float3 gN = normalize(gP);
|
|
|
|
if (_HasGroundEmissionTexture)
|
|
{
|
|
float4 ts = SAMPLE_TEXTURECUBE(_GroundEmissionTexture, s_trilinear_clamp_sampler, mul(gN, (float3x3)_PlanetRotation));
|
|
radiance += _GroundEmissionMultiplier * ts.rgb;
|
|
}
|
|
|
|
float3 albedo = _GroundAlbedo.xyz;
|
|
|
|
if (_HasGroundAlbedoTexture)
|
|
{
|
|
albedo *= SAMPLE_TEXTURECUBE(_GroundAlbedoTexture, s_trilinear_clamp_sampler, mul(gN, (float3x3)_PlanetRotation)).rgb;
|
|
}
|
|
|
|
float3 gBrdf = INV_PI * albedo;
|
|
|
|
// Shade the ground.
|
|
for (uint i = 0; i < _DirectionalLightCount; i++)
|
|
{
|
|
DirectionalLightData light = _DirectionalLightDatas[i];
|
|
|
|
// Use scalar or integer cores (more efficient).
|
|
bool interactsWithSky = asint(light.distanceFromCamera) >= 0;
|
|
|
|
float3 L = -light.forward.xyz;
|
|
float3 intensity = light.color.rgb;
|
|
float3 irradiance = SampleGroundIrradianceTexture(dot(gN, L));
|
|
|
|
radiance += gBrdf * (irradiance * intensity); // Scale from unit intensity to light's intensity
|
|
}
|
|
}
|
|
}
|
|
else if (tFrag == FLT_INF) // See the stars?
|
|
{
|
|
if (_HasSpaceEmissionTexture)
|
|
{
|
|
// V points towards the camera.
|
|
float4 ts = SAMPLE_TEXTURECUBE(_SpaceEmissionTexture, s_trilinear_clamp_sampler, mul(-V, (float3x3)_SpaceRotation));
|
|
radiance += _SpaceEmissionMultiplier * ts.rgb;
|
|
}
|
|
}
|
|
|
|
float3 skyColor = 0, skyOpacity = 0;
|
|
|
|
if (rayIntersectsAtmosphere)
|
|
{
|
|
float distAlongRay = tFrag;
|
|
EvaluatePbrAtmosphere(_WorldSpaceCameraPos1, V, distAlongRay, renderSunDisk, skyColor, skyOpacity);
|
|
}
|
|
|
|
skyColor += radiance * (1 - skyOpacity);
|
|
skyColor *= _IntensityMultiplier;
|
|
|
|
return float4(skyColor, 1.0);
|
|
}
|
|
|
|
float4 FragBaking(Varyings input) : SV_Target
|
|
{
|
|
return RenderSky(input); // The cube map is not pre-exposed
|
|
}
|
|
|
|
float4 FragRender(Varyings input) : SV_Target
|
|
{
|
|
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
|
|
float4 value = RenderSky(input);
|
|
value.rgb *= GetCurrentExposureMultiplier(); // Only the full-screen pass is pre-exposed
|
|
return value;
|
|
}
|
|
|
|
float4 FragBlack(Varyings input) : SV_Target
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
ENDHLSL
|
|
|
|
SubShader
|
|
{
|
|
Pass
|
|
{
|
|
ZWrite Off
|
|
ZTest Always
|
|
Blend Off
|
|
Cull Off
|
|
|
|
HLSLPROGRAM
|
|
#pragma fragment FragBaking
|
|
ENDHLSL
|
|
}
|
|
|
|
Pass
|
|
{
|
|
ZWrite Off
|
|
ZTest Always
|
|
Blend Off
|
|
Cull Off
|
|
|
|
HLSLPROGRAM
|
|
#pragma fragment FragBlack
|
|
ENDHLSL
|
|
}
|
|
|
|
Pass
|
|
{
|
|
ZWrite Off
|
|
ZTest LEqual
|
|
Blend Off
|
|
Cull Off
|
|
|
|
HLSLPROGRAM
|
|
#pragma fragment FragRender
|
|
ENDHLSL
|
|
}
|
|
|
|
Pass
|
|
{
|
|
ZWrite Off
|
|
ZTest LEqual
|
|
Blend Off
|
|
Cull Off
|
|
|
|
HLSLPROGRAM
|
|
#pragma fragment FragBlack
|
|
ENDHLSL
|
|
}
|
|
|
|
}
|
|
Fallback Off
|
|
}
|