• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.

Pateman

Members
  • Content count

    13
  • Joined

  • Last visited

Community Reputation

184 Neutral

About Pateman

  • Rank
    Member

Personal Information

  1. 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. 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. 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. Anyone have any ideas? I can provide all the details you need just in case my original description is not detailed enough. :)
  5. 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

    [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?