Procedural Prefabs: Python documentation cleanup (#6136)
* Auto LOD script setup Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Working auto LODs Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Correctly selected LODs and added default prefab Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Cleanup code Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Cleanup code Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Add missing legal header, move name cleanup to scene_helpers, add documentation Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Add PhysX mesh group support. Updated example script to show usage Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Add a physics collider component Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Update DefaultOrValue call Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Document remaining methods in scene_data.py Add enums where appropriate Add type hints and default values Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Remove unused import Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Convert docstring to numpy style Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Fix return types Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Remove empty returns Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Add docs on enums Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com>
This commit is contained in:
@@ -14,30 +14,44 @@ from scene_api.scene_data import SceneGraphName
|
||||
|
||||
|
||||
def log_exception_traceback():
|
||||
"""
|
||||
Outputs an exception stacktrace.
|
||||
"""
|
||||
"""Outputs an exception stacktrace."""
|
||||
data = traceback.format_exc()
|
||||
logger = logging.getLogger('python')
|
||||
logger.error(data)
|
||||
|
||||
|
||||
def sanitize_name_for_disk(name: str):
|
||||
"""
|
||||
Removes illegal filename characters from a string.
|
||||
def sanitize_name_for_disk(name: str) -> str:
|
||||
"""Removes illegal filename characters from a string.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name :
|
||||
String to clean.
|
||||
|
||||
|
||||
Returns
|
||||
-------
|
||||
str
|
||||
Name with illegal characters removed.
|
||||
|
||||
:param name: String to clean.
|
||||
:return: Name with illegal characters removed.
|
||||
"""
|
||||
return "".join(char for char in name if char not in "|<>:\"/?*\\")
|
||||
|
||||
|
||||
def get_mesh_node_names(scene_graph: sceneData.SceneGraph) -> Tuple[List[SceneGraphName], List[str]]:
|
||||
"""
|
||||
Returns a tuple of all the mesh nodes as well as all the node paths
|
||||
"""Returns a tuple of all the mesh nodes as well as all the node paths
|
||||
|
||||
Parameters
|
||||
----------
|
||||
scene_graph :
|
||||
Scene graph to search
|
||||
|
||||
|
||||
Returns
|
||||
-------
|
||||
Tuple[List[SceneGraphName], List[str]]
|
||||
Tuple of [Mesh Nodes, All Node Paths]
|
||||
|
||||
:param scene_graph: Scene graph to search
|
||||
:return: Tuple of [Mesh Nodes, All Node Paths]
|
||||
"""
|
||||
import azlmbr.scene as sceneApi
|
||||
import azlmbr.scene.graph
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
import azlmbr.bus
|
||||
import azlmbr.math
|
||||
|
||||
from scene_api.scene_data import PrimitiveShape, DecompositionMode
|
||||
from scene_api.scene_data import PrimitiveShape, DecompositionMode, ColorChannel, TangentSpaceSource, TangentSpaceMethod
|
||||
from scene_helpers import *
|
||||
|
||||
|
||||
@@ -71,6 +71,7 @@ def add_physx_meshes(scene_manifest: sceneData.SceneManifest, source_file_name:
|
||||
triangle = scene_manifest.add_physx_triangle_mesh_group(source_file_name + "_triangle", False, True, True, True, True, True)
|
||||
scene_manifest.physx_mesh_group_add_selected_unselected_nodes(triangle, [first_mesh], all_except_first_mesh)
|
||||
|
||||
|
||||
def update_manifest(scene):
|
||||
import uuid, os
|
||||
import azlmbr.scene.graph
|
||||
@@ -114,10 +115,11 @@ def update_manifest(scene):
|
||||
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_cloth_rule(mesh_group, mesh_path, "Col0", ColorChannel.GREEN, "Col0",
|
||||
ColorChannel.BLUE, "Col0", ColorChannel.BLUE, ColorChannel.ALPHA)
|
||||
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)
|
||||
scene_manifest.mesh_group_add_tangent_rule(mesh_group, TangentSpaceSource.MIKKT_GENERATION, TangentSpaceMethod.TSPACE_BASIC)
|
||||
|
||||
# Create an editor entity
|
||||
entity_id = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "CreateEditorReadyEntity", mesh_group_name)
|
||||
|
||||
@@ -7,13 +7,13 @@ SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
import typing
|
||||
import json
|
||||
import azlmbr.scene as sceneApi
|
||||
from enum import Enum, IntEnum
|
||||
from enum import IntEnum
|
||||
|
||||
|
||||
# Wraps the AZ.SceneAPI.Containers.SceneGraph.NodeIndex internal class
|
||||
class SceneGraphNodeIndex:
|
||||
def __init__(self, sceneGraphNodeIndex) -> None:
|
||||
self.nodeIndex = sceneGraphNodeIndex
|
||||
def __init__(self, scene_graph_node_index) -> None:
|
||||
self.nodeIndex = scene_graph_node_index
|
||||
|
||||
def as_number(self):
|
||||
return self.nodeIndex.AsNumber()
|
||||
@@ -29,9 +29,9 @@ class SceneGraphNodeIndex:
|
||||
|
||||
|
||||
# Wraps AZ.SceneAPI.Containers.SceneGraph.Name internal class
|
||||
class SceneGraphName():
|
||||
def __init__(self, sceneGraphName) -> None:
|
||||
self.name = sceneGraphName
|
||||
class SceneGraphName:
|
||||
def __init__(self, scene_graph_name) -> None:
|
||||
self.name = scene_graph_name
|
||||
|
||||
def get_path(self) -> str:
|
||||
return self.name.GetPath()
|
||||
@@ -41,9 +41,9 @@ class SceneGraphName():
|
||||
|
||||
|
||||
# Wraps AZ.SceneAPI.Containers.SceneGraph class
|
||||
class SceneGraph():
|
||||
def __init__(self, sceneGraphInstance) -> None:
|
||||
self.sceneGraph = sceneGraphInstance
|
||||
class SceneGraph:
|
||||
def __init__(self, scene_graph_instance) -> None:
|
||||
self.sceneGraph = scene_graph_instance
|
||||
|
||||
@classmethod
|
||||
def is_valid_name(cls, name):
|
||||
@@ -96,53 +96,161 @@ class SceneGraph():
|
||||
return self.sceneGraph.GetNodeContent(node)
|
||||
|
||||
|
||||
class ColorChannel(IntEnum):
|
||||
RED = 0
|
||||
""" Red color channel """
|
||||
GREEN = 1
|
||||
""" Green color channel """
|
||||
BLUE = 2
|
||||
""" Blue color channel """
|
||||
ALPHA = 3
|
||||
""" Alpha color channel """
|
||||
|
||||
|
||||
class TangentSpaceSource(IntEnum):
|
||||
SCENE = 0
|
||||
""" Extract the tangents and bitangents directly from the source scene file. """
|
||||
MIKKT_GENERATION = 1
|
||||
""" Use MikkT algorithm to generate tangents """
|
||||
|
||||
|
||||
class TangentSpaceMethod(IntEnum):
|
||||
TSPACE = 0
|
||||
""" Generates the tangents and bitangents with their true magnitudes which can be used for relief mapping effects.
|
||||
It calculates the 'real' bitangent which may not be perpendicular to the tangent.
|
||||
However, both, the tangent and bitangent are perpendicular to the vertex normal.
|
||||
"""
|
||||
TSPACE_BASIC = 1
|
||||
""" Calculates unit vector tangents and bitangents at pixel/vertex level which are sufficient for basic normal mapping. """
|
||||
|
||||
|
||||
class PrimitiveShape(IntEnum):
|
||||
BEST_FIT = 0
|
||||
""" The algorithm will determine which of the shapes fits best. """
|
||||
SPHERE = 1
|
||||
""" Sphere shape """
|
||||
BOX = 2
|
||||
""" Box shape """
|
||||
CAPSULE = 3
|
||||
""" Capsule shape """
|
||||
|
||||
|
||||
class DecompositionMode(IntEnum):
|
||||
VOXEL = 0
|
||||
""" Voxel-based approximate convex decomposition """
|
||||
TETRAHEDRON = 1
|
||||
""" Tetrahedron-based approximate convex decomposition """
|
||||
|
||||
|
||||
# Contains a dictionary to contain and export AZ.SceneAPI.Containers.SceneManifest
|
||||
class SceneManifest():
|
||||
class SceneManifest:
|
||||
def __init__(self):
|
||||
self.manifest = {'values': []}
|
||||
|
||||
def add_mesh_group(self, name: str) -> dict:
|
||||
meshGroup = {}
|
||||
meshGroup['$type'] = '{07B356B7-3635-40B5-878A-FAC4EFD5AD86} MeshGroup'
|
||||
meshGroup['name'] = name
|
||||
meshGroup['nodeSelectionList'] = {'selectedNodes': [], 'unselectedNodes': []}
|
||||
meshGroup['rules'] = {'rules': [{'$type': 'MaterialRule'}]}
|
||||
self.manifest['values'].append(meshGroup)
|
||||
return meshGroup
|
||||
"""Adds a Mesh Group to the scene manifest.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name :
|
||||
Name of the mesh group. This will become a file on disk and be usable as a Mesh in the editor.
|
||||
|
||||
|
||||
Returns
|
||||
-------
|
||||
dict
|
||||
Newly created mesh group.
|
||||
|
||||
"""
|
||||
mesh_group = {
|
||||
'$type': '{07B356B7-3635-40B5-878A-FAC4EFD5AD86} MeshGroup',
|
||||
'name': name,
|
||||
'nodeSelectionList': {'selectedNodes': [], 'unselectedNodes': []},
|
||||
'rules': {'rules': [{'$type': 'MaterialRule'}]}
|
||||
}
|
||||
self.manifest['values'].append(mesh_group)
|
||||
return mesh_group
|
||||
|
||||
def add_prefab_group(self, name: str, id: str, json: dict) -> dict:
|
||||
prefabGroup = {}
|
||||
prefabGroup['$type'] = '{99FE3C6F-5B55-4D8B-8013-2708010EC715} PrefabGroup'
|
||||
prefabGroup['name'] = name
|
||||
prefabGroup['id'] = id
|
||||
prefabGroup['prefabDomData'] = json
|
||||
self.manifest['values'].append(prefabGroup)
|
||||
return prefabGroup
|
||||
"""Adds a Prefab Group to the scene manifest. This will become a file on disk and be usable as a ProceduralPrefab in the editor.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name :
|
||||
Name of the prefab.
|
||||
id :
|
||||
Unique ID for this prefab group.
|
||||
json :
|
||||
The prefab template data.
|
||||
|
||||
|
||||
Returns
|
||||
-------
|
||||
dict
|
||||
The newly created Prefab group
|
||||
|
||||
"""
|
||||
prefab_group = {
|
||||
'$type': '{99FE3C6F-5B55-4D8B-8013-2708010EC715} PrefabGroup',
|
||||
'name': name,
|
||||
'id': id,
|
||||
'prefabDomData': json
|
||||
}
|
||||
self.manifest['values'].append(prefab_group)
|
||||
return prefab_group
|
||||
|
||||
def mesh_group_select_node(self, mesh_group: dict, node_name: str) -> None:
|
||||
"""Adds a node as a selected node.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
mesh_group :
|
||||
Mesh group to apply the selection to.
|
||||
node_name :
|
||||
Path of the node.
|
||||
|
||||
"""
|
||||
mesh_group['nodeSelectionList']['selectedNodes'].append(node_name)
|
||||
|
||||
def mesh_group_unselect_node(self, mesh_group: dict, node_name: str) -> None:
|
||||
"""Adds a node as an unselected node.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
mesh_group :
|
||||
Mesh group to apply the selection to.
|
||||
node_name :
|
||||
Path of the node.
|
||||
|
||||
"""
|
||||
mesh_group['nodeSelectionList']['unselectedNodes'].append(node_name)
|
||||
|
||||
def mesh_group_add_advanced_coordinate_system(self, mesh_group: dict, origin_node_name: str, translation: object,
|
||||
rotation: object, scale: float) -> None:
|
||||
def mesh_group_add_advanced_coordinate_system(self, mesh_group: dict,
|
||||
origin_node_name: str = '',
|
||||
translation: typing.Optional[object] = None,
|
||||
rotation: typing.Optional[object] = None,
|
||||
scale: float = 1.0) -> None:
|
||||
"""Adds an Advanced Coordinate System rule which modifies the target coordinate system,
|
||||
applying a transformation to all data (transforms and vertex data if it exists).
|
||||
|
||||
Parameters
|
||||
----------
|
||||
mesh_group :
|
||||
Mesh group to add the Advanced Coordinate System rule to.
|
||||
origin_node_name :
|
||||
Path of the node to use as the origin.
|
||||
translation :
|
||||
Moves the group along the given vector.
|
||||
rotation :
|
||||
Sets the orientation offset of the processed mesh in degrees. Rotates the group after translation.
|
||||
scale :
|
||||
Sets the scale offset of the processed mesh.
|
||||
|
||||
"""
|
||||
origin_rule = {
|
||||
'$type': 'CoordinateSystemRule',
|
||||
'useAdvancedData': True,
|
||||
'originNodeName': '' if origin_node_name is None else origin_node_name
|
||||
'originNodeName': self.__default_or_value(origin_node_name, '')
|
||||
}
|
||||
if translation is not None:
|
||||
origin_rule['translation'] = translation
|
||||
@@ -153,31 +261,57 @@ class SceneManifest():
|
||||
mesh_group['rules']['rules'].append(origin_rule)
|
||||
|
||||
def mesh_group_add_comment(self, mesh_group: dict, comment: str) -> None:
|
||||
commentRule = {
|
||||
"""Adds a Comment rule.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
mesh_group :
|
||||
Mesh group to add the comment rule to.
|
||||
comment :
|
||||
Text for the comment rule.
|
||||
|
||||
"""
|
||||
comment_rule = {
|
||||
'$type': 'CommentRule',
|
||||
'comment': comment
|
||||
}
|
||||
mesh_group['rules']['rules'].append(commentRule)
|
||||
mesh_group['rules']['rules'].append(comment_rule)
|
||||
|
||||
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
|
||||
def mesh_group_add_cloth_rule(self, mesh_group: dict,
|
||||
cloth_node_name: str,
|
||||
inverse_masses_stream_name: typing.Optional[str],
|
||||
inverse_masses_channel: typing.Optional[ColorChannel],
|
||||
motion_constraints_stream_name: typing.Optional[str],
|
||||
motion_constraints_channel: typing.Optional[ColorChannel],
|
||||
backstop_stream_name: typing.Optional[str],
|
||||
backstop_offset_channel: typing.Optional[ColorChannel],
|
||||
backstop_radius_channel: typing.Optional[ColorChannel]) -> None:
|
||||
"""Adds a Cloth rule.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
mesh_group :
|
||||
Mesh Group to add the cloth rule to
|
||||
cloth_node_name :
|
||||
Name of the node that the rule applies to
|
||||
inverse_masses_stream_name :
|
||||
Name of the color stream to use for inverse masses
|
||||
inverse_masses_channel :
|
||||
Color channel (index) for inverse masses
|
||||
motion_constraints_stream_name :
|
||||
Name of the color stream to use for motion constraints
|
||||
motion_constraints_channel :
|
||||
Color channel (index) for motion constraints
|
||||
backstop_stream_name :
|
||||
Name of the color stream to use for backstop
|
||||
backstop_offset_channel :
|
||||
Color channel (index) for backstop offset value
|
||||
backstop_radius_channel :
|
||||
Color channel (index) for backstop radius value
|
||||
|
||||
"""
|
||||
cloth_rule = {
|
||||
'$type': 'ClothRule',
|
||||
@@ -186,22 +320,31 @@ class SceneManifest():
|
||||
}
|
||||
|
||||
if inverse_masses_channel is not None:
|
||||
cloth_rule['inverseMassesChannel'] = inverse_masses_channel
|
||||
cloth_rule['inverseMassesChannel'] = int(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['motionConstraintsChannel'] = int(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
|
||||
cloth_rule['backstopOffsetChannel'] = int(backstop_offset_channel)
|
||||
if backstop_radius_channel is not None:
|
||||
cloth_rule['backstopRadiusChannel'] = backstop_radius_channel
|
||||
cloth_rule['backstopRadiusChannel'] = int(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
|
||||
"""Adds an LOD rule.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
mesh_group :
|
||||
Mesh Group to add the rule to.
|
||||
|
||||
|
||||
Returns
|
||||
-------
|
||||
dict
|
||||
LOD rule.
|
||||
|
||||
"""
|
||||
lod_rule = {
|
||||
'$type': '{6E796AC8-1484-4909-860A-6D3F22A7346F} LodRule',
|
||||
@@ -212,47 +355,76 @@ class SceneManifest():
|
||||
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
|
||||
"""Adds an LOD level to the LOD rule. Nodes are added in order. The first node added represents LOD1, 2nd LOD2, etc.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
lod_rule :
|
||||
LOD rule to add the LOD level to.
|
||||
|
||||
|
||||
Returns
|
||||
-------
|
||||
dict
|
||||
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
|
||||
"""Adds a node as a selected node.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
lod :
|
||||
LOD level to add the node to.
|
||||
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
|
||||
"""Adds a node as an unselected node.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
lod :
|
||||
LOD rule to add the node to.
|
||||
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
|
||||
def mesh_group_add_advanced_mesh_rule(self, mesh_group: dict,
|
||||
use_32bit_vertices: bool = False,
|
||||
merge_meshes: bool = True,
|
||||
use_custom_normals: bool = True,
|
||||
vertex_color_stream: typing.Optional[str] = None) -> None:
|
||||
"""Adds an Advanced Mesh rule.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
mesh_group :
|
||||
Mesh Group to add the rule to.
|
||||
use_32bit_vertices :
|
||||
False = 16bit vertex position precision. True = 32bit vertex position precision.
|
||||
merge_meshes :
|
||||
Merge all meshes into a single mesh.
|
||||
use_custom_normals :
|
||||
True = use normals from DCC tool. False = average normals.
|
||||
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)
|
||||
'use32bitVertices': use_32bit_vertices,
|
||||
'mergeMeshes': merge_meshes,
|
||||
'useCustomNormals': use_custom_normals
|
||||
}
|
||||
|
||||
if vertex_color_stream is not None:
|
||||
@@ -260,37 +432,51 @@ class SceneManifest():
|
||||
|
||||
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
|
||||
def mesh_group_add_skin_rule(self, mesh_group: dict, max_weights_per_vertex: int = 4, weight_threshold: float = 0.001) -> None:
|
||||
"""Adds a Skin rule.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
mesh_group :
|
||||
Mesh Group to add the rule to.
|
||||
max_weights_per_vertex :
|
||||
Max number of joints that can influence a vertex.
|
||||
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)
|
||||
'maxWeightsPerVertex': max_weights_per_vertex,
|
||||
'weightThreshold': weight_threshold
|
||||
}
|
||||
|
||||
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
|
||||
def mesh_group_add_tangent_rule(self, mesh_group: dict,
|
||||
tangent_space: TangentSpaceSource = TangentSpaceSource.SCENE,
|
||||
tspace_method: TangentSpaceMethod = TangentSpaceMethod.TSPACE) -> None:
|
||||
"""Adds a Tangent rule to control tangent space generation.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
mesh_group :
|
||||
Mesh Group to add the rule to.
|
||||
tangent_space :
|
||||
Tangent space source. 0 = Scene, 1 = MikkT Tangent Generation.
|
||||
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)
|
||||
'tangentSpace': int(tangent_space),
|
||||
'tSpaceMethod': int(tspace_method)
|
||||
}
|
||||
|
||||
mesh_group['rules']['rules'].append(rule)
|
||||
|
||||
def __add_physx_base_mesh_group(self, name: str, physics_material: typing.Optional[str]) -> dict:
|
||||
def __add_physx_base_mesh_group(self, name: str, physics_material: typing.Optional[str] = None) -> dict:
|
||||
import azlmbr.math
|
||||
group = {
|
||||
'$type': '{5B03C8E6-8CEE-4DA0-A7FA-CD88689DD45B} MeshGroup',
|
||||
@@ -314,7 +500,9 @@ class SceneManifest():
|
||||
|
||||
return group
|
||||
|
||||
def add_physx_triangle_mesh_group(self, name: str, merge_meshes: bool = True, weld_vertices: bool = False,
|
||||
def add_physx_triangle_mesh_group(self, name: str,
|
||||
merge_meshes: bool = True,
|
||||
weld_vertices: bool = False,
|
||||
disable_clean_mesh: bool = False,
|
||||
force_32bit_indices: bool = False,
|
||||
suppress_triangle_mesh_remap_table: bool = False,
|
||||
@@ -322,26 +510,42 @@ class SceneManifest():
|
||||
mesh_weld_tolerance: float = 0.0,
|
||||
num_tris_per_leaf: int = 4,
|
||||
physics_material: typing.Optional[str] = None) -> dict:
|
||||
"""
|
||||
Adds a Triangle type PhysX Mesh Group to the scene.
|
||||
"""Adds a Triangle type PhysX Mesh Group to the scene.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name :
|
||||
Name of the mesh group.
|
||||
merge_meshes :
|
||||
When true, all selected nodes will be merged into a single collision mesh.
|
||||
weld_vertices :
|
||||
When true, mesh welding is performed. Clean mesh must be enabled.
|
||||
disable_clean_mesh :
|
||||
When true, mesh cleaning is disabled. This makes cooking faster.
|
||||
force_32bit_indices :
|
||||
When true, 32-bit indices will always be created regardless of triangle count.
|
||||
suppress_triangle_mesh_remap_table :
|
||||
When true, the face remap table is not created.
|
||||
This saves a significant amount of memory, but the SDK will not be able to provide the remap
|
||||
information for internal mesh triangles returned by collisions, sweeps or raycasts hits.
|
||||
build_triangle_adjacencies :
|
||||
When true, the triangle adjacency information is created.
|
||||
mesh_weld_tolerance :
|
||||
If mesh welding is enabled, this controls the distance at
|
||||
which vertices are welded. If mesh welding is not enabled, this value defines the
|
||||
acceptance distance for mesh validation. Provided no two vertices are within this
|
||||
distance, the mesh is considered to be clean. If not, a warning will be emitted.
|
||||
num_tris_per_leaf :
|
||||
Mesh cooking hint for max triangles per leaf limit. Fewer triangles per leaf
|
||||
produces larger meshes with better runtime performance and worse cooking performance.
|
||||
physics_material :
|
||||
Configure which physics material to use.
|
||||
|
||||
Returns
|
||||
-------
|
||||
dict
|
||||
The newly created mesh group.
|
||||
|
||||
:param name: Name of the mesh group.
|
||||
:param merge_meshes: When true, all selected nodes will be merged into a single collision mesh.
|
||||
:param weld_vertices: When true, mesh welding is performed. Clean mesh must be enabled.
|
||||
:param disable_clean_mesh: When true, mesh cleaning is disabled. This makes cooking faster.
|
||||
:param force_32bit_indices: When true, 32-bit indices will always be created regardless of triangle count.
|
||||
:param suppress_triangle_mesh_remap_table: When true, the face remap table is not created.
|
||||
This saves a significant amount of memory, but the SDK will not be able to provide the remap
|
||||
information for internal mesh triangles returned by collisions, sweeps or raycasts hits.
|
||||
:param build_triangle_adjacencies: When true, the triangle adjacency information is created.
|
||||
:param mesh_weld_tolerance: If mesh welding is enabled, this controls the distance at
|
||||
which vertices are welded. If mesh welding is not enabled, this value defines the
|
||||
acceptance distance for mesh validation. Provided no two vertices are within this
|
||||
distance, the mesh is considered to be clean. If not, a warning will be emitted.
|
||||
:param num_tris_per_leaf: Mesh cooking hint for max triangles per leaf limit. Fewer triangles per leaf
|
||||
produces larger meshes with better runtime performance and worse cooking performance.
|
||||
:param physics_material: Configure which physics material to use.
|
||||
:return: The newly created mesh group.
|
||||
"""
|
||||
group = self.__add_physx_base_mesh_group(name, physics_material)
|
||||
group["export method"] = 0
|
||||
@@ -367,32 +571,49 @@ class SceneManifest():
|
||||
gauss_map_limit: int = 32,
|
||||
build_gpu_data: bool = False,
|
||||
physics_material: typing.Optional[str] = None) -> dict:
|
||||
"""
|
||||
Adds a Convex type PhysX Mesh Group to the scene.
|
||||
"""Adds a Convex type PhysX Mesh Group to the scene.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name :
|
||||
Name of the mesh group.
|
||||
area_test_epsilon :
|
||||
If the area of a triangle of the hull is below this value, the triangle will be
|
||||
rejected. This test is done only if Check Zero Area Triangles is used.
|
||||
plane_tolerance :
|
||||
The value is used during hull construction. When a new point is about to be added
|
||||
to the hull it gets dropped when the point is closer to the hull than the planeTolerance.
|
||||
use_16bit_indices :
|
||||
Denotes the use of 16-bit vertex indices in Convex triangles or polygons.
|
||||
check_zero_area_triangles :
|
||||
Checks and removes almost zero-area triangles during convex hull computation.
|
||||
The rejected area size is specified in Area Test Epsilon.
|
||||
quantize_input :
|
||||
Quantizes the input vertices using the k-means clustering.
|
||||
use_plane_shifting :
|
||||
Enables plane shifting vertex limit algorithm. Plane shifting is an alternative
|
||||
algorithm for the case when the computed hull has more vertices than the specified vertex
|
||||
limit.
|
||||
shift_vertices :
|
||||
Convex hull input vertices are shifted to be around origin to provide better
|
||||
computation stability
|
||||
gauss_map_limit :
|
||||
Vertex limit beyond which additional acceleration structures are computed for each
|
||||
convex mesh. Increase that limit to reduce memory usage. Computing the extra structures
|
||||
all the time does not guarantee optimal performance.
|
||||
build_gpu_data :
|
||||
When true, additional information required for GPU-accelerated rigid body
|
||||
simulation is created. This can increase memory usage and cooking times for convex meshes
|
||||
and triangle meshes. Convex hulls are created with respect to GPU simulation limitations.
|
||||
Vertex limit is set to 64 and vertex limit per face is internally set to 32.
|
||||
physics_material :
|
||||
Configure which physics material to use.
|
||||
|
||||
Returns
|
||||
-------
|
||||
dict
|
||||
The newly created mesh group.
|
||||
|
||||
:param name: Name of the mesh group.
|
||||
:param area_test_epsilon: If the area of a triangle of the hull is below this value, the triangle will be
|
||||
rejected. This test is done only if Check Zero Area Triangles is used.
|
||||
:param plane_tolerance: The value is used during hull construction. When a new point is about to be added
|
||||
to the hull it gets dropped when the point is closer to the hull than the planeTolerance.
|
||||
:param use_16bit_indices: Denotes the use of 16-bit vertex indices in Convex triangles or polygons.
|
||||
:param check_zero_area_triangles: Checks and removes almost zero-area triangles during convex hull computation.
|
||||
The rejected area size is specified in Area Test Epsilon.
|
||||
:param quantize_input: Quantizes the input vertices using the k-means clustering.
|
||||
:param use_plane_shifting: Enables plane shifting vertex limit algorithm. Plane shifting is an alternative
|
||||
algorithm for the case when the computed hull has more vertices than the specified vertex
|
||||
limit.
|
||||
:param shift_vertices: Convex hull input vertices are shifted to be around origin to provide better
|
||||
computation stability
|
||||
:param gauss_map_limit: Vertex limit beyond which additional acceleration structures are computed for each
|
||||
convex mesh. Increase that limit to reduce memory usage. Computing the extra structures
|
||||
all the time does not guarantee optimal performance.
|
||||
:param build_gpu_data: When true, additional information required for GPU-accelerated rigid body
|
||||
simulation is created. This can increase memory usage and cooking times for convex meshes
|
||||
and triangle meshes. Convex hulls are created with respect to GPU simulation limitations.
|
||||
Vertex limit is set to 64 and vertex limit per face is internally set to 32.
|
||||
:param physics_material: Configure which physics material to use.
|
||||
:return: The newly created mesh group.
|
||||
"""
|
||||
group = self.__add_physx_base_mesh_group(name, physics_material)
|
||||
group["export method"] = 1
|
||||
@@ -414,17 +635,27 @@ class SceneManifest():
|
||||
primitive_shape_target: PrimitiveShape = PrimitiveShape.BEST_FIT,
|
||||
volume_term_coefficient: float = 0.0,
|
||||
physics_material: typing.Optional[str] = None) -> dict:
|
||||
"""
|
||||
Adds a Primitive Shape type PhysX Mesh Group to the scene
|
||||
"""Adds a Primitive Shape type PhysX Mesh Group to the scene
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name :
|
||||
Name of the mesh group.
|
||||
primitive_shape_target :
|
||||
The shape that should be fitted to this mesh. If BEST_FIT is selected, the
|
||||
algorithm will determine which of the shapes fits best.
|
||||
volume_term_coefficient :
|
||||
This parameter controls how aggressively the primitive fitting algorithm will try
|
||||
to minimize the volume of the fitted primitive. A value of 0 (no volume minimization) is
|
||||
recommended for most meshes, especially those with moderate to high vertex counts.
|
||||
physics_material :
|
||||
Configure which physics material to use.
|
||||
|
||||
Returns
|
||||
-------
|
||||
dict
|
||||
The newly created mesh group.
|
||||
|
||||
:param name: Name of the mesh group.
|
||||
:param primitive_shape_target: The shape that should be fitted to this mesh. If BEST_FIT is selected, the
|
||||
algorithm will determine which of the shapes fits best.
|
||||
:param volume_term_coefficient: This parameter controls how aggressively the primitive fitting algorithm will try
|
||||
to minimize the volume of the fitted primitive. A value of 0 (no volume minimization) is
|
||||
recommended for most meshes, especially those with moderate to high vertex counts.
|
||||
:param physics_material: Configure which physics material to use.
|
||||
:return: The newly created mesh group.
|
||||
"""
|
||||
group = self.__add_physx_base_mesh_group(name, physics_material)
|
||||
group["export method"] = 2
|
||||
@@ -447,26 +678,40 @@ class SceneManifest():
|
||||
convex_hull_downsampling: int = 4,
|
||||
pca: bool = False,
|
||||
project_hull_vertices: bool = True) -> None:
|
||||
"""
|
||||
Enables and configures mesh decomposition for a PhysX Mesh Group.
|
||||
"""Enables and configures mesh decomposition for a PhysX Mesh Group.
|
||||
Only valid for convex or primitive mesh types.
|
||||
|
||||
:param mesh_group: Mesh group to configure decomposition for.
|
||||
:param max_convex_hulls: Controls the maximum number of hulls to generate.
|
||||
:param max_num_vertices_per_convex_hull: Controls the maximum number of triangles per convex hull.
|
||||
:param concavity: Maximum concavity of each approximate convex hull.
|
||||
:param resolution: Maximum number of voxels generated during the voxelization stage.
|
||||
:param mode: Select voxel-based approximate convex decomposition or tetrahedron-based
|
||||
approximate convex decomposition.
|
||||
:param alpha: Controls the bias toward clipping along symmetry planes.
|
||||
:param beta: Controls the bias toward clipping along revolution axes.
|
||||
:param min_volume_per_convex_hull: Controls the adaptive sampling of the generated convex hulls.
|
||||
:param plane_downsampling: Controls the granularity of the search for the best clipping plane.
|
||||
:param convex_hull_downsampling: Controls the precision of the convex hull generation process
|
||||
during the clipping plane selection stage.
|
||||
:param pca: Enable or disable normalizing the mesh before applying the convex decomposition.
|
||||
:param project_hull_vertices: Project the output convex hull vertices onto the original source mesh to increase
|
||||
the floating point accuracy of the results.
|
||||
Parameters
|
||||
----------
|
||||
mesh_group :
|
||||
Mesh group to configure decomposition for.
|
||||
max_convex_hulls :
|
||||
Controls the maximum number of hulls to generate.
|
||||
max_num_vertices_per_convex_hull :
|
||||
Controls the maximum number of triangles per convex hull.
|
||||
concavity :
|
||||
Maximum concavity of each approximate convex hull.
|
||||
resolution :
|
||||
Maximum number of voxels generated during the voxelization stage.
|
||||
mode :
|
||||
Select voxel-based approximate convex decomposition or tetrahedron-based
|
||||
approximate convex decomposition.
|
||||
alpha :
|
||||
Controls the bias toward clipping along symmetry planes.
|
||||
beta :
|
||||
Controls the bias toward clipping along revolution axes.
|
||||
min_volume_per_convex_hull :
|
||||
Controls the adaptive sampling of the generated convex hulls.
|
||||
plane_downsampling :
|
||||
Controls the granularity of the search for the best clipping plane.
|
||||
convex_hull_downsampling :
|
||||
Controls the precision of the convex hull generation process
|
||||
during the clipping plane selection stage.
|
||||
pca :
|
||||
Enable or disable normalizing the mesh before applying the convex decomposition.
|
||||
project_hull_vertices :
|
||||
Project the output convex hull vertices onto the original source mesh to increase
|
||||
the floating point accuracy of the results.
|
||||
"""
|
||||
mesh_group['DecomposeMeshes'] = True
|
||||
mesh_group['ConvexDecompositionParams'] = {
|
||||
@@ -485,41 +730,54 @@ class SceneManifest():
|
||||
}
|
||||
|
||||
def physx_mesh_group_add_selected_node(self, mesh_group: dict, node: str) -> None:
|
||||
"""
|
||||
Adds a node to the selected nodes list
|
||||
"""Adds a node to the selected nodes list
|
||||
|
||||
:param mesh_group: Mesh group to add to.
|
||||
:param node: Node path to add.
|
||||
Parameters
|
||||
----------
|
||||
mesh_group :
|
||||
Mesh group to add to.
|
||||
node :
|
||||
Node path to add.
|
||||
"""
|
||||
mesh_group['NodeSelectionList']['selectedNodes'].append(node)
|
||||
|
||||
def physx_mesh_group_add_unselected_node(self, mesh_group: dict, node: str) -> None:
|
||||
"""
|
||||
Adds a node to the unselected nodes list
|
||||
"""Adds a node to the unselected nodes list
|
||||
|
||||
:param mesh_group: Mesh group to add to.
|
||||
:param node: Node path to add.
|
||||
Parameters
|
||||
----------
|
||||
mesh_group :
|
||||
Mesh group to add to.
|
||||
node :
|
||||
Node path to add.
|
||||
"""
|
||||
mesh_group['NodeSelectionList']['unselectedNodes'].append(node)
|
||||
|
||||
def physx_mesh_group_add_selected_unselected_nodes(self, mesh_group: dict, selected: typing.List[str],
|
||||
unselected: typing.List[str]) -> None:
|
||||
"""
|
||||
Adds a set of nodes to the selected/unselected node lists
|
||||
"""Adds a set of nodes to the selected/unselected node lists
|
||||
|
||||
:param mesh_group: Mesh group to add to.
|
||||
:param selected: List of node paths to add to the selected list.
|
||||
:param unselected: List of node paths to add to the unselected list.
|
||||
Parameters
|
||||
----------
|
||||
mesh_group :
|
||||
Mesh group to add to.
|
||||
selected :
|
||||
List of node paths to add to the selected list.
|
||||
unselected :
|
||||
List of node paths to add to the unselected list.
|
||||
"""
|
||||
mesh_group['NodeSelectionList']['selectedNodes'].extend(selected)
|
||||
mesh_group['NodeSelectionList']['unselectedNodes'].extend(unselected)
|
||||
|
||||
def physx_mesh_group_add_comment(self, mesh_group: dict, comment: str) -> None:
|
||||
"""
|
||||
Adds a comment rule
|
||||
"""Adds a comment rule
|
||||
|
||||
:param mesh_group: Mesh group to add the rule to.
|
||||
:param comment: Comment string.
|
||||
Parameters
|
||||
----------
|
||||
mesh_group :
|
||||
Mesh group to add the rule to.
|
||||
comment :
|
||||
Comment string.
|
||||
"""
|
||||
rule = {
|
||||
"$type": "CommentRule",
|
||||
|
||||
Reference in New Issue
Block a user