# Irlan Robson

Member

612

4073 Excellent

• Rank

• Role
Programmer
• Interests
Programming

## Recent Profile Visitors

20937 profile views

1. ## 3D Rigidbody Simulation

I'm happy to help. It is always recommended to use a very minimalist simulation configuration to test things out. ;)
2. ## 3D Rigidbody Simulation

Your test with a couple of changes in the initialization works completely fine in my framework. The ball spins around the body x-axis. Here are the changes. Increase the sphere mass and radius Set the position to (0, 10, 0) Set the linear velocity to (0, 0, 0) Set the angular momentum to (10, 0, 0) I use the standard multiplication convention (as OpenGL). You would swap around the order in DirectXMath. Here's the source code: class IsuDiss : public Test { public: IsuDiss() { m_mass = 1.0f; m_radius = 2.0f; float32 s = 0.4f * m_mass * m_radius * m_radius; b3Mat33 I = b3Diagonal(s); m_invI = b3Inverse(I); m_f.SetZero(); m_torque.SetZero(); m_x.Set(0.0f, 10.0f, 0.0f); m_v.SetZero(); m_q.Set(b3Vec3_z, 0.5f * B3_PI); m_L.Set(10.0f, 0.0f, 0.0f); m_xf.rotation = b3QuatMat33(m_q); m_xf.position = m_x; m_worldInvI = m_xf.rotation * m_invI * b3Transpose(m_xf.rotation); m_omega = m_worldInvI * m_L; } ~IsuDiss() { } void Step() override { float32 h = g_testSettings->inv_hertz; m_x += h * m_v; m_v += h * (m_f / m_mass); b3Quat w(m_omega.x, m_omega.y, m_omega.z, 0.0f); m_q += h * 0.5f * w * m_q; m_q.Normalize(); m_L += h * m_torque; m_xf.position = m_x; m_xf.rotation = b3QuatMat33(m_q); m_worldInvI = m_xf.rotation * m_invI * b3Transpose(m_xf.rotation); m_omega = m_worldInvI * m_L; b3SphereShape s; s.m_center.SetZero(); s.m_radius = m_radius; g_draw->DrawSolidSphere(&s, b3Color_pink, m_xf); } static Test* Create() { return new IsuDiss(); } float32 m_radius; float32 m_mass; b3Mat33 m_invI; b3Vec3 m_x; b3Vec3 m_v; b3Vec3 m_f; b3Quat m_q; b3Vec3 m_omega; b3Vec3 m_torque; b3Vec3 m_L; b3Mat33 m_worldInvI; b3Transform m_xf; };
3. ## 3D Rigidbody Simulation

IIRC in DirectXMath quaternion multiplication order is consistent with matrix multiplication order. Maybe you can try changing the quaternion derivative to XMVECTOR qOmega = XMQuaternionMultiply(XMVectorSet(Omega.m128_f32[0], Omega.m128_f32[1], Omega.m128_f32[2], 0), q);﻿ Also check the shaders. Possibly it's a small problem with the transforms.
4. ## 3D Rigidbody Simulation

I see no problems with your initialization. The orientation quaternion can become non-unit over time due to round-off errors. Therefore, you should normalize the quaternion just after you've integrated it and keep track of this. E.g. q += dt * 0.5 * omega * q; q = XMQuaternionNormalize(q); Note the function XMQuaternionNormalize only returns the normalized quaternion of the given quaternion. Then you can convert the quaternion to its corresponding 3-by-3 matrix using XMMatrixRotationQuaternion. R = XMMatrixRotationQuaternion(q); The quaternion-to-matrix conversion functions and vice-versa are already implemented in DirectXMath. The functions are XMMatrixRotationQuaternion and XMQuaternionRotationMatrix.
5. ## 3D Rigidbody Simulation

