Merge branch 'main' into gh-pages

This commit is contained in:
Srdjan Milicev 2023-06-30 08:12:18 +02:00
commit a4be6057a0
16 changed files with 180979 additions and 3580 deletions

View File

@ -129,9 +129,47 @@ Several Python examples are provided for reference and can be found in the **exa
Note: Examples are grouped in three groups: DNA, DNACalib, and DNAViewer. These names are embedded as prefixes: dna_, dnacalib_, and dna_viewer_. Note: Examples are grouped in three groups: DNA, DNACalib, and DNAViewer. These names are embedded as prefixes: dna_, dnacalib_, and dna_viewer_.
## Example DNA files ## Example DNA files
[Two demo DNA files](data/dna) are provided for easier testing of this tool. Any DNA generated with [MetaHumanCreator](https://www.unrealengine.com/en-US/metahuman) [Two demo DNA files](data/dna_files) are provided for easier testing of this tool. Any DNA generated with [MetaHumanCreator](https://www.unrealengine.com/en-US/metahuman)
should work. should work.
The MHC 2023 spring release introduced changes to the rig definition (number of joints increased as well as the number of expressions).
In order to accommodate those changes, we added several files to the repository in `/data/mh4` folder: new [gui scene](/data/mh4/gui.ma), updated [assemble script](/data/mh4/additional_assemble_script.py) and example of Adas [DNA file](data/mh4/dna_files/Ada.dna).
If a user wants to switch and use this new rig version it is necessary to update paths in their scripts:
```python
GUI = f"{DATA_DIR}/mh4/gui.ma"
ADDITIONAL_ASSEMBLE_SCRIPT = f"{DATA_DIR}/mh4/additional_assemble_script.py"
```
In case character DNA is downloaded from [Quixel Bridge](https://quixel.com/bridge) and we are not sure which rig definition is used, it can be checked with following code:
```python
from dna import (
BinaryStreamReader,
DataLayer_All,
FileStream,
Status,
)
def load_dna_reader(dna_file):
stream = FileStream(
dna_file, FileStream.AccessMode_Read, FileStream.OpenMode_Binary
)
reader = BinaryStreamReader(stream, DataLayer_All)
reader.read()
if not Status.isOk():
status = Status.get()
raise RuntimeError(f"Error loading DNA: {status.message}")
return reader
character_dna = "path_to/character.dna"
reader = load_dna_reader(character_dna)
if reader.getDBName() == "MH.4":
print("Use mh4 folder")
elif reader.getDBName() == "DHI":
print("Use data folder")
else:
print("Unsupported rig definition!")
```
# Notes # Notes
If a user runs examples in Maya 2022, the value for `ROOT_DIR` should be changed and absolute paths must be used, If a user runs examples in Maya 2022, the value for `ROOT_DIR` should be changed and absolute paths must be used,
e.g. `c:/MetaHuman-DNA-Calibration` in Windows or `/home/user/MetaHuman-DNA-Calibration` in Linux. Important: Use `/` (forward slash), Maya uses forward slashes in path. e.g. `c:/MetaHuman-DNA-Calibration` in Windows or `/home/user/MetaHuman-DNA-Calibration` in Linux. Important: Use `/` (forward slash), Maya uses forward slashes in path.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

BIN
data/mh4/dna_files/Ada.dna Normal file

Binary file not shown.

179084
data/mh4/gui.ma Normal file

File diff suppressed because it is too large Load Diff

View File

@ -41,6 +41,7 @@ sudo ln -s ~/MetaHuman-DNA-Calibration/lib/Maya2022/linux/libdnacalib.so.6 /usr/
sudo ln -s ~/MetaHuman-DNA-Calibration/lib/Maya2022/linux/libembeddedRL4.so /usr/lib/embeddedRL4.mll sudo ln -s ~/MetaHuman-DNA-Calibration/lib/Maya2022/linux/libembeddedRL4.so /usr/lib/embeddedRL4.mll
sudo ln -s ~/MetaHuman-DNA-Calibration/lib/Maya2022/linux/MayaUERBFPlugin.mll /usr/lib/MayaUERBFPlugin.mll
``` ```
Note: Change the path `~/MetaHuman-DNA-Calibration` to where `MetaHuman-DNA-Calibration` is located. Note: Change the path `~/MetaHuman-DNA-Calibration` to where `MetaHuman-DNA-Calibration` is located.
@ -59,3 +60,7 @@ Furthermore, [`additional_assemble_script.py`](/data/additional_assemble_script.
connect controls. The ideal setup looks like this: connect controls. The ideal setup looks like this:
![image](img/aas.png) ![image](img/aas.png)
The MHC 2023 spring release introduced changes to the rig definition (number of joints increased as well as the number of expressions).
In order to accommodate those changes, we added several files to the repository in `/data/mh4` folder: new [gui scene](/data/mh4/gui.ma), updated [assemble script](/data/mh4/additional_assemble_script.py) and example of Adas [DNA file](data/mh4/dna_files/Ada.dna).
Furthermore, in lib folder we added Maya RBF plugin which is used for controlling neck expressions. Neck setup has recently been improved and adding RBF plugin as well as new gui scene to use it, we get better neck deformations.

View File

@ -20,7 +20,7 @@ NOTE: If OUTPUT_DIR does not exist, it will be created.
from os import makedirs from os import makedirs
from os import path as ospath from os import path as ospath
# if you use Maya, use absolute path # If you use Maya, use absolute path
ROOT_DIR = f"{ospath.dirname(ospath.abspath(__file__))}/..".replace("\\", "/") ROOT_DIR = f"{ospath.dirname(ospath.abspath(__file__))}/..".replace("\\", "/")
OUTPUT_DIR = f"{ROOT_DIR}/output" OUTPUT_DIR = f"{ROOT_DIR}/output"

View File

@ -21,7 +21,7 @@ NOTE: If OUTPUT_DIR does not exist, it will be created.
from os import makedirs from os import makedirs
from os import path as ospath from os import path as ospath
# if you use Maya, use absolute path # If you use Maya, use absolute path
ROOT_DIR = f"{ospath.dirname(ospath.abspath(__file__))}/..".replace("\\", "/") ROOT_DIR = f"{ospath.dirname(ospath.abspath(__file__))}/..".replace("\\", "/")
OUTPUT_DIR = f"{ROOT_DIR}/output" OUTPUT_DIR = f"{ROOT_DIR}/output"

View File

@ -53,10 +53,10 @@ if __name__ == "__main__":
makedirs(OUTPUT_DIR, exist_ok=True) makedirs(OUTPUT_DIR, exist_ok=True)
# this fixes warning when calling this script with headless maya Warning: line 1: Unknown object type: HIKCharacterNode # This fixes warning when calling this script with headless maya Warning: line 1: Unknown object type: HIKCharacterNode
mel.eval(f"HIKCharacterControlsTool;") mel.eval(f"HIKCharacterControlsTool;")
# generate workspace.mel # Generate workspace.mel
mel.eval(f'setProject "{OUTPUT_DIR}";') mel.eval(f'setProject "{OUTPUT_DIR}";')
config = RigConfig( config = RigConfig(
@ -70,5 +70,5 @@ if __name__ == "__main__":
# Renames and saves the scene # Renames and saves the scene
cmds.file(rename=f"{OUTPUT_DIR}/{CHARACTER_NAME}.mb") cmds.file(rename=f"{OUTPUT_DIR}/{CHARACTER_NAME}.mb")
cmds.file(save=True) cmds.file(save=True)
# copy dna fila and workspace file alongside generated scene # Copy dna file and workspace file alongside generated scene
copyfile(CHARACTER_DNA, f"{OUTPUT_DIR}/{CHARACTER_NAME}.dna") copyfile(CHARACTER_DNA, f"{OUTPUT_DIR}/{CHARACTER_NAME}.dna")

View File

@ -49,8 +49,7 @@ ADD_COLOR_VERTEX = False
DNA_DIR = f"{DATA_DIR}/dna_files" DNA_DIR = f"{DATA_DIR}/dna_files"
BODY_DIR = f"{DATA_DIR}/body" BODY_DIR = f"{DATA_DIR}/body"
CHARACTER_DNA = f"{DNA_DIR}/{CHARACTER_NAME}.dna" CHARACTER_DNA = f"{DNA_DIR}/{CHARACTER_NAME}.dna"
ANALOG_GUI = f"{DATA_DIR}/analog_gui.ma"
GUI = f"{DATA_DIR}/gui.ma"
UP_AXIS = "z" UP_AXIS = "z"
if UP_AXIS not in ("z", "y"): if UP_AXIS not in ("z", "y"):
raise ValueError("UP_AXIS can be 'z' or 'y'") raise ValueError("UP_AXIS can be 'z' or 'y'")
@ -182,7 +181,7 @@ def create_head_and_body_scene(mesh_names):
cmds.file(BODY_FILE, options="v=0", type="mayaAscii", i=True) cmds.file(BODY_FILE, options="v=0", type="mayaAscii", i=True)
if UP_AXIS == "y": if UP_AXIS == "y":
cmds.rotate("-90deg", 0, 0, "root") cmds.joint("root", edit=True, orientation=[-90.0, 0.0, 0.0])
for facial_joint, neck_joint in zip(FACIAL_ROOT_JOINTS, NECK_JOINTS): for facial_joint, neck_joint in zip(FACIAL_ROOT_JOINTS, NECK_JOINTS):
cmds.parent(facial_joint, neck_joint) cmds.parent(facial_joint, neck_joint)
@ -287,14 +286,14 @@ if __name__ == "__main__":
# Loads the builtin plugin needed for FBX # Loads the builtin plugin needed for FBX
cmds.loadPlugin("fbxmaya.mll") cmds.loadPlugin("fbxmaya.mll")
# this fixes warning when calling this script with headless maya Warning: line 1: Unknown object type: HIKCharacterNode # This fixes warning when calling this script with headless maya Warning: line 1: Unknown object type: HIKCharacterNode
mel.eval(f"HIKCharacterControlsTool;") mel.eval(f"HIKCharacterControlsTool;")
# generate workspace.mel # Generate workspace.mel
mel.eval(f'setProject "{OUTPUT_DIR}";') mel.eval(f'setProject "{OUTPUT_DIR}";')
# Export FBX for each lod # Export FBX for each lod
cmds.upAxis(ax=UP_AXIS)
dna = get_dna() dna = get_dna()
for lod in range(dna.get_lod_count()): for lod in range(dna.get_lod_count()):
export_fbx_for_lod(dna, lod) export_fbx_for_lod(dna, lod)

View File

@ -49,7 +49,7 @@ from os import path as ospath
CHARACTER_NAME = "Ada" CHARACTER_NAME = "Ada"
# if you use Maya, use absolute path # If you use Maya, use absolute path
ROOT_DIR = f"{ospath.dirname(ospath.abspath(__file__))}/..".replace("\\", "/") ROOT_DIR = f"{ospath.dirname(ospath.abspath(__file__))}/..".replace("\\", "/")
OUTPUT_DIR = f"{ROOT_DIR}/output" OUTPUT_DIR = f"{ROOT_DIR}/output"
ROOT_LIB_DIR = f"{ROOT_DIR}/lib" ROOT_LIB_DIR = f"{ROOT_DIR}/lib"
@ -142,9 +142,9 @@ def run_joints_command(reader, calibrated):
rotation = cmds.joint(joint_name, query=True, orientation=True) rotation = cmds.joint(joint_name, query=True, orientation=True)
joint_rotations.append(rotation) joint_rotations.append(rotation)
# this is step 5 sub-step a # This is step 5 sub-step a
set_new_joints_translations = SetNeutralJointTranslationsCommand(joint_translations) set_new_joints_translations = SetNeutralJointTranslationsCommand(joint_translations)
# this is step 5 sub-step b # This is step 5 sub-step b
set_new_joints_rotations = SetNeutralJointRotationsCommand(joint_rotations) set_new_joints_rotations = SetNeutralJointRotationsCommand(joint_rotations)
# Abstraction to collect all commands into a sequence, and run them with only one invocation # Abstraction to collect all commands into a sequence, and run them with only one invocation
@ -154,7 +154,7 @@ def run_joints_command(reader, calibrated):
commands.add(set_new_joints_rotations) commands.add(set_new_joints_rotations)
commands.run(calibrated) commands.run(calibrated)
# verify that everything went fine # Verify that everything went fine
if not Status.isOk(): if not Status.isOk():
status = Status.get() status = Status.get()
raise RuntimeError(f"Error run_joints_command: {status.message}") raise RuntimeError(f"Error run_joints_command: {status.message}")
@ -163,7 +163,7 @@ def run_joints_command(reader, calibrated):
def run_vertices_command( def run_vertices_command(
calibrated, old_vertices_positions, new_vertices_positions, mesh_index calibrated, old_vertices_positions, new_vertices_positions, mesh_index
): ):
# making deltas between old vertices positions and new one # Making deltas between old vertices positions and new one
deltas = [] deltas = []
for new_vertex, old_vertex in zip(new_vertices_positions, old_vertices_positions): for new_vertex, old_vertex in zip(new_vertices_positions, old_vertices_positions):
delta = [] delta = []
@ -171,7 +171,7 @@ def run_vertices_command(
delta.append(new - old) delta.append(new - old)
deltas.append(delta) deltas.append(delta)
# this is step 5 sub-step c # This is step 5 sub-step c
new_neutral_mesh = SetVertexPositionsCommand( new_neutral_mesh = SetVertexPositionsCommand(
mesh_index, deltas, VectorOperation_Add mesh_index, deltas, VectorOperation_Add
) )
@ -180,7 +180,7 @@ def run_vertices_command(
commands.add(new_neutral_mesh) commands.add(new_neutral_mesh)
commands.run(calibrated) commands.run(calibrated)
# verify that everything went fine # Verify that everything went fine
if not Status.isOk(): if not Status.isOk():
status = Status.get() status = Status.get()
raise RuntimeError(f"Error run_vertices_command: {status.message}") raise RuntimeError(f"Error run_vertices_command: {status.message}")
@ -209,7 +209,7 @@ config = RigConfig(
) )
build_rig(dna=dna, config=config) build_rig(dna=dna, config=config)
# this is step 3 sub-step a # This is step 3 sub-step a
current_vertices_positions = {} current_vertices_positions = {}
mesh_indices = [] mesh_indices = []
for mesh_index, name in enumerate(dna.meshes.names): for mesh_index, name in enumerate(dna.meshes.names):
@ -217,15 +217,15 @@ for mesh_index, name in enumerate(dna.meshes.names):
"mesh_index": mesh_index, "mesh_index": mesh_index,
"positions": get_mesh_vertex_positions_from_scene(name), "positions": get_mesh_vertex_positions_from_scene(name),
} }
# loaded data - end of 3rd step # Loaded data - end of 3rd step
################################## ##################################
################################## ##################################
# modify rig in maya, 4th step # Modify rig in maya, 4th step
################################## ##################################
################################## ##################################
# propagate changes to dna, 5th step # Propagate changes to dna, 5th step
reader = load_dna_reader(CHARACTER_DNA) reader = load_dna_reader(CHARACTER_DNA)
calibrated = DNACalibDNAReader(reader) calibrated = DNACalibDNAReader(reader)

View File

@ -10,7 +10,7 @@ IMPORTANT: You have to setup the environment before running this example. Please
""" """
# this example is intended to be used in Maya # This example is intended to be used in Maya
import dna_viewer import dna_viewer

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.