# Pateman

Member

13

184 Neutral

• Rank
Member

• Website
• Interests
|programmer|
1. ## Map rigid body's transform to bone

Hi Dirk,   Thanks for your reply. You are absolutely right, but the problem was elsewhere and I managed to finally figure it out. :)   The first mistake was in the initialization part. It is indeed correct to use the world bind matrix of the bone with scaling applied. Scaling was breaking transformation matrices passed to Bullet, so I assumed that I should get rid of it as well when computing the initial transforms of bones. Second thing was the incorrect usage of getNormalizedRotation(), but that's specific to the math library that I'm using (JOML - https://github.com/JOML-CI/JOML). The third problem was getting the rotation from the bone's world bind matrix after it was multiplied by the inverse transformation matrix of the rigid body. It turned out that it's only needed for the translation part. Here's the modified code:   private void initializeBone(final Bone bone, final Matrix4f invRigidBodyTransform) {     final TempVars vars = TempVars.get();     final TransformComponents transformComponents = new TransformComponents();     //  Get the bone's world bind matrix.     vars.tempMat4x41.set(bone.getWorldBindMatrix());     //  Set the unnormalized rotation taken from the world bind matrix as the initial rotation of the bone.     vars.tempMat4x41.getUnnormalizedRotation(transformComponents.getRotation());     //  Get the scale from the world bind matrix as well.     vars.tempMat4x41.getScale(transformComponents.getScale());     //  In order to get the translation of the bone, we need to convert the world bind matrix into the     //  rigid body's sppace and get the translation then.     invRigidBodyTransform.mul(vars.tempMat4x41, vars.tempMat4x41);     vars.tempMat4x41.getTranslation(transformComponents.getTranslation());     this.initialBoneTransforms.put(bone.getIndex(), transformComponents);     vars.release(); } The update part was flawed as well. Here's the modified code with comments:   void getTransformedBone(final Bone bone, final Vector3f outPos, final Quaternionf outRot,                         final Vector3f outScale) {     final TempVars vars = TempVars.get();     final TransformComponents initialTrans = this.initialBoneTransforms.get(bone.getIndex());     //  Start by getting the current rigid body's transformation matrix.     Utils.transformToMatrix(vars.tempMat4x41, this.rigidBody.getCenterOfMassTransform(vars.vecmathTransform));     //  Transform the initial bone's position by the current rigid body's transformation matrix.     vars.tempMat4x41.transformPosition(initialTrans.getTranslation(), outPos);     //  In order to get the transformed rotation, we need to calculate the difference between the     //  ** rigid body's ** initial rotation and its current rotation, and then multiply it by the ** bone's **     //  initial rotation.     vars.tempMat4x41.getUnnormalizedRotation(vars.quat1);     final Quaternionf diff = this.initialRotation.invert(vars.quat2).mul(vars.quat1, vars.quat3);     diff.mul(initialTrans.getRotation(), outRot);     //  Scale doesn't change.     outScale.set(initialTrans.getScale());     vars.release(); } Finally, during the update, the inverse transformation matrix of the entity needs to be multiplied by the bone matrix to orient it correctly.    EDIT Oh, and of course, don't forget to multiply the matrix by the inverse bind pose, but you should already have that ;)   And that's pretty much it :) Hope it helps someone.
2. ## Map rigid body's transform to bone

For anyone wondering what I mean by "the mesh is broken", I attached a preview of what's going on:     It looks like there's some weird offset applied, but I can't figure out why.
3. ## Map rigid body's transform to bone

I use AABBs only to construct the rigid bodies. They're not involved in the calculations later on. :) I've got the animation working fine. Like I stated, the problem is that the bones seem to be oriented fine (as you can see in the last picture), so the bone matrices are okay. The problem is that when I apply them to the skin, the mesh is broken. My understanding is that Bullet returns the rigid bodies' transformation in world space and I use it to orient the bones accordingly. The issue is with the skin. I've tried to multiply the resulting matrices by the corresponding inverse bind matrices, but it hasn't helped. I'm not sure where the problem is. Probably my reasoning is wrong somewhere, but I can't pinpoint my mistake. If you guys need more information, I can give you more insights.
4. ## Map rigid body's transform to bone

Anyone have any ideas? I can provide all the details you need just in case my original description is not detailed enough. :)
5. ## Map rigid body's transform to bone

