Files
2026-03-04 10:03:45 +08:00

403 lines
14 KiB
C#

using System;
using System.Collections.Generic;
using UltimateWater.Internal;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Serialization;
namespace UltimateWater
{
[Serializable]
public class WaterRenderer
{
[HideInInspector]
[SerializeField]
[FormerlySerializedAs("volumeFrontShader")]
private Shader _VolumeFrontShader;
[HideInInspector]
[SerializeField]
[FormerlySerializedAs("volumeFrontFastShader")]
private Shader _VolumeFrontFastShader;
[HideInInspector]
[SerializeField]
[FormerlySerializedAs("volumeBackShader")]
private Shader _VolumeBackShader;
[SerializeField]
[FormerlySerializedAs("reflectionProbeAnchor")]
private Transform _ReflectionProbeAnchor;
[SerializeField]
[FormerlySerializedAs("shadowCastingMode")]
private ShadowCastingMode _ShadowCastingMode;
[SerializeField]
[FormerlySerializedAs("useSharedMask")]
private bool _UseSharedMask = true;
private Water _Water;
private MaterialPropertyBlock _PropertyBlock;
private RenderTexture _AdditiveMaskTexture;
private RenderTexture _SubtractiveMaskTexture;
private readonly List<WaterSimpleMask> _Masks = new List<WaterSimpleMask>();
public int MaskCount => _Masks.Count;
public MaterialPropertyBlock PropertyBlock
{
get
{
if (_PropertyBlock == null)
{
return _PropertyBlock = new MaterialPropertyBlock();
}
return _PropertyBlock;
}
}
public Transform ReflectionProbeAnchor
{
get
{
return _ReflectionProbeAnchor;
}
set
{
_ReflectionProbeAnchor = value;
}
}
public void AddMask(WaterSimpleMask mask)
{
mask.Renderer.enabled = false;
int renderQueuePriority = mask.RenderQueuePriority;
for (int num = _Masks.Count - 1; num >= 0; num--)
{
if (_Masks[num].RenderQueuePriority <= renderQueuePriority)
{
_Masks.Insert(num + 1, mask);
return;
}
}
_Masks.Insert(0, mask);
}
public void RemoveMask(WaterSimpleMask mask)
{
_Masks.Remove(mask);
}
public void RenderEffects(WaterCamera waterCamera)
{
Camera cameraComponent = waterCamera.CameraComponent;
if (_Water.isActiveAndEnabled && (cameraComponent.cullingMask & (1 << _Water.gameObject.layer)) != 0 && (_Water.Volume.Boundless || !_Water.Volume.HasRenderableAdditiveVolumes || waterCamera.RenderVolumes))
{
_Water.OnWaterRender(waterCamera);
}
}
public void Render(Camera camera, WaterGeometryType geometryType, CommandBuffer commandBuffer = null, Shader shader = null)
{
if (!_Water.isActiveAndEnabled || (camera.cullingMask & (1 << _Water.gameObject.layer)) == 0)
{
return;
}
WaterCamera waterCamera = WaterCamera.GetWaterCamera(camera);
if ((object)waterCamera == null || (!_Water.Volume.Boundless && _Water.Volume.HasRenderableAdditiveVolumes && !waterCamera.RenderVolumes))
{
return;
}
if (_Water.ShaderSet.ReceiveShadows)
{
Vector2 min = new Vector2(0f, 0f);
Vector2 max = new Vector2(1f, 1f);
waterCamera.ReportShadowedWaterMinMaxRect(min, max);
}
if (!_UseSharedMask)
{
RenderMasks(camera, waterCamera, _PropertyBlock);
}
Matrix4x4 matrix;
Mesh[] transformedMeshes = _Water.Geometry.GetTransformedMeshes(camera, out matrix, geometryType, volume: false, waterCamera.ForcedVertexCount);
if (commandBuffer == null)
{
Camera camera2 = ((waterCamera.RenderMode != WaterRenderMode.DefaultQueue) ? waterCamera._WaterRenderCamera : camera);
for (int i = 0; i < transformedMeshes.Length; i++)
{
Graphics.DrawMesh(transformedMeshes[i], matrix, _Water.Materials.SurfaceMaterial, _Water.gameObject.layer, camera2, 0, _PropertyBlock, _ShadowCastingMode, receiveShadows: false, (_ReflectionProbeAnchor != null) ? _ReflectionProbeAnchor : _Water.transform, useLightProbes: false);
if (waterCamera.ContainingWater != null && waterCamera.Type == WaterCamera.CameraType.Normal)
{
Graphics.DrawMesh(transformedMeshes[i], matrix, _Water.Materials.SurfaceBackMaterial, _Water.gameObject.layer, camera2, 0, _PropertyBlock, _ShadowCastingMode, receiveShadows: false, (_ReflectionProbeAnchor != null) ? _ReflectionProbeAnchor : _Water.transform, useLightProbes: false);
}
}
}
else
{
Material variant = UtilityShaderVariants.Instance.GetVariant(shader, _Water.Materials.UsedKeywords);
for (int j = 0; j < transformedMeshes.Length; j++)
{
commandBuffer.DrawMesh(transformedMeshes[j], matrix, variant, 0, 0, _PropertyBlock);
}
}
}
public void RenderVolumes(CommandBuffer commandBuffer, Shader shader, bool twoPass)
{
if (_Water.enabled)
{
Material variant = UtilityShaderVariants.Instance.GetVariant(shader, _Water.Materials.UsedKeywords);
List<WaterVolumeAdd> volumesDirect = _Water.Volume.GetVolumesDirect();
RenderVolumes(commandBuffer, variant, volumesDirect, twoPass);
List<WaterVolumeSubtract> subtractiveVolumesDirect = _Water.Volume.GetSubtractiveVolumesDirect();
RenderVolumes(commandBuffer, variant, subtractiveVolumesDirect, twoPass);
}
}
public void RenderMasks(CommandBuffer commandBuffer)
{
for (int num = _Masks.Count - 1; num >= 0; num--)
{
commandBuffer.DrawMesh(_Masks[num].GetComponent<MeshFilter>().sharedMesh, _Masks[num].transform.localToWorldMatrix, _Masks[num].Renderer.sharedMaterial, 0, 0);
}
}
public void PostRender(WaterCamera waterCamera)
{
if (_Water != null)
{
_Water.OnWaterPostRender(waterCamera);
}
ReleaseTemporaryBuffers();
}
public void OnSharedSubtractiveMaskRender(ref bool hasSubtractiveVolumes, ref bool hasAdditiveVolumes, ref bool hasFlatMasks)
{
if (!_Water.enabled)
{
return;
}
List<WaterVolumeAdd> volumesDirect = _Water.Volume.GetVolumesDirect();
int count = volumesDirect.Count;
for (int i = 0; i < count; i++)
{
volumesDirect[i].DisableRenderers();
}
List<WaterVolumeSubtract> subtractiveVolumesDirect = _Water.Volume.GetSubtractiveVolumesDirect();
int count2 = subtractiveVolumesDirect.Count;
if (_UseSharedMask)
{
for (int j = 0; j < count2; j++)
{
subtractiveVolumesDirect[j].EnableRenderers(forBorderRendering: false);
}
hasSubtractiveVolumes = hasSubtractiveVolumes || _Water.Volume.GetSubtractiveVolumesDirect().Count != 0;
hasAdditiveVolumes = hasAdditiveVolumes || count != 0;
hasFlatMasks = hasFlatMasks || _Masks.Count != 0;
}
else
{
for (int k = 0; k < count2; k++)
{
subtractiveVolumesDirect[k].DisableRenderers();
}
}
}
public void OnSharedMaskAdditiveRender()
{
if (_Water.enabled && _UseSharedMask)
{
List<WaterVolumeAdd> volumesDirect = _Water.Volume.GetVolumesDirect();
int count = volumesDirect.Count;
for (int i = 0; i < count; i++)
{
volumesDirect[i].EnableRenderers(forBorderRendering: false);
}
List<WaterVolumeSubtract> subtractiveVolumesDirect = _Water.Volume.GetSubtractiveVolumesDirect();
int count2 = subtractiveVolumesDirect.Count;
for (int j = 0; j < count2; j++)
{
subtractiveVolumesDirect[j].DisableRenderers();
}
}
}
public void OnSharedMaskPostRender()
{
if (_Water.enabled)
{
List<WaterVolumeAdd> volumesDirect = _Water.Volume.GetVolumesDirect();
int count = volumesDirect.Count;
for (int i = 0; i < count; i++)
{
volumesDirect[i].EnableRenderers(forBorderRendering: true);
}
List<WaterVolumeSubtract> subtractiveVolumesDirect = _Water.Volume.GetSubtractiveVolumesDirect();
int count2 = subtractiveVolumesDirect.Count;
for (int j = 0; j < count2; j++)
{
subtractiveVolumesDirect[j].EnableRenderers(forBorderRendering: true);
}
}
}
internal void Awake(Water water)
{
_Water = water;
PropertyBlock.SetFloat("_RiverEnabled", 0f);
}
internal void OnValidate()
{
if (_VolumeFrontShader == null)
{
_VolumeFrontShader = Shader.Find("UltimateWater/Volumes/Front");
}
if (_VolumeFrontFastShader == null)
{
_VolumeFrontFastShader = Shader.Find("UltimateWater/Volumes/Front Simple");
}
if (_VolumeBackShader == null)
{
_VolumeBackShader = Shader.Find("UltimateWater/Volumes/Back");
}
}
private static void RenderVolumes<T>(CommandBuffer commandBuffer, Material material, List<T> boundingVolumes, bool twoPass) where T : WaterVolumeBase
{
for (int num = boundingVolumes.Count - 1; num >= 0; num--)
{
MeshRenderer[] volumeRenderers = boundingVolumes[num].VolumeRenderers;
MeshFilter[] volumeFilters = boundingVolumes[num].VolumeFilters;
if (volumeRenderers != null && volumeRenderers.Length != 0 && volumeRenderers[0].enabled)
{
if (!twoPass)
{
int shaderPass = ((material.passCount != 1) ? 1 : 0);
for (int i = 0; i < volumeRenderers.Length; i++)
{
commandBuffer.DrawMesh(volumeFilters[i].sharedMesh, volumeRenderers[i].transform.localToWorldMatrix, material, 0, shaderPass);
}
}
else
{
for (int j = 0; j < volumeRenderers.Length; j++)
{
Mesh sharedMesh = volumeFilters[j].sharedMesh;
commandBuffer.DrawMesh(sharedMesh, volumeRenderers[j].transform.localToWorldMatrix, material, 0, 0);
commandBuffer.DrawMesh(sharedMesh, volumeRenderers[j].transform.localToWorldMatrix, material, 0, 1);
}
}
}
}
}
private void ReleaseTemporaryBuffers()
{
if (_AdditiveMaskTexture != null)
{
RenderTexture.ReleaseTemporary(_AdditiveMaskTexture);
_AdditiveMaskTexture = null;
}
if (_SubtractiveMaskTexture != null)
{
RenderTexture.ReleaseTemporary(_SubtractiveMaskTexture);
_SubtractiveMaskTexture = null;
}
}
private void RenderMasks(Camera camera, WaterCamera waterCamera, MaterialPropertyBlock propertyBlock)
{
List<WaterVolumeSubtract> subtractiveVolumesDirect = _Water.Volume.GetSubtractiveVolumesDirect();
List<WaterVolumeAdd> volumesDirect = _Water.Volume.GetVolumesDirect();
if ((object)waterCamera == null || !waterCamera.RenderVolumes || (subtractiveVolumesDirect.Count == 0 && volumesDirect.Count == 0 && _Masks.Count == 0))
{
ReleaseTemporaryBuffers();
return;
}
int waterTempLayer = WaterProjectSettings.Instance.WaterTempLayer;
int waterCollidersLayer = WaterProjectSettings.Instance.WaterCollidersLayer;
Camera effectsCamera = waterCamera.EffectsCamera;
if (effectsCamera == null)
{
ReleaseTemporaryBuffers();
return;
}
bool hasSubtractiveVolumes = false;
bool hasAdditiveVolumes = false;
bool hasFlatMasks = false;
OnSharedSubtractiveMaskRender(ref hasSubtractiveVolumes, ref hasAdditiveVolumes, ref hasFlatMasks);
effectsCamera.CopyFrom(camera);
effectsCamera.enabled = false;
effectsCamera.GetComponent<WaterCamera>().enabled = false;
effectsCamera.renderingPath = RenderingPath.Forward;
effectsCamera.depthTextureMode = DepthTextureMode.None;
effectsCamera.cullingMask = 1 << waterTempLayer;
if (subtractiveVolumesDirect.Count != 0)
{
if (_SubtractiveMaskTexture == null)
{
_SubtractiveMaskTexture = RenderTexture.GetTemporary(camera.pixelWidth, camera.pixelHeight, 24, SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.ARGBFloat) ? RenderTextureFormat.ARGBFloat : RenderTextureFormat.ARGBHalf, RenderTextureReadWrite.Linear, 1);
}
Graphics.SetRenderTarget(_SubtractiveMaskTexture);
int count = subtractiveVolumesDirect.Count;
for (int i = 0; i < count; i++)
{
subtractiveVolumesDirect[i].SetLayer(waterTempLayer);
}
TemporaryRenderTexture temporary = RenderTexturesCache.GetTemporary(camera.pixelWidth, camera.pixelHeight, 24, SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.ARGBFloat) ? RenderTextureFormat.ARGBFloat : RenderTextureFormat.ARGBHalf, linear: true, uav: false);
effectsCamera.clearFlags = CameraClearFlags.Color;
effectsCamera.backgroundColor = new Color(0f, 0f, 0.5f, 0f);
effectsCamera.targetTexture = temporary;
effectsCamera.RenderWithShader(_VolumeFrontShader, "CustomType");
GL.Clear(clearDepth: true, clearColor: true, new Color(0f, 0f, 0f, 0f), 0f);
Shader.SetGlobalTexture("_VolumesFrontDepth", (RenderTexture)temporary);
effectsCamera.clearFlags = CameraClearFlags.Nothing;
effectsCamera.targetTexture = _SubtractiveMaskTexture;
effectsCamera.RenderWithShader(_VolumeBackShader, "CustomType");
temporary.Dispose();
for (int j = 0; j < count; j++)
{
subtractiveVolumesDirect[j].SetLayer(waterCollidersLayer);
}
propertyBlock.SetTexture(ShaderVariables.SubtractiveMask, _SubtractiveMaskTexture);
}
if (volumesDirect.Count != 0)
{
OnSharedMaskAdditiveRender();
if (_AdditiveMaskTexture == null)
{
_AdditiveMaskTexture = RenderTexture.GetTemporary(camera.pixelWidth, camera.pixelHeight, 16, SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.ARGBFloat) ? RenderTextureFormat.ARGBFloat : RenderTextureFormat.ARGBHalf, RenderTextureReadWrite.Linear, 1);
}
Graphics.SetRenderTarget(_AdditiveMaskTexture);
GL.Clear(clearDepth: true, clearColor: true, new Color(0f, 0f, 0f, 0f));
int count2 = volumesDirect.Count;
for (int k = 0; k < count2; k++)
{
volumesDirect[k].SetLayer(waterTempLayer);
volumesDirect[k].EnableRenderers(forBorderRendering: false);
}
effectsCamera.clearFlags = CameraClearFlags.Nothing;
effectsCamera.targetTexture = _AdditiveMaskTexture;
effectsCamera.RenderWithShader(waterCamera.IsInsideAdditiveVolume ? _VolumeFrontShader : _VolumeFrontFastShader, "CustomType");
effectsCamera.clearFlags = CameraClearFlags.Nothing;
effectsCamera.targetTexture = _AdditiveMaskTexture;
effectsCamera.RenderWithShader(_VolumeBackShader, "CustomType");
for (int l = 0; l < count2; l++)
{
volumesDirect[l].SetLayer(waterCollidersLayer);
}
propertyBlock.SetTexture(ShaderVariables.AdditiveMask, _AdditiveMaskTexture);
}
OnSharedMaskPostRender();
effectsCamera.targetTexture = null;
}
}
}