// Get a reference to a physical shape. Create if it doesn't exist public static BSShape GetShapeReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) { BSShape ret = null; if (prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE) { // an avatar capsule is close to a native shape (it is not shared) ret = BSShapeNative.GetReference(physicsScene, prim, BSPhysicsShapeType.SHAPE_CAPSULE, FixedShapeKey.KEY_CAPSULE); physicsScene.DetailLog("{0},BSShape.GetShapeReference,avatarCapsule,shape={1}", prim.LocalID, ret); } // Compound shapes are handled special as they are rebuilt from scratch. // This isn't too great a hardship since most of the child shapes will already been created. if (ret == null && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND) { // Getting a reference to a compound shape gets you the compound shape with the root prim shape added ret = BSShapeCompound.GetReference(prim); physicsScene.DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, ret); } if (ret == null) ret = GetShapeReferenceNonSpecial(physicsScene, forceRebuild, prim); return ret; }
// For compound implimented linksets, if there are children, use compound shape for the root. public override BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor) { // Returning 'unknown' means we don't have a preference. BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN; if (IsRoot(requestor) && HasAnyChildren) { ret = BSPhysicsShapeType.SHAPE_COMPOUND; } // DetailLog("{0},BSLinksetCompound.PreferredPhysicalShape,call,shape={1}", LinksetRoot.LocalID, ret); return ret; }
// When physical properties are changed the linkset needs to recalculate // its internal properties. // This is queued in the 'post taint' queue so the // refresh will happen once after all the other taints are applied. public override void Refresh(BSPhysObject requestor) { base.Refresh(requestor); // Queue to happen after all the other taint processing PhysicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate() { if (HasAnyChildren && IsRoot(requestor)) RecomputeLinksetConstraints(); }); }
// Create the correct type of linkset for this child public static BSLinkset Factory(BSScene physScene, BSPhysObject parent) { BSLinkset ret = null; switch ((int)BSParam.LinksetImplementation) { case (int)LinksetImplementation.Constraint: ret = new BSLinksetConstraints(physScene, parent); break; case (int)LinksetImplementation.Compound: ret = new BSLinksetCompound(physScene, parent); break; case (int)LinksetImplementation.Manual: // ret = new BSLinksetManual(physScene, parent); break; default: ret = new BSLinksetCompound(physScene, parent); break; } return ret; }
public void RestoreBodyDependencies(BSPhysObject prim) { if (Prim.LocalID != prim.LocalID) { // The call should be on us by our prim. Error if not. PhysicsScene.Logger.ErrorFormat("{0} RestoreBodyDependencies: called by not my prim. passedLocalID={1}, vehiclePrimLocalID={2}", LogHeader, prim.LocalID, Prim.LocalID); return; } Refresh(); }
// Called at taint-time!! public override void UpdateProperties(BSPhysObject updated, bool inTaintTime) { // Nothing to do for constraints on property updates }
// Remove linkage between myself and any possible children I might have. // Returns 'true' of any constraints were destroyed. // Called at taint time! private bool PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim) { DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID); return PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody); }
private BSConstraint BuildConstraint(BSPhysObject rootPrim, BSPhysObject childPrim) { // Zero motion for children so they don't interpolate childPrim.ZeroMotion(true); // Relative position normalized to the root prim // Essentually a vector pointing from center of rootPrim to center of childPrim OMV.Vector3 childRelativePosition = childPrim.Position - rootPrim.Position; // real world coordinate of midpoint between the two objects OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2); DetailLog("{0},BSLinksetConstraint.BuildConstraint,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}", rootPrim.LocalID, rootPrim.LocalID, rootPrim.PhysBody.ptr.ToString(), childPrim.LocalID, childPrim.PhysBody.ptr.ToString(), rootPrim.Position, childPrim.Position, midPoint); // create a constraint that allows no freedom of movement between the two objects // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 BSConstraint6Dof constrain = new BSConstraint6Dof( PhysicsScene.World, rootPrim.PhysBody, childPrim.PhysBody, midPoint, true, true ); // PhysicsScene.World, childPrim.BSBody, rootPrim.BSBody, midPoint, true, true ); /* NOTE: below is an attempt to build constraint with full frame computation, etc. * Using the midpoint is easier since it lets the Bullet code manipulate the transforms * of the objects. * Code left for future programmers. // ================================================================================== // relative position normalized to the root prim OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation); OMV.Vector3 childRelativePosition = (childPrim.Position - rootPrim.Position) * invThisOrientation; // relative rotation of the child to the parent OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim.Orientation; OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation); DetailLog("{0},BSLinksetConstraint.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID); BS6DofConstraint constrain = new BS6DofConstraint( PhysicsScene.World, rootPrim.Body, childPrim.Body, OMV.Vector3.Zero, OMV.Quaternion.Inverse(rootPrim.Orientation), OMV.Vector3.Zero, OMV.Quaternion.Inverse(childPrim.Orientation), true, true ); // ================================================================================== */ PhysicsScene.Constraints.AddConstraint(constrain); // zero linear and angular limits makes the objects unable to move in relation to each other constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero); constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero); // tweek the constraint to increase stability constrain.UseFrameOffset(BSParam.BoolNumeric(BSParam.LinkConstraintUseFrameOffset)); constrain.TranslationalLimitMotor(BSParam.BoolNumeric(BSParam.LinkConstraintEnableTransMotor), BSParam.LinkConstraintTransMotorMaxVel, BSParam.LinkConstraintTransMotorMaxForce); constrain.SetCFMAndERP(BSParam.LinkConstraintCFM, BSParam.LinkConstraintERP); if (BSParam.LinkConstraintSolverIterations != 0f) { constrain.SetSolverIterations(BSParam.LinkConstraintSolverIterations); } return constrain; }
// Remove the specified child from the linkset. // Safe to call even if the child is not really in my linkset. protected override void RemoveChildFromLinkset(BSPhysObject child) { if (m_children.Remove(child)) { BSPhysObject rootx = LinksetRoot; // capture the root and body as of now BSPhysObject childx = child; DetailLog("{0},BSLinksetConstraints.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", childx.LocalID, rootx.LocalID, rootx.PhysBody.ptr.ToString(), childx.LocalID, childx.PhysBody.ptr.ToString()); PhysicsScene.TaintedObject("BSLinksetConstraints.RemoveChildFromLinkset", delegate() { PhysicallyUnlinkAChildFromRoot(rootx, childx); }); // See that the linkset parameters are recomputed at the end of the taint time. Refresh(LinksetRoot); } else { // Non-fatal occurance. // PhysicsScene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader); } return; }
// I am the root of a linkset and one of my children is being removed. // Safe to call even if the child is not really in my linkset. protected abstract void RemoveChildFromLinkset(BSPhysObject child);
// Return 'true' if the passed object is the root object of this linkset public bool IsRoot(BSPhysObject requestor) { return(requestor.LocalID == LinksetRoot.LocalID); }
public BSLinksetCompound(BSScene scene, BSPhysObject parent) : base(scene, parent) { }
// Called when a parameter update comes from the physics engine for any object // of the linkset is received. // Passed flag is update came from physics engine (true) or the user (false). // Called at taint-time!! public abstract void UpdateProperties(BSPhysObject physObject, bool physicalUpdate);
// The object is going static (non-physical). Do any setup necessary // for a static linkset. // Return 'true' if any properties updated on the passed object. // Called at taint-time! public abstract bool MakeStatic(BSPhysObject child);
// The object is going dynamic (physical). Do any setup necessary // for a dynamic linkset. // Only the state of the passed object can be modified. The rest of the linkset // has not yet been fully constructed. // Return 'true' if any properties updated on the passed object. // Called at taint-time! public abstract bool MakeDynamic(BSPhysObject child);
// When physical properties are changed the linkset needs to recalculate // its internal properties. // May be called at runtime or taint-time. public virtual void Refresh(BSPhysObject requestor) { LinksetMass = ComputeLinksetMass(); }
private BSShapeNative(BSScene physicsScene, BSPhysObject prim, BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) { ShapeData nativeShapeData = new ShapeData(); nativeShapeData.Type = shapeType; nativeShapeData.ID = prim.LocalID; nativeShapeData.Scale = prim.Scale; nativeShapeData.Size = prim.Scale; nativeShapeData.MeshKey = (ulong)shapeKey; nativeShapeData.HullKey = (ulong)shapeKey; if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE) { ptr = BulletSimAPI.BuildCapsuleShape2(physicsScene.World.ptr, 1f, 1f, prim.Scale); physicsScene.DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale); } else { ptr = BulletSimAPI.BuildNativeShape2(physicsScene.World.ptr, nativeShapeData); } if (ptr == null) { physicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", LogHeader, prim.LocalID, shapeType); } type = shapeType; key = (UInt64)shapeKey; }
// Some linksets have a preferred physical shape. // Returns SHAPE_UNKNOWN if there is no preference. Causes the correct shape to be selected. public virtual BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor) { return BSPhysicsShapeType.SHAPE_UNKNOWN; }
// I am the root of a linkset and a new child is being added // Called while LinkActivity is locked. protected abstract void AddChildToLinkset(BSPhysObject child);
// Link to a linkset where the child knows the parent. // Parent changing should not happen so do some sanity checking. // We return the parent's linkset so the child can track its membership. // Called at runtime. public BSLinkset AddMeToLinkset(BSPhysObject child) { lock (m_linksetActivityLock) { // Don't add the root to its own linkset if (!IsRoot(child)) AddChildToLinkset(child); LinksetMass = ComputeLinksetMass(); } return this; }
// Remove a child from a linkset. // Returns a new linkset for the child which is a linkset of one (just the // orphened child). // Called at runtime. public BSLinkset RemoveMeFromLinkset(BSPhysObject child) { lock (m_linksetActivityLock) { if (IsRoot(child)) { // Cannot remove the root from a linkset. return this; } RemoveChildFromLinkset(child); LinksetMass = ComputeLinksetMass(); } // The child is down to a linkset of just itself return BSLinkset.Factory(PhysicsScene, child); }
// ================================================================ // Add a new child to the linkset. // Called while LinkActivity is locked. protected override void AddChildToLinkset(BSPhysObject child) { if (!HasChild(child)) { m_children.Add(child); DetailLog("{0},BSLinksetConstraints.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); // Cause constraints and assorted properties to be recomputed before the next simulation step. Refresh(LinksetRoot); } return; }
// Return 'true' if the passed object is the root object of this linkset public bool IsRoot(BSPhysObject requestor) { return (requestor.LocalID == LinksetRoot.LocalID); }
// Create a constraint between me (root of linkset) and the passed prim (the child). // Called at taint time! private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BSPhysObject childPrim) { // Don't build the constraint when asked. Put it off until just before the simulation step. Refresh(rootPrim); }
// Return 'true' if this child is in this linkset public bool HasChild(BSPhysObject child) { bool ret = false; lock (m_linksetActivityLock) { ret = m_children.Contains(child); /* Safer version but the above should work foreach (BSPhysObject bp in m_children) { if (child.LocalID == bp.LocalID) { ret = true; break; } } */ } return ret; }
// Remove linkage between the linkset root and a particular child // The root and child bodies are passed in because we need to remove the constraint between // the bodies that were present at unlink time. // Called at taint time! private bool PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BSPhysObject childPrim) { bool ret = false; DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}", rootPrim.LocalID, rootPrim.LocalID, rootPrim.PhysBody.ptr.ToString(), childPrim.LocalID, childPrim.PhysBody.ptr.ToString()); // Find the constraint for this link and get rid of it from the overall collection and from my list if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody)) { // Make the child refresh its location BulletSimAPI.PushUpdate2(childPrim.PhysBody.ptr); ret = true; } return ret; }
// private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]"; public BSLinksetConstraints(BSScene scene, BSPhysObject parent) : base(scene, parent) { }
// The object is going static (non-physical). Do any setup necessary for a static linkset. // Return 'true' if any properties updated on the passed object. // This doesn't normally happen -- OpenSim removes the objects from the physical // world if it is a static linkset. // Called at taint-time! public override bool MakeStatic(BSPhysObject child) { // What is done for each object in BSPrim is what we want. return false; }
public bool RemoveBodyDependencies(BSPhysObject prim) { // If active, we need to add our properties back when the body is rebuilt. return IsActive; }
public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim, BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) { // Native shapes are not shared and are always built anew. return new BSShapeNative(physicsScene, prim, shapeType, shapeKey); }
public static BSShape GetReference(BSPhysObject prim) { return new BSShapeNull(); }
public static BSShape GetShapeReferenceNonNative(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) { return null; }
// Some linksets have a preferred physical shape. // Returns SHAPE_UNKNOWN if there is no preference. Causes the correct shape to be selected. public virtual BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor) { return(BSPhysicsShapeType.SHAPE_UNKNOWN); }