You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
222 lines
8.6 KiB
Python
222 lines
8.6 KiB
Python
#
|
|
# 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()
|
|
|
|
global sceneJobHandler
|
|
sceneJobHandler.disconnect()
|
|
sceneJobHandler = None
|
|
|
|
# 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
|