Couple questions about extracting vectors from a matrix and frustum transformations.

Started by
6 comments, last by GameDev.net 14 years, 7 months ago
Hello, I am designing a frustum class for my game engine but am having a few questions. Question 1) Ok, so it is my understanding that given a view matrix you can extract the AT vector (the position of the viewer) and other related vectors (look etc.). This is straightforward in that it is just one of the rows/columns depending on row or column major order. I for the most part understand this and it is straightforward. Ok, so now my question is ... given a matrix that represents the projection AND the view matrix concatenated, can you extract the AT vector (and others) using the same formulas? Any clarifications are greatly appreciated. Question 2) Ok, I am now trying to figure out exactly what the projection and view concatenated matrix is doing in relation to the frusum. Please correct me if I am wrong but it is my understanding that if you construct an axis aligned cube of extents 1 x 1 x 1 with the center at the origin and multiply the 8 corners by the concatenated view/projection matrix you will then get the 8 corners of the view frustum in world space? Also, if you transform the origin (0,0,0) by the concatenated view/projection matrix you would then get the apex of the frustum in world space or the center of the frustum? Just trying to clarify and understand this a bit more. Thank you for your help. Jeremy
Advertisement
Quote:Ok, so it is my understanding that given a view matrix you can extract the AT vector (the position of the viewer) and other related vectors (look etc.). This is straightforward in that it is just one of the rows/columns depending on row or column major order. I for the most part understand this and it is straightforward.
Typically, the 'at' point would not be the position of the viewer, but rather a point that the viewer is looking at.

In any case, neither the 'at' point nor the position of the viewer can be extracted directly from the view matrix in the way you describe. The position can be extracted with a little math, if needed; as for the 'at' point (such as would be used to build a 'look at' matrix), that information is lost when the transform is constructed. (You can certainly extract an 'at' point, but there is no the 'at' point once the transform has been constructed.)

You can however extract the camera direction vectors directly from the view matrix (they will reside in the rows/columns, as you describe).
Quote:Ok, so now my question is ... given a matrix that represents the projection AND the view matrix concatenated, can you extract the AT vector (and others) using the same formulas?
No, not normally. You could if you had the original projection parameters available, although I'm not sure what the point would be. (IMX at least, it's not often necessary to extract view and projection parameters in this way. Assuming you built the original transforms yourself, you should have all the original input parameters available already.)
Thank you for your help.

Yeah ... I meant eye vector not at vector. The terminology is a bit misleading if you ask me.

What I am trying to do with all of this (and I think I have it figured out) is to construct a frustum with encompassing bounding sphere, AABB, and OBB for efficient object culling each frame of animation. I would like to have a clean interface to construct all of this from and I believe that simply a view*projection matrix is all that is required to calculate this information efficiently. Please explain if you see a better route. I would also like to calculate and store the world space positions of the view plane corners.

