Java-Gaming.org    
Featured games (91)
games approved by the League of Dukes
Games in Showcase (579)
games submitted by our members
Games in WIP (500)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Matrices (and some random OpenGL 3.x questions)  (Read 3009 times)
0 Members and 1 Guest are viewing this topic.
Offline theagentd
« Posted 2011-07-27 11:20:42 »

Hello.
Until now I've been using the deprecated functions for setting up my matrices, but now I wish to only use OpenGL 3.x. I think I've gotten the grasp of vertex buffers, vertex arrays, shaders, etc, so now I just need to get my matrices working.
My old code:
1  
2  
3  
4  
5  
6  
7  
8  
GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glLoadIdentity();
GLU.gluPerspective(fieldOfView, (float)width / height, near, far);

GL11.glMatrixMode(GL11.GL_MODELVIEW);
GL11.glLoadIdentity();
// 'e' stands for eye, 'c' stands for center, 'u' stands for up
GLU.gluLookAt(ex, ey, ez, cx, cy, cz, ux, uy, uz);

Earlier I just used the glTranslate/Rotate/Scale methods to move around my models. This works fine, but since none of the above functions are supported in OpenGL 3.x, I basically need a crash course in matrix operations. I've been reading around on the Internet and (I think) I understand; Different matrices are multiplied together and then finally multiplied with the game world coordinates in the vertex shader, but I'm having a hard time finding out what the different matrices actually do or represent. I've also heard that lighting should be done in between the projection matrix and the modelview matrix, but I'm just so confused about all these names/words. I don't really understand what some of them represent or what they yield. What am I supposed to put in each matrix?
According to Swiftless I need 3 matrices in my vertex shader, which I believe older versions of OpenGL premultiplied together on the CPU, right? Would there be any benefit of having them split up? I'm guessing lighting here (which I won't be doing in while, but still interested).
What is the best way of keeping track of the matrix data now that OpenGL's matrix stack is deprecated? My own implementation of a matrix stack? I don't think I need one. Are there any libraries for matrix operations (LWJGL)?
My biggest need is probably an explanation of what the different matrices do. So far I think I've figured out this at least:
View Matrix: The camera position and orientation?
Model Matrix: The current models position, orientation and scale?
Projection Matrix: Uuuh... Basically makes things smaller if they are far away?
Also, how would I send it to my shaders? Premultiplied? My game will most likely be GPU-limited so it's probably best to premultiply some or all of the matrices, but which ones CAN I premultiply?
Ah, finally: I've heard that bones in skeleton animation are matrices. Is each bone multiplied with it's parent?

Jeez, so many questions but try to bear with me.  Grin

Myomyomyo.
Offline gouessej

« In padded room »



TUER


« Reply #1 - Posted 2011-07-27 12:00:20 »

Hi

Look at the implementation of the LWJGL renderer of JMonkeyEngine 3 using the programmable pipeline, you will find some answers in it.

Offline theagentd
« Reply #2 - Posted 2011-07-27 17:05:53 »

I haven't used JMonkeyEngine, and I couldn't even find the Javadoc... Still interested though!
Made some very small benchmarks to see if 3 matrix multiplications would be slower than 1. Yeah, right. Damn card is spewing out 10 million triangles at 40 FPS!!! Are matrix multiplications single cycle or what?! (In vertex shaders, I mean...)

Myomyomyo.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline lhkbob

JGO Knight


Medals: 32



« Reply #3 - Posted 2011-07-27 17:43:45 »

I would look at the Redbook's discussion of the different matrices.  Even though its talking about the old API, it explains the concepts really well.

So some explanations:
Any matrix can transform a vector.  It helps to think of this transformation as changing coordinate spaces.  Usually in the game, you have multiple coordinate spaces.  There's the one where your geometry is defined for each model, which you might call the local space.  Each object in the world has a translation, rotation, and scale, that represents its location in the world space.

Multiplying the vertices of the geometry in local space with the object's transform changes the coordinate space to be the world space by computing the equivalent "location".

When you multiply a matrix with another matrix, you're concatenating the transforms.  This means that when you use the resulting matrix, it behaves just as if you transformed the vertex by both.  The order they are applied goes from right to left.  So the following transforms are equivalent:
1  
2  
3  
4  
5  
6  
7  
 Matrix4f c = a x b; // multiply a with b
Vector4f t1 = c x v; // transform v by c

 Vector4f t2 = b x v;
 Vector4f t3 = a x t2;

 t1.equals(t3) == true; // barring floating point errors


Now to the actual OpenGL concepts.  I'll talk about the MODELVIEW matrix first.  This is a combination of two conceptual tranforms.  The model transform represents the transform from an object or light's local space to the world space (as I talked about above). 

