|
|
|
|
|
|
|
|
|
|
namespace UnityEngine.Experimental.Rendering |
|
|
|
{ |
|
|
|
public static class GeometryUtils |
|
|
|
{ |
|
|
|
public static readonly Matrix4x4 FlipMatrixLHSRHS = Matrix4x4.Scale(new Vector3(1, 1, -1)); |
|
|
|
|
|
|
|
public static Vector4 Plane(Vector3 position, Vector3 normal) |
|
|
|
{ |
|
|
|
var n = normal; |
|
|
|
var d = -Vector3.Dot(n, position); |
|
|
|
var plane = new Vector4(n.x, n.y, n.z, d); |
|
|
|
return plane; |
|
|
|
} |
|
|
|
|
|
|
|
public static Vector4 CameraSpacePlane(Matrix4x4 worldToCamera, Vector3 pos, Vector3 normal, float sideSign = 1, float clipPlaneOffset = 0) |
|
|
|
{ |
|
|
|
var offsetPos = pos + normal * clipPlaneOffset; |
|
|
|
var cpos = worldToCamera.MultiplyPoint(offsetPos); |
|
|
|
var cnormal = worldToCamera.MultiplyVector(normal).normalized * sideSign; |
|
|
|
return new Vector4(cnormal.x, cnormal.y, cnormal.z, -Vector3.Dot(cpos, cnormal)); |
|
|
|
} |
|
|
|
|
|
|
|
public static Matrix4x4 CalculateWorldToCameraMatrixRHS(Vector3 position, Quaternion rotation) |
|
|
|
{ |
|
|
|
return Matrix4x4.Scale(new Vector3(1, 1, -1)) * Matrix4x4.TRS(position, rotation, Vector3.one).inverse; |
|
|
|
} |
|
|
|
|
|
|
|
public static Matrix4x4 CalculateWorldToCameraMatrixRHS(Transform transform) |
|
|
|
{ |
|
|
|
return Matrix4x4.Scale(new Vector3(1, 1, -1)) * transform.localToWorldMatrix.inverse; |
|
|
|
} |
|
|
|
|
|
|
|
public static Matrix4x4 CalculateObliqueMatrix(Matrix4x4 sourceProjection, Vector4 clipPlane) |
|
|
|
{ |
|
|
|
var projection = sourceProjection; |
|
|
|
var inversion = sourceProjection.inverse; |
|
|
|
|
|
|
|
var cps = new Vector4( |
|
|
|
Mathf.Sign(clipPlane.x), |
|
|
|
Mathf.Sign(clipPlane.y), |
|
|
|
1.0f, |
|
|
|
1.0f); |
|
|
|
var q = inversion * cps; |
|
|
|
var c = clipPlane * (2.0f / Vector4.Dot(clipPlane, q)); |
|
|
|
|
|
|
|
projection[2] = c.x - projection[3]; |
|
|
|
projection[6] = c.y - projection[7]; |
|
|
|
projection[10] = c.z - projection[11]; |
|
|
|
projection[14] = c.w - projection[15]; |
|
|
|
|
|
|
|
return projection; |
|
|
|
} |
|
|
|
|
|
|
|
public static Matrix4x4 CalculateReflectionMatrix(Vector3 position, Vector3 normal) |
|
|
|
{ |
|
|
|
return CalculateReflectionMatrix(Plane(position, normal.normalized)); |
|
|
|
} |
|
|
|
|
|
|
|
public static Matrix4x4 CalculateReflectionMatrix(Vector4 plane) |
|
|
|
{ |
|
|
|
var reflectionMat = new Matrix4x4(); |
|
|
|
|
|
|
|
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; |
|
|
|
|
|
|
|
return reflectionMat; |
|
|
|
} |
|
|
|
|
|
|
|
public static Matrix4x4 GetWorldToCameraMatrixLHS(this Camera camera) |
|
|
|
{ |
|
|
|
return FlipMatrixLHSRHS * camera.worldToCameraMatrix; |
|
|
|
} |
|
|
|
|
|
|
|
public static Matrix4x4 GetProjectionMatrixLHS(this Camera camera) |
|
|
|
{ |
|
|
|
return camera.projectionMatrix * FlipMatrixLHSRHS; |
|
|
|
} |
|
|
|
|
|
|
|
public static Matrix4x4 CalculateProjectionMatrix(Camera camera) |
|
|
|
{ |
|
|
|
if (camera.orthographic) |
|
|
|
{ |
|
|
|
var h = camera.orthographicSize; |
|
|
|
var w = camera.orthographicSize * camera.aspect; |
|
|
|
return Matrix4x4.Ortho(-w, w, -h, h, camera.nearClipPlane, camera.farClipPlane); |
|
|
|
} |
|
|
|
else |
|
|
|
return Matrix4x4.Perspective(camera.fieldOfView, camera.aspect, camera.nearClipPlane, camera.farClipPlane); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public struct Frustum |
|
|
|
{ |
|
|
|
public Plane[] planes; // Left, right, top, bottom, near, far
|
|
|
|
|
|
|
|
|
|
|
GeometryUtility.CalculateFrustumPlanes(viewProjMatrix, frustum.planes); |
|
|
|
|
|
|
|
float nd = -1.0f; |
|
|
|
|
|
|
|
nd = 0.0f; |
|
|
|
|
|
|
|
// See "Fast Extraction of Viewing Frustum Planes" by Gribb and Hartmann.
|
|
|
|
Vector3 f = new Vector3(viewProjMatrix.m20, viewProjMatrix.m21, viewProjMatrix.m22); |
|
|
|
float s = (float)(1.0 / Math.Sqrt(f.sqrMagnitude)); |
|
|
|
|
|
|
frustum.corners[1] = invViewProjMatrix.MultiplyPoint(new Vector3( 1, -1, 1)); |
|
|
|
frustum.corners[2] = invViewProjMatrix.MultiplyPoint(new Vector3(-1, 1, 1)); |
|
|
|
frustum.corners[3] = invViewProjMatrix.MultiplyPoint(new Vector3( 1, 1, 1)); |
|
|
|
frustum.corners[4] = invViewProjMatrix.MultiplyPoint(new Vector3(-1, -1, 0)); |
|
|
|
frustum.corners[5] = invViewProjMatrix.MultiplyPoint(new Vector3( 1, -1, 0)); |
|
|
|
frustum.corners[6] = invViewProjMatrix.MultiplyPoint(new Vector3(-1, 1, 0)); |
|
|
|
frustum.corners[7] = invViewProjMatrix.MultiplyPoint(new Vector3( 1, 1, 0)); |
|
|
|
frustum.corners[4] = invViewProjMatrix.MultiplyPoint(new Vector3(-1, -1, nd)); |
|
|
|
frustum.corners[5] = invViewProjMatrix.MultiplyPoint(new Vector3( 1, -1, nd)); |
|
|
|
frustum.corners[6] = invViewProjMatrix.MultiplyPoint(new Vector3(-1, 1, nd)); |
|
|
|
frustum.corners[7] = invViewProjMatrix.MultiplyPoint(new Vector3( 1, 1, nd)); |
|
|
|
} |
|
|
|
} // struct Frustum
|
|
|
|
[GenerateHLSL] |
|
|
|
// TODO: in the shader, merge axes and extents, and 16-byte align the data structure.
|
|
|
|
public Vector3 center; |
|
|
|
public Vector3 right, up, forward; // X, Y, Z, normalized
|
|
|
|
public Vector3 extents; // Size of the half-diagonal
|
|
|
|
public Vector4 center; // w is unused
|
|
|
|
public Vector4 right, up, forward; // {x, y, z} = normalized local axis, w = 1/2 * size along the axis
|
|
|
|
obb.center = t.position; |
|
|
|
obb.right = t.right; |
|
|
|
obb.up = t.up; |
|
|
|
obb.forward = t.forward; |
|
|
|
obb.extents = t.localScale * 0.5f; |
|
|
|
obb.center = t.position; |
|
|
|
obb.right = t.right; |
|
|
|
obb.right.w = 0.5f * t.localScale.x; |
|
|
|
obb.up = t.up; |
|
|
|
obb.up.w = 0.5f * t.localScale.y; |
|
|
|
obb.forward = t.forward; |
|
|
|
obb.forward.w = 0.5f * t.localScale.z; |
|
|
|
} // struct OrientedBBox
|
|
|
|
public static class GeometryUtils |
|
|
|
{ |
|
|
|
public bool OverlapsFrustum(Frustum frustum, int numPlanes, int numCorners, Vector3 cameraRelativeOffset) |
|
|
|
public static bool Overlap(OrientedBBox obb, Vector3 cameraRelativeOffset, |
|
|
|
Frustum frustum, int numPlanes, int numCorners) |
|
|
|
Vector3 relCenter = center + cameraRelativeOffset; |
|
|
|
Vector3 relCenter = (Vector3)obb.center + cameraRelativeOffset; |
|
|
|
|
|
|
|
bool overlap = true; |
|
|
|
|
|
|
|
|
|
|
float d = frustum.planes[i].distance; |
|
|
|
|
|
|
|
// Max projection of the half-diagonal onto the normal (always positive).
|
|
|
|
float maxHalfDiagProj = extents.x * Mathf.Abs(Vector3.Dot(n, right)) |
|
|
|
+ extents.y * Mathf.Abs(Vector3.Dot(n, up)) |
|
|
|
+ extents.z * Mathf.Abs(Vector3.Dot(n, forward)); |
|
|
|
float maxHalfDiagProj = Mathf.Abs(Vector3.Dot(n, obb.right)) * obb.right.w |
|
|
|
+ Mathf.Abs(Vector3.Dot(n, obb.up)) * obb.up.w |
|
|
|
+ Mathf.Abs(Vector3.Dot(n, obb.forward)) * obb.forward.w; |
|
|
|
|
|
|
|
// Negative distance -> center behind the plane (outside).
|
|
|
|
float centerToPlaneDist = Vector3.Dot(n, relCenter) + d; |
|
|
|
|
|
|
// We can exploit the symmetry of the box by only testing against 3 planes rather than 6.
|
|
|
|
Plane[] planes = new Plane[3]; |
|
|
|
|
|
|
|
planes[0].normal = right; |
|
|
|
planes[0].distance = extents.x; |
|
|
|
planes[1].normal = up; |
|
|
|
planes[1].distance = extents.y; |
|
|
|
planes[2].normal = forward; |
|
|
|
planes[2].distance = extents.z; |
|
|
|
planes[0].normal = obb.right; |
|
|
|
planes[0].distance = obb.right.w; |
|
|
|
planes[1].normal = obb.up; |
|
|
|
planes[1].distance = obb.up.w; |
|
|
|
planes[2].normal = obb.forward; |
|
|
|
planes[2].distance = obb.forward.w; |
|
|
|
|
|
|
|
for (int i = 0; overlap && i < 3; i++) |
|
|
|
{ |
|
|
|
|
|
|
|
|
|
|
return overlap; |
|
|
|
} |
|
|
|
} // struct OrientedBBox
|
|
|
|
|
|
|
|
public static readonly Matrix4x4 FlipMatrixLHSRHS = Matrix4x4.Scale(new Vector3(1, 1, -1)); |
|
|
|
|
|
|
|
public static Vector4 Plane(Vector3 position, Vector3 normal) |
|
|
|
{ |
|
|
|
var n = normal; |
|
|
|
var d = -Vector3.Dot(n, position); |
|
|
|
var plane = new Vector4(n.x, n.y, n.z, d); |
|
|
|
return plane; |
|
|
|
} |
|
|
|
|
|
|
|
public static Vector4 CameraSpacePlane(Matrix4x4 worldToCamera, Vector3 pos, Vector3 normal, float sideSign = 1, float clipPlaneOffset = 0) |
|
|
|
{ |
|
|
|
var offsetPos = pos + normal * clipPlaneOffset; |
|
|
|
var cpos = worldToCamera.MultiplyPoint(offsetPos); |
|
|
|
var cnormal = worldToCamera.MultiplyVector(normal).normalized * sideSign; |
|
|
|
return new Vector4(cnormal.x, cnormal.y, cnormal.z, -Vector3.Dot(cpos, cnormal)); |
|
|
|
} |
|
|
|
|
|
|
|
public static Matrix4x4 CalculateWorldToCameraMatrixRHS(Vector3 position, Quaternion rotation) |
|
|
|
{ |
|
|
|
return Matrix4x4.Scale(new Vector3(1, 1, -1)) * Matrix4x4.TRS(position, rotation, Vector3.one).inverse; |
|
|
|
} |
|
|
|
|
|
|
|
public static Matrix4x4 CalculateWorldToCameraMatrixRHS(Transform transform) |
|
|
|
{ |
|
|
|
return Matrix4x4.Scale(new Vector3(1, 1, -1)) * transform.localToWorldMatrix.inverse; |
|
|
|
} |
|
|
|
|
|
|
|
public static Matrix4x4 CalculateObliqueMatrix(Matrix4x4 sourceProjection, Vector4 clipPlane) |
|
|
|
{ |
|
|
|
var projection = sourceProjection; |
|
|
|
var inversion = sourceProjection.inverse; |
|
|
|
|
|
|
|
var cps = new Vector4( |
|
|
|
Mathf.Sign(clipPlane.x), |
|
|
|
Mathf.Sign(clipPlane.y), |
|
|
|
1.0f, |
|
|
|
1.0f); |
|
|
|
var q = inversion * cps; |
|
|
|
var c = clipPlane * (2.0f / Vector4.Dot(clipPlane, q)); |
|
|
|
|
|
|
|
projection[2] = c.x - projection[3]; |
|
|
|
projection[6] = c.y - projection[7]; |
|
|
|
projection[10] = c.z - projection[11]; |
|
|
|
projection[14] = c.w - projection[15]; |
|
|
|
|
|
|
|
return projection; |
|
|
|
} |
|
|
|
|
|
|
|
public static Matrix4x4 CalculateReflectionMatrix(Vector3 position, Vector3 normal) |
|
|
|
{ |
|
|
|
return CalculateReflectionMatrix(Plane(position, normal.normalized)); |
|
|
|
} |
|
|
|
|
|
|
|
public static Matrix4x4 CalculateReflectionMatrix(Vector4 plane) |
|
|
|
{ |
|
|
|
var reflectionMat = new Matrix4x4(); |
|
|
|
|
|
|
|
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; |
|
|
|
|
|
|
|
return reflectionMat; |
|
|
|
} |
|
|
|
|
|
|
|
public static Matrix4x4 GetWorldToCameraMatrixLHS(this Camera camera) |
|
|
|
{ |
|
|
|
return FlipMatrixLHSRHS * camera.worldToCameraMatrix; |
|
|
|
} |
|
|
|
|
|
|
|
public static Matrix4x4 GetProjectionMatrixLHS(this Camera camera) |
|
|
|
{ |
|
|
|
return camera.projectionMatrix * FlipMatrixLHSRHS; |
|
|
|
} |
|
|
|
|
|
|
|
public static Matrix4x4 CalculateProjectionMatrix(Camera camera) |
|
|
|
{ |
|
|
|
if (camera.orthographic) |
|
|
|
{ |
|
|
|
var h = camera.orthographicSize; |
|
|
|
var w = camera.orthographicSize * camera.aspect; |
|
|
|
return Matrix4x4.Ortho(-w, w, -h, h, camera.nearClipPlane, camera.farClipPlane); |
|
|
|
} |
|
|
|
else |
|
|
|
return Matrix4x4.Perspective(camera.fieldOfView, camera.aspect, camera.nearClipPlane, camera.farClipPlane); |
|
|
|
} |
|
|
|
} // class GeometryUtils
|
|
|
|
} |