ODEDynamics.cs 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096
  1. /*
  2. * Copyright (c) Contributors, http://opensimulator.org/
  3. * See CONTRIBUTORS.TXT for a full list of copyright holders.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * * Neither the name of the OpenSimulator Project nor the
  13. * names of its contributors may be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
  17. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
  20. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. /* Revised Aug, Sept 2009 by Kitto Flora. ODEDynamics.cs replaces
  28. * ODEVehicleSettings.cs. It and ODEPrim.cs are re-organised:
  29. * ODEPrim.cs contains methods dealing with Prim editing, Prim
  30. * characteristics and Kinetic motion.
  31. * ODEDynamics.cs contains methods dealing with Prim Physical motion
  32. * (dynamics) and the associated settings. Old Linear and angular
  33. * motors for dynamic motion have been replace with MoveLinear()
  34. * and MoveAngular(); 'Physical' is used only to switch ODE dynamic
  35. * simualtion on/off; VEHICAL_TYPE_NONE/VEHICAL_TYPE_<other> is to
  36. * switch between 'VEHICLE' parameter use and general dynamics
  37. * settings use.
  38. */
  39. // Extensive change Ubit 2012
  40. using System;
  41. using System.Collections.Generic;
  42. using System.Reflection;
  43. using System.Runtime.InteropServices;
  44. using log4net;
  45. using OpenMetaverse;
  46. using OdeAPI;
  47. using OpenSim.Framework;
  48. using OpenSim.Region.PhysicsModules.SharedBase;
  49. namespace OpenSim.Region.PhysicsModule.ubOde
  50. {
  51. public class ODEDynamics
  52. {
  53. public Vehicle Type
  54. {
  55. get { return m_type; }
  56. }
  57. private OdePrim rootPrim;
  58. private ODEScene _pParentScene;
  59. // Vehicle properties
  60. // WARNING this are working copies for internel use
  61. // their values may not be the corresponding parameter
  62. private Quaternion m_referenceFrame = Quaternion.Identity; // Axis modifier
  63. private Quaternion m_RollreferenceFrame = Quaternion.Identity; // what hell is this ?
  64. private Vehicle m_type = Vehicle.TYPE_NONE; // If a 'VEHICLE', and what kind
  65. private VehicleFlag m_flags = (VehicleFlag) 0; // Boolean settings:
  66. // HOVER_TERRAIN_ONLY
  67. // HOVER_GLOBAL_HEIGHT
  68. // NO_DEFLECTION_UP
  69. // HOVER_WATER_ONLY
  70. // HOVER_UP_ONLY
  71. // LIMIT_MOTOR_UP
  72. // LIMIT_ROLL_ONLY
  73. private Vector3 m_BlockingEndPoint = Vector3.Zero; // not sl
  74. // Linear properties
  75. private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time
  76. private Vector3 m_linearFrictionTimescale = new Vector3(1000, 1000, 1000);
  77. private float m_linearMotorDecayTimescale = 120;
  78. private float m_linearMotorTimescale = 1000;
  79. private Vector3 m_linearMotorOffset = Vector3.Zero;
  80. //Angular properties
  81. private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor
  82. private float m_angularMotorTimescale = 1000; // motor angular velocity ramp up rate
  83. private float m_angularMotorDecayTimescale = 120; // motor angular velocity decay rate
  84. private Vector3 m_angularFrictionTimescale = new Vector3(1000, 1000, 1000); // body angular velocity decay rate
  85. //Deflection properties
  86. private float m_angularDeflectionEfficiency = 0;
  87. private float m_angularDeflectionTimescale = 1000;
  88. private float m_linearDeflectionEfficiency = 0;
  89. private float m_linearDeflectionTimescale = 1000;
  90. //Banking properties
  91. private float m_bankingEfficiency = 0;
  92. private float m_bankingMix = 0;
  93. private float m_bankingTimescale = 1000;
  94. //Hover and Buoyancy properties
  95. private float m_VhoverHeight = 0f;
  96. private float m_VhoverEfficiency = 0f;
  97. private float m_VhoverTimescale = 1000f;
  98. private float m_VehicleBuoyancy = 0f; //KF: m_VehicleBuoyancy is set by VEHICLE_BUOYANCY for a vehicle.
  99. // Modifies gravity. Slider between -1 (double-gravity) and 1 (full anti-gravity)
  100. // KF: So far I have found no good method to combine a script-requested .Z velocity and gravity.
  101. // Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity.
  102. //Attractor properties
  103. private float m_verticalAttractionEfficiency = 1.0f; // damped
  104. private float m_verticalAttractionTimescale = 1000f; // Timescale > 300 means no vert attractor.
  105. // auxiliar
  106. private float m_lmEfect = 0f; // current linear motor eficiency
  107. private float m_lmDecay = 0f; // current linear decay
  108. private float m_amEfect = 0; // current angular motor eficiency
  109. private float m_amDecay = 0f; // current linear decay
  110. private float m_ffactor = 1.0f;
  111. private float m_timestep = 0.02f;
  112. private float m_invtimestep = 50;
  113. float m_ampwr;
  114. float m_amdampX;
  115. float m_amdampY;
  116. float m_amdampZ;
  117. float m_gravmod;
  118. public float FrictionFactor
  119. {
  120. get
  121. {
  122. return m_ffactor;
  123. }
  124. }
  125. public float GravMod
  126. {
  127. set
  128. {
  129. m_gravmod = value;
  130. }
  131. }
  132. public ODEDynamics(OdePrim rootp)
  133. {
  134. rootPrim = rootp;
  135. _pParentScene = rootPrim._parent_scene;
  136. m_timestep = _pParentScene.ODE_STEPSIZE;
  137. m_invtimestep = 1.0f / m_timestep;
  138. m_gravmod = rootPrim.GravModifier;
  139. }
  140. public void DoSetVehicle(VehicleData vd)
  141. {
  142. m_type = vd.m_type;
  143. m_flags = vd.m_flags;
  144. // Linear properties
  145. m_linearMotorDirection = vd.m_linearMotorDirection;
  146. m_linearFrictionTimescale = vd.m_linearFrictionTimescale;
  147. if (m_linearFrictionTimescale.X < m_timestep) m_linearFrictionTimescale.X = m_timestep;
  148. if (m_linearFrictionTimescale.Y < m_timestep) m_linearFrictionTimescale.Y = m_timestep;
  149. if (m_linearFrictionTimescale.Z < m_timestep) m_linearFrictionTimescale.Z = m_timestep;
  150. m_linearMotorDecayTimescale = vd.m_linearMotorDecayTimescale;
  151. if (m_linearMotorDecayTimescale < m_timestep) m_linearMotorDecayTimescale = m_timestep;
  152. m_linearMotorDecayTimescale += 0.2f;
  153. m_linearMotorDecayTimescale *= m_invtimestep;
  154. m_linearMotorTimescale = vd.m_linearMotorTimescale;
  155. if (m_linearMotorTimescale < m_timestep) m_linearMotorTimescale = m_timestep;
  156. m_linearMotorOffset = vd.m_linearMotorOffset;
  157. //Angular properties
  158. m_angularMotorDirection = vd.m_angularMotorDirection;
  159. m_angularMotorTimescale = vd.m_angularMotorTimescale;
  160. if (m_angularMotorTimescale < m_timestep) m_angularMotorTimescale = m_timestep;
  161. m_angularMotorDecayTimescale = vd.m_angularMotorDecayTimescale;
  162. if (m_angularMotorDecayTimescale < m_timestep) m_angularMotorDecayTimescale = m_timestep;
  163. m_angularMotorDecayTimescale *= m_invtimestep;
  164. m_angularFrictionTimescale = vd.m_angularFrictionTimescale;
  165. if (m_angularFrictionTimescale.X < m_timestep) m_angularFrictionTimescale.X = m_timestep;
  166. if (m_angularFrictionTimescale.Y < m_timestep) m_angularFrictionTimescale.Y = m_timestep;
  167. if (m_angularFrictionTimescale.Z < m_timestep) m_angularFrictionTimescale.Z = m_timestep;
  168. //Deflection properties
  169. m_angularDeflectionEfficiency = vd.m_angularDeflectionEfficiency;
  170. m_angularDeflectionTimescale = vd.m_angularDeflectionTimescale;
  171. if (m_angularDeflectionTimescale < m_timestep) m_angularDeflectionTimescale = m_timestep;
  172. m_linearDeflectionEfficiency = vd.m_linearDeflectionEfficiency;
  173. m_linearDeflectionTimescale = vd.m_linearDeflectionTimescale;
  174. if (m_linearDeflectionTimescale < m_timestep) m_linearDeflectionTimescale = m_timestep;
  175. //Banking properties
  176. m_bankingEfficiency = vd.m_bankingEfficiency;
  177. m_bankingMix = vd.m_bankingMix;
  178. m_bankingTimescale = vd.m_bankingTimescale;
  179. if (m_bankingTimescale < m_timestep) m_bankingTimescale = m_timestep;
  180. //Hover and Buoyancy properties
  181. m_VhoverHeight = vd.m_VhoverHeight;
  182. m_VhoverEfficiency = vd.m_VhoverEfficiency;
  183. m_VhoverTimescale = vd.m_VhoverTimescale;
  184. if (m_VhoverTimescale < m_timestep) m_VhoverTimescale = m_timestep;
  185. m_VehicleBuoyancy = vd.m_VehicleBuoyancy;
  186. //Attractor properties
  187. m_verticalAttractionEfficiency = vd.m_verticalAttractionEfficiency;
  188. m_verticalAttractionTimescale = vd.m_verticalAttractionTimescale;
  189. if (m_verticalAttractionTimescale < m_timestep) m_verticalAttractionTimescale = m_timestep;
  190. // Axis
  191. m_referenceFrame = vd.m_referenceFrame;
  192. m_lmEfect = 0;
  193. m_lmDecay = (1.0f - 1.0f / m_linearMotorDecayTimescale);
  194. m_amEfect = 0;
  195. m_ffactor = 1.0f;
  196. }
  197. internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue)
  198. {
  199. float len;
  200. switch (pParam)
  201. {
  202. case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY:
  203. if (pValue < 0f) pValue = 0f;
  204. if (pValue > 1f) pValue = 1f;
  205. m_angularDeflectionEfficiency = pValue;
  206. break;
  207. case Vehicle.ANGULAR_DEFLECTION_TIMESCALE:
  208. if (pValue < m_timestep) pValue = m_timestep;
  209. m_angularDeflectionTimescale = pValue;
  210. break;
  211. case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE:
  212. if (pValue < m_timestep) pValue = m_timestep;
  213. else if (pValue > 120) pValue = 120;
  214. m_angularMotorDecayTimescale = pValue * m_invtimestep;
  215. m_amDecay = 1.0f - 1.0f / m_angularMotorDecayTimescale;
  216. break;
  217. case Vehicle.ANGULAR_MOTOR_TIMESCALE:
  218. if (pValue < m_timestep) pValue = m_timestep;
  219. m_angularMotorTimescale = pValue;
  220. break;
  221. case Vehicle.BANKING_EFFICIENCY:
  222. if (pValue < -1f) pValue = -1f;
  223. if (pValue > 1f) pValue = 1f;
  224. m_bankingEfficiency = pValue;
  225. break;
  226. case Vehicle.BANKING_MIX:
  227. if (pValue < 0f) pValue = 0f;
  228. if (pValue > 1f) pValue = 1f;
  229. m_bankingMix = pValue;
  230. break;
  231. case Vehicle.BANKING_TIMESCALE:
  232. if (pValue < m_timestep) pValue = m_timestep;
  233. m_bankingTimescale = pValue;
  234. break;
  235. case Vehicle.BUOYANCY:
  236. if (pValue < -1f) pValue = -1f;
  237. if (pValue > 1f) pValue = 1f;
  238. m_VehicleBuoyancy = pValue;
  239. break;
  240. case Vehicle.HOVER_EFFICIENCY:
  241. if (pValue < 0f) pValue = 0f;
  242. if (pValue > 1f) pValue = 1f;
  243. m_VhoverEfficiency = pValue;
  244. break;
  245. case Vehicle.HOVER_HEIGHT:
  246. m_VhoverHeight = pValue;
  247. break;
  248. case Vehicle.HOVER_TIMESCALE:
  249. if (pValue < m_timestep) pValue = m_timestep;
  250. m_VhoverTimescale = pValue;
  251. break;
  252. case Vehicle.LINEAR_DEFLECTION_EFFICIENCY:
  253. if (pValue < 0f) pValue = 0f;
  254. if (pValue > 1f) pValue = 1f;
  255. m_linearDeflectionEfficiency = pValue;
  256. break;
  257. case Vehicle.LINEAR_DEFLECTION_TIMESCALE:
  258. if (pValue < m_timestep) pValue = m_timestep;
  259. m_linearDeflectionTimescale = pValue;
  260. break;
  261. case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE:
  262. if (pValue < m_timestep) pValue = m_timestep;
  263. else if (pValue > 120) pValue = 120;
  264. m_linearMotorDecayTimescale = (0.2f +pValue) * m_invtimestep;
  265. m_lmDecay = (1.0f - 1.0f / m_linearMotorDecayTimescale);
  266. break;
  267. case Vehicle.LINEAR_MOTOR_TIMESCALE:
  268. if (pValue < m_timestep) pValue = m_timestep;
  269. m_linearMotorTimescale = pValue;
  270. break;
  271. case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY:
  272. if (pValue < 0f) pValue = 0f;
  273. if (pValue > 1f) pValue = 1f;
  274. m_verticalAttractionEfficiency = pValue;
  275. break;
  276. case Vehicle.VERTICAL_ATTRACTION_TIMESCALE:
  277. if (pValue < m_timestep) pValue = m_timestep;
  278. m_verticalAttractionTimescale = pValue;
  279. break;
  280. // These are vector properties but the engine lets you use a single float value to
  281. // set all of the components to the same value
  282. case Vehicle.ANGULAR_FRICTION_TIMESCALE:
  283. if (pValue < m_timestep) pValue = m_timestep;
  284. m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue);
  285. break;
  286. case Vehicle.ANGULAR_MOTOR_DIRECTION:
  287. m_angularMotorDirection = new Vector3(pValue, pValue, pValue);
  288. len = m_angularMotorDirection.Length();
  289. if (len > 12.566f)
  290. m_angularMotorDirection *= (12.566f / len);
  291. m_amEfect = 1.0f ; // turn it on
  292. m_amDecay = 1.0f - 1.0f / m_angularMotorDecayTimescale;
  293. if (rootPrim.Body != IntPtr.Zero && !d.BodyIsEnabled(rootPrim.Body)
  294. && !rootPrim.m_isSelected && !rootPrim.m_disabled)
  295. d.BodyEnable(rootPrim.Body);
  296. break;
  297. case Vehicle.LINEAR_FRICTION_TIMESCALE:
  298. if (pValue < m_timestep) pValue = m_timestep;
  299. m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue);
  300. break;
  301. case Vehicle.LINEAR_MOTOR_DIRECTION:
  302. m_linearMotorDirection = new Vector3(pValue, pValue, pValue);
  303. len = m_linearMotorDirection.Length();
  304. if (len > 100.0f)
  305. m_linearMotorDirection *= (100.0f / len);
  306. m_lmDecay = 1.0f - 1.0f / m_linearMotorDecayTimescale;
  307. m_lmEfect = 1.0f; // turn it on
  308. m_ffactor = 0.0f;
  309. if (rootPrim.Body != IntPtr.Zero && !d.BodyIsEnabled(rootPrim.Body)
  310. && !rootPrim.m_isSelected && !rootPrim.m_disabled)
  311. d.BodyEnable(rootPrim.Body);
  312. break;
  313. case Vehicle.LINEAR_MOTOR_OFFSET:
  314. m_linearMotorOffset = new Vector3(pValue, pValue, pValue);
  315. len = m_linearMotorOffset.Length();
  316. if (len > 100.0f)
  317. m_linearMotorOffset *= (100.0f / len);
  318. break;
  319. }
  320. }//end ProcessFloatVehicleParam
  321. internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue)
  322. {
  323. float len;
  324. switch (pParam)
  325. {
  326. case Vehicle.ANGULAR_FRICTION_TIMESCALE:
  327. if (pValue.X < m_timestep) pValue.X = m_timestep;
  328. if (pValue.Y < m_timestep) pValue.Y = m_timestep;
  329. if (pValue.Z < m_timestep) pValue.Z = m_timestep;
  330. m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
  331. break;
  332. case Vehicle.ANGULAR_MOTOR_DIRECTION:
  333. m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
  334. // Limit requested angular speed to 2 rps= 4 pi rads/sec
  335. len = m_angularMotorDirection.Length();
  336. if (len > 12.566f)
  337. m_angularMotorDirection *= (12.566f / len);
  338. m_amEfect = 1.0f; // turn it on
  339. m_amDecay = 1.0f - 1.0f / m_angularMotorDecayTimescale;
  340. if (rootPrim.Body != IntPtr.Zero && !d.BodyIsEnabled(rootPrim.Body)
  341. && !rootPrim.m_isSelected && !rootPrim.m_disabled)
  342. d.BodyEnable(rootPrim.Body);
  343. break;
  344. case Vehicle.LINEAR_FRICTION_TIMESCALE:
  345. if (pValue.X < m_timestep) pValue.X = m_timestep;
  346. if (pValue.Y < m_timestep) pValue.Y = m_timestep;
  347. if (pValue.Z < m_timestep) pValue.Z = m_timestep;
  348. m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
  349. break;
  350. case Vehicle.LINEAR_MOTOR_DIRECTION:
  351. m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
  352. len = m_linearMotorDirection.Length();
  353. if (len > 100.0f)
  354. m_linearMotorDirection *= (100.0f / len);
  355. m_lmEfect = 1.0f; // turn it on
  356. m_lmDecay = 1.0f - 1.0f / m_linearMotorDecayTimescale;
  357. m_ffactor = 0.0f;
  358. if (rootPrim.Body != IntPtr.Zero && !d.BodyIsEnabled(rootPrim.Body)
  359. && !rootPrim.m_isSelected && !rootPrim.m_disabled)
  360. d.BodyEnable(rootPrim.Body);
  361. break;
  362. case Vehicle.LINEAR_MOTOR_OFFSET:
  363. m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z);
  364. len = m_linearMotorOffset.Length();
  365. if (len > 100.0f)
  366. m_linearMotorOffset *= (100.0f / len);
  367. break;
  368. case Vehicle.BLOCK_EXIT:
  369. m_BlockingEndPoint = new Vector3(pValue.X, pValue.Y, pValue.Z);
  370. break;
  371. }
  372. }//end ProcessVectorVehicleParam
  373. internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue)
  374. {
  375. switch (pParam)
  376. {
  377. case Vehicle.REFERENCE_FRAME:
  378. // m_referenceFrame = Quaternion.Inverse(pValue);
  379. m_referenceFrame = pValue;
  380. break;
  381. case Vehicle.ROLL_FRAME:
  382. m_RollreferenceFrame = pValue;
  383. break;
  384. }
  385. }//end ProcessRotationVehicleParam
  386. internal void ProcessVehicleFlags(int pParam, bool remove)
  387. {
  388. if (remove)
  389. {
  390. m_flags &= ~((VehicleFlag)pParam);
  391. }
  392. else
  393. {
  394. m_flags |= (VehicleFlag)pParam;
  395. }
  396. }//end ProcessVehicleFlags
  397. internal void ProcessTypeChange(Vehicle pType)
  398. {
  399. m_lmEfect = 0;
  400. m_amEfect = 0;
  401. m_ffactor = 1f;
  402. m_linearMotorDirection = Vector3.Zero;
  403. m_angularMotorDirection = Vector3.Zero;
  404. m_BlockingEndPoint = Vector3.Zero;
  405. m_RollreferenceFrame = Quaternion.Identity;
  406. m_linearMotorOffset = Vector3.Zero;
  407. m_referenceFrame = Quaternion.Identity;
  408. // Set Defaults For Type
  409. m_type = pType;
  410. switch (pType)
  411. {
  412. case Vehicle.TYPE_NONE:
  413. m_linearFrictionTimescale = new Vector3(1000, 1000, 1000);
  414. m_angularFrictionTimescale = new Vector3(1000, 1000, 1000);
  415. m_linearMotorTimescale = 1000;
  416. m_linearMotorDecayTimescale = 120 * m_invtimestep;
  417. m_angularMotorTimescale = 1000;
  418. m_angularMotorDecayTimescale = 1000 * m_invtimestep;
  419. m_VhoverHeight = 0;
  420. m_VhoverEfficiency = 1;
  421. m_VhoverTimescale = 1000;
  422. m_VehicleBuoyancy = 0;
  423. m_linearDeflectionEfficiency = 0;
  424. m_linearDeflectionTimescale = 1000;
  425. m_angularDeflectionEfficiency = 0;
  426. m_angularDeflectionTimescale = 1000;
  427. m_bankingEfficiency = 0;
  428. m_bankingMix = 1;
  429. m_bankingTimescale = 1000;
  430. m_verticalAttractionEfficiency = 0;
  431. m_verticalAttractionTimescale = 1000;
  432. m_flags = (VehicleFlag)0;
  433. break;
  434. case Vehicle.TYPE_SLED:
  435. m_linearFrictionTimescale = new Vector3(30, 1, 1000);
  436. m_angularFrictionTimescale = new Vector3(1000, 1000, 1000);
  437. m_linearMotorTimescale = 1000;
  438. m_linearMotorDecayTimescale = 120 * m_invtimestep;
  439. m_angularMotorTimescale = 1000;
  440. m_angularMotorDecayTimescale = 120 * m_invtimestep;
  441. m_VhoverHeight = 0;
  442. m_VhoverEfficiency = 1;
  443. m_VhoverTimescale = 10;
  444. m_VehicleBuoyancy = 0;
  445. m_linearDeflectionEfficiency = 1;
  446. m_linearDeflectionTimescale = 1;
  447. m_angularDeflectionEfficiency = 0;
  448. m_angularDeflectionTimescale = 10;
  449. m_verticalAttractionEfficiency = 1;
  450. m_verticalAttractionTimescale = 1000;
  451. m_bankingEfficiency = 0;
  452. m_bankingMix = 1;
  453. m_bankingTimescale = 10;
  454. m_flags &=
  455. ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY |
  456. VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY);
  457. m_flags |= (VehicleFlag.NO_DEFLECTION_UP |
  458. VehicleFlag.LIMIT_ROLL_ONLY |
  459. VehicleFlag.LIMIT_MOTOR_UP);
  460. break;
  461. case Vehicle.TYPE_CAR:
  462. m_linearFrictionTimescale = new Vector3(100, 2, 1000);
  463. m_angularFrictionTimescale = new Vector3(1000, 1000, 1000);
  464. m_linearMotorTimescale = 1;
  465. m_linearMotorDecayTimescale = 60 * m_invtimestep;
  466. m_angularMotorTimescale = 1;
  467. m_angularMotorDecayTimescale = 0.8f * m_invtimestep;
  468. m_VhoverHeight = 0;
  469. m_VhoverEfficiency = 0;
  470. m_VhoverTimescale = 1000;
  471. m_VehicleBuoyancy = 0;
  472. m_linearDeflectionEfficiency = 1;
  473. m_linearDeflectionTimescale = 2;
  474. m_angularDeflectionEfficiency = 0;
  475. m_angularDeflectionTimescale = 10;
  476. m_verticalAttractionEfficiency = 1f;
  477. m_verticalAttractionTimescale = 10f;
  478. m_bankingEfficiency = -0.2f;
  479. m_bankingMix = 1;
  480. m_bankingTimescale = 1;
  481. m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY |
  482. VehicleFlag.HOVER_TERRAIN_ONLY |
  483. VehicleFlag.HOVER_GLOBAL_HEIGHT);
  484. m_flags |= (VehicleFlag.NO_DEFLECTION_UP |
  485. VehicleFlag.LIMIT_ROLL_ONLY |
  486. VehicleFlag.LIMIT_MOTOR_UP |
  487. VehicleFlag.HOVER_UP_ONLY);
  488. break;
  489. case Vehicle.TYPE_BOAT:
  490. m_linearFrictionTimescale = new Vector3(10, 3, 2);
  491. m_angularFrictionTimescale = new Vector3(10, 10, 10);
  492. m_linearMotorTimescale = 5;
  493. m_linearMotorDecayTimescale = 60 * m_invtimestep;
  494. m_angularMotorTimescale = 4;
  495. m_angularMotorDecayTimescale = 4 * m_invtimestep;
  496. m_VhoverHeight = 0;
  497. m_VhoverEfficiency = 0.5f;
  498. m_VhoverTimescale = 2;
  499. m_VehicleBuoyancy = 1;
  500. m_linearDeflectionEfficiency = 0.5f;
  501. m_linearDeflectionTimescale = 3;
  502. m_angularDeflectionEfficiency = 0.5f;
  503. m_angularDeflectionTimescale = 5;
  504. m_verticalAttractionEfficiency = 0.5f;
  505. m_verticalAttractionTimescale = 5f;
  506. m_bankingEfficiency = -0.3f;
  507. m_bankingMix = 0.8f;
  508. m_bankingTimescale = 1;
  509. m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY |
  510. VehicleFlag.HOVER_GLOBAL_HEIGHT |
  511. VehicleFlag.HOVER_UP_ONLY); // |
  512. // VehicleFlag.LIMIT_ROLL_ONLY);
  513. m_flags |= (VehicleFlag.NO_DEFLECTION_UP |
  514. VehicleFlag.LIMIT_MOTOR_UP |
  515. VehicleFlag.HOVER_UP_ONLY | // new sl
  516. VehicleFlag.HOVER_WATER_ONLY);
  517. break;
  518. case Vehicle.TYPE_AIRPLANE:
  519. m_linearFrictionTimescale = new Vector3(200, 10, 5);
  520. m_angularFrictionTimescale = new Vector3(20, 20, 20);
  521. m_linearMotorTimescale = 2;
  522. m_linearMotorDecayTimescale = 60 * m_invtimestep;
  523. m_angularMotorTimescale = 4;
  524. m_angularMotorDecayTimescale = 8 * m_invtimestep;
  525. m_VhoverHeight = 0;
  526. m_VhoverEfficiency = 0.5f;
  527. m_VhoverTimescale = 1000;
  528. m_VehicleBuoyancy = 0;
  529. m_linearDeflectionEfficiency = 0.5f;
  530. m_linearDeflectionTimescale = 0.5f;
  531. m_angularDeflectionEfficiency = 1;
  532. m_angularDeflectionTimescale = 2;
  533. m_verticalAttractionEfficiency = 0.9f;
  534. m_verticalAttractionTimescale = 2f;
  535. m_bankingEfficiency = 1;
  536. m_bankingMix = 0.7f;
  537. m_bankingTimescale = 2;
  538. m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY |
  539. VehicleFlag.HOVER_TERRAIN_ONLY |
  540. VehicleFlag.HOVER_GLOBAL_HEIGHT |
  541. VehicleFlag.HOVER_UP_ONLY |
  542. VehicleFlag.NO_DEFLECTION_UP |
  543. VehicleFlag.LIMIT_MOTOR_UP);
  544. m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY);
  545. break;
  546. case Vehicle.TYPE_BALLOON:
  547. m_linearFrictionTimescale = new Vector3(5, 5, 5);
  548. m_angularFrictionTimescale = new Vector3(10, 10, 10);
  549. m_linearMotorTimescale = 5;
  550. m_linearMotorDecayTimescale = 60 * m_invtimestep;
  551. m_angularMotorTimescale = 6;
  552. m_angularMotorDecayTimescale = 10 * m_invtimestep;
  553. m_VhoverHeight = 5;
  554. m_VhoverEfficiency = 0.8f;
  555. m_VhoverTimescale = 10;
  556. m_VehicleBuoyancy = 1;
  557. m_linearDeflectionEfficiency = 0;
  558. m_linearDeflectionTimescale = 5 * m_invtimestep;
  559. m_angularDeflectionEfficiency = 0;
  560. m_angularDeflectionTimescale = 5;
  561. m_verticalAttractionEfficiency = 1f;
  562. m_verticalAttractionTimescale = 1000f;
  563. m_bankingEfficiency = 0;
  564. m_bankingMix = 0.7f;
  565. m_bankingTimescale = 5;
  566. m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY |
  567. VehicleFlag.HOVER_TERRAIN_ONLY |
  568. VehicleFlag.HOVER_UP_ONLY |
  569. VehicleFlag.NO_DEFLECTION_UP |
  570. VehicleFlag.LIMIT_MOTOR_UP | //);
  571. VehicleFlag.LIMIT_ROLL_ONLY | // new sl
  572. VehicleFlag.HOVER_GLOBAL_HEIGHT); // new sl
  573. // m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY |
  574. // VehicleFlag.HOVER_GLOBAL_HEIGHT);
  575. break;
  576. }
  577. m_lmDecay = (1.0f - 1.0f / m_linearMotorDecayTimescale);
  578. m_amDecay = 1.0f - 1.0f / m_angularMotorDecayTimescale;
  579. }//end SetDefaultsForType
  580. internal void Stop()
  581. {
  582. m_lmEfect = 0;
  583. m_lmDecay = 0f;
  584. m_amEfect = 0;
  585. m_amDecay = 0;
  586. m_ffactor = 1f;
  587. }
  588. public static Vector3 Xrot(Quaternion rot)
  589. {
  590. Vector3 vec;
  591. rot.Normalize(); // just in case
  592. vec.X = 2 * (rot.X * rot.X + rot.W * rot.W) - 1;
  593. vec.Y = 2 * (rot.X * rot.Y + rot.Z * rot.W);
  594. vec.Z = 2 * (rot.X * rot.Z - rot.Y * rot.W);
  595. return vec;
  596. }
  597. public static Vector3 Zrot(Quaternion rot)
  598. {
  599. Vector3 vec;
  600. rot.Normalize(); // just in case
  601. vec.X = 2 * (rot.X * rot.Z + rot.Y * rot.W);
  602. vec.Y = 2 * (rot.Y * rot.Z - rot.X * rot.W);
  603. vec.Z = 2 * (rot.Z * rot.Z + rot.W * rot.W) - 1;
  604. return vec;
  605. }
  606. private const float pi = (float)Math.PI;
  607. private const float halfpi = 0.5f * (float)Math.PI;
  608. private const float twopi = 2.0f * pi;
  609. public static Vector3 ubRot2Euler(Quaternion rot)
  610. {
  611. // returns roll in X
  612. // pitch in Y
  613. // yaw in Z
  614. Vector3 vec;
  615. // assuming rot is normalised
  616. // rot.Normalize();
  617. float zX = rot.X * rot.Z + rot.Y * rot.W;
  618. if (zX < -0.49999f)
  619. {
  620. vec.X = 0;
  621. vec.Y = -halfpi;
  622. vec.Z = (float)(-2d * Math.Atan(rot.X / rot.W));
  623. }
  624. else if (zX > 0.49999f)
  625. {
  626. vec.X = 0;
  627. vec.Y = halfpi;
  628. vec.Z = (float)(2d * Math.Atan(rot.X / rot.W));
  629. }
  630. else
  631. {
  632. vec.Y = (float)Math.Asin(2 * zX);
  633. float sqw = rot.W * rot.W;
  634. float minuszY = rot.X * rot.W - rot.Y * rot.Z;
  635. float zZ = rot.Z * rot.Z + sqw - 0.5f;
  636. vec.X = (float)Math.Atan2(minuszY, zZ);
  637. float yX = rot.Z * rot.W - rot.X * rot.Y; //( have negative ?)
  638. float yY = rot.X * rot.X + sqw - 0.5f;
  639. vec.Z = (float)Math.Atan2(yX, yY);
  640. }
  641. return vec;
  642. }
  643. public static void GetRollPitch(Quaternion rot, out float roll, out float pitch)
  644. {
  645. // assuming rot is normalised
  646. // rot.Normalize();
  647. float zX = rot.X * rot.Z + rot.Y * rot.W;
  648. if (zX < -0.49999f)
  649. {
  650. roll = 0;
  651. pitch = -halfpi;
  652. }
  653. else if (zX > 0.49999f)
  654. {
  655. roll = 0;
  656. pitch = halfpi;
  657. }
  658. else
  659. {
  660. pitch = (float)Math.Asin(2 * zX);
  661. float minuszY = rot.X * rot.W - rot.Y * rot.Z;
  662. float zZ = rot.Z * rot.Z + rot.W * rot.W - 0.5f;
  663. roll = (float)Math.Atan2(minuszY, zZ);
  664. }
  665. return ;
  666. }
  667. internal void Step()
  668. {
  669. IntPtr Body = rootPrim.Body;
  670. d.Mass dmass;
  671. d.BodyGetMass(Body, out dmass);
  672. d.Quaternion rot = d.BodyGetQuaternion(Body);
  673. Quaternion objrotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W); // rotq = rotation of object
  674. Quaternion rotq = objrotq; // rotq = rotation of object
  675. rotq *= m_referenceFrame; // rotq is now rotation in vehicle reference frame
  676. Quaternion irotq = Quaternion.Inverse(rotq);
  677. d.Vector3 dvtmp;
  678. Vector3 tmpV;
  679. Vector3 curVel; // velocity in world
  680. Vector3 curAngVel; // angular velocity in world
  681. Vector3 force = Vector3.Zero; // actually linear aceleration until mult by mass in world frame
  682. Vector3 torque = Vector3.Zero;// actually angular aceleration until mult by Inertia in vehicle frame
  683. d.Vector3 dtorque = new d.Vector3();
  684. dvtmp = d.BodyGetLinearVel(Body);
  685. curVel.X = dvtmp.X;
  686. curVel.Y = dvtmp.Y;
  687. curVel.Z = dvtmp.Z;
  688. Vector3 curLocalVel = curVel * irotq; // current velocity in local
  689. dvtmp = d.BodyGetAngularVel(Body);
  690. curAngVel.X = dvtmp.X;
  691. curAngVel.Y = dvtmp.Y;
  692. curAngVel.Z = dvtmp.Z;
  693. Vector3 curLocalAngVel = curAngVel * irotq; // current angular velocity in local
  694. float ldampZ = 0;
  695. // linear motor
  696. if (m_lmEfect > 0.01 && m_linearMotorTimescale < 1000)
  697. {
  698. tmpV = m_linearMotorDirection - curLocalVel; // velocity error
  699. tmpV *= m_lmEfect / m_linearMotorTimescale; // error to correct in this timestep
  700. tmpV *= rotq; // to world
  701. if ((m_flags & VehicleFlag.LIMIT_MOTOR_UP) != 0)
  702. tmpV.Z = 0;
  703. if (m_linearMotorOffset.X != 0 || m_linearMotorOffset.Y != 0 || m_linearMotorOffset.Z != 0)
  704. {
  705. // have offset, do it now
  706. tmpV *= dmass.mass;
  707. d.BodyAddForceAtRelPos(Body, tmpV.X, tmpV.Y, tmpV.Z, m_linearMotorOffset.X, m_linearMotorOffset.Y, m_linearMotorOffset.Z);
  708. }
  709. else
  710. {
  711. force.X += tmpV.X;
  712. force.Y += tmpV.Y;
  713. force.Z += tmpV.Z;
  714. }
  715. m_lmEfect *= m_lmDecay;
  716. // m_ffactor = 0.01f + 1e-4f * curVel.LengthSquared();
  717. m_ffactor = 0.0f;
  718. }
  719. else
  720. {
  721. m_lmEfect = 0;
  722. m_ffactor = 1f;
  723. }
  724. // hover
  725. if (m_VhoverTimescale < 300 && rootPrim.prim_geom != IntPtr.Zero)
  726. {
  727. // d.Vector3 pos = d.BodyGetPosition(Body);
  728. d.Vector3 pos = d.GeomGetPosition(rootPrim.prim_geom);
  729. pos.Z -= 0.21f; // minor offset that seems to be always there in sl
  730. float t = _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y);
  731. float perr;
  732. // default to global but don't go underground
  733. perr = m_VhoverHeight - pos.Z;
  734. if ((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) == 0)
  735. {
  736. if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0)
  737. {
  738. perr += _pParentScene.GetWaterLevel();
  739. }
  740. else if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0)
  741. {
  742. perr += t;
  743. }
  744. else
  745. {
  746. float w = _pParentScene.GetWaterLevel();
  747. if (t > w)
  748. perr += t;
  749. else
  750. perr += w;
  751. }
  752. }
  753. else if (t > m_VhoverHeight)
  754. perr = t - pos.Z; ;
  755. if ((m_flags & VehicleFlag.HOVER_UP_ONLY) == 0 || perr > -0.1)
  756. {
  757. ldampZ = m_VhoverEfficiency * m_invtimestep;
  758. perr *= (1.0f + ldampZ) / m_VhoverTimescale;
  759. // force.Z += perr - curVel.Z * tmp;
  760. force.Z += perr;
  761. ldampZ *= -curVel.Z;
  762. force.Z += _pParentScene.gravityz * m_gravmod * (1f - m_VehicleBuoyancy);
  763. }
  764. else // no buoyancy
  765. force.Z += _pParentScene.gravityz;
  766. }
  767. else
  768. {
  769. // default gravity and Buoyancy
  770. force.Z += _pParentScene.gravityz * m_gravmod * (1f - m_VehicleBuoyancy);
  771. }
  772. // linear deflection
  773. if (m_linearDeflectionEfficiency > 0)
  774. {
  775. float len = curVel.Length();
  776. if (len > 0.01) // if moving
  777. {
  778. Vector3 atAxis;
  779. atAxis = Xrot(rotq); // where are we pointing to
  780. atAxis *= len; // make it same size as world velocity vector
  781. tmpV = -atAxis; // oposite direction
  782. atAxis -= curVel; // error to one direction
  783. len = atAxis.LengthSquared();
  784. tmpV -= curVel; // error to oposite
  785. float lens = tmpV.LengthSquared();
  786. if (len > 0.01 || lens > 0.01) // do nothing if close enougth
  787. {
  788. if (len < lens)
  789. tmpV = atAxis;
  790. tmpV *= (m_linearDeflectionEfficiency / m_linearDeflectionTimescale); // error to correct in this timestep
  791. force.X += tmpV.X;
  792. force.Y += tmpV.Y;
  793. if ((m_flags & VehicleFlag.NO_DEFLECTION_UP) == 0)
  794. force.Z += tmpV.Z;
  795. }
  796. }
  797. }
  798. // linear friction/damping
  799. if (curLocalVel.X != 0 || curLocalVel.Y != 0 || curLocalVel.Z != 0)
  800. {
  801. tmpV.X = -curLocalVel.X / m_linearFrictionTimescale.X;
  802. tmpV.Y = -curLocalVel.Y / m_linearFrictionTimescale.Y;
  803. tmpV.Z = -curLocalVel.Z / m_linearFrictionTimescale.Z;
  804. tmpV *= rotq; // to world
  805. if(ldampZ != 0 && Math.Abs(ldampZ) > Math.Abs(tmpV.Z))
  806. tmpV.Z = ldampZ;
  807. force.X += tmpV.X;
  808. force.Y += tmpV.Y;
  809. force.Z += tmpV.Z;
  810. }
  811. // vertical atractor
  812. if (m_verticalAttractionTimescale < 300)
  813. {
  814. float roll;
  815. float pitch;
  816. float ftmp = m_invtimestep / m_verticalAttractionTimescale / m_verticalAttractionTimescale;
  817. float ftmp2;
  818. ftmp2 = 0.5f * m_verticalAttractionEfficiency * m_invtimestep;
  819. m_amdampX = ftmp2;
  820. m_ampwr = 1.0f - 0.8f * m_verticalAttractionEfficiency;
  821. GetRollPitch(irotq, out roll, out pitch);
  822. if (roll > halfpi)
  823. roll = pi - roll;
  824. else if (roll < -halfpi)
  825. roll = -pi - roll;
  826. float effroll = pitch / halfpi;
  827. effroll *= effroll;
  828. effroll = 1 - effroll;
  829. effroll *= roll;
  830. torque.X += effroll * ftmp;
  831. if ((m_flags & VehicleFlag.LIMIT_ROLL_ONLY) == 0)
  832. {
  833. float effpitch = roll / halfpi;
  834. effpitch *= effpitch;
  835. effpitch = 1 - effpitch;
  836. effpitch *= pitch;
  837. torque.Y += effpitch * ftmp;
  838. }
  839. if (m_bankingEfficiency != 0 && Math.Abs(effroll) > 0.01)
  840. {
  841. float broll = effroll;
  842. /*
  843. if (broll > halfpi)
  844. broll = pi - broll;
  845. else if (broll < -halfpi)
  846. broll = -pi - broll;
  847. */
  848. broll *= m_bankingEfficiency;
  849. if (m_bankingMix != 0)
  850. {
  851. float vfact = Math.Abs(curLocalVel.X) / 10.0f;
  852. if (vfact > 1.0f) vfact = 1.0f;
  853. if (curLocalVel.X >= 0)
  854. broll *= (1 + (vfact - 1) * m_bankingMix);
  855. else
  856. broll *= -(1 + (vfact - 1) * m_bankingMix);
  857. }
  858. // make z rot be in world Z not local as seems to be in sl
  859. broll = broll / m_bankingTimescale;
  860. tmpV = Zrot(irotq);
  861. tmpV *= broll;
  862. torque.X += tmpV.X;
  863. torque.Y += tmpV.Y;
  864. torque.Z += tmpV.Z;
  865. m_amdampZ = Math.Abs(m_bankingEfficiency) / m_bankingTimescale;
  866. m_amdampY = m_amdampZ;
  867. }
  868. else
  869. {
  870. m_amdampZ = 1 / m_angularFrictionTimescale.Z;
  871. m_amdampY = m_amdampX;
  872. }
  873. }
  874. else
  875. {
  876. m_ampwr = 1.0f;
  877. m_amdampX = 1 / m_angularFrictionTimescale.X;
  878. m_amdampY = 1 / m_angularFrictionTimescale.Y;
  879. m_amdampZ = 1 / m_angularFrictionTimescale.Z;
  880. }
  881. // angular motor
  882. if (m_amEfect > 0.01 && m_angularMotorTimescale < 1000)
  883. {
  884. tmpV = m_angularMotorDirection - curLocalAngVel; // velocity error
  885. tmpV *= m_amEfect / m_angularMotorTimescale; // error to correct in this timestep
  886. torque.X += tmpV.X * m_ampwr;
  887. torque.Y += tmpV.Y * m_ampwr;
  888. torque.Z += tmpV.Z;
  889. m_amEfect *= m_amDecay;
  890. }
  891. else
  892. m_amEfect = 0;
  893. // angular deflection
  894. if (m_angularDeflectionEfficiency > 0)
  895. {
  896. Vector3 dirv;
  897. if (curLocalVel.X > 0.01f)
  898. dirv = curLocalVel;
  899. else if (curLocalVel.X < -0.01f)
  900. // use oposite
  901. dirv = -curLocalVel;
  902. else
  903. {
  904. // make it fall into small positive x case
  905. dirv.X = 0.01f;
  906. dirv.Y = curLocalVel.Y;
  907. dirv.Z = curLocalVel.Z;
  908. }
  909. float ftmp = m_angularDeflectionEfficiency / m_angularDeflectionTimescale;
  910. if (Math.Abs(dirv.Z) > 0.01)
  911. {
  912. torque.Y += - (float)Math.Atan2(dirv.Z, dirv.X) * ftmp;
  913. }
  914. if (Math.Abs(dirv.Y) > 0.01)
  915. {
  916. torque.Z += (float)Math.Atan2(dirv.Y, dirv.X) * ftmp;
  917. }
  918. }
  919. // angular friction
  920. if (curLocalAngVel.X != 0 || curLocalAngVel.Y != 0 || curLocalAngVel.Z != 0)
  921. {
  922. torque.X -= curLocalAngVel.X * m_amdampX;
  923. torque.Y -= curLocalAngVel.Y * m_amdampY;
  924. torque.Z -= curLocalAngVel.Z * m_amdampZ;
  925. }
  926. if (force.X != 0 || force.Y != 0 || force.Z != 0)
  927. {
  928. force *= dmass.mass;
  929. d.BodyAddForce(Body, force.X, force.Y, force.Z);
  930. }
  931. if (torque.X != 0 || torque.Y != 0 || torque.Z != 0)
  932. {
  933. torque *= m_referenceFrame; // to object frame
  934. dtorque.X = torque.X ;
  935. dtorque.Y = torque.Y;
  936. dtorque.Z = torque.Z;
  937. d.MultiplyM3V3(out dvtmp, ref dmass.I, ref dtorque);
  938. d.BodyAddRelTorque(Body, dvtmp.X, dvtmp.Y, dvtmp.Z); // add torque in object frame
  939. }
  940. }
  941. }
  942. }