using System.Collections.Generic; using System.Reflection; namespace UnityEngine.AzureSky { [ExecuteInEditMode] [AddComponentMenu("Azure[Sky]/Azure Weather Controller")] public class AzureWeatherController : MonoBehaviour { [Tooltip("Drag the 'Azure Time Controller' here if you want the weather profiles to be avaluated using Azure time of day. Otherwise you will need to evaluate the profiles by code calling the 'SetEvaluateTime(float evaluateTime)' on this component.")] [SerializeField] private AzureTimeController m_azureTimeController; [Tooltip("The transition length used to back to the default weather profile.")] [SerializeField] private float m_defaultWeatherTransitionLength = 10f; [Tooltip("List of default weather profiles. The scene will start using the first profile in this list and a random profile will be defined when a new day starts.")] [SerializeField] private List m_defaultWeatherProfilesList = new List(); [Tooltip("List of global weather profiles. Call 'SetNewWeatherProfile(int index)' on this component to change the global weather by scripting.")] [SerializeField] private List m_globalWeatherProfilesList = new List(); [Tooltip("Transform that will drive the local weather zone blending feature. By setting this field to 'null' will disable the local weather zones computation (global one will still work).")] [SerializeField] private Transform m_localWeatherZoneTrigger; [Tooltip("List of local weather zones. Place here all the local weather zones and arrange according to its priorities.")] [SerializeField] private List m_localWeatherZonesList = new List(); [Tooltip("The override object with the custom property settings.")] public AzureOverrideObject overrideObject; [Tooltip("List of properties to override using the weather profiles.")] [SerializeField] private List m_overridePropertyList = new List(); private AzureWeatherProfile m_defaultWeatherProfile; private AzureWeatherProfile m_currentWeatherProfile; private AzureWeatherProfile m_targetWeatherProfile; [SerializeField] private float m_weatherTransitionProgress; private float m_weatherRamp; private float m_weatherTransitionLength = 10f; private float m_weatherTransitionStart; private int m_weatherIndex = -1; private bool m_isWeatherChanging; [SerializeField] private float m_timeOfDay = 6f; [SerializeField] private float m_timeOfDayClamped = 6f; private string m_componentName; private string m_propertyName; private float m_profileMultiplier = 1f; private Vector3 m_localWeatherZoneTriggerPosition = Vector3.zero; private Collider m_localWeatherZoneCollider; private float m_localWeatherZoneClosestDistanceSqr; private Vector3 m_localWeatherZoneClosestPoint; private float m_localWeatherZoneDistance; private float m_localWeatherZoneBlendDistanceSqr; private float m_localWeatherZoneInterpolationFactor; private FieldInfo m_targetField; private PropertyInfo m_targetProperty; private Component m_targetComponent; private Material m_targetMaterial; private int m_targetUniformID = -1; private void Awake() { m_azureTimeController = GetComponent(); RefreshOverrideTargets(); m_defaultWeatherProfile = m_defaultWeatherProfilesList[0]; m_currentWeatherProfile = m_defaultWeatherProfile; m_targetWeatherProfile = m_defaultWeatherProfile; EvaluateWeatherProfiles(); } private void OnEnable() { m_azureTimeController = GetComponent(); } private void Update() { } private void FixedUpdate() { EvaluateWeatherProfiles(); } public void SetRandomDefaultWeather(float transitionLength) { m_defaultWeatherProfile = m_defaultWeatherProfilesList[Random.Range(0, m_defaultWeatherProfilesList.Count)]; if (m_weatherIndex < 0 && !m_isWeatherChanging) { m_targetWeatherProfile = m_defaultWeatherProfile; if (m_targetWeatherProfile != m_currentWeatherProfile) { m_weatherTransitionLength = transitionLength; m_weatherTransitionProgress = 0f; m_weatherTransitionStart = Time.time; m_isWeatherChanging = true; } } } public void SetNewWeatherProfile(int index) { if (index == -1) { if ((bool)m_defaultWeatherProfile) { m_targetWeatherProfile = m_defaultWeatherProfile; m_weatherTransitionLength = m_defaultWeatherTransitionLength; m_weatherIndex = -1; } } else if ((bool)m_globalWeatherProfilesList[index].profile) { m_targetWeatherProfile = m_globalWeatherProfilesList[index].profile; m_weatherTransitionLength = m_globalWeatherProfilesList[index].transitionLength; m_weatherIndex = index; } m_weatherTransitionProgress = 0f; m_weatherTransitionStart = Time.time; m_isWeatherChanging = true; } public void SetNewWeatherProfile(AzureWeatherProfile profile) { m_currentWeatherProfile = profile; } public void SetNewWeatherProfile(AzureWeatherProfile profile, float transitionTime) { m_targetWeatherProfile = profile; m_weatherTransitionLength = transitionTime; m_weatherTransitionProgress = 0f; m_weatherTransitionStart = Time.time; m_isWeatherChanging = true; } public AzureWeatherProfile GetCurrentWeatherProfile() { return m_currentWeatherProfile; } public AzureWeatherProfile GetDefaultWeatherProfile() { return m_defaultWeatherProfile; } public AzureWeatherProfile GetTargetWeatherProfile() { if (m_isWeatherChanging) { return m_targetWeatherProfile; } return null; } public int GetGlobalWeatherIndex() { return m_weatherIndex; } public float GetOverrideFloatOutput(int index, float multiplier = 1f) { return m_overridePropertyList[index].floatOutput * multiplier; } public Color GetOverrideColorOutput(int index, float multiplier = 1f) { return m_overridePropertyList[index].colorOutput * multiplier; } public void EvaluateTimeOfDay(float evaluateTime) { m_timeOfDay = evaluateTime; } private void EvaluateWeatherProfiles() { if (!overrideObject) { return; } if ((bool)m_azureTimeController) { m_timeOfDay = m_azureTimeController.GetEvaluateTime(); if (m_azureTimeController.TimeSystem == AzureTimeSystem.Realistic) { m_timeOfDayClamped = Mathf.InverseLerp(-1f, 1f, m_azureTimeController.GetSunElevation()); m_timeOfDay = Mathf.Lerp(0f, 12f, m_timeOfDayClamped); } } if (!m_isWeatherChanging) { EvaluateCurrentWeatherProfile(); } else { m_weatherTransitionProgress = Mathf.Clamp01((Time.time - m_weatherTransitionStart) / m_weatherTransitionLength); ApplyGlobalWeatherTransition(m_currentWeatherProfile, m_targetWeatherProfile, m_weatherTransitionProgress); if (Mathf.Abs(m_weatherTransitionProgress - 1f) <= 0f) { m_isWeatherChanging = false; m_weatherTransitionProgress = 0f; m_weatherTransitionStart = 0f; m_currentWeatherProfile = m_targetWeatherProfile; } } if (!m_localWeatherZoneTrigger) { return; } m_localWeatherZoneTriggerPosition = m_localWeatherZoneTrigger.position; foreach (AzureWeatherZone localWeatherZones in m_localWeatherZonesList) { if (localWeatherZones == null) { continue; } m_localWeatherZoneCollider = localWeatherZones.GetComponent(); if (!m_localWeatherZoneCollider || !m_localWeatherZoneCollider.enabled || !m_localWeatherZoneCollider.gameObject.activeInHierarchy) { continue; } m_localWeatherZoneClosestDistanceSqr = float.PositiveInfinity; m_localWeatherZoneClosestPoint = m_localWeatherZoneCollider.ClosestPoint(m_localWeatherZoneTriggerPosition); m_localWeatherZoneDistance = ((m_localWeatherZoneClosestPoint - m_localWeatherZoneTriggerPosition) / 2f).sqrMagnitude; if (m_localWeatherZoneDistance < m_localWeatherZoneClosestDistanceSqr) { m_localWeatherZoneClosestDistanceSqr = m_localWeatherZoneDistance; } m_localWeatherZoneCollider = null; m_localWeatherZoneBlendDistanceSqr = localWeatherZones.blendDistance * localWeatherZones.blendDistance; if (!(m_localWeatherZoneClosestDistanceSqr > m_localWeatherZoneBlendDistanceSqr)) { m_localWeatherZoneInterpolationFactor = 1f; if (m_localWeatherZoneBlendDistanceSqr > 0f) { m_localWeatherZoneInterpolationFactor = 1f - m_localWeatherZoneClosestDistanceSqr / m_localWeatherZoneBlendDistanceSqr; } ApplyWeatherZonesInfluence(localWeatherZones.profile, m_localWeatherZoneInterpolationFactor); } } } private void EvaluateCurrentWeatherProfile() { for (int i = 0; i < overrideObject.customPropertyList.Count; i++) { switch (overrideObject.customPropertyList[i].outputType) { case AzureOutputType.Float: { m_overridePropertyList[i].floatOutput = m_currentWeatherProfile.profilePropertyList[i].GetFloatOutput(m_timeOfDay); for (int k = 0; k < m_overridePropertyList[i].overridePropertySetupList.Count; k++) { m_profileMultiplier = m_overridePropertyList[i].overridePropertySetupList[k].multiplier; switch (m_overridePropertyList[i].overridePropertySetupList[k].targetType) { case AzureOverrideType.Field: m_targetField = m_overridePropertyList[i].overridePropertySetupList[k].targetField; m_targetComponent = m_overridePropertyList[i].overridePropertySetupList[k].targetComponent; if (m_targetField != null) { m_targetField.SetValue(m_targetComponent, m_overridePropertyList[i].floatOutput * m_profileMultiplier); } break; case AzureOverrideType.Property: m_targetProperty = m_overridePropertyList[i].overridePropertySetupList[k].targetProperty; m_targetComponent = m_overridePropertyList[i].overridePropertySetupList[k].targetComponent; if (m_targetProperty != null) { m_targetProperty.SetValue(m_targetComponent, m_overridePropertyList[i].floatOutput * m_profileMultiplier); } break; case AzureOverrideType.ShaderProperty: m_targetMaterial = m_overridePropertyList[i].overridePropertySetupList[k].targetMaterial; m_targetUniformID = m_overridePropertyList[i].overridePropertySetupList[k].targetUniformID; if (m_overridePropertyList[i].overridePropertySetupList[k].targetShaderUpdateMode == AzureShaderUpdateMode.Local) { if ((bool)m_targetMaterial) { m_targetMaterial.SetFloat(m_targetUniformID, m_overridePropertyList[i].floatOutput * m_profileMultiplier); } } else { Shader.SetGlobalFloat(m_targetUniformID, m_overridePropertyList[i].floatOutput * m_profileMultiplier); } break; } } break; } case AzureOutputType.Color: { m_overridePropertyList[i].colorOutput = m_currentWeatherProfile.profilePropertyList[i].GetColorOutput(m_timeOfDay); for (int j = 0; j < m_overridePropertyList[i].overridePropertySetupList.Count; j++) { m_profileMultiplier = m_overridePropertyList[i].overridePropertySetupList[j].multiplier; switch (m_overridePropertyList[i].overridePropertySetupList[j].targetType) { case AzureOverrideType.Field: m_targetField = m_overridePropertyList[i].overridePropertySetupList[j].targetField; m_targetComponent = m_overridePropertyList[i].overridePropertySetupList[j].targetComponent; if (m_targetField != null) { m_targetField.SetValue(m_targetComponent, m_overridePropertyList[i].colorOutput * m_profileMultiplier); } break; case AzureOverrideType.Property: m_targetProperty = m_overridePropertyList[i].overridePropertySetupList[j].targetProperty; m_targetComponent = m_overridePropertyList[i].overridePropertySetupList[j].targetComponent; if (m_targetProperty != null) { m_targetProperty.SetValue(m_targetComponent, m_overridePropertyList[i].colorOutput * m_profileMultiplier); } break; case AzureOverrideType.ShaderProperty: m_targetMaterial = m_overridePropertyList[i].overridePropertySetupList[j].targetMaterial; m_targetUniformID = m_overridePropertyList[i].overridePropertySetupList[j].targetUniformID; if (m_overridePropertyList[i].overridePropertySetupList[j].targetShaderUpdateMode == AzureShaderUpdateMode.Local) { if ((bool)m_targetMaterial) { m_targetMaterial.SetColor(m_targetUniformID, m_overridePropertyList[i].colorOutput * m_profileMultiplier); } } else { Shader.SetGlobalColor(m_targetUniformID, m_overridePropertyList[i].colorOutput * m_profileMultiplier); } break; } } break; } } } } private void ApplyGlobalWeatherTransition(AzureWeatherProfile from, AzureWeatherProfile to, float t) { for (int i = 0; i < overrideObject.customPropertyList.Count; i++) { m_weatherRamp = to.profilePropertyList[i].rampCurve.Evaluate(t); switch (overrideObject.customPropertyList[i].outputType) { case AzureOutputType.Float: { m_overridePropertyList[i].floatOutput = FloatInterpolation(from.profilePropertyList[i].GetFloatOutput(m_timeOfDay), to.profilePropertyList[i].GetFloatOutput(m_timeOfDay), m_weatherRamp); for (int k = 0; k < m_overridePropertyList[i].overridePropertySetupList.Count; k++) { m_profileMultiplier = m_overridePropertyList[i].overridePropertySetupList[k].multiplier; switch (m_overridePropertyList[i].overridePropertySetupList[k].targetType) { case AzureOverrideType.Field: m_targetField = m_overridePropertyList[i].overridePropertySetupList[k].targetField; m_targetComponent = m_overridePropertyList[i].overridePropertySetupList[k].targetComponent; if (m_targetField != null) { m_targetField.SetValue(m_targetComponent, m_overridePropertyList[i].floatOutput * m_profileMultiplier); } break; case AzureOverrideType.Property: m_targetProperty = m_overridePropertyList[i].overridePropertySetupList[k].targetProperty; m_targetComponent = m_overridePropertyList[i].overridePropertySetupList[k].targetComponent; if (m_targetProperty != null) { m_targetProperty.SetValue(m_targetComponent, m_overridePropertyList[i].floatOutput * m_profileMultiplier); } break; case AzureOverrideType.ShaderProperty: m_targetMaterial = m_overridePropertyList[i].overridePropertySetupList[k].targetMaterial; m_targetUniformID = m_overridePropertyList[i].overridePropertySetupList[k].targetUniformID; if (m_overridePropertyList[i].overridePropertySetupList[k].targetShaderUpdateMode == AzureShaderUpdateMode.Local) { if ((bool)m_targetMaterial) { m_targetMaterial.SetFloat(m_targetUniformID, m_overridePropertyList[i].floatOutput * m_profileMultiplier); } } else { Shader.SetGlobalFloat(m_targetUniformID, m_overridePropertyList[i].floatOutput * m_profileMultiplier); } break; } } break; } case AzureOutputType.Color: { m_overridePropertyList[i].colorOutput = ColorInterpolation(from.profilePropertyList[i].GetColorOutput(m_timeOfDay), to.profilePropertyList[i].GetColorOutput(m_timeOfDay), m_weatherRamp); for (int j = 0; j < m_overridePropertyList[i].overridePropertySetupList.Count; j++) { m_profileMultiplier = m_overridePropertyList[i].overridePropertySetupList[j].multiplier; switch (m_overridePropertyList[i].overridePropertySetupList[j].targetType) { case AzureOverrideType.Field: m_targetField = m_overridePropertyList[i].overridePropertySetupList[j].targetField; m_targetComponent = m_overridePropertyList[i].overridePropertySetupList[j].targetComponent; if (m_targetField != null) { m_targetField.SetValue(m_targetComponent, m_overridePropertyList[i].colorOutput * m_profileMultiplier); } break; case AzureOverrideType.Property: m_targetProperty = m_overridePropertyList[i].overridePropertySetupList[j].targetProperty; m_targetComponent = m_overridePropertyList[i].overridePropertySetupList[j].targetComponent; if (m_targetProperty != null) { m_targetProperty.SetValue(m_targetComponent, m_overridePropertyList[i].colorOutput * m_profileMultiplier); } break; case AzureOverrideType.ShaderProperty: m_targetMaterial = m_overridePropertyList[i].overridePropertySetupList[j].targetMaterial; m_targetUniformID = m_overridePropertyList[i].overridePropertySetupList[j].targetUniformID; if (m_overridePropertyList[i].overridePropertySetupList[j].targetShaderUpdateMode == AzureShaderUpdateMode.Local) { if ((bool)m_targetMaterial) { m_targetMaterial.SetColor(m_targetUniformID, m_overridePropertyList[i].colorOutput * m_profileMultiplier); } } else { Shader.SetGlobalColor(m_targetUniformID, m_overridePropertyList[i].colorOutput * m_profileMultiplier); } break; } } break; } } } } private void ApplyWeatherZonesInfluence(AzureWeatherProfile localZoneProfile, float t) { for (int i = 0; i < overrideObject.customPropertyList.Count; i++) { m_weatherRamp = localZoneProfile.profilePropertyList[i].rampCurve.Evaluate(t); switch (overrideObject.customPropertyList[i].outputType) { case AzureOutputType.Float: { m_overridePropertyList[i].floatOutput = FloatInterpolation(m_overridePropertyList[i].floatOutput, localZoneProfile.profilePropertyList[i].GetFloatOutput(m_timeOfDay), m_weatherRamp); for (int k = 0; k < m_overridePropertyList[i].overridePropertySetupList.Count; k++) { m_profileMultiplier = m_overridePropertyList[i].overridePropertySetupList[k].multiplier; switch (m_overridePropertyList[i].overridePropertySetupList[k].targetType) { case AzureOverrideType.Field: m_targetField = m_overridePropertyList[i].overridePropertySetupList[k].targetField; m_targetComponent = m_overridePropertyList[i].overridePropertySetupList[k].targetComponent; if (m_targetField != null) { m_targetField.SetValue(m_targetComponent, m_overridePropertyList[i].floatOutput * m_profileMultiplier); } break; case AzureOverrideType.Property: m_targetProperty = m_overridePropertyList[i].overridePropertySetupList[k].targetProperty; m_targetComponent = m_overridePropertyList[i].overridePropertySetupList[k].targetComponent; if (m_targetProperty != null) { m_targetProperty.SetValue(m_targetComponent, m_overridePropertyList[i].floatOutput * m_profileMultiplier); } break; case AzureOverrideType.ShaderProperty: m_targetMaterial = m_overridePropertyList[i].overridePropertySetupList[k].targetMaterial; m_targetUniformID = m_overridePropertyList[i].overridePropertySetupList[k].targetUniformID; if (m_overridePropertyList[i].overridePropertySetupList[k].targetShaderUpdateMode == AzureShaderUpdateMode.Local) { if ((bool)m_targetMaterial) { m_targetMaterial.SetFloat(m_targetUniformID, m_overridePropertyList[i].floatOutput * m_profileMultiplier); } } else { Shader.SetGlobalFloat(m_targetUniformID, m_overridePropertyList[i].floatOutput * m_profileMultiplier); } break; } } break; } case AzureOutputType.Color: { m_overridePropertyList[i].colorOutput = ColorInterpolation(m_overridePropertyList[i].colorOutput, localZoneProfile.profilePropertyList[i].GetColorOutput(m_timeOfDay), m_weatherRamp); for (int j = 0; j < m_overridePropertyList[i].overridePropertySetupList.Count; j++) { m_profileMultiplier = m_overridePropertyList[i].overridePropertySetupList[j].multiplier; switch (m_overridePropertyList[i].overridePropertySetupList[j].targetType) { case AzureOverrideType.Field: m_targetField = m_overridePropertyList[i].overridePropertySetupList[j].targetField; m_targetComponent = m_overridePropertyList[i].overridePropertySetupList[j].targetComponent; if (m_targetField != null) { m_targetField.SetValue(m_targetComponent, m_overridePropertyList[i].colorOutput * m_profileMultiplier); } break; case AzureOverrideType.Property: m_targetProperty = m_overridePropertyList[i].overridePropertySetupList[j].targetProperty; m_targetComponent = m_overridePropertyList[i].overridePropertySetupList[j].targetComponent; if (m_targetProperty != null) { m_targetProperty.SetValue(m_targetComponent, m_overridePropertyList[i].colorOutput * m_profileMultiplier); } break; case AzureOverrideType.ShaderProperty: m_targetMaterial = m_overridePropertyList[i].overridePropertySetupList[j].targetMaterial; m_targetUniformID = m_overridePropertyList[i].overridePropertySetupList[j].targetUniformID; if (m_overridePropertyList[i].overridePropertySetupList[j].targetShaderUpdateMode == AzureShaderUpdateMode.Local) { if ((bool)m_targetMaterial) { m_targetMaterial.SetColor(m_targetUniformID, m_overridePropertyList[i].colorOutput * m_profileMultiplier); } } else { Shader.SetGlobalColor(m_targetUniformID, m_overridePropertyList[i].colorOutput * m_profileMultiplier); } break; } } break; } } } } public void RefreshOverrideTargets() { if (!overrideObject) { return; } if (overrideObject.customPropertyList.Count != m_overridePropertyList.Count) { UpdateOverridePropertyListSize(); } for (int i = 0; i < overrideObject.customPropertyList.Count; i++) { for (int j = 0; j < m_overridePropertyList[i].overridePropertySetupList.Count; j++) { if ((bool)m_overridePropertyList[i].overridePropertySetupList[j].targetGameObject) { m_componentName = m_overridePropertyList[i].overridePropertySetupList[j].targetComponentName; m_overridePropertyList[i].overridePropertySetupList[j].targetComponent = m_overridePropertyList[i].overridePropertySetupList[j].targetGameObject.GetComponent(m_componentName); if ((bool)m_overridePropertyList[i].overridePropertySetupList[j].targetComponent) { m_propertyName = m_overridePropertyList[i].overridePropertySetupList[j].targetPropertyName; m_overridePropertyList[i].overridePropertySetupList[j].targetField = m_overridePropertyList[i].overridePropertySetupList[j].targetComponent.GetType().GetField(m_propertyName); m_overridePropertyList[i].overridePropertySetupList[j].targetProperty = m_overridePropertyList[i].overridePropertySetupList[j].targetComponent.GetType().GetProperty(m_propertyName); } } } } } private void UpdateOverridePropertyListSize() { while (m_overridePropertyList.Count > overrideObject.customPropertyList.Count) { m_overridePropertyList.RemoveAt(m_overridePropertyList.Count - 1); } while (m_overridePropertyList.Count < overrideObject.customPropertyList.Count) { m_overridePropertyList.Add(new AzureOverrideProperty()); } } public float GetWeatherTransitionProgress() { return m_weatherTransitionProgress; } private float FloatInterpolation(float from, float to, float t) { return from + (to - from) * t; } private Color ColorInterpolation(Color from, Color to, float t) { Color result = default(Color); result.r = from.r + (to.r - from.r) * t; result.g = from.g + (to.g - from.g) * t; result.b = from.b + (to.b - from.b) * t; result.a = from.a + (to.a - from.a) * t; return result; } } }