mirror of
https://github.com/originalnicodr/CinematicUnityExplorer.git
synced 2026-10-10 13:03:15 +08:00
Refactored camera paths.
This commit is contained in:
@@ -132,483 +132,4 @@ namespace UnityExplorer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Based of JPBotelho implementation
|
||||
https://github.com/JPBotelho/Catmull-Rom-Splines
|
||||
|
||||
Catmull-Rom splines are Hermite curves with special tangent values.
|
||||
Hermite curve formula:
|
||||
(2t^3 - 3t^2 + 1) * p0 + (t^3 - 2t^2 + t) * m0 + (-2t^3 + 3t^2) * p1 + (t^3 - t^2) * m1
|
||||
For points p0 and p1 passing through points m0 and m1 interpolated over t = [0, 1]
|
||||
Tangent M[k] = (P[k+1] - P[k-1]) / 2
|
||||
*/
|
||||
public class CatmullRom
|
||||
{
|
||||
//Struct to keep position, normal and tangent of a spline point
|
||||
[System.Serializable]
|
||||
public struct CatmullRomPoint
|
||||
{
|
||||
public Vector3 position;
|
||||
public Quaternion rotation;
|
||||
public float fov;
|
||||
|
||||
public CatmullRomPoint(Vector3 position, Quaternion rotation, float fov)
|
||||
{
|
||||
this.position = position;
|
||||
this.rotation = rotation;
|
||||
this.fov = fov;
|
||||
}
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
public struct PathControlPoint
|
||||
{
|
||||
public Vector3 position;
|
||||
public Quaternion rotation;
|
||||
public float fov;
|
||||
public int frames;
|
||||
|
||||
public PathControlPoint(Vector3 position, Quaternion rotation, float fov, int frames = 500)
|
||||
{
|
||||
this.position = position;
|
||||
this.rotation = rotation;
|
||||
this.fov = fov;
|
||||
this.frames = frames;
|
||||
}
|
||||
}
|
||||
|
||||
private bool closedLoop;
|
||||
|
||||
private CatmullRomPoint[] splinePoints; //Generated spline points
|
||||
|
||||
private PathControlPoint[] controlPoints;
|
||||
public bool playingPath;
|
||||
int currentPoint = 0;
|
||||
|
||||
//Returns spline points. Count is the summation of all the node frames (it excludes the last node frames if path isn't a closed loop).
|
||||
public CatmullRomPoint[] GetPoints()
|
||||
{
|
||||
if(splinePoints == null)
|
||||
{
|
||||
throw new System.NullReferenceException("Spline not Initialized!");
|
||||
}
|
||||
|
||||
return splinePoints;
|
||||
}
|
||||
|
||||
public CatmullRom(PathControlPoint[] controlPoints, bool closedLoop)
|
||||
{
|
||||
if(controlPoints == null || controlPoints.Length <= 2)
|
||||
{
|
||||
ExplorerCore.Log(controlPoints);
|
||||
throw new ArgumentException("Catmull Rom Error: Too few control points!");
|
||||
}
|
||||
|
||||
this.controlPoints = controlPoints;
|
||||
this.closedLoop = closedLoop;
|
||||
|
||||
GenerateSplinePoints();
|
||||
}
|
||||
|
||||
//Updates control points
|
||||
public void Update(PathControlPoint[] controlPoints)
|
||||
{
|
||||
if(controlPoints.Length <= 0 || controlPoints == null)
|
||||
{
|
||||
throw new ArgumentException("Invalid control points");
|
||||
}
|
||||
|
||||
this.controlPoints = controlPoints;
|
||||
|
||||
GenerateSplinePoints();
|
||||
}
|
||||
|
||||
//Updates closed loop values
|
||||
public void Update(bool closedLoop)
|
||||
{
|
||||
this.closedLoop = closedLoop;
|
||||
|
||||
GenerateSplinePoints();
|
||||
}
|
||||
|
||||
//Draws a line between every point and the next.
|
||||
public void DrawSpline(Color color)
|
||||
{
|
||||
if(ValidatePoints())
|
||||
{
|
||||
|
||||
for(int i = 0; i < splinePoints.Length; i++)
|
||||
{
|
||||
if(i == splinePoints.Length - 1 && closedLoop)
|
||||
{
|
||||
Debug.DrawLine(splinePoints[i].position, splinePoints[0].position, color);
|
||||
}
|
||||
else if(i < splinePoints.Length - 1)
|
||||
{
|
||||
Debug.DrawLine(splinePoints[i].position, splinePoints[i+1].position, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Validates if splinePoints have been set already. Throws nullref exception.
|
||||
private bool ValidatePoints()
|
||||
{
|
||||
if(splinePoints == null)
|
||||
{
|
||||
throw new NullReferenceException("Spline not initialized!");
|
||||
}
|
||||
return splinePoints != null;
|
||||
}
|
||||
|
||||
//Sets the length of the point array based on total amount of frames.
|
||||
private void InitializeProperties()
|
||||
{
|
||||
int pointsToCreate = 0;
|
||||
if (closedLoop)
|
||||
{
|
||||
for (var i = 0; i < controlPoints.Length; i++)
|
||||
{
|
||||
pointsToCreate += controlPoints[i].frames;//Loops back to the beggining, so no need to adjust for arrays starting at 0
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (var i = 0; i < controlPoints.Length - 1; i++)
|
||||
{
|
||||
pointsToCreate += controlPoints[i].frames;
|
||||
}
|
||||
}
|
||||
|
||||
//if(splinePoints != null)
|
||||
// Array.Clear(splinePoints, 0, splinePoints.Length);
|
||||
|
||||
splinePoints = new CatmullRomPoint[pointsToCreate];
|
||||
}
|
||||
|
||||
public void MaybeRunPath(){
|
||||
if(playingPath){
|
||||
if(ExplorerCore.CameraPathsManager != null && currentPoint < splinePoints.Length){
|
||||
CatmullRomPoint point = splinePoints[currentPoint];
|
||||
|
||||
//ExplorerCore.Log($"velocity: {Vector3.Distance(point.position,FreeCamPanel.ourCamera.transform.position)}/node");
|
||||
|
||||
FreeCamPanel.ourCamera.transform.position = point.position;
|
||||
FreeCamPanel.ourCamera.transform.rotation = point.rotation;
|
||||
FreeCamPanel.ourCamera.fieldOfView = point.fov;
|
||||
currentPoint++;
|
||||
if(currentPoint >= splinePoints.Length)
|
||||
playingPath = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void StartPath(){
|
||||
currentPoint = 0;
|
||||
playingPath = true;
|
||||
}
|
||||
|
||||
public void Stop(){
|
||||
currentPoint = 0;
|
||||
playingPath = false;
|
||||
}
|
||||
|
||||
public void Pause(){
|
||||
playingPath = false;
|
||||
}
|
||||
|
||||
public void Continue(){
|
||||
if(currentPoint < ExplorerCore.CameraPathsManager.GetPoints().Length)
|
||||
playingPath = true;
|
||||
}
|
||||
|
||||
private void GenerateSplinePoints()
|
||||
{
|
||||
InitializeProperties();
|
||||
|
||||
Vector3 p0, p1, p2, p3; //Previous position, Start position, end position, Next position
|
||||
Vector4 r0, r1, r2, r3; //Previous rotation, Start rotation, end rotation, Next rotation
|
||||
float fov0, fov1;
|
||||
|
||||
//Fix rotation
|
||||
/*
|
||||
for(int i = 0; i < controlPoints.Length; i++){
|
||||
if(i>0 && Dot(controlPoints[i - 1].rotation, controlPoints[i].rotation) < 0){
|
||||
Quaternion q = controlPoints[i].rotation;
|
||||
controlPoints[i].rotation = new Quaternion(- q.x, - q.y, - q.z, - q.w);
|
||||
ExplorerCore.Log($"cambio orientacion n° {i}");
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// First for loop goes through each individual control point and connects it to the next, so 0-1, 1-2, 2-3 and so on
|
||||
int closedAdjustment = closedLoop ? 0 : 1;
|
||||
int totalframes = 0;//count the total number of frames so we can save the points in the right splinePoints position
|
||||
|
||||
for (int currentPoint = 0; currentPoint < controlPoints.Length - closedAdjustment; currentPoint++)
|
||||
{
|
||||
bool closedLoopFinalPoint = (closedLoop && currentPoint == controlPoints.Length - 1);
|
||||
|
||||
//Had tu add "controlPoints.Length" because C# mod doesnt work well with negative values
|
||||
int previousPoint = closedLoop ? (currentPoint + controlPoints.Length - 1)%(controlPoints.Length) : System.Math.Max(currentPoint - 1, 0);
|
||||
int endSegmentPoint = closedLoop ? (currentPoint + 1)%(controlPoints.Length) : System.Math.Min(currentPoint + 1, controlPoints.Length - 1);
|
||||
int nextPoint = closedLoop ? (currentPoint + 2)%(controlPoints.Length) : System.Math.Min(currentPoint + 2, controlPoints.Length - 1);
|
||||
|
||||
p0 = controlPoints[previousPoint].position;
|
||||
r0 = QuaternionToVector4(controlPoints[previousPoint].rotation);
|
||||
|
||||
p1 = controlPoints[currentPoint].position;
|
||||
r1 = QuaternionToVector4(controlPoints[currentPoint].rotation);
|
||||
|
||||
p2 = controlPoints[endSegmentPoint].position;
|
||||
r2 = QuaternionToVector4(controlPoints[endSegmentPoint].rotation);
|
||||
|
||||
p3 = controlPoints[nextPoint].position;
|
||||
r3 = QuaternionToVector4(controlPoints[nextPoint].rotation);
|
||||
|
||||
//Check if we are using the shortest path on the rotation. If not, change r1 to represent that shortest path.
|
||||
if (Vector4.Dot(r0, r1) < 0)
|
||||
r1 = - r1;
|
||||
|
||||
if (Vector4.Dot(r1, r2) < 0)
|
||||
r2 = - r2;
|
||||
|
||||
if (Vector4.Dot(r2, r3) < 0)
|
||||
r3 = - r3;
|
||||
|
||||
fov0 = controlPoints[currentPoint].fov;
|
||||
fov1 = controlPoints[endSegmentPoint].fov;
|
||||
|
||||
int frames = controlPoints[currentPoint].frames; //resolution and time the node takes to get to the other node
|
||||
float pointStep = 1.0f / frames;
|
||||
|
||||
if ((currentPoint == controlPoints.Length - 2 && !closedLoop) || closedLoopFinalPoint) //Final point
|
||||
{
|
||||
pointStep = 1.0f / (frames - 1); // last point of last segment should reach p1
|
||||
}
|
||||
|
||||
// Creates [frames] points between this control point and the next
|
||||
for (int tesselatedPoint = 0; tesselatedPoint < frames; tesselatedPoint++)
|
||||
{
|
||||
float t = tesselatedPoint * pointStep;
|
||||
|
||||
CatmullRomPoint point = Evaluate(p0, p1, p2, p3, r0, r1, r2, r3, fov0, fov1, t);
|
||||
|
||||
splinePoints[totalframes + tesselatedPoint] = point;
|
||||
}
|
||||
totalframes+=frames;
|
||||
}
|
||||
}
|
||||
|
||||
static CatmullRomPoint Evaluate(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, Vector4 r0, Vector4 r1, Vector4 r2, Vector4 r3, float fovStart, float fovEnd, float t)
|
||||
{
|
||||
Vector3 position = CatmullRomInterpolation(p0, p1, p2, p3, t);
|
||||
Vector4 v4rot = CatmullRomInterpolation(r0, r1, r2, r3, t);
|
||||
Quaternion rotation = new Quaternion(v4rot.x, v4rot.y, v4rot.z, v4rot.w);
|
||||
float fov = Mathf.SmoothStep(fovStart, fovEnd, t);
|
||||
|
||||
return new CatmullRomPoint(position, rotation, fov);
|
||||
}
|
||||
|
||||
//Implementation from: https://qroph.github.io/2018/07/30/smooth-paths-using-catmull-rom-splines.html
|
||||
static Vector3 CatmullRomInterpolation(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t){
|
||||
float tension = 0;
|
||||
float alpha = 0.5f;
|
||||
|
||||
float t01 = (float) System.Math.Pow((double) Vector3.Distance(p0, p1), (double) alpha);
|
||||
float t12 = (float) System.Math.Pow((double) Vector3.Distance(p1, p2), (double) alpha);
|
||||
float t23 = (float) System.Math.Pow((double) Vector3.Distance(p2, p3), (double) alpha);
|
||||
|
||||
Vector3 v1 = t01 != 0 ? (p1 - p0) / t01 : new Vector3(0, 0, 0);
|
||||
Vector3 v2 = t23 != 0 ? (p3 - p2) / t23 : new Vector3(0, 0, 0);
|
||||
|
||||
Vector3 m1 = (1.0f - tension) * (p2 - p1 + t12 * (v1 - (p2 -p0) / (t01 + t12)));
|
||||
Vector3 m2 = (1.0f - tension) * (p2 - p1 + t12 * (v2 - (p3 -p1) / (t12 + t23)));
|
||||
|
||||
Vector3 a = 2.0f * (p1 - p2) + m1 + m2;
|
||||
Vector3 b = -3.0f * (p1 - p2) - m1 - m1 - m2;
|
||||
Vector3 c = m1;
|
||||
Vector3 d = p1;
|
||||
|
||||
return a * t * t * t + b * t * t + c * t + d;
|
||||
}
|
||||
|
||||
static Vector4 CatmullRomInterpolation(Vector4 r0, Vector4 r1, Vector4 r2, Vector4 r3, float t){
|
||||
float tension = 0;
|
||||
float alpha = 0.5f;
|
||||
|
||||
float t01 = (float) System.Math.Pow((double) Vector4.Distance(r0, r1), (double) alpha);
|
||||
float t12 = (float) System.Math.Pow((double) Vector4.Distance(r1, r2), (double) alpha);
|
||||
float t23 = (float) System.Math.Pow((double) Vector4.Distance(r2, r3), (double) alpha);
|
||||
|
||||
Vector4 v1 = t01 != 0 ? (r1 - r0) / t01 : new Vector4(0, 0, 0, 0);
|
||||
Vector4 v2 = t23 != 0 ? (r3 - r2) / t23 : new Vector4(0, 0, 0, 0);
|
||||
|
||||
Vector4 m1 = (1.0f - tension) * (r2 - r1 + t12 * (v1 - (r2 -r0) / (t01 + t12)));
|
||||
Vector4 m2 = (1.0f - tension) * (r2 - r1 + t12 * (v2 - (r3 -r1) / (t12 + t23)));
|
||||
|
||||
Vector4 a = 2.0f * (r1 - r2) + m1 + m2;
|
||||
Vector4 b = -3.0f * (r1 - r2) - m1 - m1 - m2;
|
||||
Vector4 c = m1;
|
||||
Vector4 d = r1;
|
||||
|
||||
return a * t * t * t + b * t * t + c * t + d;
|
||||
//return Vector4.Lerp(r1, r2, t);
|
||||
}
|
||||
|
||||
static Vector3 CatmullRomAlt(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t)
|
||||
{
|
||||
float t2 = t * t;
|
||||
float t3 = t2 * t;
|
||||
|
||||
Vector3 v0 = (p2 - p0) * 0.5f;
|
||||
Vector3 v1 = (p3 - p1) * 0.5f;
|
||||
|
||||
float h1 = 2 * t3 - 3 * t2 + 1;
|
||||
float h2 = -2 * t3 + 3 * t2;
|
||||
float h3 = t3 - 2 * t2 + t;
|
||||
float h4 = t3 - t2;
|
||||
|
||||
Vector3 interpolatedPoint = h1 * p1 + h2 * p2 + h3 * v0 + h4 * v1;
|
||||
return interpolatedPoint;
|
||||
}
|
||||
|
||||
static Vector4 CatmullRomAlt(Vector4 p0, Vector4 p1, Vector4 p2, Vector4 p3, float t)
|
||||
{
|
||||
float t2 = t * t;
|
||||
float t3 = t2 * t;
|
||||
|
||||
Vector4 v0 = (p2 - p0) * 0.5f;
|
||||
Vector4 v1 = (p3 - p1) * 0.5f;
|
||||
|
||||
float h1 = 2 * t3 - 3 * t2 + 1;
|
||||
float h2 = -2 * t3 + 3 * t2;
|
||||
float h3 = t3 - 2 * t2 + t;
|
||||
float h4 = t3 - t2;
|
||||
|
||||
Vector4 interpolatedPoint = h1 * p1 + h2 * p2 + h3 * v0 + h4 * v1;
|
||||
return interpolatedPoint;
|
||||
}
|
||||
|
||||
//Used for calculating path length for constant speed paths
|
||||
public float[] GenerateSplinePointsByRes(int resolution = 3000) //resolution of each segment
|
||||
{
|
||||
List<float> splineSegmentDistances = new List<float>();
|
||||
|
||||
Vector3 p0, p1; //Start point, end point
|
||||
Vector3 m0, m1; //Tangents
|
||||
|
||||
// First for loop goes through each individual control point and connects it to the next, so 0-1, 1-2, 2-3 and so on
|
||||
int closedAdjustment = closedLoop ? 0 : 1;
|
||||
for (int currentPoint = 0; currentPoint < controlPoints.Length - closedAdjustment; currentPoint++)
|
||||
{
|
||||
bool closedLoopFinalPoint = (closedLoop && currentPoint == controlPoints.Length - 1);
|
||||
|
||||
p0 = controlPoints[currentPoint].position;
|
||||
|
||||
if(closedLoopFinalPoint)
|
||||
{
|
||||
p1 = controlPoints[0].position;
|
||||
}
|
||||
else
|
||||
{
|
||||
p1 = controlPoints[currentPoint + 1].position;
|
||||
}
|
||||
|
||||
// m0
|
||||
if (currentPoint == 0) // Tangent M[k] = (P[k+1] - P[k-1]) / 2
|
||||
{
|
||||
if(closedLoop)
|
||||
{
|
||||
m0 = p1 - controlPoints[controlPoints.Length - 1].position;
|
||||
}
|
||||
else
|
||||
{
|
||||
m0 = p1 - p0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m0 = p1 - controlPoints[currentPoint - 1].position;
|
||||
}
|
||||
|
||||
// m1
|
||||
if (closedLoop)
|
||||
{
|
||||
if (currentPoint == controlPoints.Length - 1) //Last point case
|
||||
{
|
||||
m1 = controlPoints[(currentPoint + 2) % controlPoints.Length].position - p0;
|
||||
}
|
||||
else if (currentPoint == 0) //First point case
|
||||
{
|
||||
m1 = controlPoints[currentPoint + 2].position - p0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m1 = controlPoints[(currentPoint + 2) % controlPoints.Length].position - p0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (currentPoint < controlPoints.Length - 2)
|
||||
{
|
||||
m1 = controlPoints[(currentPoint + 2) % controlPoints.Length].position - p0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m1 = p1 - p0;
|
||||
}
|
||||
}
|
||||
|
||||
m0 *= 0.5f; //Doing this here instead of in every single above statement
|
||||
m1 *= 0.5f;
|
||||
|
||||
float pointStep = 1.0f / resolution;
|
||||
|
||||
if ((currentPoint == controlPoints.Length - 2 && !closedLoop) || closedLoopFinalPoint) //Final point
|
||||
{
|
||||
pointStep = 1.0f / (resolution - 1); // last point of last segment should reach p1
|
||||
}
|
||||
|
||||
Vector3 pos1;
|
||||
Vector3 pos0 = new Vector3(0, 0, 0); //simply initialization so the compiler doesnt complain.
|
||||
float segmentDistance = 0;
|
||||
|
||||
// Creates [resolution] points between this control point and the next
|
||||
for (int tesselatedPoint = 1; tesselatedPoint < resolution; tesselatedPoint++)
|
||||
{
|
||||
if(tesselatedPoint == 1)
|
||||
pos0 = CalculatePosition(p0, p1, m0, m1, 0);
|
||||
|
||||
float t = tesselatedPoint * pointStep;
|
||||
pos1 = CalculatePosition(p0, p1, m0, m1, t);
|
||||
segmentDistance += Vector3.Distance(pos0, pos1);
|
||||
|
||||
pos0 = pos1;
|
||||
}
|
||||
|
||||
splineSegmentDistances.Add(segmentDistance);
|
||||
}
|
||||
|
||||
return splineSegmentDistances.ToArray();
|
||||
}
|
||||
|
||||
//Calculates curve position at t[0, 1]
|
||||
public static Vector3 CalculatePosition(Vector3 start, Vector3 end, Vector3 tanPoint1, Vector3 tanPoint2, float t)
|
||||
{
|
||||
// Hermite curve formula:
|
||||
// (2t^3 - 3t^2 + 1) * p0 + (t^3 - 2t^2 + t) * m0 + (-2t^3 + 3t^2) * p1 + (t^3 - t^2) * m1
|
||||
Vector3 position = (2.0f * t * t * t - 3.0f * t * t + 1.0f) * start
|
||||
+ (t * t * t - 2.0f * t * t + t) * tanPoint1
|
||||
+ (-2.0f * t * t * t + 3.0f * t * t) * end
|
||||
+ (t * t * t - t * t) * tanPoint2;
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
static Vector4 QuaternionToVector4(Quaternion q){
|
||||
return new Vector4(q.x, q.y, q.z, q.w);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-6
@@ -7,6 +7,7 @@ global using UnityEngine;
|
||||
global using UnityEngine.UI;
|
||||
global using UniverseLib;
|
||||
global using UniverseLib.Utility;
|
||||
using UnityExplorer.CatmullRom;
|
||||
using UnityExplorer.Config;
|
||||
using UnityExplorer.ObjectExplorer;
|
||||
using UnityExplorer.Runtime;
|
||||
@@ -29,8 +30,6 @@ namespace UnityExplorer
|
||||
|
||||
public static HarmonyLib.Harmony Harmony { get; } = new HarmonyLib.Harmony(GUID);
|
||||
|
||||
public static CatmullRom CameraPathsManager = null;
|
||||
|
||||
/// <summary>
|
||||
/// Initialize UnityExplorer with the provided Loader implementation.
|
||||
/// </summary>
|
||||
@@ -59,7 +58,7 @@ namespace UnityExplorer
|
||||
UnityCrashPrevention.Init();
|
||||
|
||||
//Extra inits
|
||||
KeypressListener.Setup();
|
||||
KeypressListener.Setup();
|
||||
}
|
||||
|
||||
// Do a delayed setup so that objects aren't destroyed instantly.
|
||||
@@ -85,9 +84,6 @@ namespace UnityExplorer
|
||||
{
|
||||
UIManager.ShowMenu = !UIManager.ShowMenu;
|
||||
}
|
||||
|
||||
if(CameraPathsManager != null)
|
||||
CameraPathsManager.MaybeRunPath();
|
||||
}
|
||||
|
||||
|
||||
|
||||
+46
-101
@@ -21,20 +21,18 @@ namespace UnityExplorer.UI.Panels
|
||||
{
|
||||
}
|
||||
|
||||
public override string Name => "CamPaths";
|
||||
public override string Name => "Cam Paths";
|
||||
public override UIManager.Panels PanelType => UIManager.Panels.CamPaths;
|
||||
public override int MinWidth => 1000;
|
||||
public override int MinWidth => 600;
|
||||
public override int MinHeight => 600;
|
||||
public override Vector2 DefaultAnchorMin => new(0.4f, 0.4f);
|
||||
public override Vector2 DefaultAnchorMax => new(0.6f, 0.6f);
|
||||
public override bool NavButtonWanted => true;
|
||||
public override bool ShouldSaveActiveState => true;
|
||||
public List<CatmullRom.PathControlPoint> controlPoints = new List<CatmullRom.PathControlPoint>();
|
||||
public List<CatmullRom.CatmullRomPoint> controlPoints = new List<CatmullRom.CatmullRomPoint>();
|
||||
List<GameObject> UINodes = new List<GameObject>();
|
||||
bool closedLoop;
|
||||
|
||||
bool constantSpeed;
|
||||
int pathTotalFrames = 2000;
|
||||
float speed = 10;
|
||||
|
||||
// ~~~~~~~~ UI construction / callbacks ~~~~~~~~
|
||||
|
||||
@@ -44,24 +42,27 @@ namespace UnityExplorer.UI.Panels
|
||||
default, new Color(1, 1, 1, 0), TextAnchor.MiddleLeft);
|
||||
UIFactory.SetLayoutElement(horiGroup, minHeight: 25, flexibleWidth: 9999);
|
||||
|
||||
ButtonRef startButton = UIFactory.CreateButton(horiGroup, "Start", "Start CamPath");
|
||||
UIFactory.SetLayoutElement(startButton.GameObject, minWidth: 150, minHeight: 25, flexibleWidth: 9999);
|
||||
ButtonRef startButton = UIFactory.CreateButton(horiGroup, "Start", "▶");
|
||||
UIFactory.SetLayoutElement(startButton.GameObject, minWidth: 50, minHeight: 25);
|
||||
startButton.ButtonText.fontSize = 20;
|
||||
startButton.OnClick += StartButton_OnClick;
|
||||
|
||||
ButtonRef pauseContinueButton = UIFactory.CreateButton(horiGroup, "Pause/Continue", "Pause/Continue");
|
||||
UIFactory.SetLayoutElement(pauseContinueButton.GameObject, minWidth: 150, minHeight: 25, flexibleWidth: 9999);
|
||||
pauseContinueButton.OnClick += PauseContinue_OnClick;
|
||||
ButtonRef pauseContinueButton = UIFactory.CreateButton(horiGroup, "Pause/Continue", "❚❚/▶");
|
||||
UIFactory.SetLayoutElement(pauseContinueButton.GameObject, minWidth: 50, minHeight: 25);
|
||||
pauseContinueButton.ButtonText.fontSize = 20;
|
||||
pauseContinueButton.OnClick += TogglePause_OnClick;
|
||||
|
||||
ButtonRef stopButton = UIFactory.CreateButton(horiGroup, "Stop", "Stop CamPath");
|
||||
UIFactory.SetLayoutElement(stopButton.GameObject, minWidth: 150, minHeight: 25, flexibleWidth: 9999);
|
||||
ButtonRef stopButton = UIFactory.CreateButton(horiGroup, "Stop", "■");
|
||||
UIFactory.SetLayoutElement(stopButton.GameObject, minWidth: 50, minHeight: 25);
|
||||
stopButton.ButtonText.fontSize = 20;
|
||||
stopButton.OnClick += Stop_OnClick;
|
||||
|
||||
ButtonRef AddNode = UIFactory.CreateButton(horiGroup, "AddCamNode", "Add Cam node");
|
||||
UIFactory.SetLayoutElement(AddNode.GameObject, minWidth: 150, minHeight: 25, flexibleWidth: 9999);
|
||||
UIFactory.SetLayoutElement(AddNode.GameObject, minWidth: 150, minHeight: 25);
|
||||
AddNode.OnClick += AddNode_OnClick;
|
||||
|
||||
ButtonRef DeletePath = UIFactory.CreateButton(horiGroup, "DeletePath", "Delete Path");
|
||||
UIFactory.SetLayoutElement(DeletePath.GameObject, minWidth: 150, minHeight: 25, flexibleWidth: 9999);
|
||||
UIFactory.SetLayoutElement(DeletePath.GameObject, minWidth: 150, minHeight: 25);
|
||||
DeletePath.OnClick += () => {controlPoints.Clear(); UpdateListNodes();};
|
||||
|
||||
Toggle closedLoopToggle = new Toggle();
|
||||
@@ -71,16 +72,9 @@ namespace UnityExplorer.UI.Panels
|
||||
closedLoopToggle.isOn = false;
|
||||
toggleClosedLoopText.text = "Close path in a loop";
|
||||
|
||||
Toggle constantspeedToggle = new Toggle();
|
||||
GameObject toggleConstantSpeedObj = UIFactory.CreateToggle(horiGroup, "Constant speed", out constantspeedToggle, out Text toggleConstantSpeedText);
|
||||
UIFactory.SetLayoutElement(toggleConstantSpeedObj, minHeight: 25, flexibleWidth: 9999);
|
||||
constantspeedToggle.onValueChanged.AddListener((isConstantSpeed) => {constantSpeed = isConstantSpeed; UpdateListNodes();});
|
||||
constantspeedToggle.isOn = false;
|
||||
toggleConstantSpeedText.text = "Constant speed";
|
||||
|
||||
InputFieldRef CompletePathFramesInput = null;
|
||||
AddInputField("Frames", "Constant speed complete path duration (in frames):", "Default: 2000", out CompletePathFramesInput, TotalFrames_OnEndEdit, false);
|
||||
CompletePathFramesInput.Text = pathTotalFrames.ToString();
|
||||
InputFieldRef SpeedInput = null;
|
||||
AddInputField("Speed", "Path speed:", $"Default: {speed}", out SpeedInput, Speed_OnEndEdit, false);
|
||||
SpeedInput.Text = speed.ToString();
|
||||
}
|
||||
|
||||
private void UpdateListNodes(){
|
||||
@@ -91,12 +85,12 @@ namespace UnityExplorer.UI.Panels
|
||||
}
|
||||
|
||||
for(int i = 0; i < controlPoints.Count; i++) {
|
||||
CatmullRom.PathControlPoint point = controlPoints[i];
|
||||
CatmullRom.CatmullRomPoint point = controlPoints[i];
|
||||
DrawNodeOptions(point, i);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawNodeOptions(CatmullRom.PathControlPoint point, int index){
|
||||
private void DrawNodeOptions(CatmullRom.CatmullRomPoint point, int index){
|
||||
GameObject horiGroup = UIFactory.CreateHorizontalGroup(ContentRoot, "LightOptions", true, false, true, false, 4,
|
||||
default, new Color(1, 1, 1, 0), TextAnchor.MiddleLeft);
|
||||
UIFactory.SetLayoutElement(horiGroup, minHeight: 25, flexibleWidth: 9999);
|
||||
@@ -121,32 +115,9 @@ namespace UnityExplorer.UI.Panels
|
||||
UIFactory.SetLayoutElement(destroyButton.GameObject, minWidth: 80, minHeight: 25, flexibleWidth: 9999);
|
||||
destroyButton.OnClick += () => {controlPoints.Remove(point); UpdateListNodes();};
|
||||
|
||||
//Frames
|
||||
if (!constantSpeed){
|
||||
InputFieldRef framesInput = null;
|
||||
AddInputField("Frames", "Length (in frames):", $"Default: {point.frames}", out framesInput, (frames) => { FramesInput_OnEndEdit(point, index, frames); });
|
||||
framesInput.Text = point.frames.ToString();
|
||||
}
|
||||
|
||||
//ShowPos and rot?
|
||||
}
|
||||
|
||||
void PauseContinue_OnClick(){
|
||||
if(ExplorerCore.CameraPathsManager.playingPath)
|
||||
ExplorerCore.CameraPathsManager.Pause();
|
||||
else
|
||||
ExplorerCore.CameraPathsManager.Continue();
|
||||
}
|
||||
|
||||
void Stop_OnClick(){
|
||||
CatmullRom.PathControlPoint point = controlPoints[0];
|
||||
ExplorerCore.CameraPathsManager.Stop();
|
||||
|
||||
FreeCamPanel.ourCamera.transform.position = point.position;
|
||||
FreeCamPanel.ourCamera.transform.rotation = point.rotation;
|
||||
FreeCamPanel.ourCamera.fieldOfView = point.fov;
|
||||
}
|
||||
|
||||
GameObject AddInputField(string name, string labelText, string placeHolder, out InputFieldRef inputField, Action<string> onInputEndEdit, bool shouldDeleteOnUpdate = true)
|
||||
{
|
||||
GameObject row = UIFactory.CreateHorizontalGroup(ContentRoot, "Editor Field",
|
||||
@@ -155,10 +126,10 @@ namespace UnityExplorer.UI.Panels
|
||||
UINodes.Add(row); //To delete it when we update the node list
|
||||
|
||||
Text posLabel = UIFactory.CreateLabel(row, $"{name}_Label", labelText);
|
||||
UIFactory.SetLayoutElement(posLabel.gameObject, minWidth: 100, minHeight: 25);
|
||||
UIFactory.SetLayoutElement(posLabel.gameObject, minWidth: 80, minHeight: 25);
|
||||
|
||||
inputField = UIFactory.CreateInputField(row, $"{name}_Input", placeHolder);
|
||||
UIFactory.SetLayoutElement(inputField.GameObject, minWidth: 125, minHeight: 25, flexibleWidth: 9999);
|
||||
UIFactory.SetLayoutElement(inputField.GameObject, minWidth: 50, minHeight: 25);
|
||||
inputField.Component.GetOnEndEdit().AddListener(onInputEndEdit);
|
||||
|
||||
return row;
|
||||
@@ -166,78 +137,52 @@ namespace UnityExplorer.UI.Panels
|
||||
|
||||
void StartButton_OnClick()
|
||||
{
|
||||
//float normalExtrusion = 0;
|
||||
//float tangentExtrusion = 0;
|
||||
|
||||
if(ExplorerCore.CameraPathsManager == null)
|
||||
ExplorerCore.CameraPathsManager = new CatmullRom(controlPoints.ToArray(), closedLoop);
|
||||
else{
|
||||
ExplorerCore.CameraPathsManager.Update(closedLoop);
|
||||
ExplorerCore.CameraPathsManager.Update(controlPoints.ToArray());
|
||||
if(GetCameraPathsManager()){
|
||||
GetCameraPathsManager().setClosedLoop(closedLoop);
|
||||
GetCameraPathsManager().setSplinePoints(controlPoints.ToArray());
|
||||
GetCameraPathsManager().setSpeed(speed);
|
||||
GetCameraPathsManager().StartPath();
|
||||
}
|
||||
|
||||
if(constantSpeed){
|
||||
UpdateNodeFramesConstantspeed();
|
||||
}
|
||||
|
||||
ExplorerCore.CameraPathsManager.StartPath();
|
||||
}
|
||||
|
||||
void FramesInput_OnEndEdit(CatmullRom.PathControlPoint point, int index, string input){
|
||||
EventSystemHelper.SetSelectedGameObject(null);
|
||||
|
||||
if (!ParseUtility.TryParse(input, out int parsed, out Exception parseEx))
|
||||
{
|
||||
ExplorerCore.LogWarning($"Could not parse value: {parseEx.ReflectionExToString()}");
|
||||
//ui_input.Text = point.frames.ToString();
|
||||
return;
|
||||
void TogglePause_OnClick(){
|
||||
if(GetCameraPathsManager()){
|
||||
GetCameraPathsManager().TogglePause();
|
||||
}
|
||||
}
|
||||
|
||||
int frames = parsed;
|
||||
|
||||
if(frames > 1){
|
||||
point.frames = frames;
|
||||
controlPoints[index] = point;
|
||||
void Stop_OnClick(){
|
||||
if (GetCameraPathsManager()){
|
||||
GetCameraPathsManager().Stop();
|
||||
}
|
||||
else
|
||||
throw new ArgumentException("Catmull Rom Error: Too few frames!");
|
||||
}
|
||||
|
||||
void AddNode_OnClick(){
|
||||
Camera freeCam = FreeCamPanel.ourCamera;
|
||||
CatmullRom.PathControlPoint point = new CatmullRom.PathControlPoint(freeCam.transform.position, freeCam.transform.rotation, freeCam.fieldOfView);
|
||||
CatmullRom.CatmullRomPoint point = new CatmullRom.CatmullRomPoint(freeCam.transform.position, freeCam.transform.rotation, freeCam.fieldOfView);
|
||||
ExplorerCore.LogWarning($"Added point: {point.position}");
|
||||
controlPoints.Add(point);
|
||||
|
||||
UpdateListNodes();
|
||||
}
|
||||
|
||||
void UpdateNodeFramesConstantspeed(){
|
||||
float[] d = ExplorerCore.CameraPathsManager.GenerateSplinePointsByRes(3000);
|
||||
float dTotal = d.Sum();
|
||||
int closedAdjustment = closedLoop ? 0 : 1;
|
||||
|
||||
for(int i = 0; i < controlPoints.Count - closedAdjustment; i++) {
|
||||
CatmullRom.PathControlPoint point = controlPoints[i];
|
||||
point.frames = (int)(pathTotalFrames *(d[i] / dTotal));
|
||||
controlPoints[i] = point;
|
||||
}
|
||||
|
||||
ExplorerCore.CameraPathsManager.Update(controlPoints.ToArray());
|
||||
}
|
||||
|
||||
|
||||
void TotalFrames_OnEndEdit(string input)
|
||||
void Speed_OnEndEdit(string input)
|
||||
{
|
||||
EventSystemHelper.SetSelectedGameObject(null);
|
||||
|
||||
if (!ParseUtility.TryParse(input, out int parsed, out Exception parseEx))
|
||||
{
|
||||
ExplorerCore.LogWarning($"Could not parse value: {parseEx.ReflectionExToString()}");
|
||||
//pathTotalFrames.Text = pathTotalFrames.ToString();
|
||||
return;
|
||||
}
|
||||
|
||||
pathTotalFrames = parsed;
|
||||
speed = parsed;
|
||||
if(GetCameraPathsManager()){
|
||||
GetCameraPathsManager().setSpeed(speed);
|
||||
}
|
||||
}
|
||||
|
||||
private CatmullRom.CatmullRomMover GetCameraPathsManager(){
|
||||
return FreeCamPanel.cameraPathMover;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ namespace UnityExplorer.UI.Panels
|
||||
public static Camera ourCamera;
|
||||
internal static Camera lastMainCamera;
|
||||
internal static FreeCamBehaviour freeCamScript;
|
||||
internal static CatmullRom.CatmullRomMover cameraPathMover;
|
||||
|
||||
internal static float desiredMoveSpeed = 5f;
|
||||
|
||||
@@ -121,6 +122,9 @@ namespace UnityExplorer.UI.Panels
|
||||
if (!freeCamScript)
|
||||
freeCamScript = ourCamera.gameObject.AddComponent<FreeCamBehaviour>();
|
||||
|
||||
if (!cameraPathMover)
|
||||
cameraPathMover = ourCamera.gameObject.AddComponent<CatmullRom.CatmullRomMover>();
|
||||
|
||||
ourCamera.transform.position = (Vector3)currentUserCameraPosition;
|
||||
ourCamera.transform.rotation = (Quaternion)currentUserCameraRotation;
|
||||
|
||||
@@ -156,6 +160,12 @@ namespace UnityExplorer.UI.Panels
|
||||
freeCamScript = null;
|
||||
}
|
||||
|
||||
if (cameraPathMover)
|
||||
{
|
||||
GameObject.Destroy(cameraPathMover);
|
||||
cameraPathMover = null;
|
||||
}
|
||||
|
||||
if (lastMainCamera)
|
||||
lastMainCamera.enabled = true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,365 @@
|
||||
using UnityExplorer.UI.Panels;
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
#if UNHOLLOWER
|
||||
using UnhollowerRuntimeLib;
|
||||
#endif
|
||||
#if INTEROP
|
||||
using Il2CppInterop.Runtime.Injection;
|
||||
#endif
|
||||
|
||||
namespace UnityExplorer.CatmullRom
|
||||
{
|
||||
// Struct to keep position, rotation and fov of a spline point
|
||||
[System.Serializable]
|
||||
public struct CatmullRomPoint
|
||||
{
|
||||
public Vector3 position;
|
||||
public Quaternion rotation;
|
||||
public float fov;
|
||||
|
||||
public CatmullRomPoint(Vector3 position, Quaternion rotation, float fov)
|
||||
{
|
||||
this.position = position;
|
||||
this.rotation = rotation;
|
||||
this.fov = fov;
|
||||
}
|
||||
|
||||
public CatmullRomPoint(Vector3 position, Vector4 rotation, float fov)
|
||||
{
|
||||
this.position = position;
|
||||
this.rotation = Vector4ToQuaternion(rotation);
|
||||
this.fov = fov;
|
||||
}
|
||||
|
||||
public static Vector4 QuaternionToVector4(Quaternion q){
|
||||
return new Vector4(q.x, q.y, q.z, q.w);
|
||||
}
|
||||
|
||||
public static Quaternion Vector4ToQuaternion(Vector4 v){
|
||||
return new Quaternion(v.x, v.y, v.z, v.w);
|
||||
}
|
||||
|
||||
public static CatmullRomPoint operator +(CatmullRomPoint a, CatmullRomPoint b)
|
||||
{
|
||||
Vector4 ra = QuaternionToVector4(a.rotation);
|
||||
Vector4 rb = QuaternionToVector4(b.rotation);
|
||||
|
||||
Vector4 newRot = ra + rb;
|
||||
return new CatmullRomPoint(a.position + b.position, Vector4ToQuaternion(newRot), a.fov + b.fov); // what to do with the fov??
|
||||
}
|
||||
|
||||
public static CatmullRomPoint operator -(CatmullRomPoint a, CatmullRomPoint b)
|
||||
{
|
||||
Vector4 newRot = QuaternionToVector4(a.rotation) - QuaternionToVector4(b.rotation);
|
||||
return new CatmullRomPoint(a.position - b.position, Vector4ToQuaternion(newRot), a.fov - b.fov); // what to do with the fov??
|
||||
}
|
||||
|
||||
public static CatmullRomPoint operator /(CatmullRomPoint a, float b)
|
||||
{
|
||||
//Vector4 newRot = QuaternionToVector4(a.rotation)/b;
|
||||
//return new CatmullRomPoint(a.position/b, Vector4ToQuaternion(newRot), a.fov / b); // what to do with the fov??
|
||||
return new CatmullRomPoint(a.position/b, a.rotation, a.fov);
|
||||
}
|
||||
|
||||
public static CatmullRomPoint operator *(CatmullRomPoint a, float b)
|
||||
{
|
||||
//Vector4 newRot = QuaternionToVector4(a.rotation)*b;
|
||||
//return new CatmullRomPoint(a.position*b, Vector4ToQuaternion(newRot), a.fov * b); // what to do with the fov??
|
||||
return new CatmullRomPoint(a.position*b, a.rotation, a.fov); // what to do with the fov??
|
||||
}
|
||||
|
||||
public CatmullRomPoint Normalize()
|
||||
{
|
||||
position.Normalize();
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public class CatmullRomMover : MonoBehaviour
|
||||
{
|
||||
#if CPP
|
||||
static CatmullRomMover()
|
||||
{
|
||||
ClassInjector.RegisterTypeInIl2Cpp<CatmullRomMover>();
|
||||
}
|
||||
|
||||
public CatmullRomMover(IntPtr ptr) : base(ptr) { }
|
||||
#endif
|
||||
|
||||
bool playingPath;
|
||||
private bool closedLoop;
|
||||
private CatmullRomPoint[] splinePoints;
|
||||
// The point the camera will be following along the path
|
||||
private CatmullRomPoint lookahead;
|
||||
// How smooth the path is (beware of not making too many calculations per update tho)
|
||||
float lookaheadDelta;
|
||||
float speed;
|
||||
// Current position in the path, from 0 to 1
|
||||
float delta;
|
||||
|
||||
public CatmullRomMover(){
|
||||
splinePoints = new CatmullRomPoint[] { };
|
||||
speed = 10;
|
||||
lookaheadDelta = 0.01f;
|
||||
delta = lookaheadDelta;
|
||||
}
|
||||
|
||||
public void StartPath(){
|
||||
if(splinePoints == null || splinePoints.Length <= 2)
|
||||
{
|
||||
ExplorerCore.Log(splinePoints);
|
||||
throw new ArgumentException("Catmull Rom Error: Too few spline points!");
|
||||
}
|
||||
else {
|
||||
playingPath = true;
|
||||
MoveCameraToPoint(splinePoints[0]);
|
||||
lookahead = GetPointFromPath(delta);
|
||||
}
|
||||
}
|
||||
|
||||
public void TogglePause(){
|
||||
playingPath = !playingPath;
|
||||
}
|
||||
|
||||
public void Stop(){
|
||||
playingPath = false;
|
||||
delta = lookaheadDelta;
|
||||
lookahead = GetPointFromPath(delta);
|
||||
MoveCameraToPoint(splinePoints[0]);
|
||||
}
|
||||
|
||||
public void setClosedLoop(bool newClosedLoop){
|
||||
closedLoop = newClosedLoop;
|
||||
ExplorerCore.LogWarning("Update closedLoop!");
|
||||
}
|
||||
|
||||
public void setSplinePoints(CatmullRomPoint[] newSplinePoints){
|
||||
splinePoints = newSplinePoints;
|
||||
ExplorerCore.LogWarning("Update spline points!");
|
||||
}
|
||||
|
||||
public void setSpeed(float newSpeed){
|
||||
speed = newSpeed;
|
||||
lookaheadDelta = newSpeed / 1000;
|
||||
}
|
||||
|
||||
public void Update(){
|
||||
if (delta >= 1 && FreeCamPanel.ourCamera != null){
|
||||
playingPath = false;
|
||||
delta = lookaheadDelta;
|
||||
}
|
||||
if (playingPath) AdvanceMover(Time.deltaTime);
|
||||
}
|
||||
|
||||
/*
|
||||
private CatmullRomPoint GetPointFromPath(float d){
|
||||
//ExplorerCore.LogWarning(splinePoints.Length);
|
||||
int currentSegment = (int)(splinePoints.Length * d); // have to do + 1 if closed loop
|
||||
//ExplorerCore.LogWarning(currentSegment);
|
||||
CatmullRomPoint lastPointInPath = splinePoints[Math.Min(currentSegment, splinePoints.Length - 1)];
|
||||
CatmullRomPoint nextPointInPath = splinePoints[Math.Min(currentSegment + 1, splinePoints.Length - 1)];
|
||||
|
||||
float interpolationBetweenPaths = (d - (float)currentSegment / (float)splinePoints.Length) * (float)splinePoints.Length;
|
||||
// Dumb Lerp to test things. Should use proper CatmullRom instead.
|
||||
return lastPointInPath * (1 - interpolationBetweenPaths) + nextPointInPath * interpolationBetweenPaths;
|
||||
}
|
||||
*/
|
||||
|
||||
private CatmullRomPoint GetCurrentPoint(){
|
||||
return new CatmullRomPoint(FreeCamPanel.ourCamera.transform.position, FreeCamPanel.ourCamera.transform.rotation, FreeCamPanel.ourCamera.fieldOfView);
|
||||
}
|
||||
|
||||
private void AdvanceMover(float dt){
|
||||
// We use 0.01665f (60fps) in place of Time.DeltaTime so the camera moves at fullspeed even in slow motion.
|
||||
float move = 0.01665f * speed; // units to move
|
||||
while (move > 0.0) {
|
||||
CatmullRomPoint currentPoint = GetCurrentPoint();
|
||||
// distance between target and current position
|
||||
float room = Vector3.Distance(lookahead.position, currentPoint.position);
|
||||
|
||||
// how much we're actually moving this iteration
|
||||
// move the whole distance to the lookahead, or would the move cut us short
|
||||
float actual = Math.Min(move, room);
|
||||
|
||||
MoveCameraStep(currentPoint, actual, room);
|
||||
|
||||
// update move to be the remaining amount we need to move
|
||||
move -= actual;
|
||||
//ExplorerCore.LogWarning($"move: {move}, actual: {actual}, room: {room}, delta:{delta}");
|
||||
currentPoint = GetCurrentPoint();
|
||||
if(delta > 1) break;
|
||||
//ExplorerCore.LogWarning($"currentPoint.position: {currentPoint.position}, currentPoint.rotation: {currentPoint.rotation}");
|
||||
|
||||
// update room to check if we need a new lookahead
|
||||
room = Vector3.Distance(lookahead.position, currentPoint.position);
|
||||
// while ends, need another lookaheadDelta for the next Update
|
||||
if (room <= 0) {
|
||||
delta += lookaheadDelta;
|
||||
lookahead = GetPointFromPath(delta);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void MoveCameraStep(CatmullRomPoint currentPoint, float actual, float room){
|
||||
// move my position accordingly
|
||||
//CatmullRomPoint direction = ((lookahead - currentPoint) / room)*actual;
|
||||
|
||||
CatmullRomPoint direction = (lookahead - currentPoint).Normalize() * actual;
|
||||
//float rotationDiff = Vector4.Distance(CatmullRomPoint.QuaternionToVector4(lookahead.rotation), CatmullRomPoint.QuaternionToVector4(currentPoint.rotation));
|
||||
//ExplorerCore.LogWarning($"direction.rotation: {direction.rotation}, rotation diff: {rotationDiff}");
|
||||
|
||||
Vector4 ra = CatmullRomPoint.QuaternionToVector4(currentPoint.rotation);
|
||||
Vector4 rb = CatmullRomPoint.QuaternionToVector4(direction.rotation) * actual / room;
|
||||
|
||||
if (Vector4.Dot(ra, rb) < 0)
|
||||
{
|
||||
//ExplorerCore.LogWarning($"tengo que arreglar quaternion");
|
||||
rb = - rb;
|
||||
}
|
||||
FreeCamPanel.ourCamera.transform.position += direction.position;
|
||||
FreeCamPanel.ourCamera.transform.rotation = CatmullRomPoint.Vector4ToQuaternion(ra + rb);
|
||||
//FreeCamPanel.ourCamera.transform.rotation = lookahead.rotation;
|
||||
FreeCamPanel.ourCamera.fieldOfView += direction.fov * actual / room;
|
||||
//ExplorerCore.LogWarning($"current cam pos: {FreeCamPanel.ourCamera.transform.position} at d: {delta}");
|
||||
}
|
||||
|
||||
public void MoveCameraToPoint(CatmullRomPoint newPoint){
|
||||
FreeCamPanel.ourCamera.transform.position = newPoint.position;
|
||||
FreeCamPanel.ourCamera.transform.rotation = newPoint.rotation;
|
||||
FreeCamPanel.ourCamera.fieldOfView = newPoint.fov;
|
||||
}
|
||||
|
||||
/*test*/
|
||||
private CatmullRomPoint GetPointFromPath(float d)
|
||||
{
|
||||
Vector3 p0, p1, p2, p3; //Previous position, Start position, end position, Next position
|
||||
Vector4 r0, r1, r2, r3; //Previous rotation, Start rotation, end rotation, Next rotation
|
||||
float fov0, fov1;
|
||||
|
||||
//Fix rotation
|
||||
/*
|
||||
for(int i = 0; i < splinePoints.Length; i++){
|
||||
if(i>0 && Dot(splinePoints[i - 1].rotation, splinePoints[i].rotation) < 0){
|
||||
Quaternion q = splinePoints[i].rotation;
|
||||
splinePoints[i].rotation = new Quaternion(- q.x, - q.y, - q.z, - q.w);
|
||||
ExplorerCore.Log($"cambio orientacion n° {i}");
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// First for loop goes through each individual control point and connects it to the next, so 0-1, 1-2, 2-3 and so on
|
||||
int closedAdjustment = closedLoop ? 0 : 1;
|
||||
|
||||
int currentPoint = (int)((splinePoints.Length - closedAdjustment) * d); // have to do + 1 if closed loop
|
||||
|
||||
//ExplorerCore.LogWarning($"currentPoint: {currentPoint}, d: {d}");
|
||||
|
||||
bool closedLoopFinalPoint = (closedLoop && currentPoint == splinePoints.Length - 1);
|
||||
|
||||
//Had tu add "splinePoints.Length" because C# mod doesnt work well with negative values
|
||||
int previousPoint = closedLoop ? (currentPoint + splinePoints.Length - 1)%(splinePoints.Length) : System.Math.Max(currentPoint - 1, 0);
|
||||
int endSegmentPoint = closedLoop ? (currentPoint + 1)%(splinePoints.Length) : System.Math.Min(currentPoint + 1, splinePoints.Length - 1);
|
||||
int nextPoint = closedLoop ? (currentPoint + 2)%(splinePoints.Length) : System.Math.Min(currentPoint + 2, splinePoints.Length - 1);
|
||||
|
||||
ExplorerCore.LogWarning($"p0: {previousPoint}, p1: {currentPoint}, p2: {endSegmentPoint}, p3: {nextPoint},");
|
||||
|
||||
p0 = splinePoints[previousPoint].position;
|
||||
r0 = CatmullRomPoint.QuaternionToVector4(splinePoints[previousPoint].rotation);
|
||||
|
||||
p1 = splinePoints[currentPoint].position;
|
||||
r1 = CatmullRomPoint.QuaternionToVector4(splinePoints[currentPoint].rotation);
|
||||
|
||||
p2 = splinePoints[endSegmentPoint].position;
|
||||
r2 = CatmullRomPoint.QuaternionToVector4(splinePoints[endSegmentPoint].rotation);
|
||||
|
||||
p3 = splinePoints[nextPoint].position;
|
||||
r3 = CatmullRomPoint.QuaternionToVector4(splinePoints[nextPoint].rotation);
|
||||
|
||||
if (d >= 1) return splinePoints[currentPoint];
|
||||
|
||||
//Check if we are using the shortest path on the rotation. If not, change r1 to represent that shortest path.
|
||||
if (Vector4.Dot(r0, r1) < 0)
|
||||
r1 = - r1;
|
||||
|
||||
if (Vector4.Dot(r1, r2) < 0)
|
||||
r2 = - r2;
|
||||
|
||||
if (Vector4.Dot(r2, r3) < 0)
|
||||
r3 = - r3;
|
||||
|
||||
fov0 = splinePoints[currentPoint].fov;
|
||||
fov1 = splinePoints[endSegmentPoint].fov;
|
||||
|
||||
//float t = (d - (float)currentPoint / (float)(splinePoints.Length + closedAdjustment)) * (float)(splinePoints.Length + closedAdjustment);
|
||||
float t = ((splinePoints.Length - closedAdjustment) * d) % 1;
|
||||
|
||||
//ExplorerCore.LogWarning($"t: {t}, d: {d}");
|
||||
|
||||
CatmullRomPoint newPoint = Evaluate(p0, p1, p2, p3, r0, r1, r2, r3, fov0, fov1, t);
|
||||
|
||||
//ExplorerCore.LogWarning($"p1.pos: {p1}, p2.pos: {p2}, t: {t}, dist-p1: {Vector3.Distance(GetCurrentPoint().position, p1)}, dist-p2: {Vector3.Distance(GetCurrentPoint().position, p2)}");
|
||||
|
||||
return newPoint;
|
||||
}
|
||||
|
||||
private CatmullRomPoint Evaluate(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, Vector4 r0, Vector4 r1, Vector4 r2, Vector4 r3, float fovStart, float fovEnd, float t)
|
||||
{
|
||||
Vector3 position = CatmullRomInterpolation(p0, p1, p2, p3, t);
|
||||
Vector4 v4rot = CatmullRomInterpolation(r0, r1, r2, r3, t);
|
||||
Quaternion rotation = new Quaternion(v4rot.x, v4rot.y, v4rot.z, v4rot.w);
|
||||
float fov = Mathf.SmoothStep(fovStart, fovEnd, t);
|
||||
|
||||
return new CatmullRomPoint(position, rotation, fov);
|
||||
}
|
||||
|
||||
//Implementation from: https://qroph.github.io/2018/07/30/smooth-paths-using-catmull-rom-splines.html
|
||||
private Vector3 CatmullRomInterpolation(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t){
|
||||
float tension = 0;
|
||||
float alpha = 0.5f;
|
||||
|
||||
float t01 = (float) System.Math.Pow((double) Vector3.Distance(p0, p1), (double) alpha);
|
||||
float t12 = (float) System.Math.Pow((double) Vector3.Distance(p1, p2), (double) alpha);
|
||||
float t23 = (float) System.Math.Pow((double) Vector3.Distance(p2, p3), (double) alpha);
|
||||
|
||||
Vector3 v1 = t01 != 0 ? (p1 - p0) / t01 : new Vector3(0, 0, 0);
|
||||
Vector3 v2 = t23 != 0 ? (p3 - p2) / t23 : new Vector3(0, 0, 0);
|
||||
|
||||
Vector3 m1 = (1.0f - tension) * (p2 - p1 + t12 * (v1 - (p2 -p0) / (t01 + t12)));
|
||||
Vector3 m2 = (1.0f - tension) * (p2 - p1 + t12 * (v2 - (p3 -p1) / (t12 + t23)));
|
||||
|
||||
Vector3 a = 2.0f * (p1 - p2) + m1 + m2;
|
||||
Vector3 b = -3.0f * (p1 - p2) - m1 - m1 - m2;
|
||||
Vector3 c = m1;
|
||||
Vector3 d = p1;
|
||||
|
||||
return a * t * t * t + b * t * t + c * t + d;
|
||||
}
|
||||
|
||||
private Vector4 CatmullRomInterpolation(Vector4 r0, Vector4 r1, Vector4 r2, Vector4 r3, float t){
|
||||
float tension = 0;
|
||||
float alpha = 0.5f;
|
||||
|
||||
float t01 = (float) System.Math.Pow((double) Vector4.Distance(r0, r1), (double) alpha);
|
||||
float t12 = (float) System.Math.Pow((double) Vector4.Distance(r1, r2), (double) alpha);
|
||||
float t23 = (float) System.Math.Pow((double) Vector4.Distance(r2, r3), (double) alpha);
|
||||
|
||||
Vector4 v1 = t01 != 0 ? (r1 - r0) / t01 : new Vector4(0, 0, 0, 0);
|
||||
Vector4 v2 = t23 != 0 ? (r3 - r2) / t23 : new Vector4(0, 0, 0, 0);
|
||||
|
||||
Vector4 m1 = (1.0f - tension) * (r2 - r1 + t12 * (v1 - (r2 -r0) / (t01 + t12)));
|
||||
Vector4 m2 = (1.0f - tension) * (r2 - r1 + t12 * (v2 - (r3 -r1) / (t12 + t23)));
|
||||
|
||||
Vector4 a = 2.0f * (r1 - r2) + m1 + m2;
|
||||
Vector4 b = -3.0f * (r1 - r2) - m1 - m1 - m2;
|
||||
Vector4 c = m1;
|
||||
Vector4 d = r1;
|
||||
|
||||
return a * t * t * t + b * t * t + c * t + d;
|
||||
//return Vector4.Lerp(r1, r2, t);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user