I was able to figure it out. The process is divided in two parts - the initialization phase and update phase.   During initialization (for every rigid body):   a) Calculate its inverse transform matrix Utils.transformToMatrix(vars.tempMat4x42, this.rigidBody.getCenterOfMassTransform(vars.vecmathTransform)); vars.tempMat4x42.invert(); b) For each bone assigned to the body, transform the bone's world bind position by the inverse transform matrix and save it for later. Also, save the bone's world bind rotation, and the inverse of rigid body's initial rotation quaternion. private void initializeBone(final Bone bone, final Matrix4f invRigidBodyTransform) {     final TempVars vars = TempVars.get();     final TransformComponents transformComponents = new TransformComponents();     RagdollUtils.getMatrixForBone(vars.tempMat4x41, bone); // <-- this returns the bone's world bind matrix without scaling applied     final Vector3f boneTranslation = vars.tempMat4x41.getTranslation(vars.vect3d1);     invRigidBodyTransform.transformPosition(boneTranslation, transformComponents.getTranslation());     vars.tempMat4x41.getNormalizedRotation(transformComponents.getRotation());     this.initialBoneTransforms.put(bone.getIndex(), transformComponents);     vars.release(); }   During update (for every rigid body): a) Get the current rigid body's transform matrix, transform the initial position by it. b) Multiply the inverse of the rigid body's initial rotation by the current rotation. c) Multiply the initial bone's rotation by the result of the previous operation. d) Multiply the resulting transformation matrix by the inverse transformation matrix of the model (the owner of the skeleton) // This method performs stuff described in the points a-c. void getTransformedBone(final Bone bone, final Vector3f outVec, final Quaternionf outQuat) {     final TempVars vars = TempVars.get();     final TransformComponents initialTrans = this.initialBoneTransforms.get(bone.getIndex());     Utils.transformToMatrix(vars.tempMat4x41, this.rigidBody.getCenterOfMassTransform(vars.vecmathTransform));     Utils.convert(vars.quat1, vars.vecmathTransform.getRotation(vars.vecmathQuat));     vars.tempMat4x41.transformPosition(initialTrans.getTranslation(), outVec);     final Quaternionf rot = this.initialRotation.invert(vars.quat2).mul(vars.quat1, vars.quat1);     initialTrans.getRotation().mul(rot, outQuat);     vars.release(); } The above works well, as you can see here:   However, when I apply the matrices computed like that to the skin, it gets messed up. Any idea what might be causing the problem? I'm guessing that the matrices are in world space, maybe that's what causing the problem?    Thanks for any suggestions, Patryk
6. ## Map rigid body's transform to bone

