using System; using UnityEngine.Serialization; namespace UnityEngine.Rendering.HighDefinition { /// Artist-friendly density volume parametrization. [Serializable] public partial struct DensityVolumeArtistParameters { /// Single scattering albedo: [0, 1]. Alpha is ignored. public Color albedo; /// Mean free path, in meters: [1, inf]. public float meanFreePath; // Should be chromatic - this is an optimization! /// Anisotropy of the phase function: [-1, 1]. Positive values result in forward scattering, and negative values - in backward scattering. [FormerlySerializedAs("asymmetry")] public float anisotropy; // . Not currently available for density volumes /// Texture containing density values. public Texture3D volumeMask; /// Scrolling speed of the density texture. public Vector3 textureScrollingSpeed; /// Tiling rate of the density texture. public Vector3 textureTiling; /// Edge fade factor along the positive X, Y and Z axes. [FormerlySerializedAs("m_PositiveFade")] public Vector3 positiveFade; /// Edge fade factor along the negative X, Y and Z axes. [FormerlySerializedAs("m_NegativeFade")] public Vector3 negativeFade; [SerializeField, FormerlySerializedAs("m_UniformFade")] internal float m_EditorUniformFade; [SerializeField] internal Vector3 m_EditorPositiveFade; [SerializeField] internal Vector3 m_EditorNegativeFade; [SerializeField, FormerlySerializedAs("advancedFade"), FormerlySerializedAs("m_AdvancedFade")] internal bool m_EditorAdvancedFade; /// Dimensions of the volume. public Vector3 size; /// Inverts the fade gradient. public bool invertFade; /// Distance at which density fading starts. public float distanceFadeStart; /// Distance at which density fading ends. public float distanceFadeEnd; [SerializeField] internal int textureIndex; /// Allows translation of the tiling density texture. [SerializeField, FormerlySerializedAs("volumeScrollingAmount")] public Vector3 textureOffset; /// Constructor. /// Single scattering albedo. /// Mean free path. /// Anisotropy. public DensityVolumeArtistParameters(Color color, float _meanFreePath, float _anisotropy) { albedo = color; meanFreePath = _meanFreePath; anisotropy = _anisotropy; volumeMask = null; textureIndex = -1; textureScrollingSpeed = Vector3.zero; textureTiling = Vector3.one; textureOffset = textureScrollingSpeed; size = Vector3.one; positiveFade = Vector3.zero; negativeFade = Vector3.zero; invertFade = false; distanceFadeStart = 10000; distanceFadeEnd = 10000; m_EditorPositiveFade = Vector3.zero; m_EditorNegativeFade = Vector3.zero; m_EditorUniformFade = 0; m_EditorAdvancedFade = false; } internal void Update(float time) { //Update scrolling based on deltaTime if (volumeMask != null) { textureOffset = (textureScrollingSpeed * time); // Switch from right-handed to left-handed coordinate system. textureOffset.x = -textureOffset.x; textureOffset.y = -textureOffset.y; } } internal void Constrain() { albedo.r = Mathf.Clamp01(albedo.r); albedo.g = Mathf.Clamp01(albedo.g); albedo.b = Mathf.Clamp01(albedo.b); albedo.a = 1.0f; meanFreePath = Mathf.Clamp(meanFreePath, 1.0f, float.MaxValue); anisotropy = Mathf.Clamp(anisotropy, -1.0f, 1.0f); textureOffset = Vector3.zero; distanceFadeStart = Mathf.Max(0, distanceFadeStart); distanceFadeEnd = Mathf.Max(distanceFadeStart, distanceFadeEnd); } internal DensityVolumeEngineData ConvertToEngineData() { DensityVolumeEngineData data = new DensityVolumeEngineData(); data.extinction = VolumeRenderingUtils.ExtinctionFromMeanFreePath(meanFreePath); data.scattering = VolumeRenderingUtils.ScatteringFromExtinctionAndAlbedo(data.extinction, (Vector3)(Vector4)albedo); data.textureIndex = textureIndex; data.textureScroll = textureOffset; data.textureTiling = textureTiling; // Clamp to avoid NaNs. Vector3 positiveFade = this.positiveFade; Vector3 negativeFade = this.negativeFade; data.rcpPosFaceFade.x = Mathf.Min(1.0f / positiveFade.x, float.MaxValue); data.rcpPosFaceFade.y = Mathf.Min(1.0f / positiveFade.y, float.MaxValue); data.rcpPosFaceFade.z = Mathf.Min(1.0f / positiveFade.z, float.MaxValue); data.rcpNegFaceFade.y = Mathf.Min(1.0f / negativeFade.y, float.MaxValue); data.rcpNegFaceFade.x = Mathf.Min(1.0f / negativeFade.x, float.MaxValue); data.rcpNegFaceFade.z = Mathf.Min(1.0f / negativeFade.z, float.MaxValue); data.invertFade = invertFade ? 1 : 0; float distFadeLen = Mathf.Max(distanceFadeEnd - distanceFadeStart, 0.00001526f); data.rcpDistFadeLen = 1.0f / distFadeLen; data.endTimesRcpDistFadeLen = distanceFadeEnd * data.rcpDistFadeLen; return data; } } // class DensityVolumeParameters /// Density volume class. [HelpURL(Documentation.baseURL + Documentation.version + Documentation.subURL + "Density-Volume" + Documentation.endURL)] [ExecuteAlways] [AddComponentMenu("Rendering/Density Volume")] public partial class DensityVolume : MonoBehaviour { /// Density volume parameters. public DensityVolumeArtistParameters parameters = new DensityVolumeArtistParameters(Color.white, 10.0f, 0.0f); private Texture3D previousVolumeMask = null; #if UNITY_EDITOR private int volumeMaskHash = 0; #endif /// Action shich should be performed after updating the texture. public Action OnTextureUpdated; /// Gather and Update any parameters that may have changed. internal void PrepareParameters(float time) { //Texture has been updated notify the manager bool updated = previousVolumeMask != parameters.volumeMask; #if UNITY_EDITOR int newMaskHash = parameters.volumeMask ? parameters.volumeMask.imageContentsHash.GetHashCode() : 0; updated |= newMaskHash != volumeMaskHash; #endif if (updated) { NotifyUpdatedTexure(); previousVolumeMask = parameters.volumeMask; #if UNITY_EDITOR volumeMaskHash = newMaskHash; #endif } parameters.Update(time); } private void NotifyUpdatedTexure() { if (OnTextureUpdated != null) { OnTextureUpdated(); } } private void OnEnable() { DensityVolumeManager.manager.RegisterVolume(this); #if UNITY_EDITOR // Handle scene visibility UnityEditor.SceneVisibilityManager.visibilityChanged += UpdateDecalVisibility; #endif } #if UNITY_EDITOR void UpdateDecalVisibility() { if (UnityEditor.SceneVisibilityManager.instance.IsHidden(gameObject)) { if (DensityVolumeManager.manager.ContainsVolume(this)) DensityVolumeManager.manager.DeRegisterVolume(this); } else { if (!DensityVolumeManager.manager.ContainsVolume(this)) DensityVolumeManager.manager.RegisterVolume(this); } } #endif private void OnDisable() { DensityVolumeManager.manager.DeRegisterVolume(this); #if UNITY_EDITOR UnityEditor.SceneVisibilityManager.visibilityChanged -= UpdateDecalVisibility; #endif } private void Update() { } private void OnValidate() { parameters.Constrain(); } } }