It seems that your quaternion derivative is q_dot = 0.5 * q * q_omega where q_omega = Quaternion(omega.x, omega.y, omega.z, 0) This is wrong if you're using a global angular velocity. The time derivative of an orientation given the angular velocity of the rotation frame represented by the orientation is q_dot = 0.5 * q_omega * q Then to integrate the current orientation q over a time step dt you use the formula q = q + dt * q_dot For a local angular velocity the time derivative is q_dot = 0.5 * q * omega_q However, you can forget local integration since is not used much in rigid body dynamics. It's used in multibody dynamics (e.g. Featherstone). If this doesn't solve your problem I would check the transforms. Edit: Oops... I just checked XMQuaternionMultiply and it seems that it returns q2 * q1 instead of q1 * q2. So I think there is no problem with your quaternion integration. I would check the matrices.
6. ## FBX SDK skinned animation

While Dirk is searching his beautiful code you can try reading this code for becoming familiar with skeletal animation and skinning. However, this code ignores the geometric transform. Since most of my test models are from mixamo, I haven't needed such a transform. If you need this transform then simply transform the mesh vertices and normals using it, as Dirk pointed out.
7. ## Time complexity considerations of Sutherland–Hodgman clipping in one-shot contact generation

I've been using Sutherland-Hodgman for years with good results. Yes, it's fast enough and simple to implement. The good thing is that it preserves the polygon vertex order. Not informed about temporal coherency in the context of clipping. However, in the context of contact creation, temporal coherency can be exploited by reclipping the touching features. If two faces are chosen as the touching features in one frame, you run clipping and cache these features. If these two faces still are the touching features in the next frame, you check if the relative orientation of the shapes has changed up to some small tolerance. If not, you reclip those features. Of course we assume you can detect the touching features using an algorithm such as the SAT.
8. ## SAT sphere triangle test, calculating response

You can implement a position based constraint solver for this. Sharp corners requires a large number of solver iterations. Erin Catto (Box2D) described this algorithm at the end of his presentation:    http://box2d.org/files/GDC2014/GDC2014_ErinCatto.zip   It should be pretty easy to simplify it to your case and a great exercise. This is a very good resource with no lack of mathematical foundation.   Sorry, I cannot list you all the edge cases because I haven't taken the time to implement a robust character controller. But that is not a difficult problem we can tell you. If your engine supports double side collision the order of the triangle vertices doesn't matter.
9. ## SAT sphere triangle test, calculating response

