aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs365
1 files changed, 139 insertions, 226 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
index e05562a..6359046 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
@@ -35,81 +35,55 @@ using OMV = OpenMetaverse;
35namespace OpenSim.Region.Physics.BulletSPlugin 35namespace OpenSim.Region.Physics.BulletSPlugin
36{ 36{
37 37
38// When a child is linked, the relationship position of the child to the parent 38public sealed class BSLinksetCompound : BSLinkset
39// is remembered so the child's world position can be recomputed when it is
40// removed from the linkset.
41sealed class BSLinksetCompoundInfo : BSLinksetInfo
42{ 39{
43 public int Index; 40 private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]";
44 public OMV.Vector3 OffsetFromRoot; 41
45 public OMV.Vector3 OffsetFromCenterOfMass; 42 public BSLinksetCompound(BSScene scene, BSPrimLinkable parent)
46 public OMV.Quaternion OffsetRot; 43 : base(scene, parent)
47 public BSLinksetCompoundInfo(int indx, OMV.Vector3 p, OMV.Quaternion r)
48 { 44 {
49 Index = indx;
50 OffsetFromRoot = p;
51 OffsetFromCenterOfMass = p;
52 OffsetRot = r;
53 } 45 }
54 // 'centerDisplacement' is the distance from the root the the center-of-mass (Bullet 'zero' of the shape) 46
55 public BSLinksetCompoundInfo(int indx, BSPrimLinkable root, BSPrimLinkable child, OMV.Vector3 centerDisplacement) 47 // ================================================================
48 // Changing the physical property of the linkset only needs to change the root
49 public override void SetPhysicalFriction(float friction)
56 { 50 {
57 // Each child position and rotation is given relative to the center-of-mass. 51 if (LinksetRoot.PhysBody.HasPhysicalBody)
58 OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(root.RawOrientation); 52 m_physicsScene.PE.SetFriction(LinksetRoot.PhysBody, friction);
59 OMV.Vector3 displacementFromRoot = (child.RawPosition - root.RawPosition) * invRootOrientation;
60 OMV.Vector3 displacementFromCOM = displacementFromRoot - centerDisplacement;
61 OMV.Quaternion displacementRot = child.RawOrientation * invRootOrientation;
62
63 // Save relative position for recomputing child's world position after moving linkset.
64 Index = indx;
65 OffsetFromRoot = displacementFromRoot;
66 OffsetFromCenterOfMass = displacementFromCOM;
67 OffsetRot = displacementRot;
68 } 53 }
69 public override void Clear() 54 public override void SetPhysicalRestitution(float restitution)
70 { 55 {
71 Index = 0; 56 if (LinksetRoot.PhysBody.HasPhysicalBody)
72 OffsetFromRoot = OMV.Vector3.Zero; 57 m_physicsScene.PE.SetRestitution(LinksetRoot.PhysBody, restitution);
73 OffsetFromCenterOfMass = OMV.Vector3.Zero;
74 OffsetRot = OMV.Quaternion.Identity;
75 } 58 }
76 public override string ToString() 59 public override void SetPhysicalGravity(OMV.Vector3 gravity)
77 { 60 {
78 StringBuilder buff = new StringBuilder(); 61 if (LinksetRoot.PhysBody.HasPhysicalBody)
79 buff.Append("<i="); 62 m_physicsScene.PE.SetGravity(LinksetRoot.PhysBody, gravity);
80 buff.Append(Index.ToString());
81 buff.Append(",p=");
82 buff.Append(OffsetFromRoot.ToString());
83 buff.Append(",m=");
84 buff.Append(OffsetFromCenterOfMass.ToString());
85 buff.Append(",r=");
86 buff.Append(OffsetRot.ToString());
87 buff.Append(">");
88 return buff.ToString();
89 } 63 }
90}; 64 public override void ComputeAndSetLocalInertia(OMV.Vector3 inertiaFactor, float linksetMass)
91
92public sealed class BSLinksetCompound : BSLinkset
93{
94 private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]";
95
96 public BSLinksetCompound(BSScene scene, BSPrimLinkable parent)
97 : base(scene, parent)
98 { 65 {
66 OMV.Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(LinksetRoot.PhysShape.physShapeInfo, linksetMass);
67 LinksetRoot.Inertia = inertia * inertiaFactor;
68 m_physicsScene.PE.SetMassProps(LinksetRoot.PhysBody, linksetMass, LinksetRoot.Inertia);
69 m_physicsScene.PE.UpdateInertiaTensor(LinksetRoot.PhysBody);
99 } 70 }
100 71 public override void SetPhysicalCollisionFlags(CollisionFlags collFlags)
101 // For compound implimented linksets, if there are children, use compound shape for the root. 72 {
102 public override BSPhysicsShapeType PreferredPhysicalShape(BSPrimLinkable requestor) 73 if (LinksetRoot.PhysBody.HasPhysicalBody)
103 { 74 m_physicsScene.PE.SetCollisionFlags(LinksetRoot.PhysBody, collFlags);
104 // Returning 'unknown' means we don't have a preference. 75 }
105 BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN; 76 public override void AddToPhysicalCollisionFlags(CollisionFlags collFlags)
106 if (IsRoot(requestor) && HasAnyChildren) 77 {
107 { 78 if (LinksetRoot.PhysBody.HasPhysicalBody)
108 ret = BSPhysicsShapeType.SHAPE_COMPOUND; 79 m_physicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, collFlags);
109 } 80 }
110 // DetailLog("{0},BSLinksetCompound.PreferredPhysicalShape,call,shape={1}", LinksetRoot.LocalID, ret); 81 public override void RemoveFromPhysicalCollisionFlags(CollisionFlags collFlags)
111 return ret; 82 {
83 if (LinksetRoot.PhysBody.HasPhysicalBody)
84 m_physicsScene.PE.RemoveFromCollisionFlags(LinksetRoot.PhysBody, collFlags);
112 } 85 }
86 // ================================================================
113 87
114 // When physical properties are changed the linkset needs to recalculate 88 // When physical properties are changed the linkset needs to recalculate
115 // its internal properties. 89 // its internal properties.
@@ -124,14 +98,15 @@ public sealed class BSLinksetCompound : BSLinkset
124 // Schedule a refresh to happen after all the other taint processing. 98 // Schedule a refresh to happen after all the other taint processing.
125 private void ScheduleRebuild(BSPrimLinkable requestor) 99 private void ScheduleRebuild(BSPrimLinkable requestor)
126 { 100 {
127 DetailLog("{0},BSLinksetCompound.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}", 101 DetailLog("{0},BSLinksetCompound.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}",
128 requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren)); 102 requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren));
103
129 // When rebuilding, it is possible to set properties that would normally require a rebuild. 104 // When rebuilding, it is possible to set properties that would normally require a rebuild.
130 // If already rebuilding, don't request another rebuild. 105 // If already rebuilding, don't request another rebuild.
131 // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding. 106 // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding.
132 if (!Rebuilding && HasAnyChildren) 107 if (!Rebuilding && HasAnyChildren)
133 { 108 {
134 PhysicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate() 109 m_physicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate()
135 { 110 {
136 if (HasAnyChildren) 111 if (HasAnyChildren)
137 RecomputeLinksetCompound(); 112 RecomputeLinksetCompound();
@@ -153,46 +128,23 @@ public sealed class BSLinksetCompound : BSLinkset
153 // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly. 128 // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly.
154 ScheduleRebuild(LinksetRoot); 129 ScheduleRebuild(LinksetRoot);
155 } 130 }
156 else
157 {
158 // The origional prims are removed from the world as the shape of the root compound
159 // shape takes over.
160 PhysicsScene.PE.AddToCollisionFlags(child.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
161 PhysicsScene.PE.ForceActivationState(child.PhysBody, ActivationState.DISABLE_SIMULATION);
162 // We don't want collisions from the old linkset children.
163 PhysicsScene.PE.RemoveFromCollisionFlags(child.PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
164
165 child.PhysBody.collisionType = CollisionType.LinksetChild;
166
167 ret = true;
168 }
169 return ret; 131 return ret;
170 } 132 }
171 133
172 // The object is going static (non-physical). Do any setup necessary for a static linkset. 134 // The object is going static (non-physical). We do not do anything for static linksets.
173 // Return 'true' if any properties updated on the passed object. 135 // Return 'true' if any properties updated on the passed object.
174 // This doesn't normally happen -- OpenSim removes the objects from the physical
175 // world if it is a static linkset.
176 // Called at taint-time! 136 // Called at taint-time!
177 public override bool MakeStatic(BSPrimLinkable child) 137 public override bool MakeStatic(BSPrimLinkable child)
178 { 138 {
179 bool ret = false; 139 bool ret = false;
140
180 DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); 141 DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child));
142 child.ClearDisplacement();
181 if (IsRoot(child)) 143 if (IsRoot(child))
182 { 144 {
145 // Schedule a rebuild to verify that the root shape is set to the real shape.
183 ScheduleRebuild(LinksetRoot); 146 ScheduleRebuild(LinksetRoot);
184 } 147 }
185 else
186 {
187 // The non-physical children can come back to life.
188 PhysicsScene.PE.RemoveFromCollisionFlags(child.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
189
190 child.PhysBody.collisionType = CollisionType.LinksetChild;
191
192 // Don't force activation so setting of DISABLE_SIMULATION can stay if used.
193 PhysicsScene.PE.Activate(child.PhysBody, false);
194 ret = true;
195 }
196 return ret; 148 return ret;
197 } 149 }
198 150
@@ -200,13 +152,20 @@ public sealed class BSLinksetCompound : BSLinkset
200 // Called at taint-time. 152 // Called at taint-time.
201 public override void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable updated) 153 public override void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable updated)
202 { 154 {
155 if (!LinksetRoot.IsPhysicallyActive)
156 {
157 // No reason to do this physical stuff for static linksets.
158 DetailLog("{0},BSLinksetCompound.UpdateProperties,notPhysical", LinksetRoot.LocalID);
159 return;
160 }
161
203 // The user moving a child around requires the rebuilding of the linkset compound shape 162 // The user moving a child around requires the rebuilding of the linkset compound shape
204 // One problem is this happens when a border is crossed -- the simulator implementation 163 // One problem is this happens when a border is crossed -- the simulator implementation
205 // stores the position into the group which causes the move of the object 164 // stores the position into the group which causes the move of the object
206 // but it also means all the child positions get updated. 165 // but it also means all the child positions get updated.
207 // What would cause an unnecessary rebuild so we make sure the linkset is in a 166 // What would cause an unnecessary rebuild so we make sure the linkset is in a
208 // region before bothering to do a rebuild. 167 // region before bothering to do a rebuild.
209 if (!IsRoot(updated) && PhysicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition)) 168 if (!IsRoot(updated) && m_physicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition))
210 { 169 {
211 // If a child of the linkset is updating only the position or rotation, that can be done 170 // If a child of the linkset is updating only the position or rotation, that can be done
212 // without rebuilding the linkset. 171 // without rebuilding the linkset.
@@ -218,22 +177,22 @@ public sealed class BSLinksetCompound : BSLinkset
218 // and that is caused by us updating the object. 177 // and that is caused by us updating the object.
219 if ((whichUpdated & ~(UpdatedProperties.Position | UpdatedProperties.Orientation)) == 0) 178 if ((whichUpdated & ~(UpdatedProperties.Position | UpdatedProperties.Orientation)) == 0)
220 { 179 {
221 // Find the physical instance of the child 180 // Find the physical instance of the child
222 if (LinksetRoot.PhysShape.HasPhysicalShape && PhysicsScene.PE.IsCompound(LinksetRoot.PhysShape)) 181 if (LinksetRoot.PhysShape.HasPhysicalShape && m_physicsScene.PE.IsCompound(LinksetRoot.PhysShape.physShapeInfo))
223 { 182 {
224 // It is possible that the linkset is still under construction and the child is not yet 183 // It is possible that the linkset is still under construction and the child is not yet
225 // inserted into the compound shape. A rebuild of the linkset in a pre-step action will 184 // inserted into the compound shape. A rebuild of the linkset in a pre-step action will
226 // build the whole thing with the new position or rotation. 185 // build the whole thing with the new position or rotation.
227 // The index must be checked because Bullet references the child array but does no validity 186 // The index must be checked because Bullet references the child array but does no validity
228 // checking of the child index passed. 187 // checking of the child index passed.
229 int numLinksetChildren = PhysicsScene.PE.GetNumberOfCompoundChildren(LinksetRoot.PhysShape); 188 int numLinksetChildren = m_physicsScene.PE.GetNumberOfCompoundChildren(LinksetRoot.PhysShape.physShapeInfo);
230 if (updated.LinksetChildIndex < numLinksetChildren) 189 if (updated.LinksetChildIndex < numLinksetChildren)
231 { 190 {
232 BulletShape linksetChildShape = PhysicsScene.PE.GetChildShapeFromCompoundShapeIndex(LinksetRoot.PhysShape, updated.LinksetChildIndex); 191 BulletShape linksetChildShape = m_physicsScene.PE.GetChildShapeFromCompoundShapeIndex(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex);
233 if (linksetChildShape.HasPhysicalShape) 192 if (linksetChildShape.HasPhysicalShape)
234 { 193 {
235 // Found the child shape within the compound shape 194 // Found the child shape within the compound shape
236 PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape, updated.LinksetChildIndex, 195 m_physicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex,
237 updated.RawPosition - LinksetRoot.RawPosition, 196 updated.RawPosition - LinksetRoot.RawPosition,
238 updated.RawOrientation * OMV.Quaternion.Inverse(LinksetRoot.RawOrientation), 197 updated.RawOrientation * OMV.Quaternion.Inverse(LinksetRoot.RawOrientation),
239 true /* shouldRecalculateLocalAabb */); 198 true /* shouldRecalculateLocalAabb */);
@@ -267,7 +226,6 @@ public sealed class BSLinksetCompound : BSLinkset
267 // there will already be a rebuild scheduled. 226 // there will already be a rebuild scheduled.
268 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild.schedulingRebuild,whichUpdated={1}", 227 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild.schedulingRebuild,whichUpdated={1}",
269 updated.LocalID, whichUpdated); 228 updated.LocalID, whichUpdated);
270 updated.LinksetInfo = null; // setting to 'null' causes relative position to be recomputed.
271 ScheduleRebuild(updated); 229 ScheduleRebuild(updated);
272 } 230 }
273 } 231 }
@@ -275,75 +233,22 @@ public sealed class BSLinksetCompound : BSLinkset
275 } 233 }
276 234
277 // Routine called when rebuilding the body of some member of the linkset. 235 // Routine called when rebuilding the body of some member of the linkset.
278 // Since we don't keep in world relationships, do nothing unless it's a child changing. 236 // If one of the bodies is being changed, the linkset needs rebuilding.
237 // For instance, a linkset is built and then a mesh asset is read in and the mesh is recreated.
279 // Returns 'true' of something was actually removed and would need restoring 238 // Returns 'true' of something was actually removed and would need restoring
280 // Called at taint-time!! 239 // Called at taint-time!!
281 public override bool RemoveBodyDependencies(BSPrimLinkable child) 240 public override bool RemoveDependencies(BSPrimLinkable child)
282 { 241 {
283 bool ret = false; 242 bool ret = false;
284 243
285 DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}", 244 DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}",
286 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody, IsRoot(child)); 245 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody, IsRoot(child));
287 246
288 if (!IsRoot(child)) 247 ScheduleRebuild(child);
289 {
290 // Because it is a convenient time, recompute child world position and rotation based on
291 // its position in the linkset.
292 RecomputeChildWorldPosition(child, true /* inTaintTime */);
293 child.LinksetInfo = null;
294 }
295
296 // Cannot schedule a refresh/rebuild here because this routine is called when
297 // the linkset is being rebuilt.
298 // InternalRefresh(LinksetRoot);
299 248
300 return ret; 249 return ret;
301 } 250 }
302 251
303 // When the linkset is built, the child shape is added to the compound shape relative to the
304 // root shape. The linkset then moves around but this does not move the actual child
305 // prim. The child prim's location must be recomputed based on the location of the root shape.
306 private void RecomputeChildWorldPosition(BSPrimLinkable child, bool inTaintTime)
307 {
308 // For the moment (20130201), disable this computation (converting the child physical addr back to
309 // a region address) until we have a good handle on center-of-mass offsets and what the physics
310 // engine moving a child actually means.
311 // The simulator keeps track of where children should be as the linkset moves. Setting
312 // the pos/rot here does not effect that knowledge as there is no good way for the
313 // physics engine to send the simulator an update for a child.
314
315 /*
316 BSLinksetCompoundInfo lci = child.LinksetInfo as BSLinksetCompoundInfo;
317 if (lci != null)
318 {
319 if (inTaintTime)
320 {
321 OMV.Vector3 oldPos = child.RawPosition;
322 child.ForcePosition = LinksetRoot.RawPosition + lci.OffsetFromRoot;
323 child.ForceOrientation = LinksetRoot.RawOrientation * lci.OffsetRot;
324 DetailLog("{0},BSLinksetCompound.RecomputeChildWorldPosition,oldPos={1},lci={2},newPos={3}",
325 child.LocalID, oldPos, lci, child.RawPosition);
326 }
327 else
328 {
329 // TaintedObject is not used here so the raw position is set now and not at taint-time.
330 child.Position = LinksetRoot.RawPosition + lci.OffsetFromRoot;
331 child.Orientation = LinksetRoot.RawOrientation * lci.OffsetRot;
332 }
333 }
334 else
335 {
336 // This happens when children have been added to the linkset but the linkset
337 // has not been constructed yet. So like, at taint time, adding children to a linkset
338 // and then changing properties of the children (makePhysical, for instance)
339 // but the post-print action of actually rebuilding the linkset has not yet happened.
340 // PhysicsScene.Logger.WarnFormat("{0} Restoring linkset child position failed because of no relative position computed. ID={1}",
341 // LogHeader, child.LocalID);
342 DetailLog("{0},BSLinksetCompound.recomputeChildWorldPosition,noRelativePositonInfo", child.LocalID);
343 }
344 */
345 }
346
347 // ================================================================ 252 // ================================================================
348 253
349 // Add a new child to the linkset. 254 // Add a new child to the linkset.
@@ -376,8 +281,6 @@ public sealed class BSLinksetCompound : BSLinkset
376 child.LocalID, child.PhysBody.AddrString); 281 child.LocalID, child.PhysBody.AddrString);
377 282
378 // Cause the child's body to be rebuilt and thus restored to normal operation 283 // Cause the child's body to be rebuilt and thus restored to normal operation
379 RecomputeChildWorldPosition(child, false);
380 child.LinksetInfo = null;
381 child.ForceBodyShapeRebuild(false); 284 child.ForceBodyShapeRebuild(false);
382 285
383 if (!HasAnyChildren) 286 if (!HasAnyChildren)
@@ -399,108 +302,118 @@ public sealed class BSLinksetCompound : BSLinkset
399 // Constraint linksets are rebuilt every time. 302 // Constraint linksets are rebuilt every time.
400 // Note that this works for rebuilding just the root after a linkset is taken apart. 303 // Note that this works for rebuilding just the root after a linkset is taken apart.
401 // Called at taint time!! 304 // Called at taint time!!
402 private bool disableCOM = true; // DEBUG DEBUG: disable until we get this debugged 305 private bool UseBulletSimRootOffsetHack = false; // Attempt to have Bullet track the coords of root compound shape
403 private void RecomputeLinksetCompound() 306 private void RecomputeLinksetCompound()
404 { 307 {
405 try 308 try
406 { 309 {
407 // Suppress rebuilding while rebuilding. (We know rebuilding is on only one thread.)
408 Rebuilding = true; 310 Rebuilding = true;
409 311
410 // Cause the root shape to be rebuilt as a compound object with just the root in it 312 // No matter what is being done, force the root prim's PhysBody and PhysShape to get set
411 LinksetRoot.ForceBodyShapeRebuild(true /* inTaintTime */); 313 // to what they should be as if the root was not in a linkset.
314 // Not that bad since we only get into this routine if there are children in the linkset and
315 // something has been updated/changed.
316 // Have to do the rebuild before checking for physical because this might be a linkset
317 // being destructed and going non-physical.
318 LinksetRoot.ForceBodyShapeRebuild(true);
412 319
413 // The center of mass for the linkset is the geometric center of the group. 320 // There is no reason to build all this physical stuff for a non-physical linkset.
414 // Compute a displacement for each component so it is relative to the center-of-mass. 321 if (!LinksetRoot.IsPhysicallyActive)
415 // Bullet presumes an object's origin (relative <0,0,0>) is its center-of-mass
416 OMV.Vector3 centerOfMassW = LinksetRoot.RawPosition;
417 if (!disableCOM) // DEBUG DEBUG
418 { 322 {
419 // Compute a center-of-mass in world coordinates. 323 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,notPhysical", LinksetRoot.LocalID);
420 centerOfMassW = ComputeLinksetCenterOfMass(); 324 return; // Note the 'finally' clause at the botton which will get executed.
421 } 325 }
422 326
423 OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation); 327 // Get a new compound shape to build the linkset shape in.
328 BSShape linksetShape = BSShapeCompound.GetReference(m_physicsScene);
424 329
425 // 'centerDisplacement' is the value to subtract from children to give physical offset position 330 // Compute a displacement for each component so it is relative to the center-of-mass.
426 OMV.Vector3 centerDisplacement = (centerOfMassW - LinksetRoot.RawPosition) * invRootOrientation; 331 // Bullet presumes an object's origin (relative <0,0,0>) is its center-of-mass
427 LinksetRoot.SetEffectiveCenterOfMassW(centerDisplacement); 332 OMV.Vector3 centerOfMassW = ComputeLinksetCenterOfMass();
428
429 // This causes the physical position of the root prim to be offset to accomodate for the displacements
430 LinksetRoot.ForcePosition = LinksetRoot.RawPosition;
431 333
432 // Update the local transform for the root child shape so it is offset from the <0,0,0> which is COM 334 OMV.Quaternion invRootOrientation = OMV.Quaternion.Normalize(OMV.Quaternion.Inverse(LinksetRoot.RawOrientation));
433 PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape, 0 /* childIndex */, 335 OMV.Vector3 origRootPosition = LinksetRoot.RawPosition;
434 -centerDisplacement,
435 OMV.Quaternion.Identity, // LinksetRoot.RawOrientation,
436 false /* shouldRecalculateLocalAabb (is done later after linkset built) */);
437 336
438 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,COM,com={1},rootPos={2},centerDisp={3}", 337 // 'centerDisplacementV' is the vehicle relative distance from the simulator root position to the center-of-mass
439 LinksetRoot.LocalID, centerOfMassW, LinksetRoot.RawPosition, centerDisplacement); 338 OMV.Vector3 centerDisplacementV = (centerOfMassW - LinksetRoot.RawPosition) * invRootOrientation;
339 if (UseBulletSimRootOffsetHack || !BSParam.LinksetOffsetCenterOfMass)
340 {
341 // Zero everything if center-of-mass displacement is not being done.
342 centerDisplacementV = OMV.Vector3.Zero;
343 LinksetRoot.ClearDisplacement();
344 }
345 else
346 {
347 // The actual center-of-mass could have been set by the user.
348 centerDisplacementV = LinksetRoot.SetEffectiveCenterOfMassDisplacement(centerDisplacementV);
349 }
440 350
441 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}", 351 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,COM,rootPos={1},com={2},comDisp={3}",
442 LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren); 352 LinksetRoot.LocalID, origRootPosition, centerOfMassW, centerDisplacementV);
443 353
444 // Add a shape for each of the other children in the linkset 354 // Add the shapes of all the components of the linkset
445 int memberIndex = 1; 355 int memberIndex = 1;
446 ForEachMember(delegate(BSPrimLinkable cPrim) 356 ForEachMember(delegate(BSPrimLinkable cPrim)
447 { 357 {
448 if (IsRoot(cPrim)) 358 if (IsRoot(cPrim))
449 { 359 {
360 // Root shape is always index zero.
450 cPrim.LinksetChildIndex = 0; 361 cPrim.LinksetChildIndex = 0;
451 } 362 }
452 else 363 else
453 { 364 {
454 cPrim.LinksetChildIndex = memberIndex; 365 cPrim.LinksetChildIndex = memberIndex;
366 memberIndex++;
367 }
455 368
456 if (cPrim.PhysShape.isNativeShape) 369 // Get a reference to the shape of the child for adding of that shape to the linkset compound shape
457 { 370 BSShape childShape = cPrim.PhysShape.GetReference(m_physicsScene, cPrim);
458 // A native shape is turned into a hull collision shape because native
459 // shapes are not shared so we have to hullify it so it will be tracked
460 // and freed at the correct time. This also solves the scaling problem
461 // (native shapes scale but hull/meshes are assumed to not be).
462 // TODO: decide of the native shape can just be used in the compound shape.
463 // Use call to CreateGeomNonSpecial().
464 BulletShape saveShape = cPrim.PhysShape;
465 cPrim.PhysShape.Clear(); // Don't let the create free the child's shape
466 PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null);
467 BulletShape newShape = cPrim.PhysShape;
468 cPrim.PhysShape = saveShape;
469
470 OMV.Vector3 offsetPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation - centerDisplacement;
471 OMV.Quaternion offsetRot = cPrim.RawOrientation * invRootOrientation;
472 PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, newShape, offsetPos, offsetRot);
473 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addNative,indx={1},rShape={2},cShape={3},offPos={4},offRot={5}",
474 LinksetRoot.LocalID, memberIndex, LinksetRoot.PhysShape, newShape, offsetPos, offsetRot);
475 }
476 else
477 {
478 // For the shared shapes (meshes and hulls), just use the shape in the child.
479 // The reference count added here will be decremented when the compound shape
480 // is destroyed in BSShapeCollection (the child shapes are looped over and dereferenced).
481 if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape))
482 {
483 PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}",
484 LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape);
485 }
486 OMV.Vector3 offsetPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation - centerDisplacement;
487 OMV.Quaternion offsetRot = cPrim.RawOrientation * invRootOrientation;
488 PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, cPrim.PhysShape, offsetPos, offsetRot);
489 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addNonNative,indx={1},rShape={2},cShape={3},offPos={4},offRot={5}",
490 LinksetRoot.LocalID, memberIndex, LinksetRoot.PhysShape, cPrim.PhysShape, offsetPos, offsetRot);
491 371
492 } 372 // Offset the child shape from the center-of-mass and rotate it to vehicle relative.
493 memberIndex++; 373 OMV.Vector3 offsetPos = (cPrim.RawPosition - origRootPosition) * invRootOrientation - centerDisplacementV;
374 OMV.Quaternion offsetRot = OMV.Quaternion.Normalize(cPrim.RawOrientation) * invRootOrientation;
375
376 // Add the child shape to the compound shape being built
377 m_physicsScene.PE.AddChildShapeToCompoundShape(linksetShape.physShapeInfo, childShape.physShapeInfo, offsetPos, offsetRot);
378 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addChild,indx={1},cShape={2},offPos={3},offRot={4}",
379 LinksetRoot.LocalID, cPrim.LinksetChildIndex, childShape, offsetPos, offsetRot);
380
381 // Since we are borrowing the shape of the child, disable the origional child body
382 if (!IsRoot(cPrim))
383 {
384 m_physicsScene.PE.AddToCollisionFlags(cPrim.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
385 m_physicsScene.PE.ForceActivationState(cPrim.PhysBody, ActivationState.DISABLE_SIMULATION);
386 // We don't want collisions from the old linkset children.
387 m_physicsScene.PE.RemoveFromCollisionFlags(cPrim.PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
388 cPrim.PhysBody.collisionType = CollisionType.LinksetChild;
494 } 389 }
390
495 return false; // 'false' says to move onto the next child in the list 391 return false; // 'false' says to move onto the next child in the list
496 }); 392 });
497 393
394 // Replace the root shape with the built compound shape.
395 // Object removed and added to world to get collision cache rebuilt for new shape.
396 LinksetRoot.PhysShape.Dereference(m_physicsScene);
397 LinksetRoot.PhysShape = linksetShape;
398 m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, LinksetRoot.PhysBody);
399 m_physicsScene.PE.SetCollisionShape(m_physicsScene.World, LinksetRoot.PhysBody, linksetShape.physShapeInfo);
400 m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, LinksetRoot.PhysBody);
401 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addBody,body={1},shape={2}",
402 LinksetRoot.LocalID, LinksetRoot.PhysBody, linksetShape);
403
498 // With all of the linkset packed into the root prim, it has the mass of everyone. 404 // With all of the linkset packed into the root prim, it has the mass of everyone.
499 LinksetMass = ComputeLinksetMass(); 405 LinksetMass = ComputeLinksetMass();
500 LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true); 406 LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true);
501 407
502 // Enable the physical position updator to return the position and rotation of the root shape 408 if (UseBulletSimRootOffsetHack)
503 PhysicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, CollisionFlags.BS_RETURN_ROOT_COMPOUND_SHAPE); 409 {
410 // Enable the physical position updator to return the position and rotation of the root shape.
411 // This enables a feature in the C++ code to return the world coordinates of the first shape in the
412 // compound shape. This aleviates the need to offset the returned physical position by the
413 // center-of-mass offset.
414 // TODO: either debug this feature or remove it.
415 m_physicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, CollisionFlags.BS_RETURN_ROOT_COMPOUND_SHAPE);
416 }
504 } 417 }
505 finally 418 finally
506 { 419 {
@@ -508,7 +421,7 @@ public sealed class BSLinksetCompound : BSLinkset
508 } 421 }
509 422
510 // See that the Aabb surrounds the new shape 423 // See that the Aabb surrounds the new shape
511 PhysicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape); 424 m_physicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape.physShapeInfo);
512 } 425 }
513} 426}
514} \ No newline at end of file 427} \ No newline at end of file