get vertex value after glrotatef

Started by
12 comments, last by Zakwayda 13 years, 11 months ago
Hi all, I am trying to figure out how to get a vertex's value after it has been translated or rotated (the one that I'm dealing now is rotate), the thing is that I'm doing a Collision Detection system with some cases (ray - sphere/triangle/etc), and now I'm doing the AABB and OBB, which for the AABB I made the only way I could think of, which is kind of an expensive algorithm, it's just that I couldn't think of a easier way (so far I don't know if there is a way to get the new vertex values after translation/rotation -> hopefully both cases have the same way of getting the transformed values), the AABB as many ppl know, it has to be recalculated everytime the object spins, because I don't know how to get the values after the rotation, I avoided the glrotatef by using some Sin/Cos formulas which are the problem with performance (from 100fps went down to 50fps, I know still a good frame speed, but one object divided by half the performance, so if I add another object with a Bouding Box -> AABB, then the code will be just cr*p), now that I'm with the OBB, I got to the same problem, in some way (in a badly way) I got to the solution of the AABB, but with the OBB (which the Bounding Box has to spin too), for not using Sin/Cos, I'm thinking of using the function glrotatef, but the problem as I repeated already a couple of times is that I don't know how to retreive the new vertexes' values after the rotation, and if by any case the way or getting this values can be used with the translation function then I will try to change the AABB. Sorry for the long story of my life, but I just can't find anything on .net, so far I got a name of a function glgetfloatv but I don't know if that is what I need, and if it is, could anyone explain me how an array of 16 float values is going to help me :) Thxs from now, and hope to hear an answer soon. Elqno
Advertisement
I recommend doing the math on the CPU side and pushing the transformed matrices to the hardware. If I'm not mistaken, reading back from the hardware can be slow and also stalls the graphics pipeline, which ultimately will lead to reduced performance.
smr Thanks for your advice, I have to say you that I'm doing it that way (all is done in the CPU), I think what will make better the performance will be when I take off the Sin/Cos calculations of the render function (they are calculated, when the objects is visible -> which is not the whole time, so when is rendered is calculated and then the program starts to go slower in fps), so to avoid that I think will be by doing a retrieve of the vertexes' values after the rotation made by using glrotatef, but how to do it?, that is what I would like to know :) btw smr if you know about it, I would really appreciate another answer from you ^^
AFAIK reading back transformed vertices is not possible or at least very hard but maybe with there's an easy way with OpenCL now.

However, I doubt you would gain much from reading transformed vertices in order to use them for collision detection. I'd also suggest not to recalculate the AABB after every transformation, especially if you have many vertices.

You'd better use a more coarse bounding volume for the whole object (i.e. a sphere) and decompose that into multiple smaller volumes, i.e. you form a bounding volume hierarchy which you use for collision queries.

Additionally, per-triangle collision detection is expensive and thus generally a "collision mesh" with fewer triangles is used for that (ofter in combination with a BVH). Collision meshes aren't rendered (at least in production code) and thus you would not be able to read back their vertices.

To summarize, I'd suggest to start with a bounding sphere which you could supplement with an OBB (testing the sphere first) and then build a bounding volume hierarchy.

Note that you can't use glRotateX(..) in that case but rather should do the transformation on the CPU. However, if you plan to use shader you should do that anyways.
If I was helpful, feel free to rate me up ;)If I wasn't and you feel to rate me down, please let me know why!
Quote:so to avoid that I think will be by doing a retrieve of the vertexes' values after the rotation made by using glrotatef, but how to do it?
I think it's unlikely that querying OpenGL state is the correct solution to the problems you describe. If the CPU isn't being able to keep up with your collision code, then I would guess that you're doing something particularly inefficient or unoptimal.

I didn't follow all the details of your original post, but reconstructing an AABB after rotation isn't all that expensive, and shouldn't involve any transforming of vertices. There will probably be a few 'sines and cosines' involved in keeping your object transforms up to date, but that happens in almost every game out there - it really shouldn't be a bottleneck of any sort.

