235 lines
8.7 KiB
C#
235 lines
8.7 KiB
C#
|
|
namespace UnityEngine.Rendering.Universal
|
|
{
|
|
public class DebugCascadeShadow : MonoBehaviour
|
|
{
|
|
public Camera targetCamera;
|
|
public bool showCullingSpheres = true;
|
|
public bool showCameraFrustums = true;
|
|
public bool showCascadeFrustums = true;
|
|
[Range(0f, 4f)]
|
|
public int showMaxCascade = 4;
|
|
public Color[] cascadeColors = new Color[]
|
|
{
|
|
new Color(1, 0, 0, 0.5f), // 红
|
|
new Color(0, 1, 0, 0.5f), // 绿
|
|
new Color(0, 0.5f, 1, 0.5f), // 蓝
|
|
new Color(1, 1, 0, 0.5f) // 黄
|
|
};
|
|
|
|
public static Vector3 cascadeSplits;
|
|
public static Vector4[] cullingSpheres = new Vector4[4];
|
|
public static Matrix4x4[] cascadeVps = new Matrix4x4[4];
|
|
Plane[][] planes = new Plane[][]
|
|
{
|
|
new Plane[] { new(),new(),new(),new(),new(),new() },
|
|
new Plane[] { new(),new(),new(),new(),new(),new() },
|
|
new Plane[] { new(),new(),new(),new(),new(),new() },
|
|
new Plane[] { new(),new(),new(),new(),new(),new() },
|
|
};
|
|
|
|
void ExtractFrustumPlanes(in Matrix4x4 VP, in Plane[] planes)
|
|
{
|
|
// Left clipping plane
|
|
planes[0] = new Plane(
|
|
new Vector3(VP.m30 + VP.m00, VP.m31 + VP.m01, VP.m32 + VP.m02),
|
|
VP.m33 + VP.m03);
|
|
// Right clipping plane
|
|
planes[1] = new Plane(
|
|
new Vector3(VP.m30 - VP.m00, VP.m31 - VP.m01, VP.m32 - VP.m02),
|
|
VP.m33 - VP.m03);
|
|
// Top clipping plane
|
|
planes[2] = new Plane(
|
|
new Vector3(VP.m30 - VP.m10, VP.m31 - VP.m11, VP.m32 - VP.m12),
|
|
VP.m33 - VP.m13);
|
|
// Bottom clipping plane
|
|
planes[3] = new Plane(
|
|
new Vector3(VP.m30 + VP.m10, VP.m31 + VP.m11, VP.m32 + VP.m12),
|
|
VP.m33 + VP.m13);
|
|
// Near clipping plane
|
|
planes[4] = new Plane(
|
|
new Vector3(VP.m20, VP.m21, VP.m22),
|
|
VP.m23);
|
|
// Far clipping plane
|
|
planes[5] = new Plane(
|
|
new Vector3(VP.m30 - VP.m20, VP.m31 - VP.m21, VP.m32 - VP.m22),
|
|
VP.m33 - VP.m23);
|
|
}
|
|
|
|
protected static void ExtractFrustumPlanesStereo(in Matrix4x4 leftVP, in Matrix4x4 rightVP, in Plane[] planes)
|
|
{
|
|
// Left clipping plane
|
|
planes[0] = new Plane(
|
|
new Vector3(leftVP.m30 + leftVP.m00, leftVP.m31 + leftVP.m01, leftVP.m32 + leftVP.m02),
|
|
leftVP.m33 + leftVP.m03);
|
|
// Right clipping plane
|
|
planes[1] = new Plane(
|
|
new Vector3(rightVP.m30 - rightVP.m00, rightVP.m31 - rightVP.m01, rightVP.m32 - rightVP.m02),
|
|
rightVP.m33 - rightVP.m03);
|
|
// Top clipping plane
|
|
planes[2] = new Plane(
|
|
new Vector3(leftVP.m30 - leftVP.m10, leftVP.m31 - leftVP.m11, leftVP.m32 - leftVP.m12),
|
|
leftVP.m33 - leftVP.m13);
|
|
// Bottom clipping plane
|
|
planes[3] = new Plane(
|
|
new Vector3(leftVP.m30 + leftVP.m10, leftVP.m31 + leftVP.m11, leftVP.m32 + leftVP.m12),
|
|
leftVP.m33 + leftVP.m13);
|
|
// Near clipping plane
|
|
planes[4] = new Plane(
|
|
new Vector3(leftVP.m20, leftVP.m21, leftVP.m22),
|
|
leftVP.m23);
|
|
// Far clipping plane
|
|
planes[5] = new Plane(
|
|
new Vector3(leftVP.m30 - leftVP.m20, leftVP.m31 - leftVP.m21, leftVP.m32 - leftVP.m22),
|
|
leftVP.m33 - leftVP.m23);
|
|
}
|
|
|
|
protected void DrawFrustum(in Matrix4x4 vp)
|
|
{
|
|
Matrix4x4 clip2world = vp.inverse;
|
|
|
|
Vector4[] corners =
|
|
{
|
|
new(-1, -1, -1, 1),
|
|
new(1, -1, -1, 1),
|
|
new(1, 1, -1, 1),
|
|
new(-1, 1, -1, 1),
|
|
|
|
new(-1, -1, 1, 1),
|
|
new(1, -1, 1, 1),
|
|
new(1, 1, 1, 1),
|
|
new(-1, 1, 1, 1),
|
|
};
|
|
|
|
for (int i = 0; i < corners.Length; i++)
|
|
{
|
|
corners[i] = clip2world * corners[i];
|
|
corners[i] /= corners[i].w;
|
|
}
|
|
|
|
Gizmos.DrawLine(corners[0], corners[1]);
|
|
Gizmos.DrawLine(corners[1], corners[2]);
|
|
Gizmos.DrawLine(corners[2], corners[3]);
|
|
Gizmos.DrawLine(corners[3], corners[0]);
|
|
|
|
Gizmos.DrawLine(corners[4], corners[5]);
|
|
Gizmos.DrawLine(corners[5], corners[6]);
|
|
Gizmos.DrawLine(corners[6], corners[7]);
|
|
Gizmos.DrawLine(corners[7], corners[4]);
|
|
|
|
Gizmos.DrawLine(corners[0], corners[4]);
|
|
Gizmos.DrawLine(corners[1], corners[5]);
|
|
Gizmos.DrawLine(corners[2], corners[6]);
|
|
Gizmos.DrawLine(corners[3], corners[7]);
|
|
}
|
|
|
|
void OnDrawGizmos()
|
|
{
|
|
if (targetCamera == null) return;
|
|
|
|
if (showCullingSpheres)
|
|
{
|
|
for (int i = 0; i < cullingSpheres.Length; i++)
|
|
{
|
|
if (i > showMaxCascade - 1)
|
|
{
|
|
break;
|
|
}
|
|
if (cullingSpheres[i].w <= 0) continue;
|
|
|
|
Gizmos.color = cascadeColors[i % cascadeColors.Length];
|
|
Vector3 sphereCenter = cullingSpheres[i];
|
|
float sphereRadius = cullingSpheres[i].w;
|
|
Gizmos.DrawWireSphere(sphereCenter, sphereRadius);
|
|
}
|
|
}
|
|
|
|
if (showCascadeFrustums)
|
|
{
|
|
for (int i = 0; i < cascadeVps.Length; i++)
|
|
{
|
|
if (i > showMaxCascade - 1)
|
|
{
|
|
break;
|
|
}
|
|
|
|
var vp = cascadeVps[i];
|
|
Gizmos.color = cascadeColors[i % cascadeVps.Length];
|
|
DrawFrustum(vp);
|
|
ExtractFrustumPlanes(vp, planes[i]);
|
|
}
|
|
}
|
|
|
|
if (showCameraFrustums)
|
|
{
|
|
float lastSplit = targetCamera.nearClipPlane;
|
|
|
|
for (int i = 0; i < 3; i++)
|
|
{
|
|
if (i > showMaxCascade - 1)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (cascadeSplits[i] <= 0) break;
|
|
|
|
Gizmos.color = cascadeColors[i % cascadeColors.Length];
|
|
DrawCascadeFrustum(targetCamera, lastSplit, cascadeSplits[i]);
|
|
lastSplit = cascadeSplits[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
private void DrawCascadeFrustum(Camera cam, float startDist, float endDist)
|
|
{
|
|
// 计算视锥体角点
|
|
Vector3[] nearCorners = GetFrustumCorners(cam, startDist);
|
|
Vector3[] farCorners = GetFrustumCorners(cam, endDist);
|
|
|
|
// 绘制视锥体线框
|
|
Gizmos.DrawLine(nearCorners[0], farCorners[0]);
|
|
Gizmos.DrawLine(nearCorners[1], farCorners[1]);
|
|
Gizmos.DrawLine(nearCorners[2], farCorners[2]);
|
|
Gizmos.DrawLine(nearCorners[3], farCorners[3]);
|
|
|
|
// 绘制近/远平面
|
|
DrawFrustumPlane(nearCorners);
|
|
DrawFrustumPlane(farCorners);
|
|
}
|
|
|
|
private Vector3[] GetFrustumCorners(Camera cam, float distance)
|
|
{
|
|
Vector3[] corners = new Vector3[4];
|
|
Transform camTransform = cam.transform;
|
|
|
|
float halfFOV = cam.fieldOfView * 0.5f * Mathf.Deg2Rad;
|
|
float aspect = cam.aspect;
|
|
|
|
float height = distance * Mathf.Tan(halfFOV);
|
|
float width = height * aspect;
|
|
|
|
// 计算相对于相机的角点
|
|
corners[0] = camTransform.forward * distance + camTransform.up * height - camTransform.right * width; // 左下
|
|
corners[1] = camTransform.forward * distance + camTransform.up * height + camTransform.right * width; // 右下
|
|
corners[2] = camTransform.forward * distance - camTransform.up * height + camTransform.right * width; // 右上
|
|
corners[3] = camTransform.forward * distance - camTransform.up * height - camTransform.right * width; // 左上
|
|
|
|
// 转换到世界坐标
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
corners[i] = camTransform.position + corners[i];
|
|
}
|
|
|
|
return corners;
|
|
}
|
|
|
|
private void DrawFrustumPlane(Vector3[] corners)
|
|
{
|
|
Gizmos.DrawLine(corners[0], corners[1]);
|
|
Gizmos.DrawLine(corners[1], corners[2]);
|
|
Gizmos.DrawLine(corners[2], corners[3]);
|
|
Gizmos.DrawLine(corners[3], corners[0]);
|
|
}
|
|
}
|
|
}
|