Пример #1
0
        public void ComputeMass(out MassData md)
        {
            // Calculate inertia tensor
            double ex2  = 4 * e.x * e.x;
            double ey2  = 4 * e.y * e.y;
            double ez2  = 4 * e.z * e.z;
            double mass = 8 * e.x * e.y * e.z * density;
            double x    = 1 / 12.0 * mass * (ey2 + ez2);
            double y    = 1 / 12.0 * mass * (ex2 + ez2);
            double z    = 1 / 12.0 * mass * (ex2 + ey2);
            Mat3   I    = Mat3.Diagonal(x, y, z);

            // Transform tensor to local space
            I  = local.rotation * I * Mat3.Transpose(local.rotation);
            I += (Mat3.Identity * Vec3.Dot(local.position, local.position) - Mat3.OuterProduct(local.position, local.position)) * mass;

            md.center  = local.position;
            md.inertia = I;
            md.mass    = mass;
        }
Пример #2
0
        // Resources:
        // http://www.randygaul.net/2014/05/22/deriving-obb-to-obb-intersection-sat/
        // https://box2d.googlecode.com/files/GDC2007_ErinCatto.zip
        // https://box2d.googlecode.com/files/Box2D_Lite.zip
        public static void BoxtoBox(Manifold m, Box a, Box b)
        {
            Transform atx = a.body.GetTransform();
            Transform btx = b.body.GetTransform();
            Transform aL  = a.local;
            Transform bL  = b.local;

            atx = Transform.Mul(atx, aL);
            btx = Transform.Mul(btx, bL);
            Vec3 eA = a.e;
            Vec3 eB = b.e;

            // B's frame input A's space
            Mat3 C = Mat3.Transpose(atx.rotation) * btx.rotation;

            Mat3   absC     = new Mat3();
            bool   parallel = false;
            double kCosTol  = 1e-6;

            for (int i = 0; i < 3; ++i)
            {
                for (int j = 0; j < 3; ++j)
                {
                    double val = Math.Abs(C[i][j]);
                    var    o   = absC[i];
                    o[j]    = val;
                    absC[i] = o;

                    if (val + kCosTol >= 1)
                    {
                        parallel = true;
                    }
                }
            }

            // Vector from center A to center B input A's space
            Vec3 t = Transform.MulT(atx.rotation, btx.position - atx.position);

            // Query states
            double s;
            double aMax  = -double.MaxValue;
            double bMax  = -double.MaxValue;
            double eMax  = -double.MaxValue;
            int    aAxis = ~0;
            int    bAxis = ~0;
            int    eAxis = ~0;
            Vec3   nA    = new Vec3();
            Vec3   nB    = new Vec3();
            Vec3   nE    = new Vec3();

            // Face axis checks

            // a's x axis
            s = Math.Abs(t.x) - (eA.x + Vec3.Dot(absC.Column0(), eB));
            if (TrackFaceAxis(ref aAxis, 0, s, ref aMax, atx.rotation.ex, ref nA))
            {
                return;
            }

            // a's y axis
            s = Math.Abs(t.y) - (eA.y + Vec3.Dot(absC.Column1(), eB));
            if (TrackFaceAxis(ref aAxis, 1, s, ref aMax, atx.rotation.ey, ref nA))
            {
                return;
            }

            // a's z axis
            s = Math.Abs(t.z) - (eA.z + Vec3.Dot(absC.Column2(), eB));
            if (TrackFaceAxis(ref aAxis, 2, s, ref aMax, atx.rotation.ez, ref nA))
            {
                return;
            }

            // b's x axis
            s = Math.Abs(Vec3.Dot(t, C.ex)) - (eB.x + Vec3.Dot(absC.ex, eA));
            if (TrackFaceAxis(ref bAxis, 3, s, ref bMax, btx.rotation.ex, ref nB))
            {
                return;
            }

            // b's y axis
            s = Math.Abs(Vec3.Dot(t, C.ey)) - (eB.y + Vec3.Dot(absC.ey, eA));
            if (TrackFaceAxis(ref bAxis, 4, s, ref bMax, btx.rotation.ey, ref nB))
            {
                return;
            }

            // b's z axis
            s = Math.Abs(Vec3.Dot(t, C.ez)) - (eB.z + Vec3.Dot(absC.ez, eA));
            if (TrackFaceAxis(ref bAxis, 5, s, ref bMax, btx.rotation.ez, ref nB))
            {
                return;
            }

            if (!parallel)
            {
                // Edge axis checks
                double rA;
                double rB;

                // Cross( a.x, b.x )
                rA = eA.y * absC[0][2] + eA.z * absC[0][1];
                rB = eB.y * absC[2][0] + eB.z * absC[1][0];
                s  = Math.Abs(t.z * C[0][1] - t.y * C[0][2]) - (rA + rB);
                if (TrackEdgeAxis(ref eAxis, 6, s, ref eMax, new Vec3(0, -C[0][2], C[0][1]), ref nE))
                {
                    return;
                }

                // Cross( a.x, b.y )
                rA = eA.y * absC[1][2] + eA.z * absC[1][1];
                rB = eB.x * absC[2][0] + eB.z * absC[0][0];
                s  = Math.Abs(t.z * C[1][1] - t.y * C[1][2]) - (rA + rB);
                if (TrackEdgeAxis(ref eAxis, 7, s, ref eMax, new Vec3(0, -C[1][2], C[1][1]), ref nE))
                {
                    return;
                }

                // Cross( a.x, b.z )
                rA = eA.y * absC[2][2] + eA.z * absC[2][1];
                rB = eB.x * absC[1][0] + eB.y * absC[0][0];
                s  = Math.Abs(t.z * C[2][1] - t.y * C[2][2]) - (rA + rB);
                if (TrackEdgeAxis(ref eAxis, 8, s, ref eMax, new Vec3(0, -C[2][2], C[2][1]), ref nE))
                {
                    return;
                }

                // Cross( a.y, b.x )
                rA = eA.x * absC[0][2] + eA.z * absC[0][0];
                rB = eB.y * absC[2][1] + eB.z * absC[1][1];
                s  = Math.Abs(t.x * C[0][2] - t.z * C[0][0]) - (rA + rB);
                if (TrackEdgeAxis(ref eAxis, 9, s, ref eMax, new Vec3(C[0][2], 0, -C[0][0]), ref nE))
                {
                    return;
                }

                // Cross( a.y, b.y )
                rA = eA.x * absC[1][2] + eA.z * absC[1][0];
                rB = eB.x * absC[2][1] + eB.z * absC[0][1];
                s  = Math.Abs(t.x * C[1][2] - t.z * C[1][0]) - (rA + rB);
                if (TrackEdgeAxis(ref eAxis, 10, s, ref eMax, new Vec3(C[1][2], 0, -C[1][0]), ref nE))
                {
                    return;
                }

                // Cross( a.y, b.z )
                rA = eA.x * absC[2][2] + eA.z * absC[2][0];
                rB = eB.x * absC[1][1] + eB.y * absC[0][1];
                s  = Math.Abs(t.x * C[2][2] - t.z * C[2][0]) - (rA + rB);
                if (TrackEdgeAxis(ref eAxis, 11, s, ref eMax, new Vec3(C[2][2], 0, -C[2][0]), ref nE))
                {
                    return;
                }

                // Cross( a.z, b.x )
                rA = eA.x * absC[0][1] + eA.y * absC[0][0];
                rB = eB.y * absC[2][2] + eB.z * absC[1][2];
                s  = Math.Abs(t.y * C[0][0] - t.x * C[0][1]) - (rA + rB);
                if (TrackEdgeAxis(ref eAxis, 12, s, ref eMax, new Vec3(-C[0][1], C[0][0], 0), ref nE))
                {
                    return;
                }

                // Cross( a.z, b.y )
                rA = eA.x * absC[1][1] + eA.y * absC[1][0];
                rB = eB.x * absC[2][2] + eB.z * absC[0][2];
                s  = Math.Abs(t.y * C[1][0] - t.x * C[1][1]) - (rA + rB);
                if (TrackEdgeAxis(ref eAxis, 13, s, ref eMax, new Vec3(-C[1][1], C[1][0], 0), ref nE))
                {
                    return;
                }

                // Cross( a.z, b.z )
                rA = eA.x * absC[2][1] + eA.y * absC[2][0];
                rB = eB.x * absC[1][2] + eB.y * absC[0][2];
                s  = Math.Abs(t.y * C[2][0] - t.x * C[2][1]) - (rA + rB);
                if (TrackEdgeAxis(ref eAxis, 14, s, ref eMax, new Vec3(-C[2][1], C[2][0], 0), ref nE))
                {
                    return;
                }
            }

            // Artificial axis bias to improve frame coherence
            double kRelTol = 0.95;
            double kAbsTol = 0.01;
            int    axis;
            double sMax;
            Vec3   n;
            double faceMax = Math.Max(aMax, bMax);

            if (kRelTol * eMax > faceMax + kAbsTol)
            {
                axis = eAxis;
                sMax = eMax;
                n    = nE;
            }

            else
            {
                if (kRelTol * bMax > aMax + kAbsTol)
                {
                    axis = bAxis;
                    sMax = bMax;
                    n    = nB;
                }

                else
                {
                    axis = aAxis;
                    sMax = aMax;
                    n    = nA;
                }
            }

            if (Vec3.Dot(n, btx.position - atx.position) < 0)
            {
                n = -n;
            }



            if (axis < 6)
            {
                Transform rtx;
                Transform itx;
                Vec3      eR;
                Vec3      eI;
                bool      flip;

                if (axis < 3)
                {
                    rtx  = atx;
                    itx  = btx;
                    eR   = eA;
                    eI   = eB;
                    flip = false;
                }

                else
                {
                    rtx  = btx;
                    itx  = atx;
                    eR   = eB;
                    eI   = eA;
                    flip = true;
                    n    = -n;
                }

                // Compute reference and incident edge information necessary for clipping

                ComputeIncidentFace(itx, eI, n, incident);
                Mat3 basis;
                Vec3 e;
                ComputeReferenceEdgesAndBasis(eR, rtx, n, axis, clipEdges, out basis, out e);

                // Clip the incident face against the reference face side planes
                int resultNum;
                resultNum = Clip(rtx.position, e, clipEdges, basis, incident, results, depths);

                if (resultNum != 0)
                {
                    m.contactCount = resultNum;
                    m.normal       = flip ? -n : n;

                    for (int i = 0; i < resultNum; ++i)
                    {
                        Contact c = m.contacts[i];

                        FeaturePair pair = results[i].f;

                        if (flip)
                        {
                            Swap(ref pair.inI, ref pair.inR);
                            Swap(ref pair.outI, ref pair.outR);
                        }

                        c.fp          = results[i].f;
                        c.position    = results[i].v;
                        c.penetration = depths[i];
                    }
                }
            }

            else
            {
                n = atx.rotation * n;

                if (Vec3.Dot(n, btx.position - atx.position) < 0)
                {
                    n = -n;
                }

                Vec3 PA, QA;
                Vec3 PB, QB;

                SupportEdge(atx, eA, n, out PA, out QA);

                SupportEdge(btx, eB, -n, out PB, out QB);

                Vec3 CA, CB;

                EdgesContact(out CA, out CB, PA, QA, PB, QB);

                m.normal       = n;
                m.contactCount = 1;

                Contact     c    = m.contacts[0];
                FeaturePair pair = new FeaturePair();
                pair.key      = axis;
                c.fp          = pair;
                c.penetration = sMax;
                c.position    = (CA + CB) * (0.5);
            }
        }
