Camera not in sync with position and rotation

I’m working on a prototype, mostly for fun.

I have the camera following the player model, by its position and rotation.

Everything works kinda, but there seems to be a problem with the camera being desynced with the position and rotation I’m giving it. It’s always a bit offset, depending on speed of rotation.

After adding deltaTime to the velocity’s speed, the player model starts stuttering really hard. This is because there’s large framedrops happening. So it’s not contstant, but it shouldn’t matter, as the position should be synced. It seems like some issue of order, but even if I change order it doesn’t fix it.
I tried all things I can imagine and no success. It seems like the camera is desynced somehow or lerping it’s position. I can’t make sense of it, even studying p5.camera code.

I upload the prototype so you can try for yourself. Shift - Control is speed. Once you start moving faster you see the ship model flickering. Also when rotating, you can see the two cursor (one static, one attacked to the player) offsetting/shifting. Which shouldn’t be, as there’s no code doing it.

The prototype. Works best in Chrome and Edge. Firefox is too slow.
https://philipp.urlich.ch/exp/space2/

Any help is appreciated.

Use millis() to track time for a real-time interactive application. Save a lastTime and each frame look up the var currTime = millis(); and use it to compute deltaTime = currTime - lastTime; then update lastTime = currTime;. Throughout your code, all translations and rotations have to be scaled by deltaTime.

Do not try to use frameRate() or any lerp() smoothing to adjust deltaTime. It needs to be the exact difference in time from the last frame to this one. If something in your computer (garbage collections or another browser tab or program grabbing the CPU for a while) causes a long delay between frames, your simulation need to advance everything by that full delay to maintain the overall sense of smooth motion.

That includes user interaction. If pressing a key fires a thruster, you will want to scale the amount by deltaTime. Absolute positioning, such as you might use for rotations, do not scale. I tend to prefer running all UI controls through the physics engine, though, (which would use the time scaling) since that lets them interact more with the physical environment. For instance, a UI control to rotate the ship would create a torque to turn it which might be countered by a collision turning it in the opposite direction and the final direction would be computed by the physics.

In any case, your program doesn’t run for me so I can’t see the exact problem you describe. But it looks like you are over-complicating your time computations. Simplify it to just the difference between frame times and make sure you’re scaling by the delta everywhere and it should play smoothly even when your computer gets distracted and jitters the frame rate.

1 Like

Thank you for your time explaining. That’s exactly what I’m doing and using deltaTime everywhere even inputs. Do you mean millis() would make the difference, computing deltaTime manually?

I just tried different thing out that’s maybe what you see in code. I’m not using frameRate or lerp. When I don’t use deltaTime it is smooth.

I don’t see in the code where you set deltaTime. Is it based on the real-world time (such as I suggested using millis()) or is it a fixed amount?

It appears that you are not using deltaTime when computing rotXDelta and rotYDelta. It doesn’t seem like that would be related to the issues you describe, but you might want to fix that for consistency.

When I try to run your program, I just get a “Loading…” message and nothing else happens.

The deltaTime is globally set by p5.js. No need to use millis().

And I use it to do what deltaTime is for in games. Since it caused issued o some places I tried endless things, so there’s might be a case where I left it out, but it doesn’t matter anyway. I removed the some testing code.

I used it for the velocity of the player for example, where it’s causing stuttering:

var speedD = newVelocity.copy().mult(this.speed * deltaTime / 1000);
this.position.add(speedD);
translate(this.position);

It’s 100mb so maybe takes a while. I don’t know why it shouldn’t work. There’s no errors or warnings, and it works on all my testing devices. Tho some people also said it’s not loading, but at the end it then still worked.

I asked a pro game programmer friend, and all the methods I use to calculate things and use deltaTime seems correct and it kinda works, it’s just stuttering really bad, when there’s larger framerate changes. But the camera that is attached to the player position should then too, but it’s not. Weird magic.

EDIT: Also the fighter spaceship (enemy) are stuttering as soon as I add deltaTime to the calculation. I’m not sure anymore what else to do. Once I implement deltaTime, speeds are frame independent, but it’s stuttering like crazy. If I don’t add it it’s smooth as butter, but also frame dependent.

Ah. I don’t often use p5 and didn’t know about deltaTime. Handy. From looking at the code, it should be identical to what I suggested using millis().

