Pateman

Member
  • Content count

    13
  • Joined

  • Last visited

Community Reputation

184 Neutral

About Pateman

  • Rank
    Member

Personal Information

  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. 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; }
  8. Hello community,   Ok, first of all, I'm using OpenGL 3, 3ds max, and Delphi to create a skeletal animation demo. I'm using the IGame interface to export meshes from 3ds max to XML - I use the sample included in the SDK.   Now, I'm going to describe as precisely as I can what I do.   Passing bone weights to the shader I'll skip parsing geometry, because it works okay. Now, if a mesh is skinned (using the Physique modifier), the resulting XML contains information about bone influences for each vertex, like so:     <Skin VertexID="2" Type="Rigid">     <Bone BoneID="22" Weight="1,000000"></Bone>     </Skin>     ...     <Skin VertexID="14" Type="Blended">     <Bone BoneID="22" Weight="0,986472"></Bone>     <Bone BoneID="14" Weight="0,013015"></Bone>     <Bone BoneID="23" Weight="0,000513"></Bone>     </Skin>     ...     <Skin VertexID="31" Type="Blended">     <Bone BoneID="22" Weight="0,948354"></Bone>     <Bone BoneID="23" Weight="0,030462"></Bone>     <Bone BoneID="23" Weight="0,011265"></Bone>     <Bone BoneID="14" Weight="0,009909"></Bone>     <Bone BoneID="23" Weight="0,000011"></Bone>     </Skin> My shader assumes that there should be always 4 bones, which influence a single vertex, and as you can see, sometimes there is sulprus/insufficient number of them, so I decided to: Sum up weights of the same bone - take a look at vertex 31 - there are five entries, but after summing them up, we're left with three. Pad the remaining number of weights with zero. Right now, I have a list of bone IDs/vertex weight pairs, which I pass to the shader like so:     const     MAX_BONES_PER_VERTEX = 4;     type     TVertexWeight = record     BoneID: Integer;     Weight: Single; // standard float     end;     ...     var       L: TList<TVertexWeight>;     ...     glGenBuffers(1, @FBonesVBO);     glBindBuffer(GL_ARRAY_BUFFER, FBonesVBO);     glBufferData(GL_ARRAY_BUFFER, L.ListSize, L.ListPointer, GL_STATIC_DRAW);          glEnableVertexAttribArray(FBoneIDsAttr);     glVertexAttribIPointer(FBoneIDsAttr, MAX_BONES_PER_VERTEX, GL_INT,     SizeOf(TVertexWeight), PInteger(0));          glEnableVertexAttribArray(FWeightsAttr);     glVertexAttribPointer(FWeightsAttr, MAX_BONES_PER_VERTEX, GL_FLOAT,     False, SizeOf(TVertexWeight), PInteger(4)); I think this part is working fine, because when I hardcode an identity matrix in the shader, the model is rendered in its bind pose.   Computing bone matrices For now, I just want to display the model in a pose which it would be in, let's say, frame 49:   Here's the code I use: procedure CalculateBones(const SequenceName: String; const FrameID: Integer; const ABone: TAnimatedMeshBone; const ParentTransform: TBrainMatrix); var    Samples: TBrainList<TAnimatedMeshAnimationSample>;    BoneSample: TAnimatedMeshAnimationSample;    I: Integer;    BoneTransform, GlobalTransform: TBrainMatrix;    Children: TBonesList; begin    Samples := TBrainList<TAnimatedMeshAnimationSample>.Create();    Children := TBonesList.Create();    try       FAnims[SequenceName].SamplesByFrame(FrameID, Samples);       BoneSample := nil;       for I := 0 to Samples.Count -1 do          if (Samples[I].Bone.ID = ABone.ID) then          begin             BoneSample := Samples[I];             break;          end;       BoneTransform := ABone.OffsetMatrix;       if (BoneSample <> nil) then          BoneTransform := BoneSample.Matrix;              GlobalTransform := Mat4Multiply(ParentTransform, BoneTransform);       BoneMatrices.Add(GlobalTransform);       FBones.BonesByParentID(ABone.ID, Children);       for I := 0 to Children.Count -1 do          CalculateBones(SequenceName, FrameID, Children[I], GlobalTransform);    finally       Samples.Free();       Children.Free();    end; end; ... BoneMatrices := TBrainList<TBrainMatrix>.Create(); try    // A bone's offset matrix is the bind pose.    CalculateBones('zhuxian2', 49, FBones.RootBone, FBones.RootBone.OffsetMatrix);    glUniformMatrix4fv(FShader.GetUniformLocation('boneMatrices'),       BoneMatrices.Count, False, BoneMatrices.ListPointer); finally    BoneMatrices.Free(); end; A bone's OffsetMatrix is basically the bind pose (regarding to what the exporter says, it's in object space) of the bone. Now, a TAnimatedMeshAnimationSample contains position and rotation (in quaternion) of a bone in the given frame. The loop at the top of CalculateBones() basically checks if in the given frame (in this case, 49th) there's transformation data for the given bone.   After launching the code above, all I get is this: (please ignore the lack of textures for now)   But when I change the initial parent transform from FBones.RootBone.OffsetMatrix to Mat4Identity() (basically use an identity matrix), the model is displayed in its bind pose:   Vertex shader code   #version 150 #define MAX_BONES_PER_VERTEX 4 #define MAX_BONES 32 uniform mat4 proj; uniform mat4 modelview; uniform mat4 boneMatrices[MAX_BONES]; in vec3 vertex; in vec3 normal; in vec2 texCoord; in ivec4 boneIDs; in vec4 boneWeights; out vec4 fragmentColor; float phong_weightCalc(in vec3 light_pos, in vec3 frag_normal) {    return max(0.0, dot(frag_normal, light_pos)); } 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; } void main() {    vec3 EC_Light_location = vec3(0.0, 1.0, 1.0);        float diffuse_weight = phong_weightCalc(       normalize(EC_Light_location),       normalize(normal)    );        fragmentColor = clamp(       (          (vec4(0.2, 0.2, 0.2, 1.0))          + (vec4(0.8, 0.8, 0.8, 1.0) * diffuse_weight)       ),        0.0, 1.0);              float totalWeight = 0.0;    vec4 PosL = vec4(0.0, 0.0, 0.0, 1.0);    for (int i = 0; i < MAX_BONES_PER_VERTEX; i++) {       float w = getWeight(i);       PosL += w * (vec4(vertex, 1.0) * getBoneMatrix(i));       totalWeight += w;    }    PosL /= totalWeight;    PosL.w = 1.0;    gl_Position = proj * modelview * PosL; }   The question is, can someone point out what is wrong with the code?   Thank you very much.   PS. If you need any more information, please let me know.  
  9. 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. 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. 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. 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. 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?