Files
2025-05-26 00:46:28 +02:00

363 lines
12 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Fragilem17.MirrorsAndPortals
{
public class PortalUtils
{
public enum DebugColors
{
Info,
Warn,
Error
}
public static string Colorize(string text, DebugColors color, bool bold = false)
{
string c = "00BC0E";
if (color == DebugColors.Error)
{
c = "BE0000";
}
else if (color == DebugColors.Warn)
{
c = "FFB900";
}
return "<color=#" + c + ">" + (bold ? "<b>" : "") + text + (bold ? "</b>" : "") + "</color>";
}
// taken from http://www.terathon.com/code/oblique.html
public static void MakeProjectionMatrixOblique(ref Matrix4x4 matrix, Vector4 clipPlane)
{
Vector4 q = matrix.inverse * new Vector4(Mathf.Sign(clipPlane.x), Mathf.Sign(clipPlane.y), 1.0f, 1.0f);
Vector4 c = clipPlane * (2.0F / (Vector4.Dot(clipPlane, q)));
// Replace the third row of the projection matrix
matrix[2] = c.x - matrix[3];
matrix[6] = c.y - matrix[7];
matrix[10] = c.z - matrix[11];
matrix[14] = c.w - matrix[15];
/*
Vector4 q;
// Calculate the clip-space corner point opposite the clipping plane
// as (sgn(clipPlane.x), sgn(clipPlane.y), 1, 1) and
// transform it into camera space by multiplying it
// by the inverse of the projection matrix
q.x = (sgn(clipPlane.x) + matrix[8]) / matrix[0];
q.y = (sgn(clipPlane.y) + matrix[9]) / matrix[5];
q.z = -1.0F;
q.w = (1.0F + matrix[10]) / matrix[14];
// Calculate the scaled plane vector
Vector4 c = clipPlane * (2.0F / Vector4.Dot(clipPlane, q));
// Replace the third row of the projection matrix
matrix[2] = c.x;
matrix[6] = c.y;
matrix[10] = c.z + 1.0F;
matrix[14] = c.w;
*/
}
public static Matrix4x4 OffAxisProjectionMatrix(float near, float far, Vector3 pa, Vector3 pb, Vector3 pc, Vector3 pe)
{
Vector3 va; // from pe to pa
Vector3 vb; // from pe to pb
Vector3 vc; // from pe to pc
Vector3 vr; // right axis of screen
Vector3 vu; // up axis of screen
Vector3 vn; // normal vector of screen
float l; // distance to left screen edge
float r; // distance to right screen edge
float b; // distance to bottom screen edge
float t; // distance to top screen edge
float d; // distance from eye to screen
vr = pb - pa;
vu = pc - pa;
va = pa - pe;
vb = pb - pe;
vc = pc - pe;
// are we looking at the backface of the plane object?
if (Vector3.Dot(-Vector3.Cross(va, vc), vb) < 0.0)
{
// mirror points along the z axis (most users
// probably expect the x axis to stay fixed)
vu = -vu;
pa = pc;
pb = pa + vr;
pc = pa + vu;
va = pa - pe;
vb = pb - pe;
vc = pc - pe;
}
vr.Normalize();
vu.Normalize();
vn = -Vector3.Cross(vr, vu);
// we need the minus sign because Unity
// uses a left-handed coordinate system
vn.Normalize();
d = -Vector3.Dot(va, vn);
// Set near clip plane
near = d; // + _clippingDistance;
l = Vector3.Dot(vr, va) * near / d;
r = Vector3.Dot(vr, vb) * near / d;
b = Vector3.Dot(vu, va) * near / d;
t = Vector3.Dot(vu, vc) * near / d;
Matrix4x4 p = new Matrix4x4(); // projection matrix
p[0, 0] = 2.0f * near / (r - l);
p[0, 1] = 0.0f;
p[0, 2] = (r + l) / (r - l);
p[0, 3] = 0.0f;
p[1, 0] = 0.0f;
p[1, 1] = 2.0f * near / (t - b);
p[1, 2] = (t + b) / (t - b);
p[1, 3] = 0.0f;
p[2, 0] = 0.0f;
p[2, 1] = 0.0f;
p[2, 2] = (far + near) / (near - far);
p[2, 3] = 2.0f * far * near / (near - far);
p[3, 0] = 0.0f;
p[3, 1] = 0.0f;
p[3, 2] = -1.0f;
p[3, 3] = 0.0f;
Matrix4x4 rm = new Matrix4x4(); // rotation matrix;
rm[0, 0] = vr.x;
rm[0, 1] = vr.y;
rm[0, 2] = vr.z;
rm[0, 3] = 0.0f;
rm[1, 0] = vu.x;
rm[1, 1] = vu.y;
rm[1, 2] = vu.z;
rm[1, 3] = 0.0f;
rm[2, 0] = vn.x;
rm[2, 1] = vn.y;
rm[2, 2] = vn.z;
rm[2, 3] = 0.0f;
rm[3, 0] = 0.0f;
rm[3, 1] = 0.0f;
rm[3, 2] = 0.0f;
rm[3, 3] = 1.0f;
Matrix4x4 tm = new Matrix4x4(); // translation matrix;
tm[0, 0] = 1.0f;
tm[0, 1] = 0.0f;
tm[0, 2] = 0.0f;
tm[0, 3] = -pe.x;
tm[1, 0] = 0.0f;
tm[1, 1] = 1.0f;
tm[1, 2] = 0.0f;
tm[1, 3] = -pe.y;
tm[2, 0] = 0.0f;
tm[2, 1] = 0.0f;
tm[2, 2] = 1.0f;
tm[2, 3] = -pe.z;
tm[3, 0] = 0.0f;
tm[3, 1] = 0.0f;
tm[3, 2] = 0.0f;
tm[3, 3] = 1.0f;
Matrix4x4 worldToCameraMatrix = rm * tm;
return p * worldToCameraMatrix;
}
// Extended sign: returns -1, 0 or 1 based on sign of a
private static float sgn(float a)
{
if (a > 0.0f) return 1.0f;
if (a < 0.0f) return -1.0f;
return 0.0f;
}
// Given position/normal of the plane, calculates plane in camera space.
public static Vector4 CameraSpacePlane(Matrix4x4 worldToCameraMatrix, Vector3 pos, Vector3 normal, float sideSign, float clippingPlaneOffset)
{
Vector3 offsetPos = pos + normal * clippingPlaneOffset;
Vector3 cpos = worldToCameraMatrix.MultiplyPoint(offsetPos);
Vector3 cnormal = worldToCameraMatrix.MultiplyVector(normal).normalized * sideSign;
return new Vector4(cnormal.x, cnormal.y, cnormal.z, -Vector3.Dot(cpos, cnormal));
}
/*
// Calculates reflection matrix around the given plane
public static 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;
}
*/
}
[Serializable]
public class SerializableCurve
{
public SerializableKeyframe[] keys;
public string postWrapMode;
public string preWrapMode;
[Serializable]
public class SerializableKeyframe
{
public Single inTangent;
public Single inWeight;
public Single outTangent;
public Single outWeight;
public Int32 weightedMode;
//public Int32 tangentMode;
public Single time;
public Single value;
public SerializableKeyframe(Keyframe original, int index)
{
inTangent = original.inTangent;
inWeight = original.inWeight;
outTangent = original.outTangent;
outWeight = original.outWeight;
weightedMode = (int)original.weightedMode;
//tangentMode = original.tangentMode;
time = original.time;
value = original.value;
}
}
public SerializableCurve(AnimationCurve original)
{
postWrapMode = getWrapModeAsString(original.postWrapMode);
preWrapMode = getWrapModeAsString(original.preWrapMode);
keys = new SerializableKeyframe[original.length];
for (int i = 0; i < original.keys.Length; i++)
{
keys[i] = new SerializableKeyframe(original.keys[i], i);
}
}
public AnimationCurve toCurve()
{
AnimationCurve res = new AnimationCurve();
res.postWrapMode = getWrapMode(postWrapMode);
res.preWrapMode = getWrapMode(preWrapMode);
Keyframe[] newKeys = new Keyframe[keys.Length];
for (int i = 0; i < keys.Length; i++)
{
SerializableKeyframe aux = keys[i];
Keyframe newK = new Keyframe();
newK.inTangent = aux.inTangent;
newK.inWeight = aux.inWeight;
newK.outTangent = aux.outTangent;
newK.outWeight = aux.outWeight;
//newK.tangentMode = aux.tangentMode;
newK.weightedMode = (WeightedMode)aux.weightedMode;
newK.time = aux.time;
newK.value = aux.value;
newKeys[i] = newK;
}
res.keys = newKeys;
return res;
}
private WrapMode getWrapMode(String mode)
{
if (mode.Equals("Clamp"))
{
return WrapMode.Clamp;
}
if (mode.Equals("ClampForever"))
{
return WrapMode.ClampForever;
}
if (mode.Equals("Default"))
{
return WrapMode.Default;
}
if (mode.Equals("Loop"))
{
return WrapMode.Loop;
}
if (mode.Equals("Once"))
{
return WrapMode.Once;
}
if (mode.Equals("PingPong"))
{
return WrapMode.PingPong;
}
Debug.LogError("Wat is this wrap mode???");
return WrapMode.Default;
}
private string getWrapModeAsString(WrapMode mode)
{
if (mode.Equals(WrapMode.Clamp))
{
return "Clamp";
}
if (mode.Equals(WrapMode.ClampForever))
{
return "ClampForever";
}
if (mode.Equals(WrapMode.Default))
{
return "Default";
}
if (mode.Equals(WrapMode.Loop))
{
return "Loop";
}
if (mode.Equals(WrapMode.Once))
{
return "Once";
}
if (mode.Equals(WrapMode.PingPong))
{
return "PingPong";
}
Debug.LogError("Wat is this wrap mode???");
return "f you";
}
}
}