Sign in to follow this  
Elqno

get vertex value after glrotatef

Recommended Posts

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

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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 ^^

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.)

Share this post


Link to post
Share on other sites
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 ..?

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites
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[i] = test.vertices[test.v_idx[i]].x*aabbCos[aabbIndex]-test.vertices[test.v_idx[i]].y*aabbSin[aabbIndex];
rY[i] = test.vertices[test.v_idx[i]].y*aabbCos[aabbIndex]+test.vertices[test.v_idx[i]].x*aabbSin[aabbIndex];

//this is used to know the min and max vertices of the object
//CALCULATE MIN MAX OF EVERY AXIS
if (rX[i] < aabb[0].min.x)
aabb[0].min.x = rX[i];
else if (rX[i] > aabb[0].max.x )
aabb[0].max.x = rX[i];
if (rY[i] < aabb[0].min.y)
aabb[0].min.y = rY[i];
else if (rY[i] > aabb[0].max.y )
aabb[0].max.y = rY[i];
if (test.vertices[test.v_idx[i]].z < aabb[0].min.z)
aabb[0].min.z = test.vertices[test.v_idx[i]].z;
else if (test.vertices[test.v_idx[i]].z > aabb[0].max.z)
aabb[0].max.z = test.vertices[test.v_idx[i]].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[i]+aabb[0].translate.x,//test.vertices[test.v_idx[i]].x,
rY[i]+aabb[0].translate.y,//test.vertices[test.v_idx[i]].y,
test.vertices[test.v_idx[i]].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?

Share this post


Link to post
Share on other sites
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.]

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
Quote:
Original post by jyk
[Edit: Could you repost your code using tags, and with the longer lines broken? That will make it easier to read.]


Thxs for all your help, but actually I think...o nooo, I used "code" instead of "source" , my bad, sorry, next time I will remember that :)

about the Bounding Volume, I am using an AABB in this case and the thing is that I'm making the object rotate (not using glRotatef -> coz I didn't know if there was a way that could be recalculated the AABB from the new rotated object, now i know that is done using glGet), beside that, if I understood good the book of Real-Time Rendering of Moller, the AABB is a BV that must be recalculated when is rotated, while the OBB just spins with the object (one rotate for both), I'm trying 3 types of BV, which the sphere is not a problem, while the AABB and OBB was because of this problem of how to get the rotation matrix, but as I said before sb told me that is using glGet :)

Share this post


Link to post
Share on other sites
Quote:
about the Bounding Volume, I am using an AABB in this case and the thing is that I'm making the object rotate (not using glRotatef -> coz I didn't know if there was a way that could be recalculated the AABB from the new rotated object, now i know that is done using glGet), beside that, if I understood good the book of Real-Time Rendering of Moller, the AABB is a BV that must be recalculated when is rotated, while the OBB just spins with the object (one rotate for both), I'm trying 3 types of BV, which the sphere is not a problem, while the AABB and OBB was because of this problem of how to get the rotation matrix, but as I said before sb told me that is using glGet :)
I may be misunderstanding you here, but IMO, you should not be using glGet*() anywhere in your collision code. Whatever you might be using glGet*() for can (and should) be done using other means.

Share this post


Link to post
Share on other sites
You can retrieve the rotation matrix with glGet and transform your OBB with it.
Then you'd calculate the 8 corners of the OBB and use those to update your AABB instead of all 90000 vertices.

If you're using shaders (or plan to use them in the future) you might need to calculate the matrices yourself and pass them to the shaders since the newer versions of GLSL don't allow to query OpenGL state anymore.

Share this post


Link to post
Share on other sites
Quote:
You can retrieve the rotation matrix with glGet and transform your OBB with it.
Then you'd calculate the 8 corners of the OBB and use those to update your AABB instead of all 90000 vertices.
Are you sure that's the best approach? That's exactly what I've been encouraging the OP *not* to do :-|

I've never made extensive use of OpenGL state queries so I don't have any direct experience with this, but I *believe* that such queries are generally discouraged for performance reasons.

Regardless though, getting the rotation matrix by way of the OpenGL matrix stack is awkward, roundabout, and really completely unnecessary. Even if you're using the fixed-function pipeline, you really should already have these transforms available on the client side (since they are so often needed for collision detection, AI, and so on). It really shouldn't be necessary to abuse the OpenGL matrix stack for this purpose.

Also, although you do need the object's transform to recompute the AABB from the OBB, you *don't* need to transform the 8 corners of the OBB (the AABB can be computed from the OBB in a more direct and efficient manner by projecting the OBB onto the cardinal axes).

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this