{lyn2264} Adding Python API for Actor Group (#6064)

* {lyn2264} Adding Python API for Actor Group

* updating the IBoneData with behavior attributes
* adding actor_group.py for making actor group JSON data
* adding physics_data.py for making physics JSON data

Signed-off-by: Allen Jackson <23512001+jackalbe@users.noreply.github.com>

* fixing dictionary issues

Signed-off-by: Allen Jackson <23512001+jackalbe@users.noreply.github.com>

* updated comment style to numpydoc

Signed-off-by: Allen Jackson <23512001+jackalbe@users.noreply.github.com>

* updated to numpydoc style

Signed-off-by: Allen Jackson <23512001+jackalbe@users.noreply.github.com>

* example of actor group rules

Signed-off-by: Allen Jackson <23512001+jackalbe@users.noreply.github.com>

* Updated based on feedback

Signed-off-by: Allen Jackson <23512001+jackalbe@users.noreply.github.com>
This commit is contained in:
Allen Jackson
2021-12-06 17:11:30 -06:00
committed by GitHub
parent 35b7705119
commit dae25beef5
6 changed files with 1334 additions and 0 deletions
@@ -0,0 +1,519 @@
"""
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
"""
import json
import uuid
import os, sys
sys.path.append(os.path.dirname(__file__))
import physics_data
class ActorGroup():
"""
Configure actor data exporting.
Attributes
----------
name:
Name for the group. This name will also be used as the name for the generated file.
selectedRootBone:
The root bone of the animation that will be exported.
rules: `list` of actor rules (derived from BaseRule)
modifiers to fine-tune the export process.
Methods
-------
to_dict()
Converts contents to a Python dictionary
add_rule(rule)
Adds a rule into the internal rules container
Returns True if the rule was added to the internal rules container
create_rule(rule)
Helper method to add and return the rule
remove_rule(type)
Removes the rule from the internal rules container
to_dict()
Converts the contents to as a Python dictionary
to_json()
Converts the contents to a JSON string
"""
def __init__(self):
self.typename = 'ActorGroup'
self.name = ''
self.selectedRootBone = ''
self.id = uuid.uuid4()
self.rules = set()
def add_rule(self, rule) -> bool:
if (rule not in self.rules):
self.rules.add(rule)
return True
return False
def create_rule(self, rule) -> any:
if (self.add_rule(rule)):
return rule
return None
def remove_rule(self, type) -> None:
self.rules.discard(rule)
def to_dict(self) -> dict:
out = {}
out['$type'] = self.typename
out['name'] = self.name
out['selectedRootBone'] = self.selectedRootBone
out['id'] = f"{{{str(self.id)}}}"
# convert the rules
ruleList = []
for rule in self.rules:
jsonStr = json.dumps(rule, cls=RuleEncoder)
jsonDict = json.loads(jsonStr)
ruleList.append(jsonDict)
out['rules'] = ruleList
return out
def to_json(self) -> any:
jsonDOM = self.to_dict()
return json.dumps(jsonDOM, cls=RuleEncoder, indent=1)
class RuleEncoder(json.JSONEncoder):
"""
A helper class to encode the Python classes with to a Python dictionary
Methods
-------
encode(obj)
Converts contents to a Python dictionary for the JSONEncoder
"""
def encode(self, obj):
chunk = obj
if isinstance(obj, BaseRule):
chunk = obj.to_dict()
elif isinstance(obj, dict):
chunk = obj
elif hasattr(obj, 'to_dict'):
chunk = obj.to_dict()
else:
chunk = obj.__dict__
return super().encode(chunk)
class BaseRule():
"""
Base class of the actor rules to help encode the type name of abstract rules
Parameters
----------
typename : str
A typename the $type will be in the JSON chunk object
Attributes
----------
typename: str
The type name of the abstract classes to be serialized
id: UUID
a unique ID for the rule
Methods
-------
to_dict()
Converts contents to a Python dictionary
Adds the '$type' member
Adds a random 'id' member
"""
def __init__(self, typename):
self.typename = typename
self.id = uuid.uuid4()
def __eq__(self, other):
return self.id.__eq__(other.id)
def __ne__(self, other):
return self.__eq__(other) is False
def __hash__(self):
return self.id.__hash__()
def to_dict(self):
data = self.__dict__
data['id'] = f"{{{str(self.id)}}}"
# rename 'typename' to '$type'
data['$type'] = self.typename
data.pop('typename')
return data
class SceneNodeSelectionList(BaseRule):
"""
Contains a list of node names to include (selectedNodes) and to exclude (unselectedNodes)
Attributes
----------
selectedNodes: `list` of str
The node names to include for this group rule
unselectedNodes: `list` of str
The node names to exclude for this group rule
Methods
-------
convert_selection(self, container, key):
this adds its contents to an existing dictionary container at a key position
select_targets(self, selectedList, allNodesList:list)
helper function to include a small list of node names from list of all the node names
to_dict()
Converts contents to a Python dictionary
"""
def __init__(self):
super().__init__('SceneNodeSelectionList')
self.selectedNodes = []
self.unselectedNodes = []
def convert_selection(self, container, key):
container[key] = self.to_dict()
def select_targets(self, selectedList, allNodesList:list):
self.selectedNodes = selectedList
self.unselectedNodes = allNodesList.copy()
for node in selectedList:
if node in self.unselectedNodes:
self.unselectedNodes.remove(node)
class LodNodeSelectionList(SceneNodeSelectionList):
"""
Level of Detail node selection list
The selected nodes should be joints with BoneData
derived from SceneNodeSelectionList
see also LodRule
Attributes
----------
lodLevel: int
the level of detail to target where 0 is nearest level of detail
up to 5 being the farthest level of detail range for 6 levels maximum
Methods
-------
to_dict()
Converts contents to a Python dictionary
"""
def __init__(self):
super().__init__()
self.typename = 'LodNodeSelectionList'
self.lodLevel = 0
def to_dict(self):
data = super().to_dict()
data['lodLevel'] = self.lodLevel
return data
class PhysicsAnimationConfiguration():
"""
Configuration for animated physics structures which are more detailed than the character controller.
For example, ragdoll or hit detection configurations.
See also 'class Physics::AnimationConfiguration'
Attributes
----------
hitDetectionConfig: CharacterColliderConfiguration
for hit detection
ragdollConfig: RagdollConfiguration
to set up physics properties
clothConfig: CharacterColliderConfiguration
for cloth physics
simulatedObjectColliderConfig: CharacterColliderConfiguration
for simulation physics
Methods
-------
to_dict()
Converts contents to a Python dictionary
"""
def __init__(self):
self.hitDetectionConfig = physics_data.CharacterColliderConfiguration()
self.ragdollConfig = physics_data.RagdollConfiguration()
self.clothConfig = physics_data.CharacterColliderConfiguration()
self.simulatedObjectColliderConfig = physics_data.CharacterColliderConfiguration()
def to_dict(self):
data = {}
data["hitDetectionConfig"] = self.hitDetectionConfig.to_dict()
data["ragdollConfig"] = self.ragdollConfig.to_dict()
data["clothConfig"] = self.clothConfig.to_dict()
data["simulatedObjectColliderConfig"] = self.simulatedObjectColliderConfig.to_dict()
return data
class EMotionFXPhysicsSetup():
"""
Physics setup properties
See also 'class EMotionFX::PhysicsSetup'
Attributes
----------
config: PhysicsAnimationConfiguration
Configuration to setup physics properties
Methods
-------
to_dict()
Converts contents to a Python dictionary
"""
def __init__(self):
self.typename = 'PhysicsSetup'
self.config = PhysicsAnimationConfiguration()
def to_dict(self):
return {
"config" : self.config.to_dict()
}
class ActorPhysicsSetupRule(BaseRule):
"""
Physics setup properties
Attributes
----------
data: EMotionFXPhysicsSetup
Data to setup physics properties
Methods
-------
set_hit_detection_config(self, hitDetectionConfig)
Simple helper function to assign the hit detection configuration
set_ragdoll_config(self, ragdollConfig)
Simple helper function to assign the ragdoll configuration
set_cloth_config(self, clothConfig)
Simple helper function to assign the cloth configuration
set_simulated_object_collider_config(self, simulatedObjectColliderConfig)
Simple helper function to assign the assign simulated object collider configuration
to_dict()
Converts contents to a Python dictionary
"""
def __init__(self):
super().__init__('ActorPhysicsSetupRule')
self.data = EMotionFXPhysicsSetup()
def set_hit_detection_config(self, hitDetectionConfig) -> None:
self.data.config.hitDetectionConfig = hitDetectionConfig
def set_ragdoll_config(self, ragdollConfig) -> None:
self.data.config.ragdollConfig = ragdollConfig
def set_cloth_config(self, clothConfig) -> None:
self.data.config.clothConfig = clothConfig
def set_simulated_object_collider_config(self, simulatedObjectColliderConfig) -> None:
self.data.config.simulatedObjectColliderConfig = simulatedObjectColliderConfig
def to_dict(self):
data = super().to_dict()
data["data"] = self.data.to_dict()
return data
class ActorScaleRule(BaseRule):
"""
Scale the actor
Attributes
----------
scaleFactor: float
Set the multiplier to scale geometry.
Methods
-------
to_dict()
Converts contents to a Python dictionary
"""
def __init__(self):
super().__init__('ActorScaleRule')
self.scaleFactor = 1.0
class CoordinateSystemRule(BaseRule):
"""
Modify the target coordinate system, applying a transformation to all data (transforms and vertex data if it exists).
Attributes
----------
targetCoordinateSystem: int
Change the direction the actor/motion will face by applying a post transformation to the data.
useAdvancedData: bool
If True, use advanced settings
originNodeName: str
Select a Node from the scene as the origin for this export.
rotation: [float, float, float, float]
Sets the orientation offset of the processed mesh in degrees. Rotates (yaw, pitch, roll) the group after translation.
translation: [float, float, float]
Moves the group along the given vector3.
scale: float
Sets the scale offset of the processed mesh.
Methods
-------
to_dict()
Converts contents to a Python dictionary
"""
def __init__(self):
super().__init__('CoordinateSystemRule')
self.targetCoordinateSystem = 0
self.useAdvancedData = False
self.originNodeName = ''
self.rotation = [0.0, 0.0, 0.0, 1.0]
self.translation = [0.0, 0.0, 0.0]
self.scale = 1.0
class SkeletonOptimizationRule(BaseRule):
"""
Advanced skeleton optimization rule.
Attributes
----------
autoSkeletonLOD: bool
Client side skeleton LOD based on skinning information and critical bones list.
serverSkeletonOptimization: bool
Server side skeleton optimization based on hit detections and critical bones list.
criticalBonesList: `list` of SceneNodeSelectionList
Bones in this list will not be optimized out.
Methods
-------
to_dict()
Converts contents to a Python dictionary
"""
def __init__(self):
super().__init__('SkeletonOptimizationRule')
self.autoSkeletonLOD = True
self.serverSkeletonOptimization = False
self.criticalBonesList = SceneNodeSelectionList()
def to_dict(self):
data = super().to_dict()
self.criticalBonesList.convert_selection(data, 'criticalBonesList')
return data
class LodRule(BaseRule):
"""
Set up the level of detail for the meshes in this group.
The engine supports 6 total lods.
1 for the base model then 5 more lods.
The rule only captures lods past level 0 so this is set to 5.
Attributes
----------
nodeSelectionList: `list` of LodNodeSelectionList
Select the meshes to assign to each level of detail.
Methods
-------
add_lod_level(lodLevel, selectedNodes=None, unselectedNodes=None)
A helper function to add selected nodes (list of node names) and unselected nodes (list of node names)
This creates a LodNodeSelectionList and adds it to the node selection list
returns the LodNodeSelectionList that was created
to_dict()
Converts contents to a Python dictionary
"""
def __init__(self):
super().__init__('{3CB103B3-CEAF-49D7-A9DC-5A31E2DF15E4} LodRule')
self.nodeSelectionList = [] # list of LodNodeSelectionList
def add_lod_level(self, lodLevel, selectedNodes=None, unselectedNodes=None) -> LodNodeSelectionList:
lodNodeSelection = LodNodeSelectionList()
lodNodeSelection.selectedNodes = selectedNodes
lodNodeSelection.unselectedNodes = unselectedNodes
lodNodeSelection.lodLevel = lodLevel
self.nodeSelectionList.append(lodNodeSelection)
return lodNodeSelection
def to_dict(self):
data = super().to_dict()
selectionListList = data.pop('nodeSelectionList')
data['nodeSelectionList'] = []
for nodeList in selectionListList:
data['nodeSelectionList'].append(nodeList.to_dict())
return data
class MorphTargetRule(BaseRule):
"""
Select morph targets for actor.
Attributes
----------
targets: `list` of SceneNodeSelectionList
Select 1 or more meshes to include in the actor as morph targets.
Methods
-------
to_dict()
Converts contents to a Python dictionary
"""
def __init__(self):
super().__init__('MorphTargetRule')
self.targets = SceneNodeSelectionList()
def to_dict(self):
data = super().to_dict()
self.targets.convert_selection(data, 'targets')
return data
class CommentRule(BaseRule):
"""
Add an optional comment to the asset's properties.
Attributes
----------
text: str
Text for the comment.
Methods
-------
to_dict()
Converts contents to a Python dictionary
"""
def __init__(self):
super().__init__('CommentRule')
self.text = ''
@@ -0,0 +1,580 @@
"""
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.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