Files
2026-02-21 16:45:37 +08:00

318 lines
7.9 KiB
C#

using System;
using UnityEngine;
using UnityEngine.Serialization;
namespace UltimateWater.Internal
{
[Serializable]
public class WaterGeometry
{
public enum Type
{
RadialGrid = 0,
ProjectionGrid = 1,
UniformGrid = 2,
CustomMeshes = 3
}
[FormerlySerializedAs("type")]
[SerializeField]
[Tooltip("Geometry type used for display.")]
private Type _Type;
[FormerlySerializedAs("baseVertexCount")]
[SerializeField]
[Tooltip("Water geometry vertex count at 1920x1080.")]
private int _BaseVertexCount = 500000;
[FormerlySerializedAs("tesselatedBaseVertexCount")]
[SerializeField]
[Tooltip("Water geometry vertex count at 1920x1080 on systems with tessellation support. Set it a bit lower as tessellation will place additional, better distributed vertices in shader.")]
private int _TesselatedBaseVertexCount = 16000;
[FormerlySerializedAs("adaptToResolution")]
[SerializeField]
private bool _AdaptToResolution = true;
[FormerlySerializedAs("radialGrid")]
[SerializeField]
private WaterRadialGrid _RadialGrid;
[FormerlySerializedAs("projectionGrid")]
[SerializeField]
private WaterProjectionGrid _ProjectionGrid;
[FormerlySerializedAs("uniformGrid")]
[SerializeField]
private WaterUniformGrid _UniformGrid;
[FormerlySerializedAs("customSurfaceMeshes")]
[SerializeField]
private WaterCustomSurfaceMeshes _CustomSurfaceMeshes;
private Water _Water;
private Type _PreviousType;
private int _PreviousTargetVertexCount;
private int _ThisSystemVertexCount;
private int _FrameCount;
private readonly WaterQuadGeometry _QuadGeometry = new WaterQuadGeometry();
public Type GeometryType
{
get
{
return _Type;
}
set
{
_Type = value;
}
}
public int VertexCount
{
get
{
return _BaseVertexCount;
}
}
public int TesselatedBaseVertexCount
{
get
{
return _TesselatedBaseVertexCount;
}
}
public bool AdaptToResolution
{
get
{
return _AdaptToResolution;
}
}
public bool Triangular
{
get
{
return _Type == Type.CustomMeshes && _CustomSurfaceMeshes.Triangular;
}
}
public WaterCustomSurfaceMeshes CustomSurfaceMeshes
{
get
{
return _CustomSurfaceMeshes;
}
}
public Mesh[] GetMeshes(WaterGeometryType geometryType, int vertexCount, bool volume)
{
if (geometryType == WaterGeometryType.ProjectionGrid)
{
throw new InvalidOperationException("Projection grid needs camera to be retrieved. Use GetTransformedMeshes instead.");
}
if (_Type == Type.CustomMeshes)
{
geometryType = WaterGeometryType.Auto;
}
Matrix4x4 matrix;
switch (geometryType)
{
case WaterGeometryType.Auto:
switch (_Type)
{
case Type.RadialGrid:
return _RadialGrid.GetTransformedMeshes(null, out matrix, vertexCount, volume);
case Type.ProjectionGrid:
return _ProjectionGrid.GetTransformedMeshes(null, out matrix, vertexCount, volume);
case Type.UniformGrid:
return _UniformGrid.GetTransformedMeshes(null, out matrix, vertexCount, volume);
case Type.CustomMeshes:
return _CustomSurfaceMeshes.GetTransformedMeshes(null, out matrix, volume);
default:
throw new InvalidOperationException("Unknown water geometry type.");
}
case WaterGeometryType.RadialGrid:
return _RadialGrid.GetTransformedMeshes(null, out matrix, vertexCount, volume);
case WaterGeometryType.ProjectionGrid:
return _ProjectionGrid.GetTransformedMeshes(null, out matrix, vertexCount, volume);
case WaterGeometryType.UniformGrid:
return _UniformGrid.GetTransformedMeshes(null, out matrix, vertexCount, volume);
case WaterGeometryType.QuadGeometry:
return _QuadGeometry.GetTransformedMeshes(null, out matrix, vertexCount, volume);
default:
throw new InvalidOperationException("Unknown water geometry type.");
}
}
public Mesh[] GetTransformedMeshes(Camera camera, out Matrix4x4 matrix, WaterGeometryType geometryType, bool volume, int vertexCount = 0)
{
if (vertexCount == 0)
{
vertexCount = ComputeVertexCountForCamera(camera);
}
if (_Type == Type.CustomMeshes)
{
geometryType = WaterGeometryType.Auto;
}
switch (geometryType)
{
case WaterGeometryType.Auto:
switch (_Type)
{
case Type.RadialGrid:
return _RadialGrid.GetTransformedMeshes(camera, out matrix, vertexCount, volume);
case Type.ProjectionGrid:
return _ProjectionGrid.GetTransformedMeshes(camera, out matrix, vertexCount, volume);
case Type.UniformGrid:
return _UniformGrid.GetTransformedMeshes(camera, out matrix, vertexCount, volume);
case Type.CustomMeshes:
return _CustomSurfaceMeshes.GetTransformedMeshes(null, out matrix, volume);
default:
throw new InvalidOperationException("Unknown water geometry type.");
}
case WaterGeometryType.RadialGrid:
return _RadialGrid.GetTransformedMeshes(camera, out matrix, vertexCount, volume);
case WaterGeometryType.ProjectionGrid:
return _ProjectionGrid.GetTransformedMeshes(camera, out matrix, vertexCount, volume);
case WaterGeometryType.UniformGrid:
return _UniformGrid.GetTransformedMeshes(camera, out matrix, vertexCount, volume);
case WaterGeometryType.QuadGeometry:
return _QuadGeometry.GetTransformedMeshes(camera, out matrix, vertexCount, volume);
default:
throw new InvalidOperationException("Unknown water geometry type.");
}
}
public int ComputeVertexCountForCamera(Camera camera)
{
return (!_AdaptToResolution) ? _ThisSystemVertexCount : ((int)((float)_ThisSystemVertexCount * ((float)(camera.pixelWidth * camera.pixelHeight) / 2073600f) + 0.5f));
}
private void UpdateVertexCount()
{
_ThisSystemVertexCount = ((!SystemInfo.supportsComputeShaders) ? Mathf.Min(_BaseVertexCount, WaterQualitySettings.Instance.MaxVertexCount) : Mathf.Min(_TesselatedBaseVertexCount, WaterQualitySettings.Instance.MaxTesselatedVertexCount));
}
internal void Awake(Water water)
{
_Water = water;
}
internal void OnEnable()
{
OnValidate();
UpdateVertexCount();
_RadialGrid.OnEnable(_Water);
_ProjectionGrid.OnEnable(_Water);
_UniformGrid.OnEnable(_Water);
_CustomSurfaceMeshes.OnEnable(_Water);
}
internal void OnDisable()
{
if (_RadialGrid != null)
{
_RadialGrid.OnDisable();
}
if (_ProjectionGrid != null)
{
_ProjectionGrid.OnDisable();
}
if (_UniformGrid != null)
{
_UniformGrid.OnDisable();
}
if (_CustomSurfaceMeshes != null)
{
_CustomSurfaceMeshes.OnDisable();
}
}
internal void OnValidate()
{
if (_RadialGrid == null)
{
_RadialGrid = new WaterRadialGrid();
}
if (_ProjectionGrid == null)
{
_ProjectionGrid = new WaterProjectionGrid();
}
if (_UniformGrid == null)
{
_UniformGrid = new WaterUniformGrid();
}
if (_CustomSurfaceMeshes == null)
{
_CustomSurfaceMeshes = new WaterCustomSurfaceMeshes();
}
if (_PreviousType != _Type)
{
switch (_PreviousType)
{
case Type.RadialGrid:
_RadialGrid.RemoveFromMaterial(_Water);
break;
case Type.ProjectionGrid:
_ProjectionGrid.RemoveFromMaterial(_Water);
break;
case Type.UniformGrid:
_UniformGrid.RemoveFromMaterial(_Water);
break;
}
switch (_Type)
{
case Type.RadialGrid:
_RadialGrid.AddToMaterial(_Water);
break;
case Type.ProjectionGrid:
_ProjectionGrid.AddToMaterial(_Water);
break;
case Type.UniformGrid:
_UniformGrid.AddToMaterial(_Water);
break;
}
_PreviousType = _Type;
}
UpdateVertexCount();
if (_PreviousTargetVertexCount != _ThisSystemVertexCount)
{
_RadialGrid.Dispose();
_UniformGrid.Dispose();
_ProjectionGrid.Dispose();
_PreviousTargetVertexCount = _ThisSystemVertexCount;
}
}
internal void Update()
{
if (++_FrameCount > 8)
{
_FrameCount = 0;
}
switch (_FrameCount)
{
case 0:
_RadialGrid.Update();
break;
case 3:
_ProjectionGrid.Update();
break;
case 6:
_UniformGrid.Update();
break;
}
}
}
}