Anyway, I'd suggest forgetting about the OpenGL feedback thing, and instead concentrate on optimizing and gaining a better understanding of your collision detection code. (As a side note, I know there are some techniques for moving collision detection and other traditionally CPU-oriented tasks to the GPU, but I don't get the sense that that's what we're talking about here.)
glRotate as any other transformation routine is internally used to build up the transformation matrix (MODELVIEW in your case). That matrix is send to the GPU together with the vertex data. Then the GPU applies the transformation to the vertices and handles the transformed vertices on-the-fly. It is not supposed to store the transformed vertices anywhere (perhaps with the exception of an internal cache and registers).

I doubt that such few sin/cos invocations can half your frame rate at all. I assume that you're doing unneccessary computations. First of, it is recommended not to use Euler angles to store the orientation but to use a rotation matrix. But even if you use Euler angles, you have to compute the transformation matrix just once for each object and frame. So computing a new AABB for an object requires at most 3 invocations of sin() and cos() for the rotation matrix.


EDIT: Huh, am I so slow in typing ..?

T: Transform Matrix
T~: invers Transform Matrix
a: Vector in World Space
b: Vector in Object Space

a = T * b
b = T~ * a

Matrix math 4tw^^

never looked into collision detaction but this is how you would get the World coordinates of a rotated Vertex
I will post the function that makes the AABB calculation, if I am not wrong, when calculating a rotating object with AABB, each vertex has to be calculated with Sin/Cos to know the new position (doing that way for avoid using glRotatef), so in my case the object is made of ~90,000 triangles, so from what you guys are saying I understand that, that 90,000 calculations with Sin or Cos is the mistake (I made a lookup table of 360 values for Sin and 360 for Cos -> a full rotation), but for get the new value, I have to do in runtime the multiplication of the vertex with the Sin or Cos respectively, I'm doing that because, while rotating, of course the min X,Y,Z and max X,Y,Z will be another vertice than the one from previous rotation, or am I completely wrong?

the Code with some comments for some lines which might be useful to know what the hell is it used for...

