- Home /
Why is my camera shaky in editor but not in compiled project?
I wrote this somewhat simple camera script that works silky smooth in my compiled project, but jerks around a lot in the editor. I can't figure it out. The reason it's a problem is because some computers do it and some do not and it usually has nothing to do with the speed of the computer.
It seems to jerk at very random times. I can't even see it in the profiler what might be causing it.
The thing that seems to be failing is the Vector3.Lerp function. I tried using a smooth Delta Time, but that didn't make any difference.
Any help on this will be very appreciated as I am practically tearing my hair out on this one.
post some sample code so we can test locally/vet for issues
//Highly simplified version that still has problem
var target:Transform; private var q1:Quaternion; private var qCam:Quaternion; private var v1:Vector3; private var vCam:Vector3; private var fSpeed:float; private var fDist:float; private var zoom:float;
function LateUpdate ()
{
//Camera Behavior Type 2 (tight)
q1=Quaternion.Slerp(qCam,target.rotation,Time.deltaTime*6.0);
qCam=q1*Quaternion.Euler(1,0,0);
fDist=Vector3.Distance(v1,target.position);
fSpeed=14+(8*$$anonymous$$athf.Asin($$anonymous$$athf.Lerp(1,0,fDist-2)));
v1=Vector3.Lerp(v1,target.position-(transform.forward*(2+zoom)),Time.deltaTime*fSpeed);
vCam=v1;
//Set the camera
transform.rotation=qCam;
transform.position=vCam;
}
Also having a more specific look at that code, you seem to have a logic flaw in your code.
You're interpolation and movement independently, which can lead to unpredicted/undesired results. You have first to interpolate the rotation and apply it, then interpolate the direction. Otherwise the camera will move in the wrong direction for the current frame/Update
Answer by Rush3fan · Dec 31, 2011 at 06:38 AM
I think I might have it figured out. I thought I was supposed to be using LateUpdate(), but putting it in Update() reduced the shaking quite a bit. Not completely, but close enough so that people wont get headaches playing my game.
Sounds like this really has just hidden the issue. But whatever works.
Answer by Rod-Green · Dec 30, 2011 at 06:35 PM
Problem is this line :
qCam=q1*Quaternion.Euler(1,0,0);
you're offsetting the camera rotation by 1 on x every update.. so the camera rotation glitches then smooths back out..
I'm not sure really why you're doing that there at all? maybe you meant to do something like?
qCam=Quaternion.Slerp(qCam,target.rotation * Quaternion.Euler(1,0,0),Time.deltaTime*6.0);
Yea, that rotation thing was a bad idea, but the main problem is still there. The camera translation still jerks around in the editor. :(
You've got no other scripts modifying the camera's position?
No other scripts should be changing it. There is however my car which is what it follows.
The script at the bottom just moves an object (smoothly)
Sorry no I meant test the camera follow script using that script as the target. As that script moves an object very smoothly. Basically to eli$$anonymous$$ate the potential issue with your car. Basically to certify that the issue is located within this camera script.
Answer by Tseng · Dec 31, 2011 at 02:24 PM
I think you shouldn't use Time.deltaTime for Slerp, but use Time.time*modification
instead.
Time.deltaTime is just the time of the last frame and will vary. But for Lerp you need a value which "fraction" runs continually in one direction.
For example, if you interpolate between two values, lets say 1 and 10 and you have
Quaternion.Slerp(qCam,target.rotation,0.5f)
Then it would interpolate to half way between 1 and 10, so it will interpolate to 5. If you have it 0.25f then it will interpolate to 2.5 etc.
But if you use Time.deltaTime*6
you will get seamlessly random numbers, because deltaTime will not be increased continuously but go up and down between each frame. Time.time increases with every frame, it never goes down.
The "down" should be the one which cause the camera to act jumpy.
Edit: Oh btw. Use use Update() for normal camera movement and LateUpdate() for following camera. Because the camera must move moved after the character (the scene) has been moved/updated
Edit2: Of course you can also do the following for the interpolation, if you want the interpolation to last 2 seconds until the camera gets interpolates from start to end:
float timePassed = 0;
...
void LastUpdate() {
timePassed += Time.deltaTime;
Quaternion.Slerp(qCam,target.rotation,timePassed/2.0f)
}
So after 0.5 seconds the value will be 0.25, after 1 second 0.5 and after 2 seconds 1.0.
Edit3: Since Rod from the comments doesn't understand the correct usage of the 3rd parameter from the Lerp/Slerp functions, here an explanation for him:
using UnityEngine;
using System.Collections;
public class LerpTest : MonoBehaviour {
public Color color1 = Color.red;
public Color color2 = Color.green;
// Use this for initialization
void Start () {
renderer.material.color = color1;
}
// Update is called once per frame
void Update () {
// This will work, it gets from red to green and then stops
renderer.material.color = Color.Lerp(color1, color2, Time.time);
// This won't do anything! It will remain red
renderer.material.color = Color.Lerp(color1, color2, Time.deltaTime);
// This will cause flickering, like the jerking described from Rush3Fan. In my case its a color in his a movement, the effect is the same!
// That's because delta time is usally very low, 0.001-0.005. If you have a fast enough
// it will remain almost zero and the value won't be interpolated at all! If you multiply it by 10-20, it will turn into 0.01-0.05, and will be more visible in this case
renderer.material.color = Color.Lerp(color1, color2, Time.deltaTime*20);
}
}
After all, the correct way of using interpolation is still set a variable to zero when the interpolation starts and do
myInterpolationValue += Time.deltaTime / duration; // i.e. if you want the interpolation to take 5 seconds, you **divide** by 5, NOT multiply. So it will take 5 seconds until myInterpolationValue becomes >= 1.0
But most people do this kind of interpolation:
transform.position = Vector3.Lerp(transform.position, target.position, 0.5f);
This LOOKS like it works as intended, but it doesn't! The reason why it looks is, because the distance from transform.position and target.position gets lower with each update, that's why it looks like the it "smoothes" down. Of course, you can use it like this, but in that case the 3rd parameter has to be a constant value between 0.0f (zero) and 1.0f (one!). The lower the value, the longer the object (in this case the camera) will take to reach it's destination.
That being said, it's not appropriate to downvote others answers, just because you don't know how Lerp/Slerp works and is to be used.
I already have my camera script written, but if I ever have more troubles with it, I'll refer back to this. Thanks for the detailed explanation. I tend to use these Lerp functions a lot, so it's great to know how to use them. :)
@Tseng Sorry that's not correct at all. You can't use Time.time as any lerp function takes a value fom 0.0 to 1.0. So you would then stop lerping at all after 1.0 s of game time. But then to make it work you would have to subtract the last update time from the current time, or constantly reset the starttime which will end up giving you the .... Delta time :) NB: the way his script works is it constantly moving to an objects position so there's no real "beginning"
Delta time gives you the time since the last update and when you pass his to a lerp it gives you a smooth frame rate linked update mechanism that typically will also provide a see$$anonymous$$gly consistent motion.
http://unity3d.com/support/documentation/ScriptReference/Time-deltaTime.html
Use this function to make your game frame rate independent.
If you add or subtract to a value every frame chances are you should multiply with Time.deltaTime. When you multiply with Time.deltaTime you essentially express: I want to move this object 10 meters per second ins$$anonymous$$d of 10 meters per frame."
After saying all this I have heard that people have an easier time with smoothDeltaTime... As this seems to help average out the detlatime update ranges. $$anonymous$$aybe that might have been your issue all along?
Also why slerp??
Of course, you must know it better than the Unity Technology developers...
http://unity3d.com/support/documentation/ScriptReference/Quaternion.Slerp.html
Every Lerp/Slerp Example uses Time.time * speed$$anonymous$$odifier in their examples. $$anonymous$$aybe you should consult the documentation, before posting wrong answers?
To prove you wrong, I'll update the answer above which shows the difference. It not my error, that you use this function in a wrong and unintended way.
whoa. Relax man. I'm not making things up here. They may use Time.time as their example but it's a fact that Lerp functions use a 0 - 1 range for their blend input.. so if you pass in a time > 1 it's equivalent to no lerp at all it will 100% be the target rotation/value. Without any smoothness.
http://unity3d.com/support/documentation/ScriptReference/Vector3.Lerp.html
t is clamped between [0...1]. When t = 0 returns from. When t = 1 returns to. When t = 0.5 returns the average of from and to.
They use time because typically lerp is used to smooth transition over a given time.. to say it has to be Time.time or Time.deltaTime is really down to the use case. In this case he's updating a position constantly and therefore it's best to use DeltaTime.
I was merely pointing out that to say that his issue was BECAUSE he's using DeltaTime was incorrect.. not that DeltaTime HAS to be used with lerping operations.
Sorry if that wasn't clear.
@Tseng come on man why so aggressive?
I down voted because you are not correct for THIS question. I can explain why your use case doesn't work..
renderer.material.color = Color.Lerp(color1, color2, Time.deltaTime);
what you are doing here is lerping everyframe from color1 to color2 by the frame difference..
However this is VERY different to
lastColor = Color.Lerp(lastColor, targetColor, Time.deltaTime);
renderer.material.color = lastColor;
see the difference? Ones a fixed lerp between two points the other is a progressive lerp that handles adjusting start and end points..
In the script the original question was using he was progressively moving to a moving target every frame.
With your own script.. press play.. wait a couple of seconds then change color2.. what happens?? does it blend between color1 to color2 over time?? no it will just snap to color2? Why? Because Time.time > 1 and therefore there are is NO transisition.
Answer by Rush3fan · Dec 31, 2011 at 08:27 AM
Looks like my camera system is turning out pretty nice. Thanks for all you help Rod Green!
Your answer
Follow this Question
Related Questions
Strategy camera problems. 0 Answers
Sprite not displaying when I add a line of code that moves the main camera to another sprite 0 Answers
Play mode problem 2 Answers
Stopping camera 1 Answer