// Crest Ocean System // Copyright 2020 Wave Harmonic Ltd using UnityEngine; using UnityEngine.Rendering; #if UNITY_EDITOR using UnityEditor; #endif namespace Crest { /// /// Provides out-scattering based on the camera's underwater depth. It scales down environmental lighting /// (directional light, reflections, ambient etc) with the underwater depth. This works with vanilla lighting, but /// uncommon or custom lighting will require a custom solution (use this for reference). /// [AddComponentMenu(Internal.Constants.MENU_PREFIX_EXAMPLE + "Underwater Environmental Lighting")] public class UnderwaterEnvironmentalLighting : CustomMonoBehaviour { /// /// The version of this asset. Can be used to migrate across versions. This value should /// only be changed when the editor upgrades the version. /// [SerializeField, HideInInspector] #pragma warning disable 414 int _version = 0; #pragma warning restore 414 [Tooltip("How much this effect applies. Values less than 1 attenuate light less underwater. Value of 1 is physically based."), SerializeField, Range(0f, 3f)] float _weight = 1f; #if CREST_SRP [RenderPipeline(RenderPipeline.HighDefinition), DecoratedField] [Tooltip("This profile will be weighed in the deeper underwater the camera goes."), SerializeField] VolumeProfile _volumeProfile = null; static Volume _volume; #endif Light _primaryLight; float _lightIntensity; float _ambientIntensity; float _reflectionIntensity; float _fogDensity; float _averageDensity = 0f; public const float DEPTH_OUTSCATTER_CONSTANT = 0.25f; bool _isInitialised = false; void OnEnable() { if (OceanRenderer.Instance == null) { enabled = false; return; } // Check to make sure the property exists. We might be using a test material. if (!OceanRenderer.Instance.OceanMaterial.HasProperty("_DepthFogDensity")) { enabled = false; return; } _primaryLight = OceanRenderer.Instance._primaryLight; // Store lighting settings if (_primaryLight) { _lightIntensity = _primaryLight.intensity; } _ambientIntensity = RenderSettings.ambientIntensity; _reflectionIntensity = RenderSettings.reflectionIntensity; _fogDensity = RenderSettings.fogDensity; #if CREST_SRP // Only on HDRP so far... if (_volume == null && RenderPipelineHelper.IsHighDefinition) { // Create volume to weigh in underwater profile var go = new GameObject(); go.transform.parent = OceanRenderer.Instance.Container.transform; go.hideFlags = HideFlags.HideAndDontSave; go.name = "Underwater Lighting Volume"; _volume = go.AddComponent(); _volume.weight = 0; _volume.priority = 1000; _volume.profile = _volumeProfile; } #endif var density = OceanRenderer.Instance.UnderwaterDepthFogDensity; _averageDensity = (density.x + density.y + density.z) / 3f; _isInitialised = true; } void OnDisable() { if (!_isInitialised) { return; } // Restore lighting settings if (_primaryLight) { _primaryLight.intensity = _lightIntensity; } RenderSettings.ambientIntensity = _ambientIntensity; RenderSettings.reflectionIntensity = _reflectionIntensity; RenderSettings.fogDensity = _fogDensity; #if CREST_SRP if (_volume != null) { _volume.weight = 0; } #endif _isInitialised = false; } void LateUpdate() { if (OceanRenderer.Instance == null || UnderwaterRenderer.Instance == null) { return; } var density = OceanRenderer.Instance.UnderwaterDepthFogDensity; _averageDensity = (density.x + density.y + density.z) / 3f; float depthMultiplier = Mathf.Exp(_averageDensity * Mathf.Min(OceanRenderer.Instance.ViewerHeightAboveWater * DEPTH_OUTSCATTER_CONSTANT, 0f) * _weight); // Darken environmental lighting when viewer underwater if (_primaryLight) { _primaryLight.intensity = Mathf.Lerp(0, _lightIntensity, depthMultiplier); } RenderSettings.ambientIntensity = Mathf.Lerp(0, _ambientIntensity, depthMultiplier); RenderSettings.reflectionIntensity = Mathf.Lerp(0, _reflectionIntensity, depthMultiplier); RenderSettings.fogDensity = Mathf.Lerp(0, _fogDensity, depthMultiplier); #if CREST_SRP if (_volume != null) { _volume.weight = 1f - depthMultiplier; } #endif } } #if UNITY_EDITOR [CustomEditor(typeof(UnderwaterEnvironmentalLighting))] public class UnderwaterEnvironmentalLightingEditor : CustomBaseEditor { public override void OnInspectorGUI() { EditorGUILayout.Space(); EditorGUILayout.HelpBox("This is an example component that will likely require modification to work " + "correctly with your project. It implements out-scattering when underwater. It does so, primarily, " + "by changing the intensity of the primary light. The deeper underwater, the less intense the light. " + "There may be unsuitable performance costs or required features to be enabled.", MessageType.Info); EditorGUILayout.Space(); base.OnInspectorGUI(); } } #endif }