For what it’s worth, my webgl rendering doesn’t seem particularly smooth at all. Might be related to the ~300 tabs I have open. I would suggest starting from much simpler models and build back up to your current code to see if you can pinpoint the motion trouble. But even code as simple as the code below gives me very uneven updating. Hit a key to cycle through using millis() in red, deltaTime in green, or fixed timing in blue. Does this animate smoothly for you?

I hadn’t noticed jitter before, so it may just be some tab I have open that is causing interrupts.

var N = 2000;
var lastTime;
var t = 0;
var mode = 0;
var seed;

function setup() {
  createCanvas( 900, 900, WEBGL );
  lastTime = millis();
  seed = random(1<<24);
  frameRate(60);
}

function draw() {
  var currTime = millis();
  var dt = currTime - lastTime;
  if( mode == 1 ) { dt = deltaTime; }
  else if( mode == 2 ) { dt = 1000/60; }
  lastTime = currTime;
  t += 0.00005*dt;

  background( 64 );
  //translate( width/2, height/2 );
  randomSeed( seed );
  fill( (mode==0) ? '#ffaa77' : (mode==1) ? '#77ee77' : '#77aaff' );
  for( var i=0; i<N; i++ ) {
    push();
    translate( 400*cos(random(2,6)*t+random(TAU)), 
               400*cos(random(2,6)*t+random(TAU)),
               400*cos(random(2,6)*t+random(TAU)));
//    box( 10, 10, 10 );
    circle( 0, 0, 10 );
    pop();
  }
}

function keyPressed() { mode = (mode < 2) ? (mode + 1) : 0; }
1 Like

WebGL is pretty smooth, and I don’t think it’s performance. It’s all fine if the object is small, fast and at some distance with a fixed camera. I’m working on serveral prototypes since weeks/months. Usually using godot.

My prototype is pretty barebone, simple code. Well, I did a testing version on the online editor and went from there. p5.js Web Editor

But as soon as you attach a camera following the player model, you can see the jittering cause by deltaTime. I have no idea why. I think I’ve once read that in such cases you have to use some smoothing or whatever, but couldn’t find it anymore.

As I said, this shouldn’t happen at all, because the camera is following the exact position of the player. So it’s either some order of execution or some smoothing already happening automatically on the camera in the back, or some wrong calculation on my side. But it does make no sense.

1 Like

I had a similar problem when I was creating a 3D game using p5.js

In my case I believe the problem was that the frame execution time (world update and rendering) was greater than the ~17ms available when the frame rate was set to 60fps. I resolved it by reducing the frame rate. You might try changing the frame rate to 25 and see if that makes a difference.

BTW your game graphics look great :+1:

1 Like

What I would prefer to see in your code is a very clear separation between user input, physics, and drawing in that order, with no overlap. It seems possible to me that you are updating either the camera or the ship position (either by physics or by UI) in between the drawing of the two which causes them to go out of sync. Maybe change your draw() to just have three functions:

function draw() {
  checkInput();
  updatePhysics();
  drawStuff();
}

where no drawing commands are allowed in the first two and no objects get moved in the last one. The first commands in drawStuff() clear the screen and set the camera position based on the ship position. Then you can draw the rest in whatever order maybe doing some culling based on the camera positions and angle.

1 Like

Thank you very much. Framerate doesn’t matter unfortunately.

It’s a prototype! Thanks, but I don’t care about well written code, and the order is fine for what it’s doing. I’ve written way more complex p5 prototypes that deal with all stuff like culling etc. It’s fun little projects and I appreciate the feedback, but I think I know what I’m doing. There’s two update that happen right at the same time, position of ship and position of camera.

Edit: Maybe you’re right, but I have a plain simple version that’s doing nothing else but a camera following and object and it’s behaving the exact same, I changed order and codes around for days now and no difference where it matter.

checkInput();
updatePhysics();
drawStuff();

That’s bascially what I’m doing, check input, update physics and draw stuff…

In the code in https://philipp.urlich.ch/exp/space2/sketch.js?v=2 it looks to me as though you are drawing the cubes and fighters BEFORE you update the player position and set the camera. Instead, you want to position ALL objects first, THEN set your camera and only after that draw all of your objects.

Prototype or not, you’re getting camera judder because things are going out of sync. Separate out your physics from your drawing, not just per-object but across ALL objects, and I bet your judder will go away. I don’t think using deltaTime was the problem, it just made it more visible.

There’s no studder, it’s butter smooth at 75 fps, until I add deltaTime.

The camera is attached to the player position, and updated at the same time as the player. It’s all happening in draw in the right order, otherwise it wouldn’t work at all. It’s frame per frame calculation overall, so it doesn’t matter if you have it separated or in one spot. I played around with orders and barebone simple tests, and it’s always the exact same happening once I add deltaTime.

