aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/BulletSNPlugin/BSLinksetConstraints.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/Physics/BulletSNPlugin/BSLinksetConstraints.cs314
1 files changed, 314 insertions, 0 deletions
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSLinksetConstraints.cs
new file mode 100644
index 0000000..5757e64
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSNPlugin/BSLinksetConstraints.cs
@@ -0,0 +1,314 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OMV = OpenMetaverse;
32
33namespace OpenSim.Region.Physics.BulletSNPlugin
34{
35public sealed class BSLinksetConstraints : BSLinkset
36{
37 // private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]";
38
39 public BSLinksetConstraints(BSScene scene, BSPhysObject parent) : base(scene, parent)
40 {
41 }
42
43 // When physical properties are changed the linkset needs to recalculate
44 // its internal properties.
45 // This is queued in the 'post taint' queue so the
46 // refresh will happen once after all the other taints are applied.
47 public override void Refresh(BSPhysObject requestor)
48 {
49 // Queue to happen after all the other taint processing
50 PhysicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate()
51 {
52 if (HasAnyChildren && IsRoot(requestor))
53 RecomputeLinksetConstraints();
54 });
55 }
56
57 // The object is going dynamic (physical). Do any setup necessary
58 // for a dynamic linkset.
59 // Only the state of the passed object can be modified. The rest of the linkset
60 // has not yet been fully constructed.
61 // Return 'true' if any properties updated on the passed object.
62 // Called at taint-time!
63 public override bool MakeDynamic(BSPhysObject child)
64 {
65 // What is done for each object in BSPrim is what we want.
66 return false;
67 }
68
69 // The object is going static (non-physical). Do any setup necessary for a static linkset.
70 // Return 'true' if any properties updated on the passed object.
71 // This doesn't normally happen -- OpenSim removes the objects from the physical
72 // world if it is a static linkset.
73 // Called at taint-time!
74 public override bool MakeStatic(BSPhysObject child)
75 {
76 // What is done for each object in BSPrim is what we want.
77 return false;
78 }
79
80 // Called at taint-time!!
81 public override void UpdateProperties(BSPhysObject updated, bool inTaintTime)
82 {
83 // Nothing to do for constraints on property updates
84 }
85
86 // Routine called when rebuilding the body of some member of the linkset.
87 // Destroy all the constraints have have been made to root and set
88 // up to rebuild the constraints before the next simulation step.
89 // Returns 'true' of something was actually removed and would need restoring
90 // Called at taint-time!!
91 public override bool RemoveBodyDependencies(BSPrim child)
92 {
93 bool ret = false;
94
95 DetailLog("{0},BSLinksetConstraint.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}",
96 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString());
97
98 lock (m_linksetActivityLock)
99 {
100 // Just undo all the constraints for this linkset. Rebuild at the end of the step.
101 ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot);
102 // Cause the constraints, et al to be rebuilt before the next simulation step.
103 Refresh(LinksetRoot);
104 }
105 return ret;
106 }
107
108 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
109 // this routine will restore the removed constraints.
110 // Called at taint-time!!
111 public override void RestoreBodyDependencies(BSPrim child)
112 {
113 // The Refresh operation queued by RemoveBodyDependencies() will build any missing constraints.
114 }
115
116 // ================================================================
117
118 // Add a new child to the linkset.
119 // Called while LinkActivity is locked.
120 protected override void AddChildToLinkset(BSPhysObject child)
121 {
122 if (!HasChild(child))
123 {
124 m_children.Add(child);
125
126 DetailLog("{0},BSLinksetConstraints.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
127
128 // Cause constraints and assorted properties to be recomputed before the next simulation step.
129 Refresh(LinksetRoot);
130 }
131 return;
132 }
133
134 // Remove the specified child from the linkset.
135 // Safe to call even if the child is not really in my linkset.
136 protected override void RemoveChildFromLinkset(BSPhysObject child)
137 {
138 if (m_children.Remove(child))
139 {
140 BSPhysObject rootx = LinksetRoot; // capture the root and body as of now
141 BSPhysObject childx = child;
142
143 DetailLog("{0},BSLinksetConstraints.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
144 childx.LocalID,
145 rootx.LocalID, rootx.PhysBody.ptr.ToString(),
146 childx.LocalID, childx.PhysBody.ptr.ToString());
147
148 PhysicsScene.TaintedObject("BSLinksetConstraints.RemoveChildFromLinkset", delegate()
149 {
150 PhysicallyUnlinkAChildFromRoot(rootx, childx);
151 });
152 // See that the linkset parameters are recomputed at the end of the taint time.
153 Refresh(LinksetRoot);
154 }
155 else
156 {
157 // Non-fatal occurance.
158 // PhysicsScene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader);
159 }
160 return;
161 }
162
163 // Create a constraint between me (root of linkset) and the passed prim (the child).
164 // Called at taint time!
165 private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
166 {
167 // Don't build the constraint when asked. Put it off until just before the simulation step.
168 Refresh(rootPrim);
169 }
170
171 private BSConstraint BuildConstraint(BSPhysObject rootPrim, BSPhysObject childPrim)
172 {
173 // Zero motion for children so they don't interpolate
174 childPrim.ZeroMotion(true);
175
176 // Relative position normalized to the root prim
177 // Essentually a vector pointing from center of rootPrim to center of childPrim
178 OMV.Vector3 childRelativePosition = childPrim.Position - rootPrim.Position;
179
180 // real world coordinate of midpoint between the two objects
181 OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2);
182
183 DetailLog("{0},BSLinksetConstraint.BuildConstraint,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}",
184 rootPrim.LocalID,
185 rootPrim.LocalID, rootPrim.PhysBody.ptr.ToString(),
186 childPrim.LocalID, childPrim.PhysBody.ptr.ToString(),
187 rootPrim.Position, childPrim.Position, midPoint);
188
189 // create a constraint that allows no freedom of movement between the two objects
190 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
191
192 BSConstraint6Dof constrain = new BSConstraint6Dof(
193 PhysicsScene.World, rootPrim.PhysBody, childPrim.PhysBody, midPoint, true, true );
194 // PhysicsScene.World, childPrim.BSBody, rootPrim.BSBody, midPoint, true, true );
195
196 /* NOTE: below is an attempt to build constraint with full frame computation, etc.
197 * Using the midpoint is easier since it lets the Bullet code manipulate the transforms
198 * of the objects.
199 * Code left for future programmers.
200 // ==================================================================================
201 // relative position normalized to the root prim
202 OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation);
203 OMV.Vector3 childRelativePosition = (childPrim.Position - rootPrim.Position) * invThisOrientation;
204
205 // relative rotation of the child to the parent
206 OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim.Orientation;
207 OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation);
208
209 DetailLog("{0},BSLinksetConstraint.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID);
210 BS6DofConstraint constrain = new BS6DofConstraint(
211 PhysicsScene.World, rootPrim.Body, childPrim.Body,
212 OMV.Vector3.Zero,
213 OMV.Quaternion.Inverse(rootPrim.Orientation),
214 OMV.Vector3.Zero,
215 OMV.Quaternion.Inverse(childPrim.Orientation),
216 true,
217 true
218 );
219 // ==================================================================================
220 */
221
222 PhysicsScene.Constraints.AddConstraint(constrain);
223
224 // zero linear and angular limits makes the objects unable to move in relation to each other
225 constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
226 constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
227
228 // tweek the constraint to increase stability
229 constrain.UseFrameOffset(BSParam.BoolNumeric(BSParam.LinkConstraintUseFrameOffset));
230 constrain.TranslationalLimitMotor(BSParam.BoolNumeric(BSParam.LinkConstraintEnableTransMotor),
231 BSParam.LinkConstraintTransMotorMaxVel,
232 BSParam.LinkConstraintTransMotorMaxForce);
233 constrain.SetCFMAndERP(BSParam.LinkConstraintCFM, BSParam.LinkConstraintERP);
234 if (BSParam.LinkConstraintSolverIterations != 0f)
235 {
236 constrain.SetSolverIterations(BSParam.LinkConstraintSolverIterations);
237 }
238 return constrain;
239 }
240
241 // Remove linkage between the linkset root and a particular child
242 // The root and child bodies are passed in because we need to remove the constraint between
243 // the bodies that were present at unlink time.
244 // Called at taint time!
245 private bool PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
246 {
247 bool ret = false;
248 DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}",
249 rootPrim.LocalID,
250 rootPrim.LocalID, rootPrim.PhysBody.ptr.ToString(),
251 childPrim.LocalID, childPrim.PhysBody.ptr.ToString());
252
253 // Find the constraint for this link and get rid of it from the overall collection and from my list
254 if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody))
255 {
256 // Make the child refresh its location
257 BulletSimAPI.PushUpdate2(childPrim.PhysBody.ptr);
258 ret = true;
259 }
260
261 return ret;
262 }
263
264 // Remove linkage between myself and any possible children I might have.
265 // Returns 'true' of any constraints were destroyed.
266 // Called at taint time!
267 private bool PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim)
268 {
269 DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
270
271 return PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody);
272 }
273
274 // Call each of the constraints that make up this linkset and recompute the
275 // various transforms and variables. Create constraints of not created yet.
276 // Called before the simulation step to make sure the constraint based linkset
277 // is all initialized.
278 // Called at taint time!!
279 private void RecomputeLinksetConstraints()
280 {
281 float linksetMass = LinksetMass;
282 LinksetRoot.UpdatePhysicalMassProperties(linksetMass);
283
284 // DEBUG: see of inter-linkset collisions are causing problems
285 // BulletSimAPI.SetCollisionFilterMask2(LinksetRoot.BSBody.ptr,
286 // (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask);
287 DetailLog("{0},BSLinksetConstraint.RecomputeLinksetConstraints,set,rBody={1},linksetMass={2}",
288 LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString(), linksetMass);
289
290 foreach (BSPhysObject child in m_children)
291 {
292 // A child in the linkset physically shows the mass of the whole linkset.
293 // This allows Bullet to apply enough force on the child to move the whole linkset.
294 // (Also do the mass stuff before recomputing the constraint so mass is not zero.)
295 child.UpdatePhysicalMassProperties(linksetMass);
296
297 BSConstraint constrain;
298 if (!PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, child.PhysBody, out constrain))
299 {
300 // If constraint doesn't exist yet, create it.
301 constrain = BuildConstraint(LinksetRoot, child);
302 }
303 constrain.RecomputeConstraintVariables(linksetMass);
304
305 // DEBUG: see of inter-linkset collisions are causing problems
306 // BulletSimAPI.SetCollisionFilterMask2(child.BSBody.ptr,
307 // (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask);
308
309 // BulletSimAPI.DumpConstraint2(PhysicsScene.World.ptr, constrain.Constraint.ptr); // DEBUG DEBUG
310 }
311
312 }
313}
314}