You can use Barycentric coordinates to find the closest point on the triangle to the sphere center. Here's some personal code of mine you can use: // Convert a point Q from Cartesian coordinates to Barycentric coordinates (u, v) // with respect to a segment AB. // The last output value is the divisor. static B3_FORCE_INLINE void b3Barycentric(float32 out[3],     const b3Vec3& A, const b3Vec3& B,     const b3Vec3& Q) {     b3Vec3 AB = B - A;     b3Vec3 QA = A - Q;     b3Vec3 QB = B - Q;     float32 divisor = b3Dot(AB, AB);          out[0] = b3Dot(QB, AB);     out[1] = -b3Dot(QA, AB);     out[2] = divisor; } // Convert a point Q from Cartesian coordinates to Barycentric coordinates (u, v, w) // with respect to a triangle ABC. // The last output value is the divisor. static B3_FORCE_INLINE void b3Barycentric(float32 out[4],     const b3Vec3& A, const b3Vec3& B, const b3Vec3& C,     const b3Vec3& Q) {     b3Vec3 AB = B - A;     b3Vec3 AC = C - A;     b3Vec3 QA = A - Q;     b3Vec3 QB = B - Q;     b3Vec3 QC = C - Q;     b3Vec3 QB_x_QC = b3Cross(QB, QC);     b3Vec3 QC_x_QA = b3Cross(QC, QA);     b3Vec3 QA_x_QB = b3Cross(QA, QB);     b3Vec3 AB_x_AC = b3Cross(AB, AC);          float32 divisor = b3Dot(AB_x_AC, AB_x_AC);     out[0] = b3Dot(QB_x_QC, AB_x_AC);     out[1] = b3Dot(QC_x_QA, AB_x_AC);     out[2] = b3Dot(QA_x_QB, AB_x_AC);     out[3] = divisor; } // Return the closest point on a triangle ABC to a point Q. b3Vec3 Solve3(const b3Vec3& A, const b3Vec3& C, const b3Vec3& C, const b3Vec3& Q) {     // Test vertex regions     float32 wAB[3], wBC[3], wCA[3];     b3Barycentric(wAB, A, B, Q);     b3Barycentric(wBC, B, C, Q);     b3Barycentric(wCA, C, A, Q);          // R A     if (wAB[1] <= 0.0f && wCA[0] <= 0.0f)     {         return A;     }     // R B     if (wAB[0] <= 0.0f && wBC[1] <= 0.0f)     {         return B;     }     // R C     if (wBC[0] <= 0.0f && wCA[1] <= 0.0f)     {         return C;     }     // Test edge regions             float32 wABC[4];     b3Barycentric(wABC, A.point, B.point, C.point, Q);          // This is used to help testing if the face degenerates     // into an edge.     float32 area = wABC[3];     // R AB     if (wAB[0] > 0.0f && wAB[1] > 0.0f && area * wABC[2] <= 0.0f)     {         float32 s = wAB[2];         B3_ASSERT(s > 0.0f);         return (wAB[0] * A + wAB[1] * B) / s;     }     // R BC     if (wBC[0] > 0.0f && wBC[1] > 0.0f && area * wABC[0] <= 0.0f)     {         float32 s = wBC[2];         B3_ASSERT(s > 0.0f);         return (wBC[0] * B + wBC[1] * C) / s;     }     // R CA     if (wCA[0] > 0.0f && wCA[1] > 0.0f && area * wABC[1] <= 0.0f)     {         float32 s = wCA[2];         B3_ASSERT(s > 0.0f);         return (wCA[0] * C + wCA[1] * A) / s;     }     // R ABC/ACB     float32 s = wABC[3];     if (s <= 0.0f)     {         // Give up. Triangle is degenerate. // You should handle all cases correctly in production code.         return;     }     B3_ASSERT(s > 0.0f); return (wABC[0] * A + wABC[1] * B + wABC[2] * C) / s; } If you want to learn the math read Real-Time Collision Detection book.
10. ## SAT sphere triangle test, calculating response

The penetration depth is the distance between the closest points minus the sphere radius. The collision normal is the separating axis. If the triangle is static and you want a positional response then you can shift the sphere center by the penetration depth along the collision normal. Assume p2 is the closest point on the triangle to the sphere center. You can shift the sphere like this:   penetration = dot(p2 - center, normal) - radius center = center + penetration * normal
11. ## Quaternions and multiple rotations

I hope the following example helps.   Define ref_joint_rotation as a constant reference joint rotation. ref_joint_rotation transforms vectors defined in joint frame to vectors in parent joint frame at pose configuration. Now you want to define the current reference joint rotation cur_joint_rotation as the reference joint rotation plus a rotation about 90 degrees about the z axis relative to the parent frame. That's how you would do this: Vector3 axis axis.Set(0.0f, 0.0f, 1.0f); float angle = 0.5f * PI; Quaternion joint_rotation; joint_rotation.SetAxisAngle(axis, angle); cur_joint_rotation = joint_rotation * ref_joint_rotation; cur_joint_rotation rotates vectors in child frame to vectors in parent frame at the current configuration. Here the quaternion multiplication is defined in the original form. That is, a rotation by ref_joint_rotation followed by a rotation by joint_rotation.
12. ## D3D9 - Rotation on a specific local axis

