升级6.4.升级水,升级天气
This commit is contained in:
@@ -10,6 +10,7 @@ using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
using UnityEngine.Rendering.HighDefinition;
|
||||
using UnityEngine.Rendering.Universal;
|
||||
using WaveHarmonic.Crest.Internal;
|
||||
|
||||
namespace WaveHarmonic.Crest
|
||||
{
|
||||
@@ -36,13 +37,8 @@ namespace WaveHarmonic.Crest
|
||||
/// Renders reflections for water. Currently on planar reflections.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public sealed partial class WaterReflections
|
||||
public sealed partial class WaterReflections : Versioned
|
||||
{
|
||||
[SerializeField, HideInInspector]
|
||||
#pragma warning disable 414
|
||||
int _Version = 0;
|
||||
#pragma warning restore 414
|
||||
|
||||
[@Space(10)]
|
||||
|
||||
[@Label("Enable")]
|
||||
@@ -55,7 +51,7 @@ namespace WaveHarmonic.Crest
|
||||
[@Heading("Capture")]
|
||||
|
||||
[Tooltip("What side of the water surface to render planar reflections for.")]
|
||||
[@GenerateAPI(name: "ReflectionSide")]
|
||||
[@GenerateAPI(Setter.Custom, name: "ReflectionSide")]
|
||||
[@DecoratedField, SerializeField]
|
||||
internal WaterReflectionSide _Mode = WaterReflectionSide.Above;
|
||||
|
||||
@@ -69,10 +65,11 @@ namespace WaveHarmonic.Crest
|
||||
[@Delayed, SerializeField]
|
||||
int _Resolution = 256;
|
||||
|
||||
[Tooltip("Whether to render to the viewer camera only.\n\nWhen disabled, reflections will render for all cameras rendering the water layer, which currently this prevents Refresh Rate from working. Enabling will unlock the Refresh Rate heading.")]
|
||||
[Tooltip("Overscan amount to capture off-screen content.\n\nRenders the reflections at a larger viewport size to capture off-screen content when the surface reflects off-screen. This avoids a category of artifacts - especially when looking down. This can be expensive, as the value is a multiplier to the capture size.")]
|
||||
[@Range(1, 2)]
|
||||
[@GenerateAPI]
|
||||
[@DecoratedField, SerializeField]
|
||||
internal bool _RenderOnlySingleCamera;
|
||||
[SerializeField]
|
||||
float _Overscan = 1.5f;
|
||||
|
||||
[@Space(10)]
|
||||
|
||||
@@ -88,7 +85,7 @@ namespace WaveHarmonic.Crest
|
||||
|
||||
#pragma warning disable 414
|
||||
[Tooltip("Disables shadows.")]
|
||||
[@GenerateAPI]
|
||||
[@GenerateAPI(Setter.Custom)]
|
||||
[@DecoratedField, SerializeField]
|
||||
bool _DisableShadows = true;
|
||||
#pragma warning restore 414
|
||||
@@ -103,11 +100,6 @@ namespace WaveHarmonic.Crest
|
||||
[@DecoratedField, SerializeField]
|
||||
bool _Stencil = false;
|
||||
|
||||
[Tooltip("Whether to allow MSAA.")]
|
||||
[@GenerateAPI]
|
||||
[@DecoratedField, SerializeField]
|
||||
bool _AllowMSAA = false;
|
||||
|
||||
[@Space(10)]
|
||||
|
||||
[Tooltip("Overrides global quality settings.")]
|
||||
@@ -144,11 +136,11 @@ namespace WaveHarmonic.Crest
|
||||
[@Heading("Refresh Rate")]
|
||||
|
||||
[Tooltip("Refresh reflection every x frames (one is every frame)")]
|
||||
[@Predicated(nameof(_RenderOnlySingleCamera))]
|
||||
[@Enable(nameof(_RenderOnlySingleCamera))]
|
||||
[@DecoratedField, SerializeField]
|
||||
int _RefreshPerFrames = 1;
|
||||
|
||||
[@Predicated(nameof(_RenderOnlySingleCamera))]
|
||||
[@Enable(nameof(_RenderOnlySingleCamera))]
|
||||
[@DecoratedField, SerializeField]
|
||||
int _FrameRefreshOffset = 0;
|
||||
|
||||
@@ -162,19 +154,34 @@ namespace WaveHarmonic.Crest
|
||||
bool _UseObliqueMatrix = true;
|
||||
|
||||
[Tooltip("Planar relfections using an oblique frustum for better performance.\n\nThis can cause depth issues for TIRs, especially near the surface.")]
|
||||
[@Predicated(nameof(_UseObliqueMatrix))]
|
||||
[@Enable(nameof(_UseObliqueMatrix))]
|
||||
[@GenerateAPI]
|
||||
[@DecoratedField, SerializeField]
|
||||
bool _NonObliqueNearSurface;
|
||||
|
||||
[Tooltip("If within this distance from the surface, disable the oblique matrix.")]
|
||||
[@Predicated(nameof(_NonObliqueNearSurface))]
|
||||
[@Predicated(nameof(_UseObliqueMatrix))]
|
||||
[@Enable(nameof(_NonObliqueNearSurface))]
|
||||
[@Enable(nameof(_UseObliqueMatrix))]
|
||||
[@GenerateAPI]
|
||||
[@DecoratedField, SerializeField]
|
||||
float _NonObliqueNearSurfaceThreshold = 0.05f;
|
||||
|
||||
|
||||
[@Heading("Advanced")]
|
||||
|
||||
[Tooltip("Whether to render to the viewer camera only.\n\nWhen disabled, reflections will render for all cameras rendering the water layer, which currently this prevents Refresh Rate from working. Enabling will unlock the Refresh Rate heading.")]
|
||||
[@GenerateAPI]
|
||||
[@DecoratedField, SerializeField]
|
||||
internal bool _RenderOnlySingleCamera;
|
||||
|
||||
[Tooltip("Renderer index for the reflection camera.")]
|
||||
[@Show(RenderPipeline.Universal)]
|
||||
[@Minimum(0)]
|
||||
[@GenerateAPI(Setter.Custom)]
|
||||
[@DecoratedField]
|
||||
[@SerializeField]
|
||||
int _RendererIndex;
|
||||
|
||||
[@Space(10)]
|
||||
|
||||
[@DecoratedField, SerializeField]
|
||||
@@ -189,66 +196,91 @@ namespace WaveHarmonic.Crest
|
||||
[Tooltip("Rendering reflections per-camera requires recursive rendering. Check this toggle if experiencing issues. The other downside without it is a one-frame delay.")]
|
||||
[@DecoratedField, SerializeField]
|
||||
internal bool _DisableRecursiveRendering;
|
||||
|
||||
[Tooltip("Whether to create a context more compatible for planar reflections camera. Try enabling this if you are getting exceptions.")]
|
||||
[@Show(RenderPipeline.Universal)]
|
||||
[@DecoratedField]
|
||||
[SerializeField]
|
||||
internal bool _ForceCompatibility;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// What side of the water surface to render planar reflections for.
|
||||
/// </summary>
|
||||
public WaterReflectionSide Mode { get => _Mode; set => _Mode = value; }
|
||||
|
||||
|
||||
static class ShaderIDs
|
||||
{
|
||||
public static int s_ReflectionTexture = Shader.PropertyToID("_Crest_ReflectionTexture");
|
||||
public static int s_ReflectionColorTexture = Shader.PropertyToID("_Crest_ReflectionColorTexture");
|
||||
public static int s_ReflectionDepthTexture = Shader.PropertyToID("_Crest_ReflectionDepthTexture");
|
||||
public static int s_ReflectionPositionNormal = Shader.PropertyToID("_Crest_ReflectionPositionNormal");
|
||||
}
|
||||
public static readonly int s_ReflectionMatrixIVP = Shader.PropertyToID("_Crest_ReflectionMatrixIVP");
|
||||
public static readonly int s_ReflectionMatrixV = Shader.PropertyToID("_Crest_ReflectionMatrixV");
|
||||
public static readonly int s_Crest_ReflectionOverscan = Shader.PropertyToID("_Crest_ReflectionOverscan");
|
||||
|
||||
// Checked in underwater to filter cameras.
|
||||
internal static Camera CurrentCamera { get; private set; }
|
||||
public static readonly int s_PlanarReflectionsApplySmoothness = Shader.PropertyToID("_Crest_PlanarReflectionsApplySmoothness");
|
||||
}
|
||||
|
||||
internal WaterRenderer _Water;
|
||||
internal UnderwaterRenderer _UnderWater;
|
||||
|
||||
RenderTexture _ReflectionTexture;
|
||||
internal RenderTexture ReflectionTexture => _ReflectionTexture;
|
||||
bool _ApplySmoothness;
|
||||
|
||||
RenderTexture _ColorTexture;
|
||||
RenderTexture _DepthTexture;
|
||||
internal RenderTexture ColorTexture => _ColorTexture;
|
||||
internal RenderTexture DepthTexture => _DepthTexture;
|
||||
readonly Vector4[] _ReflectionPositionNormal = new Vector4[2];
|
||||
readonly Matrix4x4[] _ReflectionMatrixIVP = new Matrix4x4[2];
|
||||
readonly Matrix4x4[] _ReflectionMatrixV = new Matrix4x4[2];
|
||||
|
||||
internal int _ActiveSlice;
|
||||
|
||||
Camera _CameraViewpoint;
|
||||
Skybox _CameraViewpointSkybox;
|
||||
Camera _CameraReflections;
|
||||
Skybox _CameraReflectionsSkybox;
|
||||
internal Camera ReflectionCamera => _CameraReflections;
|
||||
|
||||
int RefreshPerFrames => _RenderOnlySingleCamera ? _RefreshPerFrames : 1;
|
||||
long _LastRefreshOnFrame = -1;
|
||||
|
||||
internal bool SupportsRecursiveRendering =>
|
||||
#if !UNITY_6000_0_OR_NEWER
|
||||
// HDRP cannot recursive render for 2022.
|
||||
!RenderPipelineHelper.IsHighDefinition &&
|
||||
#endif
|
||||
!_Debug._DisableRecursiveRendering;
|
||||
internal bool SupportsRecursiveRendering => _Water.SupportsRecursiveRendering && !_Debug._DisableRecursiveRendering;
|
||||
|
||||
readonly float[] _CullDistances = new float[32];
|
||||
|
||||
Texture _CameraDepthTexture;
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when the reflection camera is created.
|
||||
/// </summary>
|
||||
public static Action<Camera> OnCameraAdded { get; set; }
|
||||
|
||||
bool RequireTemporaryTargets =>
|
||||
#if UNITY_6000_0_OR_NEWER && d_UnityURP
|
||||
// As of Unity 6 we can write directly to a slice for URP.
|
||||
!RenderPipelineHelper.IsUniversal &&
|
||||
#endif
|
||||
true;
|
||||
|
||||
internal void OnEnable()
|
||||
{
|
||||
_CameraViewpoint = _Water.Viewer;
|
||||
_CameraViewpointSkybox = _CameraViewpoint.GetComponent<Skybox>();
|
||||
// We initialized here previously to fix the first frame being black, but could not
|
||||
// replicate anymore.
|
||||
|
||||
// This is called also called every frame, but was required here as there was a
|
||||
// black reflection for a frame without this earlier setup call.
|
||||
CreateWaterObjects(_CameraViewpoint);
|
||||
#if d_UnityURP
|
||||
#if UNITY_6000_0_OR_NEWER
|
||||
RenderPipelineManager.beginCameraRendering -= CaptureTargetDepth;
|
||||
RenderPipelineManager.beginCameraRendering += CaptureTargetDepth;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
internal void OnDisable()
|
||||
{
|
||||
Shader.SetGlobalTexture(ShaderIDs.s_ReflectionTexture, Texture2D.blackTexture);
|
||||
Shader.SetGlobalTexture(ShaderIDs.s_ReflectionColorTexture, Texture2D.blackTexture);
|
||||
Shader.SetGlobalTexture(ShaderIDs.s_ReflectionDepthTexture, Texture2D.blackTexture);
|
||||
|
||||
#if d_UnityURP
|
||||
#if UNITY_6000_0_OR_NEWER
|
||||
RenderPipelineManager.beginCameraRendering -= CaptureTargetDepth;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
internal void OnDestroy()
|
||||
@@ -259,18 +291,30 @@ namespace WaveHarmonic.Crest
|
||||
_CameraReflections = null;
|
||||
}
|
||||
|
||||
if (_ReflectionTexture)
|
||||
if (_ColorTexture)
|
||||
{
|
||||
_ReflectionTexture.Release();
|
||||
Helpers.Destroy(_ReflectionTexture);
|
||||
_ReflectionTexture = null;
|
||||
_ColorTexture.Release();
|
||||
Helpers.Destroy(_ColorTexture);
|
||||
_ColorTexture = null;
|
||||
}
|
||||
|
||||
if (_DepthTexture)
|
||||
{
|
||||
_DepthTexture.Release();
|
||||
Helpers.Destroy(_DepthTexture);
|
||||
_DepthTexture = null;
|
||||
}
|
||||
}
|
||||
|
||||
bool ShouldRender(Camera camera)
|
||||
internal bool ShouldRender(Camera camera)
|
||||
{
|
||||
if (!_Enabled)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// If no surface, then do not execute the reflection camera.
|
||||
if (!WaterRenderer.ShouldRender(camera, _Water.Surface.Layer))
|
||||
if (!_Water._ActiveModules.HasFlag(WaterRenderer.ActiveModules.Surface))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -278,7 +322,7 @@ namespace WaveHarmonic.Crest
|
||||
// This method could be executed twice: once by the camera rendering the surface,
|
||||
// and once again by the planar reflection camera. For the latter, we do not want
|
||||
// to proceed or infinite recursion. For safety.
|
||||
if (camera == CurrentCamera)
|
||||
if (camera == _CameraReflections)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -294,11 +338,6 @@ namespace WaveHarmonic.Crest
|
||||
|
||||
internal void OnBeginCameraRendering(ScriptableRenderContext context, Camera camera)
|
||||
{
|
||||
if (!ShouldRender(camera))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (SupportsRecursiveRendering)
|
||||
{
|
||||
// This option only valid for recursive, otherwise, it is always single camera.
|
||||
@@ -314,18 +353,44 @@ namespace WaveHarmonic.Crest
|
||||
if (camera == _CameraViewpoint)
|
||||
{
|
||||
// TODO: Emit an event instead so WBs can listen.
|
||||
Shader.SetGlobalTexture(ShaderIDs.s_ReflectionTexture, _ReflectionTexture);
|
||||
Shader.SetGlobalTexture(ShaderIDs.s_ReflectionColorTexture, _ColorTexture);
|
||||
Shader.SetGlobalTexture(ShaderIDs.s_ReflectionDepthTexture, _DepthTexture);
|
||||
}
|
||||
}
|
||||
|
||||
internal void OnEndReflectionCameraRendering(Camera camera)
|
||||
{
|
||||
if (camera == ReflectionCamera)
|
||||
{
|
||||
// Appears to be the only reasonable way to get camera depth separately for SRPs.
|
||||
_CameraDepthTexture = Shader.GetGlobalTexture(Crest.ShaderIDs.Unity.s_CameraDepthTexture);
|
||||
}
|
||||
}
|
||||
|
||||
internal void OnEndCameraRendering(Camera camera)
|
||||
{
|
||||
if (!ShouldRender(camera))
|
||||
Shader.SetGlobalTexture(ShaderIDs.s_ReflectionColorTexture, Texture2D.blackTexture);
|
||||
}
|
||||
|
||||
internal void LateUpdate()
|
||||
{
|
||||
// Check if enabled for at least one material every frame.
|
||||
_ApplySmoothness = false;
|
||||
|
||||
CheckSurfaceMaterial(_Water.Surface.Material);
|
||||
|
||||
foreach (var wb in WaterBody.WaterBodies)
|
||||
{
|
||||
CheckSurfaceMaterial(wb._Material);
|
||||
}
|
||||
|
||||
if (SupportsRecursiveRendering)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Shader.SetGlobalTexture(ShaderIDs.s_ReflectionTexture, Texture2D.blackTexture);
|
||||
// Passing a struct.
|
||||
LateUpdate(new());
|
||||
}
|
||||
|
||||
internal void LateUpdate(ScriptableRenderContext context)
|
||||
@@ -376,19 +441,18 @@ namespace WaveHarmonic.Crest
|
||||
UpdateCameraModes();
|
||||
ForceDistanceCulling(_FarClipPlane);
|
||||
|
||||
_CameraReflections.targetTexture = _ReflectionTexture;
|
||||
|
||||
// TODO: Do not do this every frame.
|
||||
if (_Mode != WaterReflectionSide.Both)
|
||||
{
|
||||
Helpers.ClearRenderTexture(_ReflectionTexture, Color.clear, depth: false);
|
||||
Helpers.ClearRenderTexture(_ColorTexture, Color.clear, depth: true);
|
||||
Helpers.ClearRenderTexture(_DepthTexture, Color.clear, depth: true);
|
||||
}
|
||||
|
||||
var isActive = _Water.Surface.Root.gameObject.activeSelf;
|
||||
|
||||
// We do not want the water plane when rendering planar reflections.
|
||||
_Water.Surface.Root.gameObject.SetActive(false);
|
||||
|
||||
CurrentCamera = _CameraReflections;
|
||||
|
||||
// Optionally disable pixel lights for reflection/refraction
|
||||
var oldPixelLightCount = QualitySettings.pixelLightCount;
|
||||
if (_DisablePixelLights)
|
||||
@@ -436,8 +500,7 @@ namespace WaveHarmonic.Crest
|
||||
|
||||
_QualitySettingsOverride.Restore();
|
||||
|
||||
CurrentCamera = null;
|
||||
_Water.Surface.Root.gameObject.SetActive(true);
|
||||
_Water.Surface.Root.gameObject.SetActive(isActive);
|
||||
|
||||
// Remember this frame as last refreshed.
|
||||
_LastRefreshOnFrame = Time.renderedFrameCount;
|
||||
@@ -446,41 +509,60 @@ namespace WaveHarmonic.Crest
|
||||
|
||||
void Render(ScriptableRenderContext context)
|
||||
{
|
||||
#if UNITY_6000_0_OR_NEWER && d_UnityURP
|
||||
_CameraReflections.targetTexture = _ReflectionTexture;
|
||||
#else
|
||||
var descriptor = _ReflectionTexture.descriptor;
|
||||
descriptor.dimension = TextureDimension.Tex2D;
|
||||
descriptor.volumeDepth = 1;
|
||||
descriptor.useMipMap = false;
|
||||
// No need to clear, as camera clears using the skybox.
|
||||
var target = RenderTexture.GetTemporary(descriptor);
|
||||
_CameraReflections.targetTexture = target;
|
||||
#endif
|
||||
var colorTarget = _ColorTexture;
|
||||
var depthTarget = _DepthTexture;
|
||||
|
||||
if (RequireTemporaryTargets)
|
||||
{
|
||||
var descriptor = _ColorTexture.descriptor;
|
||||
descriptor.dimension = TextureDimension.Tex2D;
|
||||
descriptor.volumeDepth = 1;
|
||||
descriptor.useMipMap = false;
|
||||
// No need to clear, as camera clears using the skybox.
|
||||
colorTarget = RenderTexture.GetTemporary(descriptor);
|
||||
|
||||
if (RenderPipelineHelper.IsLegacy)
|
||||
{
|
||||
descriptor = _DepthTexture.descriptor;
|
||||
descriptor.dimension = TextureDimension.Tex2D;
|
||||
descriptor.volumeDepth = 1;
|
||||
descriptor.useMipMap = false;
|
||||
// No need to clear, as camera clears using the skybox.
|
||||
depthTarget = RenderTexture.GetTemporary(descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
if (RenderPipelineHelper.IsLegacy)
|
||||
{
|
||||
// Not documented, but does not work for SRPs.
|
||||
_CameraReflections.SetTargetBuffers(colorTarget.colorBuffer, depthTarget.depthBuffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
_CameraReflections.targetTexture = colorTarget;
|
||||
}
|
||||
|
||||
if (_Mode != WaterReflectionSide.Below)
|
||||
{
|
||||
_ReflectionPositionNormal[0] = ComputeHorizonPositionAndNormal(_CameraReflections, _Water.SeaLevel, 0.05f, false);
|
||||
|
||||
if (_UnderWater._Enabled)
|
||||
{
|
||||
// Disable underwater layer. It is the only way to exclude probes.
|
||||
_CameraReflections.cullingMask = _Layers & ~(1 << _UnderWater.Layer);
|
||||
}
|
||||
|
||||
_ActiveSlice = 0;
|
||||
|
||||
RenderCamera(context, _CameraReflections, Vector3.up, false, 0);
|
||||
|
||||
#if !(UNITY_6000_0_OR_NEWER && d_UnityURP)
|
||||
Graphics.CopyTexture(target, 0, 0, _ReflectionTexture, 0, 0);
|
||||
#endif
|
||||
CopyTargets(colorTarget, depthTarget, 0);
|
||||
|
||||
_ReflectionPositionNormal[0] = ComputeHorizonPositionAndNormal(_CameraReflections, _Water.SeaLevel, 0.5f / _Resolution, false);
|
||||
|
||||
_CameraReflections.ResetProjectionMatrix();
|
||||
}
|
||||
|
||||
if (_Mode != WaterReflectionSide.Above)
|
||||
{
|
||||
_ReflectionPositionNormal[1] = ComputeHorizonPositionAndNormal(_CameraReflections, _Water.SeaLevel, -0.05f, true);
|
||||
|
||||
if (_UnderWater._Enabled)
|
||||
{
|
||||
// Enable underwater layer.
|
||||
@@ -489,22 +571,34 @@ namespace WaveHarmonic.Crest
|
||||
_CameraReflections.depthTextureMode = DepthTextureMode.Depth;
|
||||
}
|
||||
|
||||
_ActiveSlice = 1;
|
||||
|
||||
RenderCamera(context, _CameraReflections, Vector3.down, _NonObliqueNearSurface, 1);
|
||||
|
||||
#if !(UNITY_6000_0_OR_NEWER && d_UnityURP)
|
||||
Graphics.CopyTexture(target, 0, 0, _ReflectionTexture, 1, 0);
|
||||
#endif
|
||||
CopyTargets(colorTarget, depthTarget, 1);
|
||||
|
||||
_ReflectionPositionNormal[1] = ComputeHorizonPositionAndNormal(_CameraReflections, _Water.SeaLevel, -0.05f, true);
|
||||
|
||||
_CameraReflections.ResetProjectionMatrix();
|
||||
}
|
||||
|
||||
#if !(UNITY_6000_0_OR_NEWER && d_UnityURP)
|
||||
RenderTexture.ReleaseTemporary(target);
|
||||
if (RequireTemporaryTargets)
|
||||
{
|
||||
RenderTexture.ReleaseTemporary(colorTarget);
|
||||
if (RenderPipelineHelper.IsLegacy) RenderTexture.ReleaseTemporary(depthTarget);
|
||||
}
|
||||
|
||||
#if !d_Crest_DisablePlanarReflectionApplySmoothness
|
||||
if (_ApplySmoothness)
|
||||
{
|
||||
// We are only using mip-maps if applying smoothness/roughness.
|
||||
_ColorTexture.GenerateMips();
|
||||
}
|
||||
#endif
|
||||
|
||||
_ReflectionTexture.GenerateMips();
|
||||
|
||||
Shader.SetGlobalVectorArray(ShaderIDs.s_ReflectionPositionNormal, _ReflectionPositionNormal);
|
||||
Shader.SetGlobalMatrixArray(ShaderIDs.s_ReflectionMatrixIVP, _ReflectionMatrixIVP);
|
||||
Shader.SetGlobalMatrixArray(ShaderIDs.s_ReflectionMatrixV, _ReflectionMatrixV);
|
||||
}
|
||||
|
||||
void RenderCamera(ScriptableRenderContext context, Camera camera, Vector3 planeNormal, bool nonObliqueNearSurface, int slice)
|
||||
@@ -517,10 +611,9 @@ namespace WaveHarmonic.Crest
|
||||
var viewpoint = _CameraViewpoint.transform;
|
||||
if (offset == 0f && viewpoint.position.y == planePosition.y)
|
||||
{
|
||||
// Minor offset to prevent "Screen position out of view frustum". Smallest number
|
||||
// to work with both above and below. Smallest number to work with both above and
|
||||
// below. Could be BIRP only.
|
||||
offset = 0.00001f;
|
||||
// Minor offset to prevent "Screen position out of view frustum". Needs to scale
|
||||
// with distance from center.
|
||||
offset = viewpoint.position.magnitude >= 15000f ? 0.01f : 0.001f;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -539,7 +632,12 @@ namespace WaveHarmonic.Crest
|
||||
|
||||
if (_UseObliqueMatrix && (!nonObliqueNearSurface || Mathf.Abs(_CameraViewpoint.transform.position.y - planePosition.y) > _NonObliqueNearSurfaceThreshold))
|
||||
{
|
||||
camera.projectionMatrix = _CameraViewpoint.CalculateObliqueMatrix(clipPlane);
|
||||
var matrix = _CameraViewpoint.CalculateObliqueMatrix(clipPlane);
|
||||
// Overscan.
|
||||
var overscan = 1f - (_Overscan - 1f) * 0.5f;
|
||||
matrix[0, 0] *= overscan;
|
||||
matrix[1, 1] *= overscan;
|
||||
camera.projectionMatrix = matrix;
|
||||
}
|
||||
|
||||
// Set custom culling matrix from the current camera
|
||||
@@ -550,9 +648,12 @@ namespace WaveHarmonic.Crest
|
||||
camera.transform.eulerAngles = new(-euler.x, euler.y, euler.z);
|
||||
camera.cullingMatrix = camera.projectionMatrix * camera.worldToCameraMatrix;
|
||||
|
||||
_ReflectionMatrixV[slice] = camera.worldToCameraMatrix;
|
||||
_ReflectionMatrixIVP[slice] = (GL.GetGPUProjectionMatrix(camera.projectionMatrix, true) * camera.worldToCameraMatrix).inverse;
|
||||
|
||||
if (SupportsRecursiveRendering)
|
||||
{
|
||||
Helpers.RenderCamera(camera, context, slice);
|
||||
Helpers.RenderCamera(camera, context, slice, _Debug._ForceCompatibility);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -560,6 +661,35 @@ namespace WaveHarmonic.Crest
|
||||
}
|
||||
}
|
||||
|
||||
void CopyTargets(Texture color, Texture depth, int slice)
|
||||
{
|
||||
if (RequireTemporaryTargets)
|
||||
{
|
||||
Graphics.CopyTexture(color, 0, 0, 0, 0, _Resolution, _Resolution, _ColorTexture, slice, 0, 0, 0);
|
||||
}
|
||||
|
||||
if (!RenderPipelineHelper.IsLegacy)
|
||||
{
|
||||
depth = _CameraDepthTexture;
|
||||
}
|
||||
|
||||
if (Rendering.IsRenderGraph)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// This can change between depth and R32 based on settings.
|
||||
if (depth != null && depth.graphicsFormat != _DepthTexture.graphicsFormat)
|
||||
{
|
||||
RecreateDepth(depth);
|
||||
}
|
||||
|
||||
if (depth != null && depth.width >= _Resolution)
|
||||
{
|
||||
Graphics.CopyTexture(depth, 0, 0, 0, 0, _Resolution, _Resolution, _DepthTexture, slice, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Limit render distance for reflection camera for first 32 layers
|
||||
/// </summary>
|
||||
@@ -611,6 +741,7 @@ namespace WaveHarmonic.Crest
|
||||
{
|
||||
// Destroy otherwise skybox will not render if empty.
|
||||
Helpers.Destroy(_CameraViewpointSkybox);
|
||||
_CameraViewpointSkybox = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -623,54 +754,125 @@ namespace WaveHarmonic.Crest
|
||||
_CameraReflections.orthographic = _CameraViewpoint.orthographic;
|
||||
_CameraReflections.fieldOfView = _CameraViewpoint.fieldOfView;
|
||||
_CameraReflections.orthographicSize = _CameraViewpoint.orthographicSize;
|
||||
_CameraReflections.allowMSAA = _AllowMSAA;
|
||||
_CameraReflections.allowMSAA = false;
|
||||
_CameraReflections.aspect = _CameraViewpoint.aspect;
|
||||
_CameraReflections.useOcclusionCulling = !_DisableOcclusionCulling && _CameraViewpoint.useOcclusionCulling;
|
||||
_CameraReflections.depthTextureMode = _CameraViewpoint.depthTextureMode;
|
||||
|
||||
// Overscan
|
||||
{
|
||||
_CameraReflections.usePhysicalProperties = _Overscan > 1f;
|
||||
|
||||
var baseSensor = new Vector2(36f, 24f);
|
||||
var focal = (baseSensor.y * 0.5f) / Mathf.Tan(_CameraViewpoint.fieldOfView * 0.5f * Mathf.Deg2Rad);
|
||||
|
||||
var overscan = 1f - (_Overscan - 1f) * 0.5f;
|
||||
_CameraReflections.sensorSize = baseSensor / overscan;
|
||||
_CameraReflections.focalLength = focal;
|
||||
|
||||
Shader.SetGlobalFloat(ShaderIDs.s_Crest_ReflectionOverscan, overscan);
|
||||
}
|
||||
}
|
||||
|
||||
void RecreateDepth(Texture depth)
|
||||
{
|
||||
if (_DepthTexture != null && _DepthTexture.IsCreated())
|
||||
{
|
||||
_DepthTexture.Release();
|
||||
_DepthTexture.descriptor = depth.GetDescriptor();
|
||||
}
|
||||
else
|
||||
{
|
||||
_DepthTexture = new(depth.GetDescriptor());
|
||||
}
|
||||
|
||||
_DepthTexture.name = "_Crest_ReflectionDepth";
|
||||
_DepthTexture.width = _DepthTexture.height = _Resolution;
|
||||
_DepthTexture.isPowerOfTwo = true;
|
||||
_DepthTexture.useMipMap = false;
|
||||
_DepthTexture.autoGenerateMips = false;
|
||||
_DepthTexture.filterMode = FilterMode.Point;
|
||||
_DepthTexture.volumeDepth = 2;
|
||||
_DepthTexture.dimension = TextureDimension.Tex2DArray;
|
||||
_DepthTexture.Create();
|
||||
}
|
||||
|
||||
// On-demand create any objects we need for water
|
||||
void CreateWaterObjects(Camera currentCamera)
|
||||
{
|
||||
var format = _HDR ? RenderTextureFormat.ARGBHalf : RenderTextureFormat.ARGB32;
|
||||
var stencil = _Stencil ? 24 : 16;
|
||||
// We cannot exclude stencil for URP, as the depth texture format always has it.
|
||||
var colorFormat = Rendering.GetDefaultColorFormat(_HDR);
|
||||
var depthFormat = Rendering.GetDefaultDepthFormat(_Stencil || RenderPipelineHelper.IsUniversal);
|
||||
|
||||
// Reflection render texture
|
||||
if (!_ReflectionTexture || _ReflectionTexture.width != _Resolution || _ReflectionTexture.format != format || _ReflectionTexture.depth != stencil)
|
||||
if (!_ColorTexture || _ColorTexture.width != _Resolution || _ColorTexture.graphicsFormat != colorFormat || _ColorTexture.depthStencilFormat != depthFormat)
|
||||
{
|
||||
if (_ReflectionTexture)
|
||||
if (_ColorTexture)
|
||||
{
|
||||
Helpers.Destroy(_ReflectionTexture);
|
||||
Helpers.Destroy(_ColorTexture);
|
||||
Helpers.Destroy(_DepthTexture);
|
||||
}
|
||||
|
||||
Debug.Assert(SystemInfo.SupportsRenderTextureFormat(format), "Crest: The graphics device does not support the render texture format " + format.ToString());
|
||||
_ReflectionTexture = new(_Resolution, _Resolution, stencil, format)
|
||||
var descriptor = new RenderTextureDescriptor(_Resolution, _Resolution)
|
||||
{
|
||||
name = "_Crest_WaterReflection",
|
||||
isPowerOfTwo = true,
|
||||
dimension = TextureDimension.Tex2DArray,
|
||||
volumeDepth = 2,
|
||||
depthStencilFormat = depthFormat,
|
||||
msaaSamples = 1,
|
||||
useMipMap = false,
|
||||
};
|
||||
|
||||
_ColorTexture = new(descriptor)
|
||||
{
|
||||
name = "_Crest_ReflectionColor",
|
||||
graphicsFormat = colorFormat,
|
||||
isPowerOfTwo = true,
|
||||
#if !d_Crest_DisablePlanarReflectionApplySmoothness
|
||||
useMipMap = true,
|
||||
#endif
|
||||
autoGenerateMips = false,
|
||||
filterMode = FilterMode.Trilinear,
|
||||
};
|
||||
_ReflectionTexture.Create();
|
||||
_ColorTexture.Create();
|
||||
|
||||
_DepthTexture = new(descriptor)
|
||||
{
|
||||
name = "_Crest_ReflectionDepth",
|
||||
graphicsFormat = UnityEngine.Experimental.Rendering.GraphicsFormat.None,
|
||||
isPowerOfTwo = true,
|
||||
useMipMap = false,
|
||||
autoGenerateMips = false,
|
||||
filterMode = FilterMode.Point,
|
||||
};
|
||||
|
||||
if (RenderPipelineHelper.IsHighDefinition)
|
||||
{
|
||||
_DepthTexture.graphicsFormat = UnityEngine.Experimental.Rendering.GraphicsFormat.R32_SFloat;
|
||||
_DepthTexture.depthStencilFormat = UnityEngine.Experimental.Rendering.GraphicsFormat.None;
|
||||
}
|
||||
|
||||
_DepthTexture.Create();
|
||||
}
|
||||
|
||||
var create = _CameraReflections == null;
|
||||
|
||||
// Camera for reflection
|
||||
if (!_CameraReflections)
|
||||
if (create)
|
||||
{
|
||||
var go = new GameObject("_Crest_WaterReflectionCamera");
|
||||
go.transform.SetParent(_Water.Container.transform, worldPositionStays: true);
|
||||
_CameraReflections = go.AddComponent<Camera>();
|
||||
_CameraReflections.enabled = false;
|
||||
_CameraReflections.cullingMask = _Layers;
|
||||
_CameraReflections.cameraType = CameraType.Reflection;
|
||||
_CameraReflections.backgroundColor = Color.clear;
|
||||
|
||||
if (RenderPipelineHelper.IsLegacy)
|
||||
{
|
||||
#pragma warning disable IDE0079
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
||||
_CameraReflections.gameObject.AddComponent<FlareLayer>();
|
||||
#pragma warning restore CS0618 // Type or member is obsolete
|
||||
#pragma warning restore IDE0079
|
||||
}
|
||||
|
||||
#if d_UnityHDRP
|
||||
@@ -690,15 +892,34 @@ namespace WaveHarmonic.Crest
|
||||
if (RenderPipelineHelper.IsUniversal)
|
||||
{
|
||||
var additionalCameraData = _CameraReflections.gameObject.AddComponent<UniversalAdditionalCameraData>();
|
||||
additionalCameraData.renderShadows = !_DisableShadows;
|
||||
additionalCameraData.requiresColorTexture = false;
|
||||
additionalCameraData.requiresDepthTexture = false;
|
||||
additionalCameraData.requiresDepthTexture = true;
|
||||
}
|
||||
#endif
|
||||
OnCameraAdded?.Invoke(_CameraReflections);
|
||||
|
||||
_UpdateCamera = true;
|
||||
}
|
||||
|
||||
_CameraReflections.gameObject.hideFlags = _Debug._ShowHiddenObjects ? HideFlags.DontSave : HideFlags.HideAndDontSave;
|
||||
if (_UpdateCamera)
|
||||
{
|
||||
_CameraReflections.gameObject.hideFlags = _Debug._ShowHiddenObjects ? HideFlags.DontSave : HideFlags.HideAndDontSave;
|
||||
|
||||
#if d_UnityURP
|
||||
if (RenderPipelineHelper.IsUniversal)
|
||||
{
|
||||
var additionalCameraData = _CameraReflections.GetUniversalAdditionalCameraData();
|
||||
additionalCameraData.SetRenderer(_RendererIndex);
|
||||
additionalCameraData.renderShadows = !_DisableShadows; // Does not appear to work!
|
||||
additionalCameraData.requiresColorTexture = _Mode != WaterReflectionSide.Above; // or incur assertions
|
||||
}
|
||||
#endif
|
||||
|
||||
_UpdateCamera = false;
|
||||
}
|
||||
|
||||
if (create)
|
||||
{
|
||||
OnCameraAdded?.Invoke(_CameraReflections);
|
||||
}
|
||||
}
|
||||
|
||||
// Given position/normal of the plane, calculates plane in camera space.
|
||||
@@ -856,14 +1077,34 @@ namespace WaveHarmonic.Crest
|
||||
positionWS.Dispose();
|
||||
}
|
||||
|
||||
normal = normal.normalized;
|
||||
|
||||
if (flipped)
|
||||
{
|
||||
normal = -normal;
|
||||
}
|
||||
else if (position.y == 0f)
|
||||
{
|
||||
// Sample anywhere if pointing downwards.
|
||||
position.y = 1f;
|
||||
}
|
||||
|
||||
return new(position.x, position.y, normal.x, normal.y);
|
||||
}
|
||||
|
||||
void CheckSurfaceMaterial(Material material)
|
||||
{
|
||||
if (material == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_ApplySmoothness)
|
||||
{
|
||||
_ApplySmoothness = material.GetBoolean(ShaderIDs.s_PlanarReflectionsApplySmoothness);
|
||||
}
|
||||
}
|
||||
|
||||
void SetEnabled(bool previous, bool current)
|
||||
{
|
||||
if (previous == current) return;
|
||||
@@ -871,6 +1112,26 @@ namespace WaveHarmonic.Crest
|
||||
if (_Enabled) OnEnable(); else OnDisable();
|
||||
}
|
||||
|
||||
bool _UpdateCamera;
|
||||
|
||||
void SetReflectionSide(WaterReflectionSide previous, WaterReflectionSide current)
|
||||
{
|
||||
if (previous == current) return;
|
||||
_UpdateCamera = true;
|
||||
}
|
||||
|
||||
void SetDisableShadows(bool previous, bool current)
|
||||
{
|
||||
if (previous == current) return;
|
||||
_UpdateCamera = true;
|
||||
}
|
||||
|
||||
void SetRendererIndex(int previous, int current)
|
||||
{
|
||||
if (previous == current) return;
|
||||
_UpdateCamera = true;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[@OnChange]
|
||||
void OnChange(string propertyPath, object previousValue)
|
||||
@@ -880,8 +1141,37 @@ namespace WaveHarmonic.Crest
|
||||
case nameof(_Enabled):
|
||||
SetEnabled((bool)previousValue, _Enabled);
|
||||
break;
|
||||
case nameof(_Debug) + "." + nameof(DebugFields._ShowHiddenObjects):
|
||||
_UpdateCamera = true;
|
||||
break;
|
||||
case nameof(_Mode):
|
||||
SetReflectionSide((WaterReflectionSide)previousValue, _Mode);
|
||||
break;
|
||||
case nameof(_DisableShadows):
|
||||
SetDisableShadows((bool)previousValue, _DisableShadows);
|
||||
break;
|
||||
case nameof(_RendererIndex):
|
||||
SetRendererIndex((int)previousValue, _RendererIndex);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
partial class WaterReflections
|
||||
{
|
||||
// MSAA would require separate textures to resolve to. Not worth the expense.
|
||||
[HideInInspector]
|
||||
[Obsolete("MSAA for the planar reflection camera is no longer supported. This setting will be ignored.")]
|
||||
[Tooltip("Whether to allow MSAA.")]
|
||||
[@GenerateAPI]
|
||||
[@DecoratedField, SerializeField]
|
||||
bool _AllowMSAA;
|
||||
|
||||
/// <summary>
|
||||
/// What side of the water surface to render planar reflections for.
|
||||
/// </summary>
|
||||
[Obsolete("Please use ReflectionSide instead.")]
|
||||
public WaterReflectionSide Mode { get => _Mode; set => _Mode = value; }
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user