LookAt - How to get the correct temporary vector up ?

Started by
4 comments, last by ellenature 3 years, 8 months ago

Hey ?

The way I find up_tmp in init_camera_axis() is not optimal because if my cam->vec is (1, 1, -1) I can't find the right up_tmp. I currently find (0, 0, 1) and it should be equal to (-1, 0, 1). I then use these vectors in the lookat method.
How to get the correct vector up_tmp ?

void	init_camera_axis(t_camera *cam)
{
	t_vec3 up_tmp;
	
	up_tmp = (t_vec3){0,0,0};
	cam->forward = get_normalised(invert(cam->vec));
	if (fabs(cam->vec.y) > 0.7)
	{
		if (cam->vec.z <= 0)
			up_tmp = (t_vec3){0, 0, 1};
		else
			up_tmp = (t_vec3){0, 0, -1};
	}
	else
		up_tmp = (t_vec3){0, 1, 0};
	cam->right = vec_cross(up_tmp, cam->forward);
	cam->up = vec_cross(cam->forward, cam->right);
	normalize(&amp;cam->right);
	normalize(&amp;cam->up);
}
Advertisement

Would up_tmp = (-cam->vec.x, 0, -cam->vec.z); be correct when y > 0.7 ?

	cam->right = vec_cross(up_tmp, cam->forward);
	cam->up = vec_cross(cam->forward, cam->right);
	normalize(&amp;cam->right);
	normalize(&amp;cam->up);

This could be optimized:

	cam->right = vec_cross(up_tmp, cam->forward);
	normalize(&amp;cam->right);
	cam->up = vec_cross(cam->forward, cam->right);

… to get rid of one normalization, just fyi.

Any up vector will fail in case the front direction is the same. In such case what you could do is generating an arbitrary matrix that is orthogonal.
But i realize your mistake is worse than that, i'll try to fix it:

void	init_camera_axis(t_camera *cam)
{
	t_vec3 up_tmp = (t_vec3){0,0,1};
	cam->forward = get_normalised(invert(cam->vec));
	cam->right = vec_cross(up_tmp, cam->forward);

	float length = vec_length(cam->right);	
	if (length < 1.0e-6f) // up and forward are too similar or almost exactly opposite, so cross gave a zero vector and we need another up vector
	{
		up_tmp = (t_vec3){0,1,0};
 // the new one is perpendicular to the old one, so it can't happen we fail again
		cam->right = vec_cross(up_tmp, cam->forward);
		length = vec_length(cam->right);	
	}
	
	vec_mult(cam->right, 1/length); //normalize(&cam->right);
	cam->up = vec_cross(cam->forward, cam->right);
	normalize(&cam->right);
}

hope it works ; )

It seems to be working!
I just inverted the two up_tmp vectors, normalized the right vector and added this piece of code for a cam->with (0, 1, 0) :

if (cam->vec.x == 0 && cam->vec.y > 0 && cam->vec.z == 0)
	up_tmp = (t_vec3){0,0,-1};
else
	up_tmp = (t_vec3){0,0,1};
void	init_camera_axis(t_camera *cam)
{
	t_vec3	up_tmp;
	float	length;

	up_tmp = (t_vec3){0,1,0};
	cam->forward = get_normalised(invert(cam->vec));
	cam->right = vec_cross(up_tmp, cam->forward);
	length = vec_length(cam->right);	
	if (length < 1.0e-6f)
	{
		if (cam->vec.x == 0 && cam->vec.y > 0 && cam->vec.z == 0)
			up_tmp = (t_vec3){0,0,-1};
		else
			up_tmp = (t_vec3){0,0,1};
		cam->right = vec_cross(up_tmp, cam->forward);
		length = vec_length(cam->right);	
	}
	//vec_mult(1 / length, cam->right);
	normalize(&cam->right);
	cam->up = vec_cross(cam->forward, cam->right);
	normalize(&cam->right);
}

Why with a cam->vec (0, 1, 0) or (0, -1, 0), a rotation on the yaw axis is actually made on the roll axis ?
Is it the gimbal lock? It is present only for these two axes? How to fix this problem?

This topic is closed to new replies.

Advertisement