void calculateAABB(Obj &test) {//glrotate is smooth and slow while making the rotation, doing it without, and depending of the speed of the pc, I put a counter to 100 to make increment a degree more	if(++aabbCounter>=100) {aabbCounter=0;if(++aabbIndex>=360)aabbIndex=0;}	glPushMatrix();//avoiding glrotate and gltranslate	//glRotatef(rot,aabb[0].translate.x,aabb[0].translate.y,aabb[0].translate.z);	/*glTranslatef(	aabb[0].translate.x,					aabb[0].translate.y ,					aabb[0].translate.z);*///just a reset function to make the default to 0, all the code is in structures	Vec tmp = vectorize(0,0,0);	aabb[0].min = aabb[0].max = tmp;	glBegin( GL_TRIANGLES );	glColor3f(0.5f,0.5f,0.5f);//are pointers, coz I will need the values after, and I don't know the size of the object in faces (triangles) -> so the function can be used with any object, and not limitate it with just a specific object.	float *rX = new float[test.num_faces];	float *rY = new float[test.num_faces];	for(int i=0; i<test.num_faces; i++) {//the part that makes it slow. aabbCos/Sin are the lookup tables (sin/cos precalculated for avoid lost in performance, rX and rY = rotating in the Z axis		//FORMULA FOR MAKE THE OBJECT ROTATE (AVOIDING GLROTATE)		rX = test.vertices[test.v_idx].x*aabbCos[aabbIndex]-test.vertices[test.v_idx].y*aabbSin[aabbIndex];		rY = test.vertices[test.v_idx].y*aabbCos[aabbIndex]+test.vertices[test.v_idx].x*aabbSin[aabbIndex];//this is used to know the min and max vertices of the object		//CALCULATE MIN MAX OF EVERY AXIS		if (rX < aabb[0].min.x)			aabb[0].min.x = rX;		else if (rX > aabb[0].max.x )			aabb[0].max.x = rX;		if (rY < aabb[0].min.y)			aabb[0].min.y = rY;		else if (rY > aabb[0].max.y )			aabb[0].max.y = rY;		if (test.vertices[test.v_idx].z < aabb[0].min.z)			aabb[0].min.z = test.vertices[test.v_idx].z;		else if (test.vertices[test.v_idx].z > aabb[0].max.z)			aabb[0].max.z = test.vertices[test.v_idx].z;	}//this is the "reaction" of the collision detection, I'm doing when the objects rotate, to calculate if is over or under the floor then align it with the floor (almost with it, +0.1f)	for(int i=0;i<test.num_faces;i++) {		//AVOIDING HOVER EFFECT OF OBJECT OVER THE FLOOR		if (aabb[0].min.y+aabb[0].translate.y > 0) aabb[0].translate.y -= aabb[0].min.y+aabb[0].translate.y-0.1;		if (aabb[0].min.y+aabb[0].translate.y < 0) aabb[0].translate.y += (aabb[0].min.y+aabb[0].translate.y-0.1)*-1;		//DRAW...		//OBJECT ORIGINAL POSITION + TRANSLATED POSITION (FOR AVOID GLTRANSLATE)//drawing the vertices with the new position (the rotated one -> calculated before)		glVertex3f(	rX+aabb[0].translate.x,//test.vertices[test.v_idx].x,					rY+aabb[0].translate.y,//test.vertices[test.v_idx].y,					test.vertices[test.v_idx].z+aabb[0].translate.z );	}	glEnd();	glPopMatrix();	glPushMatrix();	glColor4f(1.0f,0.0f,0.0f,0.9f);//lines for show the AABB-> the box that holds the object	glBegin( GL_LINES );		//FRONT		glVertex3f(	aabb[0].max.x+aabb[0].translate.x , aabb[0].max.y+aabb[0].translate.y , aabb[0].max.z+aabb[0].translate.z );		glVertex3f(	aabb[0].max.x+aabb[0].translate.x , aabb[0].min.y+aabb[0].translate.y , aabb[0].max.z+aabb[0].translate.z );		glVertex3f(	aabb[0].max.x+aabb[0].translate.x , aabb[0].min.y+aabb[0].translate.y , aabb[0].max.z+aabb[0].translate.z );		glVertex3f(	aabb[0].min.x+aabb[0].translate.x , aabb[0].min.y+aabb[0].translate.y , aabb[0].max.z+aabb[0].translate.z );		glVertex3f(	aabb[0].min.x+aabb[0].translate.x , aabb[0].min.y+aabb[0].translate.y , aabb[0].max.z+aabb[0].translate.z );		glVertex3f(	aabb[0].min.x+aabb[0].translate.x , aabb[0].max.y+aabb[0].translate.y , aabb[0].max.z+aabb[0].translate.z );		glVertex3f(	aabb[0].min.x+aabb[0].translate.x , aabb[0].max.y+aabb[0].translate.y , aabb[0].max.z+aabb[0].translate.z );		glVertex3f(	aabb[0].max.x+aabb[0].translate.x , aabb[0].max.y+aabb[0].translate.y , aabb[0].max.z+aabb[0].translate.z );		//BACK		glVertex3f(	aabb[0].max.x+aabb[0].translate.x , aabb[0].max.y+aabb[0].translate.y , aabb[0].min.z+aabb[0].translate.z );		glVertex3f(	aabb[0].max.x+aabb[0].translate.x , aabb[0].min.y+aabb[0].translate.y , aabb[0].min.z+aabb[0].translate.z );		glVertex3f(	aabb[0].max.x+aabb[0].translate.x , aabb[0].min.y+aabb[0].translate.y , aabb[0].min.z+aabb[0].translate.z );		glVertex3f(	aabb[0].min.x+aabb[0].translate.x , aabb[0].min.y+aabb[0].translate.y , aabb[0].min.z+aabb[0].translate.z );		glVertex3f(	aabb[0].min.x+aabb[0].translate.x , aabb[0].min.y+aabb[0].translate.y , aabb[0].min.z+aabb[0].translate.z );		glVertex3f(	aabb[0].min.x+aabb[0].translate.x , aabb[0].max.y+aabb[0].translate.y , aabb[0].min.z+aabb[0].translate.z );		glVertex3f(	aabb[0].min.x+aabb[0].translate.x , aabb[0].max.y+aabb[0].translate.y , aabb[0].min.z+aabb[0].translate.z );		glVertex3f(	aabb[0].max.x+aabb[0].translate.x , aabb[0].max.y+aabb[0].translate.y , aabb[0].min.z+aabb[0].translate.z );		//SIDE LINES		glVertex3f(	aabb[0].max.x+aabb[0].translate.x , aabb[0].max.y+aabb[0].translate.y , aabb[0].max.z+aabb[0].translate.z );		glVertex3f(	aabb[0].max.x+aabb[0].translate.x , aabb[0].max.y+aabb[0].translate.y , aabb[0].min.z+aabb[0].translate.z );		glVertex3f(	aabb[0].max.x+aabb[0].translate.x , aabb[0].min.y+aabb[0].translate.y , aabb[0].max.z+aabb[0].translate.z );		glVertex3f(	aabb[0].max.x+aabb[0].translate.x , aabb[0].min.y+aabb[0].translate.y , aabb[0].min.z+aabb[0].translate.z );		glVertex3f(	aabb[0].min.x+aabb[0].translate.x , aabb[0].max.y+aabb[0].translate.y , aabb[0].max.z+aabb[0].translate.z );		glVertex3f(	aabb[0].min.x+aabb[0].translate.x , aabb[0].max.y+aabb[0].translate.y , aabb[0].min.z+aabb[0].translate.z );		glVertex3f(	aabb[0].min.x+aabb[0].translate.x , aabb[0].min.y+aabb[0].translate.y , aabb[0].max.z+aabb[0].translate.z );		glVertex3f(	aabb[0].min.x+aabb[0].translate.x , aabb[0].min.y+aabb[0].translate.y , aabb[0].min.z+aabb[0].translate.z );	glEnd();	glPopMatrix();	delete rX;	delete rY;}


sop, what am I doing wrong here? what would you change?
Quote:if I am not wrong
You are almost certainly wrong :)

