PDA

View Full Version : Matrix issue:Multiple glRotate glTranslate on single object



Leroy1981
01-14-2017, 09:03 AM
Hi I'm not really new to opengl but I'm having a serious issue orienting an object using the built in opengl matrix. It's a gun that needs to be locked to the hand of an enemy. The enemy keeps track of a grip position which is where his hand is at that particular frame. The gun also has a position set in it for grip position in the handle and that tells how the gun orients relative to the enemy hand grip position. Also there's rotation involved. The enemy has a set rotation based on current direction he's facing obviously. And the gun must also be rotated to face this same direction. So I'm using multiple calls to glRotate & glTranslate to rotate the gun around its grip point and then position it relative to the enemy's current position. Everything pans out fine until I add the last glTranslate that accounts for the enemy's world position. My algorithm is as follows

Vectors3f PlayerPos; Enemy's world position
Vectors3f PlayerDir; Enemy's facing direction(Only Y is used)

Vectors3f

Vectors3f PlayerGrip; Position of grip point in enemy hand when is at PlayerDir=0
Vectors3f GunGrip; Position in gun that should lock to PlayerGrip(in the handle)

1. Translate gun so it is centered around origin relative to it's grip point and rotate to same direction as enemy
glRotatef(PlayerDir.Y,0.0,1.0,0.0);
glTranslatef(-GunGrip.X,-GunGrip.Y,-GunGrip.Z);


2. Translate out to the position player's hand would be at PlayerDir.Y=0 and rotate around the origin at 0.0,PlayerDir.Y,0.0
glRotatef(PlayerDir.Y,0.0,1.0,0.0);
glTranslatef(PlayerGrip.X,PlayerGrip.Y,PlayerGrip. Z);


3. Translate out to final player world position
glTranslatef(PlayerPos.X,PlayerPos.Y,PlayerPos.Z);


Executing only step 1 works fine. The gun is moved to the origin and it rotates perfect and spins on its grip point. Things start messing up around step 2. I have tried rotating first then translating, and vice versa, but it doesn't work. Only doing steps 1+2 should have the gun suspended in the position of the player's hand at PlayerDir.Y=0 and spinning around in place around it's handle but it spins relative to the origin instead. Any input or tips for handling multiple glRotate/glTranslate calls on the same object are much appreciated

BBeck1
01-14-2017, 09:56 AM
Is this 2D or 3D? Because my approach to the problem would be entirely different based on that. I'm not understanding the algorithm well enough to decide whether it's 2D or not, although it obviously has Z values. I don't see where the Z is ever anything other than 0 in the example.

If it's 2D, I would avoid matrices as much as possible. They're a little overkill for 2D. Instead I would use the rotation formula I discuss in the "Direction" section of my Vector video (https://www.youtube.com/watch?v=56v9BgwSzsg) starting just short of 39 minutes in.

If it's 3D, I would take the opposite approach and not use vectors. Instead, I would maintain these values in matrices. For example, if I had an enemy that I wanted to hold a gun and point it at the player, I would have a matrix that holds the player's position, a matrix that holds the enemy's position, and a matrix that holds the gun's position. All these matrices would store orientation(direction) as well.

So, to get the enemy to point the gun at the player, I would decompose the player's matrix to get the position value out of it. Then I might use a LookAt() function to orient the enemy to face the player. I would probably need to decompose the enemy's matrix to get it's position for that as well.

I could have the gun matrix just be an offset from the enemy's matrix depending on the game. For that, the gun matrix would hold an offset of position and rotation from the enemy's matrix. You would multiply the two together and use that instead of the gun's matrix to position and orient it.

If the enemy were a skinned model, you would have a whole series of matrices (or possibly quaternions that could be turned into a matrix or you could use quaternions for this whole thing). The hand would probably have it's own matrix and the gun matrix could be relative to the hand matrix. This would place the gun in the enemy's hand whether it was pointed down at the ground or at the player.

The order of multiplication determines whether the rotation is a rotation around the object's center or an orbit around the origin. Before you start linking these matrices together the origin is the world origin. But in this sort of parent child relationship, the origin becomes the position and orientation of the parent. So, it's a question of whether you orbit the parent or rotate on object's axis. It's as simple as reversing the order of multiplication (A*B vs. B*A) to change it. However, GLM seems to try and do this math for you, which I feel over complicates things and obfuscates how the "magic" is done from someone trying to learn it. That's why you see me in my code rotating around an identity matrix:

glm::rotate(glm::mat4(), glm::radians<float>(1), glm::vec3(0.0f, 1.0f, 0.0f));

That gives me a rotation matrix that I can then use to multiply either way.

When you can't control the order of multiplication, you can always translate the object to the origin, do the rotation, then translate it back. Translating to the origin is as simple as negating the object's position and keeping track of that vector so you can then add it back to put it back where it was. Doing the rotation at the origin will avoid the orbiting.

GClements
01-14-2017, 09:13 PM
Everything pans out fine until I add the last glTranslate that accounts for the enemy's world position.
The enemy's transformation to world space should be the first transformation applied. Transformations are applied in order from the top of the hierarchy to the bottom, parent to child.

Leroy1981
01-15-2017, 06:49 AM
Actually I was incorrect when I said it works fine up until applying the world rotation. If I only apply the translation of step 2 it works fine but using both rotation/translation of step 2 is where the results start to go wrong. I think the way to solve the problem would be to put step 2's rot/tran in a separate matrix and apply it to the current matrix all in one shot instead of rotating and translating in separate calls to opengl. I'll test this out and see if I can get some results