public override void Clear() { Index = 0; OffsetFromRoot = OMV.Vector3.Zero; OffsetFromCenterOfMass = OMV.Vector3.Zero; OffsetRot = OMV.Quaternion.Identity; }
public BSLinksetCompoundInfo(int indx, OMV.Vector3 p, OMV.Quaternion r) { Index = indx; OffsetFromRoot = p; OffsetFromCenterOfMass = p; OffsetRot = r; }
protected BSPhysObject(BSScene parentScene, uint localID, string name, string typeName) { PhysicsScene = parentScene; LocalID = localID; PhysObjectName = name; Name = name; // PhysicsActor also has the name of the object. Someday consolidate. TypeName = typeName; // Initialize variables kept in base. GravModifier = 1.0f; Gravity = new OMV.Vector3(0f, 0f, BSParam.Gravity); // We don't have any physical representation yet. PhysBody = new BulletBody(localID); PhysShape = new BulletShape(); LastAssetBuildFailed = false; // Default material type. Also sets Friction, Restitution and Density. SetMaterial((int)MaterialAttributes.Material.Wood); CollisionCollection = new CollisionEventUpdate(); CollisionsLastTick = CollisionCollection; SubscribedEventsMs = 0; CollidingStep = 0; CollidingGroundStep = 0; CollisionAccumulation = 0; ColliderIsMoving = false; CollisionScore = 0; // All axis free. LockedAxis = LockedAxisFree; }
// Set all the parameters for this constraint to a fixed, non-movable constraint. public override void ResetLink() { // constraintType = ConstraintType.D6_CONSTRAINT_TYPE; constraintType = ConstraintType.BS_FIXED_CONSTRAINT_TYPE; linearLimitLow = OMV.Vector3.Zero; linearLimitHigh = OMV.Vector3.Zero; angularLimitLow = OMV.Vector3.Zero; angularLimitHigh = OMV.Vector3.Zero; useFrameOffset = BSParam.LinkConstraintUseFrameOffset; enableTransMotor = BSParam.LinkConstraintEnableTransMotor; transMotorMaxVel = BSParam.LinkConstraintTransMotorMaxVel; transMotorMaxForce = BSParam.LinkConstraintTransMotorMaxForce; cfm = BSParam.LinkConstraintCFM; erp = BSParam.LinkConstraintERP; solverIterations = BSParam.LinkConstraintSolverIterations; frameInAloc = OMV.Vector3.Zero; frameInArot = OMV.Quaternion.Identity; frameInBloc = OMV.Vector3.Zero; frameInBrot = OMV.Quaternion.Identity; useLinearReferenceFrameA = true; springAxisEnable = new bool[6]; springDamping = new float[6]; springStiffness = new float[6]; for (int ii = 0; ii < springAxisEnable.Length; ii++) { springAxisEnable[ii] = false; springDamping[ii] = BSAPITemplate.SPRING_NOT_SPECIFIED; springStiffness[ii] = BSAPITemplate.SPRING_NOT_SPECIFIED; } springLinearEquilibriumPoint = OMV.Vector3.Zero; springAngularEquilibriumPoint = OMV.Vector3.Zero; member.PhysScene.DetailLog("{0},BSLinkInfoConstraint.ResetLink", member.LocalID); }
// Clears any center-of-mass displacement introduced by linksets, etc. // Does not clear the displacement set by the user. public void ClearDisplacement() { if (UserSetCenterOfMassDisplacement.HasValue) PositionDisplacement = (OMV.Vector3)UserSetCenterOfMassDisplacement; else PositionDisplacement = OMV.Vector3.Zero; }
/// <summary> /// Create the animation. The passed animation block is expected /// to contain a defintion of a fixed rotation. If not, bad things will happen. /// </summary> /// <param name="anim">The IAnimation block with the info.</param> /// <param name="id">localID to lookup the prim in the RegionRenderInfo.renderPrimList</param> public AnimatPosition(OMV.Vector3 newPos, float durationSeconds, RegionRenderInfo rri, uint id) : base(AnimatBase.AnimatTypePosition) { m_infoID = id; RenderablePrim rp = rri.renderPrimList[id]; m_origionalPosition = rp.Position; m_targetPosition = newPos; m_durationSeconds = durationSeconds; m_distanceVector = m_targetPosition - m_origionalPosition; m_progress = 0f; }
public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying) : base(parent_scene, localID, avName, "BSCharacter") { _physicsActorType = (int)ActorTypes.Agent; _position = pos; // Old versions of ScenePresence passed only the height. If width and/or depth are zero, // replace with the default values. _size = size; if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth; if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth; // A motor to control the acceleration and deceleration of the avatar movement. // _velocityMotor = new BSVMotor("BSCharacter.Velocity", 3f, 5f, BSMotor.InfiniteVector, 1f); // _velocityMotor = new BSPIDVMotor("BSCharacter.Velocity", 3f, 5f, BSMotor.InfiniteVector, 1f); // Infinite decay and timescale values so motor only changes current to target values. _velocityMotor = new BSVMotor("BSCharacter.Velocity", 0.2f, // time scale BSMotor.Infinite, // decay time scale BSMotor.InfiniteVector, // friction timescale 1f // efficiency ); _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages. _flying = isFlying; _orientation = OMV.Quaternion.Identity; _velocity = OMV.Vector3.Zero; _appliedVelocity = OMV.Vector3.Zero; _buoyancy = ComputeBuoyancyFromFlying(isFlying); _currentFriction = BSParam.AvatarStandingFriction; _avatarDensity = BSParam.AvatarDensity; // The dimensions of the avatar capsule are kept in the scale. // Physics creates a unit capsule which is scaled by the physics engine. ComputeAvatarScale(_size); // set _avatarVolume and _mass based on capsule size, _density and Scale ComputeAvatarVolumeAndMass(); DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}", LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass); // do actual creation in taint time PhysicsScene.TaintedObject("BSCharacter.create", delegate() { DetailLog("{0},BSCharacter.create,taint", LocalID); // New body and shape into PhysBody and PhysShape PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this); SetPhysicalProperties(); }); return; }
// 'centerDisplacement' is the distance from the root the the center-of-mass (Bullet 'zero' of the shape) public BSLinksetCompoundInfo(int indx, BSPrimLinkable root, BSPrimLinkable child, OMV.Vector3 centerDisplacement) { // Each child position and rotation is given relative to the center-of-mass. OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(root.RawOrientation); OMV.Vector3 displacementFromRoot = (child.RawPosition - root.RawPosition) * invRootOrientation; OMV.Vector3 displacementFromCOM = displacementFromRoot - centerDisplacement; OMV.Quaternion displacementRot = child.RawOrientation * invRootOrientation; // Save relative position for recomputing child's world position after moving linkset. Index = indx; OffsetFromRoot = displacementFromRoot; OffsetFromCenterOfMass = displacementFromCOM; OffsetRot = displacementRot; }
/// <summary> /// Create the animation. The passed animation block is expected /// to contain a defintion of a fixed rotation. If not, bad things will happen. /// </summary> /// <param name="anim">The IAnimation block with the info.</param> /// <param name="id">localID to lookup the prim in the RegionRenderInfo.renderPrimList</param> public AnimatFixedRotation(IAnimation anim, uint id) : base(AnimatBase.AnimatTypeFixedRotation) { m_infoID = id; if (anim.DoStaticRotation) { m_rotationsPerSecond = anim.StaticRotationRotPerSec; m_rotationAxis = anim.StaticRotationAxis; } else { // shouldn't get here m_rotationsPerSecond = 1; m_rotationAxis = OMV.Vector3.UnitX; } }
public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying) : base(parent_scene, localID, avName, "BSCharacter") { _physicsActorType = (int)ActorTypes.Agent; _isPhysical = true; _position = pos; _flying = isFlying; _orientation = OMV.Quaternion.Identity; RawVelocity = OMV.Vector3.Zero; _buoyancy = ComputeBuoyancyFromFlying(isFlying); Friction = BSParam.AvatarStandingFriction; Density = BSParam.AvatarDensity / BSParam.DensityScaleFactor; // Old versions of ScenePresence passed only the height. If width and/or depth are zero, // replace with the default values. _size = size; if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth; if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth; // The dimensions of the physical capsule are kept in the scale. // Physics creates a unit capsule which is scaled by the physics engine. Scale = ComputeAvatarScale(_size); // set _avatarVolume and _mass based on capsule size, _density and Scale ComputeAvatarVolumeAndMass(); // The avatar's movement is controlled by this motor that speeds up and slows down // the avatar seeking to reach the motor's target speed. // This motor runs as a prestep action for the avatar so it will keep the avatar // standing as well as moving. Destruction of the avatar will destroy the pre-step action. m_moveActor = new BSActorAvatarMove(PhysicsScene, this, AvatarMoveActorName); PhysicalActors.Add(AvatarMoveActorName, m_moveActor); DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}", LocalID, _size, Scale, Density, _avatarVolume, RawMass); // do actual creation in taint time PhysicsScene.TaintedObject(LocalID, "BSCharacter.create", delegate() { DetailLog("{0},BSCharacter.create,taint", LocalID); // New body and shape into PhysBody and PhysShape PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this); SetPhysicalProperties(); SubscribeEvents(1000); }); return; }
public DetectParams() { Key = UUID.Zero; OffsetPos = new OpenMetaverse.Vector3(); LinkNum = 0; Group = UUID.Zero; Name = String.Empty; Owner = UUID.Zero; Position = new OpenMetaverse.Vector3(); Rotation = new OpenMetaverse.Quaternion(); Type = 0; Velocity = new OpenMetaverse.Vector3(); initializeSurfaceTouch(); }
public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying) { base.BaseInitialize(parent_scene, localID, avName, "BSCharacter"); _physicsActorType = (int)ActorTypes.Agent; _position = pos; _size = size; _flying = isFlying; _orientation = OMV.Quaternion.Identity; _velocity = OMV.Vector3.Zero; _buoyancy = ComputeBuoyancyFromFlying(isFlying); // The dimensions of the avatar capsule are kept in the scale. // Physics creates a unit capsule which is scaled by the physics engine. ComputeAvatarScale(_size); _avatarDensity = PhysicsScene.Params.avatarDensity; // set _avatarVolume and _mass based on capsule size, _density and _scale ComputeAvatarVolumeAndMass(); ShapeData shapeData = new ShapeData(); shapeData.ID = LocalID; shapeData.Type = ShapeData.PhysicsShapeType.SHAPE_AVATAR; shapeData.Position = _position; shapeData.Rotation = _orientation; shapeData.Velocity = _velocity; shapeData.Scale = _scale; shapeData.Mass = _mass; shapeData.Buoyancy = _buoyancy; shapeData.Static = ShapeData.numericFalse; shapeData.Friction = PhysicsScene.Params.avatarFriction; shapeData.Restitution = PhysicsScene.Params.avatarRestitution; // do actual create at taint time PhysicsScene.TaintedObject("BSCharacter.create", delegate() { DetailLog("{0},BSCharacter.create,taint", LocalID); BulletSimAPI.CreateObject(PhysicsScene.WorldID, shapeData); // Set the buoyancy for flying. This will be refactored when all the settings happen in C#. // If not set at creation, the avatar will stop flying when created after crossing a region boundry. BulletSimAPI.SetObjectBuoyancy(PhysicsScene.WorldID, LocalID, _buoyancy); BSBody = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(PhysicsScene.World.ptr, LocalID)); // This works here because CreateObject has already put the character into the physical world. BulletSimAPI.SetCollisionFilterMask2(BSBody.ptr, (uint)CollisionFilterGroups.AvatarFilter, (uint)CollisionFilterGroups.AvatarMask); }); return; }
// Set motion values to zero. // Do it to the properties so the values get set in the physics engine. // Push the setting of the values to the viewer. // Called at taint time! public override void ZeroMotion(bool inTaintTime) { RawVelocity = OMV.Vector3.Zero; _acceleration = OMV.Vector3.Zero; _rotationalVelocity = OMV.Vector3.Zero; // Zero some other properties directly into the physics engine PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() { if (PhysBody.HasPhysicalBody) { PhysicsScene.PE.ClearAllForces(PhysBody); } }); }
public override void ZeroAngularMotion(bool inTaintTime) { _rotationalVelocity = OMV.Vector3.Zero; PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.ZeroMotion", delegate() { if (PhysBody.HasPhysicalBody) { PhysScene.PE.SetInterpolationAngularVelocity(PhysBody, OMV.Vector3.Zero); PhysScene.PE.SetAngularVelocity(PhysBody, OMV.Vector3.Zero); // The next also get rid of applied linear force but the linear velocity is untouched. PhysScene.PE.ClearForces(PhysBody); } }); }
void SetVelocityAndTargetInternal(OMV.Vector3 vel, OMV.Vector3 targ, bool inTaintTime, int targetValueDecayTimeScale) { m_physicsScene.TaintedObject(inTaintTime, m_controllingPrim.LocalID, "BSActorAvatarMove.setVelocityAndTarget", delegate() { if (m_velocityMotor != null) { m_velocityMotor.Reset(); m_velocityMotor.SetTarget(targ); m_velocityMotor.SetCurrent(vel); m_velocityMotor.TargetValueDecayTimeScale = targetValueDecayTimeScale; m_velocityMotor.Enabled = true; } }); }
// Set all the parameters for this constraint to a fixed, non-movable constraint. public void ResetToFixedConstraint() { constraintType = ConstraintType.D6_CONSTRAINT_TYPE; linearLimitLow = OMV.Vector3.Zero; linearLimitHigh = OMV.Vector3.Zero; angularLimitLow = OMV.Vector3.Zero; angularLimitHigh = OMV.Vector3.Zero; useFrameOffset = BSParam.LinkConstraintUseFrameOffset; enableTransMotor = BSParam.LinkConstraintEnableTransMotor; transMotorMaxVel = BSParam.LinkConstraintTransMotorMaxVel; transMotorMaxForce = BSParam.LinkConstraintTransMotorMaxForce; cfm = BSParam.LinkConstraintCFM; erp = BSParam.LinkConstraintERP; solverIterations = BSParam.LinkConstraintSolverIterations; }
private OMV.Vector3 ComputeAvatarScale(OMV.Vector3 size) { OMV.Vector3 newScale; // Bullet's capsule total height is the "passed height + radius * 2"; // The base capsule is 1 unit in diameter and 2 units in height (passed radius=0.5, passed height = 1) // The number we pass in for 'scaling' is the multiplier to get that base // shape to be the size desired. // So, when creating the scale for the avatar height, we take the passed height // (size.Z) and remove the caps. // An oddity of the Bullet capsule implementation is that it presumes the Y // dimension is the radius of the capsule. Even though some of the code allows // for a asymmetrical capsule, other parts of the code presume it is cylindrical. // Scale is multiplier of radius with one of "0.5" newScale.X = size.X / 2f; newScale.Y = size.Y / 2f; float heightAdjust = BSParam.AvatarHeightMidFudge; if (BSParam.AvatarHeightLowFudge != 0f || BSParam.AvatarHeightHighFudge != 0f) { // An avatar is between 1.61 and 2.12 meters. Midpoint is 1.87m. // The "times 4" relies on the fact that the difference from the midpoint to the extremes is exactly 0.25 float midHeightOffset = size.Z - 1.87f; if (midHeightOffset < 0f) { // Small avatar. Add the adjustment based on the distance from midheight heightAdjust += -1f * midHeightOffset * 4f * BSParam.AvatarHeightLowFudge; } else { // Large avatar. Add the adjustment based on the distance from midheight heightAdjust += midHeightOffset * 4f * BSParam.AvatarHeightHighFudge; } } // The total scale height is the central cylindar plus the caps on the two ends. newScale.Z = (size.Z + (Math.Min(size.X, size.Y) * 2) + heightAdjust) / 2f; // m_log.DebugFormat("{0} ComputeAvatarScale: size={1},adj={2},scale={3}", LogHeader, size, heightAdjust, newScale); // If smaller than the endcaps, just fake like we're almost that small if (newScale.Z < 0) { newScale.Z = 0.1f; } return(newScale); }
public OMV.Vector3 ParamVector3(string key) { OMV.Vector3 ret = OMV.Vector3.Zero; string lkey = key.ToLower(); bool success = false; lock (m_params) { try { if (m_runtimeValues.ContainsKey(key)) { if (OMV.Vector3.TryParse(m_runtimeValues[lkey](lkey).AsString(), out ret)) { success = true; } } else { if (m_params.ContainsKey(lkey)) { if (OMV.Vector3.TryParse(m_params[lkey].AsString(), out ret)) { success = true; } } } } catch { success = false; } } if (!success) { switch (ParamErrorMethod) { case paramErrorType.eDefaultValue: ret = OMV.Vector3.Zero; break; case paramErrorType.eException: throw new ParameterException("Float param '" + key + "' not found"); case paramErrorType.eNullValue: ret = OMV.Vector3.Zero; break; } } return(ret); }
public override void UpdateProperties(EntityProperties entprop) { // Undo any center-of-mass displacement that might have been done. if (PositionDisplacement != OMV.Vector3.Zero || OrientationDisplacement != OMV.Quaternion.Identity) { // Correct for any rotation around the center-of-mass // TODO!!! OMV.Vector3 displacedPos = entprop.Position + (PositionDisplacement * entprop.Rotation); DetailLog("{0},BSPrimDisplaced.ForcePosition,physPos={1},disp={2},newPos={3}", LocalID, entprop.Position, PositionDisplacement, displacedPos); entprop.Position = displacedPos; // entprop.Rotation = something; } base.UpdateProperties(entprop); }
private void FixCoordinateSystem(ref Vector3 position, ref Quaternion rotation) { //center the object var centerPos = position + _centerAdj; //change coordinate system centerPos.X = -centerPos.X; //re-translate the object position = centerPos - _centerAdj; //compensate Y/Z flip var fixRot = Quaternion.CreateFromAxisAngle(1.0f, 0.0f, 0.0f, -(float)Math.PI / 2f); position = position * fixRot; rotation = fixRot * rotation; }
private void ComputeAvatarScale(OMV.Vector3 size) { OMV.Vector3 newScale = size; // newScale.X = PhysicsScene.Params.avatarCapsuleWidth; // newScale.Y = PhysicsScene.Params.avatarCapsuleDepth; // From the total height, remove the capsule half spheres that are at each end // The 1.15f came from ODE. Not sure what this factors in. // newScale.Z = (size.Z * 1.15f) - (newScale.X + newScale.Y); // The total scale height is the central cylindar plus the caps on the two ends. newScale.Z = size.Z + (Math.Min(size.X, size.Y) * 2f); // Convert diameters to radii and height to half height -- the way Bullet expects it. Scale = newScale / 2f; }
public override bool Collide(uint collidingWith, BSPhysObject collidee, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) { // prims in the same linkset cannot collide with each other BSPrimLinkable convCollidee = collidee as BSPrimLinkable; if (convCollidee != null && (this.Linkset.LinksetID == convCollidee.Linkset.LinksetID)) { return(false); } // TODO: handle collisions of other objects with with children of linkset. // This is a problem for LinksetCompound since the children are packed into the root. return(base.Collide(collidingWith, collidee, contactPoint, contactNormal, pentrationDepth)); }
// Usually called when target velocity changes to set the current velocity and the target // into the movement motor. public void SetVelocityAndTarget(OMV.Vector3 vel, OMV.Vector3 targ, bool inTaintTime) { m_physicsScene.TaintedObject(inTaintTime, m_controllingPrim.LocalID, "BSActorAvatarMove.setVelocityAndTarget", delegate() { if (m_velocityMotor != null) { m_velocityMotor.Reset(); m_velocityMotor.SetTarget(targ); m_velocityMotor.SetCurrent(vel); m_velocityMotor.Enabled = true; m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,SetVelocityAndTarget,vel={1}, targ={2}", m_controllingPrim.LocalID, vel, targ); m_waitingForLowVelocityForStationary = 0; } }); }
public virtual void ComputeAndSetLocalInertia(OMV.Vector3 inertiaFactor, float linksetMass) { ForEachMember((member) => { if (member.PhysBody.HasPhysicalBody) { OMV.Vector3 inertia = PhysicsScene.PE.CalculateLocalInertia(member.PhysShape.physShapeInfo, linksetMass); member.Inertia = inertia * inertiaFactor; PhysicsScene.PE.SetMassProps(member.PhysBody, linksetMass, member.Inertia); PhysicsScene.PE.UpdateInertiaTensor(member.PhysBody); DetailLog("{0},BSLinkset.ComputeAndSetLocalInertia,m.mass={1}, inertia={2}", member.LocalID, linksetMass, member.Inertia); } return(false); // 'false' says to continue looping } ); }
public void Update() { if (setClearFlags == false) { Camera.main.clearFlags = CameraClearFlags.Skybox; setClearFlags = true; } OpenMetaverse.Vector3 camPos = Client.Self.SimPosition + new OpenMetaverse.Vector3(-4, 0, 1) * Client.Self.Movement.BodyRotation; Camera.main.transform.position = new UnityEngine.Vector3(camPos.X, camPos.Y, -camPos.Z); //watch out the negated z OpenMetaverse.Vector3 focalPos = Client.Self.SimPosition + new OpenMetaverse.Vector3(5, 0, 0) * Client.Self.Movement.BodyRotation; Camera.main.transform.LookAt(new UnityEngine.Vector3(focalPos.X, focalPos.Y, -focalPos.Z), UnityEngine.Vector3.back); //watch out the negated z }
// Walk through all the vertices and scale the included meshes // Returns 'true' of the mesh was changed. public static bool ScaleMeshes(MeshInfo meshInfo, OMV.Vector3 scale) { bool ret = false; if (scale.X != 1.0 || scale.Y != 1.0 || scale.Z != 1.0) { ret = true; for (int ii = 0; ii < meshInfo.vertexs.Count; ii++) { OMVR.Vertex aVert = meshInfo.vertexs[ii]; aVert.Position *= scale; meshInfo.vertexs[ii] = aVert; } } return(ret); }
public LSL_List modInvokeL(string fname, params object[] parms) { Type returntype = m_comms.LookupReturnType(fname); if (returntype != typeof(object[])) { MODError(String.Format("return type mismatch for {0}", fname)); } object[] result = (object[])modInvoke(fname, parms); object[] llist = new object[result.Length]; for (int i = 0; i < result.Length; i++) { if (result[i] is string) { llist[i] = new LSL_String((string)result[i]); } else if (result[i] is int) { llist[i] = new LSL_Integer((int)result[i]); } else if (result[i] is float) { llist[i] = new LSL_Float((float)result[i]); } else if (result[i] is UUID) { llist[i] = new LSL_Key(result[i].ToString()); } else if (result[i] is OpenMetaverse.Vector3) { OpenMetaverse.Vector3 vresult = (OpenMetaverse.Vector3)result[i]; llist[i] = new LSL_Vector(vresult.X, vresult.Y, vresult.Z); } else if (result[i] is OpenMetaverse.Quaternion) { OpenMetaverse.Quaternion qresult = (OpenMetaverse.Quaternion)result[i]; llist[i] = new LSL_Rotation(qresult.X, qresult.Y, qresult.Z, qresult.W); } else { MODError(String.Format("unknown list element {1} returned by {0}", fname, result[i].GetType().Name)); } } return(new LSL_List(llist)); }
protected BSPhysObject(BSScene parentScene, uint localID, string name, string typeName) { IsInitialized = false; PhysScene = parentScene; LocalID = localID; PhysObjectName = name; Name = name; // PhysicsActor also has the name of the object. Someday consolidate. TypeName = typeName; // Oddity if object is destroyed and recreated very quickly it could still have the old body. if (!PhysBody.HasPhysicalBody) { PhysBody = new BulletBody(localID); } // Clean out anything that might be in the physical actor list. // Again, a workaround for destroying and recreating an object very quickly. PhysicalActors.Dispose(); UserSetCenterOfMassDisplacement = null; PrimAssetState = PrimAssetCondition.Unknown; // Initialize variables kept in base. // Beware that these cause taints to be queued whch can cause race conditions on startup. GravModifier = 1.0f; Gravity = new OMV.Vector3(0f, 0f, BSParam.Gravity); HoverActive = false; // Default material type. Also sets Friction, Restitution and Density. SetMaterial((int)MaterialAttributes.Material.Wood); CollisionsLastTickStep = -1; SubscribedEventsMs = 0; // Crazy values that will never be true CollidingStep = BSScene.NotASimulationStep; CollidingGroundStep = BSScene.NotASimulationStep; CollisionAccumulation = BSScene.NotASimulationStep; ColliderIsMoving = false; CollisionScore = 0; // All axis free. LockedLinearAxis = LockedAxisFree; LockedAngularAxis = LockedAxisFree; }
/// <summary> /// Determines whether a collision is valid, and updates appropriate /// collision flags. /// </summary> /// <param name="colliderID">The unique identifier of the object that /// is colliding</param> /// <param name="collider">The object that is colliding</param> /// <param name="contactPoint">The point at which contact was /// made</param> /// <param name="contactNormal">The normal of the contact point</param> /// <param name="penetrationDepth">How far one collider has penetrated /// the other</param> /// <returns>Whether the collision is valid</returns> public virtual bool Collide(uint colliderID, RemotePhysicsObject collider, OpenMetaverse.Vector3 contactPoint, OpenMetaverse.Vector3 contactNormal, float penetrationDepth) { lock (m_collisionStepLock) { // Update the step at which a collision has occurred LastCollisionStep = ParentScene.CurrentSimulationStep; // Check to see if this is a collision with terrain if (colliderID <= ParentScene.TerrainID) { GroundCollisionStep = ParentScene.CurrentSimulationStep; } else { ObjectCollisionStep = ParentScene.CurrentSimulationStep; } } // Update the number of collisions for this object NumCollisions++; // Check to see if something is subscribed to events from // this object if (SubscribedEvents()) { // Add this collision to the collection of collisions to be sent // back to the simulator at the next update, in a // thread-safe manner lock (Collisions) { Collisions.AddCollider(colliderID, new ContactPoint(contactPoint, contactNormal, penetrationDepth)); } // Indicate that the collision has been successfully processed return(true); } else { // Indicate that the collision wasn't processed, since there are // no subscribers to this object return(false); } }
public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying) { base.BaseInitialize(parent_scene, localID, avName, "BSCharacter"); _physicsActorType = (int)ActorTypes.Agent; _position = pos; _size = size; _flying = isFlying; _orientation = OMV.Quaternion.Identity; _velocity = OMV.Vector3.Zero; _appliedVelocity = OMV.Vector3.Zero; _buoyancy = ComputeBuoyancyFromFlying(isFlying); _currentFriction = PhysicsScene.Params.avatarStandingFriction; _avatarDensity = PhysicsScene.Params.avatarDensity; // The dimensions of the avatar capsule are kept in the scale. // Physics creates a unit capsule which is scaled by the physics engine. ComputeAvatarScale(_size); // set _avatarVolume and _mass based on capsule size, _density and Scale ComputeAvatarVolumeAndMass(); DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}", LocalID, _size, Scale, _avatarDensity, _avatarVolume, MassRaw); ShapeData shapeData = new ShapeData(); shapeData.ID = LocalID; shapeData.Type = ShapeData.PhysicsShapeType.SHAPE_AVATAR; shapeData.Position = _position; shapeData.Rotation = _orientation; shapeData.Velocity = _velocity; shapeData.Size = Scale; // capsule is a native shape but scale is not just <1,1,1> shapeData.Scale = Scale; shapeData.Mass = _mass; shapeData.Buoyancy = _buoyancy; shapeData.Static = ShapeData.numericFalse; shapeData.Friction = PhysicsScene.Params.avatarStandingFriction; shapeData.Restitution = PhysicsScene.Params.avatarRestitution; // do actual create at taint time PhysicsScene.TaintedObject("BSCharacter.create", delegate() { DetailLog("{0},BSCharacter.create,taint", LocalID); // New body and shape into BSBody and BSShape PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this, shapeData, null, null, null); SetPhysicalProperties(); }); return; }
public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying) : base(parent_scene, localID, avName, "BSCharacter") { _physicsActorType = (int)ActorTypes.Agent; _position = pos; _flying = isFlying; _orientation = OMV.Quaternion.Identity; _velocity = OMV.Vector3.Zero; _buoyancy = ComputeBuoyancyFromFlying(isFlying); _currentFriction = BSParam.AvatarStandingFriction; _avatarDensity = BSParam.AvatarDensity; // Old versions of ScenePresence passed only the height. If width and/or depth are zero, // replace with the default values. _size = size; if (_size.X == 0f) { _size.X = BSParam.AvatarCapsuleDepth; } if (_size.Y == 0f) { _size.Y = BSParam.AvatarCapsuleWidth; } // The dimensions of the physical capsule are kept in the scale. // Physics creates a unit capsule which is scaled by the physics engine. Scale = ComputeAvatarScale(_size); // set _avatarVolume and _mass based on capsule size, _density and Scale ComputeAvatarVolumeAndMass(); SetupMovementMotor(); DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}", LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass); // do actual creation in taint time PhysicsScene.TaintedObject("BSCharacter.create", delegate() { DetailLog("{0},BSCharacter.create,taint", LocalID); // New body and shape into PhysBody and PhysShape PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this); SetPhysicalProperties(); }); return; }
// The physics engine says that properties have updated. Update same and inform // the world that things have changed. public override void UpdateProperties(EntityProperties entprop) { // Don't change position if standing on a stationary object. if (!IsStationary) { _position = entprop.Position; } _orientation = entprop.Rotation; if (entprop.Velocity != OMV.Vector3.Zero && entprop.Velocity.ApproxEquals(OMV.Vector3.Zero, 0.01f) && Velocity != OMV.Vector3.Zero) { entprop.Velocity = OMV.Vector3.Zero; entprop.Acceleration = OMV.Vector3.Zero; entprop.RotationalVelocity = OMV.Vector3.Zero; Velocity = OMV.Vector3.Zero; TriggerSignificantMovement(); TriggerMovementUpdate(); } if (!entprop.Velocity.ApproxEquals(RawVelocity, 0.4f)) { RawVelocity = entprop.Velocity; TriggerSignificantMovement(); TriggerMovementUpdate(); } _acceleration = entprop.Acceleration; _rotationalVelocity = entprop.RotationalVelocity; // Do some sanity checking for the avatar. Make sure it's above ground and inbounds. if (PositionSanityCheck(true)) { DetailLog("{0},BSCharacter.UpdateProperties,updatePosForSanity,pos={1}", LocalID, _position); entprop.Position = _position; } // remember the current and last set values LastEntityProperties = CurrentEntityProperties; CurrentEntityProperties = entprop; DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", LocalID, _position, _orientation, RawVelocity, _acceleration, _rotationalVelocity); }
public BSCharacter( uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 vel, OMV.Vector3 size, float footOffset, bool isFlying) : base(parent_scene, localID, avName, "BSCharacter") { _physicsActorType = (int)ActorTypes.Agent; RawPosition = pos; _flying = isFlying; RawOrientation = OMV.Quaternion.Identity; RawVelocity = vel; _buoyancy = ComputeBuoyancyFromFlying(isFlying); Friction = BSParam.AvatarStandingFriction; Density = BSParam.AvatarDensity; _isPhysical = true; _footOffset = footOffset; // Adjustments for zero X and Y made in Size() // This also computes avatar scale, volume, and mass SetAvatarSize(size, footOffset, true /* initializing */); DetailLog( "{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5},pos={6},vel={7}", LocalID, Size, Scale, Density, _avatarVolume, RawMass, pos, vel); // do actual creation in taint time PhysScene.TaintedObject(LocalID, "BSCharacter.create", delegate() { DetailLog("{0},BSCharacter.create,taint", LocalID); // New body and shape into PhysBody and PhysShape PhysScene.Shapes.GetBodyAndShape(true, PhysScene.World, this); // The avatar's movement is controlled by this motor that speeds up and slows down // the avatar seeking to reach the motor's target speed. // This motor runs as a prestep action for the avatar so it will keep the avatar // standing as well as moving. Destruction of the avatar will destroy the pre-step action. m_moveActor = new BSActorAvatarMove(PhysScene, this, AvatarMoveActorName); PhysicalActors.Add(AvatarMoveActorName, m_moveActor); SetPhysicalProperties(); IsInitialized = true; }); return; }
protected BSPhysObject(BSScene parentScene, uint localID, string name, string typeName) { IsInitialized = false; PhysScene = parentScene; LocalID = localID; PhysObjectName = name; Name = name; // PhysicsActor also has the name of the object. Someday consolidate. TypeName = typeName; // The collection of things that push me around PhysicalActors = new BSActorCollection(PhysScene); // Initialize variables kept in base. GravModifier = 1.0f; Gravity = new OMV.Vector3(0f, 0f, BSParam.Gravity); HoverActive = false; // We don't have any physical representation yet. PhysBody = new BulletBody(localID); PhysShape = new BSShapeNull(); UserSetCenterOfMassDisplacement = null; PrimAssetState = PrimAssetCondition.Unknown; // Default material type. Also sets Friction, Restitution and Density. SetMaterial((int)MaterialAttributes.Material.Wood); CollisionCollection = new CollisionEventUpdate(); CollisionsLastReported = CollisionCollection; CollisionsLastTick = new CollisionEventUpdate(); CollisionsLastTickStep = -1; SubscribedEventsMs = 0; // Crazy values that will never be true CollidingStep = BSScene.NotASimulationStep; CollidingGroundStep = BSScene.NotASimulationStep; CollisionAccumulation = BSScene.NotASimulationStep; ColliderIsMoving = false; CollisionScore = 0; // All axis free. LockedLinearAxis = LockedAxisFree; LockedAngularAxis = LockedAxisFree; }
public void Set(float x, float y, float z) { if (float.IsInfinity(x) || float.IsNaN(x)) { x = 0f; } if (float.IsInfinity(y) || float.IsNaN(y)) { y = 0f; } if (float.IsInfinity(z) || float.IsNaN(z)) { z = 0f; } _impl = new Vector3(x, y, z); }
public BSPrimLinkable(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical, int material, float friction, float restitution, float gravityMultiplier, float density) : base(localID, primName, parent_scene, pos, size, rotation, pbs, pisPhysical) { Linkset = BSLinkset.Factory(PhysicsScene, this); PhysicsScene.TaintedObject("BSPrimLinksetCompound.Refresh", delegate() { base.SetMaterial(material); base.Friction = friction; base.Restitution = restitution; base.GravityMultiplier = gravityMultiplier; base.Density = density; Linkset.Refresh(this); }); }
// A version of the sanity check that also makes sure a new position value is // pushed back to the physics engine. This routine would be used by anyone // who is not already pushing the value. private bool PositionSanityCheck(bool inTaintTime) { bool ret = false; if (PositionSanityCheck()) { // The new position value must be pushed into the physics engine but we can't // just assign to "Position" because of potential call loops. PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.PositionSanityCheck", delegate() { DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation); ForcePosition = RawPosition; }); ret = true; } return(ret); }
// Usually called when target velocity changes to set the current velocity and the target // into the movement motor. public void SetVelocityAndTarget(OMV.Vector3 vel, OMV.Vector3 targ, bool inTaintTime) { m_physicsScene.TaintedObject(inTaintTime, m_controllingPrim.LocalID, "BSActorAvatarMove.setVelocityAndTarget", delegate() { if (m_velocityMotor != null) { // if (targ == OMV.Vector3.Zero) // Util.PrintCallStack(); // // Console.WriteLine("SetVelocityAndTarget, {0} {1}", vel, targ); m_velocityMotor.Reset(); m_velocityMotor.SetTarget(targ); m_velocityMotor.SetCurrent(vel); m_velocityMotor.Enabled = true; } }); }
// Decide if the character is colliding with a low object and compute a force to pop the // avatar up so it can walk up and over the low objects. private OMV.Vector3 WalkUpStairs() { OMV.Vector3 ret = OMV.Vector3.Zero; // This test is done if moving forward, not flying and is colliding with something. if (m_controllingPrim.IsColliding && !m_controllingPrim.Flying && m_controllingPrim.TargetVelocitySpeed > 0.1f /* && ForwardSpeed < 0.1f */) { // The range near the character's feet where we will consider stairs float nearFeetHeightMin = m_controllingPrim.RawPosition.Z - (m_controllingPrim.Size.Z / 2f) + 0.05f; float nearFeetHeightMax = nearFeetHeightMin + BSParam.AvatarStepHeight; // Look for a collision point that is near the character's feet and is oriented the same as the charactor is foreach (KeyValuePair <uint, ContactPoint> kvp in m_controllingPrim.CollisionsLastTick.GetCollisionEvents()) { // Don't care about collisions with the terrain if (kvp.Key > m_physicsScene.TerrainManager.HighestTerrainID) { OMV.Vector3 touchPosition = kvp.Value.Position; if (touchPosition.Z >= nearFeetHeightMin && touchPosition.Z <= nearFeetHeightMax) { // This contact is within the 'near the feet' range. // The normal should be our contact point to the object so it is pointing away // thus the difference between our facing orientation and the normal should be small. OMV.Vector3 directionFacing = OMV.Vector3.UnitX * m_controllingPrim.RawOrientation; OMV.Vector3 touchNormal = OMV.Vector3.Normalize(kvp.Value.SurfaceNormal); float diff = Math.Abs(OMV.Vector3.Distance(directionFacing, touchNormal)); if (diff < BSParam.AvatarStepApproachFactor) { // Found the stairs contact point. Push up a little to raise the character. float upForce = (touchPosition.Z - nearFeetHeightMin) * m_controllingPrim.Mass * BSParam.AvatarStepForceFactor; ret = new OMV.Vector3(0f, 0f, upForce); // Also move the avatar up for the new height OMV.Vector3 displacement = new OMV.Vector3(0f, 0f, BSParam.AvatarStepHeight / 2f); m_controllingPrim.ForcePosition = m_controllingPrim.RawPosition + displacement; } m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,touchPos={1},nearFeetMin={2},faceDir={3},norm={4},diff={5},ret={6}", m_controllingPrim.LocalID, touchPosition, nearFeetHeightMin, directionFacing, touchNormal, diff, ret); } } } } return(ret); }
// tell the renderer about the camera position public void UpdateCamera(CameraControl cam) { if (m_focusRegion != null) { OMV.Vector3 newPos = new OMV.Vector3(); newPos.X = (float)(cam.GlobalPosition.X - m_focusRegion.GlobalPosition.X); newPos.Y = (float)(cam.GlobalPosition.Y - m_focusRegion.GlobalPosition.Y); // another kludge camera offset. Pairs with position kludge in Viewer. newPos.Z = (float)(cam.GlobalPosition.Z - m_focusRegion.GlobalPosition.Z) + 10f; m_log.Log(LogLevel.DRENDERDETAIL, "UpdateCamera: g={0}, f={1}, n={2}", cam.GlobalPosition.ToString(), m_focusRegion.GlobalPosition.ToString(), newPos.ToString()); Camera.Position = newPos; OMV.Vector3 dir = new OMV.Vector3(1f, 0f, 0f); Camera.FocalPoint = (dir * cam.Heading) + Camera.Position; } return; }
public virtual bool Collide(uint collidingWith, BSPhysObject collidee, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) { bool ret = false; // The following lines make IsColliding(), CollidingGround() and CollidingObj work CollidingStep = PhysScene.SimulationStep; if (collidingWith <= PhysScene.TerrainManager.HighestTerrainID) { CollidingGroundStep = PhysScene.SimulationStep; } else { CollidingObjectStep = PhysScene.SimulationStep; } CollisionAccumulation++; // For movement tests, remember if we are colliding with an object that is moving. ColliderIsMoving = collidee != null ? (collidee.RawVelocity != OMV.Vector3.Zero) : false; ColliderIsVolumeDetect = collidee != null ? (collidee.IsVolumeDetect) : false; // Make a collection of the collisions that happened the last simulation tick. // This is different than the collection created for sending up to the simulator as it is cleared every tick. if (CollisionsLastTickStep != PhysScene.SimulationStep) { CollisionsLastTick = new CollisionEventUpdate(); CollisionsLastTickStep = PhysScene.SimulationStep; } CollisionsLastTick.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); // If someone has subscribed for collision events log the collision so it will be reported up if (SubscribedEvents()) { lock (PhysScene.CollisionLock) { CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); } DetailLog("{0},{1}.Collision.AddCollider,call,with={2},point={3},normal={4},depth={5},colliderMoving={6}", LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth, ColliderIsMoving); ret = true; } return(ret); }
public BasicActor(BasicScene scene, float height, float radius, OpenMetaverse.Vector3 position, OpenMetaverse.Quaternion rotation, bool flying, OpenMetaverse.Vector3 initialVelocity) { _scene = scene; _radius = Math.Max(radius, 0.2f); /* * The capsule is defined as a position, a vertical height, and a radius. The height is the distance between the * two sphere centers at the end of the capsule. In other words: * * p = pos (returned by controller) * h = height * r = radius * * p = center of capsule * top sphere center = p.z + h*0.5 * bottom sphere center = p.z - h*0.5 * top capsule point = p.z + h*0.5 + r * bottom capsule point = p.z - h*0.5 - r */ _height = height; _flying = flying; float volume = (float)(Math.PI * Math.Pow(_radius, 2) * this.CapsuleHeight); _mass = CHARACTER_DENSITY * volume; _position = position; _rotation = rotation; DoZDepenetration(); _lastSync = (uint)Environment.TickCount; _vTarget = initialVelocity; _velocity = initialVelocity; if (_vTarget != OpenMetaverse.Vector3.Zero) { //hack to continue at velocity until the controller picks up _lastVelocityNonZero = OpenSim.Framework.Util.GetLongTickCount() - VELOCITY_RAMPUP_TIME; } }
// The physics engine says that properties have updated. Update same and inform // the world that things have changed. public override void UpdateProperties(EntityProperties entprop) { _position = entprop.Position; _orientation = entprop.Rotation; _velocity = entprop.Velocity; _acceleration = entprop.Acceleration; _rotationalVelocity = entprop.RotationalVelocity; // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. // base.RequestPhysicsterseUpdate(); // Do some sanity checking for the avatar. Make sure it's above ground and inbounds. PositionSanityCheck2(); float heightHere = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); // only for debug DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5},terrain={6}", LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity, heightHere); }
public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying) : base(parent_scene, localID, avName, "BSCharacter") { _physicsActorType = (int)ActorTypes.Agent; _position = pos; _flying = isFlying; _orientation = OMV.Quaternion.Identity; _velocity = OMV.Vector3.Zero; _buoyancy = ComputeBuoyancyFromFlying(isFlying); _currentFriction = BSParam.AvatarStandingFriction; _avatarDensity = BSParam.AvatarDensity; // Old versions of ScenePresence passed only the height. If width and/or depth are zero, // replace with the default values. _size = size; if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth; if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth; // The dimensions of the physical capsule are kept in the scale. // Physics creates a unit capsule which is scaled by the physics engine. Scale = ComputeAvatarScale(_size); // set _avatarVolume and _mass based on capsule size, _density and Scale ComputeAvatarVolumeAndMass(); SetupMovementMotor(); DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}", LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass); // do actual creation in taint time PhysicsScene.TaintedObject("BSCharacter.create", delegate() { DetailLog("{0},BSCharacter.create,taint", LocalID); // New body and shape into PhysBody and PhysShape PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this); SetPhysicalProperties(); }); return; }
public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) : base(parent_scene, localID, primName, "BSPrim") { // MainConsole.Instance.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID); _physicsActorType = (int)ActorTypes.Prim; _position = pos; _size = size; Scale = size; // prims are the size the user wants them to be (different for BSCharactes). _orientation = rotation; _buoyancy = 0f; RawVelocity = OMV.Vector3.Zero; _rotationalVelocity = OMV.Vector3.Zero; BaseShape = pbs; _isPhysical = pisPhysical; _isVolumeDetect = false; // Add a dynamic vehicle to our set of actors that can move this prim. VehicleActor = new BSDynamics(PhysicsScene, this, VehicleActorName); PhysicalActors.Add(VehicleActorName, VehicleActor); //PhysicalActors.Add(VehicleActorName, new BSDynamics(PhysicsScene, this, VehicleActorName)); _mass = CalculateMass(); // DetailLog("{0},BSPrim.constructor,call", LocalID); // do the actual object creation at taint time PhysicsScene.TaintedObject(LocalID, "BSPrim.create", delegate() { // Make sure the object is being created with some sanity. ExtremeSanityCheck(true /* inTaintTime */); CreateGeomAndObject(true); CurrentCollisionFlags = PhysicsScene.PE.GetCollisionFlags(PhysBody); IsInitialized = true; }); }
public LLRegionContext(RegionContextBase rcontext, AssetContextBase acontext, LLTerrainInfo tinfo, OMV.Simulator sim) : base(rcontext, acontext) { m_terrainInfo = tinfo; // until we have a better protocol, we know the sims are a fixed size m_size = new OMV.Vector3(256f, 256f, 8000f); // believe it or not the world coordinates of a sim are hidden in the handle uint x, y; OMV.Utils.LongToUInts(sim.Handle, out x, out y); m_worldBase = new OMV.Vector3d((double)x, (double)y, 0d); m_simulator = sim; // this should be more general as "GRID/SIM" m_name = new EntityName(sim.Name); // a cache of requested localIDs so we don't ask too often m_recentLocalIDRequests = new Dictionary<uint, int>(); this.RegisterInterface<LLRegionContext>(this); }
/// <summary> /// When multiple regions are displayed, there is a focus region (the one the main avatar /// is in) and other regions that are offset from that focus region. Here we come up with /// that offset. /// </summary> /// <param name="rcontext"></param> /// <returns></returns> private OMV.Vector3 CalcRegionOffset(RegionContextBase rcontext) { if (rcontext == m_renderer.m_focusRegion) return OMV.Vector3.Zero; OMV.Vector3 ret = new OMV.Vector3(); ret.X = (float)(m_renderer.m_focusRegion.GlobalPosition.X - rcontext.GlobalPosition.X); ret.Y = (float)(m_renderer.m_focusRegion.GlobalPosition.Y - rcontext.GlobalPosition.Y); ret.Z = (float)(m_renderer.m_focusRegion.GlobalPosition.Z - rcontext.GlobalPosition.Z); return ret; }
// Decide if the character is colliding with a low object and compute a force to pop the // avatar up so it can walk up and over the low objects. private OMV.Vector3 WalkUpStairs() { OMV.Vector3 ret = OMV.Vector3.Zero; // This test is done if moving forward, not flying and is colliding with something. // DetailLog("{0},BSCharacter.WalkUpStairs,IsColliding={1},flying={2},targSpeed={3},collisions={4}", // LocalID, IsColliding, Flying, TargetSpeed, CollisionsLastTick.Count); if (m_controllingPrim.IsColliding && !m_controllingPrim.Flying && m_controllingPrim.TargetVelocitySpeed > 0.1f /* && ForwardSpeed < 0.1f */) { // The range near the character's feet where we will consider stairs float nearFeetHeightMin = m_controllingPrim.RawPosition.Z - (m_controllingPrim.Size.Z / 2f) + 0.05f; float nearFeetHeightMax = nearFeetHeightMin + BSParam.AvatarStepHeight; // Look for a collision point that is near the character's feet and is oriented the same as the charactor is foreach (KeyValuePair<uint, ContactPoint> kvp in m_controllingPrim.CollisionsLastTick.GetCollisionEvents()) { // Don't care about collisions with the terrain if (kvp.Key > m_physicsScene.TerrainManager.HighestTerrainID) { OMV.Vector3 touchPosition = kvp.Value.Position; // DetailLog("{0},BSCharacter.WalkUpStairs,min={1},max={2},touch={3}", // LocalID, nearFeetHeightMin, nearFeetHeightMax, touchPosition); if (touchPosition.Z >= nearFeetHeightMin && touchPosition.Z <= nearFeetHeightMax) { // This contact is within the 'near the feet' range. // The normal should be our contact point to the object so it is pointing away // thus the difference between our facing orientation and the normal should be small. OMV.Vector3 directionFacing = OMV.Vector3.UnitX * m_controllingPrim.RawOrientation; OMV.Vector3 touchNormal = OMV.Vector3.Normalize(kvp.Value.SurfaceNormal); float diff = Math.Abs(OMV.Vector3.Distance(directionFacing, touchNormal)); if (diff < BSParam.AvatarStepApproachFactor) { // Found the stairs contact point. Push up a little to raise the character. float upForce = (touchPosition.Z - nearFeetHeightMin) * m_controllingPrim.Mass * BSParam.AvatarStepForceFactor; ret = new OMV.Vector3(0f, 0f, upForce); // Also move the avatar up for the new height OMV.Vector3 displacement = new OMV.Vector3(0f, 0f, BSParam.AvatarStepHeight / 2f); m_controllingPrim.ForcePosition = m_controllingPrim.RawPosition + displacement; } m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,touchPos={1},nearFeetMin={2},faceDir={3},norm={4},diff={5},ret={6}", m_controllingPrim.LocalID, touchPosition, nearFeetHeightMin, directionFacing, touchNormal, diff, ret); } } } } return ret; }
// Usually called when target velocity changes to set the current velocity and the target // into the movement motor. public void SetVelocityAndTarget(OMV.Vector3 vel, OMV.Vector3 targ, bool inTaintTime, int targetValueDecayTimeScale) { if (m_disallowTargetVelocitySet) { if (m_controllingPrim.Flying && (m_controllingPrim.IsJumping || m_controllingPrim.IsPreJumping))//They started flying while jumping { m_physicsScene.TaintedObject("BSCharacter.setTargetVelocity", delegate() { //Reset everything in case something went wrong m_disallowTargetVelocitySet = false; m_jumpFallState = false; m_controllingPrim.IsPreJumping = false; m_controllingPrim.IsJumping = false; m_jumpStart = 0; m_preJumpStart = 0; }); } return; } if (!m_controllingPrim.Flying && m_controllingPrim.IsColliding && targ.Z >= 0.5f) { m_controllingPrim.IsPreJumping = true; m_disallowTargetVelocitySet = true; m_jumpDirection = targ; m_preJumpStart = Util.EnvironmentTickCount(); return; } SetVelocityAndTargetInternal(vel, targ, inTaintTime, targetValueDecayTimeScale); }
// No locking here because this is done when we know physics is not simulating private void CreateGeomMesh() { float lod = _pbs.SculptEntry ? _scene.SculptLOD : _scene.MeshLOD; ulong newMeshKey = (ulong)_pbs.GetMeshKey(_size, lod); // m_log.DebugFormat("{0}: CreateGeomMesh: lID={1}, oldKey={2}, newKey={3}", LogHeader, _localID, _meshKey, newMeshKey); // if this new shape is the same as last time, don't recreate the mesh if (_meshKey == newMeshKey) return; // Since we're recreating new, get rid of any previously generated shape if (_meshKey != 0) { // m_log.DebugFormat("{0}: CreateGeom: deleting old mesh. lID={1}, Key={2}", LogHeader, _localID, _meshKey); BulletSimAPI.DestroyMesh(_scene.WorldID, _meshKey); _mesh = null; _meshKey = 0; } _meshKey = newMeshKey; // always pass false for physicalness as this creates some sort of bounding box which we don't need _mesh = _scene.mesher.CreateMesh(_avName, _pbs, _size, lod, false); int[] indices = _mesh.getIndexListAsInt(); List<OMV.Vector3> vertices = _mesh.getVertexList(); float[] verticesAsFloats = new float[vertices.Count * 3]; int vi = 0; foreach (OMV.Vector3 vv in vertices) { // m_log.DebugFormat("{0}: {1}: <{2:0.00}, {3:0.00}, {4:0.00}>", LogHeader, vi / 3, vv.X, vv.Y, vv.Z); verticesAsFloats[vi++] = vv.X; verticesAsFloats[vi++] = vv.Y; verticesAsFloats[vi++] = vv.Z; } // m_log.DebugFormat("{0}: CreateGeomMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}", // LogHeader, _localID, _meshKey, indices.Length, vertices.Count); BulletSimAPI.CreateMesh(_scene.WorldID, _meshKey, indices.GetLength(0), indices, vertices.Count, verticesAsFloats); _shapeType = ShapeData.PhysicsShapeType.SHAPE_MESH; // meshes are already scaled by the meshmerizer _scale = new OMV.Vector3(1f, 1f, 1f); return; }
}// end CalculateMass #endregion Mass Calculation // Create the geometry information in Bullet for later use // The objects needs a hull if it's physical otherwise a mesh is enough // No locking here because this is done when we know physics is not simulating // if 'forceRebuild' is true, the geometry is rebuilt. Otherwise a previously built version is used private void CreateGeom(bool forceRebuild) { // the mesher thought this was too simple to mesh. Use a native Bullet collision shape. if (!_scene.NeedsMeshing(_pbs)) { if (_pbs.ProfileShape == ProfileShape.HalfCircle && _pbs.PathCurve == (byte)Extrusion.Curve1) { if (_size.X == _size.Y && _size.Y == _size.Z && _size.X == _size.Z) { // m_log.DebugFormat("{0}: CreateGeom: Defaulting to sphere of size {1}", LogHeader, _size); _shapeType = ShapeData.PhysicsShapeType.SHAPE_SPHERE; // Bullet native objects are scaled by the Bullet engine so pass the size in _scale = _size; } } else { // m_log.DebugFormat("{0}: CreateGeom: Defaulting to box. lid={1}, size={2}", LogHeader, LocalID, _size); _shapeType = ShapeData.PhysicsShapeType.SHAPE_BOX; _scale = _size; } } else { if (IsPhysical) { if (forceRebuild || _hullKey == 0) { // physical objects require a hull for interaction. // This will create the mesh if it doesn't already exist CreateGeomHull(); } } else { if (forceRebuild || _meshKey == 0) { // Static (non-physical) objects only need a mesh for bumping into CreateGeomMesh(); } } } }
// Set motion values to zero. // Do it to the properties so the values get set in the physics engine. // Push the setting of the values to the viewer. private void ZeroMotion() { Velocity = OMV.Vector3.Zero; _acceleration = OMV.Vector3.Zero; RotationalVelocity = OMV.Vector3.Zero; base.RequestPhysicsterseUpdate(); }
public void UpdateProperties(EntityProperties entprop) { UpdatedProperties changed = 0; if (SHOULD_DAMP_UPDATES) { // assign to the local variables so the normal set action does not happen // if (_position != entprop.Position) if (!_position.ApproxEquals(entprop.Position, POSITION_TOLERANCE)) { _position = entprop.Position; // m_log.DebugFormat("{0}: UpdateProperties: id={1}, pos = {2}", LogHeader, LocalID, _position); changed |= UpdatedProperties.Position; } // if (_orientation != entprop.Rotation) if (!_orientation.ApproxEquals(entprop.Rotation, ROTATION_TOLERANCE)) { _orientation = entprop.Rotation; // m_log.DebugFormat("{0}: UpdateProperties: id={1}, rot = {2}", LogHeader, LocalID, _orientation); changed |= UpdatedProperties.Rotation; } // if (_velocity != entprop.Velocity) if (!_velocity.ApproxEquals(entprop.Velocity, VELOCITY_TOLERANCE)) { _velocity = entprop.Velocity; // m_log.DebugFormat("{0}: UpdateProperties: velocity = {1}", LogHeader, _velocity); changed |= UpdatedProperties.Velocity; } // if (_acceleration != entprop.Acceleration) if (!_acceleration.ApproxEquals(entprop.Acceleration, ACCELERATION_TOLERANCE)) { _acceleration = entprop.Acceleration; // m_log.DebugFormat("{0}: UpdateProperties: acceleration = {1}", LogHeader, _acceleration); changed |= UpdatedProperties.Acceleration; } // if (_rotationalVelocity != entprop.RotationalVelocity) if (!_rotationalVelocity.ApproxEquals(entprop.RotationalVelocity, ROTATIONAL_VELOCITY_TOLERANCE)) { _rotationalVelocity = entprop.RotationalVelocity; // m_log.DebugFormat("{0}: UpdateProperties: rotationalVelocity = {1}", LogHeader, _rotationalVelocity); changed |= UpdatedProperties.RotationalVel; } if (changed != 0) { // m_log.DebugFormat("{0}: UpdateProperties: id={1}, c={2}, pos={3}, rot={4}", LogHeader, LocalID, changed, _position, _orientation); // Only update the position of single objects and linkset roots if (this._parentPrim == null) { // m_log.DebugFormat("{0}: RequestTerseUpdate. id={1}, ch={2}, pos={3}, rot={4}", LogHeader, LocalID, changed, _position, _orientation); base.RequestPhysicsterseUpdate(); } } } else { // Don't check for damping here -- it's done in BulletSim and SceneObjectPart. // Only updates only for individual prims and for the root object of a linkset. if (this._parentPrim == null) { // Assign to the local variables so the normal set action does not happen _position = entprop.Position; _orientation = entprop.Rotation; _velocity = entprop.Velocity; _acceleration = entprop.Acceleration; _rotationalVelocity = entprop.RotationalVelocity; // m_log.DebugFormat("{0}: RequestTerseUpdate. id={1}, ch={2}, pos={3}, rot={4}", LogHeader, LocalID, changed, _position, _orientation); base.RequestPhysicsterseUpdate(); } } }
public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) { // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID); _localID = localID; _avName = primName; _scene = parent_scene; _position = pos; _size = size; _scale = new OMV.Vector3(1f, 1f, 1f); // the scale will be set by CreateGeom depending on object type _orientation = rotation; _buoyancy = 1f; _velocity = OMV.Vector3.Zero; _rotationalVelocity = OMV.Vector3.Zero; _angularVelocity = OMV.Vector3.Zero; _hullKey = 0; _meshKey = 0; _pbs = pbs; _isPhysical = pisPhysical; _isVolumeDetect = false; _subscribedEventsMs = 0; _friction = _scene.Params.defaultFriction; // TODO: compute based on object material _density = _scene.Params.defaultDensity; // TODO: compute based on object material _restitution = _scene.Params.defaultRestitution; _parentPrim = null; // not a child or a parent _vehicle = new BSDynamics(this); // add vehicleness _childrenPrims = new List<BSPrim>(); if (_isPhysical) _mass = CalculateMass(); else _mass = 0f; // do the actual object creation at taint time _scene.TaintedObject(delegate() { RecreateGeomAndObject(); }); }
/// <summary> /// hook to the physics scene to apply angular impulse /// This is sent up to the group, which then finds the root prim /// and applies the force on the root prim of the group /// </summary> /// <param name="impulsei">Vector force</param> /// <param name="localGlobalTF">true for the local frame, false for the global frame</param> public void SetAngularImpulse(Vector3 impulsei, bool localGlobalTF) { OpenMetaverse.Vector3 impulse = new OpenMetaverse.Vector3(impulsei.X, impulsei.Y, impulsei.Z); if (localGlobalTF) { Quaternion grot = GetWorldRotation(); Quaternion AXgrot = grot; Vector3 AXimpulsei = impulsei; Vector3 newimpulse = AXimpulsei * AXgrot; impulse = new OpenMetaverse.Vector3(newimpulse.X, newimpulse.Y, newimpulse.Z); } if (m_parentGroup != null) { m_parentGroup.setAngularImpulse(impulse); } }
// The physics engine says that properties have updated. Update same and inform // the world that things have changed. public override void UpdateProperties(EntityProperties entprop) { // Let anyone (like the actors) modify the updated properties before they are pushed into the object and the simulator. TriggerPreUpdatePropertyAction(ref entprop); RawPosition = entprop.Position; RawOrientation = entprop.Rotation; // Smooth velocity. OpenSimulator is VERY sensitive to changes in velocity of the avatar // and will send agent updates to the clients if velocity changes by more than // 0.001m/s. Bullet introduces a lot of jitter in the velocity which causes many // extra updates. // // XXX: Contrary to the above comment, setting an update threshold here above 0.4 actually introduces jitter to // avatar movement rather than removes it. The larger the threshold, the bigger the jitter. // This is most noticeable in level flight and can be seen with // the "show updates" option in a viewer. With an update threshold, the RawVelocity cycles between a lower // bound and an upper bound, where the difference between the two is enough to trigger a large delta v update // and subsequently trigger an update in ScenePresence.SendTerseUpdateToAllClients(). The cause of this cycle (feedback?) // has not yet been identified. // // If there is a threshold below 0.4 or no threshold check at all (as in ODE), then RawVelocity stays constant and extra // updates are not triggered in ScenePresence.SendTerseUpdateToAllClients(). // if (!entprop.Velocity.ApproxEquals(RawVelocity, 0.1f)) RawVelocity = entprop.Velocity; _acceleration = entprop.Acceleration; _rotationalVelocity = entprop.RotationalVelocity; // Do some sanity checking for the avatar. Make sure it's above ground and inbounds. if (PositionSanityCheck(true)) { DetailLog("{0},BSCharacter.UpdateProperties,updatePosForSanity,pos={1}", LocalID, RawPosition); entprop.Position = RawPosition; } // remember the current and last set values LastEntityProperties = CurrentEntityProperties; CurrentEntityProperties = entprop; // Tell the linkset about value changes // Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this); // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. // PhysScene.PostUpdate(this); DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", LocalID, RawPosition, RawOrientation, RawVelocity, _acceleration, _rotationalVelocity); }
private OMV.Vector3 ComputeStairCorrection(float stepUp) { OMV.Vector3 ret = OMV.Vector3.Zero; OMV.Vector3 displacement = OMV.Vector3.Zero; if (stepUp > 0f) { // Found the stairs contact point. Push up a little to raise the character. if (BSParam.AvatarStepForceFactor > 0f) { float upForce = stepUp * m_controllingPrim.Mass * BSParam.AvatarStepForceFactor; ret = new OMV.Vector3(0f, 0f, upForce); } // Also move the avatar up for the new height if (BSParam.AvatarStepUpCorrectionFactor > 0f) { // Move the avatar up related to the height of the collision displacement = new OMV.Vector3(0f, 0f, stepUp * BSParam.AvatarStepUpCorrectionFactor); m_controllingPrim.ForcePosition = m_controllingPrim.RawPosition + displacement; } else { if (BSParam.AvatarStepUpCorrectionFactor < 0f) { // Move the avatar up about the specified step height displacement = new OMV.Vector3(0f, 0f, BSParam.AvatarStepHeight); m_controllingPrim.ForcePosition = m_controllingPrim.RawPosition + displacement; } } m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs.ComputeStairCorrection,disp={1},force={2}", m_controllingPrim.LocalID, displacement, ret); } return ret; }
// No locking here because this is done when we know physics is not simulating private void CreateGeomHull() { float lod = _pbs.SculptEntry ? _scene.SculptLOD : _scene.MeshLOD; ulong newHullKey = (ulong)_pbs.GetMeshKey(_size, lod); // m_log.DebugFormat("{0}: CreateGeomHull: lID={1}, oldKey={2}, newKey={3}", LogHeader, _localID, _hullKey, newHullKey); // if the hull hasn't changed, don't rebuild it if (newHullKey == _hullKey) return; // Since we're recreating new, get rid of any previously generated shape if (_hullKey != 0) { // m_log.DebugFormat("{0}: CreateGeom: deleting old hull. Key={1}", LogHeader, _hullKey); BulletSimAPI.DestroyHull(_scene.WorldID, _hullKey); _hullKey = 0; _hulls.Clear(); BulletSimAPI.DestroyMesh(_scene.WorldID, _meshKey); _mesh = null; // the mesh cannot match either _meshKey = 0; } _hullKey = newHullKey; if (_meshKey != _hullKey) { // if the underlying mesh has changed, rebuild it CreateGeomMesh(); } int[] indices = _mesh.getIndexListAsInt(); List<OMV.Vector3> vertices = _mesh.getVertexList(); //format conversion from IMesh format to DecompDesc format List<int> convIndices = new List<int>(); List<float3> convVertices = new List<float3>(); for (int ii = 0; ii < indices.GetLength(0); ii++) { convIndices.Add(indices[ii]); } foreach (OMV.Vector3 vv in vertices) { convVertices.Add(new float3(vv.X, vv.Y, vv.Z)); } // setup and do convex hull conversion _hulls = new List<ConvexResult>(); DecompDesc dcomp = new DecompDesc(); dcomp.mIndices = convIndices; dcomp.mVertices = convVertices; ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn); // create the hull into the _hulls variable convexBuilder.process(dcomp); // Convert the vertices and indices for passing to unmanaged // The hull information is passed as a large floating point array. // The format is: // convHulls[0] = number of hulls // convHulls[1] = number of vertices in first hull // convHulls[2] = hull centroid X coordinate // convHulls[3] = hull centroid Y coordinate // convHulls[4] = hull centroid Z coordinate // convHulls[5] = first hull vertex X // convHulls[6] = first hull vertex Y // convHulls[7] = first hull vertex Z // convHulls[8] = second hull vertex X // ... // convHulls[n] = number of vertices in second hull // convHulls[n+1] = second hull centroid X coordinate // ... // // TODO: is is very inefficient. Someday change the convex hull generator to return // data structures that do not need to be converted in order to pass to Bullet. // And maybe put the values directly into pinned memory rather than marshaling. int hullCount = _hulls.Count; int totalVertices = 1; // include one for the count of the hulls foreach (ConvexResult cr in _hulls) { totalVertices += 4; // add four for the vertex count and centroid totalVertices += cr.HullIndices.Count * 3; // we pass just triangles } float[] convHulls = new float[totalVertices]; convHulls[0] = (float)hullCount; int jj = 1; foreach (ConvexResult cr in _hulls) { // copy vertices for index access float3[] verts = new float3[cr.HullVertices.Count]; int kk = 0; foreach (float3 ff in cr.HullVertices) { verts[kk++] = ff; } // add to the array one hull's worth of data convHulls[jj++] = cr.HullIndices.Count; convHulls[jj++] = 0f; // centroid x,y,z convHulls[jj++] = 0f; convHulls[jj++] = 0f; foreach (int ind in cr.HullIndices) { convHulls[jj++] = verts[ind].x; convHulls[jj++] = verts[ind].y; convHulls[jj++] = verts[ind].z; } } // create the hull definition in Bullet // m_log.DebugFormat("{0}: CreateGeom: calling CreateHull. lid={1}, key={2}, hulls={3}", LogHeader, _localID, _hullKey, hullCount); BulletSimAPI.CreateHull(_scene.WorldID, _hullKey, hullCount, convHulls); _shapeType = ShapeData.PhysicsShapeType.SHAPE_HULL; // meshes are already scaled by the meshmerizer _scale = new OMV.Vector3(1f, 1f, 1f); return; }