GLM provides a way to declare a projection matrix:
projectionMatrix = glm::perspective(45.0f, 4.0f / 3.0f, 0.1f, 1000.f);
From this, I want to be able to check to see if bounding boxes are in my frustum. How do I obtain the frustum planes or whatever it is I would need to calculate this from the projection matrix? Is this even the correct way to do it?
This will help: http://crazyjoke.free.fr/doc/3D/plane%20extraction.pdf
Also notice that in order to extract the frustum you will need to extract it using model and view matrix as well otherwise you need to apply model and view transformation on the bounding boxes in order to perform the test.
Related
I have a model and some helper cubes which are located on its axes, three on each axis for transformations, I used them for rotate the model around its local axes.
I want to make those cubes rotate around the model center with its rotation so I translate them to the model center, rotate them by the same angle on the same axis the translate them back.
This is the code:
//Rotation around X axis
GLfloat theta=glm::radians(xoffset);
glm::quat Qx(glm::angleAxis(theta, glm::vec3(1.0f, 0.0f, 0.0f)));
glm::mat4 rotX = glm::mat4_cast(Qx);
pickedObject->Transform(rotX);//Multiply the model matrix by the transformation matrix
glm::vec3 op(pickedObject->getMatrix()[3]);//model position
for(TransformationHelper* h:pickedObject->GetTransformationHelpers()){//the small cubes
glm::mat4 m,it,t;
glm::vec3 hp(h->getMatrix()[3]);//the cube position
t=glm::translate(m,op);//m is a unit matrix
it=glm::translate(m,-op);
m=t*rotX*it;
h->Transform(m);
}
The result is unexpected
Update:
after updating the translation matrix I got this result:
The translation is in the wrong direction; the correct offset should be hp-op, i.e. the matrix t should restore the cube's position after rotating.
t=glm::translate(glm::mat(1.f),hp-op);
Also there is no need to use inverse since it is costly (and numerically less stable):
it=glm::translate(glm::mat(1.f),op-hp);
(Note: here translate was called with an explicitly constructed identity matrix. See this post for a similar problem. See here for why this is necessary.)
I'm following the OpenGL tutorials on opengl-tutorial.org, and in tutorial 4 the author proposed, as a side "project", to send two "objects" to OpenGL and we have only ever rendered one object before. Specifically, he asks this:
Draw the cube AND the triangle, at different locations. You will need to generate 2 MVP matrices, to make 2 draw calls in the main loop, but only 1 shader is required.
We define the MVP matrix like this:
GLuint MatrixID = glGetUniformLocation(programID, "MVP");
glm::mat4 Projection = glm::perspective(90.0f, 4.0f / 3.0f, 0.1f, 100.0f);
// Camera matrix
glm::mat4 View = glm::lookAt(
glm::vec3(0,0,3), // Camera is at (4,3,3), in World Space
glm::vec3(0,0,0), // and looks at the origin
glm::vec3(0,1,0) // Head is up (set to 0,-1,0 to look upside-down)
);
glm::mat4 Model = glm::mat4(1.0f);
glm::mat4 MVP = Projection * View * Model;
Now I understand that only one MVP matrix is used per object. But I have a few questions.
How do I create a MVP matrix for each object? Do I have to re-create the View and Model matrices for every object (IE specify a new one for each object)?
I thought glm::lookAt was used as the "camera" of sorts, so I shouldn't have to create a new "Camera" for each object, should I?
What does the Model matrix do? The author says it is a identity matrix right now, but if I change that to say 100, nothing happens! I thought that the Model matrix was the matrix that defined where the model was rendered, but I can't seem to change where the model is rendered without modifying the View matrix (which makes sense).
Typically, one uses one projection and one view matrix per "camera". The view matrix basically represents the position and orientation of the camera, and the projection matrix represents the properties of the camera (field of view, aspect, etc. in some way like a "lens" of a real camera, but don't stretch that analogy too far).
A model matrix typically is used to place the model in some global "world cooridnate system". So, you need a model matrix per object, so each object can be placed independently.
The world coordiante system is not strictly needed at all. What matters to the resulting picture is how the objects are placed relative to the camera - that is there ModelView enters the picture - as the composition of the model and the view transform, directly going from object space to some camera-relative eye space, bypassing any "world space" completely.
In your case, you even further combine this with the projection matrix, so you go directly from object space to clip space.
As you can see, the MVP matrix needs to change if any of the distinct matrices it is composed of does change. You could in theory precalculate an MVP per object - but that is typically not done, since the camera is moveable and all those MVP matrices would have to be recalculated anyways - there is not much to save here. So one typically keeps these matrices separate and multiplies them together directly before the draw call.
What does the Model matrix do? The author says it is a identity matrix right now, but if I change that to say 100, nothing happens!
What does this even mean, "changing a matrix to 100"? From the above code snippets it can be seen that your model matrix is indeed used and affects the MVP matrix. So changing it should have an effect - depending on what you change, of course. If you just changed the line
glm::mat4 Model = glm::mat4(1.0f);
to
glm::mat4 Model = glm::mat4(100.0f);
then it would actually not lead to any observeable change. You would get different clip space coords, but the differences would cancel each other out and the produced image would have been the same. That would be due to how homogenous coordinates work, and is a different matter entirely.
According to MSDN, we are multiplying the current matrix with the perspective matrix. What matrix are we talking about here? Also from MSDN:
"The glFrustum function multiplies the current matrix by this matrix, with the result replacing the current matrix. That is, if M is the current matrix and F is the frustum perspective matrix, then glFrustum replaces M with M • F."
Now, from my current knowledge of grade 12 calculus (in which I am currently), M is a vector and M dot product F returns a scalar, so how can one replace a vector with a scalar?
I'm also not sure what "clipping" planes are and how they can be referenced via one float value.
Please phrase your answer in terms of the parameters, and also conceptually. I'd really appreciate that.
I'm trying to learn openGL via this tutorial: http://www.youtube.com/watch?v=WdGF7Bw6SUg. It is actually not really good because it explains nothing or else it assumes one knows openGL. I'd really appreciate a link to a tutorial otherwise, I really appreciate your time and responses! I'm sure I can struggle through and figure things out.
You misunderstand what it's saying. M is a matrix. M•F therefore is also a matrix. It constructs a perspective matrix. See this article for an explanation of how it is constructed and when you want to use glFrustum() vs. gluPerspective():
glFrustum() and gluPerspective() both produce perspective projection matrices that you can use to transform from eye coordinate space to clip coordinate space. The primary difference between the two is that glFrustum() is more general and allows off-axis projections, while gluPerspective() only produces symmetrical (on-axis) projections. Indeed, you can use glFrustum() to implement gluPerspective().
Clipping planes are planes that cut out sections of the world so they don't have to be rendered. The frustum describes where the planes are in space. Its sides define the view volume.
glFrustum generates a perspective projection matrix.
This matrix maps a portion of the space (the "frustum") to your screen. Many caveats apply (normalized device coordinates, perspective divide, etc), but that's the idea.
The part that puzzles you is a relic of the deprecated OpenGL API. You can safely ignore it, because usually you apply gluFrustum() on an identity projection matrix, so the multiplication mentioned in the doc has no effect.
A perhaps more comprehensible way to do things is the following :
// Projection matrix : 45° Field of View, 4:3 ratio, display range : 0.1 unit <-> 100 units
glm::mat4 Projection = glm::perspective(45.0f, 4.0f / 3.0f, 0.1f, 100.0f);
// Or, for an ortho camera :
//glm::mat4 Projection = glm::ortho(-10.0f,10.0f,-10.0f,10.0f,0.0f,100.0f); // In world coordinates
// Camera matrix
glm::mat4 View = glm::lookAt(
glm::vec3(4,3,3), // Camera is at (4,3,3), in World Space
glm::vec3(0,0,0), // and looks at the origin
glm::vec3(0,1,0) // Head is up (set to 0,-1,0 to look upside-down)
);
// Model matrix : an identity matrix (model will be at the origin)
glm::mat4 Model = glm::mat4(1.0f);
// Our ModelViewProjection : multiplication of our 3 matrices
glm::mat4 MVP = Projection * View * Model; // Remember, matrix multiplication is the other way around
Here, I used glm::perspective (the equivalent of old-style gluPerspective() ), but you can use gluFrustum too.
As for the arguments of the function, they are best explained by this part of the doc :
left bottom - nearVal and right top - nearVal specify the points on
the near clipping plane that are mapped to the lower left and upper
right corners of the window, assuming that the eye is located at (0,
0, 0)
If you're unfamiliar with transformation matrices, I wrote a tutorial here; the "Projection Matrix" section especially should help you.
I am working with NV Path extension which forces using of fixed pipeline transformations. Now, while for view and model matrices I just roll my own and load those via:
glMatrixPushEXT(GL_MODELVIEW);
glMatrixLoadfEXT(GL_MODELVIEW, value_ptr(viewmodel) );
I have issues with perspective matrix FOV. The fixed method for creation persp matrix is this:
glMatrixLoadIdentityEXT(GL_PROJECTION);
glMatrixFrustumEXT(GL_PROJECTION, -aspect_ratio, aspect_ratio, -1, 1, nearF, farF);
but it doesn't allow passing a custom FOV. So it probably creates some default FOV based on l ,r ,b ,t params of the method above. Can I use:
glMatrixLoadfEXT(GL_PROJECTION, myProjectionMatrix);
to load a custom projection matrix without using glMatrixFrustumEXT?
UPDATE:
As some peopled pointed out, I can load projection matrix the same way I do with model view.But I found that my custom projection never looks the same as when using glMatrixFrustumEXT(). Probably FOV calculation is different. Anybody knows how glMatrixFrustumEXT calculates the FOV?
Using glFrustum or glMatrixFrustumEXT does allow to specify the FOV, and you actually do so. As you define the points on the near plane, and the distance of the near plane, you implicitely define the fov, both vertical and horizontal.
Look at the old gluPerspective function:
gluPersepctive(fov_y, aspect, zNear, zFar)
This would generate a symmetrical frustum with the given vertical FOV of fov_y as follows:
top=tan(fov_y/2.0) * zNear; // assuming fov_y in radians here
bottom=-top;
left=bottom*aspect;
right=-left;
glFrustum(left, right, bottom, top, zNear, zFar);
In your code, you are simply specifying a vertical FOV of 2*atan(1/nearF)
I have just gotten into implementing skyboxes and am doing so with OpenGL/GLSL and GLM as my math library. I assume the problem is matrix related and I haven't been able to find an implementation that utilizes the GLM library:
The model for the skybox loads just fine, the camera however circles it as if it is rotating around it in 3d third person camera.
For my skybox matrix, I am updating it every time my camera updates. Because I use glm::lookAt, it is essentially created the same way as my view matrix except I use 0, 0, 0 for the direction.
Here is my view matrix creation. It works fine in rendering of objects and geometry:
direction = glm::vec3(cos(anglePitch) * sin(angleYaw), sin(anglePitch), cos(anglePitch) * cos(angleYaw));
right = glm::vec3(sin(angleYaw - 3.14f/2.0f), 0, cos(angleYaw - 3.14f/2.0f));
up = glm::cross(right, direction);
glm::mat4 viewMatrix = glm::lookAt(position, position+direction, up);
Similarly, my sky matrix is created in the same way with only one change:
glm::vec3 position = glm::vec3(0.0f, 0.0f, 0.0f);
glm::mat4 skyView = glm::lookAt(position, position + direction, up);
I know a skybox does not apply translation and only considers rotations so I am not sure what the issue is. Is there an easier way to do this?
Visual aids:
Straight on without any movement yet
When I rotate the camera:
My question is this: how do I set up the correct matrix for rendering a skybox using glm:lookAt?
Aesthete is right skybox/skydome is only object that means you do not change projection matrix !!!
your render should be something like this:
clear screen/buffers
set camera
set modelview to identity and then translate it to position of camera you can get the position directly from projection matrix (if my memory serves at array positions 12,13,14) to obtain the matrix see this https://stackoverflow.com/a/18039707/2521214
draw skybox/skydome (do not cross your z_far plane,or disable Depth Test)
optionaly clear Z-buffer or re-enable Depth Test
draw your scene stuf .... ( do not forget to set modelview matrix for each of your drawed model)
of course you can temporary set your camera position (projection matrix) to (0,0,0) and leave modelview matrix with identity, it is sometimes more precise approach but do not forget to set the camera position back after skybox draw.
hope it helps.