physics_data.py 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582
  1. #
  2. # Copyright (c) Contributors to the Open 3D Engine Project.
  3. # For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. #
  5. # SPDX-License-Identifier: Apache-2.0 OR MIT
  6. #
  7. #
  8. # for underlying data structures, see Code\Framework\AzFramework\AzFramework\Physics\Shape.h
  9. class ColliderConfiguration():
  10. """
  11. Configuration for a collider
  12. Attributes
  13. ----------
  14. Trigger: bool
  15. Should this shape act as a trigger shape.
  16. Simulated: bool
  17. Should this shape partake in collision in the physical simulation.
  18. InSceneQueries: bool
  19. Should this shape partake in scene queries (ray casts, overlap tests, sweeps).
  20. Exclusive: bool
  21. Can this collider be shared between multiple bodies?
  22. Position: [float, float, float] Vector3
  23. Shape offset relative to the connected rigid body.
  24. Rotation: [float, float, float, float] Quaternion
  25. Shape rotation relative to the connected rigid body.
  26. ColliderTag: str
  27. Identification tag for the collider.
  28. RestOffset: float
  29. Bodies will come to rest separated by the sum of their rest offsets.
  30. ContactOffset: float
  31. Bodies will start to generate contacts when closer than the sum of their contact offsets.
  32. Methods
  33. -------
  34. to_dict()
  35. Converts contents to a Python dictionary
  36. """
  37. def __init__(self):
  38. self.Trigger = True
  39. self.Simulated = True
  40. self.InSceneQueries = True
  41. self.Exclusive = True
  42. self.Position = [0.0, 0.0, 0.0]
  43. self.Rotation = [0.0, 0.0, 0.0, 1.0]
  44. self.ColliderTag = ''
  45. self.RestOffset = 0.0
  46. self.ContactOffset = 0.02
  47. def to_dict(self):
  48. return self.__dict__
  49. # for underlying data structures, see Code\Framework\AzFramework\AzFramework\Physics\Character.h
  50. class CharacterColliderNodeConfiguration():
  51. """
  52. Shapes to define the animation's to model of physics
  53. Attributes
  54. ----------
  55. name : str
  56. debug name of the node
  57. shapes : `list` of `tuple` of (ColliderConfiguration, ShapeConfiguration)
  58. a list of pairs of collider and shape configuration
  59. Methods
  60. -------
  61. add_collider_shape_pair(colliderConfiguration, shapeConfiguration)
  62. Helper function to add a collider and shape configuration at the same time
  63. to_dict()
  64. Converts contents to a Python dictionary
  65. """
  66. def __init__(self):
  67. self.name = ''
  68. self.shapes = [] # List of Tuple of (ColliderConfiguration, ShapeConfiguration)
  69. def add_collider_shape_pair(self, colliderConfiguration, shapeConfiguration) -> None:
  70. pair = (colliderConfiguration, shapeConfiguration)
  71. self.shapes.append(pair)
  72. def to_dict(self):
  73. data = {}
  74. shapeList = []
  75. for index, shape in enumerate(self.shapes):
  76. tupleValue = (shape[0].to_dict(), # ColliderConfiguration
  77. shape[1].to_dict()) # ShapeConfiguration
  78. shapeList.append(tupleValue)
  79. data['name'] = self.name
  80. data['shapes'] = shapeList
  81. return data
  82. class CharacterColliderConfiguration():
  83. """
  84. Information required to create the basic physics representation of a character.
  85. Attributes
  86. ----------
  87. nodes : `list` of CharacterColliderNodeConfiguration
  88. a list of CharacterColliderNodeConfiguration nodes
  89. Methods
  90. -------
  91. add_character_collider_node_configuration(colliderConfiguration, shapeConfiguration)
  92. Helper function to add a character collider node configuration into the nodes
  93. add_character_collider_node_configuration_node(name, colliderConfiguration, shapeConfiguration)
  94. Helper function to add a character collider node configuration into the nodes
  95. **Returns**: CharacterColliderNodeConfiguration
  96. to_dict()
  97. Converts contents to a Python dictionary
  98. """
  99. def __init__(self):
  100. self.nodes = [] # list of CharacterColliderNodeConfiguration
  101. def add_character_collider_node_configuration(self, characterColliderNodeConfiguration) -> None:
  102. self.nodes.append(characterColliderNodeConfiguration)
  103. def add_character_collider_node_configuration_node(self, name, colliderConfiguration, shapeConfiguration) -> CharacterColliderNodeConfiguration:
  104. characterColliderNodeConfiguration = CharacterColliderNodeConfiguration()
  105. self.add_character_collider_node_configuration(characterColliderNodeConfiguration)
  106. characterColliderNodeConfiguration.name = name
  107. characterColliderNodeConfiguration.add_collider_shape_pair(colliderConfiguration, shapeConfiguration)
  108. return characterColliderNodeConfiguration
  109. def to_dict(self):
  110. data = {}
  111. nodeList = []
  112. for node in self.nodes:
  113. nodeList.append(node.to_dict())
  114. data['nodes'] = nodeList
  115. return data
  116. # see Code\Framework\AzFramework\AzFramework\Physics\ShapeConfiguration.h for underlying data structures
  117. class ShapeConfiguration():
  118. """
  119. Base class for all the shape collider configurations
  120. Attributes
  121. ----------
  122. scale : [float, float, float]
  123. a 3-element list to describe the scale along the X, Y, and Z axises such as [1.0, 1.0, 1.0]
  124. Methods
  125. -------
  126. to_dict()
  127. Converts contents to a Python dictionary
  128. """
  129. def __init__(self, shapeType):
  130. self._shapeType = shapeType
  131. self.scale = [1.0, 1.0, 1.0]
  132. def to_dict(self):
  133. return {
  134. "$type": self._shapeType,
  135. "Scale": self.scale
  136. }
  137. class SphereShapeConfiguration(ShapeConfiguration):
  138. """
  139. The configuration for a Sphere collider
  140. Attributes
  141. ----------
  142. radius: float
  143. a scalar value to define the radius of the sphere
  144. Methods
  145. -------
  146. to_dict()
  147. Converts contents to a Python dictionary
  148. """
  149. def __init__(self):
  150. super().__init__('SphereShapeConfiguration')
  151. self.radius = 0.5
  152. def to_dict(self):
  153. data = super().to_dict()
  154. data['Radius'] = self.radius
  155. return data
  156. class BoxShapeConfiguration(ShapeConfiguration):
  157. """
  158. The configuration for a Box collider
  159. Attributes
  160. ----------
  161. dimensions: [float, float, float]
  162. The width, height, and depth dimensions of the Box collider
  163. Methods
  164. -------
  165. to_dict()
  166. Converts contents to a Python dictionary
  167. """
  168. def __init__(self):
  169. super().__init__('BoxShapeConfiguration')
  170. self.dimensions = [1.0, 1.0, 1.0]
  171. def to_dict(self):
  172. data = super().to_dict()
  173. data['Configuration'] = self.dimensions
  174. return data
  175. class CapsuleShapeConfiguration(ShapeConfiguration):
  176. """
  177. The configuration for a Capsule collider
  178. Attributes
  179. ----------
  180. height: float
  181. The height of the Capsule
  182. radius: float
  183. The radius of the Capsule
  184. Methods
  185. -------
  186. to_dict()
  187. Converts contents to a Python dictionary
  188. """
  189. def __init__(self):
  190. super().__init__('CapsuleShapeConfiguration')
  191. self.height = 1.00
  192. self.radius = 0.25
  193. def to_dict(self):
  194. data = super().to_dict()
  195. data['Height'] = self.height
  196. data['Radius'] = self.radius
  197. return data
  198. class PhysicsAssetShapeConfiguration(ShapeConfiguration):
  199. """
  200. The configuration for a Asset collider using a mesh asset for collision
  201. Attributes
  202. ----------
  203. asset: { "assetHint": assetReference }
  204. the name of the asset to load for collision information
  205. assetScale: [float, float, float]
  206. The scale of the asset shape such as [1.0, 1.0, 1.0]
  207. useMaterialsFromAsset: bool
  208. Auto-set physics materials using asset's physics material names
  209. subdivisionLevel: int
  210. The level of subdivision if a primitive shape is replaced with a convex mesh due to scaling.
  211. Methods
  212. -------
  213. set_asset_reference(self, assetReference: str)
  214. Helper function to set the asset reference to the collision mesh such as 'my/folder/my_mesh.fbx.azmodel'
  215. to_dict()
  216. Converts contents to a Python dictionary
  217. """
  218. def __init__(self):
  219. super().__init__('PhysicsAssetShapeConfiguration')
  220. self.asset = {}
  221. self.assetScale = [1.0, 1.0, 1.0]
  222. self.useMaterialsFromAsset = True
  223. self.subdivisionLevel = 4
  224. def set_asset_reference(self, assetReference: str) -> None:
  225. self.asset = { "assetHint": assetReference }
  226. def to_dict(self):
  227. data = super().to_dict()
  228. data['PhysicsAsset'] = self.asset
  229. data['AssetScale'] = self.assetScale
  230. data['UseMaterialsFromAsset'] = self.useMaterialsFromAsset
  231. data['SubdivisionLevel'] = self.subdivisionLevel
  232. return data
  233. # for underlying data structures, see Code\Framework\AzFramework\AzFramework\Physics\Configuration\JointConfiguration.h
  234. class JointConfiguration():
  235. """
  236. The joint configuration
  237. see also: class AzPhysics::JointConfiguration
  238. Attributes
  239. ----------
  240. Name: str
  241. For debugging/tracking purposes only.
  242. ParentLocalRotation: [float, float, float, float]
  243. Parent joint frame relative to parent body.
  244. ParentLocalPosition: [float, float, float]
  245. Joint position relative to parent body.
  246. ChildLocalRotation: [float, float, float, float]
  247. Child joint frame relative to child body.
  248. ChildLocalPosition: [float, float, float]
  249. Joint position relative to child body.
  250. StartSimulationEnabled: bool
  251. When active, the joint will be enabled when the simulation begins.
  252. Methods
  253. -------
  254. to_dict()
  255. Converts contents to a Python dictionary
  256. """
  257. def __init__(self):
  258. self.Name = ''
  259. self.ParentLocalRotation = [0.0, 0.0, 0.0, 1.0]
  260. self.ParentLocalPosition = [0.0, 0.0, 0.0]
  261. self.ChildLocalRotation = [0.0, 0.0, 0.0, 1.0]
  262. self.ChildLocalPosition = [0.0, 0.0, 0.0]
  263. self.StartSimulationEnabled = True
  264. def to_dict(self):
  265. return self.__dict__
  266. # for underlying data structures, see Code\Framework\AzFramework\AzFramework\Physics\Configuration\SimulatedBodyConfiguration.h
  267. class SimulatedBodyConfiguration():
  268. """
  269. Base Class of all Physics Bodies that will be simulated.
  270. see also: class AzPhysics::SimulatedBodyConfiguration
  271. Attributes
  272. ----------
  273. name: str
  274. For debugging/tracking purposes only.
  275. position: [float, float, float]
  276. starting position offset
  277. orientation: [float, float, float, float]
  278. starting rotation (Quaternion)
  279. startSimulationEnabled: bool
  280. to start when simulation engine starts
  281. Methods
  282. -------
  283. to_dict()
  284. Converts contents to a Python dictionary
  285. """
  286. def __init__(self):
  287. self.name = ''
  288. self.position = [0.0, 0.0, 0.0]
  289. self.orientation = [0.0, 0.0, 0.0, 1.0]
  290. self.startSimulationEnabled = True
  291. def to_dict(self):
  292. return {
  293. "name" : self.name,
  294. "position" : self.position,
  295. "orientation" : self.orientation,
  296. "startSimulationEnabled" : self.startSimulationEnabled
  297. }
  298. # for underlying data structures, see Code\Framework\AzFramework\AzFramework\Physics\Configuration\RigidBodyConfiguration.h
  299. class RigidBodyConfiguration(SimulatedBodyConfiguration):
  300. """
  301. PhysX Rigid Body Configuration
  302. see also: class AzPhysics::RigidBodyConfiguration
  303. Attributes
  304. ----------
  305. initialLinearVelocity: [float, float, float]
  306. Linear velocity applied when the rigid body is activated.
  307. initialAngularVelocity: [float, float, float]
  308. Angular velocity applied when the rigid body is activated (limited by maximum angular velocity)
  309. centerOfMassOffset: [float, float, float]
  310. Local space offset for the center of mass (COM).
  311. mass: float
  312. The mass of the rigid body in kilograms.
  313. A value of 0 is treated as infinite.
  314. The trajectory of infinite mass bodies cannot be affected by any collisions or forces other than gravity.
  315. linearDamping: float
  316. The rate of decay over time for linear velocity even if no forces are acting on the rigid body.
  317. angularDamping: float
  318. The rate of decay over time for angular velocity even if no forces are acting on the rigid body.
  319. sleepMinEnergy: float
  320. The rigid body can go to sleep (settle) when kinetic energy per unit mass is persistently below this value.
  321. maxAngularVelocity: float
  322. Clamp angular velocities to this maximum value.
  323. startAsleep: bool
  324. When active, the rigid body will be asleep when spawned, and wake when the body is disturbed.
  325. interpolateMotion: bool
  326. When active, simulation results are interpolated resulting in smoother motion.
  327. gravityEnabled: bool
  328. When active, global gravity affects this rigid body.
  329. kinematic: bool
  330. When active, the rigid body is not affected by gravity or other forces and is moved by script.
  331. ccdEnabled: bool
  332. When active, the rigid body has continuous collision detection (CCD).
  333. Use this to ensure accurate collision detection, particularly for fast moving rigid bodies.
  334. CCD must be activated in the global PhysX preferences.
  335. ccdMinAdvanceCoefficient: float
  336. Coefficient affecting how granularly time is subdivided in CCD.
  337. ccdFrictionEnabled: bool
  338. Whether friction is applied when resolving CCD collisions.
  339. computeCenterOfMass: bool
  340. Compute the center of mass (COM) for this rigid body.
  341. computeInertiaTensor: bool
  342. When active, inertia is computed based on the mass and shape of the rigid body.
  343. computeMass: bool
  344. When active, the mass of the rigid body is computed based on the volume and density values of its colliders.
  345. Methods
  346. -------
  347. to_dict()
  348. Converts contents to a Python dictionary
  349. """
  350. def __init__(self):
  351. super().__init__()
  352. # Basic initial settings.
  353. self.initialLinearVelocity = [0.0, 0.0, 0.0]
  354. self.initialAngularVelocity = [0.0, 0.0, 0.0]
  355. self.centerOfMassOffset = [0.0, 0.0, 0.0]
  356. # Simulation parameters.
  357. self.mass = 1.0
  358. self.linearDamping = 0.05
  359. self.angularDamping = 0.15
  360. self.sleepMinEnergy = 0.005
  361. self.maxAngularVelocity = 100.0
  362. self.startAsleep = False
  363. self.interpolateMotion = False
  364. self.gravityEnabled = True
  365. self.kinematic = False
  366. self.ccdEnabled = False
  367. self.ccdMinAdvanceCoefficient = 0.15
  368. self.ccdFrictionEnabled = False
  369. self.computeCenterOfMass = True
  370. self.computeInertiaTensor = True
  371. self.computeMass = True
  372. # Flags to restrict motion along specific world-space axes.
  373. self.lockLinearX = False
  374. self.lockLinearY = False
  375. self.lockLinearZ = False
  376. # Flags to restrict rotation around specific world-space axes.
  377. self.lockAngularX = False
  378. self.lockAngularY = False
  379. self.lockAngularZ = False
  380. # If set, non-simulated shapes will also be included in the mass properties calculation.
  381. self.includeAllShapesInMassCalculation = False
  382. def to_dict(self):
  383. data = super().to_dict()
  384. data["Initial linear velocity"] = self.initialLinearVelocity
  385. data["Initial angular velocity"] = self.initialAngularVelocity
  386. data["Linear damping"] = self.linearDamping
  387. data["Angular damping"] = self.angularDamping
  388. data["Sleep threshold"] = self.sleepMinEnergy
  389. data["Start Asleep"] = self.startAsleep
  390. data["Interpolate Motion"] = self.interpolateMotion
  391. data["Gravity Enabled"] = self.gravityEnabled
  392. data["Kinematic"] = self.kinematic
  393. data["CCD Enabled"] = self.ccdEnabled
  394. data["Compute Mass"] = self.computeMass
  395. data["Lock Linear X"] = self.lockLinearX
  396. data["Lock Linear Y"] = self.lockLinearY
  397. data["Lock Linear Z"] = self.lockLinearZ
  398. data["Lock Angular X"] = self.lockAngularX
  399. data["Lock Angular Y"] = self.lockAngularY
  400. data["Lock Angular Z"] = self.lockAngularZ
  401. data["Mass"] = self.mass
  402. data["Compute COM"] = self.computeCenterOfMass
  403. data["Centre of mass offset"] = self.centerOfMassOffset
  404. data["Compute inertia"] = self.computeInertiaTensor
  405. data["Maximum Angular Velocity"] = self.maxAngularVelocity
  406. data["Include All Shapes In Mass"] = self.includeAllShapesInMassCalculation
  407. data["CCD Min Advance"] = self.ccdMinAdvanceCoefficient
  408. data["CCD Friction"] = self.ccdFrictionEnabled
  409. return data
  410. # for underlying data structures, see Code\Framework\AzFramework\AzFramework\Physics\Ragdoll.h
  411. class RagdollNodeConfiguration(RigidBodyConfiguration):
  412. """
  413. Ragdoll node Configuration
  414. see also: class Physics::RagdollConfiguration
  415. Attributes
  416. ----------
  417. JointConfig: JointConfiguration
  418. Ragdoll joint node configuration
  419. Methods
  420. -------
  421. to_dict()
  422. Converts contents to a Python dictionary
  423. """
  424. def __init__(self):
  425. super().__init__()
  426. self.JointConfig = JointConfiguration()
  427. def to_dict(self):
  428. data = super().to_dict()
  429. data['JointConfig'] = self.JointConfig.to_dict()
  430. return data
  431. class RagdollConfiguration():
  432. """
  433. A configuration of join nodes and a character collider configuration for a ragdoll
  434. see also: class Physics::RagdollConfiguration
  435. Attributes
  436. ----------
  437. nodes: `list` of RagdollNodeConfiguration
  438. A list of RagdollNodeConfiguration entries
  439. colliders: CharacterColliderConfiguration
  440. A CharacterColliderConfiguration
  441. Methods
  442. -------
  443. add_ragdoll_node_configuration(ragdollNodeConfiguration)
  444. Helper function to add a single ragdoll node configuration (normally for each joint/bone node)
  445. to_dict()
  446. Converts contents to a Python dictionary
  447. """
  448. def __init__(self):
  449. self.nodes = [] # list of RagdollNodeConfiguration
  450. self.colliders = CharacterColliderConfiguration()
  451. def add_ragdoll_node_configuration(self, ragdollNodeConfiguration) -> None:
  452. self.nodes.append(ragdollNodeConfiguration)
  453. def to_dict(self):
  454. data = {}
  455. nodeList = []
  456. for index, node in enumerate(self.nodes):
  457. nodeList.append(node.to_dict())
  458. data['nodes'] = nodeList
  459. data['colliders'] = self.colliders.to_dict()
  460. return data