using System; using UnityEngine; using UnityEngine.Rendering; namespace Artngame.SKYMASTER { [ExecuteInEditMode] public class AtmosphericScatteringSkyMaster : MonoBehaviour { public enum OcclusionDownscale { x1 = 1, x2 = 2, x4 = 4 } public enum OcclusionSamples { x64 = 0, x164 = 1, x244 = 2 } public enum ScatterDebugMode { None = 0, Scattering = 1, Occlusion = 2, OccludedScattering = 3, Rayleigh = 4, Mie = 5, Height = 6 } public enum DepthTexture { Enable = 0, Disable = 1, Ignore = 2 } [Header("World Components")] public Gradient worldRayleighColorRamp; public GameObject Sun; public bool FogSky; public float FogHorizonLower = 1f; public float worldRayleighColorIntensity = 1f; public float worldRayleighDensity = 10f; public float worldRayleighExtinctionFactor = 1.1f; public float worldRayleighIndirectScatter = 0.33f; public Gradient worldMieColorRamp; public float worldMieColorIntensity = 1f; public float worldMieDensity = 15f; public float worldMieExtinctionFactor; public float worldMiePhaseAnisotropy = 0.9f; public float worldNearScatterPush; public float worldNormalDistance = 1000f; [Header("Height Components")] public Color heightRayleighColor = Color.white; public float heightRayleighIntensity = 1f; public float heightRayleighDensity = 10f; public float heightMieDensity; public float heightExtinctionFactor = 1.1f; public float heightSeaLevel; public float heightDistance = 50f; public Vector3 heightPlaneShift = Vector3.zero; public float heightNearScatterPush; public float heightNormalDistance = 1000f; [Header("Sky Dome")] public Vector3 skyDomeScale = new Vector3(1f, 0.1f, 1f); public Vector3 skyDomeRotation = Vector3.zero; public Transform skyDomeTrackedYawRotation; public bool skyDomeVerticalFlip; public Cubemap skyDomeCube; public float skyDomeExposure = 1f; public Color skyDomeTint = Color.white; [HideInInspector] public Vector3 skyDomeOffset = Vector3.zero; [Header("Scatter Occlusion")] public bool useOcclusion; public float occlusionBias; public float occlusionBiasIndirect = 0.6f; public float occlusionBiasClouds = 0.3f; public OcclusionDownscale occlusionDownscale = OcclusionDownscale.x2; public OcclusionSamples occlusionSamples; public bool occlusionDepthFixup = true; public float occlusionDepthThreshold = 25f; public bool occlusionFullSky; public float occlusionBiasSkyRayleigh = 0.2f; public float occlusionBiasSkyMie = 0.4f; public float backLightDepth = 5000f; public float backLightIntensity = 0.95f; [Header("Other")] public float worldScaleExponent = 1f; public bool forcePerPixel; public bool forcePostEffect; [Tooltip("Soft clouds need depth values. Ignore means externally controlled.")] public DepthTexture depthTexture; public ScatterDebugMode debugMode; [HideInInspector] public Shader occlusionShader; private bool m_isAwake; private Camera m_currentCamera; private Material m_occlusionMaterial; private CommandBuffer m_occlusionCmdAfterShadows; private CommandBuffer m_occlusionCmdBeforeScreen; public SkyMasterManager SkyManager; private bool gameStart; public static AtmosphericScatteringSkyMaster instance { get; private set; } private void Start() { gameStart = true; OnWillRenderObject(); } private void Awake() { if (!GetComponent()) { MeshFilter meshFilter = base.gameObject.AddComponent(); meshFilter.sharedMesh = new Mesh(); meshFilter.sharedMesh.bounds = new Bounds(Vector3.zero, Vector3.one * 10000f); meshFilter.sharedMesh.SetTriangles((int[])null, 0); } if (!GetComponent()) { MeshRenderer meshRenderer = base.gameObject.AddComponent(); meshRenderer.receiveShadows = false; meshRenderer.lightProbeUsage = LightProbeUsage.Off; meshRenderer.shadowCastingMode = ShadowCastingMode.Off; meshRenderer.reflectionProbeUsage = ReflectionProbeUsage.Off; } if (occlusionShader == null) { occlusionShader = Shader.Find("Hidden/AtmosphericScattering_OcclusionSM34"); } m_occlusionMaterial = new Material(occlusionShader); m_occlusionMaterial.hideFlags = HideFlags.HideAndDontSave; if (worldRayleighColorRamp == null) { worldRayleighColorRamp = new Gradient(); worldRayleighColorRamp.SetKeys(new GradientColorKey[2] { new GradientColorKey(new Color(0.3f, 0.4f, 0.6f), 0f), new GradientColorKey(new Color(0.5f, 0.6f, 0.8f), 1f) }, new GradientAlphaKey[2] { new GradientAlphaKey(1f, 0f), new GradientAlphaKey(1f, 1f) }); } if (worldMieColorRamp == null) { worldMieColorRamp = new Gradient(); worldMieColorRamp.SetKeys(new GradientColorKey[2] { new GradientColorKey(new Color(0.95f, 0.75f, 0.5f), 0f), new GradientColorKey(new Color(1f, 0.9f, 8f), 1f) }, new GradientAlphaKey[2] { new GradientAlphaKey(1f, 0f), new GradientAlphaKey(1f, 1f) }); } m_isAwake = true; if (SkyManager != null && Sun == null) { Sun = SkyManager.SUN_LIGHT; } } private void Update() { if (!(SkyManager != null)) { return; } if ((!SkyManager.AutoSunPosition && ((SkyManager.Current_Time >= 9f + SkyManager.Shift_dawn) & (SkyManager.Current_Time <= SkyManager.NightTimeMax + SkyManager.Shift_dawn))) || (SkyManager.AutoSunPosition && SkyManager.Rot_Sun_X > 0f)) { if (Sun != SkyManager.SUN_LIGHT) { Sun = SkyManager.SUN_LIGHT; SkyManager.MOON_LIGHT.GetComponent().RemoveAllCommandBuffers(); EnsureHookedLightSource(Sun.GetComponent()); UpdateDynamicUniforms(); } } else if (Sun != SkyManager.MOON_LIGHT) { Sun = SkyManager.MOON_LIGHT; SkyManager.SUN_LIGHT.GetComponent().RemoveAllCommandBuffers(); EnsureHookedLightSource(Sun.GetComponent()); UpdateDynamicUniforms(); } } private void OnEnable() { if (m_isAwake) { UpdateKeywords(enable: true); UpdateStaticUniforms(); if ((bool)instance) { _ = instance != this; } instance = this; if (SkyManager != null && Sun == null) { Sun = SkyManager.SUN_LIGHT; } } } private void EnsureHookedLightSource(Light light) { if ((bool)light && light.commandBufferCount != 2) { light.RemoveAllCommandBuffers(); if (m_occlusionCmdAfterShadows != null) { m_occlusionCmdAfterShadows.Dispose(); } if (m_occlusionCmdBeforeScreen != null) { m_occlusionCmdBeforeScreen.Dispose(); } m_occlusionCmdAfterShadows = new CommandBuffer(); m_occlusionCmdAfterShadows.name = "Scatter Occlusion Pass 1"; m_occlusionCmdAfterShadows.SetGlobalTexture("u_SMCascadedShadowMap", new RenderTargetIdentifier(BuiltinRenderTextureType.CurrentActive)); m_occlusionCmdBeforeScreen = new CommandBuffer(); m_occlusionCmdBeforeScreen.name = "Scatter Occlusion Pass 2"; light.AddCommandBuffer(LightEvent.AfterShadowMap, m_occlusionCmdAfterShadows); light.AddCommandBuffer(LightEvent.BeforeScreenspaceMask, m_occlusionCmdBeforeScreen); } } private void OnDisable() { UpdateKeywords(enable: false); if (Sun != null && (bool)Sun.GetComponent()) { Sun.GetComponent().RemoveAllCommandBuffers(); } if (SkyManager != null) { if (SkyManager.SUN_LIGHT != null && (bool)SkyManager.SUN_LIGHT.GetComponent()) { SkyManager.SUN_LIGHT.GetComponent().RemoveAllCommandBuffers(); } if (SkyManager.MOON_LIGHT != null && (bool)SkyManager.MOON_LIGHT.GetComponent()) { SkyManager.MOON_LIGHT.GetComponent().RemoveAllCommandBuffers(); } } if (instance != this) { _ = (bool)instance; } else { instance = null; } } private void UpdateKeywords(bool enable) { if (enable) { _ = forcePerPixel; _ = useOcclusion; _ = debugMode; } } public void OnValidate() { if (m_isAwake) { occlusionBias = Mathf.Clamp01(occlusionBias); occlusionBiasIndirect = Mathf.Clamp01(occlusionBiasIndirect); occlusionBiasClouds = Mathf.Clamp01(occlusionBiasClouds); occlusionBiasSkyRayleigh = Mathf.Clamp01(occlusionBiasSkyRayleigh); occlusionBiasSkyMie = Mathf.Clamp01(occlusionBiasSkyMie); worldScaleExponent = Mathf.Clamp(worldScaleExponent, 1f, 2f); worldNormalDistance = Mathf.Clamp(worldNormalDistance, 1f, 10000f); worldNearScatterPush = Mathf.Clamp(worldNearScatterPush, -200f, 300f); worldRayleighDensity = Mathf.Clamp(worldRayleighDensity, 0f, 1000f); worldMieDensity = Mathf.Clamp(worldMieDensity, 0f, 1000f); worldRayleighIndirectScatter = Mathf.Clamp(worldRayleighIndirectScatter, 0f, 1f); heightNormalDistance = Mathf.Clamp(heightNormalDistance, 1f, 10000f); heightNearScatterPush = Mathf.Clamp(heightNearScatterPush, -200f, 300f); heightRayleighDensity = Mathf.Clamp(heightRayleighDensity, 0f, 1000f); heightMieDensity = Mathf.Clamp(heightMieDensity, 0f, 1000f); worldMiePhaseAnisotropy = Mathf.Clamp01(worldMiePhaseAnisotropy); skyDomeExposure = Mathf.Clamp(skyDomeExposure, 0f, 8f); if (instance == this) { OnDisable(); OnEnable(); } } } private void OnWillRenderObject() { if (!m_isAwake || (bool)m_currentCamera) { return; } if (Sun != null) { EnsureHookedLightSource(Sun.GetComponent()); } if (gameStart) { gameStart = false; return; } m_currentCamera = Camera.current; if ((SystemInfo.graphicsShaderLevel >= 40 || depthTexture == DepthTexture.Enable) && m_currentCamera.depthTextureMode == DepthTextureMode.None) { m_currentCamera.depthTextureMode = DepthTextureMode.Depth; } else if (depthTexture == DepthTexture.Disable && m_currentCamera.depthTextureMode != DepthTextureMode.None) { m_currentCamera.depthTextureMode = DepthTextureMode.None; } UpdateDynamicUniforms(); if (useOcclusion) { Vector3 right = m_currentCamera.transform.right; Vector3 up = m_currentCamera.transform.up; Vector3 forward = m_currentCamera.transform.forward; float num = Mathf.Tan(m_currentCamera.fieldOfView * 0.5f * (MathF.PI / 180f)); float num2 = num * m_currentCamera.aspect; Vector3 vector = forward * m_currentCamera.farClipPlane; Vector3 vector2 = right * num2 * m_currentCamera.farClipPlane; Vector3 vector3 = up * num * m_currentCamera.farClipPlane; m_occlusionMaterial.SetFloat("_ToggleForward", 0f); m_occlusionMaterial.SetVector("u_SMCameraPosition", m_currentCamera.transform.position); m_occlusionMaterial.SetVector("u_SMViewportCorner", vector - vector2 - vector3); m_occlusionMaterial.SetVector("u_SMViewportRight", vector2 * 2f); m_occlusionMaterial.SetVector("u_SMViewportUp", vector3 * 2f); float num3 = (m_currentCamera ? m_currentCamera.farClipPlane : 1000f); float value = (Mathf.Min(num3, QualitySettings.shadowDistance) - 1f) / num3; m_occlusionMaterial.SetFloat("u_SMOcclusionSkyRefDistance", value); Rect pixelRect = m_currentCamera.pixelRect; float num4 = 1f / (float)occlusionDownscale; int width = Mathf.RoundToInt(pixelRect.width * num4); int height = Mathf.RoundToInt(pixelRect.height * num4); int num5 = Shader.PropertyToID("u_SMOcclusionTexture"); if (m_occlusionCmdBeforeScreen != null) { m_occlusionCmdBeforeScreen.Clear(); m_occlusionCmdBeforeScreen.GetTemporaryRT(num5, width, height, 0, FilterMode.Bilinear, RenderTextureFormat.R8, RenderTextureReadWrite.sRGB); m_occlusionCmdBeforeScreen.Blit(null, num5, m_occlusionMaterial, (int)occlusionSamples); m_occlusionCmdBeforeScreen.SetGlobalTexture(num5, num5); m_occlusionCmdBeforeScreen.ReleaseTemporaryRT(num5); } } } private void OnRenderObject() { if (m_currentCamera == Camera.current) { m_currentCamera = null; } } private void UpdateStaticUniforms() { Shader.SetGlobalVector("u_SMSkyDomeOffset", skyDomeOffset); Shader.SetGlobalVector("u_SMSkyDomeScale", skyDomeScale); Shader.SetGlobalTexture("u_SMSkyDomeCube", skyDomeCube); Shader.SetGlobalFloat("u_SMSkyDomeExposure", skyDomeExposure); Shader.SetGlobalColor("u_SMSkyDomeTint", skyDomeTint); Shader.SetGlobalFloat("u_SMShadowBias", useOcclusion ? occlusionBias : 1f); Shader.SetGlobalFloat("u_SMShadowBiasIndirect", useOcclusion ? occlusionBiasIndirect : 1f); Shader.SetGlobalFloat("u_SMShadowBiasClouds", useOcclusion ? occlusionBiasClouds : 1f); Shader.SetGlobalVector("u_SMShadowBiasSkyRayleighMie", useOcclusion ? new Vector4(occlusionBiasSkyRayleigh, occlusionBiasSkyMie, 0f, 0f) : Vector4.zero); Shader.SetGlobalFloat("u_SMOcclusionDepthThreshold", occlusionDepthThreshold); Shader.SetGlobalFloat("u_SMWorldScaleExponent", worldScaleExponent); Shader.SetGlobalFloat("u_SMWorldNormalDistanceRcp", 1f / worldNormalDistance); Shader.SetGlobalFloat("u_SMWorldNearScatterPush", (0f - Mathf.Pow(Mathf.Abs(worldNearScatterPush), worldScaleExponent)) * Mathf.Sign(worldNearScatterPush)); Shader.SetGlobalFloat("u_SMWorldRayleighDensity", (0f - worldRayleighDensity) / 100000f); Shader.SetGlobalFloat("u_SMMiePhaseAnisotropy", worldMiePhaseAnisotropy); Shader.SetGlobalVector("u_SMRayleighInScatterPct", new Vector4(1f - worldRayleighIndirectScatter, worldRayleighIndirectScatter, 0f, 0f)); Shader.SetGlobalFloat("u_SMHeightNormalDistanceRcp", 1f / heightNormalDistance); Shader.SetGlobalFloat("u_SMHeightNearScatterPush", (0f - Mathf.Pow(Mathf.Abs(heightNearScatterPush), worldScaleExponent)) * Mathf.Sign(heightNearScatterPush)); Shader.SetGlobalFloat("u_SMHeightRayleighDensity", (0f - heightRayleighDensity) / 100000f); Shader.SetGlobalFloat("u_SMHeightSeaLevel", heightSeaLevel); Shader.SetGlobalFloat("u_SMHeightDistanceRcp", 1f / heightDistance); Shader.SetGlobalVector("u_SMHeightPlaneShift", heightPlaneShift); Shader.SetGlobalVector("u_SMHeightRayleighColor", (Vector4)heightRayleighColor * heightRayleighIntensity); Shader.SetGlobalFloat("u_SMHeightExtinctionFactor", heightExtinctionFactor); Shader.SetGlobalFloat("u_SMRayleighExtinctionFactor", worldRayleighExtinctionFactor); Shader.SetGlobalFloat("u_SMMieExtinctionFactor", worldMieExtinctionFactor); Color color = worldRayleighColorRamp.Evaluate(0f); Color color2 = worldRayleighColorRamp.Evaluate(0.25f); Color color3 = worldRayleighColorRamp.Evaluate(0.5f); Color color4 = worldRayleighColorRamp.Evaluate(0.75f); Color color5 = worldRayleighColorRamp.Evaluate(1f); Color color6 = worldMieColorRamp.Evaluate(0f); Color color7 = worldMieColorRamp.Evaluate(0.5f); Color color8 = worldMieColorRamp.Evaluate(1f); Shader.SetGlobalVector("u_SMRayleighColorM20", (Vector4)color * worldRayleighColorIntensity); Shader.SetGlobalVector("u_SMRayleighColorM10", (Vector4)color2 * worldRayleighColorIntensity); Shader.SetGlobalVector("u_SMRayleighColorO00", (Vector4)color3 * worldRayleighColorIntensity); Shader.SetGlobalVector("u_SMRayleighColorP10", (Vector4)color4 * worldRayleighColorIntensity); Shader.SetGlobalVector("u_SMRayleighColorP20", (Vector4)color5 * worldRayleighColorIntensity); Shader.SetGlobalVector("u_SMMieColorM20", (Vector4)color6 * worldMieColorIntensity); Shader.SetGlobalVector("u_SMMieColorO00", (Vector4)color7 * worldMieColorIntensity); Shader.SetGlobalVector("u_SMMieColorP20", (Vector4)color8 * worldMieColorIntensity); Shader.SetGlobalFloat("u_SMAtmosphericsDebugMode", (float)debugMode); if (occlusionFullSky) { Shader.SetGlobalFloat("u_SMOcclusionSkyToggle", 1f); } else { Shader.SetGlobalFloat("u_SMOcclusionSkyToggle", 0f); } if (FogSky) { Shader.SetGlobalFloat("u_SMFogSkyToggle", 1f); } else { Shader.SetGlobalFloat("u_SMFogSkyToggle", 0f); } Shader.SetGlobalFloat("u_SMFogHorizonLower", FogHorizonLower); Shader.SetGlobalFloat("backLightDepth", backLightDepth); Shader.SetGlobalFloat("backLightIntensity", backLightIntensity); } private void UpdateDynamicUniforms() { bool flag = false; flag = ((SkyManager != null) ? true : false); if (SkyManager != null) { if (SkyManager.currentWeatherName == SkyMasterManager.Volume_Weather_types.HeavyStorm || SkyManager.currentWeatherName == SkyMasterManager.Volume_Weather_types.HeavyStormDark) { Shader.SetGlobalVector("u_SMHeightRayleighColor", (Vector4)heightRayleighColor * heightRayleighIntensity * 0.6f); } else { Shader.SetGlobalVector("u_SMHeightRayleighColor", (Vector4)heightRayleighColor * heightRayleighIntensity); } } else { Shader.SetGlobalVector("u_SMHeightRayleighColor", (Vector4)heightRayleighColor * heightRayleighIntensity); } Shader.SetGlobalFloat("u_SMHeightSeaLevel", heightSeaLevel); Shader.SetGlobalFloat("u_SMHeightDistanceRcp", 1f / heightDistance); if (!Application.isPlaying) { if (occlusionFullSky) { Shader.SetGlobalFloat("u_SMOcclusionSkyToggle", 1f); } else { Shader.SetGlobalFloat("u_SMOcclusionSkyToggle", 0f); } if (FogSky) { Shader.SetGlobalFloat("u_SMFogSkyToggle", 1f); } else { Shader.SetGlobalFloat("u_SMFogSkyToggle", 0f); } Shader.SetGlobalFloat("u_SMShadowBias", useOcclusion ? occlusionBias : 1f); Shader.SetGlobalFloat("u_SMShadowBiasIndirect", useOcclusion ? occlusionBiasIndirect : 1f); Shader.SetGlobalFloat("u_SMShadowBiasClouds", useOcclusion ? occlusionBiasClouds : 1f); Shader.SetGlobalVector("u_SMShadowBiasSkyRayleighMie", useOcclusion ? new Vector4(occlusionBiasSkyRayleigh, occlusionBiasSkyMie, 0f, 0f) : Vector4.zero); } Shader.SetGlobalFloat("u_SMFogHorizonLower", FogHorizonLower); Shader.SetGlobalFloat("backLightDepth", backLightDepth); Shader.SetGlobalFloat("backLightIntensity", backLightIntensity); float num = (skyDomeTrackedYawRotation ? skyDomeTrackedYawRotation.eulerAngles.y : 0f); Shader.SetGlobalMatrix("u_SMSkyDomeRotation", Matrix4x4.TRS(Vector3.zero, Quaternion.Euler(skyDomeRotation.x, 0f, 0f), Vector3.one) * Matrix4x4.TRS(Vector3.zero, Quaternion.Euler(0f, skyDomeRotation.y - num, 0f), Vector3.one) * Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(1f, skyDomeVerticalFlip ? (-1f) : 1f, 1f))); Shader.SetGlobalVector("u_SMSunDirection", flag ? (-Sun.transform.forward) : Vector3.down); Shader.SetGlobalFloat("u_SMWorldMieDensity", flag ? ((0f - worldMieDensity) / 100000f) : 0f); Shader.SetGlobalFloat("u_SMHeightMieDensity", flag ? ((0f - heightMieDensity) / 100000f) : 0f); Rect rect = (m_currentCamera ? m_currentCamera.pixelRect : new Rect(0f, 0f, Screen.width, Screen.height)); float num2 = (float)occlusionDownscale; Vector4 value = new Vector4(num2 / rect.width, num2 / rect.height, (0f - num2) / rect.width, (0f - num2) / rect.height); Shader.SetGlobalVector("u_SMDepthTextureScaledTexelSize", value); } } }