First of all, even if you need to transform every vertex in the model for some reason, you only need to perform the necessary sine/cosine calculations once, not once for each vertex. You just build the desired transform matrix, and then apply it to each vertex in turn.

Second, the standard methods of updating bounding volumes for a model generally don't involve transforming every vertex in the model and recomputing the bounding volume from scratch - that would be prohibitively expensive in most cases.

As for how to handle your bounding volumes, there are a number of different approaches you could take. One would be to use a bounding volume (such as an AABB or sphere) that will fully contain the model at any orientation. Another would be to build a new AABB on a per-update basis from the model's OBB, which is quite inexpensive (and doesn't involve transforming any vertices whatsoever).

[Edit: Could you repost your code using [ source ] tags, and with the longer lines broken? That will make it easier to read.]
When you call glRotatef, then the CPU is used to compute a rotation matrix (and yes, sin and cos is used) and then the current matrix is multiplied by the rotation matrix.
result = currentmatrix * rot_matrix;

so the CPU is already used for this purpose and it certainly is NOT SLOW. I used this stuff back in the day with a Pentium 200MMX.
Sig: http://glhlib.sourceforge.net
an open source GLU replacement library. Much more modern than GLU.
float matrix[16], inverse_matrix[16];
glhLoadIdentityf2(matrix);
glhTranslatef2(matrix, 0.0, 0.0, 5.0);
glhRotateAboutXf2(matrix, angleInRadians);
glhScalef2(matrix, 1.0, 1.0, -1.0);
glhQuickInvertMatrixf2(matrix, inverse_matrix);
glUniformMatrix4fv(uniformLocation1, 1, FALSE, matrix);
glUniformMatrix4fv(uniformLocation2, 1, FALSE, inverse_matrix);

This topic is closed to new replies.

Advertisement