123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224 |
- #
- # 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 traceback, sys, uuid, os, json
- #
- # Example for exporting ActorGroup scene rules
- #
- def log_exception_traceback():
- exc_type, exc_value, exc_tb = sys.exc_info()
- data = traceback.format_exception(exc_type, exc_value, exc_tb)
- print(str(data))
- def get_node_names(sceneGraph, nodeTypeName, testEndPoint = False, validList = None):
- import azlmbr.scene.graph
- import scene_api.scene_data
- node = sceneGraph.get_root()
- nodeList = []
- children = []
- paths = []
- while node.IsValid():
- # store children to process after siblings
- if sceneGraph.has_node_child(node):
- children.append(sceneGraph.get_node_child(node))
- nodeName = scene_api.scene_data.SceneGraphName(sceneGraph.get_node_name(node))
- paths.append(nodeName.get_path())
-
- include = True
-
- if (validList is not None):
- include = False # if a valid list filter provided, assume to not include node name
- name_parts = nodeName.get_path().split('.')
- for valid in validList:
- if (valid in name_parts[-1]):
- include = True
- break
- # store any node that has provides specifc data content
- nodeContent = sceneGraph.get_node_content(node)
- if include and nodeContent.CastWithTypeName(nodeTypeName):
- if testEndPoint is not None:
- include = sceneGraph.is_node_end_point(node) is testEndPoint
- if include:
- if (len(nodeName.get_path())):
- nodeList.append(scene_api.scene_data.SceneGraphName(sceneGraph.get_node_name(node)))
- # advance to next node
- if sceneGraph.has_node_sibling(node):
- node = sceneGraph.get_node_sibling(node)
- elif children:
- node = children.pop()
- else:
- node = azlmbr.scene.graph.NodeIndex()
- return nodeList, paths
- def generate_mesh_group(scene, sceneManifest, meshDataList, paths):
- # Compute the name of the scene file
- clean_filename = scene.sourceFilename.replace('.', '_')
- mesh_group_name = os.path.basename(clean_filename)
- # make the mesh group
- mesh_group = sceneManifest.add_mesh_group(mesh_group_name)
- mesh_group['id'] = '{' + str(uuid.uuid5(uuid.NAMESPACE_DNS, clean_filename)) + '}'
- # add all nodes to this mesh group
- for activeMeshIndex in range(len(meshDataList)):
- mesh_name = meshDataList[activeMeshIndex]
- mesh_path = mesh_name.get_path()
- sceneManifest.mesh_group_select_node(mesh_group, mesh_path)
- def create_shape_configuration(nodeName):
- import scene_api.physics_data
-
- if(nodeName in ['_foot_','_wrist_']):
- shapeConfiguration = scene_api.physics_data.BoxShapeConfiguration()
- shapeConfiguration.scale = [1.1, 1.1, 1.1]
- shapeConfiguration.dimensions = [2.1, 3.1, 4.1]
- return shapeConfiguration
- else:
- shapeConfiguration = scene_api.physics_data.CapsuleShapeConfiguration()
- shapeConfiguration.scale = [1.0, 1.0, 1.0]
- shapeConfiguration.height = 1.0
- shapeConfiguration.radius = 1.0
- return shapeConfiguration
-
- def create_collider_configuration(nodeName):
- import scene_api.physics_data
-
- colliderConfiguration = scene_api.physics_data.ColliderConfiguration()
- colliderConfiguration.Position = [0.1, 0.1, 0.2]
- colliderConfiguration.Rotation = [45.0, 35.0, 25.0]
- return colliderConfiguration
- def generate_physics_nodes(actorPhysicsSetupRule, nodeNameList):
- import scene_api.physics_data
-
- hitDetectionConfig = scene_api.physics_data.CharacterColliderConfiguration()
- simulatedObjectColliderConfig = scene_api.physics_data.CharacterColliderConfiguration()
- clothConfig = scene_api.physics_data.CharacterColliderConfiguration()
- ragdollConfig = scene_api.physics_data.RagdollConfiguration()
-
- for nodeName in nodeNameList:
- shapeConfiguration = create_shape_configuration(nodeName)
- colliderConfiguration = create_collider_configuration(nodeName)
- hitDetectionConfig.add_character_collider_node_configuration_node(nodeName, colliderConfiguration, shapeConfiguration)
- simulatedObjectColliderConfig.add_character_collider_node_configuration_node(nodeName, colliderConfiguration, shapeConfiguration)
- clothConfig.add_character_collider_node_configuration_node(nodeName, colliderConfiguration, shapeConfiguration)
- #
- ragdollNode = scene_api.physics_data.RagdollNodeConfiguration()
- ragdollNode.JointConfig.Name = nodeName
- ragdollConfig.add_ragdoll_node_configuration(ragdollNode)
- ragdollConfig.colliders.add_character_collider_node_configuration_node(nodeName, colliderConfiguration, shapeConfiguration)
-
- actorPhysicsSetupRule.set_simulated_object_collider_config(simulatedObjectColliderConfig)
- actorPhysicsSetupRule.set_hit_detection_config(hitDetectionConfig)
- actorPhysicsSetupRule.set_cloth_config(clothConfig)
- actorPhysicsSetupRule.set_ragdoll_config(ragdollConfig)
- def generate_actor_group(scene, sceneManifest, meshDataList, paths):
- import scene_api.scene_data
- import scene_api.physics_data
- import scene_api.actor_group
-
- # fetch bone data
- validNames = ['_neck_','_pelvis_','_leg_','_knee_','_spine_','_arm_','_clavicle_','_head_','_elbow_','_wrist_']
- graph = scene_api.scene_data.SceneGraph(scene.graph)
- nodeList, allNodePaths = get_node_names(graph, 'BoneData', validList = validNames)
- nodeNameList = []
- for activeMeshIndex, nodeName in enumerate(nodeList):
- nodeNameList.append(nodeName.get_name())
- # add comment
- commentRule = scene_api.actor_group.CommentRule()
- commentRule.text = str(nodeNameList)
-
- # ActorPhysicsSetupRule
- actorPhysicsSetupRule = scene_api.actor_group.ActorPhysicsSetupRule()
- generate_physics_nodes(actorPhysicsSetupRule, nodeNameList)
-
- # add scale of the Actor rule
- actorScaleRule = scene_api.actor_group.ActorScaleRule()
- actorScaleRule.scaleFactor = 2.0
-
- # add coordinate system rule
- coordinateSystemRule = scene_api.actor_group.CoordinateSystemRule()
- coordinateSystemRule.useAdvancedData = False
-
- # add morph target rule
- morphTargetRule = scene_api.actor_group.MorphTargetRule()
- morphTargetRule.targets.select_targets([nodeNameList[0]], nodeNameList)
-
- # add skeleton optimization rule
- skeletonOptimizationRule = scene_api.actor_group.SkeletonOptimizationRule()
- skeletonOptimizationRule.autoSkeletonLOD = True
- skeletonOptimizationRule.criticalBonesList.select_targets([nodeNameList[0:2]], nodeNameList)
-
- # add LOD rule
- lodRule = scene_api.actor_group.LodRule()
- lodRule0 = lodRule.add_lod_level(0)
- lodRule0.select_targets([nodeNameList[1:4]], nodeNameList)
- actorGroup = scene_api.actor_group.ActorGroup()
- actorGroup.name = os.path.basename(scene.sourceFilename)
- actorGroup.add_rule(actorScaleRule)
- actorGroup.add_rule(coordinateSystemRule)
- actorGroup.add_rule(skeletonOptimizationRule)
- actorGroup.add_rule(morphTargetRule)
- actorGroup.add_rule(lodRule)
- actorGroup.add_rule(actorPhysicsSetupRule)
- actorGroup.add_rule(commentRule)
- sceneManifest.manifest['values'].append(actorGroup.to_dict())
-
- def update_manifest(scene):
- import json, uuid, os
- import azlmbr.scene.graph
- import scene_api.scene_data
- graph = scene_api.scene_data.SceneGraph(scene.graph)
- mesh_name_list, all_node_paths = get_node_names(graph, 'MeshData')
- scene_manifest = scene_api.scene_data.SceneManifest()
- generate_actor_group(scene, scene_manifest, mesh_name_list, all_node_paths)
- generate_mesh_group(scene, scene_manifest, mesh_name_list, all_node_paths)
- # Convert the manifest to a JSON string and return it
- return scene_manifest.export()
- sceneJobHandler = None
- def on_update_manifest(args):
- try:
- scene = args[0]
- return update_manifest(scene)
- except RuntimeError as err:
- print (f'ERROR - {err}')
- log_exception_traceback()
- except:
- log_exception_traceback()
- finally:
- global sceneJobHandler
- # do not delete or set sceneJobHandler to None, just disconnect from it.
- # this call is occuring while the scene Job Handler itself is in the callstack, so deleting it here
- # would cause a crash.
- sceneJobHandler.disconnect()
- # try to create SceneAPI handler for processing
- try:
- import azlmbr.scene
- sceneJobHandler = azlmbr.scene.ScriptBuildingNotificationBusHandler()
- sceneJobHandler.connect()
- sceneJobHandler.add_callback('OnUpdateManifest', on_update_manifest)
- except:
- sceneJobHandler = None
|