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 m_DataPool = new ObjectPool(null, null); Dictionary m_CachedData = new Dictionary(); 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(); 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().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; } } }