private void EnsureObjectAboveGround()
        {
            //check our bounding box. if it is below ground, provide a
            //z+ adjustment to our position to move it out

            //the height of ALL the terrain below our bounding box must be checked
            //to find the highest peak. quantize to the nearest meter since we don't
            //actually need to have the slope calculations performed
            int   yCoordMin      = (int)Math.Floor(_actor.WorldBounds.Center.Y - _actor.WorldBounds.Extents.Y);
            int   yCoordMax      = (int)Math.Ceiling(_actor.WorldBounds.Center.Y + _actor.WorldBounds.Extents.Y);
            int   xCoordMin      = (int)Math.Floor(_actor.WorldBounds.Center.X - _actor.WorldBounds.Extents.X);
            int   xCoordMax      = (int)Math.Ceiling(_actor.WorldBounds.Center.X + _actor.WorldBounds.Extents.X);
            float maxHeightFound = -100.0f;

            for (int x = xCoordMin; x <= xCoordMax; x++)
            {
                for (int y = yCoordMin; y <= yCoordMax; y++)
                {
                    maxHeightFound = Math.Max(maxHeightFound, (float)_scene.TerrainChannel[x, y]);
                }
            }

            if (_position.Z - _actor.WorldBounds.Extents.Z <= maxHeightFound)
            {
                _position.Z          = maxHeightFound + _actor.WorldBounds.Extents.Z + 0.1f;
                _dynActor.GlobalPose = PhysUtil.PositionToMatrix(_position, _rotation);
            }
        }
 public override void SetGrabSpinVelocity(OpenMetaverse.Vector3 target)
 {
     lock (_properties)
     {
         if (!_properties.BlockGrab)
         {
             _dynActor.AddTorque(PhysUtil.OmvVectorToPhysx(target), PhysX.ForceMode.VelocityChange, true);
         }
     }
 }
        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;
            }
        }
示例#4
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 DoPIDMoveTarget(float timeStep, uint frameNum)
        {
            float tau;

            OpenMetaverse.Vector3 target;
            float gtau;

            lock (_properties)
            {
                tau    = _properties.MoveTargetTau;
                target = _properties.MoveTarget;
                gtau   = _properties.GrabTargetTau;
            }

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

            if (tau > MIN_TAU)
            {
                //i had a whole elaborate setup here to do this.. turns out the linden
                //implementation was much simpler
                OpenMetaverse.Vector3 distance = target - _position;

                if (distance.LengthSquared() <= AT_TARGET_TOLERANCE_SQUARED)
                {
                    if (_velocity != OpenMetaverse.Vector3.Zero)
                    {
                        StopLinearMovement();
                        return;
                    }
                }

                ChangeGravityIfNeeded();
                _dynActor.AddForce(PhysUtil.OmvVectorToPhysx((distance * (1.0f / tau)) - _velocity), PhysX.ForceMode.VelocityChange, true);
            }
            else // Check for stop move to target - need to turn gravity back on if buoyancy isn't enabled
            if ((target == OpenMetaverse.Vector3.Zero) && (tau == 0.0f))
            {
                ChangeGravityIfNeeded();
            }
        }
        private bool DoGrabTarget(float timeStep, uint frameNum)
        {
            float tau;

            OpenMetaverse.Vector3 target;
            lock (_properties)
            {
                tau    = _properties.GrabTargetTau;
                target = _properties.GrabTarget;
            }

            if (tau > MIN_TAU)
            {
                _dynActor.AddTorque(PhysUtil.OmvVectorToPhysx(-_angularVelocity * 0.9f), PhysX.ForceMode.VelocityChange, false);
                OpenMetaverse.Vector3 distance = target - _position;

                if (distance.LengthSquared() <= AT_TARGET_TOLERANCE_SQUARED)
                {
                    if (_velocity != OpenMetaverse.Vector3.Zero)
                    {
                        StopLinearMovement();
                        return(true);
                    }
                }

                _grabDisableGravity = true;
                ChangeGravityIfNeeded();
                _dynActor.AddForce(PhysUtil.OmvVectorToPhysx((distance * (1.0f / tau)) - _velocity), PhysX.ForceMode.VelocityChange, true);
            }
            else
            {
                // Check for stop move to grab - need to turn gravity back on if buoyancy isn't enabled
                if (tau == 0.0f)
                {
                    _grabDisableGravity = false;
                    ChangeGravityIfNeeded();
                    return(false);
                }
            }
            return(true);
        }
        private void RunDepenetrateCycle(ref float pushFactor, ref bool foundOverlap, ref bool foundCriticalOverlap)
        {
            const int MAX_ITERATIONS = 6;
            const int MAX_OVERLAPS   = 32;

            OpenMetaverse.Vector3 offset = OpenMetaverse.Vector3.Zero;

            int iterOverlaps = 0;

            for (int i = 0; i < MAX_ITERATIONS; i++)
            {
                iterOverlaps         = 0;
                foundOverlap         = false;
                foundCriticalOverlap = false;
                foreach (var shape in _shapeToPrimIndex.Keys)
                {
                    OpenMetaverse.Vector3 translatedPose = PhysUtil.DecomposeToPosition(shape.GlobalPose) + offset;
                    PhysX.Shape[]         overlapping    = _scene.SceneImpl.OverlapMultiple(shape.Geom, PhysUtil.PositionToMatrix(translatedPose, _rotation));

                    if (overlapping == null)
                    {
                        //the overlap is too deep, instant fail
                        foundOverlap         = true;
                        foundCriticalOverlap = true;
                        return;
                    }

                    foreach (var oshape in overlapping)
                    {
                        if (oshape != null && oshape.Actor.UserData != this)
                        {
                            iterOverlaps++;
                            foundOverlap = true;
                            if (iterOverlaps > MAX_OVERLAPS)
                            {
                                foundCriticalOverlap = true;
                                break;
                            }
                        }
                    }

                    if (iterOverlaps > MAX_OVERLAPS)
                    {
                        break;
                    }
                }

                if (iterOverlaps > 0 && i + 1 < MAX_ITERATIONS)
                {
                    offset     += new OpenMetaverse.Vector3(0f, 0f, pushFactor);
                    pushFactor *= 2.0f;
                }
                else
                {
                    break;
                }
            }

            if (iterOverlaps == 0 && offset != OpenMetaverse.Vector3.Zero)
            {
                _dynActor.GlobalPose = PhysUtil.PositionToMatrix(_position + offset, _rotation);
                _position            = _position + offset;
                foundOverlap         = false;
            }
            else if (iterOverlaps == 0 && offset == OpenMetaverse.Vector3.Zero)
            {
                foundOverlap = false;
            }
            else if (iterOverlaps < MAX_OVERLAPS)
            {
                foundOverlap         = true;
                foundCriticalOverlap = false;
            }
            else
            {
                foundOverlap         = true;
                foundCriticalOverlap = true;
            }
        }
 private void StopLinearMovement()
 {
     _dynActor.ClearForce();
     _dynActor.AddForce(PhysUtil.OmvVectorToPhysx(-_velocity), PhysX.ForceMode.VelocityChange, false);
 }
        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);
        }