2025-10-21 14:18:31 +09:00

139 lines
5.3 KiB
C#

// Stylized Water 3 by Staggart Creations (http://staggart.xyz)
// COPYRIGHT PROTECTED UNDER THE UNITY ASSET STORE EULA (https://unity.com/legal/as-terms)
// • Copying or referencing source code for the production of new asset store, or public, content is strictly prohibited!
// • Uploading this file to a public repository will subject it to an automated DMCA takedown request.
using System;
using UnityEngine;
using UnityEngine.Rendering;
namespace StylizedWater3
{
/// <summary>
/// Utility for creating an orthographic top-down projection
/// </summary>
public class PlanarProjection
{
private static readonly Quaternion viewRotation = Quaternion.Euler(new Vector3(90f, 0f, 0f));
private static readonly Vector3 viewScale = new Vector3(1, 1, -1);
private static readonly Plane[] frustrumPlanes = new Plane[6];
//Input
public Vector3 center;
public Vector3 offset;
public float scale;
public int resolution;
public bool expandHeight = true;
//Output
public Matrix4x4 projection;
public Matrix4x4 view;
public Rect viewportRect;
public Vector3 boundsMin;
public Vector3 boundsMax;
//Important to snap the projection to the nearest texel. Otherwise pixel swimming is introduced when moving, due to bilinear filtering
private static Vector3 Stabilize(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));
}
public void Recalculate()
{
float extent = scale * 0.5f;
Vector3 centerPosition = center + offset;
//var frustumHeight = 2.0f * scale * Mathf.Tan(camera.fieldOfView * 0.5f * Mathf.Deg2Rad); //Still clips, plus doesn't support orthographc
var frustumHeight = expandHeight ? 10000f : scale;
centerPosition += (Vector3.up * frustumHeight * 0.5f);
centerPosition = Stabilize(centerPosition, scale / resolution);
projection = Matrix4x4.Ortho(-extent, extent, -extent, extent, 0.02f, frustumHeight);
view = Matrix4x4.TRS(centerPosition, viewRotation, viewScale).inverse;
viewportRect = new Rect(0, 0, resolution, resolution);
boundsMin.x = centerPosition.x - extent;
boundsMin.y = centerPosition.y - extent;
boundsMin.z = centerPosition.z - extent;
boundsMax.x = centerPosition.z + extent;
boundsMax.y = centerPosition.z + extent;
boundsMax.z = centerPosition.z + extent;
}
/// <summary>
/// Sets a Vector4 uniform up to be passed onto shader land, where a world-space position can be used to calculate a sampling UV
/// </summary>
/// <param name="coords"></param>
public void SetUV(ref Vector4 coords)
{
coords.x = boundsMin.x;
coords.y = boundsMin.z;
coords.z = scale;
coords.w = 1; //Enable sampling shaders
}
public void SetProjection(RasterCommandBuffer cmd)
{
cmd.SetViewProjectionMatrices(view, projection);
//Unity 6000.0.30f1+ only
//RenderingUtils.SetViewAndProjectionMatrices(cmd, view, projection, true);
}
public static int CalculateResolution(float scale, int texelsPerUnit, int min, int max)
{
int res = Mathf.RoundToInt(scale * texelsPerUnit);
//if(NON_POWER_OF_TWO == false) res = Mathf.NextPowerOfTwo(res);
return Mathf.Clamp(res, min, max);
}
public static float FadePercentageToLength(float renderRange, float fadePercentage)
{
fadePercentage = Mathf.Max(0.01f, fadePercentage);
return (renderRange * 0.5f) * (fadePercentage / 100f);
}
public void CalculateFrustumPlanes()
{
GeometryUtility.CalculateFrustumPlanes(projection * view, frustrumPlanes);
}
public bool TestPlanesAABB(Bounds bounds)
{
return GeometryUtility.TestPlanesAABB(frustrumPlanes, bounds);
}
//Using data only from the matrices, to ensure what you're seeing closely represents them
public void DrawOrthographicViewGizmo()
{
Gizmos.matrix = Matrix4x4.identity;
CalculateFrustumPlanes();
float near = frustrumPlanes[4].distance;
float far = frustrumPlanes[5].distance;
float height = near + far;
Vector3 position = new Vector3(view.inverse.m03, view.inverse.m13, view.inverse.m23);
Vector3 orthoSize = new Vector3((frustrumPlanes[0].distance + frustrumPlanes[1].distance), height, frustrumPlanes[2].distance + frustrumPlanes[3].distance);
//orthoSize = Vector3.one * 50f;
Gizmos.DrawSphere(position, 1f);
position -= Vector3.up * height * 0.5f;
Gizmos.DrawWireCube(position, orthoSize);
Gizmos.color = Color.white * 0.25f;
Gizmos.DrawCube(position, orthoSize);
}
}
}