1
0
mirror of https://github.com/originalnicodr/CinematicUnityExplorer.git synced 2026-10-10 21:13:15 +08:00

Added custom frame amount for each node.

This commit is contained in:
originalnicodr
2023-03-01 17:55:16 -03:00
parent c347bfcf68
commit cfdb7d706e
2 changed files with 223 additions and 98 deletions
+178 -88
View File
@@ -154,16 +154,17 @@ namespace UnityExplorer
public Vector3 position;
public Quaternion rotation;
public float fov;
public int frames;
public PathControlPoint(Vector3 position, Quaternion rotation, float fov)
public PathControlPoint(Vector3 position, Quaternion rotation, float fov, int frames = 500)
{
this.position = position;
this.rotation = rotation;
this.fov = fov;
this.frames = frames;
}
}
private int resolution; //Amount of points between control points. [Tesselation factor]
private bool closedLoop;
private CatmullRomPoint[] splinePoints; //Generated spline points
@@ -172,7 +173,7 @@ namespace UnityExplorer
public bool playingPath;
int currentPoint = 0;
//Returns spline points. Count is contorolPoints * resolution + [resolution] points if closed loop.
//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)
@@ -183,16 +184,15 @@ namespace UnityExplorer
return splinePoints;
}
public CatmullRom(PathControlPoint[] controlPoints, int resolution, bool closedLoop)
public CatmullRom(PathControlPoint[] controlPoints, bool closedLoop)
{
if(controlPoints == null || controlPoints.Length <= 2 || resolution < 2)
if(controlPoints == null || controlPoints.Length <= 2)
{
ExplorerCore.Log(controlPoints);
throw new ArgumentException("Catmull Rom Error: Too few control points or resolution too small");
throw new ArgumentException("Catmull Rom Error: Too few control points!");
}
this.controlPoints = controlPoints;
this.resolution = resolution;
this.closedLoop = closedLoop;
GenerateSplinePoints();
@@ -211,14 +211,9 @@ namespace UnityExplorer
GenerateSplinePoints();
}
//Updates resolution and closed loop values
public void Update(int resolution, bool closedLoop)
//Updates closed loop values
public void Update(bool closedLoop)
{
if(resolution < 2)
{
throw new ArgumentException("Invalid Resolution. Make sure it's >= 1");
}
this.resolution = resolution;
this.closedLoop = closedLoop;
GenerateSplinePoints();
@@ -229,22 +224,15 @@ namespace UnityExplorer
{
if(ValidatePoints())
{
//LineRenderer lineRenderer = new GameObject().GetComponent<LineRenderer>();
for(int i = 0; i < splinePoints.Length; i++)
{
if(i == splinePoints.Length - 1 && closedLoop)
{
//lineRenderer.SetPosition(i, splinePoints[0].position);
//lineRenderer.SetPosition(i + 1, splinePoints[i].position);
Debug.DrawLine(splinePoints[i].position, splinePoints[0].position, color);
}
else if(i < splinePoints.Length - 1)
{
//lineRenderer.SetPosition(i, splinePoints[i].position);
//lineRenderer.SetPosition(i + 1, splinePoints[i + 1].position);
Debug.DrawLine(splinePoints[i].position, splinePoints[i+1].position, color);
}
}
@@ -283,20 +271,29 @@ namespace UnityExplorer
return splinePoints != null;
}
//Sets the length of the point array based on resolution/closed loop.
//Sets the length of the point array based on total amount of frames.
private void InitializeProperties()
{
int pointsToCreate;
int pointsToCreate = 0;
if (closedLoop)
{
pointsToCreate = resolution * controlPoints.Length; //Loops back to the beggining, so no need to adjust for arrays starting at 0
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
{
pointsToCreate = resolution * (controlPoints.Length - 1);
for (var i = 0; i < controlPoints.Length - 1; i++)
{
pointsToCreate += controlPoints[i].frames;
}
}
splinePoints = new CatmullRomPoint[pointsToCreate];
//if(splinePoints != null)
// Array.Clear(splinePoints, 0, splinePoints.Length);
splinePoints = new CatmullRomPoint[pointsToCreate];
}
//Math stuff to generate the spline points
@@ -311,6 +308,15 @@ namespace UnityExplorer
// 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;
/*
Quaternion[] rotationArray = new Quaternion[controlPoints.Length];
for(int i = 0; i < controlPoints.Length - closedAdjustment; i++)
rotationArray[i] = controlPoints[i].rotation;
*/
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);
@@ -380,22 +386,24 @@ namespace UnityExplorer
m0 *= 0.5f; //Doing this here instead of in every single above statement
m1 *= 0.5f;
float pointStep = 1.0f / resolution;
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 / (resolution - 1); // last point of last segment should reach p1
pointStep = 1.0f / (frames - 1); // last point of last segment should reach p1
}
// Creates [resolution] points between this control point and the next
for (int tesselatedPoint = 0; tesselatedPoint < resolution; tesselatedPoint++)
// 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, r0, r1, m0, m1, fov0, fov1, t);
splinePoints[currentPoint * resolution + tesselatedPoint] = point;
splinePoints[totalframes + tesselatedPoint] = point;
}
totalframes+=frames;
}
}
@@ -445,13 +453,14 @@ namespace UnityExplorer
public void MaybeRunPath(){
if(playingPath){
if(ExplorerCore.CameraPathsManager != null && currentPoint < ExplorerCore.CameraPathsManager.GetPoints().Length){
CatmullRomPoint point = ExplorerCore.CameraPathsManager.GetPoints()[currentPoint];
if(ExplorerCore.CameraPathsManager != null && currentPoint < splinePoints.Length){
CatmullRomPoint point = splinePoints[currentPoint];
FreeCamPanel.ourCamera.transform.position = point.position;
FreeCamPanel.ourCamera.transform.rotation = point.rotation;
FreeCamPanel.ourCamera.fieldOfView = point.fov;
currentPoint++;
if(currentPoint >= ExplorerCore.CameraPathsManager.GetPoints().Length)
if(currentPoint >= splinePoints.Length)
playingPath = false;
}
}
@@ -477,73 +486,154 @@ namespace UnityExplorer
}
}
/*
public struct LineDrawer
{
private LineRenderer lineRenderer;
private float lineSize;
public LineDrawer(float lineSize = 0.2f)
//SQUAD
//Ported by CodeKiwi
//https://forum.unity.com/threads/need-help-implementing-quaternion-squad.273931/#post-4447033
public class Squad {
// Returns a smoothed quaternion along the set of quaternions making up the spline, each quaternion is along an equidistant value in t
public static Quaternion Spline(Quaternion[] quaternions , float t )
{
//GameObject lineObj = new GameObject("LineObj");
//lineRenderer = lineObj.AddComponent<UnityEngine.LineRenderer>();
var section = (int)((quaternions.Length - 1) * t);
//Particles/Additive
//lineRenderer.material = new Material(Shader.Find("Hidden/Internal-Colored"));
var alongLine = (quaternions.Length - 1) * t - section;
lineRenderer = new GameObject().GetComponent<UnityEngine.LineRenderer>();
this.lineSize = lineSize;
}
private void init(float lineSize = 0.2f)
{
if (lineRenderer == null)
if (section == 0)
{
//GameObject lineObj = new GameObject("LineObj");
//lineRenderer = lineObj.AddComponent<UnityEngine.LineRenderer>();
//Particles/Additive
//lineRenderer.material = new Material(Shader.Find("Hidden/Internal-Colored"));
lineRenderer = new GameObject().GetComponent<UnityEngine.LineRenderer>();
this.lineSize = lineSize;
return SplineSegment(quaternions[section], quaternions[section], quaternions[section + 1], quaternions[section + 2], alongLine);
}
}
//Draws lines through the provided vertices
public void DrawLineInGameView(Vector3 start, Vector3 end, Color color)
{
if (lineRenderer == null)
else if( section == quaternions.Length - 2 && section > 0)
{
init(0.2f);
return SplineSegment(quaternions[section - 1], quaternions[section], quaternions[section + 1], quaternions[section + 1], alongLine);
}
else if ( section >= 1 && section<quaternions.Length -2)
{
return SplineSegment(quaternions[section - 1], quaternions[section], quaternions[section + 1], quaternions[section + 2], alongLine);
}
//Set color
lineRenderer.startColor = color;
lineRenderer.endColor = color;
//Set width
lineRenderer.startWidth = lineSize;
lineRenderer.endWidth = lineSize;
//Set line count which is 2
lineRenderer.positionCount = 2;
//Set the postion of both two lines
lineRenderer.SetPosition(0, start);
lineRenderer.SetPosition(1, end);
Debug.LogError("???");
return Quaternion.identity;
}
public void Destroy()
static Quaternion SlerpNoInvert(Quaternion fro , Quaternion to, float factor)
{
if (lineRenderer != null)
float dot = Quaternion.Dot(fro, to);
if (Mathf.Abs(dot) > 0.9999f)
{
//UnityEngine.Object.Destroy(lineRenderer.gameObject);
return fro;
}
float theta = Mathf.Acos(dot);
var sinT = 1.0f / Mathf.Sin(theta);
var newFactor = Mathf.Sin(factor * theta) * sinT;
var invFactor = Mathf.Sin((1.0f - factor) * theta) * sinT;
return new Quaternion(invFactor * fro.x + newFactor * to.x, invFactor * fro.y + newFactor * to.y, invFactor * fro.z + newFactor * to.z, invFactor * fro.w + newFactor * to.w);
}
// Returns a smooth approximation between q1 and q2 using t1 and t2 as 'tangents'
static Quaternion SQUAD(Quaternion q1 , Quaternion t1 , Quaternion t2 , Quaternion q2 , float t)
{
float slerpT = 2.0f * t * (1.0f - t);
Quaternion slerp1 = SlerpNoInvert(q1, q2, t);
Quaternion slerp2 = SlerpNoInvert(t1, t2, t);
return SlerpNoInvert(slerp1, slerp2, slerpT);
}
// Returns a quaternion between q1 and q2 as part of a smooth SQUAD segment
public static Quaternion SplineSegment(Quaternion q0, Quaternion q1, Quaternion q2, Quaternion q3, float t)
{
Quaternion qa = Intermediate(q0, q1, q2);
Quaternion qb = Intermediate(q1, q2, q3);
return SQUAD(q1, qa, qb, q2, t);
}
static public void Exp(ref Quaternion a )
{
float angle = Mathf.Sqrt(a.x * a.x + a.y * a.y + a.z * a.z);
float sinAngle = Mathf.Sin(angle);
a.w = Mathf.Cos(angle);
if (Mathf.Abs(sinAngle) >= 1.0e-15)
{
float coeff = sinAngle / angle;
a.x *= coeff;
a.y *= coeff;
a.z *= coeff;
}
}
static Quaternion Add(Quaternion a , Quaternion b )
{
var r = new Quaternion();
r.w = a.w + b.w;
r.x = a.x + b.x;
r.y = a.y + b.y;
r.z = a.z + b.z;
return r;
}
static void Scale(ref Quaternion a, float s)
{
a.w *= s;
a.x *= s;
a.y *= s;
a.z *= s;
}
// Tries to compute sensible tangent values for the quaternion
static Quaternion Intermediate(Quaternion q0, Quaternion q1, Quaternion q2 )
{
Quaternion q1inv = Quaternion.Inverse(q1);
Quaternion c1 = q1inv * q2;
Quaternion c2 = q1inv * q0;
//c1.Log();
//c2.Log();
Quaternion c3 = Add(c2, c1);// c2 + c1;
Scale(ref c3, -0.25f);// c3.Scale(-0.25f);
Exp(ref c3);// c3.Exp();
Quaternion r = q1 * c3;
#if MONO
return Normalize(r);
#else
r.Normalize();
return r;
#endif
}
#if MONO
public static float Dot(Quaternion a, Quaternion b)
{
return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
}
public static Quaternion Normalize(Quaternion q)
{
float mag = Mathf.Sqrt(Dot(q, q));
if (mag < Mathf.Epsilon)
return Quaternion.identity;
return new Quaternion(q.x / mag, q.y / mag, q.z / mag, q.w / mag);
}
#endif
}
*/
}
+45 -10
View File
@@ -76,12 +76,13 @@ namespace UnityExplorer.UI.Panels
//UIElements.Remove(comp);
}
foreach (var point in controlPoints) {
DrawNodeOptions(point);
for(int i = 0; i < controlPoints.Count; i++) {
CatmullRom.PathControlPoint point = controlPoints[i];
DrawNodeOptions(point, i);
}
}
private void DrawNodeOptions(CatmullRom.PathControlPoint point){
private void DrawNodeOptions(CatmullRom.PathControlPoint 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);
@@ -100,11 +101,16 @@ namespace UnityExplorer.UI.Panels
UIFactory.SetLayoutElement(moveToPointButton.GameObject, minWidth: 100, minHeight: 25, flexibleWidth: 9999);
moveToPointButton.OnClick += () => {FreeCamPanel.ourCamera.transform.position = point.position; FreeCamPanel.ourCamera.transform.rotation = point.rotation; FreeCamPanel.ourCamera.fieldOfView = point.fov;};
//Add node next
ButtonRef destroyButton = UIFactory.CreateButton(horiGroup, "Delete", "Delete");
UIFactory.SetLayoutElement(destroyButton.GameObject, minWidth: 80, minHeight: 25, flexibleWidth: 9999);
destroyButton.OnClick += () => {controlPoints.Remove(point); UpdateListNodes();};
//Frames
InputFieldRef framesInput = null;
AddInputField("Frames", "Length (in frames):", "Default: 500", out framesInput, (frames) => { FramesInput_OnEndEdit(point, index, frames); });
framesInput.Text = point.frames.ToString();
//ShowPos and rot?
}
@@ -125,28 +131,57 @@ namespace UnityExplorer.UI.Panels
FreeCamPanel.ourCamera.fieldOfView = point.fov;
}
void AddSpacer(int height)
GameObject AddInputField(string name, string labelText, string placeHolder, out InputFieldRef inputField, Action<string> onInputEndEdit)
{
GameObject obj = UIFactory.CreateUIObject("Spacer", ContentRoot);
UIFactory.SetLayoutElement(obj, minHeight: height, flexibleHeight: 0);
GameObject row = UIFactory.CreateHorizontalGroup(ContentRoot, "Editor Field",
false, false, true, true, 5, default, new Color(1, 1, 1, 0));
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);
inputField = UIFactory.CreateInputField(row, $"{name}_Input", placeHolder);
UIFactory.SetLayoutElement(inputField.GameObject, minWidth: 125, minHeight: 25, flexibleWidth: 9999);
inputField.Component.GetOnEndEdit().AddListener(onInputEndEdit);
return row;
}
void StartButton_OnClick()
{
int resolution = 500;
//float normalExtrusion = 0;
//float tangentExtrusion = 0;
if(ExplorerCore.CameraPathsManager == null)
ExplorerCore.CameraPathsManager = new CatmullRom(controlPoints.ToArray(), resolution, closedLoop);
ExplorerCore.CameraPathsManager = new CatmullRom(controlPoints.ToArray(), closedLoop);
else{
ExplorerCore.CameraPathsManager.Update(controlPoints.ToArray());
ExplorerCore.CameraPathsManager.Update(resolution, closedLoop);
ExplorerCore.CameraPathsManager.Update(closedLoop);
}
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;
}
int frames = parsed;
if(frames > 1){
point.frames = frames;
controlPoints[index] = point;
}
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);