Project_WL/Assets/Critter Volumetric Lighting/Scripts/Utils/ProjectionLib.cs

122 lines
4.1 KiB
C#

using UnityEngine;
using System.Collections.Generic;
namespace CritterVolumetricLighting
{
public static class ProjectionLib
{
public static Vector3 FindIntersectionWithPlane(Vector3 inspectDirection, Vector3 inspectPoint, Vector3 planePoint, Vector3 planeNormal)
{
float denominator = Vector3.Dot(planeNormal, inspectDirection);
if (Mathf.Approximately(denominator, 0f))
{
return inspectPoint;
}
Vector3 startToPlanePoint = planePoint - inspectPoint;
float t = Vector3.Dot(planeNormal, startToPlanePoint) / denominator;
Vector3 intersection = inspectPoint + inspectDirection * t;
return intersection;
}
private static Vector2 ReverseEngineerUV(Vector3 positionOnPlane, Vector3 planeOrigo, Vector3 anchorPosition, Vector3 anchorForward,
float planeWidthWorldUnits, float planeHeightWorldUnits)
{
Vector3 posOnRelAxisX = FindIntersectionWithPlane(-anchorForward, positionOnPlane, anchorPosition, -anchorForward);
Vector3 compX = (posOnRelAxisX - planeOrigo);
Vector3 compY = (positionOnPlane - posOnRelAxisX);
float compXLen = compX.magnitude;
float compYLen = compY.magnitude;
float xUV = compXLen / planeWidthWorldUnits;
float yUV = compYLen / planeHeightWorldUnits;
Vector2 uv = new Vector2(xUV, yUV);
return uv;
}
public static Vector2 PositionToUV(Vector3 inputPosition, Vector3 sunForward, Vector3 anchorPosition, Vector3 anchorUp, Vector3 planeOrigo, Vector3 anchorForward,
float planeWidthWorldUnits, float planeHeightWorldUnits)
{
Vector3 pointOnPlane = FindIntersectionWithPlane(-sunForward, inputPosition, anchorPosition, anchorUp);
return ReverseEngineerUV(pointOnPlane, planeOrigo, anchorPosition, anchorForward, planeWidthWorldUnits, planeHeightWorldUnits);
}
public static Vector3 ProjectVectorOntoPlane(Vector3 vectorToProject, Vector3 planeNormal)
{
Vector3 projectionOntoNormal = Vector3.Dot(vectorToProject, planeNormal) * planeNormal;
Vector3 projectionOntoPlane = vectorToProject - projectionOntoNormal;
return projectionOntoPlane.normalized;
}
public static Vector3 ProjectPointOntoPlane(Vector3 point, Vector3 planeNormal, Vector3 planePoint)
{
Vector3 displacement = point - planePoint;
float distance = Vector3.Dot(displacement, planeNormal.normalized);
return point - planeNormal.normalized * distance;
}
public static Vector2Int CalculateLongestFrustumAxis(List<Vector3> frustumPoints)
{
Vector2Int longestAxis = Vector2Int.zero;
float longestDistance = 0f;
for (int i = 0; i <= 1; i++)
{
float distance2 = Vector3.Distance(frustumPoints[2+i], frustumPoints[4+i]);
float distance3 = Vector3.Distance(frustumPoints[2+i], frustumPoints[6+i]);
if (distance2 > longestDistance) {
longestDistance = distance2;
longestAxis = new Vector2Int(2+i, 4+i);
}
if (distance3 > longestDistance) {
longestDistance = distance3;
longestAxis = new Vector2Int(2+i, 6+i);
}
}
return longestAxis;
}
static public Vector3 CalculateRightVector(Vector3 forward)
{
Vector3 upWorld = Vector3.up;
Vector3 right = Vector3.Cross(forward, upWorld);
if (right.sqrMagnitude < 0.0001) // If right vector is nearly zero due to parallel vectors
{
// Use another vector that is guaranteed not to be parallel
right = Vector3.Cross(forward, Vector3.right);
if (right.sqrMagnitude < 0.0001) // Check again
{
right = Vector3.Cross(forward, Vector3.forward);
}
}
return right.normalized;
}
static public Vector3 CalculateUpVector(Vector3 forward, Vector3 directionalLightForward)
{
Vector3 right = CalculateRightVector(forward);
Vector3 up = Vector3.Cross(right, forward);
// Align 'up' more closely with the light's forward direction without breaking the orthogonality
Vector3 projectedLightForward = Vector3.ProjectOnPlane(directionalLightForward, forward);
float angle = Vector3.Angle(up, projectedLightForward);
if (angle > 0.0001 && angle < 179.9999) // Avoid aligning if already aligned or directly opposite
{
up = projectedLightForward.normalized;
}
return up;
}
}
}