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

Modified the camera path to use time instead of speed, precalculated the lookAhead points beforehand, fixed the path using the wrong rotations in a quaternion, and modified some buttons in the camera paths panel.

This commit is contained in:
originalnicodr
2024-01-27 11:01:38 -03:00
parent c8e6d312ae
commit 78c8a41e22
2 changed files with 85 additions and 99 deletions
+10 -11
View File
@@ -32,7 +32,7 @@ namespace UnityExplorer.UI.Panels
public List<CatmullRom.CatmullRomPoint> controlPoints = new List<CatmullRom.CatmullRomPoint>();
List<GameObject> UINodes = new List<GameObject>();
bool closedLoop;
float speed = 10;
float time = 10;
// ~~~~~~~~ UI construction / callbacks ~~~~~~~~
@@ -57,8 +57,8 @@ namespace UnityExplorer.UI.Panels
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);
ButtonRef AddNode = UIFactory.CreateButton(horiGroup, "AddCamNode", "+");
UIFactory.SetLayoutElement(AddNode.GameObject, minWidth: 50, minHeight: 25);
AddNode.OnClick += AddNode_OnClick;
ButtonRef DeletePath = UIFactory.CreateButton(horiGroup, "DeletePath", "Delete Path");
@@ -72,9 +72,9 @@ namespace UnityExplorer.UI.Panels
closedLoopToggle.isOn = false;
toggleClosedLoopText.text = "Close path in a loop";
InputFieldRef SpeedInput = null;
AddInputField("Speed", "Path speed:", $"Default: {speed}", out SpeedInput, Speed_OnEndEdit, false);
SpeedInput.Text = speed.ToString();
InputFieldRef TimeInput = null;
AddInputField("Time", "Path time (in seconds at 60fps):", $"Default: {time}", out TimeInput, Time_OnEndEdit, false);
TimeInput.Text = time.ToString();
}
private void UpdateListNodes(){
@@ -140,7 +140,7 @@ namespace UnityExplorer.UI.Panels
if(GetCameraPathsManager()){
GetCameraPathsManager().setClosedLoop(closedLoop);
GetCameraPathsManager().setSplinePoints(controlPoints.ToArray());
GetCameraPathsManager().setSpeed(speed);
GetCameraPathsManager().setTime(time);
GetCameraPathsManager().StartPath();
}
}
@@ -160,12 +160,11 @@ namespace UnityExplorer.UI.Panels
void AddNode_OnClick(){
Camera freeCam = FreeCamPanel.ourCamera;
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 Speed_OnEndEdit(string input)
void Time_OnEndEdit(string input)
{
EventSystemHelper.SetSelectedGameObject(null);
@@ -175,9 +174,9 @@ namespace UnityExplorer.UI.Panels
return;
}
speed = parsed;
time = parsed;
if(GetCameraPathsManager()){
GetCameraPathsManager().setSpeed(speed);
GetCameraPathsManager().setTime(time);
}
}
+75 -88
View File
@@ -93,18 +93,18 @@ namespace UnityExplorer.CatmullRom
private bool closedLoop;
private CatmullRomPoint[] splinePoints;
// The point the camera will be following along the path
private List<CatmullRomPoint> lookaheadPoints;
private CatmullRomPoint lookahead;
// How smooth the path is (beware of not making too many calculations per update tho)
float lookaheadDelta;
float time;
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;
lookaheadPoints = new List<CatmullRomPoint>();
}
public void StartPath(){
@@ -115,8 +115,10 @@ namespace UnityExplorer.CatmullRom
}
else {
playingPath = true;
delta = lookaheadDelta;
MoveCameraToPoint(splinePoints[0]);
lookahead = GetPointFromPath(delta);
CalculateLookahead();
lookahead = lookaheadPoints[(int)(lookaheadPoints.Count * lookaheadDelta)];
}
}
@@ -133,97 +135,78 @@ namespace UnityExplorer.CatmullRom
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 setTime(float newTime){
time = newTime;
}
public void Update(){
if (delta >= 1 && FreeCamPanel.ourCamera != null){
playingPath = false;
delta = lookaheadDelta;
}
if (playingPath) AdvanceMover(Time.deltaTime);
// We use FixedUpdate here to have a constant velocity no matter the time dilation the game is currently using,
// although the game should still run at a capped 60fps.
void FixedUpdate(){
if (playingPath) AdvanceMover(Time.fixedDeltaTime);
}
/*
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
// Units to move
float move = dt * speed;
while (move > 0.0) {
CatmullRomPoint currentPoint = GetCurrentPoint();
// distance between target and current position
// 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
// How much we're actually moving this iteration
// Move the whole distance to the lookahead, or would the move variable cut us short
float actual = Math.Min(move, room);
MoveCameraStep(currentPoint, actual, room);
// update move to be the remaining amount we need to move
// Update move to be the remaining amount we need to move this frame
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
currentPoint = GetCurrentPoint();
// 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);
// While ends, need another lookaheadDelta for the next Update
// It will do, at most, 2 iterations
while (room <= 0) {
// If the camera reached the last lookAhead we stop it
if (delta >= 1){
playingPath = false;
delta = 0;
}
delta = Math.Min(delta + lookaheadDelta, 1);
// May not be as good as calculating GetPointFromPath(delta) itself, but since its a lookahead and not the actual cam position
// the movement will still be smooth.
int lookaheadIndex = (int)((lookaheadPoints.Count - 1) * delta);
lookahead = lookaheadPoints[lookaheadIndex];
room = Vector3.Distance(lookahead.position, currentPoint.position);
}
}
}
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;
Vector4 rb = CatmullRomPoint.QuaternionToVector4(direction.rotation);
rb = rb * actual / room;
Vector4 newRot = ra + rb;
newRot.Normalize();
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.transform.rotation = CatmullRomPoint.Vector4ToQuaternion(newRot);
FreeCamPanel.ourCamera.fieldOfView += direction.fov * actual / room;
//ExplorerCore.LogWarning($"current cam pos: {FreeCamPanel.ourCamera.transform.position} at d: {delta}");
}
public void MoveCameraToPoint(CatmullRomPoint newPoint){
@@ -232,30 +215,16 @@ namespace UnityExplorer.CatmullRom
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
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}");
int currentPoint = (int)((splinePoints.Length - closedAdjustment) * d);
bool closedLoopFinalPoint = (closedLoop && currentPoint == splinePoints.Length - 1);
@@ -264,7 +233,7 @@ namespace UnityExplorer.CatmullRom
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},");
if (d >= 1) return closedLoop ? splinePoints[0] : splinePoints[splinePoints.Length - 1]; //Ideally we should really loop over tho, maybe d % 1.
p0 = splinePoints[previousPoint].position;
r0 = CatmullRomPoint.QuaternionToVector4(splinePoints[previousPoint].rotation);
@@ -278,9 +247,7 @@ namespace UnityExplorer.CatmullRom
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.
//Check if we are using the shortest path on the rotation. If not, change each rotation to represent that shortest path.
if (Vector4.Dot(r0, r1) < 0)
r1 = - r1;
@@ -293,15 +260,10 @@ namespace UnityExplorer.CatmullRom
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;
}
@@ -358,8 +320,33 @@ namespace UnityExplorer.CatmullRom
Vector4 d = r1;
return a * t * t * t + b * t * t + c * t + d;
//return Vector4.Lerp(r1, r2, t);
}
}
void CalculateLookahead() {
// Physics engine executed FixedUpdate 50 times every second.
float frames = time * 50;
float pathLength = 0;
if (lookaheadPoints.Count > 0) lookaheadPoints.Clear();
for (int i = 0; i <= frames; i++){
CatmullRomPoint newPoint = GetPointFromPath(i / frames);
if (i != 0 && Vector4.Dot(CatmullRomPoint.QuaternionToVector4(lookaheadPoints[i - 1].rotation), CatmullRomPoint.QuaternionToVector4(newPoint.rotation)) < 0){
newPoint.rotation = CatmullRomPoint.Vector4ToQuaternion(- CatmullRomPoint.QuaternionToVector4(newPoint.rotation));
}
lookaheadPoints.Add(newPoint);
if (i != 0){
pathLength += Vector3.Distance(lookaheadPoints[i - 1].position, lookaheadPoints[i].position);
}
}
speed = pathLength / time;
lookaheadDelta = speed / 1000;
//ExplorerCore.LogWarning($"Calculating speed {speed}");
//ExplorerCore.LogWarning($"for time {time}");
//ExplorerCore.LogWarning($"on path length {pathLength}");
//ExplorerCore.LogWarning($"lookaheadDelta {lookaheadDelta}");
}
}
}