Do you have a bare-bones example that you could share in the p5 web editor that shows the problem with using deltaTime?

The problem, I’m seeing after many tests check and change my code to figure out is…

The speed of the player is scaled by deltaTime, which if my frame rate drops from 75 to 35 continously… the new position by adding the velocity v * speed does get jittered, that’s the nature of it, no way around it. Why I get framedrops that hard is another question. Now, the camera is attached to exact that position, and lookat the player center. But the camera is not doing the jittering? That’s odd. Also the angle of the camera doesn’t match the rotation of the ship 1:1 it’s offset and there’s no obvious code I’m writing that does this. So my guess is that the camera somehow “lags” behind or get’s lerped or whatever. Because if it’s set to the same position as the player, why doesn’t it not follow the jittering cause by deltaTime?

Edit: The only way to set a camera position is to use camera(eyeX, eyeY, eyeZ). So I don’t know what happens exactly behind the scene with that. That’s why I guessed, maybe it’s some order of execution that happens behind the scenes (and not in my code). Moving code and order around, camera before or after player position has only a minimal change in jittering, but it’s still there no matter what. So it’s maybe my code to calculate the offset of the camera based on player position and angle, but I checked that code so many times, I think it’s correct (it’s quite simple calc).

Edit2: Also would love someone explaining me why adding deltaTime to the physics, makes the animation jitter when framerate is fluctuating? While without deltaTime it’s smooth even with frame rate drops? Doesn’t make sense, as deltaTime is exactly to make it framerate independant and keep constant offset based on frame drawing time. I have a guess but no clue it it’s correct.

If you set the camera in the middle of your drawing, then objects drawn before you move the camera are drawn using the last camera position and those after using the new one. The objects will appear at a position one frame behind meaning that they are effectively using the wrong deltaTime for their update which would make the judder worse.

But, I don’t know what p5 is doing internally. Graphics cards are fastest when you can buffer up all of your graphics calls into a single buffer and ship it off to the GPU with one call. p5 doesn’t necessarily do that because it tries to be simple for beginner programmers rather than efficient, but they probably do some batching of the geometry and it could be that their ordering doesn’t quite match yours.

If you manually set your frameRate(10) or 15, do you see any judder using deltaTime or not?

@quark, does your game load for you on Chrome? I get warnings and errors for p5.sound.min.js and the game never loads even when I have uBlock Origin disabled:

The AudioContext was not allowed to start. It must be resumed (or created) after a user gesture on the page. https://goo.gl/7K7WLu
i.Context @ p5.sound.min.js:2

Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'addModule')
    at p5.sound.min.js:2:98453
    at Array.map (<anonymous>)
    at v.<anonymous> (p5.sound.min.js:2:98338)
    at v.<anonymous> (p5.min.js:2:463632)
    at Array.forEach (<anonymous>)
    at new v (p5.min.js:2:463598)
    at p5.min.js:2:451299

It does load and run in firefox, however.

Well, some good ideas, but I don’t know. At this point I believe in anything haha.

No, framerate “doesn’t” matter, expect it seems better at 50, than 60, but also at 20 it jiggles occasionally.

Well, here’s my little start testing sketch I linked earlier. I just copied the camera code in there. And voila happy jittering!

I don’t see exactly where it’s happening, but your ship position relative to the camera depends on deltaTime… somehow. If you set deltaTime = 100 at the start of draw, your ship draws further away from the camera. It jitters because as deltaTime bounces around, so does the ship’s distance from the camera. But I don’t see where it’s doing that. posNeg is based on the velocity, so maybe there?

Of course the position of the player depends on deltaTime, we scale it by deltaTime. It’s the velocity * speed that I add to the position to move the player. BUT the camera is set to that position once the new position of the player is calculated. The weird thing is the camera has given a negative offset of 250 and then up on Y axis for another offset.

If you add a
console.log(curPosO.copy().sub(this.position).toString());
You see it’s (0,-50,250). But the camera offset is shifting depending on the speed. But the camera offset vector stays the same, still (0,-50,250) no matter what speed. AND so is the rotation, it’s offset from the ship rotation, even tho it’s set to the same rotation.

So if you remove the * deltaTime from the player speed, there’s no jittering and distance only shifts minimal cause we don’t scale by deltaTime anymore, and also still rotation is off. Which is kinda strange.

So I’m maybe kinda blind and don’t see the obvious.