PDA

View Full Version : Attaching gun model to camera



eratic-magician
02-22-2017, 02:54 PM
I've been working a game with OpenGL, and want a gun model that I have to move with the camera's position and rotation (like a gun in a FPS game). I have this so far, which keeps the gun in view as the player moves but doesn't move along with rotation:


ModelMatrix4 = glm::translate(ModelMatrix4, glm::vec3(getPosition().x+0.25, getPosition().y-0.65, getPosition().z-1));
ModelMatrix4 = glm::scale(ModelMatrix4, glm::vec3(0.1f, 0.15f, 0.15f));
ModelMatrix4 = glm::rotate(ModelMatrix4, 1.5708f, glm::vec3(0.0f, 1.0f, 0.0f));

glm::mat4 MVP4 = ProjectionMatrix * ViewMatrix * ModelMatrix4;

Leaving out the '* ViewMatrix' on the last line keeps the gun in view as I rotate the camera, but the gun model doesn't appear at the right position and as the player moves, it moves away from them.

Essentially, with the multiplication of the ViewMatrix in the MVP equation, the movement is as expected, and without it, the rotation is as expected. So what exactly can I do to have the best of both? Thanks in advance.

Dark Photon
02-23-2017, 06:04 AM
If you push on, you can probably get it to work. However, what you're doing here seems fragile and will break easily as it hard-codes geometry information about your models in code. It seems like it would be more robust to query that information from the models.

I'd encourage you to forget about rotates/translates/scales for a minute and just take a look at what you're trying to do. You want a Modeling transform for the gun which is:


ModelMatrix4 = GUN-SPACE-to-WORLD-space
= (GUN-SPACE-to-HAND-SPACE) * (HAND-SPACE-to-CHARACTER-SPACE) * (CHARACTER-SPACE-to-WORLD-SPACE)
= GUN-to-HAND * HAND-to-CHARACTER * CHARACTER-to-WORLD


Build those three coordinate frame transforms, multiply them together, and you're done.

If you're using skinning to render your character, the HAND-to-CHARACTER transform is just the joint global transform (G) for the hand joint for that frame (i.e. the product of your joint orientation and animation transforms all the way up the joint skeleton: OA*AA*OB*AB*OC*AC * ... ). GUN-to-HAND may very well be the identity transform if you gun is modeled such that its origin should be right where the hand joint is. And CHARACTER-to-WORLD, you already know, as you're rendering your character in the scene already.

If you're not using skinning, how do you build HAND-to-CHARACTER? Compute right/up/back vectors for the hand joint in character space, as well as an offset of the hand joint from the character space origin. Those two things give you the rotate+translate matrix which is HAND-to-CHARACTER. Ideally you should be able to query the position and orientation of the hand directly from your loaded model. For instance, by dropping a transform node right where the hand is.

eratic-magician
02-23-2017, 02:31 PM
Thanks for the reply, I'm not 100% sure about what you mean though. I've been learning OpenGL through a tutorial online and all I know about handling model matrices comes from that. I can see what you mean about it not being the best approach, but I'll have to look into joints and skinning as I was quite lost reading that :/

While I do that though, do you have any ideas for making it work the way I'm doing it now? If possible, I'd rather get it working as it is now and then make improvements later on.

Cheers anyway.

BBeck1
02-23-2017, 09:25 PM
Try

glm::mat4 MVP4 = ProjectionMatrix * ViewMatrix * (glm::inverse(ViewMatrix) * ModelMatrix4);


or is it:
glm::mat4 MVP4 = ProjectionMatrix * ViewMatrix * (ModelMatrix4 * glm::inverse(ViewMatrix));

I never can remember the order of multiplication. Normally you would want the MVP matrix to be projection, view, and model. However, you want the model to be a child of the camera. There's a few ways to do this. But this should work. You need the inverse of the view to turn the view matrix into a model matrix of the camera. (Invert it again if you need to turn it back into an actual camera matrix.) When you multiply two model matrices, and use the result instead of the model's matrix, you effectively form a parent/child relationship between them, linking them together. Then your model matrix becomes an offset from the camera. So, the world origin for that object becomes the parent. Position it relative to the parent.

I haven't tried this exactly, but it should work. You may have to play with the multiplication order and such a bit. I'm sure I could get it to work on the computer, but that's off the top of my head.

Oh. And I might mention that this is kind of a FPS "Doom" solution where there is no hand or player model, just the gun and the camera. You can take this whole concept and make it a bit more complicated by having a hand model with bones and using one of the bone matrices as a parent for the gun and the whole hand model a child of the camera. Or you could have a matrix that is the parent of the camera and the arm and then the gun is a child of the hand that is a child of the arm bone, etc. All sorts of things you could do here in theory. But I would just do the camera and the gun until you kind of understand the concept.

Skinned animation is tough to understand. It's based on the concepts of rigid animation. You'll want to learn rigid animation to start with, which is what I'm talking about here.

Dark Photon
02-24-2017, 07:00 AM
Thanks for the reply, I'm not 100% sure about what you mean though. I've been learning OpenGL through a tutorial online and all I know about handling model matrices comes from that. I can see what you mean about it not being the best approach, but I'll have to look into joints and skinning as I was quite lost reading that :/

Just ignore that part then. I didn't know anything about the player character you were trying to affix the gun to, so I mentioned it just in case you were using skinning.

Instead pay attention to the "If you're not using skinning, ..." part.

(You don't care right now, but skeletal animation / skinning allows you to use one player model, and then smoothly animate the vertices of the player model to simulate things like your player character walking, running, jumping, etc. Relevant to your "place the gun model" problem, with skeletal animation, the modeling transform for the hand joint in character space changes smoothly every frame. In your case though it sounds like your player model is "fixed" in its modeled pose -- that is, in player character space, the hand is always in the same relative position and orientation.)


While I do that though, do you have any ideas for making it work the way I'm doing it now?

It completely depends on how your player character model and gun model were constructed.

I have no ideal why you've got a non-uniform scale in the modeling matrix for the gun. However, conceptually you just need to build a matrix that takes the gun in its own modeled coordinate frame and positions that in the player's coordinate frame. Once you know the position (translation) and orientation (rotation) of the player's hand w.r.t. the player model's coordinate frame, you're basically done.

Dark Photon
02-24-2017, 07:09 AM
I never can remember the order of multiplication.

Sorry, didn't mean to confuse things by writing transforms in the English-intuitive left-to-right order ( v2 = v1 * M * V * P ).

Of course, in GLSL (and GLM) you'd typically write this v2 = P * V * M * v1

From a math perspective, these are equivalent. Just rows and columns are swapped. On the C++ side, either is valid, and it just depends on how your math library is written.

eratic-magician
02-25-2017, 02:12 PM
Thanks for the help guys, I ended up solving the issue by just removing the viewMatrix from the MVP multiplication, and removing my getPosition()s. You both helped me see that though, and have definitely inspired me to check out skinning, joints and so on. Cheers.

GClements
02-25-2017, 05:58 PM
Sorry, didn't mean to confuse things by writing transforms in the English-intuitive left-to-right order ( v2 = v1 * M * V * P ).

Of course, in GLSL (and GLM) you'd typically write this v2 = P * V * M * v1

From a math perspective, these are equivalent. Just rows and columns are swapped.

From a math perspective, (P * V * M * v1)T=v1T * MT * VT * PT, where the superscript T indicates transposition.

In GLSL, a matrix-by-vector multiplication treats the vector as a column vector if it's on the right-hand side of the multiplication and as a row vector if it's on the left-hand side. Note that matrices won't automatically be transposed, so v*M is equivalent.to transpose(M)*v, not to M*v.