Billboards Problems

Started by
9 comments, last by impulsee 7 years, 8 months ago

Hey everyone, im trying to get a 2d plane to face the camera (Billboards for particles) but im having some problems.

Im currently trying to construct a quaternion using angle axis to face the object to the camera but either the object is not completely facing the camera at all times

currently I am constructing the angle and axis with a vector from the object to the camera and the original direction vector of the object (0,0,1) (so we recalculate each time)


	glm::vec3 tocam = glm::normalize(camerapos - pos);

	float angle = std::acos(glm::dot(direction, tocam));

	float a = fabs(glm::degrees(angle));
	 
	glm::vec3 axis = glm::cross(direction, tocam);

	currentrotation = glm::angleAxis(angle, axis);

	newdirection = currentrotation * direction;

        glm::mat4 RotationMatrix = glm::toMat4(currentrotation);

	glm::mat4 translationmatrix = glm::translate(glm::mat4(1.0f), pos);

	modelMatrix = translationmatrix * RotationMatrix;

Is my understanding of this incorrect? i very much believe that the angle calculation is correct but that im doing something wrong with the axis.

Thanks in advance for any help and feel free to explain in detail what im doing wrong (more i can learn the better) :).

Advertisement

float angle = std::acos(glm::dot(direction, tocam));

A dot product can be used to find the angle between 2 vectors BUT it will not give you direction(clockwise/anti-clockwise). For example, if something is 45 degrees to the right of me and another thing is 45 degrees to the left of me then using a dot product to work out the angle will give me 45 degrees for both objects (rather than 45 and -45(or 315). I suspect this is causing the problems you describe.

I don't know what the usual 'done' thing is for this but instead of rotating you could create an orthogonal basis. You know the direction to the camera, that will be your 'forward' vector, cross that with your world 'up' to get a 'right' vector. Cross the 'right' and the 'forward' to get the object's new 'up' vector. Now you have 3 orthogonal vectors you can create your basis (which is, in effect the rotation matrix that you need). Those 3 vectors will be rows in your rotation matrix. Assuming 'y' is up then row0 will be 'right', row1 will be 'up' and row2 will be 'forward'. Column 3 and row 3 should be all 0 except for R[3][3] which should be 1 (load it as an identity then replace the top 3x3 values with your 3 vectors).

Do you want these things leaning over towards the player? Good for some things but not so good for trees etc.

Interested in Fractals? Check out my App, Fractal Scout, free on the Google Play store.

@[member='Nanoha'] edit as on friends account

@Nanoha, Atm its for particles so that no matter where the camera is, the quad is facing the camera.

That definitely makes sense (in relation to the angle being positive or negative), I will try the solution out and get back to you when i get home :)

You could extract modelview matix of your camera amd get screen coord up and right vectors in notime

You could extract modelview matix of your camera amd get screen coord up and right vectors in notime

I saw something similar in the other billboard thread that's floating around. This certainly sounds like a far more efficient solution. With this approach I'm guessing all the billboards/particles will then be perpendicular to the screen (rather than facing the camera position)? This may or may not be an issue but it sounds like it's worth trying and seeing what it looks like as it is far more efficient than all those cross products per particle.

Interested in Fractals? Check out my App, Fractal Scout, free on the Google Play store.

So like the following?


	glm::mat4 cammodelview = view;

	glm::vec4 right = glm::vec4(1, 0, 0, 0) * cammodelview;
	right.w = 0;

	glm::vec4 up = glm::vec4(0, 1, 0, 0) * cammodelview;
	up.w = 0;

	glm::vec4 forward = glm::vec4(0, 0, 1, 0) * cammodelview;
	forward.w = 0;

	glm::mat4 mytest;
	
	mytest = glm::mat4(right, up, forward, glm::vec4(0, 0, 0, 1));

	modelMatrix = translationmatrix * mytest;

From this code i do get a behaviour that the quad that im using does following the camera (never see the edge) but i feel its still a bit off as when close up on the right side of the quad i get (if you can make it out atall)

https://i.gyazo.com/1a3e0ae81a7a9cb71affc37b74bba640.png (white box being the quad)

I think maybe its rotating the opposite way to where im turning (the camera is rotating) as i feel like the quad should be rotating so its almost pulling away the the camera (that being said could definitely get away with this)

Thanks for the responses btw :)

So like the following?

What you have there is transforming your world axis into view space which isn't quite what you need. I'm not 100% sure about this myself as I've never had to do it but what you want is the first 3 rows of that view matrix (the right, up and forward vectors). I'm not sure what the syntax is to get that with glm so I can't show an example. Once you have those they will be the opposite of what you want, you should be able to flip the 'right' and 'forward' vectors which should work the same as rotating about the 'up' axis by 180 degrees.

Another option might be to do similar to what you are currently doing and define those vectors in view space (so they are looking at the camera, right(-1, 0, 0), up (0, 1, 0), forward (0, 0, -1)) and then transform them back into world space by multiplying them by the inverse of your view matrix.

Interested in Fractals? Check out my App, Fractal Scout, free on the Google Play store.

@[member='Nanoha'], do u mean flip the forward and right vectors or flip what the vector is (.x becomes .z)

In relation to your seconds fix, i have done written this change but the end result is very similar to what i had before

code below


	glm::mat4 cammodelview = glm::inverse(view);

	//glm::vec4 right = glm::vec4(1, 0, 0, 0) * cammodelview;
	glm::vec4 right = cammodelview * glm::vec4(-1, 0, 0, 0);
	right.w = 0;

	//glm::vec4 up = glm::vec4(0, 1, 0, 0) * cammodelview;
	glm::vec4 up = cammodelview * glm::vec4(0, -1, 0, 0);
	up.w = 0;

	//glm::vec4 forward = glm::vec4(0, 0, 1, 0) * cammodelview;
	glm::vec4 forward = cammodelview * glm::vec4(0, 0, -1, 0);
	forward.w = 0;

	glm::mat4 mytest;

	mytest = glm::mat4(right, up, forward, glm::vec4(0, 0, 0, 1));

also for glm matrixname[0] will access the first row of the matrix (x axis)

@Nanoha, do u mean flip the forward and right vectors or flip what the vector is (.x becomes .z)

Sorry for being unclear, I mean (x, y, z) becomes (-x, -y, -z). I guess I should have said mirror the vector. But only for the right and forward vectors.


	glm::mat4 viewInv = glm::inverse(view);
        
        // You might actually be able to rip this stuff right out of the matrix rather than multiplying
	glm::vec4 right = viewInv * glm::vec4(-1, 0, 0, 0);
	glm::vec4 up = viewInv * glm::vec4(0, 1, 0, 0);
	glm::vec4 forward = viewInv * glm::vec4(0, 0, -1, 0);

	glm::mat4 mytest = glm::mat4(right, up, forward, glm::vec4(0, 0, 0, 1));

The reason that 'right' is mirrored is because the particles right is your left. Forward is mirrored for similar reasons, particles forward is my backwards. You will have to check forward though because with OpenGL I think forward might actually be (0, 0, -1). It depends on the coordinate system. Up remains the same because the particle's up is also the viewer's up.

Your best bet is to look for a tutorial that is dealing with this stuff.

Interested in Fractals? Check out my App, Fractal Scout, free on the Google Play store.

This topic is closed to new replies.

Advertisement