Yes, is possible without quaternions.    You want to rotate the planet about the world x/y-axis of the ship.   Matrix33 rotation_x = MakeRotationFromAngleAxis(ship.rotation.x, angle_x); planet.rotation = rotation_x * planet.rotation;   Matrix33 rotation_y = MakeRotationFromAngleAxis(ship.rotation.y, angle_y); planet.rotation = rotation_y * planet.rotation;   MakeRotationFromAngleAxis returns a rotation matrix given an axis of rotation and angle of rotation about the axis. IIRC in DirectX there is a function called D3DXMatrixRotationAxis that computes this.   In DirectX you might need to swap the multiplication order. E.g:   planet.rotation = rotation_x * planet.rotation;   becomes   planet.rotation = planet.rotation * rotation_x;
13. ## LibGDX/Box2D orbital mechanics

You've multiplied -1 because the force direction should be planet_position - rocket_position.   I haven't read the rest of the code but as a beginner you should learn how to build or use a 2D math library before digging into game physics. If you're using Box2D for educational purposes I would just use its own.   With a math lib what you wrote becomes:   Vec2 displacement = planet.position - rocket.position; Vec2 force_direction = Normalize(displacement); float force_magnitude = planet.gravity * (rocket.mass * planet.mass) / LenghtSquared(displacement);   Vec2 F1 = force_magnitude * force_direction; Vec2 F2 = -F1;   rocket.ApplyForce(F1); planet.ApplyForce(F2);   Also...   When needed to calculate the angle between two vectors, don't use atan(y / x). Use atan2(y, x) if your math library has it because it can map to a larger angle range and handle x = 0.   You're passing degrees instead of radians to the cos and sin functions. I think in Java these functions also assume radians are given.    Don't use pow if the exponent is 2. Use base * base.
14. ## Calculating the moment of inertia of a 2D capsule

Here is the step-by-step calculation of the capsule inertia. I have the code in 3D so I downscaled it to 2D for your convenience. Of course you can simplify it but the decoupled approach is nice for clarification. You can also look use this image as a reference (originally from Dirk's paper).   float32 r = m_radius; float32 r2 = r * r; float32 w = 2.0f * r; float32 w2 = w * w; float32 h = b3Length(B - A); float32 h2 = h * h; // Rectangle inertia about the capsule center of mass b3MassData Ic_Rectangle; { // Rectangle mass float32 area = w * h; float32 mass = density * area; // Rectangle inertia about the center of mass (same as capsule center of mass) Ic_Rectangle.center = 0.5f * (A + B); Ic_Rectangle.mass = mass; Ic_Rectangle.I = mass * (w2 + h2) / 12.0f; } // Semicircle inertia about the capsule center of mass b3MassData Ic_Semicircle; { // Circle area and mass float32 circleArea = B3_PI * r2; float32 circleMass = density * circleArea; float32 circleI = circleMass * 0.5f * r2; // Semicircle area and mass float32 area = 0.5f * circleArea; float32 mass = 0.5f * circleMass; // Semicircle inertia about the base float32 Io = 0.5f * circleI; // Paralell axis theorem // I = Ic + m * d^2 // Ic = I - m * d^2 // Semicircle center of mass distance to the base float32 d1 = (3.0f / 8.0f) * r; // Semicircle inertia about its center of mass float32 Ic = Io - (mass * d1 * d1); // Semicircle center of mass distance to the capsule center of mass float32 d2 = d1 + 0.5f * h; // Semicircle inertia about the capsule center of mass float32 I = Ic + (mass * d2 * d2); Ic_Semicircle.center.Set(0.0f, d2); Ic_Semicircle.mass = mass; Ic_Semicircle.I = I; } // Capsule inertia about the capsule center of mass taking two semicircles into account b3MassData Ic_Capsule; Ic_Capsule.center = Ic_Rectangle.center; Ic_Capsule.mass = Ic_Rectangle.mass + 2.0f * Ic_Semicircle.mass; Ic_Capsule.I = Ic_Rectangle.I + 2.0f * Ic_Semicircle.I;
15. ## Calculating the moment of inertia of a 2D capsule

One problem is that momentOfInertiaOfSemiCircle is the moment of inertia of the (full) circle.    When I get home I'll try to derive you step-by-step.
×

## Important Information

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!