예제 #1
0
        //--------------------------------------------------------------------------------------------------
        public static void ComputeReferenceEdgesAndBasis(Vec3 eR, Transform rtx, Vec3 n, int axis, byte[] result, out Mat3 basis, out Vec3 e)
        {
            basis = new Mat3();
            e     = new Vec3();

            n = Transform.MulT(rtx.rotation, n);

            if (axis >= 3)
            {
                axis -= 3;
            }

            switch (axis)
            {
            case 0:
                if (n.x > 0)
                {
                    result[0] = 1;
                    result[1] = 8;
                    result[2] = 7;
                    result[3] = 9;

                    e.Set(eR.y, eR.z, eR.x);
                    basis.SetRows(rtx.rotation.ey, rtx.rotation.ez, rtx.rotation.ex);
                }

                else
                {
                    result[0] = 11;
                    result[1] = 3;
                    result[2] = 10;
                    result[3] = 5;

                    e.Set(eR.z, eR.y, eR.x);
                    basis.SetRows(rtx.rotation.ez, rtx.rotation.ey, -rtx.rotation.ex);
                }
                break;

            case 1:
                if (n.y > 0)
                {
                    result[0] = 0;
                    result[1] = 1;
                    result[2] = 2;
                    result[3] = 3;

                    e.Set(eR.z, eR.x, eR.y);
                    basis.SetRows(rtx.rotation.ez, rtx.rotation.ex, rtx.rotation.ey);
                }

                else
                {
                    result[0] = 4;
                    result[1] = 5;
                    result[2] = 6;
                    result[3] = 7;

                    e.Set(eR.z, eR.x, eR.y);
                    basis.SetRows(rtx.rotation.ez, -rtx.rotation.ex, -rtx.rotation.ey);
                }
                break;

            case 2:
                if (n.z > 0)
                {
                    result[0] = 11;
                    result[1] = 4;
                    result[2] = 8;
                    result[3] = 0;

                    e.Set(eR.y, eR.x, eR.z);
                    basis.SetRows(-rtx.rotation.ey, rtx.rotation.ex, rtx.rotation.ez);
                }

                else
                {
                    result[0] = 6;
                    result[1] = 10;
                    result[2] = 2;
                    result[3] = 9;

                    e.Set(eR.y, eR.x, eR.z);
                    basis.SetRows(-rtx.rotation.ey, -rtx.rotation.ex, -rtx.rotation.ez);
                }
                break;
            }
        }
예제 #2
0
 //--------------------------------------------------------------------------------------------------
 public static void Zero(Mat3 m)
 {
     m.Set(0, 0, 0, 0, 0, 0, 0, 0, 0);
 }
예제 #3
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);
            }
        }
예제 #4
0
 //--------------------------------------------------------------------------------------------------
 public static Vec3 MulT(Transform tx, Vec3 v)
 {
     return(Mat3.Transpose(tx.rotation) * (v - tx.position));
 }
예제 #5
0
 //--------------------------------------------------------------------------------------------------
 public static Vec3 MulT(Mat3 r, Vec3 v)
 {
     return(Mat3.Transpose(r) * v);
 }
예제 #6
0
 //--------------------------------------------------------------------------------------------------
 public static Mat3 Mul(Mat3 r, Mat3 q)
 {
     return(r * q);
 }
예제 #7
0
 //--------------------------------------------------------------------------------------------------
 public static Vec3 Mul(Mat3 r, Vec3 v)
 {
     return(r * v);
 }
예제 #8
0
 //--------------------------------------------------------------------------------------------------
 public static Mat3 MulT(Mat3 r, Mat3 q)
 {
     return(Mat3.Transpose(r) * q);
 }
예제 #9
0
        void CalculateMassData()
        {
            Mat3 inertia = Mat3.Diagonal(0);

            InvInertiaModel = Mat3.Diagonal(0);
            InvInertiaWorld = Mat3.Diagonal(0);
            InvMass         = 0;
            Mass            = 0;
            double mass = 0;

            if ((Flags & eStatic) > 0 || (Flags & eKinematic) > 0)
            {
                Vec3.Identity(ref LocalCenter);
                WorldCenter = Tx.position;
                return;
            }

            Vec3 lc = new Vec3();

            Vec3.Identity(ref lc);

            foreach (var box in Boxes)
            {
                if (box.density == 0)
                {
                    continue;
                }

                MassData md;
                box.ComputeMass(out md);
                mass    += md.mass;
                inertia += md.inertia;
                lc      += md.center * md.mass;
            }

            if (mass > 0)
            {
                Mass            = mass;
                InvMass         = 1 / mass;
                lc             *= InvMass;
                inertia        -= (Mat3.Identity * Vec3.Dot(lc, lc) - Mat3.OuterProduct(lc, lc)) * mass;
                InvInertiaModel = Mat3.Inverse(inertia);

                if ((Flags & eLockAxisX) > 0)
                {
                    Vec3.Identity(ref InvInertiaModel.ex);
                }

                if ((Flags & eLockAxisY) > 0)
                {
                    Vec3.Identity(ref InvInertiaModel.ey);
                }

                if ((Flags & eLockAxisZ) > 0)
                {
                    Vec3.Identity(ref InvInertiaModel.ez);
                }
            }
            else
            {
                // Force all dynamic bodies to have some mass
                InvMass         = 1;
                InvInertiaModel = Mat3.Diagonal(0);
                InvInertiaWorld = Mat3.Diagonal(0);
            }

            LocalCenter = lc;
            WorldCenter = Transform.Mul(Tx, lc);
        }
예제 #10
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();
                    }
                }
            }
        }