PDA

View Full Version : Billboard facing the camera has wrong rotation near 180 degrees



Geosearchef
05-17-2015, 10:21 AM
I've implemented a particle system. I'm drawing their textures on billboards that should be rotated towards the camera.

This works fine except for the case when the angle between particle->camera and the normal comes near to 180 degrees. Then the particle starts rotating around itself many times.

The angle is calculated using cos(angle) = dot(a, b) / (length(a) * length(b), the length are both 1 cause the Vectors are normalized. The axis is calculated using the cross product of those two vectors.




glDisable(GL_CULL_FACE);

//calculate rotation
Vector3f normal =newVector3f(0,0,1);
Vector3f dir =Vector3f.sub(newVector3f(GraphicsData.camera.x,Gr aphicsData.camera.y,GraphicsData.camera.z),newVect or3f(x, y, z),null);
if(dir.length()==0)
{
glEnable(GL_CULL_FACE);
return;
}
dir =(Vector3f) dir.normalise();
float angle =(float)Math.toDegrees(Math.acos(Vector3f.dot(norm al, dir)));
Vector3f rotationAxis =Vector3f.cross(normal, dir,null);
rotationAxis =(Vector3f) rotationAxis.normalise();
System.out.println("Angle: + "+ angle +" Axis: "+ rotationAxis);


glBindTexture(GL_TEXTURE_2D,ParticleEngine.particl eTextures.get(typeId).texture.getTextureID());


glColor4f(1f,1f,1f, time >= lifeTime - decayTime ?((float)lifeTime -(float)time)/((float)lifeTime -(float)decayTime):1f);
shaderEngine.createModelMatrix(newVector3f(x, y, z),newVector3f(angle * rotationAxis.x, angle * rotationAxis.y, angle * rotationAxis.z),newVector3f(sx, sy, sz));
shaderEngine.loadModelMatrix(shaderEngine.particle );
glCallList(ParticleEngine.particleTextures.get(typ eId).displayListId + textureIndex);

glEnable(GL_CULL_FACE);




What am i doing wrong calculating the rotation?




publicstaticvoid createModelMatrix(Vector3f pos,Vector3f rot,Vector3f scale)
{
GraphicsData.camera.modelMatrix =newMatrix4f();
GraphicsData.camera.modelMatrix.setIdentity();
GraphicsData.camera.modelMatrix.translate(pos);
GraphicsData.camera.modelMatrix.rotate((float)Math .toRadians(rot.x),newVector3f(1,0,0));
GraphicsData.camera.modelMatrix.rotate((float)Math .toRadians(rot.y),newVector3f(0,1,0));
GraphicsData.camera.modelMatrix.rotate((float)Math .toRadians(rot.z),newVector3f(0,0,1));
GraphicsData.camera.modelMatrix.scale(scale);
}

GClements
05-18-2015, 01:03 AM
The angle is calculated using cos(angle) = dot(a, b) / (length(a) * length(b), the length are both 1 cause the Vectors are normalized. The axis is calculated using the cross product of those two vectors.

You shouldn't be trying to calculate the angle. Just generate the matrix directly from the vectors. Better still, just render the particles in eye-space rather than trying to generate a model matrix which, aside from the translation, is the inverse of the view matrix.

More generally, if you ever find yourself wanting to use acos(), look for another solution, preferably without involving trigonometry. E.g. If you're going to pass that angle (or something derived from it) to sin/cos/tan, use trigonometric identities to eliminate both the inverse and forward trigonometric functions.