In pseudo-code what I have come up with looks like this:
class JFrustum{// private data etc.public:     void Construct(const JMatrix4x4& view_proj)     {           // Step 1) Calculate the frustum planes from view_proj (very easy)          // Step 2) Calculate the inverse of view_proj in inverse_view_proj          // Step 3) Transform (1,1,0), (-1,1,0), (1,-1,0), (-1,-1,0) by          //         inverse_view_proj.  Those are the world space view plane          //         corners right?          // Step 4) Transform (1,1,1) by inverse_view_proj.  That is a          //         world space far plane corner right?          // Step 5) Transform (0,0,0.5) by inverse_view_proj.  That is           //         the center of the frustum right?          // Step 6) Calculate distance from center to the far plane corner.          //         that is the radius of the frustum right?          // Step 7) Bounding_Sphere now has a center and a radius so construct           //         it.          // Step 8) AABB and OBB are both constructed by taking a model space           //         to world matrix and an axis aligned extents vector in           //         model space.  The AABB and OBB are constructed internally           //         by transforming the corners of the face in the positive z           //         direction in model space to world (representing the far           //         plane in this example), calculating their extents in world           //         space as needed (AABB OBB differ), and then mirroring it           //         to the other half through symmetry. So ... since the           //         the frustum * view_proj has a center at (0,0,0.5), ...           //         call:          //           //         JMatrix4x4 translation = CreateTranslationMatrix(0,0,0.5);          //         translation *= inverse_view_proj;          //         AABB.Construct(inverse_view_proj,JVector3(1,1,0.5));          //         OBB.Construct(inverse_view_proj, JVector3(1,1,0.5));          }};


So, my questions are:
Is all of that correct? Is all of that accurate? Is there a better/more efficient way?

Thank you for your help.
Jeremy
Quote:Is there a better/more efficient way?
You can extract the frustum planes from the (model)view and projection matrices using the technique described here. If needed, you can then compute the frustum corners by intersecting the frustum planes in groups of three.
Wouldn't it be more efficient to simply transform the corners
(1,1,0), (-1,1,0), (1,-1,0), (-1,-1,0)
by the inverse of view_proj to get the view plane corners?

It seems that to find a point in the frustum in world space it would be more simple to simply transform the associated point centered around the origin by the inverse of view_proj rather than calculate planar intersections.

I could be wrong.

Jeremy
Quote:Wouldn't it be more efficient to simply transform the corners
(1,1,0), (-1,1,0), (1,-1,0), (-1,-1,0)
by the inverse of view_proj to get the view plane corners?

It seems that to find a point in the frustum in world space it would be more simple to simply transform the associated point centered around the origin by the inverse of view_proj rather than calculate planar intersections.
First, I would suggest re-examining your concerns regarding efficiency. Under normal circumstances, frustum plane extraction is something that's done only once per frame (a few times at most), in which case the difference in performance between method X and method Y almost certainly won't matter.

As for which approach is more efficient, I don't know. Keep in mind though that you'll usually need access to the frustum planes at some point, so with your method, after you've transformed the corners of the unit cube, you'll then need to build the frustum planes manually.

As for your second point, I've always performed frustum culling in world space; I believe though that there may be some alternative approaches that are more like what you describe (e.g. performing the culling in clip space), but I haven't investigated these methods myself.

There are quite a few articles on this subject floating about online, so if you were to search for, say, 'frustum culling' or 'optimized frustum culling', and read every article and tutorial you could get your hands on, I think you'd probably get a pretty good cross-section of the various algorithms that are used for this purpose.
Hello Jyk and thank you,

I am absolutely in agreement with you. Extracting the planes from the view_proj matrix is the way to go to get the planes themself. You cannot get more efficient than that (I believe). Also, for the note, I do my culling in world space as well.

All I was saying is that in order to calculate the radius and extents of the AABB/OBB each frame from the view_proj matrix, it seems to me that rather than calculate the intersection between 3 planes to get each corner, you could simply transform the corners of the unit cube by the inverse_view_proj matrix.

It just seems more simple but again I could be wrong.

Thanks again man ...

That however leaves me with a couple of questions still ...

Question 1)
I know that DirectX and other APIs (OpenGL) have different configurations for their row/major ordering of matrices and other discrepencies, but do different APIs have different interpretations of the unit cube that the view_proj matrix transforms to? For DirectX the extents are (1,1,0.5) with the center of the cube at (0,0,0.5). I need to know that because if I calculate the corners of the frustum in world space by transforming the corners of the unit cube they are going to have to synch cross-API.

Question 2)
Could someone please verify that the pseudo-code I wrote above is accurate/correct?

Thank you for your help.
Jeremy
Your pseudo-code seems correct, I thought about something similar myself, but I chose a much simpler solution:
void cCore_SpacePartitionGrid::ComputeVisibleCells(){    if(m_pViewport == NULL)        return;    float distance = (m_pViewport->m_fZFar - m_pViewport->m_fZNear) * 0.5f;    float grow     = distance * 1.2f;    //debug:    //grow = 50.0f;    //debug^    D3DXVECTOR3 center = m_pViewport->m_vPos + m_pViewport->m_vLook * (m_pViewport->m_fZNear + distance);    D3DXVECTOR3 vmin = center - D3DXVECTOR3(grow, grow, grow);    D3DXVECTOR3 vmax = center + D3DXVECTOR3(grow, grow, grow);    CoordToCell(m_minI, m_minJ, m_minK, vmin);    CoordToCell(m_maxI, m_maxJ, m_maxK, vmax);}

I initially wanted to precisely find out which cells from the grid are visible, but that seemed too tedious due to the shape of the frustum so I chose to simply find out the AABB that contain the sphere which encapsulate the frustum. If I remember the math I used here correctly, that 1.2 is a rounded approximation of the sqrt(2) from (a * sqrt(2)) that defines the length of a cube's diagonal.

This topic is closed to new replies.

Advertisement