858 lines
36 KiB
C#
858 lines
36 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using UnityEditor;
|
|
using Unity.Mathematics;
|
|
using UnityEngine.Serialization;
|
|
|
|
#if UNITY_EDITOR
|
|
using UnityEditor.SceneManagement;
|
|
#endif
|
|
|
|
using static Unity.Mathematics.math;
|
|
|
|
namespace UnityEngine.Rendering.HighDefinition
|
|
{
|
|
/// <summary>
|
|
/// Enum that defines the type of a given water surface.
|
|
/// </summary>
|
|
public enum WaterSurfaceType
|
|
{
|
|
/// <summary>
|
|
/// The water surface is either a Ocean, Sea, Lake or a large water body.
|
|
/// </summary>
|
|
[InspectorName("Ocean, Sea or Lake")]
|
|
OceanSeaLake,
|
|
|
|
/// <summary>
|
|
/// The water surface is a river a stream.
|
|
/// </summary>
|
|
River,
|
|
|
|
/// <summary>
|
|
/// The water surface is a pool or a small water body.
|
|
/// </summary>
|
|
Pool,
|
|
}
|
|
|
|
/// <summary>
|
|
/// Controls the type of geometry used to render the water surface.
|
|
/// </summary>
|
|
public enum WaterGeometryType
|
|
{
|
|
/// <summary>
|
|
/// The water surface will be rendered as a procedural quad.
|
|
/// </summary>
|
|
Quad,
|
|
|
|
/// <summary>
|
|
/// The water will be rendered with one or multiple Mesh Renderers provided by the user.
|
|
/// </summary>
|
|
Custom,
|
|
|
|
/// <summary>
|
|
/// The water surface will be rendered as a set of quads that cover the area defined by the water surface.
|
|
/// </summary>
|
|
InstancedQuads,
|
|
|
|
/// <summary>
|
|
/// The water surface will be rendered as a infinite plane.
|
|
/// </summary>
|
|
Infinite
|
|
}
|
|
|
|
/// <summary>
|
|
/// Controls how a property is defined for a water surface.
|
|
/// </summary>
|
|
public enum WaterPropertyOverrideMode
|
|
{
|
|
/// <summary>
|
|
/// The property in inherited from an other similar property.
|
|
/// </summary>
|
|
Inherit,
|
|
|
|
/// <summary>
|
|
/// The property needs to be specified individually.
|
|
/// </summary>
|
|
Custom,
|
|
}
|
|
|
|
/// <summary>
|
|
/// Water surface component.
|
|
/// </summary>
|
|
[HDRPHelpURL("WaterSystem")]
|
|
[DisallowMultipleComponent]
|
|
[ExecuteInEditMode]
|
|
public partial class WaterSurface : MonoBehaviour
|
|
{
|
|
#region Instance Management
|
|
// Management to avoid memory allocations at fetch time
|
|
internal static HashSet<WaterSurface> instances = new HashSet<WaterSurface>();
|
|
internal static WaterSurface[] instancesAsArray = null;
|
|
internal static int instanceCount = 0;
|
|
|
|
internal static void RegisterInstance(WaterSurface surface)
|
|
{
|
|
instances.Add(surface);
|
|
instanceCount = instances.Count;
|
|
if (instanceCount > 0)
|
|
{
|
|
instancesAsArray = new WaterSurface[instanceCount];
|
|
instances.CopyTo(instancesAsArray);
|
|
}
|
|
else
|
|
{
|
|
instancesAsArray = null;
|
|
}
|
|
}
|
|
|
|
internal static void UnregisterInstance(WaterSurface surface)
|
|
{
|
|
instances.Remove(surface);
|
|
instanceCount = instances.Count;
|
|
if (instanceCount > 0)
|
|
{
|
|
instancesAsArray = new WaterSurface[instanceCount];
|
|
instances.CopyTo(instancesAsArray);
|
|
}
|
|
else
|
|
{
|
|
instancesAsArray = null;
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Water General
|
|
/// <summary>
|
|
/// Specifies the nature of the water body that the water system needs to simulate.
|
|
/// </summary>
|
|
public WaterSurfaceType surfaceType = WaterSurfaceType.OceanSeaLake;
|
|
|
|
/// <summary>
|
|
/// Specifies the type of geometry used to render the water surface.
|
|
/// </summary>
|
|
public WaterGeometryType geometryType = WaterGeometryType.Infinite;
|
|
|
|
/// <summary>
|
|
/// Sets the geometry to use when rendering in quad and custom geometry type mode. The vertical position of the vertices will be overridden to keep the surface of water leveled.
|
|
/// </summary>
|
|
public List<MeshRenderer> meshRenderers = new List<MeshRenderer>();
|
|
|
|
/// <summary>
|
|
/// Sets the speed of the water simulation. This allows to slow down the waves' speed or to accelerate it.
|
|
/// </summary>
|
|
[Range(0, 10)]
|
|
public float timeMultiplier = 1.0f;
|
|
#endregion
|
|
|
|
#region Water CPU Simulation
|
|
/// <summary>
|
|
/// When enabled, the Water System allows you to make height requests from a C# script.
|
|
/// </summary>
|
|
[Tooltip("When enabled, the Water System allows you to make height requests from a C# script."), FormerlySerializedAs("cpuSimulation")]
|
|
public bool scriptInteractions = false;
|
|
|
|
/// <summary>
|
|
/// Specifies if the CPU simulation should evaluate the ripples as part of the simulation. Including ripples will allow a higher visual fidelity but the cost of the simulation will increase.
|
|
/// </summary>
|
|
public bool cpuEvaluateRipples = false;
|
|
#endregion
|
|
|
|
#region Water Material
|
|
/// <summary>
|
|
/// Sets a custom material that will be used to render the water surface. If set to None a default material is used.
|
|
/// </summary>
|
|
public Material customMaterial = null;
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
public float startSmoothness = 0.95f;
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
public float endSmoothness = 0.85f;
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
public float smoothnessFadeStart = 100.0f;
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
public float smoothnessFadeDistance = 500.0f;
|
|
|
|
/// <summary>
|
|
/// Use hardware tessellation when rendering the water surface
|
|
/// </summary>
|
|
[Tooltip("When enabled, HDRP activates tessellation for this Water Surface.\nThis improves the visual quality but may have a significant performance cost depending on the platform.")]
|
|
public bool tessellation = true;
|
|
|
|
/// <summary>
|
|
/// Sets the maximum tessellation factor for the water surface.
|
|
/// </summary>
|
|
[Range(0.0f, 10.0f), Tooltip("Sets the maximum tessellation factor for the water surface.")]
|
|
public float maxTessellationFactor = 3.0f;
|
|
|
|
/// <summary>
|
|
/// Sets the distance at which the tessellation factor start to lower.
|
|
/// </summary>
|
|
[Min(0.0f), Tooltip(" Sets the distance at which the tessellation factor start to lower.")]
|
|
public float tessellationFactorFadeStart = 150.0f;
|
|
|
|
/// <summary>
|
|
/// Sets the range at which the tessellation factor reaches zero.
|
|
/// </summary>
|
|
[Min(0.0f), Tooltip("Sets the range at which the tessellation factor reaches zero.")]
|
|
public float tessellationFactorFadeRange = 1850.0f;
|
|
|
|
#if UNITY_EDITOR
|
|
static internal bool IsWaterMaterial(Material material)
|
|
{
|
|
return material.shader.FindSubshaderTagValue(0, (ShaderTagId)"ShaderGraphTargetId").name == "WaterSubTarget";
|
|
}
|
|
#endif
|
|
#endregion
|
|
|
|
#region Water Refraction
|
|
/// <summary>
|
|
/// Sets the color that is used to simulate the under-water refraction.
|
|
/// </summary>
|
|
[Tooltip("Sets the color that is used to simulate the under-water refraction.")]
|
|
[ColorUsage(false)]
|
|
public Color refractionColor = new Color(0.00f, 0.45f, 0.65f);
|
|
|
|
/// <summary>
|
|
/// Controls the maximum distance in meters used to clamp the underwater refraction depth. Higher value increases the distortion amount.
|
|
/// </summary>
|
|
[Range(0.0f, 3.5f), Tooltip("Controls the maximum distance in meters used to clamp the underwater refraction depth. Higher value increases the distortion amount.")]
|
|
public float maxRefractionDistance = 1.0f;
|
|
|
|
/// <summary>
|
|
/// Controls the approximative distance in meters that the camera can perceive through a water surface. This distance can vary widely depending on the intensity of the light the object receives.
|
|
/// </summary>
|
|
[Range(0.001f, 100.0f), Tooltip("Controls the approximative distance in meters that the camera can perceive through a water surface. This distance can vary widely depending on the intensity of the light the object receives.")]
|
|
public float absorptionDistance = 5.0f;
|
|
|
|
internal Vector3 extinction => (-Mathf.Log(0.02f) / absorptionDistance) * new Vector3(Mathf.Max(1.0f - refractionColor.r, 0.01f), Mathf.Max(1.0f - refractionColor.g, 0.01f), Mathf.Max(1.0f - refractionColor.b, 0.01f));
|
|
internal Vector3 underWaterExtinction => extinction / absorptionDistanceMultiplier;
|
|
#endregion
|
|
|
|
#region Water Scattering
|
|
/// <summary>
|
|
/// Sets the color that is used to simulate the water light scattering.
|
|
/// </summary>
|
|
[Tooltip("Sets the color that is used to simulate the water light scattering.")]
|
|
[ColorUsage(false)]
|
|
public Color scatteringColor = new Color(0.0f, 0.27f, 0.23f);
|
|
|
|
/// <summary>
|
|
/// Controls the intensity of the ambient scattering term. This can be adjusted for artistic purposes.
|
|
/// </summary>
|
|
[Range(0.0f, 1.0f), Tooltip("Controls the intensity of the height based scattering. The higher the vertical displacement, the more the water receives scattering. This can be adjusted for artistic purposes.")]
|
|
public float ambientScattering = 0.1f;
|
|
|
|
/// <summary>
|
|
/// Controls the intensity of the height based scattering. The higher the vertical displacement, the more the water receives scattering. This can be adjusted for artistic purposes.
|
|
/// </summary>
|
|
[Range(0.0f, 1.0f), Tooltip("Controls the intensity of the height based scattering. The higher the vertical displacement, the more the water receives scattering. This can be adjusted for artistic purposes.")]
|
|
public float heightScattering = 0.1f;
|
|
|
|
/// <summary>
|
|
/// Controls the intensity of the displacement based scattering. The bigger horizontal displacement, the more the water receives scattering. This can be adjusted for artistic purposes.
|
|
/// </summary>
|
|
[Range(0.0f, 1.0f), Tooltip("Controls the intensity of the displacement based scattering. The bigger horizontal displacement, the more the water receives scattering. This can be adjusted for artistic purposes.")]
|
|
public float displacementScattering = 0.3f;
|
|
|
|
/// <summary>
|
|
/// Controls the intensity of the direct light scattering on the tip of the waves. The effect is more perceivable at grazing angles.
|
|
/// </summary>
|
|
[Range(0.0f, 1.0f), Tooltip("Controls the intensity of the direct light scattering on the tip of the waves. The effect is more perceivable at grazing angles.")]
|
|
public float directLightTipScattering = 0.6f;
|
|
|
|
/// <summary>
|
|
/// Controls the intensity of the direct light scattering on the body of the waves. The effect is more perceivable at grazing angles.
|
|
/// </summary>
|
|
[Range(0.0f, 1.0f), Tooltip("Controls the intensity of the direct light scattering on the body of the waves. The effect is more perceivable at grazing angles.")]
|
|
public float directLightBodyScattering = 0.4f;
|
|
|
|
/// <summary>
|
|
/// Specifies a maximum wave height that overrides the simulation to support scattering properly for deformers.
|
|
/// </summary>
|
|
[Min(0.0f), Tooltip("Specifies a maximum wave height that overrides the simulation to support scattering properly for deformers.")]
|
|
public float maximumHeightOverride = 0.0f;
|
|
#endregion
|
|
|
|
#region Water Caustics General
|
|
/// <summary>
|
|
/// When enabled, the water surface will render caustics.
|
|
/// </summary>
|
|
[Tooltip("When enabled, the water surface will render caustics.")]
|
|
public bool caustics = true;
|
|
|
|
/// <summary>
|
|
/// Sets the intensity of the under-water caustics.
|
|
/// </summary>
|
|
[Min(0.0f)]
|
|
[Tooltip("Sets the intensity of the under-water caustics.")]
|
|
public float causticsIntensity = 0.5f;
|
|
|
|
/// <summary>
|
|
/// Sets the vertical blending distance for the water caustics.
|
|
/// </summary>
|
|
[Min(0.0f)]
|
|
[Tooltip("Sets the vertical blending distance for the water caustics.")]
|
|
public float causticsPlaneBlendDistance = 1.0f;
|
|
|
|
/// <summary>
|
|
/// Defines the resolution a which caustics are rendered (simulation only).
|
|
/// </summary>
|
|
public enum WaterCausticsResolution
|
|
{
|
|
/// <summary>
|
|
/// The water caustics are rendered at 256x256
|
|
/// </summary>
|
|
[InspectorName("Low 256")]
|
|
Caustics256 = 256,
|
|
/// <summary>
|
|
/// The water caustics are rendered at 512x512
|
|
/// </summary>
|
|
[InspectorName("Medium 512")]
|
|
Caustics512 = 512,
|
|
/// <summary>
|
|
/// The water caustics are rendered at 1024x1024
|
|
/// </summary>
|
|
[InspectorName("High 1024")]
|
|
Caustics1024 = 1024,
|
|
}
|
|
|
|
/// <summary>
|
|
/// Specifies the resolution at which the water caustics are rendered (simulation only).
|
|
/// </summary>
|
|
[Tooltip("Specifies the resolution at which the water caustics are rendered (simulation only).")]
|
|
public WaterCausticsResolution causticsResolution = WaterCausticsResolution.Caustics256;
|
|
|
|
/// <summary>
|
|
/// Controls which band is used for the caustics evaluation.
|
|
/// </summary>
|
|
[Tooltip("Controls which band is used for the caustics evaluation.")]
|
|
public int causticsBand = 1;
|
|
|
|
/// <summary>
|
|
/// Sets the distance at which the simulated caustics are projected. High values generate sharper caustics but can cause artifacts.
|
|
/// </summary>
|
|
[Min(0.001f)]
|
|
public float virtualPlaneDistance = 5.0f;
|
|
|
|
/// <summary>
|
|
/// Sets a tiling factor for the water caustics.
|
|
/// </summary>
|
|
[Min(0.001f)]
|
|
public float causticsTilingFactor = 1.0f;
|
|
|
|
/// <summary>
|
|
/// When enabled, the water caustics will take into account the directional light's shadow.
|
|
/// </summary>
|
|
public bool causticsDirectionalShadow = false;
|
|
|
|
/// <summary>
|
|
/// Sets the water caustics dimmer value for the directional shadow.
|
|
/// </summary>
|
|
[Range(0.0f, 1.0f)]
|
|
public float causticsDirectionalShadowDimmer = 0.25f;
|
|
#endregion
|
|
|
|
#region Water Miscellaneous
|
|
/// <summary>
|
|
/// Specifies the rendering layers that affect the water surface.
|
|
/// </summary>
|
|
[Tooltip("Specifies the rendering layers that affect the water surface.")]
|
|
public RenderingLayerMask renderingLayerMask = (RenderingLayerMask) (uint) UnityEngine.RenderingLayerMask.defaultRenderingLayerMask;
|
|
|
|
/// <summary>
|
|
/// Sets the debug mode for a given water surface.
|
|
/// </summary>
|
|
public WaterDebugMode debugMode = WaterDebugMode.None;
|
|
|
|
/// <summary>
|
|
/// Sets the water mask debug mode for a given water surface.
|
|
/// </summary>
|
|
public WaterMaskDebugMode waterMaskDebugMode = WaterMaskDebugMode.RedChannel;
|
|
|
|
/// <summary>
|
|
/// Sets the water current debug mode for a given water surface.
|
|
/// </summary>
|
|
public WaterCurrentDebugMode waterCurrentDebugMode = WaterCurrentDebugMode.Large;
|
|
|
|
/// <summary>
|
|
/// Sets a multiplier for the arrow density in the current debug mode.
|
|
/// </summary>
|
|
public float currentDebugMultiplier = 1.0f;
|
|
|
|
/// <summary>
|
|
/// Sets the water foam debug mode for a given water surface.
|
|
/// </summary>
|
|
public WaterFoamDebugMode waterFoamDebugMode = WaterFoamDebugMode.SurfaceFoam;
|
|
#endregion
|
|
|
|
#region Water Underwater
|
|
/// <summary>
|
|
/// When enabled, HDRP will apply a fog and color shift to the final image when the camera is under the surface. This feature has a cost even when the camera is above the water surface.
|
|
/// </summary>
|
|
public bool underWater = false;
|
|
|
|
/// <summary>
|
|
/// Sets a box collider that will be used to define the volume where the underwater effect is applied for non infinite surfaces.
|
|
/// </summary>
|
|
[Tooltip("Sets a box collider that will be used to define the volume where the underwater effect is applied for non infinite surfaces.")]
|
|
public BoxCollider volumeBounds = null;
|
|
|
|
/// <summary>
|
|
/// Sets maximum depth at which the underwater effect is evaluated for infinite surfaces.
|
|
/// </summary>
|
|
[Min(0.0f), Tooltip("Sets maximum depth at which the underwater effect is evaluated for infinite surfaces.")]
|
|
public float volumeDepth = 50.0f;
|
|
|
|
/// <summary>
|
|
/// Sets the maximum height at which the underwater effect is evaluated for infinite surfaces. This allows to cover the underwater scenario when deformers are higher than waves or ripples.
|
|
/// </summary>
|
|
[Min(0.0f), Tooltip("Sets the maximum height at which the underwater effect is evaluated for infinite surfaces. This allows to cover the underwater scenario when deformers are higher than waves or ripples.")]
|
|
public float volumeHeight = 0.0f;
|
|
|
|
/// <summary>
|
|
/// Sets a priority value that is used to define which surface should be considered for underwater rendering in the case of multiple overlapping surfaces.
|
|
/// </summary>
|
|
[Min(0), Tooltip("Sets a priority value that is used to define which surface should be considered for underwater rendering in the case of multiple overlapping surfaces.")]
|
|
public int volumePrority = 0;
|
|
|
|
/// <summary>
|
|
/// Sets the multiplier for the Absorption Distance when the camera is underwater. A value of 2.0 means you will see twice as far underwater.
|
|
/// </summary>
|
|
[Min(0.001f), Tooltip("Sets the multiplier for the Absorption Distance when the camera is underwater. A value of 2.0 means you will see twice as far underwater.")]
|
|
public float absorptionDistanceMultiplier = 1.0f;
|
|
|
|
/// <summary>
|
|
/// Sets the contribution of the ambient probe luminance when multiplied by the underwater scattering color.
|
|
/// </summary>
|
|
[Obsolete("Will be removed in the next version.")]
|
|
public float underWaterAmbientProbeContribution = 1.0f;
|
|
|
|
/// <summary>
|
|
/// Controls how the scattering color is evaluated for the underwater scenario.
|
|
/// </summary>
|
|
[Obsolete("Will be removed in the next version.")]
|
|
public enum UnderWaterScatteringColorMode
|
|
{
|
|
/// <summary>
|
|
/// The scattering color is used as the underwater scattering color.
|
|
/// </summary>
|
|
ScatteringColor,
|
|
|
|
/// <summary>
|
|
/// The property needs to be specified manually.
|
|
/// </summary>
|
|
Custom,
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets how the underwater scattering color is specified.
|
|
/// </summary>
|
|
[Obsolete("Will be removed in the next version.")]
|
|
public UnderWaterScatteringColorMode underWaterScatteringColorMode = UnderWaterScatteringColorMode.ScatteringColor;
|
|
|
|
/// <summary>
|
|
/// Sets the color that is used to simulate the scattering when the camera is under-water.
|
|
/// </summary>
|
|
[ColorUsage(false)]
|
|
[Obsolete("Will be removed in the next version.")]
|
|
public Color underWaterScatteringColor = new Color(0.0f, 0.27f, 0.23f);
|
|
|
|
/// <summary>
|
|
/// Determines if water surface should refract light when looking at objects from underwater.
|
|
/// This simulates the correct behavior of water but may introduce visual artifacts as it relies on screen space refraction.
|
|
/// </summary>
|
|
public bool underWaterRefraction = false;
|
|
#endregion
|
|
|
|
#region Constant Buffers
|
|
internal MaterialPropertyBlock mpb;
|
|
internal int surfaceIndex;
|
|
|
|
internal void CreatePropertyBlock()
|
|
{
|
|
// Prepare the material property block for the rendering
|
|
mpb = new MaterialPropertyBlock();
|
|
mpb.SetTexture(HDShaderIDs._WaterDisplacementBuffer, simulation.gpuBuffers.displacementBuffer);
|
|
mpb.SetTexture(HDShaderIDs._WaterAdditionalDataBuffer, simulation.gpuBuffers.additionalDataBuffer);
|
|
}
|
|
|
|
internal void FillMaterialPropertyBlock(WaterSystem system, bool supportDecals)
|
|
{
|
|
var constantBuffer = HDRenderPipeline.currentPipeline.waterSystem.m_ShaderVariablesWaterPerSurface[surfaceIndex];
|
|
mpb.SetConstantBuffer(HDShaderIDs._ShaderVariablesWaterPerSurface, constantBuffer, 0, constantBuffer.stride);
|
|
|
|
// Textures
|
|
mpb.SetTexture(HDShaderIDs._SimulationFoamMask, GetSimulationFoamMaskBuffer(system, supportDecals, Texture2D.whiteTexture));
|
|
mpb.SetTexture(HDShaderIDs._WaterMask, GetSimulationMaskBuffer(system, supportDecals, Texture2D.whiteTexture));
|
|
mpb.SetTexture(HDShaderIDs._Group0CurrentMap, GetLargeCurrentBuffer(system, supportDecals, Texture2D.blackTexture));
|
|
mpb.SetTexture(HDShaderIDs._Group1CurrentMap, GetRipplesCurrentBuffer(system, supportDecals, Texture2D.blackTexture));
|
|
mpb.SetTexture(HDShaderIDs._WaterDeformationBuffer, GetDeformationBuffer(system, supportDecals, Texture2D.blackTexture));
|
|
mpb.SetTexture(HDShaderIDs._WaterDeformationSGBuffer, GetDeformationNormalBuffer(system, supportDecals, Texture2D.blackTexture));
|
|
mpb.SetTexture(HDShaderIDs._WaterFoamBuffer, GetFoamBuffer(system, supportDecals,Texture2D.blackTexture));
|
|
|
|
Texture causticsData = caustics ? simulation.gpuBuffers.causticsBuffer : Texture2D.blackTexture;
|
|
mpb.SetTexture(HDShaderIDs._WaterCausticsDataBuffer, causticsData);
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Function that globally binds the textures and constant buffer for use by external systems such as VFX Graph
|
|
/// As the binding is done globally, only one surface can be bound during a frame
|
|
/// </summary>
|
|
public void SetGlobalTextures()
|
|
{
|
|
if (simulation == null)
|
|
return;
|
|
|
|
var constantBuffer = HDRenderPipeline.currentPipeline.waterSystem.m_ShaderVariablesWaterPerSurface[surfaceIndex];
|
|
Shader.SetGlobalTexture(HDShaderIDs._WaterDisplacementBuffer, simulation.gpuBuffers.displacementBuffer);
|
|
Shader.SetGlobalTexture(HDShaderIDs._WaterAdditionalDataBuffer, simulation.gpuBuffers.additionalDataBuffer);
|
|
Shader.SetGlobalConstantBuffer(HDShaderIDs._ShaderVariablesWaterPerSurface, constantBuffer, 0, constantBuffer.stride);
|
|
|
|
var system = HDRenderPipeline.currentPipeline.waterSystem;
|
|
Shader.SetGlobalTexture(HDShaderIDs._SimulationFoamMask, GetSimulationFoamMaskBuffer(system, true, Texture2D.whiteTexture));
|
|
Shader.SetGlobalTexture(HDShaderIDs._WaterMask, GetSimulationMaskBuffer(system, true, Texture2D.whiteTexture));
|
|
Shader.SetGlobalTexture(HDShaderIDs._Group0CurrentMap, GetLargeCurrentBuffer(system, true, Texture2D.blackTexture));
|
|
Shader.SetGlobalTexture(HDShaderIDs._Group1CurrentMap, GetRipplesCurrentBuffer(system, true, Texture2D.blackTexture));
|
|
Shader.SetGlobalTexture(HDShaderIDs._WaterDeformationBuffer, GetDeformationBuffer(system, true, Texture2D.blackTexture));
|
|
Shader.SetGlobalTexture(HDShaderIDs._WaterDeformationSGBuffer, GetDeformationNormalBuffer(system, true, Texture2D.blackTexture));
|
|
Shader.SetGlobalTexture(HDShaderIDs._WaterFoamBuffer, GetFoamBuffer(system, true, Texture2D.blackTexture));
|
|
}
|
|
#endregion
|
|
|
|
#region Water Decals
|
|
/// <summary>
|
|
/// Defines the resolution of the internal decal region textures.
|
|
/// </summary>
|
|
public enum WaterDecalRegionResolution
|
|
{
|
|
/// <summary>
|
|
/// The water decals are rendered in a 256x256 texture.
|
|
/// </summary>
|
|
[InspectorName("Low 256")]
|
|
Resolution256 = 256,
|
|
/// <summary>
|
|
/// The water decals are rendered in a 512x512 texture.
|
|
/// </summary>
|
|
[InspectorName("Medium 512")]
|
|
Resolution512 = 512,
|
|
/// <summary>
|
|
/// The water decals are rendered in a 1024x1024 texture.
|
|
/// </summary>
|
|
[InspectorName("High 1024")]
|
|
Resolution1024 = 1024,
|
|
/// <summary>
|
|
/// The water decals are rendered in a 2048x2048 texture.
|
|
/// </summary>
|
|
[InspectorName("Very High 2048")]
|
|
Resolution2048 = 2048,
|
|
}
|
|
|
|
/// <summary>
|
|
/// Specifies the size of the decal region in meters.
|
|
/// </summary>
|
|
public Vector2 decalRegionSize = new Vector2(200.0f, 200.0f);
|
|
|
|
/// <summary>
|
|
/// Specifies the center of the decal region. When null, the region will follow the main camera.
|
|
/// </summary>
|
|
public Transform decalRegionAnchor = null;
|
|
|
|
// Compute the decal region bounds for this frame
|
|
internal float2 frameRegionCenter, frameRegionSize;
|
|
internal void UpdateDecalRegion(Transform anchor)
|
|
{
|
|
if (decalRegionAnchor != null)
|
|
anchor = decalRegionAnchor;
|
|
|
|
frameRegionSize = decalRegionSize;
|
|
frameRegionCenter = anchor != null ? new float2(anchor.position.x, anchor.position.z) : 0.0f;
|
|
if (anchor == null)
|
|
return;
|
|
|
|
|
|
if (IsProceduralGeometry() && !IsInfinite())
|
|
{
|
|
float3 position = transform.position;
|
|
float size = length(new float2(abs(transform.lossyScale.x), abs(transform.lossyScale.z))) * 0.5f;
|
|
|
|
float2 waterMin = position.xz - size, waterMax = position.xz + size;
|
|
float2 regionMin = max(waterMin, frameRegionCenter - frameRegionSize * 0.5f);
|
|
float2 regionMax = min(waterMax, frameRegionCenter + frameRegionSize * 0.5f);
|
|
|
|
frameRegionCenter = (regionMin + regionMax) * 0.5f;
|
|
frameRegionSize = regionMax - regionMin;
|
|
//frameRegionSize = max(regionMax-frameRegionCenter, frameRegionCenter-regionMin) * 2.0f;
|
|
}
|
|
/*
|
|
else if (IsCustomMesh())
|
|
{
|
|
Vector3 decalRegionCenter = new Vector3(anchor.position.x, 0.0f, anchor.position.z);
|
|
if (!IsCustomMesh())
|
|
decalRegionCenter = transform.rotation * decalRegionCenter;
|
|
}
|
|
*/
|
|
|
|
// Move region in steps to avoid flickering under camera movement
|
|
// We only use the foam resolution as it's the one that gets reprojected
|
|
float step = max(frameRegionSize.x, frameRegionSize.y) / (float)foamResolution;
|
|
frameRegionCenter = round(frameRegionCenter / step) * step;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Function that returns the decal region center and size.
|
|
/// </summary>
|
|
/// <param name="center">Region center, based on the anchor gameObject.</param>
|
|
/// <param name="size">Region size.</param>
|
|
public void GetDecalRegion(out float2 center, out float2 size)
|
|
{
|
|
center = frameRegionCenter;
|
|
size = frameRegionSize;
|
|
}
|
|
#endregion
|
|
|
|
/// <summary>
|
|
/// Function that fills a WaterSimSearchData with the data of the current water surface.
|
|
/// </summary>
|
|
/// <param name="wsd">The water simulation search data to fill.</param>
|
|
/// <returns>A boolean that defines if the function was able to fill the search data.</returns>
|
|
public bool FillWaterSearchData(ref WaterSimSearchData wsd)
|
|
{
|
|
var hdrp = HDRenderPipeline.currentPipeline;
|
|
if (hdrp == null || !scriptInteractions)
|
|
return false;
|
|
|
|
if (simulation != null && simulation.ValidResources((int)hdrp.waterSystem.simationRes, numActiveBands, HasSimulationFoam()))
|
|
{
|
|
// General
|
|
wsd.simulationTime = simulation.simulationTime;
|
|
|
|
// Simulation
|
|
wsd.activeBandCount = WaterSystem.EvaluateCPUBandCount(surfaceType, ripples, cpuEvaluateRipples);
|
|
wsd.cpuSimulation = hdrp.waterSystem.replicateSimulationOnCPU;
|
|
wsd.spectrum = simulation.spectrum;
|
|
wsd.rendering = simulation.rendering;
|
|
|
|
wsd.decalWorkflow = HDRenderPipeline.currentPipeline.waterSystem.m_EnableDecalWorkflow;
|
|
|
|
GetDecalRegion(out var center, out var size);
|
|
wsd.decalRegionCenter = center;
|
|
wsd.decalRegionScale = 1.0f / size;
|
|
|
|
if (wsd.cpuSimulation)
|
|
{
|
|
if (simulation.cpuBuffers == null)
|
|
return false;
|
|
|
|
wsd.simulationRes = (int)hdrp.waterSystem.cpuSimationRes;
|
|
wsd.displacementDataCPU = simulation.cpuBuffers.displacementBufferCPU;
|
|
wsd.displacementDataGPU = wsd.displacementDataCPU.Reinterpret<half4>(4 * sizeof(float));
|
|
}
|
|
else
|
|
{
|
|
if (!displacementBufferSynchronizer.TryGetBuffer(out wsd.displacementDataGPU))
|
|
return false;
|
|
|
|
wsd.simulationRes = simulation.simulationResolution;
|
|
wsd.displacementDataCPU = wsd.displacementDataGPU.Reinterpret<float4>(2 * sizeof(float));
|
|
|
|
if (wsd.displacementDataGPU.Length == 0 || displacementBufferSynchronizer.CurrentSlices() < wsd.activeBandCount)
|
|
return false;
|
|
}
|
|
|
|
// Mask data
|
|
FillWaterMaskData(ref wsd);
|
|
|
|
// Deformation data
|
|
FillWaterDeformationData(ref wsd);
|
|
|
|
// Current map data
|
|
FillCurrentMapData(ref wsd);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Function that attempts to evaluate the projection of a given world space position onto the water surface. This requires the HDRP asset and the water surface to have script interactions enabled.
|
|
/// </summary>
|
|
/// <param name="wsp">The water simulation search parameters that defines the location we are targeting and additional parameters.</param>
|
|
/// <param name="wsr">The water simulation search result that contains the result position, error, etc.</param>
|
|
/// <returns>A boolean that defines if the function was able to execute the evaluation.</returns>
|
|
public bool ProjectPointOnWaterSurface(WaterSearchParameters wsp, out WaterSearchResult wsr)
|
|
{
|
|
// Invalidate the search result in case the simulation data is not available
|
|
wsr.error = float.MaxValue;
|
|
wsr.projectedPositionWS = float3(0, 0, 0);
|
|
wsr.normalWS = UpVector();
|
|
wsr.candidateLocationWS = float3(0, 0, 0);
|
|
wsr.currentDirectionWS = float3(1, 0, 0);
|
|
wsr.numIterations = wsp.maxIterations;
|
|
|
|
// Try to to fill the search data and run the evaluation.
|
|
WaterSimSearchData wsd = new WaterSimSearchData();
|
|
if (FillWaterSearchData(ref wsd))
|
|
return WaterSystem.ProjectPointOnWaterSurface(wsd, wsp, ref wsr);
|
|
return false;
|
|
}
|
|
|
|
private void Start()
|
|
{
|
|
// Add this water surface to the internal surface management
|
|
RegisterInstance(this);
|
|
}
|
|
|
|
private void Awake()
|
|
{
|
|
k_Migration.Migrate(this);
|
|
|
|
// Add this water surface to the internal surface management
|
|
RegisterInstance(this);
|
|
}
|
|
|
|
private void OnEnable()
|
|
{
|
|
// Add this water surface to the internal surface management
|
|
RegisterInstance(this);
|
|
|
|
#if UNITY_EDITOR
|
|
// Handle scene visibility
|
|
PrefabStage.prefabStageOpened += RegisterWaterSurfaceVisibilityUpdatePrefabStage;
|
|
if (PrefabStageUtility.GetCurrentPrefabStage() != null) // In case the prefab stage is already opened when enabling the decal
|
|
RegisterWaterSurfaceVisibilityUpdatePrefabStage();
|
|
#endif
|
|
}
|
|
|
|
private void OnDisable()
|
|
{
|
|
// Remove this water surface from the internal surface management
|
|
UnregisterInstance(this);
|
|
|
|
#if UNITY_EDITOR
|
|
UnregisterWaterSurfaceVisibilityUpdatePrefabStage();
|
|
PrefabStage.prefabStageOpened -= RegisterWaterSurfaceVisibilityUpdatePrefabStage;
|
|
#endif
|
|
}
|
|
|
|
#if UNITY_EDITOR
|
|
void RegisterWaterSurfaceVisibilityUpdatePrefabStage(PrefabStage stage = null)
|
|
{
|
|
SceneView.duringSceneGui -= UpdateWaterSurfaceVisibilityPrefabStage;
|
|
SceneView.duringSceneGui += UpdateWaterSurfaceVisibilityPrefabStage;
|
|
}
|
|
|
|
void UnregisterWaterSurfaceVisibilityUpdatePrefabStage()
|
|
=> SceneView.duringSceneGui -= UpdateWaterSurfaceVisibilityPrefabStage;
|
|
|
|
bool m_LastPrefabStageVisibility = true;
|
|
void UpdateWaterSurfaceVisibilityPrefabStage(SceneView sv)
|
|
{
|
|
bool showWaterSurface = true;
|
|
|
|
// If prefab context is not hidden, then we should render the WaterSurface
|
|
if (!CoreUtils.IsSceneViewPrefabStageContextHidden())
|
|
showWaterSurface = true;
|
|
|
|
var stage = PrefabStageUtility.GetCurrentPrefabStage();
|
|
if (stage != null)
|
|
{
|
|
bool isWaterSurfaceInPrefabStage = gameObject.scene == stage.scene;
|
|
|
|
if (!isWaterSurfaceInPrefabStage && stage.mode == PrefabStage.Mode.InIsolation)
|
|
showWaterSurface = false;
|
|
if (!isWaterSurfaceInPrefabStage && CoreUtils.IsSceneViewPrefabStageContextHidden())
|
|
showWaterSurface = false;
|
|
}
|
|
|
|
// Update decal visibility based on showDecal
|
|
if (!m_LastPrefabStageVisibility && showWaterSurface)
|
|
{
|
|
RegisterInstance(this);
|
|
}
|
|
else if (m_LastPrefabStageVisibility && !showWaterSurface)
|
|
{
|
|
UnregisterInstance(this);
|
|
}
|
|
m_LastPrefabStageVisibility = showWaterSurface;
|
|
}
|
|
#endif
|
|
|
|
internal bool IsInstancedQuads()
|
|
{
|
|
return IsInfinite() || geometryType == WaterGeometryType.InstancedQuads;
|
|
}
|
|
|
|
internal bool IsInfinite()
|
|
{
|
|
return (surfaceType == WaterSurfaceType.OceanSeaLake) ? geometryType == WaterGeometryType.Infinite : false;
|
|
}
|
|
|
|
internal bool IsProceduralGeometry()
|
|
{
|
|
return !IsCustomMesh();
|
|
}
|
|
|
|
internal bool IsCustomMesh()
|
|
{
|
|
return geometryType == WaterGeometryType.Custom && meshRenderers.Count != 0;
|
|
|
|
}
|
|
|
|
internal bool IsQuad()
|
|
{
|
|
return geometryType == WaterGeometryType.Quad || (geometryType == WaterGeometryType.Custom && meshRenderers.Count == 0);
|
|
}
|
|
|
|
internal float3 UpVector()
|
|
{
|
|
return transform.up;
|
|
}
|
|
|
|
internal void ReleaseResources()
|
|
{
|
|
ReleaseSimulationResources();
|
|
ReleaseCurrentMapResources();
|
|
ReleaseDeformationResources();
|
|
ReleaseWaterMaskResources();
|
|
ReleaseFoamResources();
|
|
}
|
|
|
|
void OnDestroy()
|
|
{
|
|
// Remove this water surface from the internal surface management
|
|
UnregisterInstance(this);
|
|
|
|
// Release all CPU and GPU buffers
|
|
ReleaseResources();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Function that returns the caustics buffer for the water surface. If the feature is disabled or the resource is not available the function returns null.
|
|
/// </summary>
|
|
/// <param name="regionSize">Output parameter that returns the size of the caustics region.</param>
|
|
/// <returns>A monochrome texture that holds the caustics simulation of the water surface.</returns>
|
|
public Texture GetCausticsBuffer(out float regionSize)
|
|
{
|
|
if (caustics && simulation?.gpuBuffers?.causticsBuffer != null)
|
|
{
|
|
int causticsBandIndex = WaterSystem.SanitizeCausticsBand(causticsBand, simulation.numActiveBands);
|
|
regionSize = simulation.spectrum.patchSizes[causticsBandIndex];
|
|
return simulation.gpuBuffers.causticsBuffer;
|
|
}
|
|
regionSize = 0.0f;
|
|
return null;
|
|
}
|
|
}
|
|
}
|