I have an application which uses DirectX, and hence a left-handed world-coordinate systen, a view which looks down positive z and a projection which projects into the unit cube but with z from 0..1.
I'm porting this application to OpenGL, and OpenGL has a different coordinate system etc. In particular, it's right-handed, the view looks down along negative z, and the projection is into the real unit cube.
What is the easiest way to adapt the DirectX matrices to OpenGL? The world-space change seems to be easy, just by flipping the x-axis, but I'm not entirely sure how to change the view/projection. I can modify all of the matrices individually before multiplying them together and sending them off to my shader. If possible, I would like to stick with the DirectX based coordinate system as far down the pipeline as possible (i.e. I don't want to change where I place my objects, how I compute my view frustum, etc. -- ideally, I'll only apply some modification to the matrices right before handing them over to my shaders.)
The answer is: There's no need to flip anything, only to tweak the depth range. OpenGL has -1..1, and DX has 0..1. You can use the DX matrices just as before, and only multiply a scale/bias matrix at the end on top of the projection matrix to scale the depth values from 0..1 to -1..1.
Not tested or anything, just out of the top of my head :
oglProj = transpose(dxProj)
glScalef (1., 1., -1.); // invert z
glScalef(0.5, 0.5, 1); // from [-1,1] to [-0.5, 0.5]
glTranslatef(0.5, 0.5, 0) // from [-0.5, 0.5] to [0,1]
oglView = transpose(dxView)
glScalef (1., 1., -1.); // invert z
oglModel = transpose(dwModel)
glScalef (1., 1., -1.); // invert z
oglModelView = oglView * oglModel
There is an age-old extension for OpenGL exactly for that: GL_ARB_TRANSPOSE_MATRIX. It transposes matrices on GPU and should be available on every video card.
Related
I am implementing a custom mathematics library to create model, view and projection matrices in OpenGL and DirectX. I am doing this, to improve my understanding in the mathematics behind 3D applications.
At first I took a look at right-handed and left-handed coordinate systems. I realized, that if I create my view matrix as well as my projection matrix with the same handedness, the scene renders correctly no matter if I use OpenGL or DirectX (except inverted translation/rotation/etc.). This is a bit confusing because every article I read pointed out, that OpenGL uses a right-handed and DirectX a left-handed coordinate system. Is my assumption right, that the coordinate system completely depends on the handedness of the view and projection matrices?
When I took a look at clip spaces, things became more difficult to understand. The articles stated, that the clip volume on the X and Y axis ranges from -1.0 to 1.0 in both APIs. On the Z axis OpenGL clips from -1.0 to 1.0 and DirectX clips from 0.0 to 1.0. However, in OpenGL the scene renders correctly no matter if I use a projection matrix for clipping between -1.0 and 1.0 or 0.0 and 1.0. In DirectX only the projection matrix for clipping between 0.0 and 1.0 works. If I use the other one, nothing is rendered.
So my question to this topic is: Can the clipping volume be changed on the Z axis or are those fixed implementations. If they are fixed, then why can I use both types of clipping volumes in OpenGL and only a single one in DirectX?
However, in OpenGL the scene renders correctly no matter if I use a projection matrix for clipping between -1.0 and 1.0 or 0.0 and 1.0. In DirectX only the projection matrix for clipping between 0.0 and 1.0 works
OpenGL renders because [0.0, 1.0] falls within the range [-1.0, 1.0], but DirectX does not because [-1.0, 1.0] can fall outside of [0.0, 1.0]. If you invert the depth of your test scene, you'll likely be able to see stuff in DirectX using the wrong projection matrix.
Can the clipping volume be changed on the Z axis or are those fixed implementations. If they are fixed, then why can I use both types of clipping volumes in OpenGL and only a single one in DirectX?
No, you can't change that behavior as it's part of the spec. The point of all the transformations you do as part of the rendering pipeline is to get your scene into clipping space. That means, for example, mapping your scene's depth from [-9999, 9999] down to [-1.0, 1.0] for OpenGL, or [0.0, 1.0] for DirectX
Is my assumption right, that the coordinate system completely depends on the handedness of the view and projection matrices?
Not sure what you're asking here. You already observed that a scene in OpenGL looks inverted in DirectX if you don't account for the difference in handedness. The view and projection matrix that your application uses doesn't change the behavior of the OpenGL and DirectX implementations.
I am converting some old software to support OpenGL. DirectX and OpenGL have different coordinate systems (OpenGL is right, DirectX is left). I know that in the old fixed pipeline functionality, I would use:
glScalef(1.0f, 1.0f, -1.0f);
This time around, I am working with GLM and shaders and need a compatible solution. I have tried multiplying my camera matrix by a scaling vector with no luck.
Here is my camera set up:
// Calculate the direction, right and up vectors
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);
// Update our camera matrix, projection matrix and combine them into my view matrix
cameraMatrix = glm::lookAt(position, position+direction, up);
projectionMatrix = glm::perspective(50.0f, 4.0f / 3.0f, 0.1f, 1000.f);
viewMatrix = projectionMatrix * cameraMatrix;
I have tried a number of things including reversing the vectors and reversing the z coordinate in the shader. I have also tried multiplying by the inverse of the various matrices and vectors and multiplying the camera matrix by a scaling vector.
Don't think about the handedness that much. It's true, they use different conventions, but you can just choose not to use them and it boils down to almost the same thing in both APIs. My advice is to use the exact same matrices and setups in both APIs except for these two things:
All you should need to do to port from DX to GL is:
Reverse the cull-face winding - DX culls counter-clockwise by default, while that's what GL keeps.
Adjust for the different depth range: DX uses a depth range of 0(near) to 1(far), while GL uses a signed range from -1 for near and 1 for far. You can just do this as "a last step" in the projection matrix.
DX9 also has issues with pixel-coordinate offsets, but that's something else entirely and it's no longer an issue with DX10 onward.
From what you describe, the winding is probably your problem, since you are using the GLM functions to generate matrices that should be alright for OpenGL.
(Mac OS X, Cocoa, C/C++, OpenGL, somewhat mathematically challenged.)
Project is a real-time (30fps) poker game, with a 2D view. The OpenGL view is set up for Orthographic projection using glOrtho; the camera is always looking directly down at the cards/table. To date, it's essentially been a 2D image composition engine.
My playing cards are pre-built textures (with alpha), rendered thusly:
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2f(0.0, 0.0);
glVertex3d(startDraw_X, startDraw_Y, 0.0);
glTexCoord2f(1.0, 0.0);
glVertex3d(endDraw_X, startDraw_Y, 0.0);
glTexCoord2f(0.0, 1.0);
glVertex3d(startDraw_X, endDraw_Y, 0.0);
glTexCoord2f(1.0, 1.0);
glVertex3d (endDraw_X, endDraw_Y, 0.0);
glEnd();
This works well, and provides 1:1 pixel mapping, for high image quality.
QUESTION: how can I (cheaply, quickly) "flip" or distort my card using OpenGL? The rotation part isn't hard, but I'm having trouble with the perspective aspect.
Specifically, I have in mind the horizontal flipping action of UIViews in iPhone applications (e.g. Music). The UIView will appear to flip by shrinking horizontally, with the appearance of perspective (the "rear" coordinates of the view will shrink vertically.)
Thanks for any help or tips.
Instead of using glOrtho to set up an orthographic projection, use glFrustum to set up a perspective projection.
Since you game is 2D, I assume it is a top-view camera, right ?
In this case, you can setup your projection matrix as a projection one, put your camera at the center of the table, at a decent height (> 1.2 x width of table depending on the FoV) and not change anything else.
You may have to set your card's (and other game items) height a lot closer from the table than what they may currently be (since in ortho, a delta of 10 meters along Z won't be seen).
Mixing ortho and perspective is technically possible, but I don't quite see the advantage. However, you may have special assets in your game that require special treatments...
I'm planning to create a tiled world with OpenGL, with slightly rotated tiles and houses and building in the world will be made of models.
Can anybody suggest me what projection(Orthogonal, Perspective) should I use, and how to setup the View matrix(using OpenGL)?
If you can't figure what style of world I'm planning to create, look at this game:
http://www.youtube.com/watch?v=i6eYtLjFu-Y&feature=PlayList&p=00E63EDCF757EADF&index=2
Using Orhtogonal vs Perspective projection is entirely an art style choice. The Pokemon serious you're talking about is orthogonal -- in fact, it's entirely layered 2D sprites (no 3D involved).
OpenGL has no VIEW matrix. It has a MODELVIEW matrix and a PROJECTION matrix. For Pokemon-style levels, I suggest using simple glOrtho for the projection.
Let's assume your world is in XY space (coordinates for tiles, cameras, and other objects are of the form [x, y, 0]). If a single tile is sized 1,1, then something like glOrtho(12, 9, -10, 10) would be a good projection matrix (12 wide, 9 tall, and Z=0 is the ground plane).
For MODELVIEW, you can start by loading identity, glTranslate() by the tile position, and then glTranslate() by the negative of the camera position, before you draw your geometry. If you want to be able to rotate the camera, you glRotate() by the negative (inverse) of the camera rotation between the two Translate()s. In the end, you end up with the following matrix chain:
output = Projection × (CameraTranslation-1 × CameraRotation-1 × ModelLocation × ModelRotation) × input
The parts in parens are MODELVIEW, and the "-1" means "inverse" which really is negative for translation and transpose for rotation.
If you want to rotate your models, too, you generally do that first of all (before the first glTranslate().
Finally, I suggest the OpenGL forums (www.opengl.org) or the OpenGL subforums of www.gamedev.net might be a better place to ask this question :-)
The projection used by that video game looks Oblique to me. There are many different projections, not just perspective and orthographic. See here for a list of the most common ones: http://en.wikipedia.org/wiki/File:Graphical_projection_comparison.png
You definitely want perspective, with a fixed rotation around the X-axis only. Around 45-60 degrees or thereof. If you don't care about setting up the projection code yourself, the gluPerspective function from the GLU library is handy.
Assuming OpenGL 2.1:
glMatrixMode(GL_PROJECTION); //clip matrix
glLoadIdentity();
gluPerspective(90.0, width/height, 1.0, 20.0);
glMatrixMode(GL_MODELVIEW); //world/object matrix
glLoadIdentity();
glRotatef(45.0f, 1.0f, 0.0f, 0.0f);
/* render */
The last two parameters to gluPerspective is the distance to the near and far clipping planes. Their values depend on the scale you use for the environment.
I'm trying to do a simple rotation in OpenGL but must be missing the point.
I'm not looking for a specific fix so much as a quick explanation or link that explains OpenGL rotation more generally.
At the moment I have code like this:
glPushMatrix();
glRotatef(90.0, 0.0, 1.0, 0.0);
glBegin(GL_TRIANGLES);
glVertex3f( 1.0, 1.0, 0.0 );
glVertex3f( 3.0, 2.0, 0.0 );
glVertex3f( 3.0, 1.0, 0.0 );
glEnd();
glPopMatrix();
But the result is not a triangle rotated 90 degrees.
Edit
Hmm thanks to Mike Haboustak - it appeared my code was calling a SetCamera function that use glOrtho. I'm too new to OpenGL to have any idea of what this meant but disabling this and rotating in the Z-axis produced the desired result.
Ensure that you're modifying the modelview matrix by putting the following before the glRotatef call:
glMatrixMode(GL_MODELVIEW);
Otherwise, you may be modifying either the projection or a texture matrix instead.
Do you get a 1 unit straight line? It seems that 90deg rot. around Y is going to have you looking at the side of a triangle with no depth.
You should try rotating around the Z axis instead and see if you get something that makes more sense.
OpenGL has two matrices related to the display of geometry, the ModelView and the Projection. Both are applied to coordinates before the data becomes visible on the screen. First the ModelView matrix is applied, transforming the data from model space into view space. Then the Projection matrix is applied with transforms the data from view space for "projection" on your 2D monitor.
ModelView is used to position multiple objects to their locations in the "world", Projection is used to position the objects onto the screen.
Your code seems fine, so I assume from reading the documentation you know what the nature of functions like glPushMatrix() is. If rotating around Z still doesn't make sense, verify that you're editing the ModelView matrix by calling glMatrixMode.
The "accepted answer" is not fully correct - rotating around the Z will not help you see this triangle unless you've done some strange things prior to this code. Removing a glOrtho(...) call might have corrected the problem in this case, but you still have a couple of other issues.
Two major problems with the code as written:
Have you positioned the camera previously? In OpenGL, the camera is located at the origin, looking down the Z axis, with positive Y as up. In this case, the triangle is being drawn in the same plane as your eye, but up and to the right. Unless you have a very strange projection matrix, you won't see it. gluLookat() is the easiest command to do this, but any command that moves the current matrix (which should be MODELVIEW) can be made to work.
You are drawing the triangle in a left handed, or clockwise method, whereas the default for OpenGL is a right handed, or counterclockwise coordinate system. This means that, if you are culling backfaces (which you are probably not, but will likely move onto as you get more advanced), you would not see the triangle as expected. To see the problem, put your right hand in front of your face and, imagining it is in the X-Y plane, move your fingers in the order you draw the vertices (1,1) to (3,2) to (3,1). When you do this, your thumb is facing away from your face, meaning you are looking at the back side of the triangle. You need to get into the habit of drawing faces in a right handed method, since that is the common way it is done in OpenGL.
The best thing I can recommend is to use the NeHe tutorials - http://nehe.gamedev.net/. They begin by showing you how to set up OpenGL in several systems, move onto drawing triangles, and continue slowly and surely to more advanced topics. They are very easy to follow.
Regarding Projection matrix, you can find a good source to start with here:
http://msdn.microsoft.com/en-us/library/bb147302(VS.85).aspx
It explains a bit about how to construct one type of projection matrix. Orthographic projection is the very basic/primitive form of such a matrix and basically what is does is taking 2 of the 3 axes coordinates and project them to the screen (you can still flip axes and scale them but there is no warp or perspective effect).
transformation of matrices is most likely one of the most important things when rendering in 3D and basically involves 3 matrix stages:
Transform1 = Object coordinates system to World (for example - object rotation and scale)
Transform2 = World coordinates system to Camera (placing the object in the right place)
Transform3 = Camera coordinates system to Screen space (projecting to screen)
Usually the 3 matrix multiplication result is referred to as the WorldViewProjection matrix (if you ever bump into this term), since it transforms the coordinates from Model space through World, then to Camera and finally to the screen representation.
Have fun