The view transform is the inverse of the camera's world transform.  The inverse of a transform changes coordinate spaces in the opposite direction.  So the inverse of a world transform moves from world space to local space.  Since the camera's world transform can be thought of just like any other world transform, inversing it will change the coordinate space to show everything from the point of the camera, which is exactly what we want when rendering.

The actual view transform is actually a little different in implementation because OpenGL looks down the negative z-axis, which makes things difficult.  Any formula online for a view matrix based on location, camera direction and an up vector should take this into account.

The projection matrix is the final matrix.  The model and view matrices are affine transforms, which means that no matter how you apply them, parallel lines will remain parallel (basically things aren't distorted).  The projection matrix is different.  It is responsible for creating the perspective effects that we see when rendering 3D onto a monitor.  There are multiple projection types but the most common is the perspective projection matrix. 

In camera space (i.e. after transforming with the inverse view transform), the visible scene is contained in a frustum or truncated pyramid where the tip of the pyramid is at the camera's location and it is capped by the near and far planes.  The projection matrix transforms every vertex within this frustum so that it lies within a unit cube, which makes it really easy to then map onto actual pixels.

Because of this, you will apply the projection matrix last after computing lighting and other effects.  In the older versions of OpenGL, lighting was computed in camera space.  This means that the normal vectors of your model have to be transformed, too.  However, because normal vectors don't need to be translated, you can't just multiply the model matrix with them.  I would look up tutorials on the "normal matrix" to read a good explanation of how to transform normal vectors.

Matrix multiplication is really fast, both on the GPU and CPU.  I have found that the multiplication on the CPU was faster than the JNI overhead that came from using glPushMatrix and glPopMatrix.  I don't think its necessary to implement your own matrix stack in your shaders.   It is still probably helpful to separate the projection, view and model matrices though.  If you have transform hierarchies, like in a scene graph, you can multiply all of their model matrices together in the correct order to create a single model transform for each object that will have the same end result.

Offline gouessej

« In padded room »



TUER


« Reply #4 - Posted 2011-07-28 00:57:01 »

The JNI overhead is about 17 ns, it is not that big, am I wrong?? Mickael (bienator) spoke about that recently on another forum.

Offline lhkbob

JGO Knight


Medals: 32



« Reply #5 - Posted 2011-07-28 01:56:24 »

I may have mis-remembered.  I think instead it was poor performance with the matrix stack operations.  I tended to see that the calls to glPushMatrix was really slow and then all matrix operations would be fast until the next call to glPopMatrix.  I experimented and it seemed like it could happen similarly with a slow glLoadIdentity and a fast glMultiplyMatrix.  I ended up deciding to just always use glLoadMatrix to minimize the number of OpenGL calls.

I don't know what performance would be like with calling glUniformMatrix4f or whatever is used to send a matrix to a shader, but I do know you'd be wasting valuable uniform storage space if you tried to store an entire matrix stack in the shader.

Offline theagentd
« Reply #6 - Posted 2011-07-28 13:03:49 »

Thank you so much for the explanation, lhkbob! I think I have a little better grasp of everything now.
Matrix operations are extremely fast in shaders, so I don't think I'll get any performance problems by having 3 separate matrices in my vertex shaders.
The view transform is the inverse of the camera's world transform.  The inverse of a transform changes coordinate spaces in the opposite direction.  So the inverse of a world transform moves from world space to local space.  Since the camera's world transform can be thought of just like any other world transform, inversing it will change the coordinate space to show everything from the point of the camera, which is exactly what we want when rendering.
So basically I set up a matrix by translating and rotating the camera to where I want it and then invert the matrix?

Am I right in the following assumptions?
 - The model matrix is usually updated for each model, as it maps a model's coordinates to world space.
 - The view matrix is usually updated each frame (or when the camera moves), as it represents the camera's (inverse) position and rotation.
 - The projection matrix is usually only set at the start of the game, as it creates the 3D perspective. (Changing the field of view would achieve an aim-down-sights (zoom like) effect, right?)

If I don't need lighting, would it be a good idea to just multiply the view matrix and the projection matrix at the beginning of each frame? Since none of them changes in the middle of a frame and I don't need the view space coordinates it should be okay, right? In my vertex shader I'll just multiply my vertex with my model matrix and my "ViewProjection" matrix.

My real problem now is an actual implementation. I found the Matrix4f and Vector3f classes in LWJGL, and they make it possible to setup a matrix very similarly to the old OpenGL way (glTranslate() --> matrix.translate(), etc) Performance wise is it okay to use these? Seems like a bad idea to use a whole short-lived object to represent 3 floats, as it would generate a lot of garbage for the GC, but if I were to reuse my Matrix4f and Vector3f objects would I see any benefits at all from writing my own matrix stack/handler?

EDIT: Should I use doubles or floats in my matrices? I would prefer floats as there are no LWJGL classes with doubles. xD

Myomyomyo.
Offline lhkbob

JGO Knight


Medals: 32



« Reply #7 - Posted 2011-07-28 16:21:46 »

So basically I set up a matrix by translating and rotating the camera to where I want it and then invert the matrix?

Am I right in the following assumptions?
 - The model matrix is usually updated for each model, as it maps a model's coordinates to world space.
 - The view matrix is usually updated each frame (or when the camera moves), as it represents the camera's (inverse) position and rotation.
 - The projection matrix is usually only set at the start of the game, as it creates the 3D perspective. (Changing the field of view would achieve an aim-down-sights (zoom like) effect, right?)

This sounds right to me, although with shaders you might have to set the projection matrix at the start of every time you activate your shader probram (which might just be at the start of the game).

Quote
If I don't need lighting, would it be a good idea to just multiply the view matrix and the projection matrix at the beginning of each frame? Since none of them changes in the middle of a frame and I don't need the view space coordinates it should be okay, right? In my vertex shader I'll just multiply my vertex with my model matrix and my "ViewProjection" matrix.

I think this could work, although at some point you'll probably want to add in lighting and it really doesn't by you much to have 2 versus 3 matrices.

Quote
My real problem now is an actual implementation. I found the Matrix4f and Vector3f classes in LWJGL, and they make it possible to setup a matrix very similarly to the old OpenGL way (glTranslate() --> matrix.translate(), etc) Performance wise is it okay to use these? Seems like a bad idea to use a whole short-lived object to represent 3 floats, as it would generate a lot of garbage for the GC, but if I were to reuse my Matrix4f and Vector3f objects would I see any benefits at all from writing my own matrix stack/handler?

EDIT: Should I use doubles or floats in my matrices? I would prefer floats as there are no LWJGL classes with doubles. xD

I would use an existing vector math library.  You could look at grabbing the one from LWJGL, the openmali library, the javax.vecmath library, JMonkeyEngine's, or Ardor3D's.  Premature optimization is the root of all evil, so don't worry yet about lots of short lived objects, its more than likely that the JVM can take care of it.

Offline cylab

JGO Knight


Medals: 34



« Reply #8 - Posted 2011-07-28 17:13:59 »

My real problem now is an actual implementation. I found the Matrix4f and Vector3f classes in LWJGL, and they make it possible to setup a matrix very similarly to the old OpenGL way (glTranslate() --> matrix.translate(), etc) Performance wise is it okay to use these? Seems like a bad idea to use a whole short-lived object to represent 3 floats, as it would generate a lot of garbage for the GC, but if I were to reuse my Matrix4f and Vector3f objects would I see any benefits at all from writing my own matrix stack/handler?
OpenMali's vecmath implementation has support for object pooling of vectors and matrices to take care of this and rolling your own object pooling for other libs isn't difficult to do.

Also take a look at http://www.sjbaker.org/steve/omniv/matrices_can_be_your_friends.html, which is a nice roundup, what the cells in a matrix do represent.

Mathias - I Know What [you] Did Last Summer!
Offline theagentd
« Reply #9 - Posted 2011-07-28 17:31:02 »

I'll go with LWJGL's math library for now, it seems to have what I need. Concerning garbage collection: I did some frustum culling with some library before, and it was slow as hell because of it generating loads and loads of Vertex3s when calculating the clip planes. -.- Just don't wanna end up there again.
Thanks for the help guys! I think I can continue on my game now! =D

Myomyomyo.
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

xsi3rr4x (38 views)
2014-04-15 18:08:23

BurntPizza (34 views)
2014-04-15 03:46:01

UprightPath (50 views)
2014-04-14 17:39:50

UprightPath (32 views)
2014-04-14 17:35:47

Porlus (49 views)
2014-04-14 15:48:38

tom_mai78101 (71 views)
2014-04-10 04:04:31

BurntPizza (130 views)
2014-04-08 23:06:04

tom_mai78101 (230 views)
2014-04-05 13:34:39

trollwarrior1 (193 views)
2014-04-04 12:06:45

CJLetsGame (200 views)
2014-04-01 02:16:10
List of Learning Resources
by SHC
2014-04-18 03:17:39

List of Learning Resources
by Longarmx
2014-04-08 03:14:44

Good Examples
by matheus23
2014-04-05 13:51:37

Good Examples
by Grunnt
2014-04-03 15:48:46

Good Examples
by Grunnt
2014-04-03 15:48:37

Good Examples
by matheus23
2014-04-01 18:40:51

Good Examples
by matheus23
2014-04-01 18:40:34

Anonymous/Local/Inner class gotchas
by Roquen
2014-03-11 15:22:30
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!