private void DoAxisLock(float timeStep, uint frameNum)
        {
            OpenMetaverse.Vector3 lockedaxis;
            float gtau;

            lock (_properties)
            {
                lockedaxis = _properties.LockedAxes;
                gtau       = _properties.GrabTargetTau;
            }

            // Grab overrides axis lock
            if (gtau != 0)
            {
                return;
            }

            // Fast bypass: If all axes are unlocked, skip the math.
            if (lockedaxis.X == 0 && lockedaxis.Y == 0 && lockedaxis.Z == 0)
            {
                return;
            }

            // Convert angular velocity to local.
            OpenMetaverse.Vector3 localangvel = PhysUtil.PhysxVectorToOmv(_dynActor.AngularVelocity) * OpenMetaverse.Quaternion.Inverse(_rotation);

            // Stop angular velocity on locked local axes (rotaxis.N == 0 means axis is locked)
            if (lockedaxis.X != 0)
            {
                localangvel.X = 0;
            }
            if (lockedaxis.Y != 0)
            {
                localangvel.Y = 0;
            }
            if (lockedaxis.Z != 0)
            {
                localangvel.Z = 0;
            }

            // Convert to global angular velocity.
            PhysX.Math.Vector3 angvel = PhysUtil.OmvVectorToPhysx(localangvel * _rotation);

            // This is a harsh way to do this, but a locked axis must have no angular velocity whatsoever.
            if (angvel != _dynActor.AngularVelocity)
            {
                _dynActor.ClearTorque();
                _dynActor.AngularVelocity = angvel;
            }
        }
Example #2
0
        private void GetRayCastResults(OpenMetaverse.Vector3 start, OpenMetaverse.Vector3 direction,
                                       float distance, int hitAmounts, Action <List <ContactResult> > result, PhysxScene scene)
        {
            int buffercount    = 16;
            int maxbuffercount = 1024;

            PhysX.RaycastHit[] hits = null;
            direction = OpenMetaverse.Vector3.Normalize(direction);

            //Increase the buffer count if the call indicates overflow. Prevent infinite loops.
            while (hits == null && buffercount <= maxbuffercount)
            {
                hits = SceneImpl.RaycastMultiple(PhysUtil.OmvVectorToPhysx(start),
                                                 PhysUtil.OmvVectorToPhysx(direction),
                                                 distance, PhysX.SceneQueryFlags.All,
                                                 buffercount,
                                                 null);
                buffercount *= 2;
            }

            List <ContactResult> contactResults = new List <ContactResult>();

            if (hits != null)
            {
                List <PhysX.RaycastHit> hitsSorted = new List <PhysX.RaycastHit>(hits);
                hitsSorted.Sort((a, b) => a.Distance.CompareTo(b.Distance));

                int count = 0;
                foreach (PhysX.RaycastHit hit in hitsSorted)
                {
                    contactResults.Add(new ContactResult()
                    {
                        Distance       = hit.Distance,
                        FaceIndex      = hit.FaceIndex,
                        CollisionActor = hit.Shape.Actor.UserData as PhysicsActor,
                        Position       = PhysUtil.PhysxVectorToOmv(hit.Impact),
                        Normal         = PhysUtil.PhysxVectorToOmv(hit.Normal),
                    });
                    if (++count >= hitAmounts)
                    {
                        break;
                    }
                }
            }
            result(contactResults);
        }
        private void DoRotLookTarget(float timeStep, uint frameNum)
        {
            float strength;
            float damping;

            OpenMetaverse.Quaternion target;
            float gtau;

            lock (_properties)
            {
                strength = _properties.RotLookStrength;
                damping  = _properties.RotLookDamping;
                target   = _properties.RotLookTarget;
                gtau     = _properties.GrabTargetTau;
            }

            // Grab overrides rot target
            if (gtau != 0)
            {
                return;
            }

            if (damping < MIN_ROTLOOK_DAMPING || strength < MIN_ROTLOOK_STRENGTH)
            {
                return;
            }

            OpenMetaverse.Quaternion normRot = OpenMetaverse.Quaternion.Normalize(_rotation);

            //this is the first frame we're beginning a new rotlook force
            //if we're not already at the target rotation, we need to find
            //the difference between our current rotation and the desired
            //rotation, then use the damping number as a tau to set the
            //angular velocity
            if (normRot.ApproxEquals(target, AT_ROT_TOLERANCE))
            {
                //nothing to do
                if (_dynActor.AngularVelocity != PhysX.Math.Vector3.Zero)
                {
                    _dynActor.AngularVelocity = PhysX.Math.Vector3.Zero;
                }
                return;
            }

            /*
             * rotation velocity is vector that corresponds to axis of rotation and have length equal to rotation speed,
             * for example in radians per second. It is sort of axis-angle thing.
             * Let's first find quaternion q so q*q0=q1 it is q=q1/q0
             *
             * For unit length quaternions, you can use q=q1*Conj(q0)
             *
             * To find rotation velocity that turns by q during time Dt you need to convert quaternion to axis angle using something like this:
             *
             * double len=sqrt(q.x*q.x+q.y*q.y+q.z*q.z)
             * double angle=2*atan2(len, q.w);
             * vector3 axis;
             * if(len>0)axis=q.xyz()/len; else axis=vector3(1,0,0);
             *
             * then rotation velocity w=axis*angle/dt
             *
             * For q1,q2 very close to eachother, xyz part of 2*q1*Conj(q0) is roughly equal to rotation velocity. (because for small angles sin(a)~=a)
             *
             * http://www.gamedev.net/topic/347752-quaternion-and-angular-velocity/
             */

            OpenMetaverse.Quaternion q = target * OpenMetaverse.Quaternion.Conjugate(normRot);

            double len   = Math.Sqrt(q.X * q.X + q.Y * q.Y + q.Z * q.Z);
            double angle = 2 * Math.Atan2(len, q.W);

            OpenMetaverse.Vector3 axis;
            if (len > 0)
            {
                axis.X = (float)(q.X / len);
                axis.Y = (float)(q.Y / len);
                axis.Z = (float)(q.Z / len);
            }
            else
            {
                axis = new OpenMetaverse.Vector3(1, 0, 0);
            }

            float fangle = ShortestAngle((float)angle);

            OpenMetaverse.Vector3 targetAngVel = ((axis * fangle) / damping) * ROT_LOOKAT_SCALING_CONSTANT;

            OpenMetaverse.Quaternion comRot = _centerOfMassLocalPose.Rotation;
            OpenMetaverse.Quaternion adjRot = _rotation * comRot;
            OpenMetaverse.Vector3    tensor = _massSpaceInertiaTensor;

            OpenMetaverse.Vector3 t = (tensor * (targetAngVel * OpenMetaverse.Quaternion.Inverse(adjRot))) * adjRot;

            OpenMetaverse.Vector3 currAngVel = PhysUtil.PhysxVectorToOmv(_dynActor.AngularVelocity);
            OpenMetaverse.Vector3 velDamping = (tensor * (-currAngVel * strength * ROT_LOOKAT_SCALING_CONSTANT * OpenMetaverse.Quaternion.Inverse(adjRot))) * adjRot;

            _dynActor.AddTorque(PhysUtil.OmvVectorToPhysx(t * timeStep), PhysX.ForceMode.Impulse, true);
            _dynActor.AddTorque(PhysUtil.OmvVectorToPhysx(velDamping * timeStep), PhysX.ForceMode.Impulse, true);

            //m_log.DebugFormat("New Ang Vel: {0}", targetAngVel);
        }