Procedural Prefabs - Add mesh modifier support (#5894)

* Clean up error output

Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com>

* Add mesh modifiers to scene_data.py

Add example usage of modifiers to scene_mesh_to_prefab.py

Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com>

* Add type hints, cleanup dict creation, fix variable naming

Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com>

* Add documentation

Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com>

* Rename DefaultOrValue to __default_or_value

Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com>
monroegm-disable-blank-issue-2
amzn-mike 4 years ago committed by GitHub
parent b3bf02a4d5
commit b7f051fb9a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -5,7 +5,7 @@
# SPDX-License-Identifier: Apache-2.0 OR MIT
#
#
import os, traceback, binascii, sys, json, pathlib
import os, traceback, binascii, sys, json, pathlib, logging
import azlmbr.math
import azlmbr.bus
@ -15,9 +15,9 @@ import azlmbr.bus
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))
data = traceback.format_exc()
logger = logging.getLogger('python')
logger.error(data)
def get_mesh_node_names(sceneGraph):
import azlmbr.scene as sceneApi
@ -114,12 +114,18 @@ def update_manifest(scene):
mesh_group['id'] = '{' + str(uuid.uuid5(uuid.NAMESPACE_DNS, source_filename_only + mesh_path)) + '}'
# Set our current node as the only node that is included in this MeshGroup
scene_manifest.mesh_group_select_node(mesh_group, mesh_path)
scene_manifest.mesh_group_add_comment(mesh_group, "Hello World")
# Explicitly remove all other nodes to prevent implicit inclusions
for node in all_node_paths:
if node != mesh_path:
scene_manifest.mesh_group_unselect_node(mesh_group, node)
scene_manifest.mesh_group_add_cloth_rule(mesh_group, mesh_path, "Col0", 1, "Col0", 2, "Col0", 2, 3)
scene_manifest.mesh_group_add_advanced_mesh_rule(mesh_group, True, False, True, "Col0")
scene_manifest.mesh_group_add_skin_rule(mesh_group, 3, 0.002)
scene_manifest.mesh_group_add_tangent_rule(mesh_group, 1, 0)
# Create an editor entity
entity_id = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "CreateEditorReadyEntity", mesh_group_name)
# Add an EditorMeshComponent to the entity

