protected override JobHandle OnUpdate(JobHandle inputDeps)
    {
        if (m_ContactModifierGroup.CalculateLength() == 0)
        {
            return(inputDeps);
        }

        if (m_StepPhysicsWorld.Simulation.Type == SimulationType.NoPhysics)
        {
            return(inputDeps);
        }

        var modifiers     = m_ContactModifierGroup.ToComponentDataArray <ModifyNarrowphaseContacts>(Allocator.TempJob);
        var surfaceNormal = modifiers[0].surfaceNormal;
        var surfaceRBIdx  = m_BuildPhysicsWorld.PhysicsWorld.GetRigidBodyIndex(modifiers[0].surfaceEntity);

        SimulationCallbacks.Callback callback = (ref ISimulation simulation, JobHandle inDeps) =>
        {
            inDeps.Complete();  // TODO: shouldn't be needed (jobify the below)

            SimulationData.Contacts.Iterator iterator = simulation.Contacts.GetIterator();
            while (iterator.HasItemsLeft())
            {
                ContactHeader manifold      = iterator.GetNextContactHeader();
                bool          bUpdateNormal = (manifold.BodyPair.BodyAIndex == surfaceRBIdx) || (manifold.BodyPair.BodyBIndex == surfaceRBIdx);

                float distanceScale = 1;
                if (bUpdateNormal)
                {
                    var newNormal = surfaceNormal;
                    distanceScale = math.dot(newNormal, manifold.Normal);

                    //<todo.eoin.hpi Feels pretty weird.
                    //<todo.eoin.hp Need to make this work if user has read a contact
                    iterator.SetManifoldNormal(newNormal);
                }
                for (int i = 0; i < manifold.NumContacts; i++)
                {
                    ContactPoint cp = iterator.GetNextContact();

                    if (bUpdateNormal)
                    {
                        cp.Distance *= distanceScale;
                        iterator.UpdatePreviousContact(cp);
                    }
                }
            }

            return(inDeps);
        };

        modifiers.Dispose();

        m_StepPhysicsWorld.EnqueueCallback(SimulationCallbacks.Phase.PostCreateContacts, callback);

        return(inputDeps);
    }
Пример #2
0
    protected override JobHandle OnUpdate(JobHandle inputDeps)
    {
        if (m_ContactModifierGroup.CalculateLength() == 0)
        {
            return(inputDeps);
        }

        if (m_StepPhysicsWorld.Simulation.Type == SimulationType.NoPhysics)
        {
            return(inputDeps);
        }

        SimulationCallbacks.Callback preparationCallback = (ref ISimulation simulation, JobHandle inDeps) =>
        {
            inDeps.Complete();  // shouldn't be needed (jobify the below)

            SimulationData.Contacts.Iterator iterator = simulation.Contacts.GetIterator();
            while (iterator.HasItemsLeft())
            {
                ContactHeader manifold = iterator.GetNextContactHeader();

                // JacobianModifierFlags format for this example
                // UserData 0 - soft contact
                // UserData 1 - surface velocity
                // UserData 2 - infinite inertia
                // UserData 3 - no torque
                // UserData 4 - clip impulse
                // UserData 5 - disabled contact

                if (0 != (manifold.BodyCustomDatas.CustomDataA & (byte)(1 << 0)) ||
                    0 != (manifold.BodyCustomDatas.CustomDataB & (byte)(1 << 0)))
                {
                    manifold.JacobianFlags |= JacobianFlags.UserFlag0; // Soft Contact
                }
                if (0 != (manifold.BodyCustomDatas.CustomDataA & (byte)(1 << 1)) ||
                    0 != (manifold.BodyCustomDatas.CustomDataB & (byte)(1 << 1)))
                {
                    manifold.JacobianFlags |= JacobianFlags.EnableSurfaceVelocity;
                }
                if (0 != (manifold.BodyCustomDatas.CustomDataA & (byte)(1 << 2)) ||
                    0 != (manifold.BodyCustomDatas.CustomDataB & (byte)(1 << 2)))
                {
                    manifold.JacobianFlags |= JacobianFlags.EnableMassFactors;
                }
                if (0 != (manifold.BodyCustomDatas.CustomDataA & (byte)(1 << 3)) ||
                    0 != (manifold.BodyCustomDatas.CustomDataB & (byte)(1 << 3)))
                {
                    manifold.JacobianFlags |= JacobianFlags.UserFlag1; // No Torque
                }
                if (0 != (manifold.BodyCustomDatas.CustomDataA & (byte)(1 << 4)) ||
                    0 != (manifold.BodyCustomDatas.CustomDataB & (byte)(1 << 4)))
                {
                    manifold.JacobianFlags |= JacobianFlags.EnableMaxImpulse; // No Torque
                }
                if (0 != (manifold.BodyCustomDatas.CustomDataA & (byte)(1 << 5)) ||
                    0 != (manifold.BodyCustomDatas.CustomDataB & (byte)(1 << 5)))
                {
                    manifold.JacobianFlags |= JacobianFlags.Disabled;
                }

                iterator.UpdatePreviousContactHeader(manifold);

                // Just read contacts
                for (int i = 0; i < manifold.NumContacts; i++)
                {
                    iterator.GetNextContact();
                }
            }

            return(inDeps);
        };

        SimulationCallbacks.Callback jacobianModificationCallback = (ref ISimulation simulation, JobHandle inDeps) =>
        {
            inDeps.Complete();  // shouldn't be needed (jobify the below)

            JacobianIterator iterator = simulation.Jacobians.Iterator;
            while (iterator.HasJacobiansLeft())
            {
                // JacobianModifierFlags format for this example
                // UserFlag0 - soft contact
                // UserFlag1 - no torque

                // Jacobian header
                ref JacobianHeader jacHeader = ref iterator.ReadJacobianHeader();

                // Triggers can only be disabled, other modifiers have no effect
                if (jacHeader.Type == JacobianType.Contact)
                {
                    // Contact jacobian modification
                    ref ContactJacobian contactJacobian = ref jacHeader.AccessBaseJacobian <ContactJacobian>();
                    {
                        // Check if NoTorque modifier
                        if ((jacHeader.Flags & JacobianFlags.UserFlag1) != 0)
                        {
                            // Disable all friction angular effects
                            contactJacobian.Friction0.AngularA       = 0.0f;
                            contactJacobian.Friction1.AngularA       = 0.0f;
                            contactJacobian.AngularFriction.AngularA = 0.0f;
                            contactJacobian.Friction0.AngularB       = 0.0f;
                            contactJacobian.Friction1.AngularB       = 0.0f;
                            contactJacobian.AngularFriction.AngularB = 0.0f;
                        }

                        // Check if SurfaceVelocity present
                        if (jacHeader.HasSurfaceVelocity)
                        {
                            // Since surface normal can change, make sure angular velocity is always relative to it, not independent
                            float3 angVel = contactJacobian.BaseJacobian.Normal * (new float3(0.0f, 1.0f, 0.0f));
                            float3 linVel = float3.zero;

                            Math.CalculatePerpendicularNormalized(contactJacobian.BaseJacobian.Normal, out float3 dir0, out float3 dir1);
                            float linVel0 = math.dot(linVel, dir0);
                            float linVel1 = math.dot(linVel, dir1);

                            float angVelProj = math.dot(angVel, contactJacobian.BaseJacobian.Normal);

                            jacHeader.SurfaceVelocity = new SurfaceVelocity {
                                ExtraFrictionDv = new float3(linVel0, linVel1, angVelProj)
                            };
                        }