# # Copyright (c) Contributors to the Open 3D Engine Project. # For complete copyright and license terms please see the LICENSE at the root of this distribution. # # SPDX-License-Identifier: Apache-2.0 OR MIT # # # for underlying data structures, see Code\Framework\AzFramework\AzFramework\Physics\Shape.h class ColliderConfiguration(): """ Configuration for a collider Attributes ---------- Trigger: bool Should this shape act as a trigger shape. Simulated: bool Should this shape partake in collision in the physical simulation. InSceneQueries: bool Should this shape partake in scene queries (ray casts, overlap tests, sweeps). Exclusive: bool Can this collider be shared between multiple bodies? Position: [float, float, float] Vector3 Shape offset relative to the connected rigid body. Rotation: [float, float, float, float] Quaternion Shape rotation relative to the connected rigid body. ColliderTag: str Identification tag for the collider. RestOffset: float Bodies will come to rest separated by the sum of their rest offsets. ContactOffset: float Bodies will start to generate contacts when closer than the sum of their contact offsets. Methods ------- to_dict() Converts contents to a Python dictionary """ def __init__(self): self.Trigger = True self.Simulated = True self.InSceneQueries = True self.Exclusive = True self.Position = [0.0, 0.0, 0.0] self.Rotation = [0.0, 0.0, 0.0, 1.0] self.ColliderTag = '' self.RestOffset = 0.0 self.ContactOffset = 0.02 def to_dict(self): return self.__dict__ # for underlying data structures, see Code\Framework\AzFramework\AzFramework\Physics\Character.h class CharacterColliderNodeConfiguration(): """ Shapes to define the animation's to model of physics Attributes ---------- name : str debug name of the node shapes : `list` of `tuple` of (ColliderConfiguration, ShapeConfiguration) a list of pairs of collider and shape configuration Methods ------- add_collider_shape_pair(colliderConfiguration, shapeConfiguration) Helper function to add a collider and shape configuration at the same time to_dict() Converts contents to a Python dictionary """ def __init__(self): self.name = '' self.shapes = [] # List of Tuple of (ColliderConfiguration, ShapeConfiguration) def add_collider_shape_pair(self, colliderConfiguration, shapeConfiguration) -> None: pair = (colliderConfiguration, shapeConfiguration) self.shapes.append(pair) def to_dict(self): data = {} shapeList = [] for index, shape in enumerate(self.shapes): tupleValue = (shape[0].to_dict(), # ColliderConfiguration shape[1].to_dict()) # ShapeConfiguration shapeList.append(tupleValue) data['name'] = self.name data['shapes'] = shapeList return data class CharacterColliderConfiguration(): """ Information required to create the basic physics representation of a character. Attributes ---------- nodes : `list` of CharacterColliderNodeConfiguration a list of CharacterColliderNodeConfiguration nodes Methods ------- add_character_collider_node_configuration(colliderConfiguration, shapeConfiguration) Helper function to add a character collider node configuration into the nodes add_character_collider_node_configuration_node(name, colliderConfiguration, shapeConfiguration) Helper function to add a character collider node configuration into the nodes **Returns**: CharacterColliderNodeConfiguration to_dict() Converts contents to a Python dictionary """ def __init__(self): self.nodes = [] # list of CharacterColliderNodeConfiguration def add_character_collider_node_configuration(self, characterColliderNodeConfiguration) -> None: self.nodes.append(characterColliderNodeConfiguration) def add_character_collider_node_configuration_node(self, name, colliderConfiguration, shapeConfiguration) -> CharacterColliderNodeConfiguration: characterColliderNodeConfiguration = CharacterColliderNodeConfiguration() self.add_character_collider_node_configuration(characterColliderNodeConfiguration) characterColliderNodeConfiguration.name = name characterColliderNodeConfiguration.add_collider_shape_pair(colliderConfiguration, shapeConfiguration) return characterColliderNodeConfiguration def to_dict(self): data = {} nodeList = [] for node in self.nodes: nodeList.append(node.to_dict()) data['nodes'] = nodeList return data # see Code\Framework\AzFramework\AzFramework\Physics\ShapeConfiguration.h for underlying data structures class ShapeConfiguration(): """ Base class for all the shape collider configurations Attributes ---------- scale : [float, float, float] a 3-element list to describe the scale along the X, Y, and Z axises such as [1.0, 1.0, 1.0] Methods ------- to_dict() Converts contents to a Python dictionary """ def __init__(self, shapeType): self._shapeType = shapeType self.scale = [1.0, 1.0, 1.0] def to_dict(self): return { "$type": self._shapeType, "Scale": self.scale } class SphereShapeConfiguration(ShapeConfiguration): """ The configuration for a Sphere collider Attributes ---------- radius: float a scalar value to define the radius of the sphere Methods ------- to_dict() Converts contents to a Python dictionary """ def __init__(self): super().__init__('SphereShapeConfiguration') self.radius = 0.5 def to_dict(self): data = super().to_dict() data['Radius'] = self.radius return data class BoxShapeConfiguration(ShapeConfiguration): """ The configuration for a Box collider Attributes ---------- dimensions: [float, float, float] The width, height, and depth dimensions of the Box collider Methods ------- to_dict() Converts contents to a Python dictionary """ def __init__(self): super().__init__('BoxShapeConfiguration') self.dimensions = [1.0, 1.0, 1.0] def to_dict(self): data = super().to_dict() data['Configuration'] = self.dimensions return data class CapsuleShapeConfiguration(ShapeConfiguration): """ The configuration for a Capsule collider Attributes ---------- height: float The height of the Capsule radius: float The radius of the Capsule Methods ------- to_dict() Converts contents to a Python dictionary """ def __init__(self): super().__init__('CapsuleShapeConfiguration') self.height = 1.00 self.radius = 0.25 def to_dict(self): data = super().to_dict() data['Height'] = self.height data['Radius'] = self.radius return data class PhysicsAssetShapeConfiguration(ShapeConfiguration): """ The configuration for a Asset collider using a mesh asset for collision Attributes ---------- asset: { "assetHint": assetReference } the name of the asset to load for collision information assetScale: [float, float, float] The scale of the asset shape such as [1.0, 1.0, 1.0] useMaterialsFromAsset: bool Auto-set physics materials using asset's physics material names subdivisionLevel: int The level of subdivision if a primitive shape is replaced with a convex mesh due to scaling. Methods ------- set_asset_reference(self, assetReference: str) Helper function to set the asset reference to the collision mesh such as 'my/folder/my_mesh.fbx.azmodel' to_dict() Converts contents to a Python dictionary """ def __init__(self): super().__init__('PhysicsAssetShapeConfiguration') self.asset = {} self.assetScale = [1.0, 1.0, 1.0] self.useMaterialsFromAsset = True self.subdivisionLevel = 4 def set_asset_reference(self, assetReference: str) -> None: self.asset = { "assetHint": assetReference } def to_dict(self): data = super().to_dict() data['PhysicsAsset'] = self.asset data['AssetScale'] = self.assetScale data['UseMaterialsFromAsset'] = self.useMaterialsFromAsset data['SubdivisionLevel'] = self.subdivisionLevel return data # for underlying data structures, see Code\Framework\AzFramework\AzFramework\Physics\Configuration\JointConfiguration.h class JointConfiguration(): """ The joint configuration see also: class AzPhysics::JointConfiguration Attributes ---------- Name: str For debugging/tracking purposes only. ParentLocalRotation: [float, float, float, float] Parent joint frame relative to parent body. ParentLocalPosition: [float, float, float] Joint position relative to parent body. ChildLocalRotation: [float, float, float, float] Child joint frame relative to child body. ChildLocalPosition: [float, float, float] Joint position relative to child body. StartSimulationEnabled: bool When active, the joint will be enabled when the simulation begins. Methods ------- to_dict() Converts contents to a Python dictionary """ def __init__(self): self.Name = '' self.ParentLocalRotation = [0.0, 0.0, 0.0, 1.0] self.ParentLocalPosition = [0.0, 0.0, 0.0] self.ChildLocalRotation = [0.0, 0.0, 0.0, 1.0] self.ChildLocalPosition = [0.0, 0.0, 0.0] self.StartSimulationEnabled = True def to_dict(self): return self.__dict__ # for underlying data structures, see Code\Framework\AzFramework\AzFramework\Physics\Configuration\SimulatedBodyConfiguration.h class SimulatedBodyConfiguration(): """ Base Class of all Physics Bodies that will be simulated. see also: class AzPhysics::SimulatedBodyConfiguration Attributes ---------- name: str For debugging/tracking purposes only. position: [float, float, float] starting position offset orientation: [float, float, float, float] starting rotation (Quaternion) startSimulationEnabled: bool to start when simulation engine starts Methods ------- to_dict() Converts contents to a Python dictionary """ def __init__(self): self.name = '' self.position = [0.0, 0.0, 0.0] self.orientation = [0.0, 0.0, 0.0, 1.0] self.startSimulationEnabled = True def to_dict(self): return { "name" : self.name, "position" : self.position, "orientation" : self.orientation, "startSimulationEnabled" : self.startSimulationEnabled } # for underlying data structures, see Code\Framework\AzFramework\AzFramework\Physics\Configuration\RigidBodyConfiguration.h class RigidBodyConfiguration(SimulatedBodyConfiguration): """ PhysX Rigid Body Configuration see also: class AzPhysics::RigidBodyConfiguration Attributes ---------- initialLinearVelocity: [float, float, float] Linear velocity applied when the rigid body is activated. initialAngularVelocity: [float, float, float] Angular velocity applied when the rigid body is activated (limited by maximum angular velocity) centerOfMassOffset: [float, float, float] Local space offset for the center of mass (COM). mass: float The mass of the rigid body in kilograms. A value of 0 is treated as infinite. The trajectory of infinite mass bodies cannot be affected by any collisions or forces other than gravity. linearDamping: float The rate of decay over time for linear velocity even if no forces are acting on the rigid body. angularDamping: float The rate of decay over time for angular velocity even if no forces are acting on the rigid body. sleepMinEnergy: float The rigid body can go to sleep (settle) when kinetic energy per unit mass is persistently below this value. maxAngularVelocity: float Clamp angular velocities to this maximum value. startAsleep: bool When active, the rigid body will be asleep when spawned, and wake when the body is disturbed. interpolateMotion: bool When active, simulation results are interpolated resulting in smoother motion. gravityEnabled: bool When active, global gravity affects this rigid body. kinematic: bool When active, the rigid body is not affected by gravity or other forces and is moved by script. ccdEnabled: bool When active, the rigid body has continuous collision detection (CCD). Use this to ensure accurate collision detection, particularly for fast moving rigid bodies. CCD must be activated in the global PhysX preferences. ccdMinAdvanceCoefficient: float Coefficient affecting how granularly time is subdivided in CCD. ccdFrictionEnabled: bool Whether friction is applied when resolving CCD collisions. computeCenterOfMass: bool Compute the center of mass (COM) for this rigid body. computeInertiaTensor: bool When active, inertia is computed based on the mass and shape of the rigid body. computeMass: bool When active, the mass of the rigid body is computed based on the volume and density values of its colliders. Methods ------- to_dict() Converts contents to a Python dictionary """ def __init__(self): super().__init__() # Basic initial settings. self.initialLinearVelocity = [0.0, 0.0, 0.0] self.initialAngularVelocity = [0.0, 0.0, 0.0] self.centerOfMassOffset = [0.0, 0.0, 0.0] # Simulation parameters. self.mass = 1.0 self.linearDamping = 0.05 self.angularDamping = 0.15 self.sleepMinEnergy = 0.005 self.maxAngularVelocity = 100.0 self.startAsleep = False self.interpolateMotion = False self.gravityEnabled = True self.kinematic = False self.ccdEnabled = False self.ccdMinAdvanceCoefficient = 0.15 self.ccdFrictionEnabled = False self.computeCenterOfMass = True self.computeInertiaTensor = True self.computeMass = True # Flags to restrict motion along specific world-space axes. self.lockLinearX = False self.lockLinearY = False self.lockLinearZ = False # Flags to restrict rotation around specific world-space axes. self.lockAngularX = False self.lockAngularY = False self.lockAngularZ = False # If set, non-simulated shapes will also be included in the mass properties calculation. self.includeAllShapesInMassCalculation = False def to_dict(self): data = super().to_dict() data["Initial linear velocity"] = self.initialLinearVelocity data["Initial angular velocity"] = self.initialAngularVelocity data["Linear damping"] = self.linearDamping data["Angular damping"] = self.angularDamping data["Sleep threshold"] = self.sleepMinEnergy data["Start Asleep"] = self.startAsleep data["Interpolate Motion"] = self.interpolateMotion data["Gravity Enabled"] = self.gravityEnabled data["Kinematic"] = self.kinematic data["CCD Enabled"] = self.ccdEnabled data["Compute Mass"] = self.computeMass data["Lock Linear X"] = self.lockLinearX data["Lock Linear Y"] = self.lockLinearY data["Lock Linear Z"] = self.lockLinearZ data["Lock Angular X"] = self.lockAngularX data["Lock Angular Y"] = self.lockAngularY data["Lock Angular Z"] = self.lockAngularZ data["Mass"] = self.mass data["Compute COM"] = self.computeCenterOfMass data["Centre of mass offset"] = self.centerOfMassOffset data["Compute inertia"] = self.computeInertiaTensor data["Maximum Angular Velocity"] = self.maxAngularVelocity data["Include All Shapes In Mass"] = self.includeAllShapesInMassCalculation data["CCD Min Advance"] = self.ccdMinAdvanceCoefficient data["CCD Friction"] = self.ccdFrictionEnabled return data # for underlying data structures, see Code\Framework\AzFramework\AzFramework\Physics\Ragdoll.h class RagdollNodeConfiguration(RigidBodyConfiguration): """ Ragdoll node Configuration see also: class Physics::RagdollConfiguration Attributes ---------- JointConfig: JointConfiguration Ragdoll joint node configuration Methods ------- to_dict() Converts contents to a Python dictionary """ def __init__(self): super().__init__() self.JointConfig = JointConfiguration() def to_dict(self): data = super().to_dict() data['JointConfig'] = self.JointConfig.to_dict() return data class RagdollConfiguration(): """ A configuration of join nodes and a character collider configuration for a ragdoll see also: class Physics::RagdollConfiguration Attributes ---------- nodes: `list` of RagdollNodeConfiguration A list of RagdollNodeConfiguration entries colliders: CharacterColliderConfiguration A CharacterColliderConfiguration Methods ------- add_ragdoll_node_configuration(ragdollNodeConfiguration) Helper function to add a single ragdoll node configuration (normally for each joint/bone node) to_dict() Converts contents to a Python dictionary """ def __init__(self): self.nodes = [] # list of RagdollNodeConfiguration self.colliders = CharacterColliderConfiguration() def add_ragdoll_node_configuration(self, ragdollNodeConfiguration) -> None: self.nodes.append(ragdollNodeConfiguration) def to_dict(self): data = {} nodeList = [] for index, node in enumerate(self.nodes): nodeList.append(node.to_dict()) data['nodes'] = nodeList data['colliders'] = self.colliders.to_dict() return data