Hello everyone,   I have the following ragdoll structure (green dots - bones, pinkish lines - bone links):   The black boxes are Bullet's rigid bodies (boxes) constructed by creating an AABB of all mesh vertices that are influenced by the bones in a particular, let's say, body part. So for example, if you look at the chest area, there are five bones that make up that body part - I take the vertices, calculate their AABB and construct a rigid body. (In the picture, the head is a circle, but in my code, it's actually a box, too :))   These rigid bodies are linked to each other using six-DOF constraints. The ragdoll itself is working fine, but now, when I run the simulation, I want to somehow map a rigid body's transformation to the corresponding bones to animate the mesh. To continue with the example of the chest area - whenever it is moved by Bullet, I want to apply its center of mass transform to all the bones that are within the chest area.   I was thinking of using a bone's world bind matrix and transforming it like so: destMatrix = bodyCenterOfMassTransform * boneWorldBindMatrix but it didn't quite cut the mustard.   Do you have any other ideas?   Thanks, Patryk I copied the question from StackExchange in hope of reaching a broader audience
7. ## OpenGL GLSL Skinning problem

[quote name='C0lumbo' timestamp='1358784975' post='5023946'] when you create a 'Pad the remaining number of weights with zero' are you also setting the bone ID to something valid? [/quote] Yes, I set it to zero, then in the shader I verify whether the bone ID is set to 0, like so:     mat4 getBoneMatrix(int boneIndex) {    mat4 retMat = mat4(1.0);    if (boneIDs[boneIndex] != 0) {       retMat = boneMatrices[boneIDs[boneIndex]];    }    return retMat;    } float getWeight(int boneIndex) {    float res = 1.0;    if (boneIDs[boneIndex] != 0) {       res = boneWeights[boneIndex];    }    return res; }

9. ## OpenGL [OpenGL 3.x] Camera Matrix Problem

Unfortunately, there's another problem. I noticed the code I posted doesn't take the direction vector into consideration. It's better explained in the video here: http://www.youtube.com/watch?v=lOL8sqR5fQ0 It seems like the transformation matrix doesn't rotate the axes of an object, so it still moves at the same direction, even though it was rotated. Here's how I wanted to fix that bug: function TBrainObject.GetMatrix: TBrainMatrix; var M: TBrainMatrix; V: TBrainVector; begin if UpdateNeeded then begin M := Mat4CreateRotationEuler(FRotation); V := Mat4ApplyToVector(M, Vec3(0.0, 0.0, -1.0)); V := Vec3Normalize(V); CachedMatrix := Mat4Scale(Mat4Translate(M, Vec3Negate(Vec3Add(FPosition, V))), FScale); UpdateNeeded := False; end; Result := CachedMatrix; end; But it doesn't seem to help too much. Can you tell me what's wrong with the code? Or at least suggest some changes?
10. ## OpenGL [OpenGL 3.x] Camera Matrix Problem

Finally, after weeks of struggling, the code works! :D And here is a step-by-step guide: 1. First of all, I disposed of all my matrix code and rewrote it. Here are the functions you will need to compile the code: http://www.nopaste.pl/Source/mhc.txt 2. Use the following shaders: http://www.nopaste.pl/Source/mhd.txt 3. Your rendering code should look like this: procedure TMainForm.RenderWorld; var Model, View, Proj, MVP: TBrainMatrix; begin // Clear the frame buffer glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); // Compute the model-view-projection matrix Proj := Mat4CreatePerspective(60.0, ClientWidth / ClientHeight, 0.1, 1000.0); Model := Mat4Translate(Mat4CreateRotationEuler(ModelRotation), Vec3Negate(ModelPosition)); View := Mat4Translate(Mat4CreateRotationEuler(CameraRotation), Vec3Negate(CameraPosition)); View := Mat4Inverse(View); MVP := Mat4Multiply(Model, Mat4Multiply(View, Proj)); // Update the shader glUniformMatrix4fv(ShaderManager.ActiveProgram.GetUniformLocation('mvpmatrix'), 1, False, @MVP); // Rendering code here... end; Hope this helps. :)
11. ## OpenGL [OpenGL 3.x] Camera Matrix Problem

Quote: I can't remember off the top of my head if GLSL expects matrix basis vector elements to be contiguous in memory, so if you're not sure yourself you might double check and make sure you're not missing a transpose somewhere. I tried inverting the camera matrix, transposing it, and both together, and it still doesn't work. Quote: Also, as I mentioned previously it looks like you may be constructing your view matrix incorrectly, so you might take another look at that as well. The code was used before in a different project and it worked. The same thing is with sending the matrices to GLSL - I carefully followed the examples on the official OpenGL's website. Still, the code doesn't work. Can you please suggest anything else?
12. ## OpenGL [OpenGL 3.x] Camera Matrix Problem

Oh right, I should've posted the math code, too. Here's the definition of my vector and matrix type: { .: TVector :. } PVector = ^TVector; TVector = packed record case Integer of 0: (X: Single; Y: Single; Z: Single; ); 1: (V: array [0 .. 2] of Single); end; { .: TMatrix :. } PMatrix = ^TMatrix; TMatrix = packed record case Integer of 0: (_11, _12, _13, _14: Single; _21, _22, _23, _24: Single; _31, _32, _33, _34: Single; _41, _42, _43, _44: Single); 1: (M: array [0 .. 3, 0 .. 3] of Single); 2: (V: array [0 .. 15] of Single); end; As you can see, both records are unions. The MatrixTransform function code is as follows: { .: MatrixTransform :. } function MatrixTransform(const Position, Rotation, Scale: TVector): TMatrix; var CosRx, CosRy, CosRz: Single; SinRx, SinRy, SinRz: Single; begin CosRx := Cos(Rotation.X); // Used 6x CosRy := Cos(Rotation.Y); // Used 4x CosRz := Cos(Rotation.Z); // Used 4x SinRx := Sin(Rotation.X); // Used 5x SinRy := Sin(Rotation.Y); // Used 5x SinRz := Sin(Rotation.Z); // Used 5x Result := MatrixIdentity; with Result do begin _11 := CosRy * CosRz * Scale.X; _12 := CosRy * SinRz * Scale.X; _13 := -SinRy * Scale.X; _21 := (CosRz * SinRx * SinRy * Scale.Y) - (CosRx * SinRz * Scale.Y); _22 := (CosRx * CosRz * Scale.Y) + (SinRx * SinRy * SinRz * Scale.Y); _23 := CosRy * SinRx * Scale.Y; _31 := (CosRx * CosRz * SinRy * Scale.Z) + (SinRx * SinRz * Scale.Z); _32 := (-CosRz * SinRx * Scale.Z) + (CosRx * SinRy * SinRz * Scale.Z); _33 := CosRx * CosRy * Scale.Z; _41 := Position.X; _42 := Position.Y; _43 := Position.Z; end; end;
13. ## OpenGL [OpenGL 3.x] Camera Matrix Problem

Hello to all members of Gamedev.net! :D My name is Patryk and I'm new here. I started programming in OGL 3.x and encountered a problem with the camera matrix. Here's the code I'm using to calculate the matrix (in Delphi): { .: TMainForm.Render :. } procedure TMainForm.Render; var ProjMat, Cam, ModelView: TMatrix; begin glViewport(0, 0, ClientWidth, ClientHeight); glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); // Projection update if (ClientHeight <= 0) then ClientHeight := 1; ProjMat := MatrixProjection(40.0, ClientWidth / ClientHeight, 0.1, 1000.0); // Camera transformations Cam := MatrixTransform(VectorNegate(Camera.Pos), VectorCreate(Camera.Pitch, Camera.Yaw, 0.0), VectorUniform(1.0)); ModelView := MatrixTransform(VectorCreate(0.0, 0.0, 0.0), VectorCreate(0.0, TriangleRot, 0.0), VectorUniform(0.5)); ModelView := MatrixMultiply(ModelView, Cam); ModelView := MatrixMultiply(ModelView, ProjMat); // Update the shader glUniformMatrix4fv(glGetUniformLocation(ShaderManager.GLSLPrograms['minimal']. ProgramHandle, 'mvpmatrix'), 1, ByteBool(GL_FALSE), @ModelView); // Render the triangle glBindVertexArray(TriangleVAO); glDrawArrays(GL_TRIANGLES, 0, 3); glBindVertexArray(0); end; And here's the code of my vertex shader: #version 150 precision highp float; uniform mat4 mvpmatrix; in vec3 in_Position; in vec3 in_Color; out vec3 ex_Color; void main(void) { gl_Position = mvpmatrix * vec4(in_Position, 1.0); ex_Color = in_Color; } The thing is that whenever I change either the Camera.Pitch or Camera.Yaw values, the object rotates instead of the camera. How do I change the code so that I have a Quake-like FPS camera?