using System; namespace UnityEngine.AzureSky { [ExecuteInEditMode] [AddComponentMenu("Azure[Sky]/Azure Sky Render Controller")] public class AzureSkyRenderController : MonoBehaviour { [Tooltip("The Transform used to simulate the sun position in the sky.")] [SerializeField] private Transform m_sunTransform; [Tooltip("The Transform used to simulate the moon position in the sky.")] [SerializeField] private Transform m_moonTransform; [Tooltip("The material used to render the sky.")] [SerializeField] private Material m_skyMaterial; [Tooltip("The material used to render the fog scattering.")] [SerializeField] private Material m_fogMaterial; [Tooltip("The shader used to render the sky only.")] [SerializeField] private Shader m_emptySkyShader; [Tooltip("The shader used to render the sky with static clouds.")] [SerializeField] private Shader m_staticCloudsShader; [Tooltip("The shader used to render the sky with dynamic clouds.")] [SerializeField] private Shader m_dynamicCloudsShader; [Tooltip("The texture used to render the sun disk.")] [SerializeField] private Texture2D m_sunTexture; [Tooltip("The texture used to render the moon disk.")] [SerializeField] private Texture2D m_moonTexture; [Tooltip("The cubemap texture used to render the stars and Milky Way.")] [SerializeField] private Cubemap m_starfieldTexture; [Tooltip("The texture used to render the dynamic clouds.")] [SerializeField] private Texture2D m_dynamicCloudsTexture; [Tooltip("The texture used to render the static clouds.")] public Texture2D staticCloudTexture; [Tooltip("The molecular density of the air.")] public float molecularDensity = 2.545f; [Tooltip("The red visible wavelength.")] public float wavelengthR = 680f; [Tooltip("The green visible wavelength.")] public float wavelengthG = 550f; [Tooltip("The blue visible wavelength.")] public float wavelengthB = 450f; [Tooltip("The rayleigh altitude in kilometers.")] public float kr = 8.4f; [Tooltip("The mie altitude in kilometers.")] public float km = 1.2f; [Tooltip("The rayleigh scattering multiplier.")] public float rayleigh = 1.5f; [Tooltip("The mie scattering multiplier.")] public float mie = 1f; [Tooltip("The mie distance.")] public float mieDistance = 1f; [Tooltip("The scattering intensity.")] public float scattering = 0.25f; [Tooltip("The sky luminance, useful when there is no moon at night sky.")] public float luminance = 1.5f; [Tooltip("The exposure of the internal sky shader tonemapping.")] public float exposure = 2f; [Tooltip("The rayleigh color multiplier.")] public Color rayleighColor = Color.white; [Tooltip("The mie color multiplier.")] public Color mieColor = Color.white; [Tooltip("The scattering color multiplier.")] public Color scatteringColor = Color.white; [Tooltip("The size of the sun texture.")] public float sunTextureSize = 1.5f; [Tooltip("The intensity of the sun texture.")] public float sunTextureIntensity = 1f; [Tooltip("The sun texture color multiplier.")] public Color sunTextureColor = Color.white; [Tooltip("The size of the moon texture.")] public float moonTextureSize = 1.5f; [Tooltip("The intensity of the moon texture.")] public float moonTextureIntensity = 1f; [Tooltip("The moon texture color multiplier.")] public Color moonTextureColor = Color.white; [Tooltip("The intensity of the regular stars.")] public float starsIntensity = 0.5f; [Tooltip("The intensity of the Milky Way.")] public float milkyWayIntensity; [Tooltip("The star field color multiplier.")] public Color starfieldColor = Color.white; [Tooltip("The rotation of the star field on the X axis.")] public float starfieldRotationX; [Tooltip("The rotation of the star field on the Y axis.")] public float starfieldRotationY; [Tooltip("The rotation of the star field on the Z axis.")] public float starfieldRotationZ; [Tooltip("The scattering scale factor.")] public float fogScatteringScale = 1f; [Tooltip("The distance of the global fog scattering.")] public float globalFogDistance = 1000f; [Tooltip("The smooth step transition from where there is no global fog to where is completely foggy.")] public float globalFogSmoothStep = 0.25f; [Tooltip("The global fog scattering density.")] public float globalFogDensity = 1f; [Tooltip("The distance of the height fog scattering.")] public float heightFogDistance = 100f; [Tooltip("The smooth step transition from where there is no height fog to where is completely foggy.")] public float heightFogSmoothStep = 1f; [Tooltip("The height fog scattering density.")] public float heightFogDensity; [Tooltip("The height fog start height.")] public float heightFogStart; [Tooltip("The height fog end height.")] public float heightFogEnd = 100f; [Tooltip("The altitude of the dynamic clouds in the sky.")] public float dynamicCloudsAltitude = 7.5f; [Tooltip("The movement direction of the dynamic clouds.")] public float dynamicCloudsDirection; [Tooltip("The movement speed of the dynamic clouds.")] public float dynamicCloudsSpeed = 0.1f; [Tooltip("The coverage of the dynamic clouds.")] public float dynamicCloudsDensity = 0.75f; [Tooltip("The first color of the dynamic clouds.")] public Color dynamicCloudsColor1 = Color.white; [Tooltip("The second color of the dynamic clouds.")] public Color dynamicCloudsColor2 = Color.white; private Vector2 m_dynamicCloudsDirection = Vector2.zero; public float staticCloudLayer1Speed = 0.0025f; public float staticCloudLayer2Speed = 0.0075f; private float m_staticCloudLayer1Speed; private float m_staticCloudLayer2Speed; public float staticCloudScattering = 1f; public float staticCloudExtinction = 1.5f; public float staticCloudSaturation = 2.5f; public float staticCloudOpacity = 1.25f; public Color staticCloudColor = Color.white; [SerializeField] [Tooltip("The way the sky settings should be updated. By local material or by global shader properties.")] private AzureShaderUpdateMode m_shaderUpdateMode = AzureShaderUpdateMode.Global; [SerializeField] [Tooltip("The way the scattering color should be performed. Automatic by the controller or by your custom colors.")] private AzureScatteringMode m_scatteringMode; [SerializeField] [Tooltip("The cloud render system.")] private AzureCloudMode m_cloudMode = AzureCloudMode.Dynamic; private Quaternion m_starfieldRotation; private Matrix4x4 m_starfieldRotationMatrix; private void Awake() { m_dynamicCloudsDirection = Vector2.zero; InitializeShaderUniforms(); } private void OnEnable() { if ((bool)m_skyMaterial) { RenderSettings.skybox = m_skyMaterial; } } private void LateUpdate() { m_dynamicCloudsDirection = ComputeCloudPosition(); m_staticCloudLayer1Speed += staticCloudLayer1Speed * Time.deltaTime; m_staticCloudLayer2Speed += staticCloudLayer2Speed * Time.deltaTime; if (m_staticCloudLayer1Speed >= 1f) { m_staticCloudLayer1Speed -= 1f; } if (m_staticCloudLayer2Speed >= 1f) { m_staticCloudLayer2Speed -= 1f; } UpdateShaderUniforms(); } private void InitializeShaderUniforms() { switch (m_shaderUpdateMode) { case AzureShaderUpdateMode.Local: m_skyMaterial.SetTexture(AzureShaderUniforms.SunTexture, m_sunTexture); m_skyMaterial.SetTexture(AzureShaderUniforms.MoonTexture, m_moonTexture); m_skyMaterial.SetTexture(AzureShaderUniforms.StarFieldTexture, m_starfieldTexture); m_skyMaterial.SetTexture(AzureShaderUniforms.DynamicCloudTexture, m_dynamicCloudsTexture); m_skyMaterial.SetTexture(AzureShaderUniforms.StaticCloudTexture, staticCloudTexture); break; case AzureShaderUpdateMode.Global: Shader.SetGlobalTexture(AzureShaderUniforms.SunTexture, m_sunTexture); Shader.SetGlobalTexture(AzureShaderUniforms.MoonTexture, m_moonTexture); Shader.SetGlobalTexture(AzureShaderUniforms.StarFieldTexture, m_starfieldTexture); Shader.SetGlobalTexture(AzureShaderUniforms.DynamicCloudTexture, m_dynamicCloudsTexture); Shader.SetGlobalTexture(AzureShaderUniforms.StaticCloudTexture, staticCloudTexture); break; } } private void UpdateShaderUniforms() { m_starfieldRotation = Quaternion.Euler(starfieldRotationX, starfieldRotationY, starfieldRotationZ); m_starfieldRotationMatrix = Matrix4x4.TRS(Vector3.zero, m_starfieldRotation, Vector3.one); switch (m_shaderUpdateMode) { case AzureShaderUpdateMode.Local: UpdateLocalShaderUniforms(m_skyMaterial); UpdateLocalShaderUniforms(m_fogMaterial); break; case AzureShaderUpdateMode.Global: UpdateGlobalShaderUniforms(); break; } } private void UpdateLocalShaderUniforms(Material mat) { mat.SetVector(AzureShaderUniforms.SunDirection, base.transform.InverseTransformDirection(-m_sunTransform.forward)); mat.SetVector(AzureShaderUniforms.MoonDirection, base.transform.InverseTransformDirection(-m_moonTransform.forward)); mat.SetMatrix(AzureShaderUniforms.SunMatrix, m_sunTransform.worldToLocalMatrix); mat.SetMatrix(AzureShaderUniforms.MoonMatrix, m_moonTransform.worldToLocalMatrix); mat.SetMatrix(AzureShaderUniforms.UpDirectionMatrix, base.transform.worldToLocalMatrix); mat.SetInt(AzureShaderUniforms.ScatteringMode, (int)m_scatteringMode); mat.SetFloat(AzureShaderUniforms.Kr, kr * 1000f); mat.SetFloat(AzureShaderUniforms.Km, km * 1000f); mat.SetVector(AzureShaderUniforms.Rayleigh, ComputeRayleigh() * rayleigh); mat.SetVector(AzureShaderUniforms.Mie, ComputeMie() * mie); mat.SetFloat(AzureShaderUniforms.MieDistance, mieDistance); mat.SetFloat(AzureShaderUniforms.Scattering, scattering * 60f); mat.SetFloat(AzureShaderUniforms.Luminance, luminance); mat.SetFloat(AzureShaderUniforms.Exposure, exposure); mat.SetColor(AzureShaderUniforms.RayleighColor, rayleighColor); mat.SetColor(AzureShaderUniforms.MieColor, mieColor); mat.SetColor(AzureShaderUniforms.ScatteringColor, scatteringColor); mat.SetFloat(AzureShaderUniforms.SunTextureSize, sunTextureSize); mat.SetFloat(AzureShaderUniforms.SunTextureIntensity, sunTextureIntensity); mat.SetColor(AzureShaderUniforms.SunTextureColor, sunTextureColor); mat.SetFloat(AzureShaderUniforms.MoonTextureSize, moonTextureSize); mat.SetFloat(AzureShaderUniforms.MoonTextureIntensity, moonTextureIntensity); mat.SetColor(AzureShaderUniforms.MoonTextureColor, moonTextureColor); mat.SetFloat(AzureShaderUniforms.StarsIntensity, starsIntensity); mat.SetFloat(AzureShaderUniforms.MilkyWayIntensity, milkyWayIntensity); mat.SetColor(AzureShaderUniforms.StarFieldColor, starfieldColor); mat.SetMatrix(AzureShaderUniforms.StarFieldRotation, m_starfieldRotationMatrix); mat.SetFloat(AzureShaderUniforms.FogScatteringScale, fogScatteringScale); mat.SetFloat(AzureShaderUniforms.GlobalFogDistance, globalFogDistance); mat.SetFloat(AzureShaderUniforms.GlobalFogSmoothStep, globalFogSmoothStep); mat.SetFloat(AzureShaderUniforms.GlobalFogDensity, globalFogDensity); mat.SetFloat(AzureShaderUniforms.HeightFogDistance, heightFogDistance); mat.SetFloat(AzureShaderUniforms.HeightFogSmoothStep, heightFogSmoothStep); mat.SetFloat(AzureShaderUniforms.HeightFogDensity, heightFogDensity); mat.SetFloat(AzureShaderUniforms.HeightFogStart, heightFogStart); mat.SetFloat(AzureShaderUniforms.HeightFogEnd, heightFogEnd); mat.SetFloat(AzureShaderUniforms.DynamicCloudAltitude, dynamicCloudsAltitude); mat.SetVector(AzureShaderUniforms.DynamicCloudDirection, m_dynamicCloudsDirection); mat.SetFloat(AzureShaderUniforms.DynamicCloudDensity, Mathf.Lerp(25f, 0f, dynamicCloudsDensity)); mat.SetVector(AzureShaderUniforms.DynamicCloudColor1, dynamicCloudsColor1); mat.SetVector(AzureShaderUniforms.DynamicCloudColor2, dynamicCloudsColor2); mat.SetFloat(AzureShaderUniforms.StaticCloudLayer1Speed, m_staticCloudLayer1Speed); mat.SetFloat(AzureShaderUniforms.StaticCloudLayer2Speed, m_staticCloudLayer2Speed); mat.SetFloat(AzureShaderUniforms.StaticCloudScattering, staticCloudScattering); mat.SetFloat(AzureShaderUniforms.StaticCloudExtinction, staticCloudExtinction); mat.SetFloat(AzureShaderUniforms.StaticCloudSaturation, staticCloudSaturation); mat.SetFloat(AzureShaderUniforms.StaticCloudOpacity, staticCloudOpacity); mat.SetVector(AzureShaderUniforms.StaticCloudColor, staticCloudColor); } private void UpdateGlobalShaderUniforms() { Shader.SetGlobalVector(AzureShaderUniforms.SunDirection, base.transform.InverseTransformDirection(-m_sunTransform.forward)); Shader.SetGlobalVector(AzureShaderUniforms.MoonDirection, base.transform.InverseTransformDirection(-m_moonTransform.forward)); Shader.SetGlobalMatrix(AzureShaderUniforms.SunMatrix, m_sunTransform.worldToLocalMatrix); Shader.SetGlobalMatrix(AzureShaderUniforms.MoonMatrix, m_moonTransform.worldToLocalMatrix); Shader.SetGlobalMatrix(AzureShaderUniforms.UpDirectionMatrix, base.transform.worldToLocalMatrix); Shader.SetGlobalInt(AzureShaderUniforms.ScatteringMode, (int)m_scatteringMode); Shader.SetGlobalFloat(AzureShaderUniforms.Kr, kr * 1000f); Shader.SetGlobalFloat(AzureShaderUniforms.Km, km * 1000f); Shader.SetGlobalVector(AzureShaderUniforms.Rayleigh, ComputeRayleigh() * rayleigh); Shader.SetGlobalVector(AzureShaderUniforms.Mie, ComputeMie() * mie); Shader.SetGlobalFloat(AzureShaderUniforms.MieDistance, mieDistance); Shader.SetGlobalFloat(AzureShaderUniforms.Scattering, scattering * 60f); Shader.SetGlobalFloat(AzureShaderUniforms.Luminance, luminance); Shader.SetGlobalFloat(AzureShaderUniforms.Exposure, exposure); Shader.SetGlobalColor(AzureShaderUniforms.RayleighColor, rayleighColor); Shader.SetGlobalColor(AzureShaderUniforms.MieColor, mieColor); Shader.SetGlobalColor(AzureShaderUniforms.ScatteringColor, scatteringColor); Shader.SetGlobalFloat(AzureShaderUniforms.SunTextureSize, sunTextureSize); Shader.SetGlobalFloat(AzureShaderUniforms.SunTextureIntensity, sunTextureIntensity); Shader.SetGlobalColor(AzureShaderUniforms.SunTextureColor, sunTextureColor); Shader.SetGlobalFloat(AzureShaderUniforms.MoonTextureSize, moonTextureSize); Shader.SetGlobalFloat(AzureShaderUniforms.MoonTextureIntensity, moonTextureIntensity); Shader.SetGlobalColor(AzureShaderUniforms.MoonTextureColor, moonTextureColor); Shader.SetGlobalFloat(AzureShaderUniforms.StarsIntensity, starsIntensity); Shader.SetGlobalFloat(AzureShaderUniforms.MilkyWayIntensity, milkyWayIntensity); Shader.SetGlobalColor(AzureShaderUniforms.StarFieldColor, starfieldColor); Shader.SetGlobalMatrix(AzureShaderUniforms.StarFieldRotation, m_starfieldRotationMatrix); Shader.SetGlobalFloat(AzureShaderUniforms.FogScatteringScale, fogScatteringScale); Shader.SetGlobalFloat(AzureShaderUniforms.GlobalFogDistance, globalFogDistance); Shader.SetGlobalFloat(AzureShaderUniforms.GlobalFogSmoothStep, globalFogSmoothStep); Shader.SetGlobalFloat(AzureShaderUniforms.GlobalFogDensity, globalFogDensity); Shader.SetGlobalFloat(AzureShaderUniforms.HeightFogDistance, heightFogDistance); Shader.SetGlobalFloat(AzureShaderUniforms.HeightFogSmoothStep, heightFogSmoothStep); Shader.SetGlobalFloat(AzureShaderUniforms.HeightFogDensity, heightFogDensity); Shader.SetGlobalFloat(AzureShaderUniforms.HeightFogStart, heightFogStart); Shader.SetGlobalFloat(AzureShaderUniforms.HeightFogEnd, heightFogEnd); Shader.SetGlobalFloat(AzureShaderUniforms.DynamicCloudAltitude, dynamicCloudsAltitude); Shader.SetGlobalVector(AzureShaderUniforms.DynamicCloudDirection, m_dynamicCloudsDirection); Shader.SetGlobalFloat(AzureShaderUniforms.DynamicCloudDensity, Mathf.Lerp(25f, 0f, dynamicCloudsDensity)); Shader.SetGlobalVector(AzureShaderUniforms.DynamicCloudColor1, dynamicCloudsColor1); Shader.SetGlobalVector(AzureShaderUniforms.DynamicCloudColor2, dynamicCloudsColor2); Shader.SetGlobalFloat(AzureShaderUniforms.StaticCloudLayer1Speed, m_staticCloudLayer1Speed); Shader.SetGlobalFloat(AzureShaderUniforms.StaticCloudLayer2Speed, m_staticCloudLayer2Speed); Shader.SetGlobalFloat(AzureShaderUniforms.StaticCloudScattering, staticCloudScattering); Shader.SetGlobalFloat(AzureShaderUniforms.StaticCloudExtinction, staticCloudExtinction); Shader.SetGlobalFloat(AzureShaderUniforms.StaticCloudSaturation, staticCloudSaturation); Shader.SetGlobalFloat(AzureShaderUniforms.StaticCloudOpacity, staticCloudOpacity); Shader.SetGlobalVector(AzureShaderUniforms.StaticCloudColor, staticCloudColor); } private Vector3 ComputeRayleigh() { Vector3 one = Vector3.one; Vector3 vector = new Vector3(wavelengthR, wavelengthG, wavelengthB) * 1E-09f; float num = 0.035f; float num2 = 1.0003f * 1.0003f; float num3 = molecularDensity * 1E+25f; float num4 = 248.05023f * ((num2 - 1f) * (num2 - 1f)) / (3f * num3) * ((6f + 3f * num) / (6f - 7f * num)); one.x = num4 / Mathf.Pow(vector.x, 4f); one.y = num4 / Mathf.Pow(vector.y, 4f); one.z = num4 / Mathf.Pow(vector.z, 4f); return one; } private Vector3 ComputeMie() { float num = 2.6209998E-08f; Vector3 vector = new Vector3(686f, 678f, 682f); Vector3 result = default(Vector3); result.x = 434f * num * MathF.PI * Mathf.Pow(MathF.PI * 4f / wavelengthR, 2f) * vector.x; result.y = 434f * num * MathF.PI * Mathf.Pow(MathF.PI * 4f / wavelengthG, 2f) * vector.y; result.z = 434f * num * MathF.PI * Mathf.Pow(MathF.PI * 4f / wavelengthB, 2f) * vector.z; return result; } private Vector2 ComputeCloudPosition() { float x = m_dynamicCloudsDirection.x; float y = m_dynamicCloudsDirection.y; float num = Mathf.Lerp(0f, 360f, dynamicCloudsDirection); float num2 = dynamicCloudsSpeed * 0.05f * Time.deltaTime; x += num2 * Mathf.Sin(0.01745329f * num); y += num2 * Mathf.Cos(0.01745329f * num); if (x >= 1f) { x -= 1f; } if (y >= 1f) { y -= 1f; } return new Vector2(x, y); } public void UpdateSkySettings() { switch (m_cloudMode) { case AzureCloudMode.Off: m_skyMaterial.shader = m_emptySkyShader; break; case AzureCloudMode.Static: m_skyMaterial.shader = m_staticCloudsShader; break; case AzureCloudMode.Dynamic: m_skyMaterial.shader = m_dynamicCloudsShader; break; } } } }