actor_group.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  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. import json
  9. import uuid
  10. import os, sys
  11. import scene_api.physics_data
  12. from scene_api.common_rules import RuleEncoder, BaseRule, SceneNodeSelectionList, CommentRule, CoordinateSystemRule
  13. class ActorGroup():
  14. """
  15. Configure actor data exporting.
  16. Attributes
  17. ----------
  18. name:
  19. Name for the group. This name will also be used as the name for the generated file.
  20. selectedRootBone:
  21. The root bone of the animation that will be exported.
  22. rules: `list` of actor rules (derived from BaseRule)
  23. modifiers to fine-tune the export process.
  24. Methods
  25. -------
  26. to_dict()
  27. Converts contents to a Python dictionary
  28. add_rule(rule)
  29. Adds a rule into the internal rules container
  30. Returns True if the rule was added to the internal rules container
  31. create_rule(rule)
  32. Helper method to add and return the rule
  33. remove_rule(type)
  34. Removes the rule from the internal rules container
  35. to_dict()
  36. Converts the contents to as a Python dictionary
  37. to_json()
  38. Converts the contents to a JSON string
  39. """
  40. def __init__(self):
  41. self.typename = 'ActorGroup'
  42. self.name = ''
  43. self.selectedRootBone = ''
  44. self.id = uuid.uuid4()
  45. self.rules = set()
  46. def add_rule(self, rule) -> bool:
  47. if (rule not in self.rules):
  48. self.rules.add(rule)
  49. return True
  50. return False
  51. def create_rule(self, rule) -> any:
  52. if (self.add_rule(rule)):
  53. return rule
  54. return None
  55. def remove_rule(self, type) -> None:
  56. self.rules.discard(rule)
  57. def to_dict(self) -> dict:
  58. out = {}
  59. out['$type'] = self.typename
  60. out['name'] = self.name
  61. out['selectedRootBone'] = self.selectedRootBone
  62. out['id'] = f"{{{str(self.id)}}}"
  63. # convert the rules
  64. ruleList = []
  65. for rule in self.rules:
  66. jsonStr = json.dumps(rule, cls=RuleEncoder)
  67. jsonDict = json.loads(jsonStr)
  68. ruleList.append(jsonDict)
  69. out['rules'] = ruleList
  70. return out
  71. def to_json(self, i = 0) -> any:
  72. jsonDOM = self.to_dict()
  73. return json.dumps(jsonDOM, cls=RuleEncoder, indent=i)
  74. class LodNodeSelectionList(SceneNodeSelectionList):
  75. """
  76. Level of Detail node selection list
  77. The selected nodes should be joints with BoneData
  78. derived from SceneNodeSelectionList
  79. see also LodRule
  80. Attributes
  81. ----------
  82. lodLevel: int
  83. the level of detail to target where 0 is nearest level of detail
  84. up to 5 being the farthest level of detail range for 6 levels maximum
  85. Methods
  86. -------
  87. to_dict()
  88. Converts contents to a Python dictionary
  89. """
  90. def __init__(self):
  91. super().__init__()
  92. self.typename = 'LodNodeSelectionList'
  93. self.lodLevel = 0
  94. def to_dict(self):
  95. data = super().to_dict()
  96. data['lodLevel'] = self.lodLevel
  97. return data
  98. class PhysicsAnimationConfiguration():
  99. """
  100. Configuration for animated physics structures which are more detailed than the character controller.
  101. For example, ragdoll or hit detection configurations.
  102. See also 'class Physics::AnimationConfiguration'
  103. Attributes
  104. ----------
  105. hitDetectionConfig: CharacterColliderConfiguration
  106. for hit detection
  107. ragdollConfig: RagdollConfiguration
  108. to set up physics properties
  109. clothConfig: CharacterColliderConfiguration
  110. for cloth physics
  111. simulatedObjectColliderConfig: CharacterColliderConfiguration
  112. for simulation physics
  113. Methods
  114. -------
  115. to_dict()
  116. Converts contents to a Python dictionary
  117. """
  118. def __init__(self):
  119. self.hitDetectionConfig = scene_api.physics_data.CharacterColliderConfiguration()
  120. self.ragdollConfig = scene_api.physics_data.RagdollConfiguration()
  121. self.clothConfig = scene_api.physics_data.CharacterColliderConfiguration()
  122. self.simulatedObjectColliderConfig = scene_api.physics_data.CharacterColliderConfiguration()
  123. def to_dict(self):
  124. data = {}
  125. data["hitDetectionConfig"] = self.hitDetectionConfig.to_dict()
  126. data["ragdollConfig"] = self.ragdollConfig.to_dict()
  127. data["clothConfig"] = self.clothConfig.to_dict()
  128. data["simulatedObjectColliderConfig"] = self.simulatedObjectColliderConfig.to_dict()
  129. return data
  130. class EMotionFXPhysicsSetup():
  131. """
  132. Physics setup properties
  133. See also 'class EMotionFX::PhysicsSetup'
  134. Attributes
  135. ----------
  136. config: PhysicsAnimationConfiguration
  137. Configuration to setup physics properties
  138. Methods
  139. -------
  140. to_dict()
  141. Converts contents to a Python dictionary
  142. """
  143. def __init__(self):
  144. self.typename = 'PhysicsSetup'
  145. self.config = PhysicsAnimationConfiguration()
  146. def to_dict(self):
  147. return {
  148. "config" : self.config.to_dict()
  149. }
  150. class ActorPhysicsSetupRule(BaseRule):
  151. """
  152. Physics setup properties
  153. Attributes
  154. ----------
  155. data: EMotionFXPhysicsSetup
  156. Data to setup physics properties
  157. Methods
  158. -------
  159. set_hit_detection_config(self, hitDetectionConfig)
  160. Simple helper function to assign the hit detection configuration
  161. set_ragdoll_config(self, ragdollConfig)
  162. Simple helper function to assign the ragdoll configuration
  163. set_cloth_config(self, clothConfig)
  164. Simple helper function to assign the cloth configuration
  165. set_simulated_object_collider_config(self, simulatedObjectColliderConfig)
  166. Simple helper function to assign the assign simulated object collider configuration
  167. to_dict()
  168. Converts contents to a Python dictionary
  169. """
  170. def __init__(self):
  171. super().__init__('ActorPhysicsSetupRule')
  172. self.data = EMotionFXPhysicsSetup()
  173. def set_hit_detection_config(self, hitDetectionConfig) -> None:
  174. self.data.config.hitDetectionConfig = hitDetectionConfig
  175. def set_ragdoll_config(self, ragdollConfig) -> None:
  176. self.data.config.ragdollConfig = ragdollConfig
  177. def set_cloth_config(self, clothConfig) -> None:
  178. self.data.config.clothConfig = clothConfig
  179. def set_simulated_object_collider_config(self, simulatedObjectColliderConfig) -> None:
  180. self.data.config.simulatedObjectColliderConfig = simulatedObjectColliderConfig
  181. def to_dict(self):
  182. data = super().to_dict()
  183. data["data"] = self.data.to_dict()
  184. return data
  185. class ActorScaleRule(BaseRule):
  186. """
  187. Scale the actor
  188. Attributes
  189. ----------
  190. scaleFactor: float
  191. Set the multiplier to scale geometry.
  192. Methods
  193. -------
  194. to_dict()
  195. Converts contents to a Python dictionary
  196. """
  197. def __init__(self):
  198. super().__init__('ActorScaleRule')
  199. self.scaleFactor = 1.0
  200. class SkeletonOptimizationRule(BaseRule):
  201. """
  202. Advanced skeleton optimization rule.
  203. Attributes
  204. ----------
  205. autoSkeletonLOD: bool
  206. Client side skeleton LOD based on skinning information and critical bones list.
  207. serverSkeletonOptimization: bool
  208. Server side skeleton optimization based on hit detections and critical bones list.
  209. criticalBonesList: `list` of SceneNodeSelectionList
  210. Bones in this list will not be optimized out.
  211. Methods
  212. -------
  213. to_dict()
  214. Converts contents to a Python dictionary
  215. """
  216. def __init__(self):
  217. super().__init__('SkeletonOptimizationRule')
  218. self.autoSkeletonLOD = True
  219. self.serverSkeletonOptimization = False
  220. self.criticalBonesList = SceneNodeSelectionList()
  221. def to_dict(self):
  222. data = super().to_dict()
  223. self.criticalBonesList.convert_selection(data, 'criticalBonesList')
  224. return data
  225. class LodRule(BaseRule):
  226. """
  227. Set up the level of detail for the meshes in this group.
  228. The engine supports 6 total lods.
  229. 1 for the base model then 5 more lods.
  230. The rule only captures lods past level 0 so this is set to 5.
  231. Attributes
  232. ----------
  233. nodeSelectionList: `list` of LodNodeSelectionList
  234. Select the meshes to assign to each level of detail.
  235. Methods
  236. -------
  237. add_lod_level(lodLevel, selectedNodes=None, unselectedNodes=None)
  238. A helper function to add selected nodes (list of node names) and unselected nodes (list of node names)
  239. This creates a LodNodeSelectionList and adds it to the node selection list
  240. returns the LodNodeSelectionList that was created
  241. to_dict()
  242. Converts contents to a Python dictionary
  243. """
  244. def __init__(self):
  245. super().__init__('{3CB103B3-CEAF-49D7-A9DC-5A31E2DF15E4} LodRule')
  246. self.nodeSelectionList = [] # list of LodNodeSelectionList
  247. def add_lod_level(self, lodLevel, selectedNodes=None, unselectedNodes=None) -> LodNodeSelectionList:
  248. lodNodeSelection = LodNodeSelectionList()
  249. lodNodeSelection.selectedNodes = selectedNodes
  250. lodNodeSelection.unselectedNodes = unselectedNodes
  251. lodNodeSelection.lodLevel = lodLevel
  252. self.nodeSelectionList.append(lodNodeSelection)
  253. return lodNodeSelection
  254. def to_dict(self):
  255. data = super().to_dict()
  256. selectionListList = data.pop('nodeSelectionList')
  257. data['nodeSelectionList'] = []
  258. for nodeList in selectionListList:
  259. data['nodeSelectionList'].append(nodeList.to_dict())
  260. return data
  261. class MorphTargetRule(BaseRule):
  262. """
  263. Select morph targets for actor.
  264. Attributes
  265. ----------
  266. targets: `list` of SceneNodeSelectionList
  267. Select 1 or more meshes to include in the actor as morph targets.
  268. Methods
  269. -------
  270. to_dict()
  271. Converts contents to a Python dictionary
  272. """
  273. def __init__(self):
  274. super().__init__('MorphTargetRule')
  275. self.targets = SceneNodeSelectionList()
  276. def to_dict(self):
  277. data = super().to_dict()
  278. self.targets.convert_selection(data, 'targets')
  279. return data