Пример #3
0
 //--------------------------------------------------------------------------------------------------
 public static Vec3 MulT(Mat3 r, Vec3 v)
 {
     return(Mat3.Transpose(r) * v);
 }
Пример #4
0
 //--------------------------------------------------------------------------------------------------
 public static Vec3 MulT(Transform tx, Vec3 v)
 {
     return(Mat3.Transpose(tx.rotation) * (v - tx.position));
 }
Пример #5
0
 //--------------------------------------------------------------------------------------------------
 public static Mat3 MulT(Mat3 r, Mat3 q)
 {
     return(Mat3.Transpose(r) * q);
 }
Пример #6
0
        public void Solve()
        {
            // Apply gravity
            // Integrate velocities and create state buffers, calculate world inertia
            for (int i = 0; i < Bodies.Count; ++i)
            {
                Body          body = Bodies[i];
                VelocityState v    = Velocities[i];

                if ((body.Flags & BodyFlags.eDynamic) > 0)
                {
                    body.ApplyLinearForce(Gravity * body.GravityScale);

                    // Calculate world space intertia tensor
                    Mat3 r = body.Tx.rotation;
                    body.InvInertiaWorld = r * body.InvInertiaModel * Mat3.Transpose(r);

                    // Integrate velocity
                    body.LinearVelocity  += (body.Force * body.InvMass) * Dt;
                    body.AngularVelocity += (body.InvInertiaWorld * body.Torque) * Dt;

                    // From Box2D!
                    // Apply damping.
                    // ODE: dv/dt + c * v = 0
                    // Solution: v(t) = v0 * exp(-c * t)
                    // Time step: v(t + dt) = v0 * exp(-c * (t + dt)) = v0 * exp(-c * t) * exp(-c * dt) = v * exp(-c * dt)
                    // v2 = exp(-c * dt) * v1
                    // Pade approximation:
                    // v2 = v1 * 1 / (1 + c * dt)
                    body.LinearVelocity  *= 1 / (1 + Dt * body.LinearDamping);
                    body.AngularVelocity *= 1 / (1 + Dt * body.AngularDamping);
                }

                Velocities[i] = new VelocityState {
                    v = body.LinearVelocity, w = body.AngularVelocity
                };
            }

            // Create contact solver, pass in state buffers, create buffers for contacts
            // Initialize velocity constraint for normal + friction and warm start
            ContactSolver.Initialize(this);
            ContactSolver.PreSolve(Dt);

            // Solve contacts
            for (int i = 0; i < Iterations; ++i)
            {
                ContactSolver.Solve();
            }

            ContactSolver.ShutDown();

            // Copy back state buffers
            // Integrate positions
            for (int i = 0; i < Bodies.Count; ++i)
            {
                Body          body = Bodies[i];
                VelocityState v    = Velocities[i];

                if ((body.Flags & BodyFlags.eStatic) > 0)
                {
                    continue;
                }

                body.LinearVelocity  = v.v;
                body.AngularVelocity = v.w;

                // Integrate position
                body.WorldCenter += body.LinearVelocity * Dt;
                body.Q.Integrate(body.AngularVelocity, Dt);
                body.Q           = Quaternion.Normalize(body.Q);
                body.Tx.rotation = body.Q.ToMat3();
            }

            if (AllowSleep)
            {
                // Find minimum sleep time of the entire island
                double minSleepTime = double.MaxValue;
                for (int i = 0; i < Bodies.Count; ++i)
                {
                    Body body = Bodies[i];

                    if ((body.Flags & BodyFlags.eStatic) > 0)
                    {
                        continue;
                    }

                    double sqrLinVel = Vec3.Dot(body.LinearVelocity, body.LinearVelocity);
                    double cbAngVel  = Vec3.Dot(body.AngularVelocity, body.AngularVelocity);
                    double linTol    = Q3_SLEEP_LINEAR;
                    double angTol    = Q3_SLEEP_ANGULAR;

                    if (sqrLinVel > linTol || cbAngVel > angTol)
                    {
                        minSleepTime   = 0;
                        body.SleepTime = 0;
                    }

                    else
                    {
                        body.SleepTime += Dt;
                        minSleepTime    = Math.Min(minSleepTime, body.SleepTime);
                    }
                }

                // Put entire island to sleep so long as the minimum found sleep time
                // is below the threshold. If the minimum sleep time reaches below the
                // sleeping threshold, the entire island will be reformed next step
                // and sleep test will be tried again.
                if (minSleepTime > Q3_SLEEP_TIME)
                {
                    for (int i = 0; i < Bodies.Count; ++i)
                    {
                        Bodies[i].SetToSleep();
                    }
                }
            }
        }