Files
UltimateFishing/Assets/Scripts/Assembly-CSharp/UltimateWater/PlanarReflection.cs
2026-02-21 16:45:37 +08:00

304 lines
8.9 KiB
C#

using System;
using System.Collections.Generic;
using UltimateWater.Internal;
using UnityEngine;
namespace UltimateWater
{
public sealed class PlanarReflection : WaterModule
{
[Serializable]
public class Data
{
public LayerMask ReflectionMask = int.MaxValue;
public bool ReflectSkybox = true;
public bool RenderShadows = true;
[Range(0f, 1f)]
public float Resolution = 0.5f;
[Range(0f, 1f)]
[Tooltip("Allows you to use more rational resolution of planar reflections on screens with very high dpi. Planar reflections should be blurred anyway.")]
public float RetinaResolution = 0.333f;
}
private readonly Data _Data;
private readonly Water _Water;
private readonly bool _SystemSupportsHdr;
private readonly Dictionary<Camera, TemporaryRenderTexture> _TemporaryTargets = new Dictionary<Camera, TemporaryRenderTexture>();
private TemporaryRenderTexture _CurrentTarget;
private float _FinalResolutionMultiplier;
private bool _RenderPlanarReflections;
private Material _UtilitiesMaterial;
private Shader _UtilitiesShader;
private const float _ClipPlaneOffset = 0.07f;
public float Resolution
{
get
{
return _Data.Resolution;
}
set
{
_Data.Resolution = value;
CalculateResolutionMultiplier();
}
}
public float RetinaResolution
{
get
{
return _Data.RetinaResolution;
}
set
{
_Data.RetinaResolution = value;
CalculateResolutionMultiplier();
}
}
public bool ReflectSkybox
{
get
{
return _Data.ReflectSkybox;
}
set
{
_Data.ReflectSkybox = value;
}
}
public bool RenderShadows
{
get
{
return _Data.RenderShadows;
}
set
{
_Data.RenderShadows = value;
}
}
public LayerMask ReflectionMask
{
get
{
return _Data.ReflectionMask;
}
set
{
_Data.ReflectionMask = value;
}
}
public PlanarReflection(Water water, Data data)
{
_Water = water;
_Data = data;
_SystemSupportsHdr = SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.ARGBHalf);
Validate();
water.ProfilesManager.Changed.AddListener(OnProfilesChanged);
OnProfilesChanged(water);
}
internal override void OnWaterPostRender(WaterCamera waterCamera)
{
Camera cameraComponent = waterCamera.CameraComponent;
TemporaryRenderTexture value;
if (_TemporaryTargets.TryGetValue(cameraComponent, out value))
{
_TemporaryTargets.Remove(cameraComponent);
value.Dispose();
}
}
internal override void Start(Water water)
{
}
internal override void Enable()
{
}
internal override void Disable()
{
}
internal override void Validate()
{
if (_UtilitiesShader == null)
{
_UtilitiesShader = Shader.Find("UltimateWater/Utilities/PlanarReflection - Utilities");
}
_Data.Resolution = Mathf.Clamp01((float)Mathf.RoundToInt(_Data.Resolution * 10f) * 0.1f);
_Data.RetinaResolution = Mathf.Clamp01((float)Mathf.RoundToInt(_Data.RetinaResolution * 10f) * 0.1f);
CalculateResolutionMultiplier();
}
internal override void Destroy()
{
ClearRenderTextures();
}
internal override void Update()
{
ClearRenderTextures();
}
internal override void OnWaterRender(WaterCamera waterCamera)
{
Camera cameraComponent = waterCamera.CameraComponent;
if (cameraComponent.enabled && _RenderPlanarReflections && !_TemporaryTargets.TryGetValue(cameraComponent, out _CurrentTarget))
{
Camera reflectionCamera = Reflection.GetReflectionCamera(cameraComponent);
RenderReflection(cameraComponent, reflectionCamera);
UpdateRenderProperties(reflectionCamera);
}
}
private void CalculateResolutionMultiplier()
{
float num = ((!(Screen.dpi <= 220f)) ? _Data.RetinaResolution : _Data.Resolution);
if (_FinalResolutionMultiplier != num)
{
_FinalResolutionMultiplier = num;
ClearRenderTextures();
}
}
private void RenderReflection(Camera camera, Camera reflectionCamera)
{
reflectionCamera.cullingMask = _Data.ReflectionMask;
SetCameraSettings(camera, reflectionCamera);
_CurrentTarget = GetRenderTexture(camera.pixelWidth, camera.pixelHeight, reflectionCamera);
_TemporaryTargets[camera] = _CurrentTarget;
TemporaryRenderTexture temporary = RenderTexturesCache.GetTemporary(_CurrentTarget.Texture.width, _CurrentTarget.Texture.height, 16, _CurrentTarget.Texture.format, true, false);
reflectionCamera.targetTexture = temporary;
reflectionCamera.transform.eulerAngles = CalculateReflectionAngles(camera);
reflectionCamera.transform.position = CalculateReflectionPosition(camera);
float w = 0f - _Water.transform.position.y - 0.07f;
Vector4 plane = new Vector4(0f, 1f, 0f, w);
Matrix4x4 zero = Matrix4x4.zero;
zero = Reflection.CalculateReflectionMatrix(zero, plane);
Vector3 position = zero.MultiplyPoint(camera.transform.position);
reflectionCamera.worldToCameraMatrix = camera.worldToCameraMatrix * zero;
Vector4 clipPlane = Reflection.CameraSpacePlane(reflectionCamera, _Water.transform.position, new Vector3(0f, 1f, 0f), 0.07f, 1f);
Matrix4x4 projectionMatrix = camera.projectionMatrix;
projectionMatrix = Reflection.CalculateObliqueMatrix(projectionMatrix, clipPlane);
reflectionCamera.projectionMatrix = projectionMatrix;
reflectionCamera.transform.position = position;
Vector3 eulerAngles = camera.transform.eulerAngles;
reflectionCamera.transform.eulerAngles = new Vector3(0f - eulerAngles.x, eulerAngles.y, eulerAngles.z);
reflectionCamera.clearFlags = (_Data.ReflectSkybox ? CameraClearFlags.Skybox : CameraClearFlags.Color);
if (_Data.RenderShadows)
{
GL.invertCulling = true;
reflectionCamera.Render();
GL.invertCulling = false;
}
else
{
ShadowQuality shadows = QualitySettings.shadows;
QualitySettings.shadows = ShadowQuality.Disable;
GL.invertCulling = true;
reflectionCamera.Render();
GL.invertCulling = false;
QualitySettings.shadows = shadows;
}
reflectionCamera.targetTexture = null;
if (_UtilitiesMaterial == null)
{
_UtilitiesMaterial = new Material(_UtilitiesShader)
{
hideFlags = HideFlags.DontSave
};
}
Graphics.Blit((RenderTexture)temporary, _CurrentTarget, _UtilitiesMaterial, 0);
temporary.Dispose();
}
private void UpdateRenderProperties(Camera reflectionCamera)
{
MaterialPropertyBlock propertyBlock = _Water.Renderer.PropertyBlock;
propertyBlock.SetTexture(ShaderVariables.PlanarReflectionTex, (RenderTexture)_CurrentTarget);
propertyBlock.SetMatrix("_PlanarReflectionProj", Matrix4x4.TRS(new Vector3(0.5f, 0.5f, 0f), Quaternion.identity, new Vector3(0.5f, 0.5f, 1f)) * reflectionCamera.projectionMatrix * reflectionCamera.worldToCameraMatrix);
propertyBlock.SetFloat("_PlanarReflectionMipBias", 0f - Mathf.Log(1f / _FinalResolutionMultiplier, 2f));
}
private TemporaryRenderTexture GetRenderTexture(int width, int height, Camera reflectionCamera)
{
int width2 = Mathf.ClosestPowerOfTwo(Mathf.RoundToInt((float)width * _FinalResolutionMultiplier));
int height2 = Mathf.ClosestPowerOfTwo(Mathf.RoundToInt((float)height * _FinalResolutionMultiplier));
bool allowHDR = reflectionCamera.allowHDR;
TemporaryRenderTexture temporary = RenderTexturesCache.GetTemporary(width2, height2, 0, (allowHDR && _SystemSupportsHdr && WaterProjectSettings.Instance.AllowFloatingPointMipMaps) ? RenderTextureFormat.ARGBHalf : RenderTextureFormat.ARGB32, true, false, true);
temporary.Texture.filterMode = FilterMode.Trilinear;
temporary.Texture.wrapMode = TextureWrapMode.Clamp;
return temporary;
}
private void ClearRenderTextures()
{
Dictionary<Camera, TemporaryRenderTexture>.Enumerator enumerator = _TemporaryTargets.GetEnumerator();
while (enumerator.MoveNext())
{
enumerator.Current.Value.Dispose();
}
enumerator.Dispose();
_TemporaryTargets.Clear();
}
private void OnProfilesChanged(Water water)
{
Water.WeightedProfile[] profiles = water.ProfilesManager.Profiles;
if (profiles != null)
{
float num = 0f;
for (int num2 = profiles.Length - 1; num2 >= 0; num2--)
{
Water.WeightedProfile weightedProfile = profiles[num2];
WaterProfileData profile = weightedProfile.Profile;
float weight = weightedProfile.Weight;
num += profile.PlanarReflectionIntensity * weight;
}
_RenderPlanarReflections = num > 0f;
}
}
private void SetCameraSettings(Camera source, Camera destination)
{
destination.backgroundColor = new Color(0f, 0f, 0f, 0f);
destination.fieldOfView = source.fieldOfView;
destination.aspect = source.aspect;
destination.allowHDR = _SystemSupportsHdr && source.allowHDR;
}
private Vector3 CalculateReflectionPosition(Camera camera)
{
Vector3 position = camera.transform.position;
position.y = _Water.transform.position.y - position.y;
return position;
}
private static Vector3 CalculateReflectionAngles(Camera camera)
{
Vector3 eulerAngles = camera.transform.eulerAngles;
return new Vector3(0f - eulerAngles.x, eulerAngles.y, eulerAngles.z);
}
}
}