aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/PhysicsModules/BulletS/BSDynamics.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/PhysicsModules/BulletS/BSDynamics.cs (renamed from OpenSim/Region/Physics/BulletSNPlugin/BSDynamics.cs)1099
1 files changed, 761 insertions, 338 deletions
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSDynamics.cs b/OpenSim/Region/PhysicsModules/BulletS/BSDynamics.cs
index 415ad4f..0fc5577 100644
--- a/OpenSim/Region/Physics/BulletSNPlugin/BSDynamics.cs
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSDynamics.cs
@@ -35,17 +35,21 @@ using System.Collections.Generic;
35using System.Reflection; 35using System.Reflection;
36using System.Runtime.InteropServices; 36using System.Runtime.InteropServices;
37using OpenMetaverse; 37using OpenMetaverse;
38using OpenSim.Region.Physics.Manager; 38using OpenSim.Framework;
39using OpenSim.Region.PhysicsModules.SharedBase;
39 40
40namespace OpenSim.Region.Physics.BulletSNPlugin 41namespace OpenSim.Region.PhysicsModule.BulletS
41{ 42{
42 public sealed class BSDynamics 43 public sealed class BSDynamics : BSActor
43 { 44 {
45#pragma warning disable 414
44 private static string LogHeader = "[BULLETSIM VEHICLE]"; 46 private static string LogHeader = "[BULLETSIM VEHICLE]";
47#pragma warning restore 414
45 48
46 private BSScene PhysicsScene { get; set; }
47 // the prim this dynamic controller belongs to 49 // the prim this dynamic controller belongs to
48 private BSPrim Prim { get; set; } 50 private BSPrimLinkable ControllingPrim { get; set; }
51
52 private bool m_haveRegisteredForSceneEvents;
49 53
50 // mass of the vehicle fetched each time we're calles 54 // mass of the vehicle fetched each time we're calles
51 private float m_vehicleMass; 55 private float m_vehicleMass;
@@ -72,8 +76,8 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
72 private Vector3 m_linearMotorOffset = Vector3.Zero; // the point of force can be offset from the center 76 private Vector3 m_linearMotorOffset = Vector3.Zero; // the point of force can be offset from the center
73 private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL 77 private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL
74 private Vector3 m_linearFrictionTimescale = Vector3.Zero; 78 private Vector3 m_linearFrictionTimescale = Vector3.Zero;
75 private float m_linearMotorDecayTimescale = 0; 79 private float m_linearMotorDecayTimescale = 1;
76 private float m_linearMotorTimescale = 0; 80 private float m_linearMotorTimescale = 1;
77 private Vector3 m_lastLinearVelocityVector = Vector3.Zero; 81 private Vector3 m_lastLinearVelocityVector = Vector3.Zero;
78 private Vector3 m_lastPositionVector = Vector3.Zero; 82 private Vector3 m_lastPositionVector = Vector3.Zero;
79 // private bool m_LinearMotorSetLastFrame = false; 83 // private bool m_LinearMotorSetLastFrame = false;
@@ -84,8 +88,8 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
84 private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor 88 private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor
85 // private int m_angularMotorApply = 0; // application frame counter 89 // private int m_angularMotorApply = 0; // application frame counter
86 private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity 90 private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity
87 private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate 91 private float m_angularMotorTimescale = 1; // motor angular velocity ramp up rate
88 private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate 92 private float m_angularMotorDecayTimescale = 1; // motor angular velocity decay rate
89 private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate 93 private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate
90 private Vector3 m_lastAngularVelocity = Vector3.Zero; 94 private Vector3 m_lastAngularVelocity = Vector3.Zero;
91 private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body 95 private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body
@@ -99,7 +103,7 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
99 103
100 //Banking properties 104 //Banking properties
101 private float m_bankingEfficiency = 0; 105 private float m_bankingEfficiency = 0;
102 private float m_bankingMix = 0; 106 private float m_bankingMix = 1;
103 private float m_bankingTimescale = 0; 107 private float m_bankingTimescale = 0;
104 108
105 //Hover and Buoyancy properties 109 //Hover and Buoyancy properties
@@ -108,10 +112,9 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
108 private float m_VhoverEfficiency = 0f; 112 private float m_VhoverEfficiency = 0f;
109 private float m_VhoverTimescale = 0f; 113 private float m_VhoverTimescale = 0f;
110 private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height 114 private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height
111 private float m_VehicleBuoyancy = 0f; //KF: m_VehicleBuoyancy is set by VEHICLE_BUOYANCY for a vehicle. 115 // Modifies gravity. Slider between -1 (double-gravity) and 1 (full anti-gravity)
112 // Modifies gravity. Slider between -1 (double-gravity) and 1 (full anti-gravity) 116 private float m_VehicleBuoyancy = 0f;
113 // KF: So far I have found no good method to combine a script-requested .Z velocity and gravity. 117 private Vector3 m_VehicleGravity = Vector3.Zero; // Gravity computed when buoyancy set
114 // Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity.
115 118
116 //Attractor properties 119 //Attractor properties
117 private BSVMotor m_verticalAttractionMotor = new BSVMotor("VerticalAttraction"); 120 private BSVMotor m_verticalAttractionMotor = new BSVMotor("VerticalAttraction");
@@ -121,74 +124,95 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
121 private float m_verticalAttractionTimescale = 510f; 124 private float m_verticalAttractionTimescale = 510f;
122 125
123 // Just some recomputed constants: 126 // Just some recomputed constants:
127#pragma warning disable 414
128 static readonly float TwoPI = ((float)Math.PI) * 2f;
129 static readonly float FourPI = ((float)Math.PI) * 4f;
124 static readonly float PIOverFour = ((float)Math.PI) / 4f; 130 static readonly float PIOverFour = ((float)Math.PI) / 4f;
125 static readonly float PIOverTwo = ((float)Math.PI) / 2f; 131 static readonly float PIOverTwo = ((float)Math.PI) / 2f;
132#pragma warning restore 414
126 133
127 public BSDynamics(BSScene myScene, BSPrim myPrim) 134 public BSDynamics(BSScene myScene, BSPrim myPrim, string actorName)
135 : base(myScene, myPrim, actorName)
128 { 136 {
129 PhysicsScene = myScene;
130 Prim = myPrim;
131 Type = Vehicle.TYPE_NONE; 137 Type = Vehicle.TYPE_NONE;
138 m_haveRegisteredForSceneEvents = false;
139
140 ControllingPrim = myPrim as BSPrimLinkable;
141 if (ControllingPrim == null)
142 {
143 // THIS CANNOT HAPPEN!!
144 }
145 VDetailLog("{0},Creation", ControllingPrim.LocalID);
132 } 146 }
133 147
134 // Return 'true' if this vehicle is doing vehicle things 148 // Return 'true' if this vehicle is doing vehicle things
135 public bool IsActive 149 public bool IsActive
136 { 150 {
137 get { return Type != Vehicle.TYPE_NONE && Prim.IsPhysical; } 151 get { return (Type != Vehicle.TYPE_NONE && ControllingPrim.IsPhysicallyActive); }
152 }
153
154 // Return 'true' if this a vehicle that should be sitting on the ground
155 public bool IsGroundVehicle
156 {
157 get { return (Type == Vehicle.TYPE_CAR || Type == Vehicle.TYPE_SLED); }
138 } 158 }
139 159
140 internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue) 160 #region Vehicle parameter setting
161 public void ProcessFloatVehicleParam(Vehicle pParam, float pValue)
141 { 162 {
142 VDetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue); 163 VDetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", ControllingPrim.LocalID, pParam, pValue);
164 float clampTemp;
165
143 switch (pParam) 166 switch (pParam)
144 { 167 {
145 case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY: 168 case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY:
146 m_angularDeflectionEfficiency = Math.Max(pValue, 0.01f); 169 m_angularDeflectionEfficiency = ClampInRange(0f, pValue, 1f);
147 break; 170 break;
148 case Vehicle.ANGULAR_DEFLECTION_TIMESCALE: 171 case Vehicle.ANGULAR_DEFLECTION_TIMESCALE:
149 m_angularDeflectionTimescale = Math.Max(pValue, 0.01f); 172 m_angularDeflectionTimescale = ClampInRange(0.25f, pValue, 120);
150 break; 173 break;
151 case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE: 174 case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE:
152 m_angularMotorDecayTimescale = ClampInRange(0.01f, pValue, 120); 175 m_angularMotorDecayTimescale = ClampInRange(0.25f, pValue, 120);
153 m_angularMotor.TargetValueDecayTimeScale = m_angularMotorDecayTimescale; 176 m_angularMotor.TargetValueDecayTimeScale = m_angularMotorDecayTimescale;
154 break; 177 break;
155 case Vehicle.ANGULAR_MOTOR_TIMESCALE: 178 case Vehicle.ANGULAR_MOTOR_TIMESCALE:
156 m_angularMotorTimescale = Math.Max(pValue, 0.01f); 179 m_angularMotorTimescale = ClampInRange(0.25f, pValue, 120);
157 m_angularMotor.TimeScale = m_angularMotorTimescale; 180 m_angularMotor.TimeScale = m_angularMotorTimescale;
158 break; 181 break;
159 case Vehicle.BANKING_EFFICIENCY: 182 case Vehicle.BANKING_EFFICIENCY:
160 m_bankingEfficiency = ClampInRange(-1f, pValue, 1f); 183 m_bankingEfficiency = ClampInRange(-1f, pValue, 1f);
161 break; 184 break;
162 case Vehicle.BANKING_MIX: 185 case Vehicle.BANKING_MIX:
163 m_bankingMix = Math.Max(pValue, 0.01f); 186 m_bankingMix = ClampInRange(0.01f, pValue, 1);
164 break; 187 break;
165 case Vehicle.BANKING_TIMESCALE: 188 case Vehicle.BANKING_TIMESCALE:
166 m_bankingTimescale = Math.Max(pValue, 0.01f); 189 m_bankingTimescale = ClampInRange(0.25f, pValue, 120);
167 break; 190 break;
168 case Vehicle.BUOYANCY: 191 case Vehicle.BUOYANCY:
169 m_VehicleBuoyancy = ClampInRange(-1f, pValue, 1f); 192 m_VehicleBuoyancy = ClampInRange(-1f, pValue, 1f);
193 m_VehicleGravity = ControllingPrim.ComputeGravity(m_VehicleBuoyancy);
170 break; 194 break;
171 case Vehicle.HOVER_EFFICIENCY: 195 case Vehicle.HOVER_EFFICIENCY:
172 m_VhoverEfficiency = ClampInRange(0f, pValue, 1f); 196 m_VhoverEfficiency = ClampInRange(0.01f, pValue, 1f);
173 break; 197 break;
174 case Vehicle.HOVER_HEIGHT: 198 case Vehicle.HOVER_HEIGHT:
175 m_VhoverHeight = pValue; 199 m_VhoverHeight = ClampInRange(0f, pValue, 1000000f);
176 break; 200 break;
177 case Vehicle.HOVER_TIMESCALE: 201 case Vehicle.HOVER_TIMESCALE:
178 m_VhoverTimescale = Math.Max(pValue, 0.01f); 202 m_VhoverTimescale = ClampInRange(0.01f, pValue, 120);
179 break; 203 break;
180 case Vehicle.LINEAR_DEFLECTION_EFFICIENCY: 204 case Vehicle.LINEAR_DEFLECTION_EFFICIENCY:
181 m_linearDeflectionEfficiency = Math.Max(pValue, 0.01f); 205 m_linearDeflectionEfficiency = ClampInRange(0f, pValue, 1f);
182 break; 206 break;
183 case Vehicle.LINEAR_DEFLECTION_TIMESCALE: 207 case Vehicle.LINEAR_DEFLECTION_TIMESCALE:
184 m_linearDeflectionTimescale = Math.Max(pValue, 0.01f); 208 m_linearDeflectionTimescale = ClampInRange(0.01f, pValue, 120);
185 break; 209 break;
186 case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE: 210 case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE:
187 m_linearMotorDecayTimescale = ClampInRange(0.01f, pValue, 120); 211 m_linearMotorDecayTimescale = ClampInRange(0.01f, pValue, 120);
188 m_linearMotor.TargetValueDecayTimeScale = m_linearMotorDecayTimescale; 212 m_linearMotor.TargetValueDecayTimeScale = m_linearMotorDecayTimescale;
189 break; 213 break;
190 case Vehicle.LINEAR_MOTOR_TIMESCALE: 214 case Vehicle.LINEAR_MOTOR_TIMESCALE:
191 m_linearMotorTimescale = Math.Max(pValue, 0.01f); 215 m_linearMotorTimescale = ClampInRange(0.01f, pValue, 120);
192 m_linearMotor.TimeScale = m_linearMotorTimescale; 216 m_linearMotor.TimeScale = m_linearMotorTimescale;
193 break; 217 break;
194 case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY: 218 case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY:
@@ -196,31 +220,35 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
196 m_verticalAttractionMotor.Efficiency = m_verticalAttractionEfficiency; 220 m_verticalAttractionMotor.Efficiency = m_verticalAttractionEfficiency;
197 break; 221 break;
198 case Vehicle.VERTICAL_ATTRACTION_TIMESCALE: 222 case Vehicle.VERTICAL_ATTRACTION_TIMESCALE:
199 m_verticalAttractionTimescale = Math.Max(pValue, 0.01f); 223 m_verticalAttractionTimescale = ClampInRange(0.01f, pValue, 120);
200 m_verticalAttractionMotor.TimeScale = m_verticalAttractionTimescale; 224 m_verticalAttractionMotor.TimeScale = m_verticalAttractionTimescale;
201 break; 225 break;
202 226
203 // These are vector properties but the engine lets you use a single float value to 227 // These are vector properties but the engine lets you use a single float value to
204 // set all of the components to the same value 228 // set all of the components to the same value
205 case Vehicle.ANGULAR_FRICTION_TIMESCALE: 229 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
206 m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue); 230 clampTemp = ClampInRange(0.01f, pValue, 120);
207 m_angularMotor.FrictionTimescale = m_angularFrictionTimescale; 231 m_angularFrictionTimescale = new Vector3(clampTemp, clampTemp, clampTemp);
208 break; 232 break;
209 case Vehicle.ANGULAR_MOTOR_DIRECTION: 233 case Vehicle.ANGULAR_MOTOR_DIRECTION:
210 m_angularMotorDirection = new Vector3(pValue, pValue, pValue); 234 clampTemp = ClampInRange(-TwoPI, pValue, TwoPI);
235 m_angularMotorDirection = new Vector3(clampTemp, clampTemp, clampTemp);
236 m_angularMotor.Zero();
211 m_angularMotor.SetTarget(m_angularMotorDirection); 237 m_angularMotor.SetTarget(m_angularMotorDirection);
212 break; 238 break;
213 case Vehicle.LINEAR_FRICTION_TIMESCALE: 239 case Vehicle.LINEAR_FRICTION_TIMESCALE:
214 m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); 240 clampTemp = ClampInRange(0.01f, pValue, 120);
215 m_linearMotor.FrictionTimescale = m_linearFrictionTimescale; 241 m_linearFrictionTimescale = new Vector3(clampTemp, clampTemp, clampTemp);
216 break; 242 break;
217 case Vehicle.LINEAR_MOTOR_DIRECTION: 243 case Vehicle.LINEAR_MOTOR_DIRECTION:
218 m_linearMotorDirection = new Vector3(pValue, pValue, pValue); 244 clampTemp = ClampInRange(-BSParam.MaxLinearVelocity, pValue, BSParam.MaxLinearVelocity);
219 m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue); 245 m_linearMotorDirection = new Vector3(clampTemp, clampTemp, clampTemp);
246 m_linearMotorDirectionLASTSET = new Vector3(clampTemp, clampTemp, clampTemp);
220 m_linearMotor.SetTarget(m_linearMotorDirection); 247 m_linearMotor.SetTarget(m_linearMotorDirection);
221 break; 248 break;
222 case Vehicle.LINEAR_MOTOR_OFFSET: 249 case Vehicle.LINEAR_MOTOR_OFFSET:
223 m_linearMotorOffset = new Vector3(pValue, pValue, pValue); 250 clampTemp = ClampInRange(-1000, pValue, 1000);
251 m_linearMotorOffset = new Vector3(clampTemp, clampTemp, clampTemp);
224 break; 252 break;
225 253
226 } 254 }
@@ -228,34 +256,50 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
228 256
229 internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue) 257 internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue)
230 { 258 {
231 VDetailLog("{0},ProcessVectorVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue); 259 VDetailLog("{0},ProcessVectorVehicleParam,param={1},val={2}", ControllingPrim.LocalID, pParam, pValue);
232 switch (pParam) 260 switch (pParam)
233 { 261 {
234 case Vehicle.ANGULAR_FRICTION_TIMESCALE: 262 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
263 pValue.X = ClampInRange(0.25f, pValue.X, 120);
264 pValue.Y = ClampInRange(0.25f, pValue.Y, 120);
265 pValue.Z = ClampInRange(0.25f, pValue.Z, 120);
235 m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); 266 m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
236 m_angularMotor.FrictionTimescale = m_angularFrictionTimescale;
237 break; 267 break;
238 case Vehicle.ANGULAR_MOTOR_DIRECTION: 268 case Vehicle.ANGULAR_MOTOR_DIRECTION:
239 // Limit requested angular speed to 2 rps= 4 pi rads/sec 269 // Limit requested angular speed to 2 rps= 4 pi rads/sec
240 pValue.X = ClampInRange(-12.56f, pValue.X, 12.56f); 270 pValue.X = ClampInRange(-FourPI, pValue.X, FourPI);
241 pValue.Y = ClampInRange(-12.56f, pValue.Y, 12.56f); 271 pValue.Y = ClampInRange(-FourPI, pValue.Y, FourPI);
242 pValue.Z = ClampInRange(-12.56f, pValue.Z, 12.56f); 272 pValue.Z = ClampInRange(-FourPI, pValue.Z, FourPI);
243 m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); 273 m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
274 m_angularMotor.Zero();
244 m_angularMotor.SetTarget(m_angularMotorDirection); 275 m_angularMotor.SetTarget(m_angularMotorDirection);
245 break; 276 break;
246 case Vehicle.LINEAR_FRICTION_TIMESCALE: 277 case Vehicle.LINEAR_FRICTION_TIMESCALE:
278 pValue.X = ClampInRange(0.25f, pValue.X, 120);
279 pValue.Y = ClampInRange(0.25f, pValue.Y, 120);
280 pValue.Z = ClampInRange(0.25f, pValue.Z, 120);
247 m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); 281 m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
248 m_linearMotor.FrictionTimescale = m_linearFrictionTimescale;
249 break; 282 break;
250 case Vehicle.LINEAR_MOTOR_DIRECTION: 283 case Vehicle.LINEAR_MOTOR_DIRECTION:
284 pValue.X = ClampInRange(-BSParam.MaxLinearVelocity, pValue.X, BSParam.MaxLinearVelocity);
285 pValue.Y = ClampInRange(-BSParam.MaxLinearVelocity, pValue.Y, BSParam.MaxLinearVelocity);
286 pValue.Z = ClampInRange(-BSParam.MaxLinearVelocity, pValue.Z, BSParam.MaxLinearVelocity);
251 m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); 287 m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
252 m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z); 288 m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z);
253 m_linearMotor.SetTarget(m_linearMotorDirection); 289 m_linearMotor.SetTarget(m_linearMotorDirection);
254 break; 290 break;
255 case Vehicle.LINEAR_MOTOR_OFFSET: 291 case Vehicle.LINEAR_MOTOR_OFFSET:
292 // Not sure the correct range to limit this variable
293 pValue.X = ClampInRange(-1000, pValue.X, 1000);
294 pValue.Y = ClampInRange(-1000, pValue.Y, 1000);
295 pValue.Z = ClampInRange(-1000, pValue.Z, 1000);
256 m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z); 296 m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z);
257 break; 297 break;
258 case Vehicle.BLOCK_EXIT: 298 case Vehicle.BLOCK_EXIT:
299 // Not sure the correct range to limit this variable
300 pValue.X = ClampInRange(-10000, pValue.X, 10000);
301 pValue.Y = ClampInRange(-10000, pValue.Y, 10000);
302 pValue.Z = ClampInRange(-10000, pValue.Z, 10000);
259 m_BlockingEndPoint = new Vector3(pValue.X, pValue.Y, pValue.Z); 303 m_BlockingEndPoint = new Vector3(pValue.X, pValue.Y, pValue.Z);
260 break; 304 break;
261 } 305 }
@@ -263,7 +307,7 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
263 307
264 internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue) 308 internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue)
265 { 309 {
266 VDetailLog("{0},ProcessRotationalVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue); 310 VDetailLog("{0},ProcessRotationalVehicleParam,param={1},val={2}", ControllingPrim.LocalID, pParam, pValue);
267 switch (pParam) 311 switch (pParam)
268 { 312 {
269 case Vehicle.REFERENCE_FRAME: 313 case Vehicle.REFERENCE_FRAME:
@@ -277,7 +321,7 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
277 321
278 internal void ProcessVehicleFlags(int pParam, bool remove) 322 internal void ProcessVehicleFlags(int pParam, bool remove)
279 { 323 {
280 VDetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", Prim.LocalID, pParam, remove); 324 VDetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", ControllingPrim.LocalID, pParam, remove);
281 VehicleFlag parm = (VehicleFlag)pParam; 325 VehicleFlag parm = (VehicleFlag)pParam;
282 if (pParam == -1) 326 if (pParam == -1)
283 m_flags = (VehicleFlag)0; 327 m_flags = (VehicleFlag)0;
@@ -290,9 +334,9 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
290 } 334 }
291 } 335 }
292 336
293 internal void ProcessTypeChange(Vehicle pType) 337 public void ProcessTypeChange(Vehicle pType)
294 { 338 {
295 VDetailLog("{0},ProcessTypeChange,type={1}", Prim.LocalID, pType); 339 VDetailLog("{0},ProcessTypeChange,type={1}", ControllingPrim.LocalID, pType);
296 // Set Defaults For Type 340 // Set Defaults For Type
297 Type = pType; 341 Type = pType;
298 switch (pType) 342 switch (pType)
@@ -526,81 +570,144 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
526 break; 570 break;
527 } 571 }
528 572
529 // Update any physical parameters based on this type. 573 m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale, m_linearMotorDecayTimescale, 1f);
530 Refresh(); 574 // m_linearMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
531
532 m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale,
533 m_linearMotorDecayTimescale, m_linearFrictionTimescale,
534 1f);
535 m_linearMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
536 575
537 m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale, 576 m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale, m_angularMotorDecayTimescale, 1f);
538 m_angularMotorDecayTimescale, m_angularFrictionTimescale, 577 // m_angularMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
539 1f);
540 m_angularMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
541 578
579 /* Not implemented
542 m_verticalAttractionMotor = new BSVMotor("VerticalAttraction", m_verticalAttractionTimescale, 580 m_verticalAttractionMotor = new BSVMotor("VerticalAttraction", m_verticalAttractionTimescale,
543 BSMotor.Infinite, BSMotor.InfiniteVector, 581 BSMotor.Infinite, BSMotor.InfiniteVector,
544 m_verticalAttractionEfficiency); 582 m_verticalAttractionEfficiency);
545 // Z goes away and we keep X and Y 583 // Z goes away and we keep X and Y
546 m_verticalAttractionMotor.FrictionTimescale = new Vector3(BSMotor.Infinite, BSMotor.Infinite, 0.1f);
547 m_verticalAttractionMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) 584 m_verticalAttractionMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
585 */
586
587 if (this.Type == Vehicle.TYPE_NONE)
588 {
589 UnregisterForSceneEvents();
590 }
591 else
592 {
593 RegisterForSceneEvents();
594 }
595
596 // Update any physical parameters based on this type.
597 Refresh();
598 }
599 #endregion // Vehicle parameter setting
600
601 // BSActor.Refresh()
602 public override void Refresh()
603 {
604 // If asking for a refresh, reset the physical parameters before the next simulation step.
605 // Called whether active or not since the active state may be updated before the next step.
606 m_physicsScene.PostTaintObject("BSDynamics.Refresh", ControllingPrim.LocalID, delegate()
607 {
608 SetPhysicalParameters();
609 });
548 } 610 }
549 611
550 // Some of the properties of this prim may have changed. 612 // Some of the properties of this prim may have changed.
551 // Do any updating needed for a vehicle 613 // Do any updating needed for a vehicle
552 public void Refresh() 614 private void SetPhysicalParameters()
553 { 615 {
554 if (IsActive) 616 if (IsActive)
555 { 617 {
556 // Remember the mass so we don't have to fetch it every step 618 // Remember the mass so we don't have to fetch it every step
557 m_vehicleMass = Prim.Linkset.LinksetMass; 619 m_vehicleMass = ControllingPrim.TotalMass;
558 620
559 // Friction affects are handled by this vehicle code 621 // Friction affects are handled by this vehicle code
560 float friction = 0f; 622 // m_physicsScene.PE.SetFriction(ControllingPrim.PhysBody, BSParam.VehicleFriction);
561 BulletSimAPI.SetFriction2(Prim.PhysBody.ptr, friction); 623 // m_physicsScene.PE.SetRestitution(ControllingPrim.PhysBody, BSParam.VehicleRestitution);
624 ControllingPrim.Linkset.SetPhysicalFriction(BSParam.VehicleFriction);
625 ControllingPrim.Linkset.SetPhysicalRestitution(BSParam.VehicleRestitution);
562 626
563 // Moderate angular movement introduced by Bullet. 627 // Moderate angular movement introduced by Bullet.
564 // TODO: possibly set AngularFactor and LinearFactor for the type of vehicle. 628 // TODO: possibly set AngularFactor and LinearFactor for the type of vehicle.
565 // Maybe compute linear and angular factor and damping from params. 629 // Maybe compute linear and angular factor and damping from params.
566 float angularDamping = BSParam.VehicleAngularDamping; 630 m_physicsScene.PE.SetAngularDamping(ControllingPrim.PhysBody, BSParam.VehicleAngularDamping);
567 BulletSimAPI.SetAngularDamping2(Prim.PhysBody.ptr, angularDamping); 631 m_physicsScene.PE.SetLinearFactor(ControllingPrim.PhysBody, BSParam.VehicleLinearFactor);
632 m_physicsScene.PE.SetAngularFactorV(ControllingPrim.PhysBody, BSParam.VehicleAngularFactor);
568 633
569 // Vehicles report collision events so we know when it's on the ground 634 // Vehicles report collision events so we know when it's on the ground
570 BulletSimAPI.AddToCollisionFlags2(Prim.PhysBody.ptr, CollisionFlags.BS_VEHICLE_COLLISIONS); 635 // m_physicsScene.PE.AddToCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS);
636 ControllingPrim.Linkset.AddToPhysicalCollisionFlags(CollisionFlags.BS_VEHICLE_COLLISIONS);
637
638 // Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(ControllingPrim.PhysShape.physShapeInfo, m_vehicleMass);
639 // ControllingPrim.Inertia = inertia * BSParam.VehicleInertiaFactor;
640 // m_physicsScene.PE.SetMassProps(ControllingPrim.PhysBody, m_vehicleMass, ControllingPrim.Inertia);
641 // m_physicsScene.PE.UpdateInertiaTensor(ControllingPrim.PhysBody);
642 ControllingPrim.Linkset.ComputeAndSetLocalInertia(BSParam.VehicleInertiaFactor, m_vehicleMass);
643
644 // Set the gravity for the vehicle depending on the buoyancy
645 // TODO: what should be done if prim and vehicle buoyancy differ?
646 m_VehicleGravity = ControllingPrim.ComputeGravity(m_VehicleBuoyancy);
647 // The actual vehicle gravity is set to zero in Bullet so we can do all the application of same.
648 // m_physicsScene.PE.SetGravity(ControllingPrim.PhysBody, Vector3.Zero);
649 ControllingPrim.Linkset.SetPhysicalGravity(Vector3.Zero);
650
651 VDetailLog("{0},BSDynamics.SetPhysicalParameters,mass={1},inert={2},vehGrav={3},aDamp={4},frict={5},rest={6},lFact={7},aFact={8}",
652 ControllingPrim.LocalID, m_vehicleMass, ControllingPrim.Inertia, m_VehicleGravity,
653 BSParam.VehicleAngularDamping, BSParam.VehicleFriction, BSParam.VehicleRestitution,
654 BSParam.VehicleLinearFactor, BSParam.VehicleAngularFactor
655 );
656 }
657 else
658 {
659 if (ControllingPrim.PhysBody.HasPhysicalBody)
660 m_physicsScene.PE.RemoveFromCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS);
661 // ControllingPrim.Linkset.RemoveFromPhysicalCollisionFlags(CollisionFlags.BS_VEHICLE_COLLISIONS);
662 }
663 }
571 664
572 Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(Prim.PhysShape.ptr, m_vehicleMass); 665 // BSActor.RemoveBodyDependencies
573 BulletSimAPI.SetMassProps2(Prim.PhysBody.ptr, m_vehicleMass, localInertia); 666 public override void RemoveDependencies()
574 BulletSimAPI.UpdateInertiaTensor2(Prim.PhysBody.ptr); 667 {
668 Refresh();
669 }
575 670
576 Vector3 grav = PhysicsScene.DefaultGravity * (1f - Prim.Buoyancy); 671 // BSActor.Release()
577 BulletSimAPI.SetGravity2(Prim.PhysBody.ptr, grav); 672 public override void Dispose()
673 {
674 VDetailLog("{0},Dispose", ControllingPrim.LocalID);
675 UnregisterForSceneEvents();
676 Type = Vehicle.TYPE_NONE;
677 Enabled = false;
678 return;
679 }
578 680
579 VDetailLog("{0},BSDynamics.Refresh,mass={1},frict={2},inert={3},aDamp={4}", 681 private void RegisterForSceneEvents()
580 Prim.LocalID, m_vehicleMass, friction, localInertia, angularDamping); 682 {
581 } 683 if (!m_haveRegisteredForSceneEvents)
582 else
583 { 684 {
584 BulletSimAPI.RemoveFromCollisionFlags2(Prim.PhysBody.ptr, CollisionFlags.BS_VEHICLE_COLLISIONS); 685 m_physicsScene.BeforeStep += this.Step;
686 m_physicsScene.AfterStep += this.PostStep;
687 ControllingPrim.OnPreUpdateProperty += this.PreUpdateProperty;
688 m_haveRegisteredForSceneEvents = true;
585 } 689 }
586 } 690 }
587 691
588 public bool RemoveBodyDependencies(BSPhysObject prim) 692 private void UnregisterForSceneEvents()
589 { 693 {
590 // If active, we need to add our properties back when the body is rebuilt. 694 if (m_haveRegisteredForSceneEvents)
591 return IsActive; 695 {
696 m_physicsScene.BeforeStep -= this.Step;
697 m_physicsScene.AfterStep -= this.PostStep;
698 ControllingPrim.OnPreUpdateProperty -= this.PreUpdateProperty;
699 m_haveRegisteredForSceneEvents = false;
700 }
592 } 701 }
593 702
594 public void RestoreBodyDependencies(BSPhysObject prim) 703 private void PreUpdateProperty(ref EntityProperties entprop)
595 { 704 {
596 if (Prim.LocalID != prim.LocalID) 705 // A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet
706 // TODO: handle physics introduced by Bullet with computed vehicle physics.
707 if (IsActive)
597 { 708 {
598 // The call should be on us by our prim. Error if not. 709 entprop.RotationalVelocity = Vector3.Zero;
599 PhysicsScene.Logger.ErrorFormat("{0} RestoreBodyDependencies: called by not my prim. passedLocalID={1}, vehiclePrimLocalID={2}",
600 LogHeader, prim.LocalID, Prim.LocalID);
601 return;
602 } 710 }
603 Refresh();
604 } 711 }
605 712
606 #region Known vehicle value functions 713 #region Known vehicle value functions
@@ -617,70 +724,85 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
617 private Vector3 m_knownPosition; 724 private Vector3 m_knownPosition;
618 private Vector3 m_knownVelocity; 725 private Vector3 m_knownVelocity;
619 private Vector3 m_knownForce; 726 private Vector3 m_knownForce;
727 private Vector3 m_knownForceImpulse;
620 private Quaternion m_knownOrientation; 728 private Quaternion m_knownOrientation;
621 private Vector3 m_knownRotationalVelocity; 729 private Vector3 m_knownRotationalVelocity;
622 private Vector3 m_knownRotationalForce; 730 private Vector3 m_knownRotationalForce;
623 private Vector3 m_knownForwardVelocity; // vehicle relative forward speed 731 private Vector3 m_knownRotationalImpulse;
624 732
625 private const int m_knownChangedPosition = 1 << 0; 733 private const int m_knownChangedPosition = 1 << 0;
626 private const int m_knownChangedVelocity = 1 << 1; 734 private const int m_knownChangedVelocity = 1 << 1;
627 private const int m_knownChangedForce = 1 << 2; 735 private const int m_knownChangedForce = 1 << 2;
628 private const int m_knownChangedOrientation = 1 << 3; 736 private const int m_knownChangedForceImpulse = 1 << 3;
629 private const int m_knownChangedRotationalVelocity = 1 << 4; 737 private const int m_knownChangedOrientation = 1 << 4;
630 private const int m_knownChangedRotationalForce = 1 << 5; 738 private const int m_knownChangedRotationalVelocity = 1 << 5;
631 private const int m_knownChangedTerrainHeight = 1 << 6; 739 private const int m_knownChangedRotationalForce = 1 << 6;
632 private const int m_knownChangedWaterLevel = 1 << 7; 740 private const int m_knownChangedRotationalImpulse = 1 << 7;
633 private const int m_knownChangedForwardVelocity = 1 << 8; 741 private const int m_knownChangedTerrainHeight = 1 << 8;
634 742 private const int m_knownChangedWaterLevel = 1 << 9;
635 private void ForgetKnownVehicleProperties() 743
744 public void ForgetKnownVehicleProperties()
636 { 745 {
637 m_knownHas = 0; 746 m_knownHas = 0;
638 m_knownChanged = 0; 747 m_knownChanged = 0;
639 } 748 }
640 // Push all the changed values back into the physics engine 749 // Push all the changed values back into the physics engine
641 private void PushKnownChanged() 750 public void PushKnownChanged()
642 { 751 {
643 if (m_knownChanged != 0) 752 if (m_knownChanged != 0)
644 { 753 {
645 if ((m_knownChanged & m_knownChangedPosition) != 0) 754 if ((m_knownChanged & m_knownChangedPosition) != 0)
646 Prim.ForcePosition = m_knownPosition; 755 ControllingPrim.ForcePosition = m_knownPosition;
647 756
648 if ((m_knownChanged & m_knownChangedOrientation) != 0) 757 if ((m_knownChanged & m_knownChangedOrientation) != 0)
649 Prim.ForceOrientation = m_knownOrientation; 758 ControllingPrim.ForceOrientation = m_knownOrientation;
650 759
651 if ((m_knownChanged & m_knownChangedVelocity) != 0) 760 if ((m_knownChanged & m_knownChangedVelocity) != 0)
652 { 761 {
653 Prim.ForceVelocity = m_knownVelocity; 762 ControllingPrim.ForceVelocity = m_knownVelocity;
654 BulletSimAPI.SetInterpolationLinearVelocity2(Prim.PhysBody.ptr, VehicleVelocity); 763 // Fake out Bullet by making it think the velocity is the same as last time.
764 // Bullet does a bunch of smoothing for changing parameters.
765 // Since the vehicle is demanding this setting, we override Bullet's smoothing
766 // by telling Bullet the value was the same last time.
767 // PhysicsScene.PE.SetInterpolationLinearVelocity(Prim.PhysBody, m_knownVelocity);
655 } 768 }
656 769
657 if ((m_knownChanged & m_knownChangedForce) != 0) 770 if ((m_knownChanged & m_knownChangedForce) != 0)
658 Prim.AddForce((Vector3)m_knownForce, false, true); 771 ControllingPrim.AddForce((Vector3)m_knownForce, false /*pushForce*/, true /*inTaintTime*/);
772
773 if ((m_knownChanged & m_knownChangedForceImpulse) != 0)
774 ControllingPrim.AddForceImpulse((Vector3)m_knownForceImpulse, false /*pushforce*/, true /*inTaintTime*/);
659 775
660 if ((m_knownChanged & m_knownChangedRotationalVelocity) != 0) 776 if ((m_knownChanged & m_knownChangedRotationalVelocity) != 0)
661 { 777 {
662 Prim.ForceRotationalVelocity = m_knownRotationalVelocity; 778 ControllingPrim.ForceRotationalVelocity = m_knownRotationalVelocity;
663 // Fake out Bullet by making it think the velocity is the same as last time. 779 // PhysicsScene.PE.SetInterpolationAngularVelocity(Prim.PhysBody, m_knownRotationalVelocity);
664 BulletSimAPI.SetInterpolationAngularVelocity2(Prim.PhysBody.ptr, m_knownRotationalVelocity);
665 } 780 }
666 781
782 if ((m_knownChanged & m_knownChangedRotationalImpulse) != 0)
783 ControllingPrim.ApplyTorqueImpulse((Vector3)m_knownRotationalImpulse, true /*inTaintTime*/);
784
667 if ((m_knownChanged & m_knownChangedRotationalForce) != 0) 785 if ((m_knownChanged & m_knownChangedRotationalForce) != 0)
668 Prim.AddAngularForce((Vector3)m_knownRotationalForce, false, true); 786 {
787 ControllingPrim.AddAngularForce((Vector3)m_knownRotationalForce, false /*pushForce*/, true /*inTaintTime*/);
788 }
669 789
670 // If we set one of the values (ie, the physics engine didn't do it) we must force 790 // If we set one of the values (ie, the physics engine didn't do it) we must force
671 // an UpdateProperties event to send the changes up to the simulator. 791 // an UpdateProperties event to send the changes up to the simulator.
672 BulletSimAPI.PushUpdate2(Prim.PhysBody.ptr); 792 m_physicsScene.PE.PushUpdate(ControllingPrim.PhysBody);
673 } 793 }
674 m_knownChanged = 0; 794 m_knownChanged = 0;
675 } 795 }
676 796
677 // Since the computation of terrain height can be a little involved, this routine 797 // Since the computation of terrain height can be a little involved, this routine
678 // is used to fetch the height only once for each vehicle simulation step. 798 // is used to fetch the height only once for each vehicle simulation step.
799 Vector3 lastRememberedHeightPos = new Vector3(-1, -1, -1);
679 private float GetTerrainHeight(Vector3 pos) 800 private float GetTerrainHeight(Vector3 pos)
680 { 801 {
681 if ((m_knownHas & m_knownChangedTerrainHeight) == 0) 802 if ((m_knownHas & m_knownChangedTerrainHeight) == 0 || pos != lastRememberedHeightPos)
682 { 803 {
683 m_knownTerrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos); 804 lastRememberedHeightPos = pos;
805 m_knownTerrainHeight = ControllingPrim.PhysScene.TerrainManager.GetTerrainHeightAtXYZ(pos);
684 m_knownHas |= m_knownChangedTerrainHeight; 806 m_knownHas |= m_knownChangedTerrainHeight;
685 } 807 }
686 return m_knownTerrainHeight; 808 return m_knownTerrainHeight;
@@ -688,14 +810,16 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
688 810
689 // Since the computation of water level can be a little involved, this routine 811 // Since the computation of water level can be a little involved, this routine
690 // is used ot fetch the level only once for each vehicle simulation step. 812 // is used ot fetch the level only once for each vehicle simulation step.
813 Vector3 lastRememberedWaterHeightPos = new Vector3(-1, -1, -1);
691 private float GetWaterLevel(Vector3 pos) 814 private float GetWaterLevel(Vector3 pos)
692 { 815 {
693 if ((m_knownHas & m_knownChangedWaterLevel) == 0) 816 if ((m_knownHas & m_knownChangedWaterLevel) == 0 || pos != lastRememberedWaterHeightPos)
694 { 817 {
695 m_knownWaterLevel = Prim.PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(pos); 818 lastRememberedWaterHeightPos = pos;
819 m_knownWaterLevel = ControllingPrim.PhysScene.TerrainManager.GetWaterLevelAtXYZ(pos);
696 m_knownHas |= m_knownChangedWaterLevel; 820 m_knownHas |= m_knownChangedWaterLevel;
697 } 821 }
698 return (float)m_knownWaterLevel; 822 return m_knownWaterLevel;
699 } 823 }
700 824
701 private Vector3 VehiclePosition 825 private Vector3 VehiclePosition
@@ -704,7 +828,7 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
704 { 828 {
705 if ((m_knownHas & m_knownChangedPosition) == 0) 829 if ((m_knownHas & m_knownChangedPosition) == 0)
706 { 830 {
707 m_knownPosition = Prim.ForcePosition; 831 m_knownPosition = ControllingPrim.ForcePosition;
708 m_knownHas |= m_knownChangedPosition; 832 m_knownHas |= m_knownChangedPosition;
709 } 833 }
710 return m_knownPosition; 834 return m_knownPosition;
@@ -723,7 +847,7 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
723 { 847 {
724 if ((m_knownHas & m_knownChangedOrientation) == 0) 848 if ((m_knownHas & m_knownChangedOrientation) == 0)
725 { 849 {
726 m_knownOrientation = Prim.ForceOrientation; 850 m_knownOrientation = ControllingPrim.ForceOrientation;
727 m_knownHas |= m_knownChangedOrientation; 851 m_knownHas |= m_knownChangedOrientation;
728 } 852 }
729 return m_knownOrientation; 853 return m_knownOrientation;
@@ -742,10 +866,10 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
742 { 866 {
743 if ((m_knownHas & m_knownChangedVelocity) == 0) 867 if ((m_knownHas & m_knownChangedVelocity) == 0)
744 { 868 {
745 m_knownVelocity = Prim.ForceVelocity; 869 m_knownVelocity = ControllingPrim.ForceVelocity;
746 m_knownHas |= m_knownChangedVelocity; 870 m_knownHas |= m_knownChangedVelocity;
747 } 871 }
748 return (Vector3)m_knownVelocity; 872 return m_knownVelocity;
749 } 873 }
750 set 874 set
751 { 875 {
@@ -755,15 +879,26 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
755 } 879 }
756 } 880 }
757 881
758 private void VehicleAddForce(Vector3 aForce) 882 private void VehicleAddForce(Vector3 pForce)
759 { 883 {
760 if ((m_knownHas & m_knownChangedForce) == 0) 884 if ((m_knownHas & m_knownChangedForce) == 0)
761 { 885 {
762 m_knownForce = Vector3.Zero; 886 m_knownForce = Vector3.Zero;
887 m_knownHas |= m_knownChangedForce;
763 } 888 }
764 m_knownForce += aForce; 889 m_knownForce += pForce;
765 m_knownChanged |= m_knownChangedForce; 890 m_knownChanged |= m_knownChangedForce;
766 m_knownHas |= m_knownChangedForce; 891 }
892
893 private void VehicleAddForceImpulse(Vector3 pImpulse)
894 {
895 if ((m_knownHas & m_knownChangedForceImpulse) == 0)
896 {
897 m_knownForceImpulse = Vector3.Zero;
898 m_knownHas |= m_knownChangedForceImpulse;
899 }
900 m_knownForceImpulse += pImpulse;
901 m_knownChanged |= m_knownChangedForceImpulse;
767 } 902 }
768 903
769 private Vector3 VehicleRotationalVelocity 904 private Vector3 VehicleRotationalVelocity
@@ -772,7 +907,7 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
772 { 907 {
773 if ((m_knownHas & m_knownChangedRotationalVelocity) == 0) 908 if ((m_knownHas & m_knownChangedRotationalVelocity) == 0)
774 { 909 {
775 m_knownRotationalVelocity = Prim.ForceRotationalVelocity; 910 m_knownRotationalVelocity = ControllingPrim.ForceRotationalVelocity;
776 m_knownHas |= m_knownChangedRotationalVelocity; 911 m_knownHas |= m_knownChangedRotationalVelocity;
777 } 912 }
778 return (Vector3)m_knownRotationalVelocity; 913 return (Vector3)m_knownRotationalVelocity;
@@ -794,19 +929,26 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
794 m_knownChanged |= m_knownChangedRotationalForce; 929 m_knownChanged |= m_knownChangedRotationalForce;
795 m_knownHas |= m_knownChangedRotationalForce; 930 m_knownHas |= m_knownChangedRotationalForce;
796 } 931 }
932 private void VehicleAddRotationalImpulse(Vector3 pImpulse)
933 {
934 if ((m_knownHas & m_knownChangedRotationalImpulse) == 0)
935 {
936 m_knownRotationalImpulse = Vector3.Zero;
937 m_knownHas |= m_knownChangedRotationalImpulse;
938 }
939 m_knownRotationalImpulse += pImpulse;
940 m_knownChanged |= m_knownChangedRotationalImpulse;
941 }
942
797 // Vehicle relative forward velocity 943 // Vehicle relative forward velocity
798 private Vector3 VehicleForwardVelocity 944 private Vector3 VehicleForwardVelocity
799 { 945 {
800 get 946 get
801 { 947 {
802 if ((m_knownHas & m_knownChangedForwardVelocity) == 0) 948 return VehicleVelocity * Quaternion.Inverse(Quaternion.Normalize(VehicleFrameOrientation));
803 {
804 m_knownForwardVelocity = VehicleVelocity * Quaternion.Inverse(Quaternion.Normalize(VehicleOrientation));
805 m_knownHas |= m_knownChangedForwardVelocity;
806 }
807 return m_knownForwardVelocity;
808 } 949 }
809 } 950 }
951
810 private float VehicleForwardSpeed 952 private float VehicleForwardSpeed
811 { 953 {
812 get 954 get
@@ -814,6 +956,13 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
814 return VehicleForwardVelocity.X; 956 return VehicleForwardVelocity.X;
815 } 957 }
816 } 958 }
959 private Quaternion VehicleFrameOrientation
960 {
961 get
962 {
963 return VehicleOrientation * m_referenceFrame;
964 }
965 }
817 966
818 #endregion // Known vehicle value functions 967 #endregion // Known vehicle value functions
819 968
@@ -836,106 +985,170 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
836 // for the physics engine to note the changes so an UpdateProperties event will happen. 985 // for the physics engine to note the changes so an UpdateProperties event will happen.
837 PushKnownChanged(); 986 PushKnownChanged();
838 987
839 VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}", 988 if (m_physicsScene.VehiclePhysicalLoggingEnabled)
840 Prim.LocalID, VehiclePosition, Prim.Force, VehicleVelocity, VehicleRotationalVelocity); 989 m_physicsScene.PE.DumpRigidBody(m_physicsScene.World, ControllingPrim.PhysBody);
990
991 VDetailLog("{0},BSDynamics.Step,done,pos={1}, force={2},velocity={3},angvel={4}",
992 ControllingPrim.LocalID, VehiclePosition, m_knownForce, VehicleVelocity, VehicleRotationalVelocity);
993 }
994
995 // Called after the simulation step
996 internal void PostStep(float pTimestep)
997 {
998 if (!IsActive) return;
999
1000 if (m_physicsScene.VehiclePhysicalLoggingEnabled)
1001 m_physicsScene.PE.DumpRigidBody(m_physicsScene.World, ControllingPrim.PhysBody);
841 } 1002 }
842 1003
843 // Apply the effect of the linear motor and other linear motions (like hover and float). 1004 // Apply the effect of the linear motor and other linear motions (like hover and float).
844 private void MoveLinear(float pTimestep) 1005 private void MoveLinear(float pTimestep)
845 { 1006 {
846 Vector3 linearMotorContribution = m_linearMotor.Step(pTimestep); 1007 ComputeLinearVelocity(pTimestep);
847 1008
848 // The movement computed in the linear motor is relative to the vehicle 1009 ComputeLinearDeflection(pTimestep);
849 // coordinates. Rotate the movement to world coordinates.
850 linearMotorContribution *= VehicleOrientation;
851 1010
852 // ================================================================== 1011 ComputeLinearTerrainHeightCorrection(pTimestep);
853 // Buoyancy: force to overcome gravity.
854 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g;
855 // So, if zero, don't change anything (let gravity happen). If one, negate the effect of gravity.
856 Vector3 buoyancyContribution = Prim.PhysicsScene.DefaultGravity * m_VehicleBuoyancy;
857
858 Vector3 terrainHeightContribution = ComputeLinearTerrainHeightCorrection(pTimestep);
859 1012
860 Vector3 hoverContribution = ComputeLinearHover(pTimestep); 1013 ComputeLinearHover(pTimestep);
861 1014
862 ComputeLinearBlockingEndPoint(pTimestep); 1015 ComputeLinearBlockingEndPoint(pTimestep);
863 1016
864 Vector3 limitMotorUpContribution = ComputeLinearMotorUp(pTimestep); 1017 ComputeLinearMotorUp(pTimestep);
865
866 // ==================================================================
867 Vector3 newVelocity = linearMotorContribution
868 + terrainHeightContribution
869 + hoverContribution
870 + limitMotorUpContribution;
871 1018
872 Vector3 newForce = buoyancyContribution; 1019 ApplyGravity(pTimestep);
873 1020
874 // If not changing some axis, reduce out velocity 1021 // If not changing some axis, reduce out velocity
875 if ((m_flags & (VehicleFlag.NO_X)) != 0) 1022 if ((m_flags & (VehicleFlag.NO_X | VehicleFlag.NO_Y | VehicleFlag.NO_Z)) != 0)
876 newVelocity.X = 0; 1023 {
877 if ((m_flags & (VehicleFlag.NO_Y)) != 0) 1024 Vector3 vel = VehicleVelocity;
878 newVelocity.Y = 0; 1025 if ((m_flags & (VehicleFlag.NO_X)) != 0)
879 if ((m_flags & (VehicleFlag.NO_Z)) != 0) 1026 {
880 newVelocity.Z = 0; 1027 vel.X = 0;
1028 }
1029 if ((m_flags & (VehicleFlag.NO_Y)) != 0)
1030 {
1031 vel.Y = 0;
1032 }
1033 if ((m_flags & (VehicleFlag.NO_Z)) != 0)
1034 {
1035 vel.Z = 0;
1036 }
1037 VehicleVelocity = vel;
1038 }
881 1039
882 // ================================================================== 1040 // ==================================================================
883 // Clamp high or low velocities 1041 // Clamp high or low velocities
884 float newVelocityLengthSq = newVelocity.LengthSquared(); 1042 float newVelocityLengthSq = VehicleVelocity.LengthSquared();
885 if (newVelocityLengthSq > 1000f) 1043 if (newVelocityLengthSq > BSParam.VehicleMaxLinearVelocitySquared)
886 { 1044 {
887 newVelocity /= newVelocity.Length(); 1045 Vector3 origVelW = VehicleVelocity; // DEBUG DEBUG
888 newVelocity *= 1000f; 1046 VehicleVelocity /= VehicleVelocity.Length();
1047 VehicleVelocity *= BSParam.VehicleMaxLinearVelocity;
1048 VDetailLog("{0}, MoveLinear,clampMax,origVelW={1},lenSq={2},maxVelSq={3},,newVelW={4}",
1049 ControllingPrim.LocalID, origVelW, newVelocityLengthSq, BSParam.VehicleMaxLinearVelocitySquared, VehicleVelocity);
1050 }
1051 else if (newVelocityLengthSq < BSParam.VehicleMinLinearVelocitySquared)
1052 {
1053 Vector3 origVelW = VehicleVelocity; // DEBUG DEBUG
1054 VDetailLog("{0}, MoveLinear,clampMin,origVelW={1},lenSq={2}",
1055 ControllingPrim.LocalID, origVelW, newVelocityLengthSq);
1056 VehicleVelocity = Vector3.Zero;
889 } 1057 }
890 else if (newVelocityLengthSq < 0.001f)
891 newVelocity = Vector3.Zero;
892 1058
893 // ================================================================== 1059 VDetailLog("{0}, MoveLinear,done,isColl={1},newVel={2}", ControllingPrim.LocalID, ControllingPrim.HasSomeCollision, VehicleVelocity );
894 // Stuff new linear velocity into the vehicle. 1060
895 // Since the velocity is just being set, it is not scaled by pTimeStep. Bullet will do that for us. 1061 } // end MoveLinear()
896 VehicleVelocity = newVelocity; 1062
1063 public void ComputeLinearVelocity(float pTimestep)
1064 {
1065 // Step the motor from the current value. Get the correction needed this step.
1066 Vector3 origVelW = VehicleVelocity; // DEBUG
1067 Vector3 currentVelV = VehicleForwardVelocity;
1068 Vector3 linearMotorCorrectionV = m_linearMotor.Step(pTimestep, currentVelV);
1069
1070 // Friction reduces vehicle motion based on absolute speed. Slow vehicle down by friction.
1071 Vector3 frictionFactorV = ComputeFrictionFactor(m_linearFrictionTimescale, pTimestep);
1072 linearMotorCorrectionV -= (currentVelV * frictionFactorV);
1073
1074 // Motor is vehicle coordinates. Rotate it to world coordinates
1075 Vector3 linearMotorVelocityW = linearMotorCorrectionV * VehicleFrameOrientation;
897 1076
898 // Other linear forces are applied as forces. 1077 // If we're a ground vehicle, don't add any upward Z movement
899 Vector3 totalDownForce = newForce * m_vehicleMass; 1078 if ((m_flags & VehicleFlag.LIMIT_MOTOR_UP) != 0)
900 if (!totalDownForce.ApproxEquals(Vector3.Zero, 0.01f))
901 { 1079 {
902 VehicleAddForce(totalDownForce); 1080 if (linearMotorVelocityW.Z > 0f)
1081 linearMotorVelocityW.Z = 0f;
903 } 1082 }
904 1083
905 VDetailLog("{0}, MoveLinear,done,newVel={1},totDown={2},IsColliding={3}", 1084 // Add this correction to the velocity to make it faster/slower.
906 Prim.LocalID, newVelocity, totalDownForce, Prim.IsColliding); 1085 VehicleVelocity += linearMotorVelocityW;
907 VDetailLog("{0}, MoveLinear,done,linContrib={1},terrContrib={2},hoverContrib={3},limitContrib={4},buoyContrib={5}",
908 Prim.LocalID,
909 linearMotorContribution, terrainHeightContribution, hoverContribution,
910 limitMotorUpContribution, buoyancyContribution
911 );
912 1086
913 } // end MoveLinear() 1087 VDetailLog("{0}, MoveLinear,velocity,origVelW={1},velV={2},tgt={3},correctV={4},correctW={5},newVelW={6},fricFact={7}",
1088 ControllingPrim.LocalID, origVelW, currentVelV, m_linearMotor.TargetValue, linearMotorCorrectionV,
1089 linearMotorVelocityW, VehicleVelocity, frictionFactorV);
1090 }
1091
1092 //Given a Deflection Effiency and a Velocity, Returns a Velocity that is Partially Deflected onto the X Axis
1093 //Clamped so that a DeflectionTimescale of less then 1 does not increase force over original velocity
1094 private void ComputeLinearDeflection(float pTimestep)
1095 {
1096 Vector3 linearDeflectionV = Vector3.Zero;
1097 Vector3 velocityV = VehicleForwardVelocity;
1098
1099 if (BSParam.VehicleEnableLinearDeflection)
1100 {
1101 // Velocity in Y and Z dimensions is movement to the side or turning.
1102 // Compute deflection factor from the to the side and rotational velocity
1103 linearDeflectionV.Y = SortedClampInRange(0, (velocityV.Y * m_linearDeflectionEfficiency) / m_linearDeflectionTimescale, velocityV.Y);
1104 linearDeflectionV.Z = SortedClampInRange(0, (velocityV.Z * m_linearDeflectionEfficiency) / m_linearDeflectionTimescale, velocityV.Z);
1105
1106 // Velocity to the side and around is corrected and moved into the forward direction
1107 linearDeflectionV.X += Math.Abs(linearDeflectionV.Y);
1108 linearDeflectionV.X += Math.Abs(linearDeflectionV.Z);
1109
1110 // Scale the deflection to the fractional simulation time
1111 linearDeflectionV *= pTimestep;
1112
1113 // Subtract the sideways and rotational velocity deflection factors while adding the correction forward
1114 linearDeflectionV *= new Vector3(1, -1, -1);
1115
1116 // Correction is vehicle relative. Convert to world coordinates.
1117 Vector3 linearDeflectionW = linearDeflectionV * VehicleFrameOrientation;
1118
1119 // Optionally, if not colliding, don't effect world downward velocity. Let falling things fall.
1120 if (BSParam.VehicleLinearDeflectionNotCollidingNoZ && !m_controllingPrim.HasSomeCollision)
1121 {
1122 linearDeflectionW.Z = 0f;
1123 }
1124
1125 VehicleVelocity += linearDeflectionW;
1126
1127 VDetailLog("{0}, MoveLinear,LinearDeflection,linDefEff={1},linDefTS={2},linDeflectionV={3}",
1128 ControllingPrim.LocalID, m_linearDeflectionEfficiency, m_linearDeflectionTimescale, linearDeflectionV);
1129 }
1130 }
914 1131
915 public Vector3 ComputeLinearTerrainHeightCorrection(float pTimestep) 1132 public void ComputeLinearTerrainHeightCorrection(float pTimestep)
916 { 1133 {
917 Vector3 ret = Vector3.Zero;
918 // If below the terrain, move us above the ground a little. 1134 // If below the terrain, move us above the ground a little.
919 // TODO: Consider taking the rotated size of the object or possibly casting a ray. 1135 // TODO: Consider taking the rotated size of the object or possibly casting a ray.
920 if (VehiclePosition.Z < GetTerrainHeight(VehiclePosition)) 1136 if (VehiclePosition.Z < GetTerrainHeight(VehiclePosition))
921 { 1137 {
922 // TODO: correct position by applying force rather than forcing position. 1138 // Force position because applying force won't get the vehicle through the terrain
923 Vector3 newPosition = VehiclePosition; 1139 Vector3 newPosition = VehiclePosition;
924 newPosition.Z = GetTerrainHeight(VehiclePosition) + 1f; 1140 newPosition.Z = GetTerrainHeight(VehiclePosition) + 1f;
925 VehiclePosition = newPosition; 1141 VehiclePosition = newPosition;
926 VDetailLog("{0}, MoveLinear,terrainHeight,terrainHeight={1},pos={2}", 1142 VDetailLog("{0}, MoveLinear,terrainHeight,terrainHeight={1},pos={2}",
927 Prim.LocalID, GetTerrainHeight(VehiclePosition), VehiclePosition); 1143 ControllingPrim.LocalID, GetTerrainHeight(VehiclePosition), VehiclePosition);
928 } 1144 }
929 return ret;
930 } 1145 }
931 1146
932 public Vector3 ComputeLinearHover(float pTimestep) 1147 public void ComputeLinearHover(float pTimestep)
933 { 1148 {
934 Vector3 ret = Vector3.Zero;
935
936 // m_VhoverEfficiency: 0=bouncy, 1=totally damped 1149 // m_VhoverEfficiency: 0=bouncy, 1=totally damped
937 // m_VhoverTimescale: time to achieve height 1150 // m_VhoverTimescale: time to achieve height
938 if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) 1151 if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0 && (m_VhoverHeight > 0) && (m_VhoverTimescale < 300))
939 { 1152 {
940 // We should hover, get the target height 1153 // We should hover, get the target height
941 if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0) 1154 if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0)
@@ -950,14 +1163,25 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
950 { 1163 {
951 m_VhoverTargetHeight = m_VhoverHeight; 1164 m_VhoverTargetHeight = m_VhoverHeight;
952 } 1165 }
953
954 if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0) 1166 if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0)
955 { 1167 {
956 // If body is already heigher, use its height as target height 1168 // If body is already heigher, use its height as target height
957 if (VehiclePosition.Z > m_VhoverTargetHeight) 1169 if (VehiclePosition.Z > m_VhoverTargetHeight)
1170 {
958 m_VhoverTargetHeight = VehiclePosition.Z; 1171 m_VhoverTargetHeight = VehiclePosition.Z;
1172
1173 // A 'misfeature' of this flag is that if the vehicle is above it's hover height,
1174 // the vehicle's buoyancy goes away. This is an SL bug that got used by so many
1175 // scripts that it could not be changed.
1176 // So, if above the height, reapply gravity if buoyancy had it turned off.
1177 if (m_VehicleBuoyancy != 0)
1178 {
1179 Vector3 appliedGravity = ControllingPrim.ComputeGravity(ControllingPrim.Buoyancy) * m_vehicleMass;
1180 VehicleAddForce(appliedGravity);
1181 }
1182 }
959 } 1183 }
960 1184
961 if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) 1185 if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0)
962 { 1186 {
963 if (Math.Abs(VehiclePosition.Z - m_VhoverTargetHeight) > 0.2f) 1187 if (Math.Abs(VehiclePosition.Z - m_VhoverTargetHeight) > 0.2f)
@@ -965,26 +1189,41 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
965 Vector3 pos = VehiclePosition; 1189 Vector3 pos = VehiclePosition;
966 pos.Z = m_VhoverTargetHeight; 1190 pos.Z = m_VhoverTargetHeight;
967 VehiclePosition = pos; 1191 VehiclePosition = pos;
1192
1193 VDetailLog("{0}, MoveLinear,hover,pos={1},lockHoverHeight", ControllingPrim.LocalID, pos);
968 } 1194 }
969 } 1195 }
970 else 1196 else
971 { 1197 {
972 // Error is positive if below the target and negative if above. 1198 // Error is positive if below the target and negative if above.
973 float verticalError = m_VhoverTargetHeight - VehiclePosition.Z; 1199 Vector3 hpos = VehiclePosition;
1200 float verticalError = m_VhoverTargetHeight - hpos.Z;
1201 float verticalCorrection = verticalError / m_VhoverTimescale;
1202 verticalCorrection *= m_VhoverEfficiency;
1203
1204 hpos.Z += verticalCorrection;
1205 VehiclePosition = hpos;
1206
1207 // Since we are hovering, we need to do the opposite of falling -- get rid of world Z
1208 Vector3 vel = VehicleVelocity;
1209 vel.Z = 0f;
1210 VehicleVelocity = vel;
1211
1212 /*
974 float verticalCorrectionVelocity = verticalError / m_VhoverTimescale; 1213 float verticalCorrectionVelocity = verticalError / m_VhoverTimescale;
1214 Vector3 verticalCorrection = new Vector3(0f, 0f, verticalCorrectionVelocity);
1215 verticalCorrection *= m_vehicleMass;
975 1216
976 // TODO: implement m_VhoverEfficiency correctly 1217 // TODO: implement m_VhoverEfficiency correctly
977 if (Math.Abs(verticalError) > m_VhoverEfficiency) 1218 VehicleAddForceImpulse(verticalCorrection);
978 { 1219 */
979 ret = new Vector3(0f, 0f, verticalCorrectionVelocity);
980 }
981 }
982 1220
983 VDetailLog("{0}, MoveLinear,hover,pos={1},ret={2},hoverTS={3},height={4},target={5}", 1221 VDetailLog("{0}, MoveLinear,hover,pos={1},eff={2},hoverTS={3},height={4},target={5},err={6},corr={7}",
984 Prim.LocalID, VehiclePosition, ret, m_VhoverTimescale, m_VhoverHeight, m_VhoverTargetHeight); 1222 ControllingPrim.LocalID, VehiclePosition, m_VhoverEfficiency,
1223 m_VhoverTimescale, m_VhoverHeight, m_VhoverTargetHeight,
1224 verticalError, verticalCorrection);
1225 }
985 } 1226 }
986
987 return ret;
988 } 1227 }
989 1228
990 public bool ComputeLinearBlockingEndPoint(float pTimestep) 1229 public bool ComputeLinearBlockingEndPoint(float pTimestep)
@@ -1024,7 +1263,7 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
1024 { 1263 {
1025 VehiclePosition = pos; 1264 VehiclePosition = pos;
1026 VDetailLog("{0}, MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}", 1265 VDetailLog("{0}, MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}",
1027 Prim.LocalID, m_BlockingEndPoint, posChange, pos); 1266 ControllingPrim.LocalID, m_BlockingEndPoint, posChange, pos);
1028 } 1267 }
1029 } 1268 }
1030 return changed; 1269 return changed;
@@ -1035,34 +1274,75 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
1035 // used with conjunction with banking: the strength of the banking will decay when the 1274 // used with conjunction with banking: the strength of the banking will decay when the
1036 // vehicle no longer experiences collisions. The decay timescale is the same as 1275 // vehicle no longer experiences collisions. The decay timescale is the same as
1037 // VEHICLE_BANKING_TIMESCALE. This is to help prevent ground vehicles from steering 1276 // VEHICLE_BANKING_TIMESCALE. This is to help prevent ground vehicles from steering
1038 // when they are in mid jump. 1277 // when they are in mid jump.
1039 // TODO: this code is wrong. Also, what should it do for boats (height from water)? 1278 // TODO: this code is wrong. Also, what should it do for boats (height from water)?
1040 // This is just using the ground and a general collision check. Should really be using 1279 // This is just using the ground and a general collision check. Should really be using
1041 // a downward raycast to find what is below. 1280 // a downward raycast to find what is below.
1042 public Vector3 ComputeLinearMotorUp(float pTimestep) 1281 public void ComputeLinearMotorUp(float pTimestep)
1043 { 1282 {
1044 Vector3 ret = Vector3.Zero;
1045 float distanceAboveGround = 0f;
1046
1047 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) 1283 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0)
1048 { 1284 {
1285 // This code tries to decide if the object is not on the ground and then pushing down
1286 /*
1049 float targetHeight = Type == Vehicle.TYPE_BOAT ? GetWaterLevel(VehiclePosition) : GetTerrainHeight(VehiclePosition); 1287 float targetHeight = Type == Vehicle.TYPE_BOAT ? GetWaterLevel(VehiclePosition) : GetTerrainHeight(VehiclePosition);
1050 distanceAboveGround = VehiclePosition.Z - targetHeight; 1288 distanceAboveGround = VehiclePosition.Z - targetHeight;
1051 // Not colliding if the vehicle is off the ground 1289 // Not colliding if the vehicle is off the ground
1052 if (!Prim.IsColliding) 1290 if (!Prim.HasSomeCollision)
1053 { 1291 {
1054 // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale); 1292 // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale);
1055 ret = new Vector3(0, 0, -distanceAboveGround); 1293 VehicleVelocity += new Vector3(0, 0, -distanceAboveGround);
1056 } 1294 }
1057 // TODO: this calculation is wrong. From the description at 1295 // TODO: this calculation is wrong. From the description at
1058 // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce 1296 // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce
1059 // has a decay factor. This says this force should 1297 // has a decay factor. This says this force should
1060 // be computed with a motor. 1298 // be computed with a motor.
1061 // TODO: add interaction with banking. 1299 // TODO: add interaction with banking.
1300 VDetailLog("{0}, MoveLinear,limitMotorUp,distAbove={1},colliding={2},ret={3}",
1301 Prim.LocalID, distanceAboveGround, Prim.HasSomeCollision, ret);
1302 */
1303
1304 // Another approach is to measure if we're going up. If going up and not colliding,
1305 // the vehicle is in the air. Fix that by pushing down.
1306 if (!ControllingPrim.HasSomeCollision && VehicleVelocity.Z > 0.1)
1307 {
1308 // Get rid of any of the velocity vector that is pushing us up.
1309 float upVelocity = VehicleVelocity.Z;
1310 VehicleVelocity += new Vector3(0, 0, -upVelocity);
1311
1312 /*
1313 // If we're pointed up into the air, we should nose down
1314 Vector3 pointingDirection = Vector3.UnitX * VehicleOrientation;
1315 // The rotation around the Y axis is pitch up or down
1316 if (pointingDirection.Y > 0.01f)
1317 {
1318 float angularCorrectionForce = -(float)Math.Asin(pointingDirection.Y);
1319 Vector3 angularCorrectionVector = new Vector3(0f, angularCorrectionForce, 0f);
1320 // Rotate into world coordinates and apply to vehicle
1321 angularCorrectionVector *= VehicleOrientation;
1322 VehicleAddAngularForce(angularCorrectionVector);
1323 VDetailLog("{0}, MoveLinear,limitMotorUp,newVel={1},pntDir={2},corrFrc={3},aCorr={4}",
1324 Prim.LocalID, VehicleVelocity, pointingDirection, angularCorrectionForce, angularCorrectionVector);
1325 }
1326 */
1327 VDetailLog("{0}, MoveLinear,limitMotorUp,collide={1},upVel={2},newVel={3}",
1328 ControllingPrim.LocalID, ControllingPrim.HasSomeCollision, upVelocity, VehicleVelocity);
1329 }
1062 } 1330 }
1063 VDetailLog("{0}, MoveLinear,limitMotorUp,distAbove={1},colliding={2},ret={3}", 1331 }
1064 Prim.LocalID, distanceAboveGround, Prim.IsColliding, ret); 1332
1065 return ret; 1333 private void ApplyGravity(float pTimeStep)
1334 {
1335 Vector3 appliedGravity = m_VehicleGravity * m_vehicleMass;
1336
1337 // Hack to reduce downward force if the vehicle is probably sitting on the ground
1338 if (ControllingPrim.HasSomeCollision && IsGroundVehicle)
1339 appliedGravity *= BSParam.VehicleGroundGravityFudge;
1340
1341 VehicleAddForce(appliedGravity);
1342
1343 VDetailLog("{0}, MoveLinear,applyGravity,vehGrav={1},collid={2},fudge={3},mass={4},appliedForce={5}",
1344 ControllingPrim.LocalID, m_VehicleGravity,
1345 ControllingPrim.HasSomeCollision, BSParam.VehicleGroundGravityFudge, m_vehicleMass, appliedGravity);
1066 } 1346 }
1067 1347
1068 // ======================================================================= 1348 // =======================================================================
@@ -1073,55 +1353,24 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
1073 // set directly on the vehicle. 1353 // set directly on the vehicle.
1074 private void MoveAngular(float pTimestep) 1354 private void MoveAngular(float pTimestep)
1075 { 1355 {
1076 // The user wants this many radians per second angular change? 1356 ComputeAngularTurning(pTimestep);
1077 Vector3 angularMotorContribution = m_angularMotor.Step(pTimestep);
1078
1079 // ==================================================================
1080 // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags :
1081 // This flag prevents linear deflection parallel to world z-axis. This is useful
1082 // for preventing ground vehicles with large linear deflection, like bumper cars,
1083 // from climbing their linear deflection into the sky.
1084 // That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement
1085 if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
1086 {
1087 angularMotorContribution.X = 0f;
1088 angularMotorContribution.Y = 0f;
1089 VDetailLog("{0}, MoveAngular,noDeflectionUp,angularMotorContrib={1}", Prim.LocalID, angularMotorContribution);
1090 }
1091
1092 Vector3 verticalAttractionContribution = ComputeAngularVerticalAttraction();
1093 1357
1094 Vector3 deflectionContribution = ComputeAngularDeflection(); 1358 ComputeAngularVerticalAttraction();
1095 1359
1096 Vector3 bankingContribution = ComputeAngularBanking(); 1360 ComputeAngularDeflection();
1097 1361
1098 // ================================================================== 1362 ComputeAngularBanking();
1099 m_lastVertAttractor = verticalAttractionContribution;
1100
1101 m_lastAngularVelocity = angularMotorContribution
1102 + verticalAttractionContribution
1103 + deflectionContribution
1104 + bankingContribution;
1105 1363
1106 // ================================================================== 1364 // ==================================================================
1107 // Apply the correction velocity. 1365 if (VehicleRotationalVelocity.ApproxEquals(Vector3.Zero, 0.0001f))
1108 // TODO: Should this be applied as an angular force (torque)?
1109 if (!m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f))
1110 { 1366 {
1111 VehicleRotationalVelocity = m_lastAngularVelocity; 1367 // The vehicle is not adding anything angular wise.
1112 1368 VehicleRotationalVelocity = Vector3.Zero;
1113 VDetailLog("{0}, MoveAngular,done,nonZero,angMotorContrib={1},vertAttrContrib={2},bankContrib={3},deflectContrib={4},totalContrib={5}", 1369 VDetailLog("{0}, MoveAngular,done,zero", ControllingPrim.LocalID);
1114 Prim.LocalID,
1115 angularMotorContribution, verticalAttractionContribution,
1116 bankingContribution, deflectionContribution,
1117 m_lastAngularVelocity
1118 );
1119 } 1370 }
1120 else 1371 else
1121 { 1372 {
1122 // The vehicle is not adding anything angular wise. 1373 VDetailLog("{0}, MoveAngular,done,nonZero,angVel={1}", ControllingPrim.LocalID, VehicleRotationalVelocity);
1123 VehicleRotationalVelocity = Vector3.Zero;
1124 VDetailLog("{0}, MoveAngular,done,zero", Prim.LocalID);
1125 } 1374 }
1126 1375
1127 // ================================================================== 1376 // ==================================================================
@@ -1152,10 +1401,43 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
1152 torqueFromOffset.Z = 0; 1401 torqueFromOffset.Z = 0;
1153 1402
1154 VehicleAddAngularForce(torqueFromOffset * m_vehicleMass); 1403 VehicleAddAngularForce(torqueFromOffset * m_vehicleMass);
1155 VDetailLog("{0}, BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset); 1404 VDetailLog("{0}, BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", ControllingPrim.LocalID, torqueFromOffset);
1156 } 1405 }
1157 1406
1158 } 1407 }
1408
1409 private void ComputeAngularTurning(float pTimestep)
1410 {
1411 // The user wants this many radians per second angular change?
1412 Vector3 origVehicleRotationalVelocity = VehicleRotationalVelocity; // DEBUG DEBUG
1413 Vector3 currentAngularV = VehicleRotationalVelocity * Quaternion.Inverse(VehicleFrameOrientation);
1414 Vector3 angularMotorContributionV = m_angularMotor.Step(pTimestep, currentAngularV);
1415
1416 // ==================================================================
1417 // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags :
1418 // This flag prevents linear deflection parallel to world z-axis. This is useful
1419 // for preventing ground vehicles with large linear deflection, like bumper cars,
1420 // from climbing their linear deflection into the sky.
1421 // That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement
1422 // TODO: This is here because this is where ODE put it but documentation says it
1423 // is a linear effect. Where should this check go?
1424 //if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
1425 // {
1426 // angularMotorContributionV.X = 0f;
1427 // angularMotorContributionV.Y = 0f;
1428 // }
1429
1430 // Reduce any velocity by friction.
1431 Vector3 frictionFactorW = ComputeFrictionFactor(m_angularFrictionTimescale, pTimestep);
1432 angularMotorContributionV -= (currentAngularV * frictionFactorW);
1433
1434 Vector3 angularMotorContributionW = angularMotorContributionV * VehicleFrameOrientation;
1435 VehicleRotationalVelocity += angularMotorContributionW;
1436
1437 VDetailLog("{0}, MoveAngular,angularTurning,curAngVelV={1},origVehRotVel={2},vehRotVel={3},frictFact={4}, angContribV={5},angContribW={6}",
1438 ControllingPrim.LocalID, currentAngularV, origVehicleRotationalVelocity, VehicleRotationalVelocity, frictionFactorW, angularMotorContributionV, angularMotorContributionW);
1439 }
1440
1159 // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial: 1441 // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial:
1160 // Some vehicles, like boats, should always keep their up-side up. This can be done by 1442 // Some vehicles, like boats, should always keep their up-side up. This can be done by
1161 // enabling the "vertical attractor" behavior that springs the vehicle's local z-axis to 1443 // enabling the "vertical attractor" behavior that springs the vehicle's local z-axis to
@@ -1164,77 +1446,183 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
1164 // and then set the VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY to control the damping. An 1446 // and then set the VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY to control the damping. An
1165 // efficiency of 0.0 will cause the spring to wobble around its equilibrium, while an 1447 // efficiency of 0.0 will cause the spring to wobble around its equilibrium, while an
1166 // efficiency of 1.0 will cause the spring to reach its equilibrium with exponential decay. 1448 // efficiency of 1.0 will cause the spring to reach its equilibrium with exponential decay.
1167 public Vector3 ComputeAngularVerticalAttraction() 1449 public void ComputeAngularVerticalAttraction()
1168 { 1450 {
1169 Vector3 ret = Vector3.Zero;
1170 1451
1171 // If vertical attaction timescale is reasonable 1452 // If vertical attaction timescale is reasonable
1172 if (m_verticalAttractionTimescale < m_verticalAttractionCutoff) 1453 if (BSParam.VehicleEnableAngularVerticalAttraction && m_verticalAttractionTimescale < m_verticalAttractionCutoff)
1173 { 1454 {
1174 // Take a vector pointing up and convert it from world to vehicle relative coords. 1455 Vector3 vehicleUpAxis = Vector3.UnitZ * VehicleFrameOrientation;
1175 Vector3 verticalError = Vector3.UnitZ * VehicleOrientation; 1456 switch (BSParam.VehicleAngularVerticalAttractionAlgorithm)
1176
1177 // If vertical attraction correction is needed, the vector that was pointing up (UnitZ)
1178 // is now:
1179 // leaning to one side: rotated around the X axis with the Y value going
1180 // from zero (nearly straight up) to one (completely to the side)) or
1181 // leaning front-to-back: rotated around the Y axis with the value of X being between
1182 // zero and one.
1183 // The value of Z is how far the rotation is off with 1 meaning none and 0 being 90 degrees.
1184
1185 // Y error means needed rotation around X axis and visa versa.
1186 // Since the error goes from zero to one, the asin is the corresponding angle.
1187 ret.X = (float)Math.Asin(verticalError.Y);
1188 // (Tilt forward (positive X) needs to tilt back (rotate negative) around Y axis.)
1189 ret.Y = -(float)Math.Asin(verticalError.X);
1190
1191 // If verticalError.Z is negative, the vehicle is upside down. Add additional push.
1192 if (verticalError.Z < 0f)
1193 { 1457 {
1194 ret.X += PIOverFour; 1458 case 0:
1195 ret.Y += PIOverFour; 1459 {
1460 //Another formula to try got from :
1461 //http://answers.unity3d.com/questions/10425/how-to-stabilize-angular-motion-alignment-of-hover.html
1462
1463 // Flipping what was originally a timescale into a speed variable and then multiplying it by 2
1464 // since only computing half the distance between the angles.
1465 float verticalAttractionSpeed = (1 / m_verticalAttractionTimescale) * 2.0f;
1466
1467 // Make a prediction of where the up axis will be when this is applied rather then where it is now as
1468 // this makes for a smoother adjustment and less fighting between the various forces.
1469 Vector3 predictedUp = vehicleUpAxis * Quaternion.CreateFromAxisAngle(VehicleRotationalVelocity, 0f);
1470
1471 // This is only half the distance to the target so it will take 2 seconds to complete the turn.
1472 Vector3 torqueVector = Vector3.Cross(predictedUp, Vector3.UnitZ);
1473
1474 if ((m_flags & VehicleFlag.LIMIT_ROLL_ONLY) != 0)
1475 {
1476 Vector3 vehicleForwardAxis = Vector3.UnitX * VehicleFrameOrientation;
1477 torqueVector = ProjectVector(torqueVector, vehicleForwardAxis);
1478 }
1479
1480 // Scale vector by our timescale since it is an acceleration it is r/s^2 or radians a timescale squared
1481 Vector3 vertContributionV = torqueVector * verticalAttractionSpeed * verticalAttractionSpeed;
1482
1483 VehicleRotationalVelocity += vertContributionV;
1484
1485 VDetailLog("{0}, MoveAngular,verticalAttraction,vertAttrSpeed={1},upAxis={2},PredictedUp={3},torqueVector={4},contrib={5}",
1486 ControllingPrim.LocalID,
1487 verticalAttractionSpeed,
1488 vehicleUpAxis,
1489 predictedUp,
1490 torqueVector,
1491 vertContributionV);
1492 break;
1493 }
1494 case 1:
1495 {
1496 // Possible solution derived from a discussion at:
1497 // http://stackoverflow.com/questions/14939657/computing-vector-from-quaternion-works-computing-quaternion-from-vector-does-no
1498
1499 // Create a rotation that is only the vehicle's rotation around Z
1500 Vector3 currentEulerW = Vector3.Zero;
1501 VehicleFrameOrientation.GetEulerAngles(out currentEulerW.X, out currentEulerW.Y, out currentEulerW.Z);
1502 Quaternion justZOrientation = Quaternion.CreateFromAxisAngle(Vector3.UnitZ, currentEulerW.Z);
1503
1504 // Create the axis that is perpendicular to the up vector and the rotated up vector.
1505 Vector3 differenceAxisW = Vector3.Cross(Vector3.UnitZ * justZOrientation, Vector3.UnitZ * VehicleFrameOrientation);
1506 // Compute the angle between those to vectors.
1507 double differenceAngle = Math.Acos((double)Vector3.Dot(Vector3.UnitZ, Vector3.Normalize(Vector3.UnitZ * VehicleFrameOrientation)));
1508 // 'differenceAngle' is the angle to rotate and 'differenceAxis' is the plane to rotate in to get the vehicle vertical
1509
1510 // Reduce the change by the time period it is to change in. Timestep is handled when velocity is applied.
1511 // TODO: add 'efficiency'.
1512 // differenceAngle /= m_verticalAttractionTimescale;
1513
1514 // Create the quaterian representing the correction angle
1515 Quaternion correctionRotationW = Quaternion.CreateFromAxisAngle(differenceAxisW, (float)differenceAngle);
1516
1517 // Turn that quaternion into Euler values to make it into velocities to apply.
1518 Vector3 vertContributionW = Vector3.Zero;
1519 correctionRotationW.GetEulerAngles(out vertContributionW.X, out vertContributionW.Y, out vertContributionW.Z);
1520 vertContributionW *= -1f;
1521 vertContributionW /= m_verticalAttractionTimescale;
1522
1523 VehicleRotationalVelocity += vertContributionW;
1524
1525 VDetailLog("{0}, MoveAngular,verticalAttraction,upAxis={1},diffAxis={2},diffAng={3},corrRot={4},contrib={5}",
1526 ControllingPrim.LocalID,
1527 vehicleUpAxis,
1528 differenceAxisW,
1529 differenceAngle,
1530 correctionRotationW,
1531 vertContributionW);
1532 break;
1533 }
1534 case 2:
1535 {
1536 Vector3 vertContributionV = Vector3.Zero;
1537 Vector3 origRotVelW = VehicleRotationalVelocity; // DEBUG DEBUG
1538
1539 // Take a vector pointing up and convert it from world to vehicle relative coords.
1540 Vector3 verticalError = Vector3.Normalize(Vector3.UnitZ * VehicleFrameOrientation);
1541
1542 // If vertical attraction correction is needed, the vector that was pointing up (UnitZ)
1543 // is now:
1544 // leaning to one side: rotated around the X axis with the Y value going
1545 // from zero (nearly straight up) to one (completely to the side)) or
1546 // leaning front-to-back: rotated around the Y axis with the value of X being between
1547 // zero and one.
1548 // The value of Z is how far the rotation is off with 1 meaning none and 0 being 90 degrees.
1549
1550 // Y error means needed rotation around X axis and visa versa.
1551 // Since the error goes from zero to one, the asin is the corresponding angle.
1552 vertContributionV.X = (float)Math.Asin(verticalError.Y);
1553 // (Tilt forward (positive X) needs to tilt back (rotate negative) around Y axis.)
1554 vertContributionV.Y = -(float)Math.Asin(verticalError.X);
1555
1556 // If verticalError.Z is negative, the vehicle is upside down. Add additional push.
1557 if (verticalError.Z < 0f)
1558 {
1559 vertContributionV.X += Math.Sign(vertContributionV.X) * PIOverFour;
1560 // vertContribution.Y -= PIOverFour;
1561 }
1562
1563 // 'vertContrbution' is now the necessary angular correction to correct tilt in one second.
1564 // Correction happens over a number of seconds.
1565 Vector3 unscaledContribVerticalErrorV = vertContributionV; // DEBUG DEBUG
1566
1567 // The correction happens over the user's time period
1568 vertContributionV /= m_verticalAttractionTimescale;
1569
1570 // Rotate the vehicle rotation to the world coordinates.
1571 VehicleRotationalVelocity += (vertContributionV * VehicleFrameOrientation);
1572
1573 VDetailLog("{0}, MoveAngular,verticalAttraction,,upAxis={1},origRotVW={2},vertError={3},unscaledV={4},eff={5},ts={6},vertContribV={7}",
1574 ControllingPrim.LocalID,
1575 vehicleUpAxis,
1576 origRotVelW,
1577 verticalError,
1578 unscaledContribVerticalErrorV,
1579 m_verticalAttractionEfficiency,
1580 m_verticalAttractionTimescale,
1581 vertContributionV);
1582 break;
1583 }
1584 default:
1585 {
1586 break;
1587 }
1196 } 1588 }
1197
1198 // 'ret' is now the necessary velocity to correct tilt in one second.
1199 // Correction happens over a number of seconds.
1200 Vector3 unscaledContrib = ret;
1201 ret /= m_verticalAttractionTimescale;
1202
1203 VDetailLog("{0}, MoveAngular,verticalAttraction,,verticalError={1},unscaled={2},eff={3},ts={4},vertAttr={5}",
1204 Prim.LocalID, verticalError, unscaledContrib, m_verticalAttractionEfficiency, m_verticalAttractionTimescale, ret);
1205 } 1589 }
1206 return ret;
1207 } 1590 }
1208 1591
1209 // Return the angular correction to correct the direction the vehicle is pointing to be 1592 // Angular correction to correct the direction the vehicle is pointing to be
1210 // the direction is should want to be pointing. 1593 // the direction is should want to be pointing.
1211 // The vehicle is moving in some direction and correct its orientation to it is pointing 1594 // The vehicle is moving in some direction and correct its orientation to it is pointing
1212 // in that direction. 1595 // in that direction.
1213 // TODO: implement reference frame. 1596 // TODO: implement reference frame.
1214 public Vector3 ComputeAngularDeflection() 1597 public void ComputeAngularDeflection()
1215 { 1598 {
1216 Vector3 ret = Vector3.Zero; 1599
1217 return ret; // DEBUG DEBUG DEBUG 1600 if (BSParam.VehicleEnableAngularDeflection && m_angularDeflectionEfficiency != 0 && VehicleForwardSpeed > 0.2)
1218 // Disable angular deflection for the moment.
1219 // Since angularMotorUp and angularDeflection are computed independently, they will calculate
1220 // approximately the same X or Y correction. When added together (when contributions are combined)
1221 // this creates an over-correction and then wabbling as the target is overshot.
1222 // TODO: rethink how the different correction computations inter-relate.
1223
1224 if (m_angularDeflectionEfficiency != 0)
1225 { 1601 {
1602 Vector3 deflectContributionV = Vector3.Zero;
1603
1226 // The direction the vehicle is moving 1604 // The direction the vehicle is moving
1227 Vector3 movingDirection = VehicleVelocity; 1605 Vector3 movingDirection = VehicleVelocity;
1228 movingDirection.Normalize(); 1606 movingDirection.Normalize();
1229 1607
1608 // If the vehicle is going backward, it is still pointing forward
1609 movingDirection *= Math.Sign(VehicleForwardSpeed);
1610
1230 // The direction the vehicle is pointing 1611 // The direction the vehicle is pointing
1231 Vector3 pointingDirection = Vector3.UnitX * VehicleOrientation; 1612 Vector3 pointingDirection = Vector3.UnitX * VehicleFrameOrientation;
1232 pointingDirection.Normalize(); 1613 //Predict where the Vehicle will be pointing after AngularVelocity change is applied. This will keep
1614 // from overshooting and allow this correction to merge with the Vertical Attraction peacefully.
1615 Vector3 predictedPointingDirection = pointingDirection * Quaternion.CreateFromAxisAngle(VehicleRotationalVelocity, 0f);
1616 predictedPointingDirection.Normalize();
1233 1617
1234 // The difference between what is and what should be. 1618 // The difference between what is and what should be.
1235 Vector3 deflectionError = movingDirection - pointingDirection; 1619 // Vector3 deflectionError = movingDirection - predictedPointingDirection;
1620 Vector3 deflectionError = Vector3.Cross(movingDirection, predictedPointingDirection);
1236 1621
1237 // Don't try to correct very large errors (not our job) 1622 // Don't try to correct very large errors (not our job)
1623 // if (Math.Abs(deflectionError.X) > PIOverFour) deflectionError.X = PIOverTwo * Math.Sign(deflectionError.X);
1624 // if (Math.Abs(deflectionError.Y) > PIOverFour) deflectionError.Y = PIOverTwo * Math.Sign(deflectionError.Y);
1625 // if (Math.Abs(deflectionError.Z) > PIOverFour) deflectionError.Z = PIOverTwo * Math.Sign(deflectionError.Z);
1238 if (Math.Abs(deflectionError.X) > PIOverFour) deflectionError.X = 0f; 1626 if (Math.Abs(deflectionError.X) > PIOverFour) deflectionError.X = 0f;
1239 if (Math.Abs(deflectionError.Y) > PIOverFour) deflectionError.Y = 0f; 1627 if (Math.Abs(deflectionError.Y) > PIOverFour) deflectionError.Y = 0f;
1240 if (Math.Abs(deflectionError.Z) > PIOverFour) deflectionError.Z = 0f; 1628 if (Math.Abs(deflectionError.Z) > PIOverFour) deflectionError.Z = 0f;
@@ -1242,18 +1630,19 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
1242 // ret = m_angularDeflectionCorrectionMotor(1f, deflectionError); 1630 // ret = m_angularDeflectionCorrectionMotor(1f, deflectionError);
1243 1631
1244 // Scale the correction by recovery timescale and efficiency 1632 // Scale the correction by recovery timescale and efficiency
1245 ret = (-deflectionError) * m_angularDeflectionEfficiency; 1633 // Not modeling a spring so clamp the scale to no more then the arc
1246 ret /= m_angularDeflectionTimescale; 1634 deflectContributionV = (-deflectionError) * ClampInRange(0, m_angularDeflectionEfficiency/m_angularDeflectionTimescale,1f);
1635 //deflectContributionV /= m_angularDeflectionTimescale;
1247 1636
1637 VehicleRotationalVelocity += deflectContributionV;
1248 VDetailLog("{0}, MoveAngular,Deflection,movingDir={1},pointingDir={2},deflectError={3},ret={4}", 1638 VDetailLog("{0}, MoveAngular,Deflection,movingDir={1},pointingDir={2},deflectError={3},ret={4}",
1249 Prim.LocalID, movingDirection, pointingDirection, deflectionError, ret); 1639 ControllingPrim.LocalID, movingDirection, pointingDirection, deflectionError, deflectContributionV);
1250 VDetailLog("{0}, MoveAngular,Deflection,fwdSpd={1},defEff={2},defTS={3}", 1640 VDetailLog("{0}, MoveAngular,Deflection,fwdSpd={1},defEff={2},defTS={3},PredictedPointingDir={4}",
1251 Prim.LocalID, VehicleForwardSpeed, m_angularDeflectionEfficiency, m_angularDeflectionTimescale); 1641 ControllingPrim.LocalID, VehicleForwardSpeed, m_angularDeflectionEfficiency, m_angularDeflectionTimescale, predictedPointingDirection);
1252 } 1642 }
1253 return ret;
1254 } 1643 }
1255 1644
1256 // Return an angular change to rotate the vehicle around the Z axis when the vehicle 1645 // Angular change to rotate the vehicle around the Z axis when the vehicle
1257 // is tipped around the X axis. 1646 // is tipped around the X axis.
1258 // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial: 1647 // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial:
1259 // The vertical attractor feature must be enabled in order for the banking behavior to 1648 // The vertical attractor feature must be enabled in order for the banking behavior to
@@ -1261,13 +1650,13 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
1261 // produce a angular velocity around the yaw-axis, causing the vehicle to turn. The magnitude 1650 // produce a angular velocity around the yaw-axis, causing the vehicle to turn. The magnitude
1262 // of the yaw effect will be proportional to the 1651 // of the yaw effect will be proportional to the
1263 // VEHICLE_BANKING_EFFICIENCY, the angle of the roll rotation, and sometimes the vehicle's 1652 // VEHICLE_BANKING_EFFICIENCY, the angle of the roll rotation, and sometimes the vehicle's
1264 // velocity along its preferred axis of motion. 1653 // velocity along its preferred axis of motion.
1265 // The VEHICLE_BANKING_EFFICIENCY can vary between -1 and +1. When it is positive then any 1654 // The VEHICLE_BANKING_EFFICIENCY can vary between -1 and +1. When it is positive then any
1266 // positive rotation (by the right-hand rule) about the roll-axis will effect a 1655 // positive rotation (by the right-hand rule) about the roll-axis will effect a
1267 // (negative) torque around the yaw-axis, making it turn to the right--that is the 1656 // (negative) torque around the yaw-axis, making it turn to the right--that is the
1268 // vehicle will lean into the turn, which is how real airplanes and motorcycle's work. 1657 // vehicle will lean into the turn, which is how real airplanes and motorcycle's work.
1269 // Negating the banking coefficient will make it so that the vehicle leans to the 1658 // Negating the banking coefficient will make it so that the vehicle leans to the
1270 // outside of the turn (not very "physical" but might allow interesting vehicles so why not?). 1659 // outside of the turn (not very "physical" but might allow interesting vehicles so why not?).
1271 // The VEHICLE_BANKING_MIX is a fake (i.e. non-physical) parameter that is useful for making 1660 // The VEHICLE_BANKING_MIX is a fake (i.e. non-physical) parameter that is useful for making
1272 // banking vehicles do what you want rather than what the laws of physics allow. 1661 // banking vehicles do what you want rather than what the laws of physics allow.
1273 // For example, consider a real motorcycle...it must be moving forward in order for 1662 // For example, consider a real motorcycle...it must be moving forward in order for
@@ -1279,46 +1668,43 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
1279 // totally static (0.0) and totally dynamic (1.0). By "static" we mean that the 1668 // totally static (0.0) and totally dynamic (1.0). By "static" we mean that the
1280 // banking effect depends only on the vehicle's rotation about its roll-axis compared 1669 // banking effect depends only on the vehicle's rotation about its roll-axis compared
1281 // to "dynamic" where the banking is also proportional to its velocity along its 1670 // to "dynamic" where the banking is also proportional to its velocity along its
1282 // roll-axis. Finding the best value of the "mixture" will probably require trial and error. 1671 // roll-axis. Finding the best value of the "mixture" will probably require trial and error.
1283 // The time it takes for the banking behavior to defeat a preexisting angular velocity about the 1672 // The time it takes for the banking behavior to defeat a preexisting angular velocity about the
1284 // world z-axis is determined by the VEHICLE_BANKING_TIMESCALE. So if you want the vehicle to 1673 // world z-axis is determined by the VEHICLE_BANKING_TIMESCALE. So if you want the vehicle to
1285 // bank quickly then give it a banking timescale of about a second or less, otherwise you can 1674 // bank quickly then give it a banking timescale of about a second or less, otherwise you can
1286 // make a sluggish vehicle by giving it a timescale of several seconds. 1675 // make a sluggish vehicle by giving it a timescale of several seconds.
1287 public Vector3 ComputeAngularBanking() 1676 public void ComputeAngularBanking()
1288 { 1677 {
1289 Vector3 ret = Vector3.Zero; 1678 if (BSParam.VehicleEnableAngularBanking && m_bankingEfficiency != 0 && m_verticalAttractionTimescale < m_verticalAttractionCutoff)
1290
1291 if (m_bankingEfficiency != 0 && m_verticalAttractionTimescale < m_verticalAttractionCutoff)
1292 { 1679 {
1293 // This works by rotating a unit vector to the orientation of the vehicle. The 1680 Vector3 bankingContributionV = Vector3.Zero;
1294 // roll (tilt) will be Y component of a tilting Z vector (zero for no tilt
1295 // up to one for full over).
1296 Vector3 rollComponents = Vector3.UnitZ * VehicleOrientation;
1297 1681
1298 // Figure out the yaw value for this much roll. 1682 // Rotate a UnitZ vector (pointing up) to how the vehicle is oriented.
1299 float turnComponent = rollComponents.Y * rollComponents.Y * m_bankingEfficiency; 1683 // As the vehicle rolls to the right or left, the Y value will increase from
1300 // Keep the sign 1684 // zero (straight up) to 1 or -1 (full tilt right or left)
1301 if (rollComponents.Y < 0f) 1685 Vector3 rollComponents = Vector3.UnitZ * VehicleFrameOrientation;
1302 turnComponent = -turnComponent;
1303
1304 // TODO: there must be a better computation of the banking force.
1305 float bankingTurnForce = turnComponent;
1306 1686
1687 // Figure out the yaw value for this much roll.
1688 float yawAngle = m_angularMotorDirection.X * m_bankingEfficiency;
1307 // actual error = static turn error + dynamic turn error 1689 // actual error = static turn error + dynamic turn error
1308 float mixedBankingError = bankingTurnForce * (1f - m_bankingMix) + bankingTurnForce * m_bankingMix * VehicleForwardSpeed; 1690 float mixedYawAngle =(yawAngle * (1f - m_bankingMix)) + ((yawAngle * m_bankingMix) * VehicleForwardSpeed);
1691
1309 // TODO: the banking effect should not go to infinity but what to limit it to? 1692 // TODO: the banking effect should not go to infinity but what to limit it to?
1310 mixedBankingError = ClampInRange(-20f, mixedBankingError, 20f); 1693 // And what should happen when this is being added to a user defined yaw that is already PI*4?
1694 mixedYawAngle = ClampInRange(-FourPI, mixedYawAngle, FourPI);
1311 1695
1312 // Build the force vector to change rotation from what it is to what it should be 1696 // Build the force vector to change rotation from what it is to what it should be
1313 ret.Z = -mixedBankingError; 1697 bankingContributionV.Z = -mixedYawAngle;
1698
1699 // Don't do it all at once. Fudge because 1 second is too fast with most user defined roll as PI*4.
1700 bankingContributionV /= m_bankingTimescale * BSParam.VehicleAngularBankingTimescaleFudge;
1701
1702 VehicleRotationalVelocity += bankingContributionV;
1314 1703
1315 // Don't do it all at once.
1316 ret /= m_bankingTimescale;
1317 1704
1318 VDetailLog("{0}, MoveAngular,Banking,rollComp={1},speed={2},turnComp={3},bankErr={4},mixedBankErr={5},ret={6}", 1705 VDetailLog("{0}, MoveAngular,Banking,rollComp={1},speed={2},rollComp={3},yAng={4},mYAng={5},ret={6}",
1319 Prim.LocalID, rollComponents, VehicleForwardSpeed, turnComponent, bankingTurnForce, mixedBankingError, ret); 1706 ControllingPrim.LocalID, rollComponents, VehicleForwardSpeed, rollComponents, yawAngle, mixedYawAngle, bankingContributionV);
1320 } 1707 }
1321 return ret;
1322 } 1708 }
1323 1709
1324 // This is from previous instantiations of XXXDynamics.cs. 1710 // This is from previous instantiations of XXXDynamics.cs.
@@ -1356,8 +1742,45 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
1356 if (rotq != m_rot) 1742 if (rotq != m_rot)
1357 { 1743 {
1358 VehicleOrientation = m_rot; 1744 VehicleOrientation = m_rot;
1359 VDetailLog("{0}, LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot); 1745 VDetailLog("{0}, LimitRotation,done,orig={1},new={2}", ControllingPrim.LocalID, rotq, m_rot);
1746 }
1747
1748 }
1749
1750 // Given a friction vector (reduction in seconds) and a timestep, return the factor to reduce
1751 // some value by to apply this friction.
1752 private Vector3 ComputeFrictionFactor(Vector3 friction, float pTimestep)
1753 {
1754 Vector3 frictionFactor = Vector3.Zero;
1755 if (friction != BSMotor.InfiniteVector)
1756 {
1757 // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep;
1758 // Individual friction components can be 'infinite' so compute each separately.
1759 frictionFactor.X = (friction.X == BSMotor.Infinite) ? 0f : (1f / friction.X);
1760 frictionFactor.Y = (friction.Y == BSMotor.Infinite) ? 0f : (1f / friction.Y);
1761 frictionFactor.Z = (friction.Z == BSMotor.Infinite) ? 0f : (1f / friction.Z);
1762 frictionFactor *= pTimestep;
1763 }
1764 return frictionFactor;
1765 }
1766
1767 private float SortedClampInRange(float clampa, float val, float clampb)
1768 {
1769 if (clampa > clampb)
1770 {
1771 float temp = clampa;
1772 clampa = clampb;
1773 clampb = temp;
1360 } 1774 }
1775 return ClampInRange(clampa, val, clampb);
1776
1777 }
1778
1779 //Given a Vector and a unit vector will return the amount of the vector is on the same axis as the unit.
1780 private Vector3 ProjectVector(Vector3 vector, Vector3 onNormal)
1781 {
1782 float vectorDot = Vector3.Dot(vector, onNormal);
1783 return onNormal * vectorDot;
1361 1784
1362 } 1785 }
1363 1786
@@ -1370,8 +1793,8 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
1370 // Invoke the detailed logger and output something if it's enabled. 1793 // Invoke the detailed logger and output something if it's enabled.
1371 private void VDetailLog(string msg, params Object[] args) 1794 private void VDetailLog(string msg, params Object[] args)
1372 { 1795 {
1373 if (Prim.PhysicsScene.VehicleLoggingEnabled) 1796 if (ControllingPrim.PhysScene.VehicleLoggingEnabled)
1374 Prim.PhysicsScene.DetailLog(msg, args); 1797 ControllingPrim.PhysScene.DetailLog(msg, args);
1375 } 1798 }
1376 } 1799 }
1377} 1800}