0
\$\begingroup\$

I have a quad in 3D space (a billboard in the real-world sense) that I want to move close to the camera so the user can inspect it. The quad is defined by the 3D coordinates of its four corners.

To accomplish this I compute target points very close to the camera for each of the corners.

(I use XNA's Viewport.Unproject() method which does something similar to this)

// Top left corner of the screen, 
// Z=0.1f means very close to the camera's near plane
var screenPoint = new Vector4(0,0,0.1f,1); 
var worldPoint = Vector4.Transform(screenPoint, Matrix.Inverse(ViewMatrix * ProjectionMatrix));
var worldPoint /= worldPoint.W;

These world points that are close to the camera produce a very small quad: which is understandable if we look at this picture:

Viewport quads

Here the initial position of the quad is depicted in red and the end position of the quad is depicted in blue.

For each of the corners of the quad I linearly interpolate between the original position and the position near the camera.

this.timer += deltaTime;
var progress = this.timer / 10.0f;
var currentTopLeft = Vector3.Lerp(initialTopLeft, nearTopLeft, progress);

Since I linearly interpolate the quad moves to its new position at a constant speed. I've verified this by ouputting the speed and distance to the console. However, the visual effect is that the quad first hardly moves and then all of a sudden moves very fast to its destination.

I think this is because the quad is being scaled down while moving closer (to fit the near plane) so it will stay relatively the same size on screen for a long time. Only once it comes very close it seems to move. (For example see this answer).

The question I have is: what can I do to make it look like the quad is moving closer at a constant speed?

I was thinking about not interpolating linearly but first move progress very fast and then very slow (Ive tried progress = sqrt(progress) which helped a little). But I'm not sure how I can compute the exact (or near enough) formulate to make this work.

Another idea I had was to bring the quad not so extremely close, but then there is the danger of it clipping with objects in the world.

\$\endgroup\$
  • \$\begingroup\$ You're already doing what you do. You're moving it at a constant speed. It's why it's called linear interpolation. Maybe you should add what you're exactly trying to do. Is this some UI thing? If so, you might want to do it outside your world space in a different projection? \$\endgroup\$ – Mario Feb 15 '17 at 8:50
  • \$\begingroup\$ I'm moving it linearly closer while at the same time scaling it linearly down, so the visual result is not linearly unfortunately since these both things happen at the same time. \$\endgroup\$ – Roy T. Feb 15 '17 at 8:56
  • \$\begingroup\$ Do you want some effect similar to lightboxes on websites (click on an image and it zooms/expands to fill the window)? If you want to keep it at the same size, why even move/scale it? \$\endgroup\$ – Mario Feb 15 '17 at 9:08
  • \$\begingroup\$ Exactly, it should expand to fill the screen, however since its an object in 3D space and should become closer to the camera than any other objects (so it doesn't clip anything) I need to move it as well. \$\endgroup\$ – Roy T. Feb 15 '17 at 9:12
  • \$\begingroup\$ How about converting your initial quad into screen space and then transform that in 2D space rather than 3D? \$\endgroup\$ – Mario Feb 15 '17 at 9:13
1
\$\begingroup\$

The problem is that your constant movement speed - after perspective projection - creates non-constant perceived resize speed.

Let's assume the quad is moving 1 unit per second to the camera and this is the constant speed. What you need is the constant percentage change per second. Right now, when your quad is 10 units from the camera, then after a second it's 9 units from the camera, so it changed by 1/10. After few frames, when the distance get from 2 to 1 you have a 1/2 change per second, which causes visual speedup.

Instead of this you should move the quad by 1/X of the actual distance, picking the X for your needs. This way you'll never get to the camera position, but you can stop moving at some fixed distance.

Besides of any scaling that you may need you can use an Exponential function to make it independent of fps, or you may use one of the few Easing functions.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.