My goal is to update camera parameters given a velocity vector so that the camera points in the direction of the velocity vector. How should one compute the update matrix for the camera parameters?
1 Answer
The velocity vector becomes your forward vector, just normalize it. The up direction doesn't change, use whatever version up the camera usually uses. The last vector (call it the "right hand" vector) is the cross product of up, and forward. Then, do a second cross with the forward vector and the right hand vector to guarantee an orthonormal basis.
The last bit needed is the translation which will have to come from somewhere.
The exact ordering of all the operations is going to depend on the setup you are using. Is up direction y or z ect.
Once the matrix if formed, find its inverse. (Since you went through the trouble of making sure it is orthonormal, the inverse is equivalent to the transpose.)
This is the new view matrix.
Edit: When dealing with Azimuth and Elevation you can extract the angles from a vector using the geometric asin and acos functions. For example:
vec3d fwd = target_point - camera_point; // generate a vector somehow
fwd = normalize(fwd); // normalize it
float azimuth = acos( fwd.x );
float elevation = asin( fwd.y ); // extract angles
if( fwd.z < 0 ) { elevation = -elevation; } // fix quadrant based sgn(z)
The above assumes that z is the up axis, and that azimuth/elevation are given in radians.
Now that the look direction is decided. Save it off to the side, and begin turning the camera. A good approach to turning the camera is to have a "radians per a second" turn rate. Get the time delta between updates from the system. And use those values to compute how much the camera should turn each frame just by computing the total number of radians that is needed for each direction.
float time_delta_in_seconds = elapsed_seconds_since_last_frame();
const float radians_per_second = 0.1; // slowish
float turn_amount = time_delta_in_seconds * radians_per_second;
float turn_amount = min(radians_to_turn, turn_amount); // don't overlook
radians_to_turn -= turn_amount; // update - converges on zero
So each frame:
- update the velocity vector
- compute the new camera settings but don't use them, save them
- compute your camera turn amount and update the camera with the new values
Make the 3 steps independent and the camera will just keep turning, chasing the velocity vector.
Handling user intervention seems self evident, if the user turns the camera disable the auto camera turning. If you want the camera to start turning after some preset amount of time, then just set a timer that enables auto turning and reset it every time the user moves the camera.
While this isn't the best system for auto camera following, it works and should (hopefully) get you going. The camera turning will be very mechanical since the turn rate is fixed. But once its all set its not to hard to add acceleration using the same ideas.
It just occurred to me that this is like 3 separate questions in one, really these should have been asked separately. At any rate, this should help some I hope.
-
$\begingroup$ Thank you for your response. The issue is I am not sure how to use the View matrix due to the setup of the camera in the framework I am using. In this framework, I can only set the camera's look direction (
look_dir
-- has componentsx
,y
,z
), the distance (dis
) from the camera tolook_dir
,azimuth
andelevation
manually. In some simple scenarios you can imaginelook_dir
being equivalent tovelocity_vec
but there are two issues with this: 1) I don't want to camera to have a sudden shift like 2) Velocity vector does not always determine where the camera looks. $\endgroup$– AmirJun 15, 2021 at 16:44 -
$\begingroup$ However, in my case it is okay if
look_dir
becomes equivalent to the velocity vector after some time (say 1 second -- assuming each second has 30 frames or so). However, I am not sure how to update all of the parameters such aslook_dir
,dis
,azimuth
andelevation
given a velocity vector. Maybe I should use the View Matrix in some way for this? I would appreciate if you can help me with this. $\endgroup$– AmirJun 15, 2021 at 16:49 -
$\begingroup$ Thats the beauty of using a vector and the approach I outlined above. The velocity vector has that info built into it. Once you have the matrix built you can extract all the other information from the matrix itself. (I can add an edit showing that if you need, but I won't probably get to it today sorry) $\endgroup$– pmw1234Jun 15, 2021 at 17:15
-
$\begingroup$ I'd highly appreciate it if you can update your answer and include the new solution. Also, would you mind looking through the comments I posted above that were exchanged with another user before posting your updated solution? I think those comments might also provide you some more information on what I need. Really appreciate it $\endgroup$– AmirJun 15, 2021 at 17:41
-
$\begingroup$ This documentation for the framework I am using might be helpful as well: mujoco.org/book/haptix.html#uiCamera $\endgroup$– AmirJun 16, 2021 at 4:24
look_dir
), the distance (dis
) from the camera tolook_dir
,azimuth
andelevation
manually. Initially I was thinking I should first compute the rotation matrix replace the camera rotation matrix with the updated one, but it seems that this is not possible and I need to manually compute these camera parameters. I'm not entirely sure how to obtain these parameters starting from a given velocity vector. Do you know how I can do this? $\endgroup$look_dir
to that of the velocity vector. Also azimuth and elevation, are you using trackball style camera defined using spherical coordinates? A normal camera usually is defined byside
,up
,look_at
and theposition
vectors. For the camera's position you could do something as simple as divide the velocity vector by 60 if let's say the app is running at 60 FPS then add it to the position, so after 1 complete second it's where it should be. If you wanna change the look_at as well you could lerp between the original and the velocity? $\endgroup$