@ -95,7 +95,7 @@ class SceneManifest():
def __init__(self):
self.manifest = {'values': []}
def add_mesh_group(self, name) -> dict:
def add_mesh_group(self, name: str) -> dict:
meshGroup = {}
meshGroup['$type'] = '{07B356B7-3635-40B5-878A-FAC4EFD5AD86} MeshGroup'
meshGroup['name'] = name
@ -104,7 +104,7 @@ class SceneManifest():
self.manifest['values'].append(meshGroup)
return meshGroup
def add_prefab_group(self, name, id, json) -> dict:
def add_prefab_group(self, name: str, id: str, json: dict) -> dict:
prefabGroup = {}
prefabGroup['$type'] = '{99FE3C6F-5B55-4D8B-8013-2708010EC715} PrefabGroup'
prefabGroup['name'] = name
@ -113,30 +113,164 @@ class SceneManifest():
self.manifest['values'].append(prefabGroup)
return prefabGroup
def mesh_group_select_node(self, meshGroup, nodeName):
meshGroup['nodeSelectionList']['selectedNodes'].append(nodeName)
def mesh_group_select_node(self, mesh_group: dict, node_name: str) -> None:
mesh_group['nodeSelectionList']['selectedNodes'].append(node_name)
def mesh_group_unselect_node(self, meshGroup, nodeName):
meshGroup['nodeSelectionList']['unselectedNodes'].append(nodeName)
def mesh_group_unselect_node(self, mesh_group: dict, node_name: str) -> None:
mesh_group['nodeSelectionList']['unselectedNodes'].append(node_name)
def mesh_group_add_advanced_coordinate_system(self, meshGroup, originNodeName, translation, rotation, scale):
originRule = {}
originRule['$type'] = 'CoordinateSystemRule'
originRule['useAdvancedData'] = True
originRule['originNodeName'] = '' if originNodeName is None else originNodeName
def mesh_group_add_advanced_coordinate_system(self, mesh_group: dict, origin_node_name: str, translation: object,
rotation: object, scale: float) -> None:
origin_rule = {
'$type': 'CoordinateSystemRule',
'useAdvancedData': True,
'originNodeName': '' if origin_node_name is None else origin_node_name
}
if translation is not None:
originRule['translation'] = translation
origin_rule['translation'] = translation
if rotation is not None:
originRule['rotation'] = rotation
origin_rule['rotation'] = rotation
if scale != 1.0:
originRule['scale'] = scale
meshGroup['rules']['rules'].append(originRule)
def mesh_group_add_comment(self, meshGroup, comment):
commentRule = {}
commentRule['$type'] = 'CommentRule'
commentRule['comment'] = comment
meshGroup['rules']['rules'].append(commentRule)
origin_rule['scale'] = scale
mesh_group['rules']['rules'].append(origin_rule)
def mesh_group_add_comment(self, mesh_group: dict, comment: str) -> None:
commentRule = {
'$type': 'CommentRule',
'comment': comment
}
mesh_group['rules']['rules'].append(commentRule)
def __default_or_value(self, val, default):
return default if val is None else val
def mesh_group_add_cloth_rule(self, mesh_group: dict, cloth_node_name: str,
inverse_masses_stream_name: str, inverse_masses_channel: int,
motion_constraints_stream_name: str, motion_constraints_channel: int,
backstop_stream_name: str, backstop_offset_channel: int,
backstop_radius_channel: int) -> None:
"""
Adds a Cloth rule. 0 = Red, 1 = Green, 2 = Blue, 3 = Alpha
:param mesh_group: Mesh Group to add the cloth rule to
:param cloth_node_name: Name of the node that the rule applies to
:param inverse_masses_stream_name: Name of the color stream to use for inverse masses
:param inverse_masses_channel: Color channel (index) for inverse masses
:param motion_constraints_stream_name: Name of the color stream to use for motion constraints
:param motion_constraints_channel: Color channel (index) for motion constraints
:param backstop_stream_name: Name of the color stream to use for backstop
:param backstop_offset_channel: Color channel (index) for backstop offset value
:param backstop_radius_channel: Color chnanel (index) for backstop radius value
"""
cloth_rule = {
'$type': 'ClothRule',
'meshNodeName': cloth_node_name,
'inverseMassesStreamName': self.__default_or_value(inverse_masses_stream_name, 'Default: 1.0')
}
if inverse_masses_channel is not None:
cloth_rule['inverseMassesChannel'] = inverse_masses_channel
cloth_rule['motionConstraintsStreamName'] = self.__default_or_value(motion_constraints_stream_name, 'Default: 1.0')
if motion_constraints_channel is not None:
cloth_rule['motionConstraintsChannel'] = motion_constraints_channel
cloth_rule['backstopStreamName'] = self.__default_or_value(backstop_stream_name, 'None')
if backstop_offset_channel is not None:
cloth_rule['backstopOffsetChannel'] = backstop_offset_channel
if backstop_radius_channel is not None:
cloth_rule['backstopRadiusChannel'] = backstop_radius_channel
mesh_group['rules']['rules'].append(cloth_rule)
def mesh_group_add_lod_rule(self, mesh_group: dict) -> dict:
"""
Adds an LOD rule
:param mesh_group: Mesh Group to add the rule to
:return: LOD rule
"""
lod_rule = {
'$type': '{6E796AC8-1484-4909-860A-6D3F22A7346F} LodRule',
'nodeSelectionList': []
}
mesh_group['rules']['rules'].append(lod_rule)
return lod_rule
def lod_rule_add_lod(self, lod_rule: dict) -> dict:
"""
Adds an LOD level to the LOD rule. Nodes are added in order. The first node added represents LOD1, 2nd LOD2, etc
:param lod_rule: LOD rule to add the LOD level to
:return: LOD level
"""
lod = {'selectedNodes': [], 'unselectedNodes': []}
lod_rule['nodeSelectionList'].append(lod)
return lod
def lod_select_node(self, lod: dict, selected_node: str) -> None:
"""
Adds a node as a selected node
:param lod: LOD level to add the node to
:param selected_node: Path of the node
"""
lod['selectedNodes'].append(selected_node)
def lod_unselect_node(self, lod: dict, unselected_node: str) -> None:
"""
Adds a node as an unselected node
:param lod: LOD rule to add the node to
:param unselected_node: Path of the node
"""
lod['unselectedNodes'].append(unselected_node)
def mesh_group_add_advanced_mesh_rule(self, mesh_group: dict, use_32bit_vertices: bool, merge_meshes: bool,
use_custom_normals: bool,
vertex_color_stream: str) -> None:
"""
Adds an Advanced Mesh rule
:param mesh_group: Mesh Group to add the rule to
:param use_32bit_vertices: False = 16bit vertex position precision. True = 32bit vertex position precision
:param merge_meshes: Merge all meshes into a single mesh
:param use_custom_normals: True = use normals from DCC tool. False = average normals
:param vertex_color_stream: Color stream name to use for Vertex Coloring
"""
rule = {
'$type': 'StaticMeshAdvancedRule',
'use32bitVertices': self.__default_or_value(use_32bit_vertices, False),
'mergeMeshes': self.__default_or_value(merge_meshes, True),
'useCustomNormals': self.__default_or_value(use_custom_normals, True)
}
if vertex_color_stream is not None:
rule['vertexColorStreamName'] = vertex_color_stream
mesh_group['rules']['rules'].append(rule)
def mesh_group_add_skin_rule(self, mesh_group: dict, max_weights_per_vertex: int, weight_threshold: float) -> None:
"""
Adds a Skin rule
:param mesh_group: Mesh Group to add the rule to
:param max_weights_per_vertex: Max number of joints that can influence a vertex
:param weight_threshold: Weight values below this value will be treated as 0
"""
rule = {
'$type': 'SkinRule',
'maxWeightsPerVertex': self.__default_or_value(max_weights_per_vertex, 4),
'weightThreshold': self.__default_or_value(weight_threshold, 0.001)
}
mesh_group['rules']['rules'].append(rule)
def mesh_group_add_tangent_rule(self, mesh_group: dict, tangent_space: int, tspace_method: int) -> None:
"""
Adds a Tangent rule to control tangent space generation
:param mesh_group: Mesh Group to add the rule to
:param tangent_space: Tangent space source. 0 = Scene, 1 = MikkT Tangent Generation
:param tspace_method: MikkT Generation method. 0 = TSpace, 1 = TSpaceBasic
"""
rule = {
'$type': 'TangentsRule',
'tangentSpace': self.__default_or_value(tangent_space, 1),
'tSpaceMethod': self.__default_or_value(tspace_method, 0)
}
mesh_group['rules']['rules'].append(rule)
def export(self):
return json.dumps(self.manifest)

Loading…
Cancel
Save