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

716 lines
34 KiB
C#

using System;
using System.Collections.Generic;
using UnityEngine.Experimental.Rendering;
using ShadingSource = UnityEngine.Rendering.HighDefinition.HDAdditionalLightData.CelestialBodyShadingSource;
namespace UnityEngine.Rendering.HighDefinition
{
class PhysicallyBasedSkyRenderer : SkyRenderer
{
static bool SupportSpace => ShaderConfig.s_PrecomputedAtmosphericAttenuation == 0;
class PrecomputationCache
{
class RefCountedData
{
public int refCount;
public PrecomputationData data = new PrecomputationData();
}
ObjectPool<RefCountedData> m_DataPool = new ObjectPool<RefCountedData>(null, null);
Dictionary<int, RefCountedData> m_CachedData = new Dictionary<int, RefCountedData>();
public bool HasAliveData() => m_CachedData.Count != 0;
public PrecomputationData Get(BuiltinSkyParameters builtinParams, int hash)
{
RefCountedData result;
if (m_CachedData.TryGetValue(hash, out result))
{
result.refCount++;
return result.data;
}
else
{
result = m_DataPool.Get();
result.refCount = 1;
result.data.Allocate(builtinParams);
m_CachedData.Add(hash, result);
return result.data;
}
}
public void Release(int hash)
{
if (m_CachedData.TryGetValue(hash, out var result))
{
result.refCount--;
if (result.refCount == 0)
{
result.data.Release();
m_CachedData.Remove(hash);
m_DataPool.Release(result);
}
}
}
}
class PrecomputationData
{
// Local sky
RTHandle m_GroundIrradianceTable;
RTHandle[] m_InScatteredRadianceTables; // Air SS, Aerosol SS, Atmosphere MS
// Distant sky
RTHandle m_MultiScatteringLut, m_SkyViewLut;
int m_LastLightsHash;
RTHandle m_AtmosphericScatteringLut;
bool IsWorldSpace() => m_InScatteredRadianceTables != null;
RTHandle AllocateGroundIrradianceTable()
{
var table = RTHandles.Alloc((int)PbrSkyConfig.GroundIrradianceTableSize, 1,
colorFormat: s_ColorFormat,
enableRandomWrite: true,
name: "GroundIrradianceTable");
Debug.Assert(table != null);
return table;
}
RTHandle AllocateInScatteredRadianceTable(int index)
{
// Emulate a 4D texture with a "deep" 3D texture.
var table = RTHandles.Alloc((int)PbrSkyConfig.InScatteredRadianceTableSizeX,
(int)PbrSkyConfig.InScatteredRadianceTableSizeY,
(int)PbrSkyConfig.InScatteredRadianceTableSizeZ *
(int)PbrSkyConfig.InScatteredRadianceTableSizeW,
dimension: TextureDimension.Tex3D,
colorFormat: s_ColorFormat,
enableRandomWrite: true,
name: string.Format("InScatteredRadianceTable{0}", index));
Debug.Assert(table != null);
return table;
}
public void Allocate(BuiltinSkyParameters builtinParams)
{
var cmd = builtinParams.commandBuffer;
var pbrSky = builtinParams.skySettings as PhysicallyBasedSky;
m_MultiScatteringLut = RTHandles.Alloc(
(int)PbrSkyConfig.MultiScatteringLutWidth,
(int)PbrSkyConfig.MultiScatteringLutHeight,
colorFormat: s_ColorFormat,
wrapMode: TextureWrapMode.Clamp,
enableRandomWrite: true,
name: "MultiScatteringLUT");
RenderMultiScatteringLut(cmd);
if (!SupportSpace && builtinParams.hdCamera.planet.renderingSpace == RenderingSpace.Camera)
{
m_LastLightsHash = -1;
m_SkyViewLut = RTHandles.Alloc(
(int)PbrSkyConfig.SkyViewLutWidth,
(int)PbrSkyConfig.SkyViewLutHeight,
colorFormat: s_ColorFormat,
filterMode: FilterMode.Bilinear,
wrapModeU: TextureWrapMode.Repeat,
wrapModeV: TextureWrapMode.Clamp,
enableRandomWrite: true,
name: "SkyViewLUT");
}
else
{
m_GroundIrradianceTable = AllocateGroundIrradianceTable();
m_InScatteredRadianceTables = new RTHandle[3];
m_InScatteredRadianceTables[0] = AllocateInScatteredRadianceTable(0);
m_InScatteredRadianceTables[1] = AllocateInScatteredRadianceTable(1);
m_InScatteredRadianceTables[2] = AllocateInScatteredRadianceTable(2);
PrecomputeTables(cmd);
}
if (!SupportSpace && pbrSky.atmosphericScattering.value)
{
m_AtmosphericScatteringLut = RTHandles.Alloc(
(int)PbrSkyConfig.AtmosphericScatteringLutWidth,
(int)PbrSkyConfig.AtmosphericScatteringLutHeight,
(int)PbrSkyConfig.AtmosphericScatteringLutDepth,
dimension: TextureDimension.Tex3D,
colorFormat: s_ColorFormat,
enableRandomWrite: true,
name: "AtmosphericScatteringLUT");
}
}
public void Release()
{
if (m_MultiScatteringLut != null)
{
RTHandles.Release(m_MultiScatteringLut); m_MultiScatteringLut = null;
}
if (IsWorldSpace())
{
RTHandles.Release(m_GroundIrradianceTable); m_GroundIrradianceTable = null;
RTHandles.Release(m_InScatteredRadianceTables[0]); m_InScatteredRadianceTables[0] = null;
RTHandles.Release(m_InScatteredRadianceTables[1]); m_InScatteredRadianceTables[1] = null;
RTHandles.Release(m_InScatteredRadianceTables[2]); m_InScatteredRadianceTables[2] = null;
m_InScatteredRadianceTables = null;
}
else
{
RTHandles.Release(m_SkyViewLut); m_SkyViewLut = null;
}
if (m_AtmosphericScatteringLut != null)
{
RTHandles.Release(m_AtmosphericScatteringLut); m_AtmosphericScatteringLut = null;
}
}
void RenderMultiScatteringLut(CommandBuffer cmd)
{
cmd.SetComputeTextureParam(s_SkyLUTGenerator, s_MultiScatteringKernel, HDShaderIDs._MultiScatteringLUT_RW, m_MultiScatteringLut);
cmd.DispatchCompute(s_SkyLUTGenerator, s_MultiScatteringKernel,
(int)PbrSkyConfig.MultiScatteringLutWidth,
(int)PbrSkyConfig.MultiScatteringLutHeight,
1);
}
void PrecomputeTables(CommandBuffer cmd)
{
using (new ProfilingScope(cmd, ProfilingSampler.Get(HDProfileId.InScatteredRadiancePrecomputation)))
{
// Multiple scattering LUT
cmd.SetComputeTextureParam(s_InScatteredRadiancePrecomputationCS, 0, HDShaderIDs._AirSingleScatteringTable, m_InScatteredRadianceTables[0]);
cmd.SetComputeTextureParam(s_InScatteredRadiancePrecomputationCS, 0, HDShaderIDs._AerosolSingleScatteringTable, m_InScatteredRadianceTables[1]);
cmd.SetComputeTextureParam(s_InScatteredRadiancePrecomputationCS, 0, HDShaderIDs._MultipleScatteringTable, m_InScatteredRadianceTables[2]);
cmd.SetComputeTextureParam(s_InScatteredRadiancePrecomputationCS, 0, HDShaderIDs._MultiScatteringLUT, m_MultiScatteringLut);
// Emulate a 4D dispatch with a "deep" 3D dispatch.
cmd.DispatchCompute(s_InScatteredRadiancePrecomputationCS, 0, (int)PbrSkyConfig.InScatteredRadianceTableSizeX / 4,
(int)PbrSkyConfig.InScatteredRadianceTableSizeY / 4,
(int)PbrSkyConfig.InScatteredRadianceTableSizeZ / 4 *
(int)PbrSkyConfig.InScatteredRadianceTableSizeW);
// Ground irradiance LUT
cmd.SetComputeTextureParam(s_GroundIrradiancePrecomputationCS, 0, HDShaderIDs._AirSingleScatteringTexture, m_InScatteredRadianceTables[0]);
cmd.SetComputeTextureParam(s_GroundIrradiancePrecomputationCS, 0, HDShaderIDs._AerosolSingleScatteringTexture, m_InScatteredRadianceTables[1]);
cmd.SetComputeTextureParam(s_GroundIrradiancePrecomputationCS, 0, HDShaderIDs._MultipleScatteringTexture, m_InScatteredRadianceTables[2]);
cmd.SetComputeTextureParam(s_GroundIrradiancePrecomputationCS, 0, HDShaderIDs._GroundIrradianceTable, m_GroundIrradianceTable);
cmd.DispatchCompute(s_GroundIrradiancePrecomputationCS, 0, (int)PbrSkyConfig.GroundIrradianceTableSize / 64, 1, 1);
}
}
static internal float CastFloat(float value, int size)
{
return (int)(value * size) / (float)size;
}
// Computes hash code of light parameters used during sky view lut precomputation
static int GetLightsHash()
{
int hash = 13;
for (int i = 0; i < s_CelestialLightCount; i++)
{
ref var data = ref s_CelestialBodyData[i];
hash = hash * 23 + data.forward.GetHashCode();
hash = hash * 23 + data.color.GetHashCode();
}
return hash;
}
internal void RenderSkyViewLut(CommandBuffer cmd)
{
int currLightsHash = GetLightsHash();
if (currLightsHash == m_LastLightsHash) return;
m_LastLightsHash = currLightsHash;
cmd.SetComputeTextureParam(s_SkyLUTGenerator, s_SkyViewKernel, HDShaderIDs._MultiScatteringLUT, m_MultiScatteringLut);
cmd.SetComputeTextureParam(s_SkyLUTGenerator, s_SkyViewKernel, HDShaderIDs._SkyViewLUT_RW, m_SkyViewLut);
cmd.SetComputeBufferParam(s_SkyLUTGenerator, s_SkyViewKernel, HDShaderIDs._CelestialBodyDatas, s_CelestialBodyBuffer);
cmd.DispatchCompute(s_SkyLUTGenerator, s_SkyViewKernel,
(int)PbrSkyConfig.SkyViewLutWidth / 8,
(int)PbrSkyConfig.SkyViewLutHeight / 8,
1);
}
internal void RenderAtmosphericScatteringLut(BuiltinSkyParameters builtinParams)
{
var cmd = builtinParams.commandBuffer;
cmd.SetComputeMatrixParam(s_SkyLUTGenerator, HDShaderIDs._PixelCoordToViewDirWS, builtinParams.pixelCoordToViewDirMatrix);
int kernel = IsWorldSpace() ? s_AtmosphericScatteringKernelWorld : s_AtmosphericScatteringKernelCamera;
cmd.SetComputeTextureParam(s_SkyLUTGenerator, kernel, HDShaderIDs._MultiScatteringLUT, m_MultiScatteringLut);
cmd.SetComputeTextureParam(s_SkyLUTGenerator, kernel, HDShaderIDs._AtmosphericScatteringLUT_RW, m_AtmosphericScatteringLut);
cmd.SetComputeBufferParam(s_SkyLUTGenerator, kernel, HDShaderIDs._CelestialBodyDatas, s_CelestialBodyBuffer);
cmd.DispatchCompute(s_SkyLUTGenerator, kernel,
(int)PbrSkyConfig.AtmosphericScatteringLutWidth,
(int)PbrSkyConfig.AtmosphericScatteringLutHeight,
1);
// Perform a blur pass on the buffer to reduce resolution artefacts
cmd.SetComputeTextureParam(s_SkyLUTGenerator, s_AtmosphericScatteringBlurKernel, HDShaderIDs._AtmosphericScatteringLUT_RW, m_AtmosphericScatteringLut);
cmd.DispatchCompute(s_SkyLUTGenerator, s_AtmosphericScatteringBlurKernel,
1,
1,
(int)PbrSkyConfig.AtmosphericScatteringLutDepth);
}
public void BindGlobalBuffers(CommandBuffer cmd)
{
cmd.SetGlobalBuffer(HDShaderIDs._CelestialBodyDatas, s_CelestialBodyBuffer);
if (SupportSpace)
{
cmd.SetGlobalTexture(HDShaderIDs._AirSingleScatteringTexture, m_InScatteredRadianceTables[0]);
cmd.SetGlobalTexture(HDShaderIDs._AerosolSingleScatteringTexture, m_InScatteredRadianceTables[1]);
cmd.SetGlobalTexture(HDShaderIDs._MultipleScatteringTexture, m_InScatteredRadianceTables[2]);
}
else
{
cmd.SetGlobalTexture(HDShaderIDs._AtmosphericScatteringLUT, m_AtmosphericScatteringLut ?? (RenderTargetIdentifier)CoreUtils.blackVolumeTexture);
}
}
public void BindBuffers(MaterialPropertyBlock mpb)
{
if (IsWorldSpace())
{
mpb.SetTexture(HDShaderIDs._GroundIrradianceTexture, m_GroundIrradianceTable);
mpb.SetTexture(HDShaderIDs._AirSingleScatteringTexture, m_InScatteredRadianceTables[0]);
mpb.SetTexture(HDShaderIDs._AerosolSingleScatteringTexture, m_InScatteredRadianceTables[1]);
mpb.SetTexture(HDShaderIDs._MultipleScatteringTexture, m_InScatteredRadianceTables[2]);
}
else
{
mpb.SetTexture(HDShaderIDs._SkyViewLUT, m_SkyViewLut);
}
}
}
// Store the hash of the parameters each time precomputation is done.
// If the hash does not match, we must recompute our data.
int m_LastPrecomputationParamHash;
// Precomputed data below.
PrecomputationData m_PrecomputedData;
Material m_PbrSkyMaterial;
static MaterialPropertyBlock s_PbrSkyMaterialProperties;
static PrecomputationCache s_PrecomputationCache = new PrecomputationCache();
const int k_MaxCelestialBodies = 16;
static GraphicsBuffer s_CelestialBodyBuffer;
static CelestialBodyData[] s_CelestialBodyData;
static int s_DataFrameUpdate = -1;
static uint s_CelestialLightCount;
static uint s_CelestialBodyCount;
static float s_CelestialLightExposure;
ShaderVariablesPhysicallyBasedSky m_ConstantBuffer;
int m_ShaderVariablesPhysicallyBasedSkyID = Shader.PropertyToID("ShaderVariablesPhysicallyBasedSky");
static GraphicsFormat s_ColorFormat = GraphicsFormat.B10G11R11_UFloatPack32;
// Common resourcse
static ComputeShader s_SkyLUTGenerator;
static int s_MultiScatteringKernel, s_AtmosphericScatteringBlurKernel;
// Resources for world space sky
static ComputeShader s_GroundIrradiancePrecomputationCS;
static ComputeShader s_InScatteredRadiancePrecomputationCS;
static int s_AtmosphericScatteringKernelWorld;
// Resources for camera space sky
static int s_SkyViewKernel, s_AtmosphericScatteringKernelCamera;
public override void Build()
{
var shaders = GraphicsSettings.GetRenderPipelineSettings<HDRenderPipelineRuntimeShaders>();
var hdPipeline = RenderPipelineManager.currentPipeline as HDRenderPipeline;
if (hdPipeline != null)
s_ColorFormat = hdPipeline.GetColorBufferFormat();
// Common
s_SkyLUTGenerator = shaders.skyLUTGenerator;
s_MultiScatteringKernel = s_SkyLUTGenerator.FindKernel("MultiScatteringLUT");
s_AtmosphericScatteringBlurKernel = s_SkyLUTGenerator.FindKernel("AtmosphericScatteringBlur");
// Camera space sky
s_SkyViewKernel = s_SkyLUTGenerator.FindKernel("SkyViewLUT");
s_AtmosphericScatteringKernelCamera = s_SkyLUTGenerator.FindKernel("AtmosphericScatteringLUTCamera");
// World space sky
s_GroundIrradiancePrecomputationCS = shaders.groundIrradiancePrecomputationCS;
s_InScatteredRadiancePrecomputationCS = shaders.inScatteredRadiancePrecomputationCS;
s_AtmosphericScatteringKernelWorld = s_SkyLUTGenerator.FindKernel("AtmosphericScatteringLUTWorld");
// Main Shader
m_PbrSkyMaterial = CoreUtils.CreateEngineMaterial(shaders.physicallyBasedSkyPS);
s_PbrSkyMaterialProperties = new MaterialPropertyBlock();
}
public override void SetGlobalSkyData(CommandBuffer cmd, BuiltinSkyParameters builtinParams)
{
UpdateGlobalConstantBuffer(cmd, builtinParams);
if (m_PrecomputedData != null)
m_PrecomputedData.BindGlobalBuffers(builtinParams.commandBuffer);
}
public static void SetDefaultGlobalSkyData(CommandBuffer cmd)
{
cmd.SetGlobalTexture(HDShaderIDs._AtmosphericScatteringLUT, CoreUtils.blackVolumeTexture);
}
public override void Cleanup()
{
if (m_PrecomputedData != null)
{
s_PrecomputationCache.Release(m_LastPrecomputationParamHash);
m_LastPrecomputationParamHash = 0;
m_PrecomputedData = null;
}
CoreUtils.Destroy(m_PbrSkyMaterial);
if (!s_PrecomputationCache.HasAliveData() && s_CelestialBodyBuffer != null)
{
s_CelestialBodyBuffer.Dispose();
s_CelestialBodyBuffer = null;
}
}
static float CornetteShanksPhasePartConstant(float anisotropy)
{
float g = anisotropy;
return (3.0f / (8.0f * Mathf.PI)) * (1.0f - g * g) / (2.0f + g * g);
}
static Vector2 ComputeExponentialInterpolationParams(float k)
{
if (k == 0) k = 1e-6f; // Avoid the numerical explosion around 0
// Remap t: (exp(10 k t) - 1) / (exp(10 k) - 1) = exp(x t) y - y.
float x = 10 * k;
float y = 1 / (Mathf.Exp(x) - 1);
return new Vector2(x, y);
}
void UpdateCelestialBodyBuffer(CommandBuffer cmd, BuiltinSkyParameters builtinParams)
{
if (s_CelestialBodyBuffer == null)
{
int stride = System.Runtime.InteropServices.Marshal.SizeOf(typeof(CelestialBodyData));
s_CelestialBodyBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Structured, k_MaxCelestialBodies, stride);
s_CelestialBodyData = new CelestialBodyData[k_MaxCelestialBodies];
}
if (builtinParams.frameIndex != s_DataFrameUpdate)
{
s_DataFrameUpdate = builtinParams.frameIndex;
var directionalLights = HDLightRenderDatabase.instance.directionalLights;
float exposure = 1.0f;
uint lightCount = 0;
foreach (var light in directionalLights)
{
if (light.legacyLight.enabled && light.interactsWithSky && light.legacyLight.intensity != 0.0f)
{
FillCelestialBodyData(cmd, light, ref s_CelestialBodyData[lightCount++]);
exposure = Mathf.Max(light.legacyLight.intensity * -light.transform.forward.y, exposure);
if (lightCount >= k_MaxCelestialBodies) break;
}
}
uint bodyCount = lightCount;
foreach (var light in directionalLights)
{
if (bodyCount >= k_MaxCelestialBodies) break;
if (light.legacyLight.enabled && light.interactsWithSky && light.legacyLight.intensity == 0.0f)
FillCelestialBodyData(cmd, light, ref s_CelestialBodyData[bodyCount++]);
}
s_CelestialLightCount = lightCount;
s_CelestialBodyCount = bodyCount;
s_CelestialLightExposure = exposure;
s_CelestialBodyBuffer.SetData(s_CelestialBodyData);
}
}
// For both precomputation and runtime lighting passes.
void UpdateGlobalConstantBuffer(CommandBuffer cmd, BuiltinSkyParameters builtinParams)
{
var pbrSky = builtinParams.skySettings as PhysicallyBasedSky;
UpdateCelestialBodyBuffer(cmd, builtinParams);
float R = builtinParams.hdCamera.planet.radius;
float D = pbrSky.GetMaximumAltitude();
float airH = pbrSky.GetAirScaleHeight();
float aerH = pbrSky.GetAerosolScaleHeight();
float aerA = pbrSky.aerosolAnisotropy.value;
float ozoS = pbrSky.GetOzoneLayerMinimumAltitude();
float ozoW = pbrSky.GetOzoneLayerWidth();
float iMul = GetSkyIntensity(pbrSky, builtinParams.debugSettings);
Vector2 expParams = ComputeExponentialInterpolationParams(pbrSky.horizonZenithShift.value);
m_ConstantBuffer._AtmosphericDepth = D;
m_ConstantBuffer._RcpAtmosphericDepth = 1.0f / D;
m_ConstantBuffer._AtmosphericRadius = R + D;
m_ConstantBuffer._AerosolAnisotropy = aerA;
m_ConstantBuffer._AerosolPhasePartConstant = CornetteShanksPhasePartConstant(aerA);
m_ConstantBuffer._AirDensityFalloff = 1.0f / airH;
m_ConstantBuffer._AirScaleHeight = airH;
m_ConstantBuffer._AerosolDensityFalloff = 1.0f / aerH;
m_ConstantBuffer._AerosolScaleHeight = aerH;
m_ConstantBuffer._AirSeaLevelExtinction = pbrSky.GetAirExtinctionCoefficient();
m_ConstantBuffer._AerosolSeaLevelExtinction = pbrSky.GetAerosolExtinctionCoefficient();
m_ConstantBuffer._AirSeaLevelScattering = pbrSky.GetAirScatteringCoefficient();
m_ConstantBuffer._IntensityMultiplier = iMul;
m_ConstantBuffer._AerosolSeaLevelScattering = pbrSky.GetAerosolScatteringCoefficient();
m_ConstantBuffer._ColorSaturation = pbrSky.colorSaturation.value;
m_ConstantBuffer._OzoneSeaLevelExtinction = pbrSky.GetOzoneExtinctionCoefficient();
m_ConstantBuffer._OzoneScaleOffset = new Vector2(2.0f / ozoW, -2.0f * ozoS / ozoW - 1.0f);
m_ConstantBuffer._OzoneLayerStart = R + ozoS;
m_ConstantBuffer._OzoneLayerEnd = R + ozoS + ozoW;
m_ConstantBuffer._GroundAlbedo_PlanetRadius = pbrSky.groundTint.value;
m_ConstantBuffer._GroundAlbedo_PlanetRadius.w = R;
m_ConstantBuffer._AlphaSaturation = pbrSky.alphaSaturation.value;
m_ConstantBuffer._AlphaMultiplier = pbrSky.alphaMultiplier.value;
Vector3 horizonTint = new Vector3(pbrSky.horizonTint.value.r, pbrSky.horizonTint.value.g, pbrSky.horizonTint.value.b);
m_ConstantBuffer._HorizonTint = horizonTint;
m_ConstantBuffer._HorizonZenithShiftPower = expParams.x;
Vector3 zenithTint = new Vector3(pbrSky.zenithTint.value.r, pbrSky.zenithTint.value.g, pbrSky.zenithTint.value.b);
m_ConstantBuffer._ZenithTint = zenithTint;
m_ConstantBuffer._HorizonZenithShiftScale = expParams.y;
m_ConstantBuffer._CelestialLightCount = s_CelestialLightCount;
m_ConstantBuffer._CelestialBodyCount = s_CelestialBodyCount;
m_ConstantBuffer._CelestialLightExposure = s_CelestialLightExposure;
ConstantBuffer.PushGlobal(cmd, m_ConstantBuffer, m_ShaderVariablesPhysicallyBasedSkyID);
}
protected override bool Update(BuiltinSkyParameters builtinParams)
{
UpdateGlobalConstantBuffer(builtinParams.commandBuffer, builtinParams);
var pbrSky = builtinParams.skySettings as PhysicallyBasedSky;
int currPrecomputationParamHash = pbrSky.GetPrecomputationHashCode(builtinParams.hdCamera);
if (currPrecomputationParamHash != m_LastPrecomputationParamHash)
{
if (m_LastPrecomputationParamHash != 0)
s_PrecomputationCache.Release(m_LastPrecomputationParamHash);
m_PrecomputedData = s_PrecomputationCache.Get(builtinParams, currPrecomputationParamHash);
m_LastPrecomputationParamHash = currPrecomputationParamHash;
}
return false;
}
public override void RenderSky(BuiltinSkyParameters builtinParams, bool renderForCubemap, bool renderSunDisk)
{
var pbrSky = builtinParams.skySettings as PhysicallyBasedSky;
var renderingSpace = SupportSpace ? RenderingSpace.World : builtinParams.hdCamera.planet.renderingSpace;
if (renderingSpace == RenderingSpace.Camera)
m_PrecomputedData.RenderSkyViewLut(builtinParams.commandBuffer);
if (!SupportSpace && pbrSky.atmosphericScattering.value && !renderForCubemap) // TODO: include fog & scattering in cubemaps
m_PrecomputedData.RenderAtmosphericScatteringLut(builtinParams);
m_PrecomputedData.BindGlobalBuffers(builtinParams.commandBuffer);
m_PrecomputedData.BindBuffers(s_PbrSkyMaterialProperties);
Unity.Mathematics.float4 upAltitude = HDRenderPipeline.currentPipeline.GetShaderVariablesGlobalCB()._PlanetUpAltitude;
Vector3 cameraPosPS = builtinParams.worldSpaceCameraPos - builtinParams.hdCamera.planet.center;
if (upAltitude.w < 1.0f) // Ensure camera is not below the ground
cameraPosPS -= (upAltitude.w - 1.0f) * (Vector3)upAltitude.xyz;
bool simpleEarthMode = pbrSky.type.value == PhysicallyBasedSkyModel.EarthSimple;
bool customMaterial = pbrSky.renderingMode.value == PhysicallyBasedSky.RenderingMode.Material && pbrSky.material.value != null;
var material = customMaterial ? pbrSky.material.value : m_PbrSkyMaterial;
// Common material properties
s_PbrSkyMaterialProperties.SetMatrix(HDShaderIDs._PixelCoordToViewDirWS, builtinParams.pixelCoordToViewDirMatrix);
s_PbrSkyMaterialProperties.SetVector(HDShaderIDs._PBRSkyCameraPosPS, cameraPosPS);
s_PbrSkyMaterialProperties.SetInt(HDShaderIDs._RenderSunDisk, renderSunDisk ? 1 : 0);
s_PbrSkyMaterialProperties.SetBuffer(HDShaderIDs._CelestialBodyDatas, s_CelestialBodyBuffer);
CoreUtils.SetKeyword(material, "LOCAL_SKY", renderingSpace == RenderingSpace.World);
if (!customMaterial)
{
// Precomputation is done, shading is next.
Quaternion planetRotation = Quaternion.Euler(pbrSky.planetRotation.value.x,
pbrSky.planetRotation.value.y,
pbrSky.planetRotation.value.z);
Quaternion spaceRotation = Quaternion.Euler(pbrSky.spaceRotation.value.x,
pbrSky.spaceRotation.value.y,
pbrSky.spaceRotation.value.z);
var planetRotationMatrix = Matrix4x4.Rotate(planetRotation);
planetRotationMatrix[0] *= -1;
planetRotationMatrix[1] *= -1;
planetRotationMatrix[2] *= -1;
s_PbrSkyMaterialProperties.SetMatrix(HDShaderIDs._PlanetRotation, planetRotationMatrix);
s_PbrSkyMaterialProperties.SetMatrix(HDShaderIDs._SpaceRotation, Matrix4x4.Rotate(spaceRotation));
int hasGroundAlbedoTexture = 0;
if (pbrSky.groundColorTexture.value != null && !simpleEarthMode)
{
hasGroundAlbedoTexture = 1;
s_PbrSkyMaterialProperties.SetTexture(HDShaderIDs._GroundAlbedoTexture, pbrSky.groundColorTexture.value);
}
s_PbrSkyMaterialProperties.SetInt(HDShaderIDs._HasGroundAlbedoTexture, hasGroundAlbedoTexture);
int hasGroundEmissionTexture = 0;
if (pbrSky.groundEmissionTexture.value != null && !simpleEarthMode)
{
hasGroundEmissionTexture = 1;
s_PbrSkyMaterialProperties.SetTexture(HDShaderIDs._GroundEmissionTexture, pbrSky.groundEmissionTexture.value);
s_PbrSkyMaterialProperties.SetFloat(HDShaderIDs._GroundEmissionMultiplier, pbrSky.groundEmissionMultiplier.value);
}
s_PbrSkyMaterialProperties.SetInt(HDShaderIDs._HasGroundEmissionTexture, hasGroundEmissionTexture);
int hasSpaceEmissionTexture = 0;
if (pbrSky.spaceEmissionTexture.value != null && !simpleEarthMode)
{
hasSpaceEmissionTexture = 1;
s_PbrSkyMaterialProperties.SetTexture(HDShaderIDs._SpaceEmissionTexture, pbrSky.spaceEmissionTexture.value);
s_PbrSkyMaterialProperties.SetFloat(HDShaderIDs._SpaceEmissionMultiplier, pbrSky.spaceEmissionMultiplier.value);
}
s_PbrSkyMaterialProperties.SetInt(HDShaderIDs._HasSpaceEmissionTexture, hasSpaceEmissionTexture);
}
int pass = (renderForCubemap ? 0 : 1);
CoreUtils.DrawFullScreen(builtinParams.commandBuffer, material, s_PbrSkyMaterialProperties, pass);
}
static internal void FillCelestialBodyData(CommandBuffer cmd, HDAdditionalLightData additional, ref CelestialBodyData celestialBodyData)
{
var light = additional.legacyLight;
var transform = light.transform;
celestialBodyData.color = (Vector4)additional.EvaluateLightColor();
// General
celestialBodyData.forward = transform.forward;
celestialBodyData.right = transform.right.normalized;
celestialBodyData.up = transform.up.normalized;
var angularDiameter = additional.diameterMultiplerMode ? additional.diameterMultiplier * additional.angularDiameter : additional.diameterOverride;
celestialBodyData.angularRadius = angularDiameter * 0.5f * Mathf.Deg2Rad;
celestialBodyData.distanceFromCamera = additional.distance;
celestialBodyData.radius = Mathf.Tan(celestialBodyData.angularRadius) * celestialBodyData.distanceFromCamera;
celestialBodyData.surfaceColor = (Vector4)additional.surfaceTint.linear;
celestialBodyData.earthshine = additional.earthshine * 0.01f; // earth reflects about 0.01% of sun light
celestialBodyData.shadowIndex = additional.shadowIndex;
if (additional.surfaceTexture == null)
celestialBodyData.surfaceTextureScaleOffset = Vector4.zero;
else
celestialBodyData.surfaceTextureScaleOffset = HDRenderPipeline.currentPipeline.m_TextureCaches.lightCookieManager.Fetch2DCookie(cmd, additional.surfaceTexture);
// Flare
celestialBodyData.flareSize = Mathf.Max(additional.flareSize * Mathf.Deg2Rad, 5.960464478e-8f);
celestialBodyData.flareFalloff = additional.flareFalloff;
celestialBodyData.flareCosInner = Mathf.Cos(celestialBodyData.angularRadius);
celestialBodyData.flareCosOuter = Mathf.Cos(celestialBodyData.angularRadius + celestialBodyData.flareSize);
celestialBodyData.flareColor = additional.flareMultiplier * (Vector4)additional.flareTint.linear;
// Shading
var source = additional.celestialBodyShadingSource;
if (source == ShadingSource.Emission)
{
celestialBodyData.type = 0;
float rcpSolidAngle = 1.0f / (Mathf.PI * 2.0f * (1 - celestialBodyData.flareCosInner));
celestialBodyData.surfaceColor *= rcpSolidAngle;
celestialBodyData.flareColor *= rcpSolidAngle;
celestialBodyData.surfaceColor = Vector4.Scale(celestialBodyData.color, celestialBodyData.surfaceColor);
celestialBodyData.flareColor = Vector4.Scale(celestialBodyData.color, celestialBodyData.flareColor);
}
else
{
Color sunColor;
if (source == ShadingSource.Manual)
{
var rotation = Quaternion.AngleAxis(additional.moonPhaseRotation, celestialBodyData.forward);
var remap = Quaternion.FromToRotation(Vector3.right, celestialBodyData.forward);
float phase = additional.moonPhase * 2.0f * Mathf.PI;
sunColor = additional.sunColor * additional.sunIntensity;
celestialBodyData.sunDirection = rotation * remap * new Vector3(Mathf.Cos(phase), 0, Mathf.Sin(phase));
}
else
{
var lightSource = additional.sunLightOverride;
if (lightSource == null || lightSource == additional.legacyLight || lightSource.type != LightType.Directional)
lightSource = FindSunLight(additional.legacyLight);
sunColor = lightSource != null ? (Vector4)lightSource.GetComponent<HDAdditionalLightData>().EvaluateLightColor() : Vector4.zero;
celestialBodyData.sunDirection = lightSource != null ? lightSource.transform.forward : Vector3.forward;
}
celestialBodyData.type = 1;
celestialBodyData.surfaceColor = Vector4.Scale(sunColor, celestialBodyData.surfaceColor);
celestialBodyData.flareColor = Vector4.Scale(sunColor, celestialBodyData.flareColor);
}
}
static Light FindSunLight(Light toExclude)
{
Light result = null;
float currentMax = 0.0f;
foreach (var light in HDLightRenderDatabase.instance.directionalLights)
{
if (light != toExclude && light.legacyLight.intensity > currentMax)
{
currentMax = light.legacyLight.intensity;
result = light.legacyLight;
}
}
return result;
}
}
}