aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region
diff options
context:
space:
mode:
authorBlueWall2012-11-26 06:55:03 -0500
committerBlueWall2012-11-26 06:55:03 -0500
commit88f2fbc8f165121fc63328aec60963a25d07082f (patch)
tree459d9986d18f002415c4694a6db7c3ac1efb237e /OpenSim/Region
parentMerge branch 'master' into connector_plugin (diff)
parentBulletSim: use m_angularMotor to do the basic movement. Add the setting of sa... (diff)
downloadopensim-SC_OLD-88f2fbc8f165121fc63328aec60963a25d07082f.zip
opensim-SC_OLD-88f2fbc8f165121fc63328aec60963a25d07082f.tar.gz
opensim-SC_OLD-88f2fbc8f165121fc63328aec60963a25d07082f.tar.bz2
opensim-SC_OLD-88f2fbc8f165121fc63328aec60963a25d07082f.tar.xz
Merge branch 'master' into connector_plugin
Diffstat (limited to 'OpenSim/Region')
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs307
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs191
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSMotors.cs256
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs9
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSScene.cs40
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs2
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs93
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs4
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs7
9 files changed, 571 insertions, 338 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
index dbc9039..95a4134 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
@@ -80,10 +80,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
80 private Quaternion m_referenceFrame = Quaternion.Identity; 80 private Quaternion m_referenceFrame = Quaternion.Identity;
81 81
82 // Linear properties 82 // Linear properties
83 private BSVMotor m_linearMotor = new BSVMotor("LinearMotor");
83 private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time 84 private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time
84 private Vector3 m_linearMotorOffset = Vector3.Zero; // the point of force can be offset from the center 85 private Vector3 m_linearMotorOffset = Vector3.Zero; // the point of force can be offset from the center
85 private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL 86 private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL
86 private Vector3 m_newVelocity = Vector3.Zero; // velocity computed to be applied to body
87 private Vector3 m_linearFrictionTimescale = Vector3.Zero; 87 private Vector3 m_linearFrictionTimescale = Vector3.Zero;
88 private float m_linearMotorDecayTimescale = 0; 88 private float m_linearMotorDecayTimescale = 0;
89 private float m_linearMotorTimescale = 0; 89 private float m_linearMotorTimescale = 0;
@@ -93,6 +93,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
93 // private Vector3 m_linearMotorOffset = Vector3.Zero; 93 // private Vector3 m_linearMotorOffset = Vector3.Zero;
94 94
95 //Angular properties 95 //Angular properties
96 private BSVMotor m_angularMotor = new BSVMotor("AngularMotor");
96 private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor 97 private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor
97 // private int m_angularMotorApply = 0; // application frame counter 98 // private int m_angularMotorApply = 0; // application frame counter
98 private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity 99 private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity
@@ -152,10 +153,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin
152 m_angularDeflectionTimescale = Math.Max(pValue, 0.01f); 153 m_angularDeflectionTimescale = Math.Max(pValue, 0.01f);
153 break; 154 break;
154 case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE: 155 case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE:
155 m_angularMotorDecayTimescale = Math.Max(pValue, 0.01f); 156 m_angularMotorDecayTimescale = Math.Max(0.01f, Math.Min(pValue,120));
157 m_angularMotor.TargetValueDecayTimeScale = m_angularMotorDecayTimescale;
156 break; 158 break;
157 case Vehicle.ANGULAR_MOTOR_TIMESCALE: 159 case Vehicle.ANGULAR_MOTOR_TIMESCALE:
158 m_angularMotorTimescale = Math.Max(pValue, 0.01f); 160 m_angularMotorTimescale = Math.Max(pValue, 0.01f);
161 m_angularMotor.TimeScale = m_angularMotorTimescale;
159 break; 162 break;
160 case Vehicle.BANKING_EFFICIENCY: 163 case Vehicle.BANKING_EFFICIENCY:
161 m_bankingEfficiency = Math.Max(-1f, Math.Min(pValue, 1f)); 164 m_bankingEfficiency = Math.Max(-1f, Math.Min(pValue, 1f));
@@ -185,10 +188,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin
185 m_linearDeflectionTimescale = Math.Max(pValue, 0.01f); 188 m_linearDeflectionTimescale = Math.Max(pValue, 0.01f);
186 break; 189 break;
187 case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE: 190 case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE:
188 m_linearMotorDecayTimescale = Math.Max(pValue, 0.01f); 191 m_linearMotorDecayTimescale = Math.Max(0.01f, Math.Min(pValue,120));
192 m_linearMotor.TargetValueDecayTimeScale = m_linearMotorDecayTimescale;
189 break; 193 break;
190 case Vehicle.LINEAR_MOTOR_TIMESCALE: 194 case Vehicle.LINEAR_MOTOR_TIMESCALE:
191 m_linearMotorTimescale = Math.Max(pValue, 0.01f); 195 m_linearMotorTimescale = Math.Max(pValue, 0.01f);
196 m_linearMotor.TimeScale = m_linearMotorTimescale;
192 break; 197 break;
193 case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY: 198 case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY:
194 m_verticalAttractionEfficiency = Math.Max(0.1f, Math.Min(pValue, 1f)); 199 m_verticalAttractionEfficiency = Math.Max(0.1f, Math.Min(pValue, 1f));
@@ -201,17 +206,20 @@ namespace OpenSim.Region.Physics.BulletSPlugin
201 // set all of the components to the same value 206 // set all of the components to the same value
202 case Vehicle.ANGULAR_FRICTION_TIMESCALE: 207 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
203 m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue); 208 m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue);
209 m_angularMotor.FrictionTimescale = m_angularFrictionTimescale;
204 break; 210 break;
205 case Vehicle.ANGULAR_MOTOR_DIRECTION: 211 case Vehicle.ANGULAR_MOTOR_DIRECTION:
206 m_angularMotorDirection = new Vector3(pValue, pValue, pValue); 212 m_angularMotorDirection = new Vector3(pValue, pValue, pValue);
207 // m_angularMotorApply = 100; 213 m_angularMotor.SetTarget(m_angularMotorDirection);
208 break; 214 break;
209 case Vehicle.LINEAR_FRICTION_TIMESCALE: 215 case Vehicle.LINEAR_FRICTION_TIMESCALE:
210 m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); 216 m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue);
217 m_linearMotor.FrictionTimescale = m_linearFrictionTimescale;
211 break; 218 break;
212 case Vehicle.LINEAR_MOTOR_DIRECTION: 219 case Vehicle.LINEAR_MOTOR_DIRECTION:
213 m_linearMotorDirection = new Vector3(pValue, pValue, pValue); 220 m_linearMotorDirection = new Vector3(pValue, pValue, pValue);
214 m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue); 221 m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue);
222 m_linearMotor.SetTarget(m_linearMotorDirection);
215 break; 223 break;
216 case Vehicle.LINEAR_MOTOR_OFFSET: 224 case Vehicle.LINEAR_MOTOR_OFFSET:
217 m_linearMotorOffset = new Vector3(pValue, pValue, pValue); 225 m_linearMotorOffset = new Vector3(pValue, pValue, pValue);
@@ -227,6 +235,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
227 { 235 {
228 case Vehicle.ANGULAR_FRICTION_TIMESCALE: 236 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
229 m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); 237 m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
238 m_angularMotor.FrictionTimescale = m_angularFrictionTimescale;
230 break; 239 break;
231 case Vehicle.ANGULAR_MOTOR_DIRECTION: 240 case Vehicle.ANGULAR_MOTOR_DIRECTION:
232 // Limit requested angular speed to 2 rps= 4 pi rads/sec 241 // Limit requested angular speed to 2 rps= 4 pi rads/sec
@@ -234,14 +243,16 @@ namespace OpenSim.Region.Physics.BulletSPlugin
234 pValue.Y = Math.Max(-12.56f, Math.Min(pValue.Y, 12.56f)); 243 pValue.Y = Math.Max(-12.56f, Math.Min(pValue.Y, 12.56f));
235 pValue.Z = Math.Max(-12.56f, Math.Min(pValue.Z, 12.56f)); 244 pValue.Z = Math.Max(-12.56f, Math.Min(pValue.Z, 12.56f));
236 m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); 245 m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
237 // m_angularMotorApply = 100; 246 m_angularMotor.SetTarget(m_angularMotorDirection);
238 break; 247 break;
239 case Vehicle.LINEAR_FRICTION_TIMESCALE: 248 case Vehicle.LINEAR_FRICTION_TIMESCALE:
240 m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); 249 m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
250 m_linearMotor.FrictionTimescale = m_linearFrictionTimescale;
241 break; 251 break;
242 case Vehicle.LINEAR_MOTOR_DIRECTION: 252 case Vehicle.LINEAR_MOTOR_DIRECTION:
243 m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); 253 m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
244 m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z); 254 m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z);
255 m_linearMotor.SetTarget(m_linearMotorDirection);
245 break; 256 break;
246 case Vehicle.LINEAR_MOTOR_OFFSET: 257 case Vehicle.LINEAR_MOTOR_OFFSET:
247 m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z); 258 m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z);
@@ -319,6 +330,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
319 330
320 m_referenceFrame = Quaternion.Identity; 331 m_referenceFrame = Quaternion.Identity;
321 m_flags = (VehicleFlag)0; 332 m_flags = (VehicleFlag)0;
333
322 break; 334 break;
323 335
324 case Vehicle.TYPE_SLED: 336 case Vehicle.TYPE_SLED:
@@ -351,10 +363,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin
351 m_bankingMix = 1; 363 m_bankingMix = 1;
352 364
353 m_referenceFrame = Quaternion.Identity; 365 m_referenceFrame = Quaternion.Identity;
354 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP); 366 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
355 m_flags &= 367 | VehicleFlag.HOVER_TERRAIN_ONLY
356 ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | 368 | VehicleFlag.HOVER_GLOBAL_HEIGHT
357 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); 369 | VehicleFlag.HOVER_UP_ONLY);
370 m_flags |= (VehicleFlag.NO_DEFLECTION_UP
371 | VehicleFlag.LIMIT_ROLL_ONLY
372 | VehicleFlag.LIMIT_MOTOR_UP);
358 break; 373 break;
359 case Vehicle.TYPE_CAR: 374 case Vehicle.TYPE_CAR:
360 m_linearMotorDirection = Vector3.Zero; 375 m_linearMotorDirection = Vector3.Zero;
@@ -510,6 +525,18 @@ namespace OpenSim.Region.Physics.BulletSPlugin
510 | VehicleFlag.HOVER_GLOBAL_HEIGHT); 525 | VehicleFlag.HOVER_GLOBAL_HEIGHT);
511 break; 526 break;
512 } 527 }
528
529 // Update any physical parameters based on this type.
530 Refresh();
531
532 m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale,
533 m_linearMotorDecayTimescale, m_linearFrictionTimescale, 1f);
534 m_linearMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
535 m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale,
536 m_angularMotorDecayTimescale, m_angularFrictionTimescale, 1f);
537 m_angularMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
538
539 // m_bankingMotor = new BSVMotor("BankingMotor", ...);
513 } 540 }
514 541
515 // Some of the properties of this prim may have changed. 542 // Some of the properties of this prim may have changed.
@@ -518,13 +545,25 @@ namespace OpenSim.Region.Physics.BulletSPlugin
518 { 545 {
519 if (IsActive) 546 if (IsActive)
520 { 547 {
521 // Friction effects are handled by this vehicle code 548 m_vehicleMass = Prim.Linkset.LinksetMass;
522 BulletSimAPI.SetFriction2(Prim.PhysBody.ptr, 0f);
523 BulletSimAPI.SetHitFraction2(Prim.PhysBody.ptr, 0f);
524
525 // BulletSimAPI.SetAngularDamping2(Prim.PhysBody.ptr, 0.8f);
526 549
527 VDetailLog("{0},BSDynamics.Refresh,zeroingFriction and adding damping", Prim.LocalID); 550 // Friction effects are handled by this vehicle code
551 float friction = 0f;
552 BulletSimAPI.SetFriction2(Prim.PhysBody.ptr, friction);
553
554 // Moderate angular movement introduced by Bullet.
555 // TODO: possibly set AngularFactor and LinearFactor for the type of vehicle.
556 // Maybe compute linear and angular factor and damping from params.
557 float angularDamping = PhysicsScene.Params.vehicleAngularDamping;
558 BulletSimAPI.SetAngularDamping2(Prim.PhysBody.ptr, angularDamping);
559
560 // DEBUG DEBUG DEBUG: use uniform inertia to smooth movement added by Bullet
561 // Vector3 localInertia = new Vector3(1f, 1f, 1f);
562 Vector3 localInertia = new Vector3(m_vehicleMass, m_vehicleMass, m_vehicleMass);
563 BulletSimAPI.SetMassProps2(Prim.PhysBody.ptr, m_vehicleMass, localInertia);
564
565 VDetailLog("{0},BSDynamics.Refresh,frict={1},inert={2},aDamp={3}",
566 Prim.LocalID, friction, localInertia, angularDamping);
528 } 567 }
529 } 568 }
530 569
@@ -551,97 +590,38 @@ namespace OpenSim.Region.Physics.BulletSPlugin
551 { 590 {
552 if (!IsActive) return; 591 if (!IsActive) return;
553 592
554 // DEBUG
555 // Because Bullet does apply forces to the vehicle, our last computed
556 // linear and angular velocities are not what is happening now.
557 // Vector3 externalAngularVelocity = Prim.ForceRotationalVelocity - m_lastAngularVelocity;
558 // m_lastAngularVelocity += (externalAngularVelocity * 0.5f) * pTimestep;
559 // m_lastAngularVelocity = Prim.ForceRotationalVelocity; // DEBUG: account for what Bullet did last time
560 // m_lastLinearVelocityVector = Prim.ForceVelocity * Quaternion.Inverse(Prim.ForceOrientation); // DEBUG:
561 // END DEBUG
562
563 m_vehicleMass = Prim.Linkset.LinksetMass;
564
565 MoveLinear(pTimestep); 593 MoveLinear(pTimestep);
566 // Commented out for debug
567 MoveAngular(pTimestep); 594 MoveAngular(pTimestep);
568 // Prim.ApplyTorqueImpulse(-Prim.RotationalVelocity * m_vehicleMass, false); // DEBUG DEBUG
569 // Prim.ForceRotationalVelocity = -Prim.RotationalVelocity; // DEBUG DEBUG
570 595
571 LimitRotation(pTimestep); 596 LimitRotation(pTimestep);
572 597
573 // remember the position so next step we can limit absolute movement effects 598 // remember the position so next step we can limit absolute movement effects
574 m_lastPositionVector = Prim.ForcePosition; 599 m_lastPositionVector = Prim.ForcePosition;
575 600
576 VDetailLog("{0},BSDynamics.Step,frict={1},grav={2},inertia={3},mass={4}", // DEBUG DEBUG
577 Prim.LocalID,
578 BulletSimAPI.GetFriction2(Prim.PhysBody.ptr),
579 BulletSimAPI.GetGravity2(Prim.PhysBody.ptr),
580 Prim.Inertia,
581 m_vehicleMass
582 );
583 VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}", 601 VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}",
584 Prim.LocalID, Prim.ForcePosition, Prim.Force, Prim.ForceVelocity, Prim.RotationalVelocity); 602 Prim.LocalID, Prim.ForcePosition, Prim.Force, Prim.ForceVelocity, Prim.RotationalVelocity);
585 }// end Step 603 }
586 604
587 // Apply the effect of the linear motor. 605 // Apply the effect of the linear motor.
588 // Also does hover and float. 606 // Also does hover and float.
589 private void MoveLinear(float pTimestep) 607 private void MoveLinear(float pTimestep)
590 { 608 {
591 // m_linearMotorDirection is the target direction we are moving relative to the vehicle coordinates 609 Vector3 linearMotorContribution = m_linearMotor.Step(pTimestep);
592 // m_lastLinearVelocityVector is the current speed we are moving in that direction
593 if (m_linearMotorDirection.LengthSquared() > 0.001f)
594 {
595 Vector3 origDir = m_linearMotorDirection; // DEBUG
596 Vector3 origVel = m_lastLinearVelocityVector; // DEBUG
597 // DEBUG: the vehicle velocity rotated to be relative to vehicle coordinates for comparison
598 Vector3 vehicleVelocity = Prim.ForceVelocity * Quaternion.Inverse(Prim.ForceOrientation); // DEBUG
599
600 // Add (desiredVelocity - lastAppliedVelocity) / howLongItShouldTakeToComplete
601 Vector3 addAmount = (m_linearMotorDirection - m_lastLinearVelocityVector)/(m_linearMotorTimescale) * pTimestep;
602 m_lastLinearVelocityVector += addAmount;
603
604 float decayFactor = (1.0f / m_linearMotorDecayTimescale) * pTimestep;
605 m_linearMotorDirection *= (1f - decayFactor);
606
607 // Rotate new object velocity from vehicle relative to world coordinates
608 m_newVelocity = m_lastLinearVelocityVector * Prim.ForceOrientation;
609
610 // Apply friction for next time
611 Vector3 frictionFactor = (Vector3.One / m_linearFrictionTimescale) * pTimestep;
612 m_lastLinearVelocityVector *= (Vector3.One - frictionFactor);
613
614 VDetailLog("{0},MoveLinear,nonZero,origlmDir={1},origlvVel={2},vehVel={3},add={4},decay={5},frict={6},lmDir={7},lvVec={8},newVel={9}",
615 Prim.LocalID, origDir, origVel, vehicleVelocity, addAmount, decayFactor, frictionFactor,
616 m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity);
617 }
618 else
619 {
620 // if what remains of direction is very small, zero it.
621 m_linearMotorDirection = Vector3.Zero;
622 m_lastLinearVelocityVector = Vector3.Zero;
623 m_newVelocity = Vector3.Zero;
624
625 VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID);
626 }
627 610
628 // m_newVelocity is velocity computed from linear motor in world coordinates 611 // Rotate new object velocity from vehicle relative to world coordinates
612 linearMotorContribution *= Prim.ForceOrientation;
629 613
614 // ==================================================================
630 // Gravity and Buoyancy 615 // Gravity and Buoyancy
631 // There is some gravity, make a gravity force vector that is applied after object velocity. 616 // There is some gravity, make a gravity force vector that is applied after object velocity.
632 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; 617 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g;
633 Vector3 grav = Prim.PhysicsScene.DefaultGravity * (1f - m_VehicleBuoyancy); 618 Vector3 grav = Prim.PhysicsScene.DefaultGravity * (1f - m_VehicleBuoyancy);
634 619
635 /* 620 // Current vehicle position
636 * RA: Not sure why one would do this unless we are hoping external forces are doing gravity, ...
637 // Preserve the current Z velocity
638 Vector3 vel_now = m_prim.Velocity;
639 m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity
640 */
641
642 Vector3 pos = Prim.ForcePosition; 621 Vector3 pos = Prim.ForcePosition;
643// Vector3 accel = new Vector3(-(m_dir.X - m_lastLinearVelocityVector.X / 0.1f), -(m_dir.Y - m_lastLinearVelocityVector.Y / 0.1f), m_dir.Z - m_lastLinearVelocityVector.Z / 0.1f);
644 622
623 // ==================================================================
624 Vector3 terrainHeightContribution = Vector3.Zero;
645 // If below the terrain, move us above the ground a little. 625 // If below the terrain, move us above the ground a little.
646 float terrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos); 626 float terrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos);
647 // Taking the rotated size doesn't work here because m_prim.Size is the size of the root prim and not the linkset. 627 // Taking the rotated size doesn't work here because m_prim.Size is the size of the root prim and not the linkset.
@@ -650,11 +630,14 @@ namespace OpenSim.Region.Physics.BulletSPlugin
650 // if (rotatedSize.Z < terrainHeight) 630 // if (rotatedSize.Z < terrainHeight)
651 if (pos.Z < terrainHeight) 631 if (pos.Z < terrainHeight)
652 { 632 {
633 // TODO: correct position by applying force rather than forcing position.
653 pos.Z = terrainHeight + 2; 634 pos.Z = terrainHeight + 2;
654 Prim.ForcePosition = pos; 635 Prim.ForcePosition = pos;
655 VDetailLog("{0},MoveLinear,terrainHeight,terrainHeight={1},pos={2}", Prim.LocalID, terrainHeight, pos); 636 VDetailLog("{0},MoveLinear,terrainHeight,terrainHeight={1},pos={2}", Prim.LocalID, terrainHeight, pos);
656 } 637 }
657 638
639 // ==================================================================
640 Vector3 hoverContribution = Vector3.Zero;
658 // Check if hovering 641 // Check if hovering
659 // m_VhoverEfficiency: 0=bouncy, 1=totally damped 642 // m_VhoverEfficiency: 0=bouncy, 1=totally damped
660 // m_VhoverTimescale: time to achieve height 643 // m_VhoverTimescale: time to achieve height
@@ -694,24 +677,22 @@ namespace OpenSim.Region.Physics.BulletSPlugin
694 // RA: where does the 50 come from? 677 // RA: where does the 50 come from?
695 float verticalCorrectionVelocity = pTimestep * ((verticalError * 50.0f) / m_VhoverTimescale); 678 float verticalCorrectionVelocity = pTimestep * ((verticalError * 50.0f) / m_VhoverTimescale);
696 // Replace Vertical speed with correction figure if significant 679 // Replace Vertical speed with correction figure if significant
697 if (Math.Abs(verticalError) > 0.01f) 680 if (verticalError > 0.01f)
698 { 681 {
699 m_newVelocity.Z += verticalCorrectionVelocity; 682 hoverContribution = new Vector3(0f, 0f, verticalCorrectionVelocity);
700 //KF: m_VhoverEfficiency is not yet implemented 683 //KF: m_VhoverEfficiency is not yet implemented
701 } 684 }
702 else if (verticalError < -0.01) 685 else if (verticalError < -0.01)
703 { 686 {
704 m_newVelocity.Z -= verticalCorrectionVelocity; 687 hoverContribution = new Vector3(0f, 0f, -verticalCorrectionVelocity);
705 }
706 else
707 {
708 m_newVelocity.Z = 0f;
709 } 688 }
710 } 689 }
711 690
712 VDetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}", Prim.LocalID, pos, m_newVelocity, m_VhoverHeight, m_VhoverTargetHeight); 691 VDetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}",
692 Prim.LocalID, pos, hoverContribution, m_VhoverHeight, m_VhoverTargetHeight);
713 } 693 }
714 694
695 // ==================================================================
715 Vector3 posChange = pos - m_lastPositionVector; 696 Vector3 posChange = pos - m_lastPositionVector;
716 if (m_BlockingEndPoint != Vector3.Zero) 697 if (m_BlockingEndPoint != Vector3.Zero)
717 { 698 {
@@ -749,70 +730,77 @@ namespace OpenSim.Region.Physics.BulletSPlugin
749 } 730 }
750 } 731 }
751 732
752 #region downForce 733 // ==================================================================
753 Vector3 downForce = Vector3.Zero; 734 Vector3 limitMotorUpContribution = Vector3.Zero;
754
755 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) 735 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0)
756 { 736 {
757 // If the vehicle is motoring into the sky, get it going back down. 737 // If the vehicle is motoring into the sky, get it going back down.
758 // Is this an angular force or both linear and angular??
759 float distanceAboveGround = pos.Z - terrainHeight; 738 float distanceAboveGround = pos.Z - terrainHeight;
760 if (distanceAboveGround > 2f) 739 if (distanceAboveGround > 1f)
761 { 740 {
762 // downForce = new Vector3(0, 0, (-distanceAboveGround / m_bankingTimescale) * pTimestep); 741 // downForce = new Vector3(0, 0, (-distanceAboveGround / m_bankingTimescale) * pTimestep);
763 // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale); 742 // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale);
764 downForce = new Vector3(0, 0, -distanceAboveGround); 743 limitMotorUpContribution = new Vector3(0, 0, -distanceAboveGround);
765 } 744 }
766 // TODO: this calculation is all wrong. From the description at 745 // TODO: this calculation is all wrong. From the description at
767 // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce 746 // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce
768 // has a decay factor. This says this force should 747 // has a decay factor. This says this force should
769 // be computed with a motor. 748 // be computed with a motor.
770 VDetailLog("{0},MoveLinear,limitMotorUp,distAbove={1},downForce={2}", 749 VDetailLog("{0},MoveLinear,limitMotorUp,distAbove={1},downForce={2}",
771 Prim.LocalID, distanceAboveGround, downForce); 750 Prim.LocalID, distanceAboveGround, limitMotorUpContribution);
772 } 751 }
773 #endregion // downForce 752
753 // ==================================================================
754 Vector3 newVelocity = linearMotorContribution
755 + terrainHeightContribution
756 + hoverContribution
757 + limitMotorUpContribution;
774 758
775 // If not changing some axis, reduce out velocity 759 // If not changing some axis, reduce out velocity
776 if ((m_flags & (VehicleFlag.NO_X)) != 0) 760 if ((m_flags & (VehicleFlag.NO_X)) != 0)
777 m_newVelocity.X = 0; 761 newVelocity.X = 0;
778 if ((m_flags & (VehicleFlag.NO_Y)) != 0) 762 if ((m_flags & (VehicleFlag.NO_Y)) != 0)
779 m_newVelocity.Y = 0; 763 newVelocity.Y = 0;
780 if ((m_flags & (VehicleFlag.NO_Z)) != 0) 764 if ((m_flags & (VehicleFlag.NO_Z)) != 0)
781 m_newVelocity.Z = 0; 765 newVelocity.Z = 0;
782 766
767 // ==================================================================
783 // Clamp REALLY high or low velocities 768 // Clamp REALLY high or low velocities
784 if (m_newVelocity.LengthSquared() > 1e6f) 769 float newVelocityLengthSq = newVelocity.LengthSquared();
770 if (newVelocityLengthSq > 1e6f)
785 { 771 {
786 m_newVelocity /= m_newVelocity.Length(); 772 newVelocity /= newVelocity.Length();
787 m_newVelocity *= 1000f; 773 newVelocity *= 1000f;
788 } 774 }
789 else if (m_newVelocity.LengthSquared() < 1e-6f) 775 else if (newVelocityLengthSq < 1e-6f)
790 m_newVelocity = Vector3.Zero; 776 newVelocity = Vector3.Zero;
791 777
778 // ==================================================================
792 // Stuff new linear velocity into the vehicle 779 // Stuff new linear velocity into the vehicle
793 Prim.ForceVelocity = m_newVelocity; 780 Prim.ForceVelocity = newVelocity;
794 // Prim.ApplyForceImpulse((m_newVelocity - Prim.Velocity) * m_vehicleMass, false); // DEBUG DEBUG 781 // Prim.ApplyForceImpulse((m_newVelocity - Prim.Velocity) * m_vehicleMass, false); // DEBUG DEBUG
795 782
796 Vector3 totalDownForce = downForce + grav; 783 // Other linear forces are applied as forces.
784 Vector3 totalDownForce = grav * m_vehicleMass;
797 if (totalDownForce != Vector3.Zero) 785 if (totalDownForce != Vector3.Zero)
798 { 786 {
799 Prim.AddForce(totalDownForce * m_vehicleMass, false); 787 Prim.AddForce(totalDownForce, false);
800 // Prim.ApplyForceImpulse(totalDownForce * m_vehicleMass, false);
801 } 788 }
802 789
803 VDetailLog("{0},MoveLinear,done,lmDir={1},lmVel={2},newVel={3},primVel={4},totalDown={5}", 790 VDetailLog("{0},MoveLinear,done,lmDir={1},lmVel={2},newVel={3},primVel={4},totalDown={5}",
804 Prim.LocalID, m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity, Prim.Velocity, totalDownForce); 791 Prim.LocalID, m_linearMotorDirection, m_lastLinearVelocityVector,
792 newVelocity, Prim.Velocity, totalDownForce);
805 793
806 } // end MoveLinear() 794 } // end MoveLinear()
807 795
808 // ======================================================================= 796 // =======================================================================
797 // =======================================================================
809 // Apply the effect of the angular motor. 798 // Apply the effect of the angular motor.
810 private void MoveAngular(float pTimestep) 799 private void MoveAngular(float pTimestep)
811 { 800 {
812 // m_angularMotorDirection // angular velocity requested by LSL motor 801 // m_angularMotorDirection // angular velocity requested by LSL motor
813 // m_angularMotorApply // application frame counter
814 // m_angularMotorVelocity // current angular motor velocity (ramps up and down) 802 // m_angularMotorVelocity // current angular motor velocity (ramps up and down)
815 // m_angularMotorTimescale // motor angular velocity ramp up rate 803 // m_angularMotorTimescale // motor angular velocity ramp up time
816 // m_angularMotorDecayTimescale // motor angular velocity decay rate 804 // m_angularMotorDecayTimescale // motor angular velocity decay rate
817 // m_angularFrictionTimescale // body angular velocity decay rate 805 // m_angularFrictionTimescale // body angular velocity decay rate
818 // m_lastAngularVelocity // what was last applied to body 806 // m_lastAngularVelocity // what was last applied to body
@@ -836,18 +824,16 @@ namespace OpenSim.Region.Physics.BulletSPlugin
836 m_angularMotorVelocity = Vector3.Zero; 824 m_angularMotorVelocity = Vector3.Zero;
837 } 825 }
838 826
839 #region Vertical attactor 827 Vector3 angularMotorContribution = m_angularMotor.Step(pTimestep);
840
841 Vector3 vertattr = Vector3.Zero;
842 Vector3 deflection = Vector3.Zero;
843 Vector3 banking = Vector3.Zero;
844 828
829 // ==================================================================
830 Vector3 verticalAttractionContribution = Vector3.Zero;
845 // If vertical attaction timescale is reasonable and we applied an angular force last time... 831 // If vertical attaction timescale is reasonable and we applied an angular force last time...
846 if (m_verticalAttractionTimescale < 300 && m_lastAngularVelocity != Vector3.Zero) 832 if (m_verticalAttractionTimescale < 300 && m_lastAngularVelocity != Vector3.Zero)
847 { 833 {
848 float VAservo = pTimestep * 0.2f / m_verticalAttractionTimescale; 834 float VAservo = pTimestep * 0.2f / m_verticalAttractionTimescale;
849 if (Prim.IsColliding) 835 if (Prim.IsColliding)
850 VAservo = pTimestep * 0.05f / (m_verticalAttractionTimescale); 836 VAservo = pTimestep * 0.05f / m_verticalAttractionTimescale;
851 837
852 VAservo *= (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency); 838 VAservo *= (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency);
853 839
@@ -871,24 +857,23 @@ namespace OpenSim.Region.Physics.BulletSPlugin
871 // As the body rotates around the X axis, then verticalError.Y increases; Rotated around Y 857 // As the body rotates around the X axis, then verticalError.Y increases; Rotated around Y
872 // then .X increases, so change Body angular velocity X based on Y, and Y based on X. 858 // then .X increases, so change Body angular velocity X based on Y, and Y based on X.
873 // Z is not changed. 859 // Z is not changed.
874 vertattr.X = verticalError.Y; 860 verticalAttractionContribution.X = verticalError.Y;
875 vertattr.Y = - verticalError.X; 861 verticalAttractionContribution.Y = - verticalError.X;
876 vertattr.Z = 0f; 862 verticalAttractionContribution.Z = 0f;
877 863
878 // scaling appears better usingsquare-law 864 // scaling appears better usingsquare-law
879 Vector3 angularVelocity = Prim.ForceRotationalVelocity; 865 Vector3 angularVelocity = Prim.ForceRotationalVelocity;
880 float bounce = 1.0f - (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency); 866 float bounce = 1.0f - (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency);
881 vertattr.X += bounce * angularVelocity.X; 867 verticalAttractionContribution.X += bounce * angularVelocity.X;
882 vertattr.Y += bounce * angularVelocity.Y; 868 verticalAttractionContribution.Y += bounce * angularVelocity.Y;
883 869
884 VDetailLog("{0},MoveAngular,verticalAttraction,VAservo={1},effic={2},verticalError={3},bounce={4},vertattr={5}", 870 VDetailLog("{0},MoveAngular,verticalAttraction,VAservo={1},effic={2},verticalError={3},bounce={4},vertattr={5}",
885 Prim.LocalID, VAservo, m_verticalAttractionEfficiency, verticalError, bounce, vertattr); 871 Prim.LocalID, VAservo, m_verticalAttractionEfficiency, verticalError, bounce, verticalAttractionContribution);
886 872
887 } 873 }
888 #endregion // Vertical attactor
889
890 #region Deflection
891 874
875 // ==================================================================
876 Vector3 deflectionContribution = Vector3.Zero;
892 if (m_angularDeflectionEfficiency != 0) 877 if (m_angularDeflectionEfficiency != 0)
893 { 878 {
894 // Compute a scaled vector that points in the preferred axis (X direction) 879 // Compute a scaled vector that points in the preferred axis (X direction)
@@ -899,18 +884,16 @@ namespace OpenSim.Region.Physics.BulletSPlugin
899 Vector3 preferredAxisOfMotion = scaledDefaultDirection * Quaternion.Add(Prim.ForceOrientation, m_referenceFrame); 884 Vector3 preferredAxisOfMotion = scaledDefaultDirection * Quaternion.Add(Prim.ForceOrientation, m_referenceFrame);
900 885
901 // Scale by efficiency and timescale 886 // Scale by efficiency and timescale
902 deflection = (preferredAxisOfMotion * (m_angularDeflectionEfficiency) / m_angularDeflectionTimescale) * pTimestep; 887 deflectionContribution = (preferredAxisOfMotion * (m_angularDeflectionEfficiency) / m_angularDeflectionTimescale) * pTimestep;
903 888
904 VDetailLog("{0},MoveAngular,Deflection,perfAxis={1},deflection={2}", 889 VDetailLog("{0},MoveAngular,Deflection,perfAxis={1},deflection={2}",
905 Prim.LocalID, preferredAxisOfMotion, deflection); 890 Prim.LocalID, preferredAxisOfMotion, deflectionContribution);
906 // This deflection computation is not correct. 891 // This deflection computation is not correct.
907 deflection = Vector3.Zero; 892 deflectionContribution = Vector3.Zero;
908 } 893 }
909 894
910 #endregion 895 // ==================================================================
911 896 Vector3 bankingContribution = Vector3.Zero;
912 #region Banking
913
914 if (m_bankingEfficiency != 0) 897 if (m_bankingEfficiency != 0)
915 { 898 {
916 Vector3 dir = Vector3.One * Prim.ForceOrientation; 899 Vector3 dir = Vector3.One * Prim.ForceOrientation;
@@ -925,6 +908,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
925 float mix = Math.Abs(m_bankingMix); 908 float mix = Math.Abs(m_bankingMix);
926 if (m_angularMotorVelocity.X == 0) 909 if (m_angularMotorVelocity.X == 0)
927 { 910 {
911 // The vehicle is stopped
928 /*if (!parent.Orientation.ApproxEquals(this.m_referenceFrame, 0.25f)) 912 /*if (!parent.Orientation.ApproxEquals(this.m_referenceFrame, 0.25f))
929 { 913 {
930 Vector3 axisAngle; 914 Vector3 axisAngle;
@@ -938,9 +922,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin
938 }*/ 922 }*/
939 } 923 }
940 else 924 else
941 banking.Z += (effSquared*(mult*mix))*(m_angularMotorVelocity.X) * 4; 925 {
926 bankingContribution.Z += (effSquared * (mult * mix)) * (m_angularMotorVelocity.X) * 4;
927 }
928
929 //If they are colliding, we probably shouldn't shove the prim around... probably
942 if (!Prim.IsColliding && Math.Abs(m_angularMotorVelocity.X) > mix) 930 if (!Prim.IsColliding && Math.Abs(m_angularMotorVelocity.X) > mix)
943 //If they are colliding, we probably shouldn't shove the prim around... probably
944 { 931 {
945 float angVelZ = m_angularMotorVelocity.X*-1; 932 float angVelZ = m_angularMotorVelocity.X*-1;
946 /*if(angVelZ > mix) 933 /*if(angVelZ > mix)
@@ -954,22 +941,23 @@ namespace OpenSim.Region.Physics.BulletSPlugin
954 else if (bankingRot.X < -3) 941 else if (bankingRot.X < -3)
955 bankingRot.X = -3; 942 bankingRot.X = -3;
956 bankingRot *= Prim.ForceOrientation; 943 bankingRot *= Prim.ForceOrientation;
957 banking += bankingRot; 944 bankingContribution += bankingRot;
958 } 945 }
959 m_angularMotorVelocity.X *= m_bankingEfficiency == 1 ? 0.0f : 1 - m_bankingEfficiency; 946 m_angularMotorVelocity.X *= m_bankingEfficiency == 1 ? 0.0f : 1 - m_bankingEfficiency;
960 VDetailLog("{0},MoveAngular,Banking,bEff={1},angMotVel={2},banking={3}", 947 VDetailLog("{0},MoveAngular,Banking,bEff={1},angMotVel={2},effSq={3},mult={4},mix={5},banking={6}",
961 Prim.LocalID, m_bankingEfficiency, m_angularMotorVelocity, banking); 948 Prim.LocalID, m_bankingEfficiency, m_angularMotorVelocity, effSquared, mult, mix, bankingContribution);
962 } 949 }
963 950
964 #endregion 951 // ==================================================================
965 952 m_lastVertAttractor = verticalAttractionContribution;
966 m_lastVertAttractor = vertattr;
967 953
968 // Sum velocities 954 // Sum velocities
969 m_lastAngularVelocity = m_angularMotorVelocity + vertattr + banking + deflection; 955 m_lastAngularVelocity = angularMotorContribution
970 956 + verticalAttractionContribution
971 #region Linear Motor Offset 957 + bankingContribution
958 + deflectionContribution;
972 959
960 // ==================================================================
973 //Offset section 961 //Offset section
974 if (m_linearMotorOffset != Vector3.Zero) 962 if (m_linearMotorOffset != Vector3.Zero)
975 { 963 {
@@ -985,8 +973,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
985 // 973 //
986 // The torque created is the linear velocity crossed with the offset 974 // The torque created is the linear velocity crossed with the offset
987 975
988 // NOTE: this computation does should be in the linear section 976 // TODO: this computation should be in the linear section
989 // because there we know the impulse being applied. 977 // because that is where we know the impulse being applied.
990 Vector3 torqueFromOffset = Vector3.Zero; 978 Vector3 torqueFromOffset = Vector3.Zero;
991 // torqueFromOffset = Vector3.Cross(m_linearMotorOffset, appliedImpulse); 979 // torqueFromOffset = Vector3.Cross(m_linearMotorOffset, appliedImpulse);
992 if (float.IsNaN(torqueFromOffset.X)) 980 if (float.IsNaN(torqueFromOffset.X))
@@ -1000,8 +988,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1000 VDetailLog("{0},BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset); 988 VDetailLog("{0},BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset);
1001 } 989 }
1002 990
1003 #endregion 991 // ==================================================================
1004 992 // NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement
1005 if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) 993 if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
1006 { 994 {
1007 m_lastAngularVelocity.X = 0; 995 m_lastAngularVelocity.X = 0;
@@ -1009,6 +997,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1009 VDetailLog("{0},MoveAngular,noDeflectionUp,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity); 997 VDetailLog("{0},MoveAngular,noDeflectionUp,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity);
1010 } 998 }
1011 999
1000 // ==================================================================
1012 if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f)) 1001 if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f))
1013 { 1002 {
1014 m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero. 1003 m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero.
@@ -1021,18 +1010,20 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1021 // The above calculates the absolute angular velocity needed. Angular velocity is massless. 1010 // The above calculates the absolute angular velocity needed. Angular velocity is massless.
1022 // Since we are stuffing the angular velocity directly into the object, the computed 1011 // Since we are stuffing the angular velocity directly into the object, the computed
1023 // velocity needs to be scaled by the timestep. 1012 // velocity needs to be scaled by the timestep.
1024 Vector3 applyAngularForce = ((m_lastAngularVelocity * pTimestep) - Prim.ForceRotationalVelocity); 1013 // Also remove any motion that is on the object so added motion is only from vehicle.
1014 Vector3 applyAngularForce = ((m_lastAngularVelocity * pTimestep)
1015 - Prim.ForceRotationalVelocity);
1025 Prim.ForceRotationalVelocity = applyAngularForce; 1016 Prim.ForceRotationalVelocity = applyAngularForce;
1026 1017
1027 // Decay the angular movement for next time 1018 VDetailLog("{0},MoveAngular,done,newRotVel={1},lastAngular={2}",
1028 Vector3 decayamount = (Vector3.One / m_angularFrictionTimescale) * pTimestep; 1019 Prim.LocalID, applyAngularForce, m_lastAngularVelocity);
1029 m_lastAngularVelocity *= Vector3.One - decayamount;
1030
1031 VDetailLog("{0},MoveAngular,done,newRotVel={1},decay={2},lastAngular={3}",
1032 Prim.LocalID, applyAngularForce, decayamount, m_lastAngularVelocity);
1033 } 1020 }
1034 } //end MoveAngular 1021 }
1035 1022
1023 // This is from previous instantiations of XXXDynamics.cs.
1024 // Applies roll reference frame.
1025 // TODO: is this the right way to separate the code to do this operation?
1026 // Should this be in MoveAngular()?
1036 internal void LimitRotation(float timestep) 1027 internal void LimitRotation(float timestep)
1037 { 1028 {
1038 Quaternion rotq = Prim.ForceOrientation; 1029 Quaternion rotq = Prim.ForceOrientation;
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs
new file mode 100755
index 0000000..663b6f4
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs
@@ -0,0 +1,191 @@
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;
30using System.Reflection;
31using Nini.Config;
32
33namespace OpenSim.Region.Physics.BulletSPlugin
34{
35
36public struct MaterialAttributes
37{
38 // Material type values that correspond with definitions for LSL
39 public enum Material : int
40 {
41 Stone = 0,
42 Metal,
43 Glass,
44 Wood,
45 Flesh,
46 Plastic,
47 Rubber,
48 Light,
49 // Hereafter are BulletSim additions
50 Avatar,
51 NumberOfTypes // the count of types in the enum.
52 }
53 // Names must be in the order of the above enum.
54 public static string[] MaterialNames = { "Stone", "Metal", "Glass", "Wood",
55 "Flesh", "Plastic", "Rubber", "Light", "Avatar" };
56 public static string[] MaterialAttribs = { "Density", "Friction", "Restitution",
57 "ccdMotionThreshold", "ccdSweptSphereRadius" };
58
59 public MaterialAttributes(string t, float d, float f, float r, float ccdM, float ccdS)
60 {
61 type = t;
62 density = d;
63 friction = f;
64 restitution = r;
65 ccdMotionThreshold = ccdM;
66 ccdSweptSphereRadius = ccdS;
67 }
68 public string type;
69 public float density;
70 public float friction;
71 public float restitution;
72 public float ccdMotionThreshold;
73 public float ccdSweptSphereRadius;
74}
75
76public static class BSMaterials
77{
78 public static MaterialAttributes[] Attributes;
79
80 static BSMaterials()
81 {
82 // Attribute sets for both the non-physical and physical instances of materials.
83 Attributes = new MaterialAttributes[(int)MaterialAttributes.Material.NumberOfTypes * 2];
84 }
85
86 // This is where all the default material attributes are defined.
87 public static void InitializeFromDefaults(ConfigurationParameters parms)
88 {
89 // public static string[] MaterialNames = { "Stone", "Metal", "Glass", "Wood",
90 // "Flesh", "Plastic", "Rubber", "Light", "Avatar" };
91 float dFriction = parms.defaultFriction;
92 float dRestitution = parms.defaultRestitution;
93 float dDensity = parms.defaultDensity;
94 float dCcdM = parms.ccdMotionThreshold;
95 float dCcdS = parms.ccdSweptSphereRadius;
96 Attributes[(int)MaterialAttributes.Material.Stone] =
97 new MaterialAttributes("stone",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
98 Attributes[(int)MaterialAttributes.Material.Metal] =
99 new MaterialAttributes("metal",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
100 Attributes[(int)MaterialAttributes.Material.Glass] =
101 new MaterialAttributes("glass",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
102 Attributes[(int)MaterialAttributes.Material.Wood] =
103 new MaterialAttributes("wood",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
104 Attributes[(int)MaterialAttributes.Material.Flesh] =
105 new MaterialAttributes("flesh",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
106 Attributes[(int)MaterialAttributes.Material.Plastic] =
107 new MaterialAttributes("plastic",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
108 Attributes[(int)MaterialAttributes.Material.Rubber] =
109 new MaterialAttributes("rubber",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
110 Attributes[(int)MaterialAttributes.Material.Light] =
111 new MaterialAttributes("light",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
112 Attributes[(int)MaterialAttributes.Material.Avatar] =
113 new MaterialAttributes("avatar",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
114
115 Attributes[(int)MaterialAttributes.Material.Stone + (int)MaterialAttributes.Material.NumberOfTypes] =
116 new MaterialAttributes("stonePhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
117 Attributes[(int)MaterialAttributes.Material.Metal + (int)MaterialAttributes.Material.NumberOfTypes] =
118 new MaterialAttributes("metalPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
119 Attributes[(int)MaterialAttributes.Material.Glass + (int)MaterialAttributes.Material.NumberOfTypes] =
120 new MaterialAttributes("glassPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
121 Attributes[(int)MaterialAttributes.Material.Wood + (int)MaterialAttributes.Material.NumberOfTypes] =
122 new MaterialAttributes("woodPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
123 Attributes[(int)MaterialAttributes.Material.Flesh + (int)MaterialAttributes.Material.NumberOfTypes] =
124 new MaterialAttributes("fleshPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
125 Attributes[(int)MaterialAttributes.Material.Plastic + (int)MaterialAttributes.Material.NumberOfTypes] =
126 new MaterialAttributes("plasticPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
127 Attributes[(int)MaterialAttributes.Material.Rubber + (int)MaterialAttributes.Material.NumberOfTypes] =
128 new MaterialAttributes("rubberPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
129 Attributes[(int)MaterialAttributes.Material.Light + (int)MaterialAttributes.Material.NumberOfTypes] =
130 new MaterialAttributes("lightPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
131 Attributes[(int)MaterialAttributes.Material.Avatar + (int)MaterialAttributes.Material.NumberOfTypes] =
132 new MaterialAttributes("avatarPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
133 }
134
135 // Under the [BulletSim] section, one can change the individual material
136 // attribute values. The format of the configuration parameter is:
137 // <materialName><Attribute>["Physical"] = floatValue
138 // For instance:
139 // [BulletSim]
140 // StoneFriction = 0.2
141 // FleshRestitutionPhysical = 0.8
142 // Materials can have different parameters for their static and
143 // physical instantiations. When setting the non-physical value,
144 // both values are changed. Setting the physical value only changes
145 // the physical value.
146 public static void InitializefromParameters(IConfig pConfig)
147 {
148 int matType = 0;
149 foreach (string matName in MaterialAttributes.MaterialNames)
150 {
151 foreach (string attribName in MaterialAttributes.MaterialAttribs)
152 {
153 string paramName = matName + attribName;
154 if (pConfig.Contains(paramName))
155 {
156 float paramValue = pConfig.GetFloat(paramName);
157 SetAttributeValue(matType, attribName, paramValue);
158 // set the physical value also
159 SetAttributeValue(matType + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue);
160 }
161 paramName += "Physical";
162 if (pConfig.Contains(paramName))
163 {
164 float paramValue = pConfig.GetFloat(paramName);
165 SetAttributeValue(matType + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue);
166 }
167 }
168 matType++;
169 }
170 }
171
172 private static void SetAttributeValue(int matType, string attribName, float val)
173 {
174 MaterialAttributes thisAttrib = Attributes[matType];
175 FieldInfo fieldInfo = thisAttrib.GetType().GetField(attribName);
176 if (fieldInfo != null)
177 {
178 fieldInfo.SetValue(thisAttrib, val);
179 Attributes[matType] = thisAttrib;
180 }
181 }
182
183 public static MaterialAttributes GetAttributes(MaterialAttributes.Material type, bool isPhysical)
184 {
185 int ind = (int)type;
186 if (isPhysical) ind += (int)MaterialAttributes.Material.NumberOfTypes;
187 return Attributes[ind];
188 }
189
190}
191}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
index bc6e4c4..480da2c 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
@@ -1,104 +1,152 @@
1using System; 1using System;
2using System.Collections.Generic; 2using System.Collections.Generic;
3using System.Text; 3using System.Text;
4using OpenMetaverse; 4using OpenMetaverse;
5 5
6namespace OpenSim.Region.Physics.BulletSPlugin 6namespace OpenSim.Region.Physics.BulletSPlugin
7{ 7{
8public abstract class BSMotor 8public abstract class BSMotor
9{ 9{
10 public virtual void Reset() { } 10 public BSMotor(string useName)
11 public virtual void Zero() { } 11 {
12} 12 UseName = useName;
13// Can all the incremental stepping be replaced with motor classes? 13 PhysicsScene = null;
14public class BSVMotor : BSMotor 14 }
15{ 15 public virtual void Reset() { }
16 public Vector3 FrameOfReference { get; set; } 16 public virtual void Zero() { }
17 public Vector3 Offset { get; set; } 17
18 18 public string UseName { get; private set; }
19 public float TimeScale { get; set; } 19 // Used only for outputting debug information. Might not be set so check for null.
20 public float TargetValueDecayTimeScale { get; set; } 20 public BSScene PhysicsScene { get; set; }
21 public Vector3 CurrentValueReductionTimescale { get; set; } 21 protected void MDetailLog(string msg, params Object[] parms)
22 public float Efficiency { get; set; } 22 {
23 23 if (PhysicsScene != null)
24 public Vector3 TargetValue { get; private set; } 24 {
25 public Vector3 CurrentValue { get; private set; } 25 if (PhysicsScene.VehicleLoggingEnabled)
26 26 {
27 27 PhysicsScene.DetailLog(msg, parms);
28 28 }
29 BSVMotor(float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency) 29 }
30 { 30 }
31 TimeScale = timeScale; 31}
32 TargetValueDecayTimeScale = decayTimeScale; 32// Can all the incremental stepping be replaced with motor classes?
33 CurrentValueReductionTimescale = frictionTimeScale; 33public class BSVMotor : BSMotor
34 Efficiency = efficiency; 34{
35 } 35 public Vector3 FrameOfReference { get; set; }
36 public void SetCurrent(Vector3 current) 36 public Vector3 Offset { get; set; }
37 { 37
38 CurrentValue = current; 38 public float TimeScale { get; set; }
39 } 39 public float TargetValueDecayTimeScale { get; set; }
40 public void SetTarget(Vector3 target) 40 public Vector3 FrictionTimescale { get; set; }
41 { 41 public float Efficiency { get; set; }
42 TargetValue = target; 42
43 } 43 public Vector3 TargetValue { get; private set; }
44 public Vector3 Step(float timeStep) 44 public Vector3 CurrentValue { get; private set; }
45 { 45
46 if (CurrentValue.LengthSquared() > 0.001f) 46 public BSVMotor(string useName)
47 { 47 : base(useName)
48 // Vector3 origDir = Target; // DEBUG 48 {
49 // Vector3 origVel = CurrentValue; // DEBUG 49 TimeScale = TargetValueDecayTimeScale = Efficiency = 1f;
50 50 FrictionTimescale = Vector3.Zero;
51 // Add (desiredVelocity - currentAppliedVelocity) / howLongItShouldTakeToComplete 51 CurrentValue = TargetValue = Vector3.Zero;
52 Vector3 addAmount = (TargetValue - CurrentValue)/(TargetValue) * timeStep; 52 }
53 CurrentValue += addAmount; 53 public BSVMotor(string useName, float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency)
54 54 : this(useName)
55 float decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep; 55 {
56 TargetValue *= (1f - decayFactor); 56 TimeScale = timeScale;
57 57 TargetValueDecayTimeScale = decayTimeScale;
58 Vector3 frictionFactor = (Vector3.One / CurrentValueReductionTimescale) * timeStep; 58 FrictionTimescale = frictionTimeScale;
59 CurrentValue *= (Vector3.One - frictionFactor); 59 Efficiency = efficiency;
60 } 60 CurrentValue = TargetValue = Vector3.Zero;
61 else 61 }
62 { 62 public void SetCurrent(Vector3 current)
63 // if what remains of direction is very small, zero it. 63 {
64 TargetValue = Vector3.Zero; 64 CurrentValue = current;
65 CurrentValue = Vector3.Zero; 65 }
66 66 public void SetTarget(Vector3 target)
67 // VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID); 67 {
68 } 68 TargetValue = target;
69 return CurrentValue; 69 }
70 } 70 public Vector3 Step(float timeStep)
71} 71 {
72 72 Vector3 returnCurrent = Vector3.Zero;
73public class BSFMotor : BSMotor 73 if (!CurrentValue.ApproxEquals(TargetValue, 0.01f))
74{ 74 {
75 public float TimeScale { get; set; } 75 Vector3 origTarget = TargetValue; // DEBUG
76 public float DecayTimeScale { get; set; } 76 Vector3 origCurrVal = CurrentValue; // DEBUG
77 public float Friction { get; set; } 77
78 public float Efficiency { get; set; } 78 // Addition = (desiredVector - currentAppliedVector) / secondsItShouldTakeToComplete
79 79 Vector3 addAmount = (TargetValue - CurrentValue)/TimeScale * timeStep;
80 public float Target { get; private set; } 80 CurrentValue += addAmount;
81 public float CurrentValue { get; private set; } 81 returnCurrent = CurrentValue;
82 82
83 BSFMotor(float timeScale, float decayTimescale, float friction, float efficiency) 83 // The desired value reduces to zero when also reduces the difference with current.
84 { 84 float decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep;
85 } 85 TargetValue *= (1f - decayFactor);
86 public void SetCurrent(float target) 86
87 { 87 Vector3 frictionFactor = Vector3.Zero;
88 } 88 frictionFactor = (Vector3.One / FrictionTimescale) * timeStep;
89 public void SetTarget(float target) 89 CurrentValue *= (Vector3.One - frictionFactor);
90 { 90
91 } 91 MDetailLog("{0},BSVMotor.Step,nonZero,{1},origTarget={2},origCurr={3},timeStep={4},timeScale={5},addAmnt={6},targetDecay={7},decayFact={8},fricTS={9},frictFact={10}",
92 public float Step(float timeStep) 92 BSScene.DetailLogZero, UseName, origTarget, origCurrVal,
93 { 93 timeStep, TimeScale, addAmount,
94 return 0f; 94 TargetValueDecayTimeScale, decayFactor,
95 } 95 FrictionTimescale, frictionFactor);
96} 96 MDetailLog("{0},BSVMotor.Step,nonZero,{1},curr={2},target={3},add={4},decay={5},frict={6},ret={7}",
97public class BSPIDMotor : BSMotor 97 BSScene.DetailLogZero, UseName, TargetValue, CurrentValue,
98{ 98 addAmount, decayFactor, frictionFactor, returnCurrent);
99 // TODO: write and use this one 99 }
100 BSPIDMotor() 100 else
101 { 101 {
102 } 102 // Difference between what we have and target is small. Motor is done.
103} 103 CurrentValue = Vector3.Zero;
104} 104 TargetValue = Vector3.Zero;
105
106 MDetailLog("{0},BSVMotor.Step,zero,{1},curr={2},target={3},ret={4}",
107 BSScene.DetailLogZero, UseName, TargetValue, CurrentValue, returnCurrent);
108
109 }
110 return returnCurrent;
111 }
112 public override string ToString()
113 {
114 return String.Format("<{0},curr={1},targ={2},decayTS={3},frictTS={4}>",
115 UseName, CurrentValue, TargetValue, TargetValueDecayTimeScale, FrictionTimescale);
116 }
117}
118
119public class BSFMotor : BSMotor
120{
121 public float TimeScale { get; set; }
122 public float DecayTimeScale { get; set; }
123 public float Friction { get; set; }
124 public float Efficiency { get; set; }
125
126 public float Target { get; private set; }
127 public float CurrentValue { get; private set; }
128
129 public BSFMotor(string useName, float timeScale, float decayTimescale, float friction, float efficiency)
130 : base(useName)
131 {
132 }
133 public void SetCurrent(float target)
134 {
135 }
136 public void SetTarget(float target)
137 {
138 }
139 public float Step(float timeStep)
140 {
141 return 0f;
142 }
143}
144public class BSPIDMotor : BSMotor
145{
146 // TODO: write and use this one
147 public BSPIDMotor(string useName)
148 : base(useName)
149 {
150 }
151}
152}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
index 2b3fa25..caa6c46 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -342,13 +342,12 @@ public sealed class BSPrim : BSPhysObject
342 // TODO: check for out of bounds 342 // TODO: check for out of bounds
343 343
344 // The above code computes a force to apply to correct any out-of-bounds problems. Apply same. 344 // The above code computes a force to apply to correct any out-of-bounds problems. Apply same.
345 // TODO: This should be intergrated with a geneal physics action mechanism.
346 // TODO: This should be moderated with PID'ness.
345 if (ret) 347 if (ret)
346 { 348 {
347 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.PositionSanityCheck:belowTerrain", delegate() 349 // Apply upforce and overcome gravity.
348 { 350 AddForce(upForce - PhysicsScene.DefaultGravity, false, inTaintTime);
349 // Apply upforce and overcome gravity.
350 ForceVelocity = ForceVelocity + upForce - PhysicsScene.DefaultGravity;
351 });
352 } 351 }
353 return ret; 352 return ret;
354 } 353 }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
index 27a78d1..805e670 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
@@ -39,23 +39,10 @@ using log4net;
39using OpenMetaverse; 39using OpenMetaverse;
40 40
41// TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim) 41// TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim)
42// Test sculpties (verified that they don't work)
43// Compute physics FPS reasonably
44// Based on material, set density and friction 42// Based on material, set density and friction
45// Don't use constraints in linksets of non-physical objects. Means having to move children manually.
46// Four states of prim: Physical, regular, phantom and selected. Are we modeling these correctly?
47// In SL one can set both physical and phantom (gravity, does not effect others, makes collisions with ground)
48// At the moment, physical and phantom causes object to drop through the terrain
49// Physical phantom objects and related typing (collision options )
50// Check out llVolumeDetect. Must do something for that.
51// Use collision masks for collision with terrain and phantom objects
52// More efficient memory usage when passing hull information from BSPrim to BulletSim 43// More efficient memory usage when passing hull information from BSPrim to BulletSim
53// Should prim.link() and prim.delink() membership checking happen at taint time?
54// Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once.
55// Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect 44// Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect
56// Implement LockAngularMotion 45// Implement LockAngularMotion
57// Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation)
58// Remove mesh and Hull stuff. Use mesh passed to bullet and use convexdecom from bullet.
59// Add PID movement operations. What does ScenePresence.MoveToTarget do? 46// Add PID movement operations. What does ScenePresence.MoveToTarget do?
60// Check terrain size. 128 or 127? 47// Check terrain size. 128 or 127?
61// Raycast 48// Raycast
@@ -234,6 +221,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
234 if (m_physicsLoggingEnabled) 221 if (m_physicsLoggingEnabled)
235 { 222 {
236 PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes); 223 PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes);
224 PhysicsLogging.ErrorLogger = m_log; // for DEBUG. Let's the logger output error messages.
237 } 225 }
238 else 226 else
239 { 227 {
@@ -308,6 +296,13 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
308 // Do any replacements in the parameters 296 // Do any replacements in the parameters
309 m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName); 297 m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName);
310 } 298 }
299
300 // The material characteristics.
301 BSMaterials.InitializeFromDefaults(Params);
302 if (pConfig != null)
303 {
304 BSMaterials.InitializefromParameters(pConfig);
305 }
311 } 306 }
312 } 307 }
313 308
@@ -1069,7 +1064,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
1069 (s,p,l,v) => { s.PID_P = v; } ), 1064 (s,p,l,v) => { s.PID_P = v; } ),
1070 1065
1071 new ParameterDefn("DefaultFriction", "Friction factor used on new objects", 1066 new ParameterDefn("DefaultFriction", "Friction factor used on new objects",
1072 0.5f, 1067 0.2f,
1073 (s,cf,p,v) => { s.m_params[0].defaultFriction = cf.GetFloat(p, v); }, 1068 (s,cf,p,v) => { s.m_params[0].defaultFriction = cf.GetFloat(p, v); },
1074 (s) => { return s.m_params[0].defaultFriction; }, 1069 (s) => { return s.m_params[0].defaultFriction; },
1075 (s,p,l,v) => { s.m_params[0].defaultFriction = v; } ), 1070 (s,p,l,v) => { s.m_params[0].defaultFriction = v; } ),
@@ -1084,7 +1079,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
1084 (s) => { return s.m_params[0].defaultRestitution; }, 1079 (s) => { return s.m_params[0].defaultRestitution; },
1085 (s,p,l,v) => { s.m_params[0].defaultRestitution = v; } ), 1080 (s,p,l,v) => { s.m_params[0].defaultRestitution = v; } ),
1086 new ParameterDefn("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)", 1081 new ParameterDefn("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)",
1087 0f, 1082 0.04f,
1088 (s,cf,p,v) => { s.m_params[0].collisionMargin = cf.GetFloat(p, v); }, 1083 (s,cf,p,v) => { s.m_params[0].collisionMargin = cf.GetFloat(p, v); },
1089 (s) => { return s.m_params[0].collisionMargin; }, 1084 (s) => { return s.m_params[0].collisionMargin; },
1090 (s,p,l,v) => { s.m_params[0].collisionMargin = v; } ), 1085 (s,p,l,v) => { s.m_params[0].collisionMargin = v; } ),
@@ -1151,7 +1146,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
1151 (s) => { return s.m_params[0].terrainImplementation; }, 1146 (s) => { return s.m_params[0].terrainImplementation; },
1152 (s,p,l,v) => { s.m_params[0].terrainImplementation = v; } ), 1147 (s,p,l,v) => { s.m_params[0].terrainImplementation = v; } ),
1153 new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" , 1148 new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" ,
1154 0.5f, 1149 0.3f,
1155 (s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); }, 1150 (s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); },
1156 (s) => { return s.m_params[0].terrainFriction; }, 1151 (s) => { return s.m_params[0].terrainFriction; },
1157 (s,p,l,v) => { s.m_params[0].terrainFriction = v; /* TODO: set on real terrain */} ), 1152 (s,p,l,v) => { s.m_params[0].terrainFriction = v; /* TODO: set on real terrain */} ),
@@ -1165,13 +1160,19 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
1165 (s,cf,p,v) => { s.m_params[0].terrainRestitution = cf.GetFloat(p, v); }, 1160 (s,cf,p,v) => { s.m_params[0].terrainRestitution = cf.GetFloat(p, v); },
1166 (s) => { return s.m_params[0].terrainRestitution; }, 1161 (s) => { return s.m_params[0].terrainRestitution; },
1167 (s,p,l,v) => { s.m_params[0].terrainRestitution = v; /* TODO: set on real terrain */ } ), 1162 (s,p,l,v) => { s.m_params[0].terrainRestitution = v; /* TODO: set on real terrain */ } ),
1163 new ParameterDefn("TerrainCollisionMargin", "Margin where collision checking starts" ,
1164 0.04f,
1165 (s,cf,p,v) => { s.m_params[0].terrainCollisionMargin = cf.GetFloat(p, v); },
1166 (s) => { return s.m_params[0].terrainCollisionMargin; },
1167 (s,p,l,v) => { s.m_params[0].terrainCollisionMargin = v; /* TODO: set on real terrain */ } ),
1168
1168 new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.", 1169 new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.",
1169 0.2f, 1170 0.2f,
1170 (s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); }, 1171 (s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); },
1171 (s) => { return s.m_params[0].avatarFriction; }, 1172 (s) => { return s.m_params[0].avatarFriction; },
1172 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarFriction, p, l, v); } ), 1173 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarFriction, p, l, v); } ),
1173 new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.", 1174 new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.",
1174 10f, 1175 0.99f,
1175 (s,cf,p,v) => { s.m_params[0].avatarStandingFriction = cf.GetFloat(p, v); }, 1176 (s,cf,p,v) => { s.m_params[0].avatarStandingFriction = cf.GetFloat(p, v); },
1176 (s) => { return s.m_params[0].avatarStandingFriction; }, 1177 (s) => { return s.m_params[0].avatarStandingFriction; },
1177 (s,p,l,v) => { s.m_params[0].avatarStandingFriction = v; } ), 1178 (s,p,l,v) => { s.m_params[0].avatarStandingFriction = v; } ),
@@ -1206,6 +1207,11 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
1206 (s) => { return s.m_params[0].avatarContactProcessingThreshold; }, 1207 (s) => { return s.m_params[0].avatarContactProcessingThreshold; },
1207 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ), 1208 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ),
1208 1209
1210 new ParameterDefn("VehicleAngularDamping", "Factor to damp vehicle angular movement per second (0.0 - 1.0)",
1211 0.95f,
1212 (s,cf,p,v) => { s.m_params[0].vehicleAngularDamping = cf.GetFloat(p, v); },
1213 (s) => { return s.m_params[0].vehicleAngularDamping; },
1214 (s,p,l,v) => { s.m_params[0].vehicleAngularDamping = v; } ),
1209 1215
1210 new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)", 1216 new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)",
1211 0f, 1217 0f,
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs
index 3ca756c..1450f66 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs
@@ -93,7 +93,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
93 { 93 {
94 m_mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, m_mapInfo.ID, 94 m_mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, m_mapInfo.ID,
95 m_mapInfo.minCoords, m_mapInfo.maxCoords, 95 m_mapInfo.minCoords, m_mapInfo.maxCoords,
96 m_mapInfo.heightMap, BSTerrainManager.TERRAIN_COLLISION_MARGIN); 96 m_mapInfo.heightMap, PhysicsScene.Params.terrainCollisionMargin);
97 97
98 // Create the terrain shape from the mapInfo 98 // Create the terrain shape from the mapInfo
99 m_mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(m_mapInfo.Ptr), 99 m_mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(m_mapInfo.Ptr),
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
index 23fcfd3..cd623f1 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
@@ -80,8 +80,6 @@ public sealed class BSTerrainManager
80 // amount to make sure that a bounding box is built for the terrain. 80 // amount to make sure that a bounding box is built for the terrain.
81 public const float HEIGHT_EQUAL_FUDGE = 0.2f; 81 public const float HEIGHT_EQUAL_FUDGE = 0.2f;
82 82
83 public const float TERRAIN_COLLISION_MARGIN = 0.0f;
84
85 // Until the whole simulator is changed to pass us the region size, we rely on constants. 83 // Until the whole simulator is changed to pass us the region size, we rely on constants.
86 public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); 84 public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
87 85
@@ -129,7 +127,8 @@ public sealed class BSTerrainManager
129 { 127 {
130 // The ground plane is here to catch things that are trying to drop to negative infinity 128 // The ground plane is here to catch things that are trying to drop to negative infinity
131 BulletShape groundPlaneShape = new BulletShape( 129 BulletShape groundPlaneShape = new BulletShape(
132 BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f, TERRAIN_COLLISION_MARGIN), 130 BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f,
131 PhysicsScene.Params.terrainCollisionMargin),
133 BSPhysicsShapeType.SHAPE_GROUNDPLANE); 132 BSPhysicsShapeType.SHAPE_GROUNDPLANE);
134 m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID, 133 m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID,
135 BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID, 134 BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID,
@@ -165,17 +164,22 @@ public sealed class BSTerrainManager
165 // Release all the terrain we have allocated 164 // Release all the terrain we have allocated
166 public void ReleaseTerrain() 165 public void ReleaseTerrain()
167 { 166 {
168 foreach (KeyValuePair<Vector3, BSTerrainPhys> kvp in m_terrains) 167 lock (m_terrains)
169 { 168 {
170 kvp.Value.Dispose(); 169 foreach (KeyValuePair<Vector3, BSTerrainPhys> kvp in m_terrains)
170 {
171 kvp.Value.Dispose();
172 }
173 m_terrains.Clear();
171 } 174 }
172 m_terrains.Clear();
173 } 175 }
174 176
175 // The simulator wants to set a new heightmap for the terrain. 177 // The simulator wants to set a new heightmap for the terrain.
176 public void SetTerrain(float[] heightMap) { 178 public void SetTerrain(float[] heightMap) {
177 float[] localHeightMap = heightMap; 179 float[] localHeightMap = heightMap;
178 PhysicsScene.TaintedObject("TerrainManager.SetTerrain", delegate() 180 // If there are multiple requests for changes to the same terrain between ticks,
181 // only do that last one.
182 PhysicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate()
179 { 183 {
180 if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null) 184 if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null)
181 { 185 {
@@ -211,6 +215,7 @@ public sealed class BSTerrainManager
211 // terrain shape is created and added to the body. 215 // terrain shape is created and added to the body.
212 // This call is most often used to update the heightMap and parameters of the terrain. 216 // This call is most often used to update the heightMap and parameters of the terrain.
213 // (The above does suggest that some simplification/refactoring is in order.) 217 // (The above does suggest that some simplification/refactoring is in order.)
218 // Called during taint-time.
214 private void UpdateTerrain(uint id, float[] heightMap, 219 private void UpdateTerrain(uint id, float[] heightMap,
215 Vector3 minCoords, Vector3 maxCoords, bool inTaintTime) 220 Vector3 minCoords, Vector3 maxCoords, bool inTaintTime)
216 { 221 {
@@ -220,7 +225,7 @@ public sealed class BSTerrainManager
220 // Find high and low points of passed heightmap. 225 // Find high and low points of passed heightmap.
221 // The min and max passed in is usually the area objects can be in (maximum 226 // The min and max passed in is usually the area objects can be in (maximum
222 // object height, for instance). The terrain wants the bounding box for the 227 // object height, for instance). The terrain wants the bounding box for the
223 // terrain so we replace passed min and max Z with the actual terrain min/max Z. 228 // terrain so replace passed min and max Z with the actual terrain min/max Z.
224 float minZ = float.MaxValue; 229 float minZ = float.MaxValue;
225 float maxZ = float.MinValue; 230 float maxZ = float.MinValue;
226 foreach (float height in heightMap) 231 foreach (float height in heightMap)
@@ -238,15 +243,15 @@ public sealed class BSTerrainManager
238 243
239 Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f); 244 Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f);
240 245
241 BSTerrainPhys terrainPhys; 246 lock (m_terrains)
242 if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys))
243 { 247 {
244 // There is already a terrain in this spot. Free the old and build the new. 248 BSTerrainPhys terrainPhys;
245 DetailLog("{0},UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}", 249 if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys))
246 BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords);
247
248 PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateTerrain:UpdateExisting", delegate()
249 { 250 {
251 // There is already a terrain in this spot. Free the old and build the new.
252 DetailLog("{0},UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}",
253 BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords);
254
250 // Remove old terrain from the collection 255 // Remove old terrain from the collection
251 m_terrains.Remove(terrainRegionBase); 256 m_terrains.Remove(terrainRegionBase);
252 // Release any physical memory it may be using. 257 // Release any physical memory it may be using.
@@ -271,35 +276,24 @@ public sealed class BSTerrainManager
271 // I hate doing this, but just bail 276 // I hate doing this, but just bail
272 return; 277 return;
273 } 278 }
274 }); 279 }
275 } 280 else
276 else 281 {
277 { 282 // We don't know about this terrain so either we are creating a new terrain or
278 // We don't know about this terrain so either we are creating a new terrain or 283 // our mega-prim child is giving us a new terrain to add to the phys world
279 // our mega-prim child is giving us a new terrain to add to the phys world
280
281 // if this is a child terrain, calculate a unique terrain id
282 uint newTerrainID = id;
283 if (newTerrainID >= BSScene.CHILDTERRAIN_ID)
284 newTerrainID = ++m_terrainCount;
285
286 float[] heightMapX = heightMap;
287 Vector3 minCoordsX = minCoords;
288 Vector3 maxCoordsX = maxCoords;
289 284
290 DetailLog("{0},UpdateTerrain:NewTerrain,call,id={1}, minC={2}, maxC={3}", 285 // if this is a child terrain, calculate a unique terrain id
291 BSScene.DetailLogZero, newTerrainID, minCoords, minCoords); 286 uint newTerrainID = id;
287 if (newTerrainID >= BSScene.CHILDTERRAIN_ID)
288 newTerrainID = ++m_terrainCount;
292 289
293 // Code that must happen at taint-time 290 DetailLog("{0},UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}",
294 PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateTerrain:NewTerrain", delegate() 291 BSScene.DetailLogZero, newTerrainID, minCoords, minCoords);
295 {
296 DetailLog("{0},UpdateTerrain:NewTerrain,taint,baseX={1},baseY={2}",
297 BSScene.DetailLogZero, minCoordsX.X, minCoordsX.Y);
298 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); 292 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
299 m_terrains.Add(terrainRegionBase, newTerrainPhys); 293 m_terrains.Add(terrainRegionBase, newTerrainPhys);
300 294
301 m_terrainModified = true; 295 m_terrainModified = true;
302 }); 296 }
303 } 297 }
304 } 298 }
305 299
@@ -349,6 +343,7 @@ public sealed class BSTerrainManager
349 // with the same parameters as last time. 343 // with the same parameters as last time.
350 if (!m_terrainModified && lastHeightTX == tX && lastHeightTY == tY) 344 if (!m_terrainModified && lastHeightTX == tX && lastHeightTY == tY)
351 return lastHeight; 345 return lastHeight;
346 m_terrainModified = false;
352 347
353 lastHeightTX = tX; 348 lastHeightTX = tX;
354 lastHeightTY = tY; 349 lastHeightTY = tY;
@@ -358,19 +353,19 @@ public sealed class BSTerrainManager
358 int offsetY = ((int)(tY / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y; 353 int offsetY = ((int)(tY / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y;
359 Vector3 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f); 354 Vector3 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f);
360 355
361 BSTerrainPhys physTerrain; 356 lock (m_terrains)
362 if (m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain))
363 { 357 {
364 ret = physTerrain.GetHeightAtXYZ(loc - terrainBaseXYZ); 358 BSTerrainPhys physTerrain;
365 DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,loc={1},base={2},height={3}", 359 if (m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain))
366 BSScene.DetailLogZero, loc, terrainBaseXYZ, ret); 360 {
367 } 361 ret = physTerrain.GetHeightAtXYZ(loc - terrainBaseXYZ);
368 else 362 }
369 { 363 else
370 PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}", 364 {
371 LogHeader, PhysicsScene.RegionName, tX, tY); 365 PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}",
366 LogHeader, PhysicsScene.RegionName, tX, tY);
367 }
372 } 368 }
373 m_terrainModified = false;
374 lastHeight = ret; 369 lastHeight = ret;
375 return ret; 370 return ret;
376 } 371 }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
index dca7150..d7afdeb 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
@@ -217,8 +217,6 @@ public sealed class BSTerrainMesh : BSTerrainPhys
217 } 217 }
218 } 218 }
219 verticesCount = verticesCount / 3; 219 verticesCount = verticesCount / 3;
220 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,completeVerts,verCount={1}",
221 BSScene.DetailLogZero, verticesCount);
222 220
223 for (int yy = 0; yy < sizeY; yy++) 221 for (int yy = 0; yy < sizeY; yy++)
224 { 222 {
@@ -235,8 +233,6 @@ public sealed class BSTerrainMesh : BSTerrainPhys
235 indicesCount += 6; 233 indicesCount += 6;
236 } 234 }
237 } 235 }
238 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,completeIndices,indCount={1}", // DEEBUG DEBUG DEBUG
239 LogHeader, indicesCount); // DEBUG
240 ret = true; 236 ret = true;
241 } 237 }
242 catch (Exception e) 238 catch (Exception e)
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
index e60a760..12baee9 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
@@ -287,6 +287,8 @@ public struct ConfigurationParameters
287 public float terrainFriction; 287 public float terrainFriction;
288 public float terrainHitFraction; 288 public float terrainHitFraction;
289 public float terrainRestitution; 289 public float terrainRestitution;
290 public float terrainCollisionMargin;
291
290 public float avatarFriction; 292 public float avatarFriction;
291 public float avatarStandingFriction; 293 public float avatarStandingFriction;
292 public float avatarDensity; 294 public float avatarDensity;
@@ -296,6 +298,8 @@ public struct ConfigurationParameters
296 public float avatarCapsuleHeight; 298 public float avatarCapsuleHeight;
297 public float avatarContactProcessingThreshold; 299 public float avatarContactProcessingThreshold;
298 300
301 public float vehicleAngularDamping;
302
299 public float maxPersistantManifoldPoolSize; 303 public float maxPersistantManifoldPoolSize;
300 public float maxCollisionAlgorithmPoolSize; 304 public float maxCollisionAlgorithmPoolSize;
301 public float shouldDisableContactPoolDynamicAllocation; 305 public float shouldDisableContactPoolDynamicAllocation;
@@ -482,6 +486,9 @@ public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData)
482public static extern bool IsNativeShape2(IntPtr shape); 486public static extern bool IsNativeShape2(IntPtr shape);
483 487
484[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 488[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
489public static extern void SetShapeCollisionMargin(IntPtr shape, float margin);
490
491[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
485public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale); 492public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale);
486 493
487[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 494[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]