备份CatanBuilding瘦身独立工程
This commit is contained in:
@@ -0,0 +1,181 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
#if URP
|
||||
using UnityEngine.Rendering.Universal;
|
||||
|
||||
namespace StylizedWater2
|
||||
{
|
||||
public class DisplacementPrePass : ScriptableRenderPass
|
||||
{
|
||||
private const string profilerTag = "Water Displacement Prepass";
|
||||
private static readonly ProfilingSampler profilerSampler = new ProfilingSampler(profilerTag);
|
||||
|
||||
public const string KEYWORD = "WATER_DISPLACEMENT_PASS";
|
||||
|
||||
[Serializable]
|
||||
public class Settings
|
||||
{
|
||||
public bool enable;
|
||||
|
||||
public float range = 500f;
|
||||
|
||||
[Range(0.1f, 4f)]
|
||||
public float cellSize = 0.25f;
|
||||
}
|
||||
|
||||
//Render pass
|
||||
FilteringSettings m_FilteringSettings;
|
||||
RenderStateBlock m_RenderStateBlock;
|
||||
private readonly List<ShaderTagId> m_ShaderTagIdList = new List<ShaderTagId>()
|
||||
{
|
||||
new ShaderTagId("DepthOnly")
|
||||
};
|
||||
|
||||
public DisplacementPrePass()
|
||||
{
|
||||
m_FilteringSettings = new FilteringSettings(RenderQueueRange.all, LayerMask.GetMask("Water"));
|
||||
m_RenderStateBlock = new RenderStateBlock(RenderStateMask.Nothing);
|
||||
}
|
||||
|
||||
private static readonly Quaternion viewRotation = Quaternion.Euler(new Vector3(90f, 0f, 0f));
|
||||
private static readonly Vector3 viewScale = new Vector3(1, 1, -1);
|
||||
private static Rect viewportRect;
|
||||
|
||||
private const string BufferName = "_WaterDisplacementBuffer";
|
||||
private static readonly int _WaterDisplacementBuffer = Shader.PropertyToID(BufferName);
|
||||
private const string CoordsName = "_WaterDisplacementCoords";
|
||||
private static readonly int _WaterDisplacementCoords = Shader.PropertyToID(CoordsName);
|
||||
|
||||
private RTHandle renderTarget;
|
||||
private static Vector3 centerPosition;
|
||||
private static Vector4 rendererCoords;
|
||||
|
||||
private static Matrix4x4 projection { set; get; }
|
||||
private static Matrix4x4 view { set; get; }
|
||||
|
||||
private int resolution;
|
||||
private int m_resolution;
|
||||
private float orthoSize;
|
||||
private Settings settings;
|
||||
|
||||
public void Setup(Settings settings)
|
||||
{
|
||||
this.settings = settings;
|
||||
|
||||
resolution = Mathf.CeilToInt(settings.range / settings.cellSize);
|
||||
resolution = Mathf.Clamp(resolution, 16, 2048);
|
||||
orthoSize = 0.5f * settings.range;
|
||||
}
|
||||
|
||||
//Important to snap the projection to the nearest texel. Otherwise pixel swimming is introduced when moving, due to bilinear filtering
|
||||
private static Vector3 StabilizeProjection(Vector3 pos, float texelSize)
|
||||
{
|
||||
float Snap(float coord, float cellSize) => Mathf.FloorToInt(coord / cellSize) * (cellSize) + (cellSize * 0.5f);
|
||||
|
||||
return new Vector3(Snap(pos.x, texelSize), Snap(pos.y, texelSize), Snap(pos.z, texelSize));
|
||||
}
|
||||
|
||||
private void SetupProjection(CommandBuffer cmd, Camera camera)
|
||||
{
|
||||
centerPosition = camera.transform.position;
|
||||
centerPosition += camera.transform.forward * settings.range * 0.5f;
|
||||
|
||||
centerPosition = StabilizeProjection(centerPosition, (settings.range) / resolution);
|
||||
|
||||
//var frustumHeight = 2.0f * renderRange * Mathf.Tan(camera.fieldOfView * 0.5f * Mathf.Deg2Rad); //Still clips, plus doesn't support orthographc
|
||||
var frustumHeight = settings.range;
|
||||
centerPosition += (Vector3.up * frustumHeight * 0.5f);
|
||||
|
||||
projection = Matrix4x4.Ortho(-orthoSize, orthoSize, -orthoSize, orthoSize, 0.03f, frustumHeight * 2f);
|
||||
|
||||
view = Matrix4x4.TRS(centerPosition, viewRotation, viewScale).inverse;
|
||||
|
||||
cmd.SetViewProjectionMatrices(view, projection);
|
||||
//RenderingUtils.SetViewAndProjectionMatrices(cmd, view, projection, true);
|
||||
|
||||
viewportRect.width = resolution;
|
||||
viewportRect.height = resolution;
|
||||
cmd.SetViewport(viewportRect);
|
||||
|
||||
cmd.SetGlobalMatrix("UNITY_MATRIX_V", view);
|
||||
|
||||
//Position/scale of projection. Converted to a UV in the shader
|
||||
rendererCoords.x = centerPosition.x - orthoSize;
|
||||
rendererCoords.y = centerPosition.z - orthoSize;
|
||||
rendererCoords.z = settings.range;
|
||||
rendererCoords.w = 1f; //Enable in shader
|
||||
|
||||
cmd.SetGlobalVector(_WaterDisplacementCoords, rendererCoords);
|
||||
}
|
||||
|
||||
public override void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor)
|
||||
{
|
||||
if (resolution != m_resolution || renderTarget == null)
|
||||
{
|
||||
RTHandles.Release(renderTarget);
|
||||
|
||||
renderTarget = RTHandles.Alloc(resolution, resolution, 1, DepthBits.None,
|
||||
UnityEngine.Experimental.Rendering.GraphicsFormat.R16_SFloat,
|
||||
filterMode: FilterMode.Bilinear,
|
||||
wrapMode: TextureWrapMode.Clamp,
|
||||
useMipMap: false,
|
||||
name: BufferName);
|
||||
}
|
||||
m_resolution = resolution;
|
||||
|
||||
cmd.SetGlobalTexture(_WaterDisplacementBuffer, renderTarget);
|
||||
|
||||
cmd.EnableShaderKeyword(KEYWORD);
|
||||
|
||||
ConfigureTarget(renderTarget);
|
||||
ConfigureClear(ClearFlag.Color, Color.clear);
|
||||
}
|
||||
|
||||
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
|
||||
{
|
||||
CommandBuffer cmd = CommandBufferPool.Get();
|
||||
|
||||
DrawingSettings drawingSettings = CreateDrawingSettings(m_ShaderTagIdList, ref renderingData, SortingCriteria.RenderQueue | SortingCriteria.SortingLayer | SortingCriteria.CommonTransparent);
|
||||
drawingSettings.perObjectData = PerObjectData.None;
|
||||
|
||||
using (new ProfilingScope(cmd, profilerSampler))
|
||||
{
|
||||
ref CameraData cameraData = ref renderingData.cameraData;
|
||||
|
||||
SetupProjection(cmd, cameraData.camera);
|
||||
|
||||
//Execute current commands first
|
||||
context.ExecuteCommandBuffer(cmd);
|
||||
cmd.Clear();
|
||||
|
||||
#if UNITY_2023_1_OR_NEWER
|
||||
rendererListParams.cullingResults = renderingData.cullResults;
|
||||
rendererListParams.drawSettings = drawingSettings;
|
||||
rendererListParams.filteringSettings = m_FilteringSettings;
|
||||
rendererList = context.CreateRendererList(ref rendererListParams);
|
||||
|
||||
cmd.DrawRendererList(rendererList);
|
||||
#else
|
||||
context.DrawRenderers(renderingData.cullResults, ref drawingSettings, ref m_FilteringSettings, ref m_RenderStateBlock);
|
||||
#endif
|
||||
|
||||
//Restore
|
||||
//Disabled, because this pass renders before the camera is initialized anyway
|
||||
//cmd.SetViewProjectionMatrices(cameraData.camera.worldToCameraMatrix, cameraData.camera.projectionMatrix);
|
||||
}
|
||||
|
||||
context.ExecuteCommandBuffer(cmd);
|
||||
CommandBufferPool.Release(cmd);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Shader.SetGlobalVector(_WaterDisplacementCoords, Vector4.zero);
|
||||
RTHandles.Release(renderTarget);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c08ec7d2563d4bea89aa3509298f8bf4
|
||||
timeCreated: 1701077223
|
||||
@@ -0,0 +1,575 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
#if URP
|
||||
using UnityEngine.Rendering.Universal;
|
||||
#endif
|
||||
|
||||
namespace StylizedWater2
|
||||
{
|
||||
[ExecuteInEditMode]
|
||||
[AddComponentMenu("Stylized Water 2/Planar Reflection Renderer")]
|
||||
[HelpURL("https://staggart.xyz/unity/stylized-water-2/sws-2-docs/?section=planar-reflections")]
|
||||
public class PlanarReflectionRenderer : MonoBehaviour
|
||||
{
|
||||
#if URP
|
||||
public static List<PlanarReflectionRenderer> Instances = new List<PlanarReflectionRenderer>();
|
||||
public Dictionary<Camera, Camera> reflectionCameras = new Dictionary<Camera, Camera>();
|
||||
|
||||
//Rendering
|
||||
[Tooltip("If enabled, the reflection plane will be based on this transform's up vector (green arrow).\n\nOtherwise the world's upwards direction is assumed")]
|
||||
public bool rotatable = false;
|
||||
[Tooltip("Set the layers that should be rendered into the reflection. The \"Water\" layer is always excluded")]
|
||||
public LayerMask cullingMask = -1;
|
||||
[Tooltip("The renderer used by the reflection camera. It's recommend to create a separate renderer, so any custom render features aren't executed for the reflection")]
|
||||
public int rendererIndex = -1;
|
||||
|
||||
[Min(0f)]
|
||||
public float offset = 0.05f;
|
||||
[Tooltip("When disabled, the skybox reflection comes from a Reflection Probe. This has the benefit of being omni-directional rather than flat/planar. Enabled this to render the skybox into the planar reflection anyway." +
|
||||
"\n\nNote that enabling this will override Screen Space Reflections completely!")]
|
||||
public bool includeSkybox;
|
||||
[Tooltip("Render Unity's default fog in the reflection. Note that this doesn't strictly work correctly on large triangles, as it is incompatible with oblique camera projections.")]
|
||||
public bool enableFog;
|
||||
|
||||
//Quality
|
||||
public bool renderShadows;
|
||||
[Tooltip("Objects beyond this range aren't rendered into the reflection. Note that this may causes popping for large/tall objects.")]
|
||||
public float renderRange = 500f;
|
||||
[Range(0.25f, 1f)]
|
||||
[Tooltip("A multiplier for the rendering resolution, based on the current screen resolution. The render scale, as configured in the pipeline settings is multiplied over this.")]
|
||||
public float renderScale = 0.75f;
|
||||
|
||||
[Range(0, 4)]
|
||||
[Tooltip("Do not render LOD objects lower than this value. Example: With a value of 1, LOD0 for LOD Groups will not be used")]
|
||||
public int maximumLODLevel = 0;
|
||||
|
||||
[SerializeField]
|
||||
public List<WaterObject> waterObjects = new List<WaterObject>();
|
||||
[Tooltip("If enabled, the center of the rendering bounds (that wraps around the water objects) moves with the Transform position" +
|
||||
"\n\nYou must however ensure you are only moving on the XZ axis")]
|
||||
public bool moveWithTransform;
|
||||
[HideInInspector]
|
||||
public Bounds bounds = new Bounds();
|
||||
|
||||
private float m_renderScale = 1f;
|
||||
private float m_renderRange;
|
||||
|
||||
/// <summary>
|
||||
/// Reflections will only render if this is true. Value can be set through the static SetQuality function
|
||||
/// </summary>
|
||||
public static bool AllowReflections { get; private set; } = true;
|
||||
|
||||
private static readonly int _PlanarReflectionsEnabledID = Shader.PropertyToID("_PlanarReflectionsEnabled");
|
||||
private static readonly int _PlanarReflectionID = Shader.PropertyToID("_PlanarReflection");
|
||||
|
||||
#if UNITY_2023_1_OR_NEWER
|
||||
private UniversalRenderPipeline.SingleCameraRequest requestData;
|
||||
#endif
|
||||
|
||||
[NonSerialized]
|
||||
public bool isRendering;
|
||||
|
||||
private Camera m_reflectionCamera;
|
||||
private static UniversalAdditionalCameraData m_cameraData;
|
||||
|
||||
private void Reset()
|
||||
{
|
||||
this.gameObject.name = "Planar Reflection Renderer";
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
InitializeValues();
|
||||
|
||||
Instances.Add(this);
|
||||
EnableReflections();
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
Instances.Remove(this);
|
||||
DisableReflections();
|
||||
}
|
||||
|
||||
public void InitializeValues()
|
||||
{
|
||||
m_renderScale = renderScale;
|
||||
m_renderRange = renderRange;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Assigns all Water Objects in the WaterObject.Instances list and enables reflection for them
|
||||
/// </summary>
|
||||
public void ApplyToAllWaterInstances()
|
||||
{
|
||||
waterObjects = new List<WaterObject>(WaterObject.Instances);
|
||||
RecalculateBounds();
|
||||
EnableMaterialReflectionSampling();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Toggle reflections or set the render scale for all reflection renderers. This can be tied into performance scaling or graphics settings in menus
|
||||
/// </summary>
|
||||
/// <param name="enableReflections">Toggles rendering of reflections, and toggles it on all the assigned water objects</param>
|
||||
/// <param name="renderScale">A multiplier for the current screen resolution. Note that the render scale configured in URP is also taken into account</param>
|
||||
/// <param name="renderRange">Objects beyond this range aren't rendered into the reflection</param>
|
||||
public static void SetQuality(bool enableReflections, float renderScale = -1f, float renderRange = -1f, int maxLodLevel = -1)
|
||||
{
|
||||
AllowReflections = enableReflections;
|
||||
|
||||
foreach (PlanarReflectionRenderer renderer in Instances)
|
||||
{
|
||||
if (renderScale > 0) renderer.renderScale = renderScale;
|
||||
if (renderRange > 0) renderer.renderRange = renderRange;
|
||||
if (maxLodLevel >= 0) renderer.maximumLODLevel = maxLodLevel;
|
||||
renderer.InitializeValues();
|
||||
|
||||
if (enableReflections) renderer.EnableReflections();
|
||||
if (!enableReflections) renderer.DisableReflections();
|
||||
}
|
||||
}
|
||||
|
||||
public void EnableReflections()
|
||||
{
|
||||
if (!AllowReflections || PipelineUtilities.VREnabled()) return;
|
||||
|
||||
RenderPipelineManager.beginCameraRendering += OnWillRenderCamera;
|
||||
ToggleMaterialReflectionSampling(true);
|
||||
}
|
||||
|
||||
public void DisableReflections()
|
||||
{
|
||||
RenderPipelineManager.beginCameraRendering -= OnWillRenderCamera;
|
||||
ToggleMaterialReflectionSampling(false);
|
||||
|
||||
//Clear cameras
|
||||
foreach (var kvp in reflectionCameras)
|
||||
{
|
||||
if (kvp.Value == null) continue;
|
||||
|
||||
if (kvp.Value)
|
||||
{
|
||||
RenderTexture.ReleaseTemporary(kvp.Value.targetTexture);
|
||||
DestroyImmediate(kvp.Value.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
reflectionCameras.Clear();
|
||||
}
|
||||
|
||||
private void OnDrawGizmosSelected()
|
||||
{
|
||||
Gizmos.color = bounds.size.y > 0.01f ? Color.yellow : Color.white;
|
||||
Gizmos.DrawWireCube(bounds.center, bounds.size);
|
||||
}
|
||||
|
||||
public Bounds CalculateBounds()
|
||||
{
|
||||
Bounds m_bounds = new Bounds(Vector3.zero, Vector3.zero);
|
||||
|
||||
if (waterObjects == null) return m_bounds;
|
||||
if (waterObjects.Count == 0) return m_bounds;
|
||||
|
||||
Vector3 minSum = Vector3.one * Mathf.Infinity;
|
||||
Vector3 maxSum = Vector3.one * Mathf.NegativeInfinity;
|
||||
|
||||
for (int i = 0; i < waterObjects.Count; i++)
|
||||
{
|
||||
if (!waterObjects[i]) continue;
|
||||
|
||||
minSum = Vector3.Min(waterObjects[i].meshRenderer.bounds.min, minSum);
|
||||
maxSum = Vector3.Max(waterObjects[i].meshRenderer.bounds.max, maxSum);
|
||||
}
|
||||
|
||||
m_bounds.SetMinMax(minSum, maxSum);
|
||||
|
||||
//Flatten to center
|
||||
m_bounds.size = new Vector3(m_bounds.size.x, 0f, m_bounds.size.z);
|
||||
|
||||
return m_bounds;
|
||||
}
|
||||
|
||||
public void RecalculateBounds()
|
||||
{
|
||||
bounds = CalculateBounds();
|
||||
}
|
||||
|
||||
public static bool InvalidContext(Camera camera)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
//Avoid the "Screen position outside of frustrum" error
|
||||
if (camera.orthographic && Vector3.Dot(Vector3.up, camera.transform.up) > 0.9999f) return true;
|
||||
|
||||
#if UNITY_2021_2_OR_NEWER
|
||||
//Causes an internal error in URP's rendering code in the CopyColorPass
|
||||
if (camera.cameraType == CameraType.SceneView && UnityEditor.SceneView.lastActiveSceneView && UnityEditor.SceneView.lastActiveSceneView.isUsingSceneFiltering) return true;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//Skip for any special use camera's (except scene view camera)
|
||||
//Note: Scene camera still rendering even if window not focused!
|
||||
return (camera.cameraType != CameraType.SceneView && (camera.cameraType == CameraType.Reflection || camera.cameraType == CameraType.Preview || camera.hideFlags != HideFlags.None));
|
||||
}
|
||||
|
||||
private void OnWillRenderCamera(ScriptableRenderContext context, Camera camera)
|
||||
{
|
||||
if (InvalidContext(camera))
|
||||
{
|
||||
isRendering = false;
|
||||
return;
|
||||
}
|
||||
|
||||
isRendering = WaterObjectsVisible(camera);
|
||||
|
||||
if (isRendering == false) return;
|
||||
|
||||
|
||||
if (moveWithTransform) bounds.center = this.transform.position;
|
||||
|
||||
m_cameraData = camera.GetComponent<UniversalAdditionalCameraData>();
|
||||
if (m_cameraData && m_cameraData.renderType == CameraRenderType.Overlay) return;
|
||||
|
||||
reflectionCameras.TryGetValue(camera, out m_reflectionCamera);
|
||||
if (m_reflectionCamera == null) CreateReflectionCamera(camera);
|
||||
|
||||
//It's possible it is destroyed at this point when disabling reflections
|
||||
if (!m_reflectionCamera) return;
|
||||
|
||||
UnityEngine.Profiling.Profiler.BeginSample("Planar Water Reflections", camera);
|
||||
|
||||
//Render scale changed
|
||||
if (Math.Abs(renderScale - m_renderScale) > 0.02f)
|
||||
{
|
||||
RenderTexture.ReleaseTemporary(m_reflectionCamera.targetTexture);
|
||||
CreateRenderTexture(m_reflectionCamera, camera);
|
||||
|
||||
m_renderScale = renderScale;
|
||||
}
|
||||
|
||||
UpdateWaterProperties(m_reflectionCamera);
|
||||
|
||||
UpdateCameraProperties(camera, m_reflectionCamera);
|
||||
UpdatePerspective(camera, m_reflectionCamera);
|
||||
|
||||
bool fogEnabled = RenderSettings.fog && !enableFog;
|
||||
//Fog is based on clip-space z-distance and doesn't work with oblique projections
|
||||
if (fogEnabled) RenderSettings.fog = false;
|
||||
int maxLODLevel = QualitySettings.maximumLODLevel;
|
||||
QualitySettings.maximumLODLevel = maximumLODLevel;
|
||||
GL.invertCulling = true;
|
||||
|
||||
#pragma warning disable 0618
|
||||
#if UNITY_2023_1_OR_NEWER
|
||||
/*
|
||||
requestData = new UniversalRenderPipeline.SingleCameraRequest();
|
||||
requestData.destination = reflectionCamera.targetTexture;
|
||||
requestData.slice = -1;
|
||||
|
||||
//Throws the 'Recursive rendering is not supported in SRP (are you calling Camera.Render from within a render pipeline?).' error.
|
||||
if (RenderPipeline.SupportsRenderRequest(m_reflectionCamera, requestData))
|
||||
{
|
||||
RenderPipeline.SubmitRenderRequest(m_reflectionCamera, requestData);
|
||||
}
|
||||
*/
|
||||
|
||||
//Instead, Unity will whine about using an obsolete API.
|
||||
UniversalRenderPipeline.RenderSingleCamera(context, m_reflectionCamera);
|
||||
|
||||
//So now what?
|
||||
#else
|
||||
UniversalRenderPipeline.RenderSingleCamera(context, m_reflectionCamera);
|
||||
#endif
|
||||
#pragma warning restore 0618
|
||||
|
||||
if (fogEnabled) RenderSettings.fog = true;
|
||||
QualitySettings.maximumLODLevel = maxLODLevel;
|
||||
GL.invertCulling = false;
|
||||
|
||||
UnityEngine.Profiling.Profiler.EndSample();
|
||||
}
|
||||
|
||||
private float GetRenderScale()
|
||||
{
|
||||
return Mathf.Clamp(renderScale * UniversalRenderPipeline.asset.renderScale, 0.25f, 1f);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Should the renderer index be changed at runtime, this function must be called to update any reflection cameras
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
public void SetRendererIndex(int index)
|
||||
{
|
||||
index = PipelineUtilities.ValidateRenderer(index);
|
||||
|
||||
foreach (var kvp in reflectionCameras)
|
||||
{
|
||||
if (kvp.Value == null) continue;
|
||||
|
||||
m_cameraData = kvp.Value.GetComponent<UniversalAdditionalCameraData>();
|
||||
m_cameraData.SetRenderer(index);
|
||||
}
|
||||
}
|
||||
|
||||
public void ToggleShadows(bool state)
|
||||
{
|
||||
foreach (var kvp in reflectionCameras)
|
||||
{
|
||||
if (kvp.Value == null) continue;
|
||||
|
||||
m_cameraData = kvp.Value.GetComponent<UniversalAdditionalCameraData>();
|
||||
m_cameraData.renderShadows = state;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add the WaterObject, and recalculates the rendering bounds.
|
||||
/// </summary>
|
||||
/// <param name="waterObject"></param>
|
||||
public void AddWaterObject(WaterObject waterObject)
|
||||
{
|
||||
ToggleMaterialReflectionSampling(waterObject, true);
|
||||
waterObjects.Add(waterObject);
|
||||
|
||||
RecalculateBounds();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove the WaterObject, and recalculates the rendering bounds.
|
||||
/// </summary>
|
||||
/// <param name="waterObject"></param>
|
||||
public void RemoveWaterObject(WaterObject waterObject)
|
||||
{
|
||||
ToggleMaterialReflectionSampling(waterObject, false);
|
||||
waterObjects.Remove(waterObject);
|
||||
|
||||
RecalculateBounds();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enables planar reflections on the MeshRenderers of the assigned water objects
|
||||
/// </summary>
|
||||
public void EnableMaterialReflectionSampling()
|
||||
{
|
||||
ToggleMaterialReflectionSampling(AllowReflections);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Toggles the sampling of the planar reflections texture in the water shader.
|
||||
/// </summary>
|
||||
/// <param name="state"></param>
|
||||
public void ToggleMaterialReflectionSampling(bool state)
|
||||
{
|
||||
if (waterObjects == null) return;
|
||||
|
||||
for (int i = 0; i < waterObjects.Count; i++)
|
||||
{
|
||||
if (waterObjects[i] == null) continue;
|
||||
|
||||
ToggleMaterialReflectionSampling(waterObjects[i], state);
|
||||
}
|
||||
}
|
||||
|
||||
private void ToggleMaterialReflectionSampling(WaterObject waterObject, bool state)
|
||||
{
|
||||
waterObject.props.SetFloat(_PlanarReflectionsEnabledID, state ? 1f : 0f);
|
||||
waterObject.ApplyInstancedProperties();
|
||||
}
|
||||
|
||||
private void CreateReflectionCamera(Camera source)
|
||||
{
|
||||
//Object creation
|
||||
GameObject go = new GameObject($"{source.name} Planar Reflection");
|
||||
go.hideFlags = HideFlags.DontSave | HideFlags.HideInHierarchy;
|
||||
|
||||
Camera newCamera = go.AddComponent<Camera>();
|
||||
newCamera.hideFlags = HideFlags.DontSave;
|
||||
//For the scene-view camera this also copies unwanted properties. Such as the camera type and background color!
|
||||
newCamera.CopyFrom(source);
|
||||
|
||||
//Always exclude water layer
|
||||
newCamera.cullingMask = ~(1 << 4) & cullingMask;
|
||||
//Must always be set to Game, otherwise shadows render anyway
|
||||
newCamera.cameraType = CameraType.Game;
|
||||
newCamera.depth = source.depth-1f;
|
||||
newCamera.rect = new Rect(0,0,1,1);
|
||||
newCamera.enabled = false;
|
||||
newCamera.clearFlags = includeSkybox ? CameraClearFlags.Skybox : CameraClearFlags.Depth;
|
||||
//Required to maintain the alpha channel for the scene view
|
||||
newCamera.backgroundColor = Color.clear;
|
||||
newCamera.useOcclusionCulling = false;
|
||||
|
||||
//Component required for the UniversalRenderPipeline.RenderSingleCamera call
|
||||
UniversalAdditionalCameraData data = newCamera.gameObject.AddComponent<UniversalAdditionalCameraData>();
|
||||
data.requiresDepthTexture = false;
|
||||
data.requiresColorTexture = false;
|
||||
data.renderShadows = renderShadows;
|
||||
|
||||
rendererIndex = PipelineUtilities.ValidateRenderer(rendererIndex);
|
||||
data.SetRenderer(rendererIndex);
|
||||
|
||||
CreateRenderTexture(newCamera, source);
|
||||
|
||||
reflectionCameras[source] = newCamera;
|
||||
}
|
||||
|
||||
private void CreateRenderTexture(Camera targetCamera, Camera source)
|
||||
{
|
||||
//Note: Do not use RenderTextureFormat.Default or HDR, as these may be without an alpha channel on some platforms
|
||||
RenderTextureFormat colorFormat = UniversalRenderPipeline.asset.supportsHDR && SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.ARGBHalf) ? RenderTextureFormat.ARGBHalf : RenderTextureFormat.ARGB32;
|
||||
|
||||
float scale = GetRenderScale();
|
||||
|
||||
RenderTextureDescriptor rtDsc = new RenderTextureDescriptor(
|
||||
(int)((float)source.scaledPixelWidth * scale),
|
||||
(int)((float)source.scaledPixelHeight * scale),
|
||||
colorFormat);
|
||||
|
||||
rtDsc.depthBufferBits = 16;
|
||||
|
||||
targetCamera.targetTexture = RenderTexture.GetTemporary(rtDsc);
|
||||
targetCamera.targetTexture.name = $"{source.name}_Reflection {rtDsc.width}x{rtDsc.height}";
|
||||
}
|
||||
|
||||
private static readonly Plane[] frustrumPlanes = new Plane[6];
|
||||
|
||||
public bool WaterObjectsVisible(Camera targetCamera)
|
||||
{
|
||||
GeometryUtility.CalculateFrustumPlanes(targetCamera.projectionMatrix * targetCamera.worldToCameraMatrix, frustrumPlanes);
|
||||
|
||||
return GeometryUtility.TestPlanesAABB(frustrumPlanes, bounds);
|
||||
}
|
||||
|
||||
//Assigns the render target of the current reflection camera
|
||||
private void UpdateWaterProperties(Camera cam)
|
||||
{
|
||||
for (int i = 0; i < waterObjects.Count; i++)
|
||||
{
|
||||
if (waterObjects[i] == null) continue;
|
||||
|
||||
waterObjects[i].props.SetTexture(_PlanarReflectionID, cam.targetTexture);
|
||||
waterObjects[i].ApplyInstancedProperties();
|
||||
}
|
||||
}
|
||||
|
||||
private static Vector4 reflectionPlane;
|
||||
private static Matrix4x4 reflectionBase;
|
||||
private static Vector3 oldCamPos;
|
||||
|
||||
private static Matrix4x4 worldToCamera;
|
||||
private static Matrix4x4 viewMatrix;
|
||||
private static Matrix4x4 projectionMatrix;
|
||||
private static Vector4 clipPlane;
|
||||
private static readonly float[] layerCullDistances = new float[32];
|
||||
|
||||
private void UpdateCameraProperties(Camera source, Camera reflectionCam)
|
||||
{
|
||||
reflectionCam.fieldOfView = source.fieldOfView;
|
||||
reflectionCam.orthographic = source.orthographic;
|
||||
reflectionCam.orthographicSize = source.orthographicSize;
|
||||
reflectionCam.useOcclusionCulling = source.useOcclusionCulling;
|
||||
}
|
||||
|
||||
private void UpdatePerspective(Camera source, Camera reflectionCam)
|
||||
{
|
||||
if (!source || !reflectionCam) return;
|
||||
|
||||
Vector3 normal = rotatable ? this.transform.up : Vector3.up;
|
||||
|
||||
Vector3 position = bounds.center + (normal * offset);
|
||||
|
||||
var d = -Vector3.Dot(normal, position);
|
||||
reflectionPlane = new Vector4(normal.x, normal.y, normal.z, d);
|
||||
|
||||
reflectionBase = Matrix4x4.identity;
|
||||
reflectionBase *= Matrix4x4.Scale(new Vector3(1, -1, 1));
|
||||
|
||||
// View
|
||||
CalculateReflectionMatrix(ref reflectionBase, reflectionPlane);
|
||||
oldCamPos = source.transform.position - new Vector3(0, position.y * 2, 0);
|
||||
reflectionCam.transform.forward = Vector3.Scale(source.transform.forward, new Vector3(1, -1, 1));
|
||||
|
||||
worldToCamera = source.worldToCameraMatrix;
|
||||
viewMatrix = worldToCamera * reflectionBase;
|
||||
|
||||
//Reflect position
|
||||
oldCamPos.y = -oldCamPos.y;
|
||||
reflectionCam.transform.position = oldCamPos;
|
||||
|
||||
clipPlane = CameraSpacePlane(reflectionCam.worldToCameraMatrix, position - normal * 0.1f, normal, 1.0f);
|
||||
projectionMatrix = source.CalculateObliqueMatrix(clipPlane);
|
||||
|
||||
//Settings
|
||||
reflectionCam.cullingMask = ~(1 << 4) & cullingMask;;
|
||||
m_reflectionCamera.clearFlags = includeSkybox ? CameraClearFlags.Skybox : CameraClearFlags.Depth;
|
||||
|
||||
#if !UNITY_2023_3_OR_NEWER
|
||||
//Only re-apply on value change
|
||||
if (m_renderRange != renderRange)
|
||||
{
|
||||
m_renderRange = renderRange;
|
||||
|
||||
for (int i = 0; i < layerCullDistances.Length; i++)
|
||||
{
|
||||
layerCullDistances[i] = renderRange;
|
||||
}
|
||||
}
|
||||
reflectionCam.layerCullDistances = layerCullDistances;
|
||||
reflectionCam.layerCullSpherical = true;
|
||||
#endif
|
||||
|
||||
reflectionCam.projectionMatrix = projectionMatrix;
|
||||
reflectionCam.worldToCameraMatrix = viewMatrix;
|
||||
}
|
||||
|
||||
// Calculates reflection matrix around the given plane
|
||||
private void CalculateReflectionMatrix(ref Matrix4x4 reflectionMat, Vector4 plane)
|
||||
{
|
||||
reflectionMat.m00 = (1F - 2F * plane[0] * plane[0]);
|
||||
reflectionMat.m01 = (-2F * plane[0] * plane[1]);
|
||||
reflectionMat.m02 = (-2F * plane[0] * plane[2]);
|
||||
reflectionMat.m03 = (-2F * plane[3] * plane[0]);
|
||||
|
||||
reflectionMat.m10 = (-2F * plane[1] * plane[0]);
|
||||
reflectionMat.m11 = (1F - 2F * plane[1] * plane[1]);
|
||||
reflectionMat.m12 = (-2F * plane[1] * plane[2]);
|
||||
reflectionMat.m13 = (-2F * plane[3] * plane[1]);
|
||||
|
||||
reflectionMat.m20 = (-2F * plane[2] * plane[0]);
|
||||
reflectionMat.m21 = (-2F * plane[2] * plane[1]);
|
||||
reflectionMat.m22 = (1F - 2F * plane[2] * plane[2]);
|
||||
reflectionMat.m23 = (-2F * plane[3] * plane[2]);
|
||||
|
||||
reflectionMat.m30 = 0F;
|
||||
reflectionMat.m31 = 0F;
|
||||
reflectionMat.m32 = 0F;
|
||||
reflectionMat.m33 = 1F;
|
||||
}
|
||||
|
||||
// Given position/normal of the plane, calculates plane in camera space.
|
||||
private Vector4 CameraSpacePlane(Matrix4x4 worldToCameraMatrix, Vector3 pos, Vector3 normal, float sideSign)
|
||||
{
|
||||
var offsetPos = pos + normal * offset;
|
||||
var cameraPosition = worldToCameraMatrix.MultiplyPoint(offsetPos);
|
||||
var cameraNormal = worldToCameraMatrix.MultiplyVector(normal).normalized * sideSign;
|
||||
return new Vector4(cameraNormal.x, cameraNormal.y, cameraNormal.z,
|
||||
-Vector3.Dot(cameraPosition, cameraNormal));
|
||||
}
|
||||
|
||||
public RenderTexture TryGetReflectionTexture(Camera targetCamera)
|
||||
{
|
||||
if (targetCamera)
|
||||
{
|
||||
reflectionCameras.TryGetValue(targetCamera, out m_reflectionCamera);
|
||||
if (m_reflectionCamera)
|
||||
{
|
||||
return m_reflectionCamera.targetTexture;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 569d0b097a6f78843bff90729cbe4ef1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {fileID: -1426863774865177168, guid: 0000000000000000d000000000000000, type: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
110
LocalPackages/StylizedWater2/Runtime/Rendering/SetupConstants.cs
Normal file
110
LocalPackages/StylizedWater2/Runtime/Rendering/SetupConstants.cs
Normal file
@@ -0,0 +1,110 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
#if URP
|
||||
using UnityEngine.Rendering.Universal;
|
||||
using UnityEngine.Rendering.Universal.Internal;
|
||||
|
||||
namespace StylizedWater2
|
||||
{
|
||||
public class SetupConstants : ScriptableRenderPass
|
||||
{
|
||||
private static readonly int _EnableDirectionalCaustics = Shader.PropertyToID("_EnableDirectionalCaustics");
|
||||
private static readonly int CausticsProjection = Shader.PropertyToID("CausticsProjection");
|
||||
private static readonly int _WaterSSREnabled = Shader.PropertyToID("_WaterSSREnabled");
|
||||
private static readonly int _WaterDisplacementPrePassAvailable = Shader.PropertyToID("_WaterDisplacementPrePassAvailable");
|
||||
|
||||
private bool m_directionalCaustics;
|
||||
|
||||
private static VisibleLight mainLight;
|
||||
private Matrix4x4 causticsProjection;
|
||||
|
||||
public SetupConstants()
|
||||
{
|
||||
//Force a unit scale, otherwise affects the projection tiling of the caustics
|
||||
causticsProjection = Matrix4x4.Scale(Vector3.one);
|
||||
}
|
||||
|
||||
private StylizedWaterRenderFeature settings;
|
||||
|
||||
public void Setup(StylizedWaterRenderFeature renderFeature)
|
||||
{
|
||||
this.settings = renderFeature;
|
||||
m_directionalCaustics = settings.directionalCaustics;
|
||||
}
|
||||
|
||||
#if UNITY_2020_2_OR_NEWER
|
||||
private ScriptableRenderPassInput requirements;
|
||||
#endif
|
||||
|
||||
public override void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor)
|
||||
{
|
||||
#if UNITY_2020_2_OR_NEWER
|
||||
//Inform the render pipeline which pre-passes are required
|
||||
requirements = ScriptableRenderPassInput.None;
|
||||
|
||||
//Only when using advanced shading, so don't forcibly enable
|
||||
//if(m_directionalCaustics) requirements = ScriptableRenderPassInput.Depth;
|
||||
|
||||
if (settings.screenSpaceReflectionSettings.enable)
|
||||
{
|
||||
requirements |= ScriptableRenderPassInput.Color | ScriptableRenderPassInput.Depth;
|
||||
}
|
||||
|
||||
if(settings.displacementPrePassSettings.enable) cmd.EnableShaderKeyword(DisplacementPrePass.KEYWORD);
|
||||
else cmd.DisableShaderKeyword(DisplacementPrePass.KEYWORD);
|
||||
|
||||
cmd.SetGlobalInt(_WaterSSREnabled, settings.screenSpaceReflectionSettings.enable ? 1 : 0);
|
||||
cmd.SetGlobalInt(_WaterDisplacementPrePassAvailable, settings.displacementPrePassSettings.enable ? 1 : 0);
|
||||
|
||||
ConfigureInput(requirements);
|
||||
#endif
|
||||
}
|
||||
|
||||
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
|
||||
{
|
||||
CommandBuffer cmd = CommandBufferPool.Get();
|
||||
|
||||
if (m_directionalCaustics)
|
||||
{
|
||||
//When no lights are visible, main light will be set to -1.
|
||||
if (renderingData.lightData.mainLightIndex > -1)
|
||||
{
|
||||
mainLight = renderingData.lightData.visibleLights[renderingData.lightData.mainLightIndex];
|
||||
|
||||
if (mainLight.lightType == LightType.Directional)
|
||||
{
|
||||
causticsProjection = Matrix4x4.Rotate(mainLight.light.transform.rotation);
|
||||
|
||||
cmd.SetGlobalMatrix(CausticsProjection, causticsProjection.inverse);
|
||||
}
|
||||
|
||||
#if UNITY_2021_2_OR_NEWER
|
||||
//Sets up the required View- -> Clip-space matrices
|
||||
NormalReconstruction.SetupProperties(cmd, renderingData.cameraData);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
m_directionalCaustics = false;
|
||||
}
|
||||
}
|
||||
|
||||
cmd.SetGlobalInt(_EnableDirectionalCaustics, m_directionalCaustics ? 1 : 0);
|
||||
|
||||
context.ExecuteCommandBuffer(cmd);
|
||||
CommandBufferPool.Release(cmd);
|
||||
}
|
||||
|
||||
public override void OnCameraCleanup(CommandBuffer cmd)
|
||||
{
|
||||
cmd.SetGlobalInt(_EnableDirectionalCaustics, 0);
|
||||
cmd.SetGlobalInt(_WaterSSREnabled, 0);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Shader.SetGlobalInt(_WaterDisplacementPrePassAvailable, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fb6834bcc3854bbca9142a4bc547b968
|
||||
timeCreated: 1701078225
|
||||
@@ -0,0 +1,65 @@
|
||||
#if URP
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering.Universal;
|
||||
|
||||
namespace StylizedWater2
|
||||
{
|
||||
#if UNITY_2021_1_OR_NEWER
|
||||
[DisallowMultipleRendererFeature("Stylized Water 2")]
|
||||
#endif
|
||||
public class StylizedWaterRenderFeature : ScriptableRendererFeature
|
||||
{
|
||||
public static StylizedWaterRenderFeature GetDefault()
|
||||
{
|
||||
return (StylizedWaterRenderFeature)PipelineUtilities.GetRenderFeature<StylizedWaterRenderFeature>();
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class ScreenSpaceReflectionSettings
|
||||
{
|
||||
public bool enable;
|
||||
}
|
||||
public ScreenSpaceReflectionSettings screenSpaceReflectionSettings = new ScreenSpaceReflectionSettings();
|
||||
|
||||
[Tooltip("Project caustics from the main directional light.")]
|
||||
public bool directionalCaustics;
|
||||
|
||||
public DisplacementPrePass.Settings displacementPrePassSettings = new DisplacementPrePass.Settings();
|
||||
|
||||
private SetupConstants constantsSetup;
|
||||
private DisplacementPrePass displacementPass;
|
||||
|
||||
public override void Create()
|
||||
{
|
||||
constantsSetup = new SetupConstants
|
||||
{
|
||||
renderPassEvent = RenderPassEvent.BeforeRendering
|
||||
};
|
||||
|
||||
displacementPass = new DisplacementPrePass
|
||||
{
|
||||
renderPassEvent = RenderPassEvent.BeforeRendering
|
||||
};
|
||||
}
|
||||
|
||||
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
|
||||
{
|
||||
constantsSetup.Setup(this);
|
||||
renderer.EnqueuePass(constantsSetup);
|
||||
|
||||
if (displacementPrePassSettings.enable)
|
||||
{
|
||||
displacementPass.Setup(displacementPrePassSettings);
|
||||
renderer.EnqueuePass(displacementPass);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
displacementPass.Dispose();
|
||||
constantsSetup.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2086e3e143e14a2abcd3b0dbc77a10ac
|
||||
timeCreated: 1701077140
|
||||
Reference in New Issue
Block a user