├── .gitignore ├── LICENSE ├── README.md ├── __init__.py ├── blender └── __init__.py ├── core ├── constant.py ├── context.py ├── logger.py └── pycharm_debug.py ├── houdini └── __init__.py ├── maya ├── __init__.py ├── binder.py ├── builder.py ├── core │ ├── api_utils.py │ ├── constant.py │ ├── context.py │ ├── data.py │ ├── deformer.py │ └── skin.py ├── nodes │ ├── Proto │ │ └── fddaDeformerNode.py │ ├── fddaNode.vcxproj │ └── sources │ │ ├── common.h │ │ ├── fddaNode.cpp │ │ ├── fddaNode.h │ │ ├── multiLayerPerceptron.h │ │ ├── plugin.cpp │ │ └── settings.h ├── poseGenerator.py └── scenes │ └── CylinderTest.ma ├── posedata └── biped.json └── training ├── PyTorch ├── __init__.py ├── architecture.py ├── callbacks.py ├── dataset.py ├── loader.py ├── math.py ├── settings.py └── training.py ├── TensorFlow └── __init__.py └── __init__.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | .idea 3 | ref 4 | .DS_Store -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Dhruv Govil 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FFDA 2 | [Fast and Deep Deformation Approximations](http://graphics.berkeley.edu/papers/Bailey-FDD-2018-08/index.html) 3 | 4 | # Authors 5 | - [Rémi Deletrain](https://fr.linkedin.com/in/r%C3%A9mi-deletrain-3b296028) 6 | - [Thomas Léglantier](https://www.linkedin.com/in/thomas-l%C3%A9glantier-ab318b157) 7 | - [Tristan Cordeboeuf](https://www.artstation.com/tcordeboeuf) 8 | 9 | # Dependencies 10 | - [Pytorch 1.13.1](https://pytorch.org/) 11 | - [Pandas](https://pandas.pydata.org/) 12 | - [tqdm](https://tqdm.github.io/) 13 | - [numpy](https://numpy.org/) 14 | 15 | # Launch 16 | ```python 17 | import sys 18 | 19 | sys.path.insert(0, r"PATH/OF/YOUR/CODE") 20 | 21 | from maya import cmds, OpenMaya 22 | 23 | from fdda.maya import bind, train, generate_pose 24 | from fdda.training.PyTorch.settings import Settings 25 | 26 | 27 | selected = cmds.ls(selection=True, long=True) 28 | if len(selected) != 2: 29 | raise RuntimeError("Selected Source and Destination !") 30 | source, destination = selected 31 | 32 | settings = Settings.default() 33 | settings.split = 0.1 34 | settings.units = 256 35 | settings.device = Settings.kGpu 36 | 37 | output_path = train(source, destination, settings, build_pose=True, num_pose=40) 38 | bind(destination, output_path) 39 | ``` 40 | # Results 41 | ## Basic cylindre 42 | 43 | https://github.com/RDelet/FFDA/assets/7300189/eb5d7f20-a253-43f3-b71c-3908d721ff0e 44 | 45 | ## Dana 46 | Models made by [Tristan Cordeboeuf](https://www.artstation.com/tcordeboeuf) at [The Beast Makers](https://fr.thebeastmakers.com/). 47 | 48 | https://github.com/RDelet/FFDA/assets/7300189/7aadffd3-9523-4754-9389-2f19138fb905 49 | 50 | -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | _directory, _ = os.path.split(__file__) 4 | poseDataDirectory = os.path.normpath(os.path.join(_directory, "posedata")) 5 | 6 | kBipedLimitsPath = os.path.normpath(os.path.join(poseDataDirectory, "biped.json")) 7 | -------------------------------------------------------------------------------- /blender/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RDelet/FFDA/1525a5fd27aed938a439daa4812d1e20783b1eff/blender/__init__.py -------------------------------------------------------------------------------- /core/constant.py: -------------------------------------------------------------------------------- 1 | # coding=ascii 2 | 3 | kInputName = "input_data" 4 | kOutputName = "output_data" 5 | kExtension = "json" 6 | kJsonIndent = 4 7 | 8 | kInputHeading = ["qx", "qy", "qz", "qw"] 9 | 10 | kModels = "models" 11 | kJointMap = "joint_map" 12 | kModel = "model" 13 | kBestModel = "best_model" 14 | kDevice = "device" 15 | kMean = "mean" 16 | kStd = "std" 17 | kNormalized = "normalized" 18 | kMode = 'global_mode' 19 | 20 | kTrainingDataLong = "trainingData" 21 | kTrainingDataShort = "ta" 22 | kMatrixLong = "matrix" 23 | kMatrixShort = "mat" 24 | 25 | kCPU = "cpu" 26 | kGPU = "cuda:0" -------------------------------------------------------------------------------- /core/context.py: -------------------------------------------------------------------------------- 1 | import functools 2 | 3 | 4 | class Context(object): 5 | 6 | def __init__(self, *args, **kwargs): 7 | pass 8 | 9 | def __str__(self) -> str: 10 | return self.__repr__() 11 | 12 | def __repr__(self) -> str: 13 | return f"FDDA(class: {self.__class__.__name__})" 14 | 15 | def __enter__(self, *args, **kwargs): 16 | raise NotImplementedError('{0}.__enter__ need to be reimplemented !'.format(self.__class__.__name__)) 17 | 18 | def __exit__(self, *args, **kwargs): 19 | raise NotImplementedError('{0}.__exit__ need to be reimplemented !'.format(self.__class__.__name__)) 20 | 21 | 22 | class ContextDecorator(Context): 23 | 24 | def __call__(self, f): 25 | @functools.wraps(f) 26 | def wrapper(*args, **kwargs): 27 | with self: 28 | try: 29 | return f(*args, **kwargs) 30 | except Exception as e: 31 | raise e 32 | 33 | return wrapper 34 | -------------------------------------------------------------------------------- /core/logger.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import os 3 | 4 | 5 | _formatter = logging.Formatter("%(asctime)s %(threadName)-11s %(levelname)-10s %(message)s") 6 | stream_handler = logging.StreamHandler() 7 | stream_handler.setFormatter(_formatter) 8 | 9 | 10 | def set_output_path(p, formatter=_formatter): 11 | p = os.path.normpath(p) 12 | if os.path.isdir(p): 13 | p = os.path.normpath(os.path.join(p, "FFDA.log")) 14 | # make sure directory exists 15 | directory = os.path.split(p)[0] 16 | if not os.path.exists(directory): 17 | os.mkdir(directory) 18 | # make sure file exists 19 | if not os.path.exists(p): 20 | with open(p, "w") as stream: 21 | stream.write("") 22 | 23 | file_handler = logging.FileHandler(p, "w") 24 | file_handler.setLevel(logging.DEBUG) 25 | file_handler.setFormatter(formatter) 26 | log.addHandler(file_handler) 27 | 28 | 29 | def set_log_level(log_level): 30 | log.setLevel(log_level) 31 | stream_handler.setLevel(log_level) 32 | 33 | 34 | log = logging.getLogger("FFDA") 35 | log.addHandler(stream_handler) 36 | set_log_level(logging.DEBUG) 37 | -------------------------------------------------------------------------------- /core/pycharm_debug.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | kDebugModule = "pydevd_pycharm.py" 5 | kRootPath = r"C:\Program Files\JetBrains" 6 | 7 | def find_last_version(root_path: str) -> str: 8 | dir = None 9 | last = 0 10 | for elem in os.listdir(root_path): 11 | flat_str = elem.replace(" ", "").replace(".", "").replace("_", "").replace("-", "") 12 | num_str = "" 13 | for s in flat_str: 14 | if s.isdigit(): 15 | num_str += s 16 | 17 | if int(num_str) > last: 18 | dir = elem 19 | 20 | return os.path.normpath(os.path.join(root_path, dir)) 21 | 22 | 23 | def find_debugger(root_path: str) -> str: 24 | pycharm_last_version = find_last_version(root_path) 25 | for dir_path, _, file_names in os.walk(pycharm_last_version): 26 | for f in file_names: 27 | if f.endswith(kDebugModule): 28 | return os.path.normpath(os.path.join(dir_path, f)) 29 | 30 | 31 | def connect(root_path: str = kRootPath, port: int = 50015): 32 | debug_module_path = find_debugger(root_path) 33 | sys.path.insert(0, os.path.split(debug_module_path)[0]) 34 | 35 | import pydevd_pycharm 36 | pydevd_pycharm.settrace('localhost', port=port, stdoutToServer=True, stderrToServer=True) 37 | -------------------------------------------------------------------------------- /houdini/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RDelet/FFDA/1525a5fd27aed938a439daa4812d1e20783b1eff/houdini/__init__.py -------------------------------------------------------------------------------- /maya/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | # ----------------------- 3 | # Script pour Maya: 4 | # ----------------------- 5 | import sys 6 | 7 | sys.path.insert(0, r"D:\RDE_DATA\Work") 8 | 9 | from maya import cmds, OpenMaya 10 | 11 | from fdda.maya import bind, train, generate_pose 12 | from fdda.training.PyTorch.settings import Settings 13 | 14 | 15 | selected = cmds.ls(selection=True, long=True) 16 | if len(selected) != 2: 17 | raise RuntimeError("Selected Source and Destination !") 18 | source, destination = selected 19 | 20 | settings = Settings.default() 21 | settings.split = 0.1 22 | settings.units = 256 23 | settings.device = Settings.kGpu 24 | 25 | output_path = train(source, destination, settings, build_pose=True, num_pose=40) 26 | bind(destination, output_path) 27 | """ 28 | 29 | import os 30 | 31 | from maya import cmds 32 | 33 | from fdda import kBipedLimitsPath 34 | from fdda.core.logger import log 35 | from fdda.maya.core import api_utils 36 | from fdda.maya.core import constant as cst 37 | from fdda.maya.poseGenerator import PoseGenerator 38 | from fdda.maya.builder import Builder 39 | from fdda.maya.binder import Binder 40 | from fdda.training.PyTorch.training import build_models 41 | from fdda.training.PyTorch.settings import Settings 42 | 43 | 44 | 45 | _directory = os.path.split(__file__)[0] 46 | 47 | 48 | def get_path_from_scene() -> str: 49 | scene_name = cmds.file(query=True, sceneName=True) 50 | if not scene_name: 51 | raise RuntimeError("Scene must be save before train !") 52 | 53 | directory_path, file_name = os.path.split(scene_name) 54 | output_path = os.path.normpath(os.path.join(directory_path, file_name.split(".")[0])) 55 | if not os.path.exists(output_path): 56 | os.mkdir(output_path) 57 | log.info(f"Create directory: {output_path}") 58 | 59 | return output_path 60 | 61 | def bind(node: cst.kdagType, input_directory: str): 62 | """ @!Brief Bind FDDA deformer.""" 63 | api_utils.go_to_start_frame() 64 | binder = Binder(destination=node, input_directory=input_directory) 65 | binder.bind() 66 | 67 | 68 | def generate_pose(node: str, num_pose: int = 40, data_path: str = kBipedLimitsPath): 69 | pose_generator = PoseGenerator(node) 70 | pose_generator.generate(num_pose) 71 | 72 | 73 | def train(source: str, destination: str, 74 | settings: Settings = Settings.default(), 75 | build_pose: bool = True, num_pose: int = 40) -> str: 76 | output_path = get_path_from_scene() 77 | 78 | if build_pose: 79 | generate_pose(source, num_pose=num_pose) 80 | 81 | data_builder = Builder(source, destination) 82 | data_builder.do(output_path) 83 | 84 | build_models(input_directory=output_path, settings=settings, mode=True, normalized=True, debug=True) 85 | 86 | return output_path 87 | 88 | 89 | def load_node(): 90 | node_path = os.path.normpath(os.path.join(_directory, "nodes/Proto", "fddaDeformerNode.py")) 91 | if not cmds.pluginInfo(node_path, query=True, loaded=True): 92 | cmds.loadPlugin(node_path) 93 | 94 | 95 | try: 96 | load_node() 97 | except Exception as e: 98 | log.debug(e) 99 | raise RuntimeError("Error on load FDDA plugin !") 100 | -------------------------------------------------------------------------------- /maya/binder.py: -------------------------------------------------------------------------------- 1 | # coding=ascii 2 | import os 3 | import json 4 | 5 | from maya import cmds, OpenMaya 6 | 7 | from fdda.core import constant as cst 8 | from fdda.core.logger import log 9 | from fdda.maya.core import api_utils, constant as maya_cst 10 | 11 | 12 | class Binder(object): 13 | 14 | def __init__(self, destination: maya_cst.kdagType, input_directory: str): 15 | self._destination = api_utils.get_node(destination) 16 | self._file = os.path.normpath(os.path.join(input_directory, f"{cst.kOutputName}.{cst.kExtension}")) 17 | self._data = None 18 | self._deformer = None 19 | 20 | def __str__(self) -> str: 21 | return self.__repr__() 22 | 23 | def __repr__(self) -> str: 24 | return f"(class: {self.__class__.__name__}, file: {self._file}, destination: {self._destination})" 25 | 26 | def clear(self): 27 | self._destination = None 28 | self._file = None 29 | self._data = None 30 | self._deformer = None 31 | 32 | @property 33 | def destination(self) -> OpenMaya.MDagPath: 34 | return self._destination 35 | 36 | @destination.setter 37 | def destination(self, value: maya_cst.kdagType): 38 | self._destination = api_utils.get_node(value) 39 | 40 | @property 41 | def file(self) -> str: 42 | return self._file 43 | 44 | @file.setter 45 | def file(self, value): 46 | if not os.path.exists(value): 47 | raise RuntimeError(f"Path {value} does not exists !") 48 | 49 | self._file = value 50 | with open(self._file, 'r') as stream: 51 | self._data = json.load(stream) 52 | 53 | if self._deformer is not None: 54 | deformer_name = api_utils.name(self._deformer) 55 | cmds.setAttr(f"{deformer_name}.{cst.kTrainingDataLong}", 56 | self._file, type='string') 57 | 58 | @property 59 | def deformer(self) -> OpenMaya.MDagPath: 60 | return self._deformer 61 | 62 | @deformer.setter 63 | def deformer(self, value: maya_cst.kdepType): 64 | self._deformer = api_utils.get_node(value) 65 | 66 | @property 67 | def data(self) -> dict: 68 | if not self.file: 69 | raise RuntimeError(f"No file set !") 70 | with open(self.file, 'r') as f: 71 | return json.load(f) 72 | 73 | def bind(self): 74 | dst_name = api_utils.name(self.destination) 75 | try: 76 | self.deformer = cmds.deformer(dst_name, type=maya_cst.kNodeName)[0] 77 | except Exception as e: 78 | log.debug(e) 79 | raise RuntimeError(f"Error on bind deformer on {dst_name}!") 80 | 81 | cmds.setAttr(f"{api_utils.name(self.deformer)}.trainingData", self._file, type="string") 82 | 83 | deformer_name = api_utils.name(self.deformer) 84 | joint_names = self.data.get('joint_names', list()) 85 | for i, jnt in enumerate(joint_names): 86 | cmds.connectAttr(f"{jnt}.matrix ", f"{deformer_name}.matrix[{i}]") 87 | -------------------------------------------------------------------------------- /maya/builder.py: -------------------------------------------------------------------------------- 1 | # coding=ascii 2 | 3 | import copy 4 | import csv 5 | import json 6 | import os 7 | import traceback 8 | 9 | from maya import OpenMaya 10 | 11 | from fdda.core import constant as cst 12 | from fdda.core.logger import log 13 | from fdda.maya.core import api_utils 14 | from fdda.maya.core.data import SkinData, MeshData 15 | from fdda.maya.core import constant as maya_cst 16 | 17 | 18 | class Builder(object): 19 | 20 | def __init__(self, source: maya_cst.kdagType = None, destination: maya_cst.kdagType = None): 21 | self._source = api_utils.get_node(source) 22 | self._destination = api_utils.get_node(destination) 23 | self._data = None 24 | 25 | def __str__(self) -> str: 26 | return self.__repr__() 27 | 28 | def __repr__(self) -> str: 29 | src_name = api_utils.name(self.source) 30 | dst_name = api_utils.name(self.destination) 31 | return f"(class: {self.__class__.__name__}, source: {src_name}, destination: {dst_name})" 32 | 33 | def clear(self): 34 | self._source = None 35 | self._destination = None 36 | self._data = None 37 | 38 | @property 39 | def source(self) -> OpenMaya.MDagPath: 40 | return self._source 41 | 42 | @source.setter 43 | def source(self, value: maya_cst.kdagType): 44 | self._source = api_utils.get_node(value) 45 | 46 | @property 47 | def destination(self) -> OpenMaya.MDagPath: 48 | return self._destination 49 | 50 | @destination.setter 51 | def destination(self, value: maya_cst.kdagType): 52 | self._destination = api_utils.get_node(value) 53 | 54 | def do(self, output_dir: str, 55 | start: float = None, end: float = None) -> str: 56 | """!Brief Build models from meshes.""" 57 | try: 58 | return self._data_acquisition(out_dir=output_dir, start=start, end=end) 59 | except Exception: 60 | log.debug(traceback.format_exc()) 61 | raise RuntimeError("Error on get data !") 62 | 63 | def _data_acquisition(self, out_dir: str = None, 64 | start: float = None, end: float = None) -> str: 65 | """!@Brief Write out data for the machine learning algorithm to train from.""" 66 | if self.source is None: 67 | raise RuntimeError("No source set !") 68 | if self.destination is None: 69 | raise RuntimeError("No destination set !") 70 | if not os.path.exists(out_dir): 71 | os.mkdir(out_dir) 72 | 73 | mesh_data = MeshData() 74 | mesh_data.get(self.source, self.destination, start=start, end=end) 75 | skin_data = mesh_data.skin_data 76 | 77 | data = {"input_fields": cst.kInputHeading, 78 | "csv_files": self.__dump_csv(mesh_data, skin_data, out_dir), 79 | "joint_names": skin_data.skin.influences_names, 80 | "joint_indexes": [i for i in skin_data.skin.influences_ids], 81 | "weights": skin_data.weight_map, 82 | "joint_map": skin_data.joint_map, 83 | "n_vertices": skin_data.n_verts} 84 | 85 | return self.__dump_data(data, out_dir) 86 | 87 | @classmethod 88 | def __dump_csv(cls, mesh_data: MeshData, skin_data: SkinData, out_dir: str) -> list: 89 | csv_files = list() 90 | 91 | skin_inf = skin_data.skin.influences_names 92 | for jnt in skin_inf: 93 | data = mesh_data.frame_data[jnt] 94 | heading = copy.copy(cst.kInputHeading) 95 | 96 | # Repeat the heading two times because we stock the source mesh vertices & the destination mesh vertices. 97 | for v in skin_data.joint_map[skin_inf.index(jnt)]: 98 | heading.extend([f"vtx{v}x", f"vtx{v}y", f"vtx{v}z"]) 99 | 100 | file_name = f"{jnt.split('|')[-1].split(':')[-1]}.csv" 101 | file_path = os.path.join(out_dir, file_name) 102 | log.info(f"Wrote data for {jnt} to {file_path}") 103 | 104 | with open(file_path, 'w') as f: 105 | writer = csv.writer(f) 106 | writer.writerow(heading) 107 | writer.writerows(data) 108 | 109 | csv_files.append(file_path) 110 | 111 | return csv_files 112 | 113 | @classmethod 114 | def __dump_data(cls, data: dict, output_directory: str) -> str: 115 | file_path = os.path.normpath(os.path.join(output_directory, f"{cst.kInputName}.{cst.kExtension}")) 116 | log.info(f"Wrote Weight Map to {file_path}") 117 | 118 | try: 119 | with open(file_path, 'w') as stream: 120 | json.dump(data, stream, indent=cst.kJsonIndent) 121 | except Exception: 122 | log.debug(traceback.format_exc()) 123 | raise RecursionError("Error on dump data !") 124 | 125 | return file_path 126 | -------------------------------------------------------------------------------- /maya/core/api_utils.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | from typing import Union 4 | 5 | from maya import cmds, OpenMaya, OpenMayaAnim 6 | 7 | from fdda.maya.core import constant as cst 8 | 9 | 10 | _msl = OpenMaya.MSelectionList() 11 | 12 | kRotateMinX = OpenMaya.MFnTransform.kRotateMinX 13 | kRotateMinY = OpenMaya.MFnTransform.kRotateMinY 14 | kRotateMinZ = OpenMaya.MFnTransform.kRotateMinZ 15 | kRotateMaxX = OpenMaya.MFnTransform.kRotateMaxX 16 | kRotateMaxY = OpenMaya.MFnTransform.kRotateMaxY 17 | kRotateMaxZ = OpenMaya.MFnTransform.kRotateMaxZ 18 | kMinRotLimits = [kRotateMinX, kRotateMinY, kRotateMinZ] 19 | kMaxRotLimits = [kRotateMaxX, kRotateMaxY, kRotateMaxZ] 20 | 21 | 22 | def get_object(n: str) -> OpenMaya.MObject: 23 | try: 24 | _msl.clear() 25 | _msl.add(n) 26 | mo = OpenMaya.MObject() 27 | _msl.getDependNode(0, mo) 28 | return mo 29 | except RuntimeError: 30 | if cmds.ls(n): 31 | raise RuntimeError(f"Multi node found for {n} !") 32 | raise RuntimeError(f"Node {n} does not exist !") 33 | 34 | 35 | def get_path(n: Union[str, OpenMaya.MObject]) -> OpenMaya.MDagPath: 36 | if isinstance(n, str): 37 | try: 38 | _msl.clear() 39 | _msl.add(n) 40 | dp = OpenMaya.MDagPath() 41 | _msl.getDagPath(0, dp) 42 | return dp 43 | except RuntimeError: 44 | if cmds.ls(n): 45 | raise RuntimeError(f"Multi node found for {n} !") 46 | raise RuntimeError(f"Node {n} does not exist !") 47 | elif isinstance(n, OpenMaya.MObject): 48 | try: 49 | if n.isNull(): 50 | raise RuntimeError("Object given is null !") 51 | moh = OpenMaya.MObjectHandle(n) 52 | if not moh.isValid() or not moh.isAlive(): 53 | raise RuntimeError("Object given is not valid !") 54 | dp = OpenMaya.MDagPath() 55 | OpenMaya.MDagPath.getAPathTo(n, dp) 56 | return dp 57 | except RuntimeError: 58 | raise RuntimeError("Error on get path from MObject !") 59 | else: 60 | raise TypeError(f"Argument need to be str or MObject not {type(n)} !") 61 | 62 | 63 | def get_node(node: Union[str, OpenMaya.MObject, OpenMaya.MDagPath]) -> OpenMaya.MDagPath: 64 | if isinstance(node, (str, OpenMaya.MObject)): 65 | if isinstance(node, str): 66 | node = get_object(node) 67 | if not node.hasFn(OpenMaya.MFn.kDagNode): 68 | return node 69 | return get_path(node) 70 | elif isinstance(node, OpenMaya.MDagPath): 71 | return node 72 | else: 73 | raise RuntimeError(f"Argument must be a str, MObject or MDagPath not {type(node)} !") 74 | 75 | 76 | def name(node: Union[OpenMaya.MObject, OpenMaya.MDagPath], 77 | full: bool = True, namespace: bool = True): 78 | if isinstance(node, OpenMaya.MDagPath): 79 | return node.fullPathName() 80 | elif isinstance(node, OpenMaya.MPlug): 81 | return f"{name_of(node.node())}.{OpenMaya.MFnAttribute(node.attribute()).name()}" 82 | elif isinstance(node, OpenMaya.MObject): 83 | if not node.hasFn(OpenMaya.MFn.kDagNode) or not full: 84 | s_node = OpenMaya.MFnDependencyNode(node).name() 85 | else: 86 | s_node = OpenMaya.MFnDagNode(node).fullPathName() 87 | return s_node if namespace is True else s_node.split(":")[-1] 88 | else: 89 | raise TypeError(f"Argument must be a MObject or MDagPath not {type(node)}") 90 | 91 | 92 | def dependency_iterator(node: cst.kdagType, mfn_type: int, 93 | direction: int = OpenMaya.MItDependencyGraph.kUpstream, 94 | traversal: int = OpenMaya.MItDependencyGraph.kDepthFirst, 95 | level: int = OpenMaya.MItDependencyGraph.kNodeLevel) -> OpenMaya.MItDependencyGraph: 96 | if isinstance(node, str): 97 | node = get_object(node) 98 | if isinstance(node, OpenMaya.MDagPath): 99 | node = node.node() 100 | 101 | return OpenMaya.MItDependencyGraph(node, mfn_type, direction, traversal, level) 102 | 103 | 104 | def matrix_of(node: cst.kdagType, 105 | exclusive: bool = False, inverse: bool = False, world: bool = True, 106 | time: OpenMaya.MTime = None) -> OpenMaya.MMatrix: 107 | if isinstance(node, (str, OpenMaya.MObject)): 108 | node = get_path(node) 109 | 110 | if time is not None: 111 | om_context = OpenMaya.MDGContext(time) 112 | om_context_guard = OpenMaya.MDGContextGuard(om_context) 113 | 114 | if world: 115 | if inverse: 116 | return node.exclusiveMatrixInverse() if exclusive else node.inclusiveMatrixInverse() 117 | return node.exclusiveMatrix() if exclusive else node.inclusiveMatrix() 118 | else: 119 | mfn = OpenMaya.MFnTransform(node) 120 | return mfn.transformation().asMatrixInverse() if inverse else mfn.transformation().asMatrix() 121 | 122 | 123 | def get_rotation_limits(node: cst.kdagType) -> list: 124 | output = [] 125 | mfn = OpenMaya.MFnTransform(get_node(node)) 126 | for min_limit, max_limit in zip(kMinRotLimits, kMaxRotLimits): 127 | min_value = mfn.limitValue(min_limit) if mfn.isLimited(min_limit) else -360 128 | max_value = mfn.limitValue(max_limit) if mfn.isLimited(max_limit) else 360 129 | output.append([math.degrees(min_value), math.degrees(max_value)]) 130 | 131 | return output 132 | 133 | 134 | def array_from_matrix(matrix: OpenMaya.MMatrix) -> list: 135 | """!@Brief Transform maya matrix to float array.""" 136 | if not isinstance(matrix, (OpenMaya.MMatrix, OpenMaya.MFloatMatrix)): 137 | raise TypeError("Invalid argument type given !") 138 | return [matrix(i, j) for i in range(4) for j in range(4)] 139 | 140 | 141 | def get_current_time() -> OpenMaya.MTime: 142 | return OpenMayaAnim.MAnimControl().currentTime() 143 | 144 | 145 | def start_frame() -> float: 146 | return cmds.playbackOptions(query=True, minTime=True) 147 | 148 | 149 | def end_frame() -> float: 150 | return cmds.playbackOptions(query=True, maxTime=True) 151 | 152 | 153 | def go_to_start_frame(): 154 | set_current_time(start_frame()) 155 | 156 | 157 | def time_line_range(start: float = None, end: float = None) -> range: 158 | start = start_frame() if start is None else start 159 | end = end_frame() if end is None else end 160 | return range(int(math.floor(start)), int(math.ceil(end)) + 1) 161 | 162 | 163 | def set_time_line(start: float = None, end: float = None): 164 | cmds.playbackOptions(edit=True, animationStartTime=start) 165 | cmds.playbackOptions(edit=True, minTime=start) 166 | cmds.playbackOptions(edit=True, animationEndTime=end) 167 | cmds.playbackOptions(edit=True, maxTime=end) 168 | 169 | 170 | def set_current_time(time: Union[int, float, OpenMaya.MTime]) -> OpenMaya.MTime: 171 | if isinstance(time, OpenMaya.MTime): 172 | time = time.value() 173 | 174 | current_time = get_current_time() 175 | cmds.currentTime(time) 176 | 177 | return current_time 178 | 179 | 180 | def get_points(shape: cst.kdagType, world: bool = True, vertex_ids: list = None) -> OpenMaya.MPointArray: 181 | if isinstance(shape, (str, OpenMaya.MObject)): 182 | shape = get_path(shape) 183 | 184 | points = OpenMaya.MPointArray() 185 | mfn = OpenMaya.MFnMesh(shape) 186 | space = OpenMaya.MSpace.kWorld if world else OpenMaya.MSpace.kObject 187 | 188 | if not vertex_ids: 189 | mfn.getPoints(points, space) 190 | else: 191 | points.setLength(len(vertex_ids)) 192 | point = OpenMaya.MPoint() 193 | for i, vertex_id in enumerate(vertex_ids): 194 | mfn.getPoint(vertex_id, point, space) 195 | points.set(point, i) 196 | 197 | return points 198 | -------------------------------------------------------------------------------- /maya/core/constant.py: -------------------------------------------------------------------------------- 1 | # coding=ascii 2 | 3 | from typing import Union 4 | 5 | from maya import OpenMaya 6 | 7 | 8 | kdagType = Union[str, OpenMaya.MObject, OpenMaya.MDagPath] 9 | kdepType = Union[str, OpenMaya.MObject] 10 | kNodeName = "fdda" -------------------------------------------------------------------------------- /maya/core/context.py: -------------------------------------------------------------------------------- 1 | from maya import cmds 2 | 3 | from fdda.maya.core import api_utils 4 | from fdda.core.context import ContextDecorator 5 | 6 | 7 | class KeepCurrentFrame(ContextDecorator): 8 | 9 | def __init__(self): 10 | super().__init__() 11 | self._current_frame = None 12 | 13 | def __enter__(self): 14 | if self._current_frame is None: 15 | self._current_frame = api_utils.get_current_time() 16 | 17 | def __exit__(self, *args): 18 | api_utils.set_current_time(self._current_frame) 19 | self._current_frame = None 20 | 21 | 22 | class DisableRefresh(ContextDecorator): 23 | 24 | def __enter__(self): 25 | cmds.refresh(suspend=True) 26 | 27 | def __exit__(self, *args): 28 | cmds.refresh(suspend=False) 29 | -------------------------------------------------------------------------------- /maya/core/data.py: -------------------------------------------------------------------------------- 1 | # coding=ascii 2 | 3 | from maya import OpenMaya 4 | 5 | import numpy as np 6 | 7 | from fdda.core.logger import log 8 | from fdda.maya.core import api_utils 9 | from fdda.maya.core.skin import Skin 10 | from fdda.maya.core.context import KeepCurrentFrame, DisableRefresh 11 | 12 | 13 | class BaseData: 14 | 15 | def __init__(self, *args, **kwargs): 16 | pass 17 | 18 | def __str__(self) -> str: 19 | return self.__repr__() 20 | 21 | def __repr__(self) -> str: 22 | return f"FDDA(class: {self.__class__.__name__})" 23 | 24 | 25 | class SkinData(BaseData): 26 | 27 | def __init__(self): 28 | self.skin = Skin() 29 | self.weight_map = list() 30 | self.joint_map = list() 31 | self.n_verts = 0 32 | 33 | def clear(self): 34 | self.skin = Skin() 35 | self.weight_map = list() 36 | self.joint_map = list() 37 | self.n_verts = 0 38 | 39 | def get(self, mesh_path: OpenMaya.MDagPath): 40 | self.clear() 41 | 42 | self.skin = Skin.find(mesh_path) 43 | if not self.skin: 44 | raise RuntimeError(f"No skin cluster found on {mesh_path.fullPathName()} !") 45 | 46 | inf_count = self.skin.influences_count() 47 | weights = [self.skin.weights[i] for i in range(self.skin.weights.length())] 48 | self.weight_map = list() 49 | self.joint_map = [list() for _ in range(inf_count)] 50 | self.n_verts = OpenMaya.MFnMesh(self.skin.shape).numVertices() 51 | 52 | for vtx in range(OpenMaya.MFnMesh(self.skin.shape).numVertices()): 53 | vtx_weights = weights[vtx * inf_count: (vtx * inf_count) + inf_count] 54 | i_max = np.argmax(np.array(vtx_weights)) 55 | self.weight_map.append(vtx_weights[i_max]) 56 | self.joint_map[i_max].append(vtx) 57 | 58 | 59 | class MeshData(BaseData): 60 | 61 | def __init__(self): 62 | self.frame_data = dict() 63 | self.skin_data = SkinData() 64 | 65 | def clear(self): 66 | self.frame_data = dict() 67 | self.skin_data.clear() 68 | 69 | @KeepCurrentFrame() 70 | @DisableRefresh() 71 | def get(self, source: OpenMaya.MDagPath, destination: OpenMaya.MDagPath, start: float = None, end: float = None): 72 | """!@Brief: Build data from a maya scene. Input: Joint quaternion and translation vector and delta between 73 | source and destination object.""" 74 | self.clear() 75 | self.skin_data.get(destination) 76 | 77 | inf_names = self.skin_data.skin.influences_names 78 | self.frame_data = {jnt: list() for jnt in inf_names} 79 | 80 | for frame in api_utils.time_line_range(start=start, end=end): 81 | log.info(f"Processing frame: {frame}") 82 | api_utils.set_current_time(frame) 83 | 84 | source_pts = api_utils.get_points(source) 85 | destination_pts = api_utils.get_points(destination) 86 | if source_pts.length() != destination_pts.length(): 87 | raise RuntimeError("Mismatch number of points between source and destination mesh !") 88 | 89 | for jnt_id, vertices in enumerate(self.skin_data.joint_map): 90 | jnt = inf_names[jnt_id] 91 | 92 | # Conversion homogenous transformation matrix (4x4) to quaternion and translation vector 93 | local_mat = api_utils.matrix_of(jnt, world=False) 94 | transform = OpenMaya.MTransformationMatrix(local_mat) 95 | q = transform.rotation() 96 | 97 | data = [q.x, q.y, q.z, q.w] 98 | 99 | for vtx_id in vertices: 100 | delta = source_pts[vtx_id] - destination_pts[vtx_id] 101 | data.extend([delta.x, delta.y, delta.z]) 102 | self.frame_data[jnt].append(data) -------------------------------------------------------------------------------- /maya/core/deformer.py: -------------------------------------------------------------------------------- 1 | # coding=ascii 2 | from typing import Union 3 | 4 | from maya import cmds, OpenMaya, OpenMayaAnim 5 | 6 | from fdda.maya.core import api_utils 7 | 8 | 9 | class Deformer(object): 10 | 11 | def __init__(self, node: Union[str, OpenMaya.MObject] = None): 12 | self._object = None 13 | self.mfn = None 14 | self.shape = None 15 | 16 | if node: 17 | self.__get(node) 18 | 19 | def __str__(self) -> str: 20 | return self.__repr__() 21 | 22 | def __repr__(self) -> str: 23 | return f"FDDA(class: {self.__class__.__name__})" 24 | 25 | @property 26 | def object(self) -> OpenMaya.MObject: 27 | return self._object 28 | 29 | @object.setter 30 | def object(self, value: Union[str, OpenMaya.MObject]): 31 | self.__get(value) 32 | 33 | def __get_shape(self): 34 | output_geom = self.outputs_geometry() 35 | if output_geom.length() == 0: 36 | raise RuntimeError(f"No output shape found on {api_utils.name(self.object)}") 37 | elif output_geom.length() > 1: 38 | raise RuntimeError(f"Multi shape found on {api_utils.name(self.object)}") 39 | 40 | return self.outputs_geometry()[0] 41 | 42 | @property 43 | def deformer_name(self) -> str: 44 | return api_utils.name(self.object) if self.object else "" 45 | 46 | def shape_name(self) -> str: 47 | return api_utils.name(self.shape) if self.shape else "" 48 | 49 | def __get(self, node): 50 | if isinstance(node, str): 51 | node = api_utils.get_object(node) 52 | 53 | self._object = node 54 | self.mfn = OpenMayaAnim.MFnGeometryFilter(node) 55 | self.shape = self.__get_shape() 56 | 57 | def outputs_geometry(self) -> OpenMaya.MObjectArray: 58 | output = OpenMaya.MObjectArray() 59 | self.mfn.getOutputGeometry(output) 60 | 61 | # It's possible "getOutputGeometry" don't return shape. 62 | # If no shape found check connection 63 | if output.length() == 0: 64 | out_geom_plug = self.mfn.findPlug("outputGeometry", False) 65 | out_plugs = OpenMaya.MPlugArray() 66 | out_geom_plug.destinations(out_plugs) 67 | for i in range(out_plugs.length()): 68 | output.append(out_plugs[i].node()) 69 | 70 | return output 71 | 72 | def inputs_geometry(self) -> OpenMaya.MObjectArray: 73 | output = OpenMaya.MObjectArray() 74 | self.mfn.getInputGeometry(output) 75 | 76 | return output 77 | 78 | @classmethod 79 | def is_deformer(cls, node: OpenMaya.MObject): 80 | if isinstance(node, str): 81 | node = api_utils.get_object(node) 82 | 83 | return node.hasFn(OpenMaya.MFn.kGeometryFilt) 84 | 85 | @classmethod 86 | def _find(cls, node: Union[str, OpenMaya.MObject, OpenMaya.MDagPath], 87 | mfn_type: int) -> Union[OpenMaya.MObject, OpenMaya.MObjectArray, None]: 88 | if isinstance(node, str): 89 | node = api_utils.get_object(node) 90 | # If node is transform, retrieve shape 91 | node_to_parse = node 92 | if node.hasFn(OpenMaya.MFn.kTransform): 93 | mfn_node = OpenMaya.MFnTransform(node) 94 | for i in range(mfn_node.childCount()): 95 | child = mfn_node.child(i) 96 | if child.hasFn(OpenMaya.MFn.kShape): 97 | child_name = api_utils.name(child) 98 | if cmds.getAttr(f"{child_name}.intermediateObject"): 99 | continue 100 | node_to_parse = child 101 | break 102 | # Parse graph 103 | iterator = api_utils.dependency_iterator(node_to_parse, mfn_type) 104 | output = OpenMaya.MObjectArray() 105 | while not iterator.isDone(): 106 | output.append(iterator.currentItem()) 107 | iterator.next() 108 | 109 | if output.length() == 1: 110 | return output[0] 111 | else: 112 | return output 113 | -------------------------------------------------------------------------------- /maya/core/skin.py: -------------------------------------------------------------------------------- 1 | # coding=ascii 2 | from typing import Union 3 | 4 | from maya import cmds, OpenMaya, OpenMayaAnim 5 | 6 | from fdda.core.logger import log 7 | from fdda.maya.core import api_utils 8 | from fdda.maya.core.deformer import Deformer 9 | from fdda.maya.core import constant as cst 10 | 11 | 12 | class Skin(Deformer): 13 | 14 | kType = 'skinCluster' 15 | kApiType = OpenMaya.MFn.kSkinClusterFilter 16 | 17 | kSkinningMethod = "skinningMethod" 18 | kUseComponents = "useComponents" 19 | kDeformUserNormals = 'deformUserNormals' 20 | kDqsSupportNonRigid = 'dqsSupportNonRigid' 21 | kDqsScale = 'dqsScale' 22 | kNormalizeWeights = 'normalizeWeights' 23 | kWeightDistribution = 'weightDistribution' 24 | kMaxInfluences = "maxInfluences" 25 | kMaintainMaxInfluences = "maintainMaxInfluences" 26 | 27 | # Rotation limits 28 | kRotateMinX = OpenMaya.MFnTransform.kRotateMinX 29 | kRotateMaxX = OpenMaya.MFnTransform.kRotateMaxX 30 | kRotateMinY = OpenMaya.MFnTransform.kRotateMinY 31 | kRotateMaxY = OpenMaya.MFnTransform.kRotateMaxY 32 | kRotateMinZ = OpenMaya.MFnTransform.kRotateMinZ 33 | kRotateMaxZ = OpenMaya.MFnTransform.kRotateMaxZ 34 | 35 | def __init__(self, node: Union[str, OpenMaya.MObject] = None, weights: bool = True): 36 | super(Skin, self).__init__(node=node) 37 | 38 | self.skinning_method = 0 39 | self.use_components = False 40 | self.deform_user_normals = True 41 | self.dqs_support_non_rigid = False 42 | self.dqs_scale = [1.0, 1.0, 1.0] 43 | self.normalize_weights = 1 44 | self.weight_distribution = 0 45 | self.max_influences = 8 46 | self.maintain_max_influences = True 47 | 48 | self.influences_ids = [] 49 | self.influences_names = [] 50 | self.weights = [] 51 | 52 | if node: 53 | self.__get(weights=weights) 54 | 55 | def influences_count(self) -> int: 56 | return len(self.influences_ids) 57 | 58 | def __get(self, weights: bool = True): 59 | self.mfn = OpenMayaAnim.MFnSkinCluster(self.object) 60 | self.__get_attributes() 61 | self.__get_influences() 62 | if weights: 63 | self.__get_weights() 64 | 65 | def __get_attributes(self): 66 | name = self.deformer_name 67 | 68 | self.skinning_method = cmds.getAttr(f"{name}.{self.kSkinningMethod}") 69 | self.use_components = cmds.getAttr(f"{name}.{self.kUseComponents}") 70 | self.deform_user_normals = cmds.getAttr(f"{name}.{self.kDeformUserNormals}") 71 | self.dqs_support_non_rigid = cmds.getAttr(f"{name}.{self.kDqsSupportNonRigid}") 72 | self.dqs_scale = cmds.getAttr(f"{name}.{self.kDqsScale}") 73 | self.normalize_weights = cmds.getAttr(f"{name}.{self.kNormalizeWeights}") 74 | self.weight_distribution = cmds.getAttr(f"{name}.{self.kWeightDistribution}") 75 | self.max_influences = cmds.getAttr(f"{name}.{self.kMaxInfluences}") 76 | self.maintain_max_influences = cmds.getAttr(f"{name}.{self.kMaintainMaxInfluences}") 77 | 78 | def __get_influences(self): 79 | self.influences_ids = [] 80 | self.influences_names = [] 81 | self.influences_len = None 82 | 83 | try: 84 | influences = OpenMaya.MDagPathArray() 85 | influences_count = self.mfn.influenceObjects(influences) 86 | self.influences_len = OpenMaya.MScriptUtil(influences.length()) 87 | 88 | for i in range(influences_count): 89 | dp_node = influences[i] 90 | if dp_node.fullPathName() in self.influences_names: 91 | continue 92 | self.influences_ids.append(self.mfn.indexForInfluenceObject(dp_node)) 93 | self.influences_names.append(dp_node.fullPathName()) 94 | except Exception as e: 95 | log.debug(e) 96 | 97 | def __get_weights(self): 98 | component = self.__get_shape_component() 99 | inf_count_ptr = self.influences_len.asUintPtr() 100 | self.weights = OpenMaya.MDoubleArray() 101 | shape_path = api_utils.get_path(self.shape) 102 | self.mfn.getWeights(shape_path, component, self.weights, inf_count_ptr) 103 | 104 | def set_weights(self, weights: Union[list, tuple, OpenMaya.MDoubleArray] = None) -> OpenMaya.MDoubleArray: 105 | if not self.object: 106 | raise Exception("No SkinCluster set !") 107 | 108 | component = self.__get_shape_component() 109 | 110 | if isinstance(weights, (list, tuple)): 111 | tmp = OpenMaya.MDoubleArray() 112 | for w in weights: 113 | tmp.append(w) 114 | weights = tmp 115 | 116 | if weights is not None: 117 | self.weights = weights 118 | 119 | influence_ids = OpenMaya.MIntArray() 120 | for inf_id in self.influences_ids: 121 | influence_ids.append(inf_id) 122 | 123 | old_weights = OpenMaya.MDoubleArray() 124 | shape_path = api_utils.get_path(self.shape) 125 | self.mfn.setWeights(shape_path, component, influence_ids, self.weights, False, old_weights) 126 | 127 | return old_weights 128 | 129 | def __get_shape_component(self) -> OpenMaya.MObject: 130 | if self.shape.hasFn(OpenMaya.MFn.kMesh): 131 | mfn = OpenMaya.MFnSingleIndexedComponent() 132 | component = mfn.create(OpenMaya.MFn.kMeshVertComponent) 133 | mit = OpenMaya.MItMeshVertex(self.shape) 134 | while not mit.isDone(): 135 | mfn.addElement(mit.index()) 136 | mit.next() 137 | else: 138 | raise RuntimeError(f"Invalid shape type: self._shape.apiTypeStr() !") 139 | 140 | return component 141 | 142 | @classmethod 143 | def find(cls, node: cst.kdepType) -> "Skin": 144 | if isinstance(node, str): 145 | node = api_utils.get_object(node) 146 | 147 | skin_node = Deformer._find(node, cls.kApiType) 148 | if not node: 149 | raise RuntimeError(f"No skin cluster found on {api_utils.name(node)} !") 150 | 151 | return cls(skin_node) 152 | -------------------------------------------------------------------------------- /maya/nodes/Proto/fddaDeformerNode.py: -------------------------------------------------------------------------------- 1 | # coding=ascii 2 | 3 | import numpy as np 4 | 5 | from maya import OpenMaya, OpenMayaMPx 6 | 7 | from fdda.core.logger import log 8 | from fdda.training.PyTorch.loader import Loader 9 | from fdda.training.PyTorch.architecture import get_prediction 10 | from fdda.maya.core import constant as maya_cst 11 | 12 | 13 | class FDDADeformerNode(OpenMayaMPx.MPxDeformerNode): 14 | 15 | kNodeName = maya_cst.kNodeName 16 | kNodeID = OpenMaya.MTypeId(0x0012d5c1) 17 | 18 | DATA_LOCATION = OpenMaya.MObject() 19 | IN_MATRICES = OpenMaya.MObject() 20 | 21 | def __init__(self, *args): 22 | super(FDDADeformerNode, self).__init__(*args) 23 | 24 | self._loader = Loader() 25 | self._location_changed = True 26 | 27 | def __str__(self) -> str: 28 | return self.__repr__() 29 | 30 | def __repr__(self) -> str: 31 | return f"FDDA(class: {self.__class__.__name__})" 32 | 33 | @classmethod 34 | def creator(cls): 35 | return OpenMayaMPx.asMPxPtr(cls()) 36 | 37 | @classmethod 38 | def initialize(cls): 39 | in_attrs = list() 40 | out_attrs = list() 41 | 42 | # Inputs 43 | td_attr = OpenMaya.MFnTypedAttribute() 44 | cls.DATA_LOCATION = td_attr.create("trainingData", "ta", OpenMaya.MFnData.kString) 45 | td_attr.setHidden(False) 46 | td_attr.setKeyable(True) 47 | in_attrs.append(cls.DATA_LOCATION) 48 | 49 | m_attr = OpenMaya.MFnMatrixAttribute() 50 | cls.IN_MATRICES = m_attr.create("matrix", "mat") 51 | m_attr.setKeyable(True) 52 | m_attr.setArray(True) 53 | in_attrs.append(cls.IN_MATRICES) 54 | 55 | # Manage attributes 56 | for attribute in (in_attrs + out_attrs): 57 | cls.addAttribute(attribute) 58 | 59 | # Set the attribute dependencies 60 | for out_attr in out_attrs: 61 | for in_attr in in_attrs: 62 | cls.attributeAffects(in_attr, out_attr) 63 | 64 | @classmethod 65 | def __get_envelope(cls, data: OpenMaya.MDataBlock) -> float: 66 | return data.inputValue(OpenMayaMPx.cvar.MPxGeometryFilter_envelope).asFloat() 67 | 68 | def __get_matrices(self, data: OpenMaya.MDataBlock, num_models: int) -> list: 69 | matrices = list() 70 | 71 | matrices_handle = data.inputArrayValue(self.IN_MATRICES) 72 | matrix_count = matrices_handle.elementCount() 73 | # In local mode, we need to have the same number of joints and models. 74 | if matrix_count > num_models and not self._loader.global_mode: 75 | log.error("More input joints than models ! ({} joints and {} models.".format(matrix_count, num_models)) 76 | return matrices 77 | 78 | for i in range(matrix_count): 79 | matrices_handle.jumpToElement(i) 80 | matrix_handle = matrices_handle.inputValue() 81 | 82 | # Conversion homogenous transformation matrix (4x4) to quaternion and translation vector 83 | transform = OpenMaya.MTransformationMatrix(matrix_handle.asMatrix()) 84 | q = transform.rotation() 85 | matrices.append(np.array([q.x, q.y, q.z, q.w], dtype=np.float32)) 86 | 87 | if self._loader.global_mode: 88 | matrices = [np.concatenate(matrices)] 89 | 90 | return matrices 91 | 92 | def __get_deltas(self, iterator: OpenMaya.MItGeometry, matrices: list) -> np.array: 93 | deltas = np.zeros(3 * iterator.count()) 94 | 95 | for i in range(len(matrices)): 96 | # Some joints don"t have a model in the json so skip them. 97 | model = self._loader.models[i] 98 | mean = self._loader.means[i] 99 | std = self._loader.stds[i] 100 | if not model: 101 | continue 102 | 103 | prediction = get_prediction(model, matrices[i], mean, std, 104 | normalized=self._loader.normalized, 105 | device=self._loader.device) 106 | 107 | for j, vtx in enumerate(model.vertices): 108 | deltas[vtx * 3:(vtx * 3) + 3] = prediction[j * 3:(j * 3) + 3] 109 | 110 | return deltas 111 | 112 | def __apply_deltas(self, deltas: list, envelope: float, 113 | iterator: OpenMaya.MItGeometry, 114 | data: OpenMaya.MDataBlock, geom_id: int): 115 | while not iterator.isDone(): 116 | index = iterator.index() 117 | pos = iterator.position() 118 | weight = self.weightValue(data, geom_id, index) 119 | 120 | delta = deltas[index * 3:(index * 3) + 3] 121 | delta = [d * envelope * weight for d in delta] 122 | pos.x += delta[0] 123 | pos.y += delta[1] 124 | pos.z += delta[2] 125 | 126 | iterator.setPosition(pos) 127 | iterator.next() 128 | 129 | def deform(self, data: OpenMaya.MDataBlock, 130 | iterator: OpenMaya.MItGeometry, 131 | matrix: OpenMaya.MMatrix, geom_id: int): 132 | 133 | if self.location_changed: 134 | file_path = data.inputValue(self.DATA_LOCATION).asString() 135 | if not self._loader.load(file_path): 136 | return 137 | self.location_changed = False 138 | 139 | if self._loader.model_count == 0: 140 | log.error("No model found !") 141 | return 142 | 143 | envelope = self.__get_envelope(data) 144 | matrices = self.__get_matrices(data, self._loader.model_count) 145 | deltas = self.__get_deltas(iterator, matrices) 146 | self.__apply_deltas(deltas, envelope, iterator, data, geom_id) 147 | 148 | # noinspection PyPep8Naming 149 | def preEvaluation(self, context, evaluation_node) -> None: 150 | """!@Brief Check if certain values have changed to cause a recache""" 151 | if evaluation_node.dirtyPlugExists(FDDADeformerNode.DATA_LOCATION): 152 | self.location_changed = True 153 | return super(FDDADeformerNode, self).preEvaluation(context, evaluation_node) 154 | 155 | # noinspection PyPep8Naming 156 | def setDependentsDirty(self, plug, plug_array) -> None: 157 | """!@Brief Check if certain values have changed to cause a recache""" 158 | if plug == FDDADeformerNode.DATA_LOCATION: 159 | self.location_changed = True 160 | return super(FDDADeformerNode, self).setDependentsDirty(plug, plug_array) 161 | 162 | 163 | # noinspection PyPep8Naming 164 | def initializePlugin(plugin): 165 | plugin = OpenMayaMPx.MFnPlugin(plugin, "QuanticDream", "1.0") 166 | try: 167 | plugin.registerNode(FDDADeformerNode.kNodeName, 168 | FDDADeformerNode.kNodeID, 169 | FDDADeformerNode.creator, 170 | FDDADeformerNode.initialize, 171 | OpenMayaMPx.MPxNode.kDeformerNode) 172 | except Exception: 173 | raise RuntimeError(f"Failed to register node: {FDDADeformerNode.kNodeName}") 174 | 175 | 176 | # noinspection PyPep8Naming 177 | def uninitializePlugin(plugin): 178 | plugin = OpenMayaMPx.MFnPlugin(plugin) 179 | try: 180 | plugin.deregisterNode(FDDADeformerNode.kNodeID) 181 | except Exception: 182 | raise RuntimeError(f"Failed to unregister node: {FDDADeformerNode.kNodeName}") 183 | -------------------------------------------------------------------------------- /maya/nodes/fddaNode.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | Win32Proj 24 | {4ee3e49e-5127-4513-8e2b-b5b54e6850d8} 25 | fddaNode 26 | 10.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v143 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v143 39 | true 40 | Unicode 41 | 42 | 43 | DynamicLibrary 44 | true 45 | v143 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v143 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | .mll 75 | 76 | 77 | 78 | Level3 79 | true 80 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 81 | true 82 | 83 | 84 | Console 85 | true 86 | 87 | 88 | 89 | 90 | Level3 91 | true 92 | true 93 | true 94 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 95 | true 96 | 97 | 98 | Console 99 | true 100 | true 101 | true 102 | 103 | 104 | 105 | 106 | Level3 107 | true 108 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 109 | true 110 | D:\Work\Shared\ThirdParty\Maya2022\include;D:\Work\Shared\ThirdParty\libtorch\include;D:\Work\Shared\ThirdParty\libtorch\include\torch\csrc\api\include;D:\Work\Shared\ThirdParty\json\include;%(AdditionalIncludeDirectories) 111 | 112 | 113 | Console 114 | true 115 | D:\Work\Shared\ThirdParty\Maya2022\lib;D:\Work\Shared\ThirdParty\libtorch\lib;%(AdditionalIncludeDirectories) 116 | Foundation.lib;OpenMaya.lib;OpenMayaAnim.lib;$(CoreLibraryDependencies); 117 | 118 | 119 | 120 | 121 | Level3 122 | true 123 | true 124 | true 125 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 126 | true 127 | 128 | 129 | Console 130 | true 131 | true 132 | true 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | -------------------------------------------------------------------------------- /maya/nodes/sources/common.h: -------------------------------------------------------------------------------- 1 | #ifndef COMMON_H 2 | #define COMMON_H 3 | 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include 26 | #include 27 | 28 | #include "nlohmann/json.hpp" 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #include "settings.h" 35 | #include "multiLayerPerceptron.h" 36 | 37 | 38 | #endif -------------------------------------------------------------------------------- /maya/nodes/sources/fddaNode.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RDelet/FFDA/1525a5fd27aed938a439daa4812d1e20783b1eff/maya/nodes/sources/fddaNode.cpp -------------------------------------------------------------------------------- /maya/nodes/sources/fddaNode.h: -------------------------------------------------------------------------------- 1 | #ifndef FDDA_NODE_H 2 | #define FDDA_NODE_H 3 | 4 | 5 | #include "common.h" 6 | 7 | 8 | class FDDANode : public MPxDeformerNode { 9 | 10 | public: 11 | 12 | FDDANode() {} 13 | virtual ~FDDANode() {} 14 | virtual MStatus deform(MDataBlock& data, MItGeometry& itGeo, const MMatrix& localToWorldMatrix, unsigned int geomIndex); 15 | virtual MStatus preEvaluation(const MDGContext& context, const MEvaluationNode& evaluationNode); 16 | virtual MStatus setDependentsDirty(const MPlug& plugBeingDirtied, MPlugArray& affectedPlugs); 17 | static void* creator() { return new FDDANode(); } 18 | static MStatus initialize(); 19 | 20 | public: 21 | 22 | // Maya node data 23 | static MTypeId kNodeId; 24 | static MString kNodeName; 25 | static MPxNode::Type kNodeType; 26 | 27 | private: 28 | 29 | static float getEnveloppe(MDataBlock& data); 30 | static std::vector getRotations(MDataBlock& data, unsigned int numModels); 31 | static void clear(); 32 | static void loadModel(MDataBlock& data); 33 | static void readModel(); 34 | static TorchModel deserializeModel(const int& modelID, MDataBlock& data, nlohmann::json& model); 35 | static void getPredition(); 36 | static std::vector getDeltas(MItGeometry& itGeo); 37 | static void applyDeltas(MDataBlock& data, const std::vector& deltas, const float deformerEnveloppe, MItGeometry& itGeo, unsigned int geomIndex); 38 | 39 | // Node attributes 40 | static MObject iTrainingData; 41 | static MObject iMatrix; 42 | 43 | // data 44 | static std::string dataLocation; 45 | static bool locationChanged; 46 | static nlohmann::json modelData; 47 | static std::vector models; 48 | static std::vector> means; 49 | static std::vector> stds; 50 | static at::Device device; 51 | static bool normalized; 52 | static bool globaMode; 53 | 54 | // Json keys 55 | static std::string kModels; 56 | static std::string kJointMap; 57 | static std::string kModel; 58 | static std::string kBestModel; 59 | static std::string kDevice; 60 | static std::string kMean; 61 | static std::string kStd; 62 | static std::string kNormalized; 63 | static std::string kGlobalMode; 64 | 65 | static std::string kTrainingDataLong; 66 | static std::string kTrainingDataShort; 67 | static std::string kMatrixLong; 68 | static std::string kMatrixShort; 69 | 70 | static nlohmann::json jsonRoot; 71 | 72 | }; 73 | 74 | #endif -------------------------------------------------------------------------------- /maya/nodes/sources/multiLayerPerceptron.h: -------------------------------------------------------------------------------- 1 | #ifndef MULTI_LAYER_PERCEPTRON_H 2 | #define MULTI_LAYER_PERCEPTRON_H 3 | 4 | #include "common.h" 5 | #include "settings.h" 6 | 7 | 8 | class MultiLayerPerceptron : torch::nn::Module { 9 | 10 | public: 11 | MultiLayerPerceptron(); 12 | MultiLayerPerceptron(Settings& _settings, MPointArray& _inputShape, MPointArray& _outputShape) { 13 | 14 | std::vector layers; 15 | if (_settings.layers < 2) { 16 | MGlobal::displayWarning("A minimum of 2 layers is required."); 17 | _settings.layers = 2; 18 | } 19 | 20 | for (int i = 0; i < _settings.layers; i++) { 21 | if (layers.size() == 0) { 22 | torch::nn::Linear pouet = torch::nn::Linear(_inputShape[0], _settings.units); 23 | layers.push_back(pouet); 24 | /* 25 | if (_settings.activation == kLinear) { 26 | layers.push_back(_settings.activation); 27 | } 28 | */ 29 | continue; 30 | } 31 | 32 | if (layers.size() == _settings.layers - 1) { 33 | torch::nn::Linear groot = torch::nn::Linear(_settings.units, _outputShape[0]); 34 | layers.push_back(groot); 35 | continue; 36 | } 37 | 38 | torch::nn::Linear kapouet = torch::nn::Linear(_settings.units, _settings.units); 39 | layers.push_back(kapouet); 40 | /* 41 | if (_settings.activation == kLinear) { 42 | layers.push_back(_settings.activation); 43 | } 44 | */ 45 | } 46 | 47 | net = torch::nn::Sequential(layers); 48 | 49 | } 50 | virtual ~MultiLayerPerceptron() {} 51 | 52 | void forward(torch::Tensor& x) { net(x); } 53 | 54 | public: 55 | 56 | torch::nn::Sequential net; 57 | 58 | }; 59 | 60 | 61 | struct TorchModel { 62 | 63 | MultiLayerPerceptron model = MultiLayerPerceptron(); 64 | std::vector vertices = std::vector(); 65 | 66 | }; 67 | 68 | 69 | #endif -------------------------------------------------------------------------------- /maya/nodes/sources/plugin.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RDelet/FFDA/1525a5fd27aed938a439daa4812d1e20783b1eff/maya/nodes/sources/plugin.cpp -------------------------------------------------------------------------------- /maya/nodes/sources/settings.h: -------------------------------------------------------------------------------- 1 | #ifndef SETTINGS_H 2 | #define SETTINGS_H 3 | 4 | 5 | #include "common.h" 6 | 7 | enum Actication { 8 | 9 | kSigmoid = 0, 10 | kTanH, 11 | kSoftmax, 12 | kElu, 13 | kLeakyRelu, 14 | kLinear, 15 | k = kSigmoid 16 | 17 | }; 18 | 19 | 20 | enum Architecture { 21 | 22 | kDense = 0, 23 | 24 | }; 25 | 26 | 27 | enum Device { 28 | 29 | CPU = 0, 30 | GPU = 1 31 | 32 | }; 33 | 34 | 35 | class Settings { 36 | 37 | public: 38 | 39 | Settings() : 40 | rate(1e-3), 41 | epochs(800), split(0.3), 42 | batchSize(32), 43 | shuffle(true), 44 | units(512), 45 | inputDim(100), 46 | layers(4), 47 | earlyStop(20), 48 | architecture(kDense), 49 | activation(kElu), 50 | device(GPU) {} 51 | virtual ~Settings() {} 52 | 53 | public: 54 | float rate; 55 | int epochs; 56 | float split; 57 | int batchSize; 58 | bool shuffle; 59 | int units; 60 | int inputDim; 61 | int layers; 62 | int earlyStop; 63 | Architecture architecture; 64 | Actication activation; 65 | Device device; 66 | 67 | }; 68 | 69 | #endif -------------------------------------------------------------------------------- /maya/poseGenerator.py: -------------------------------------------------------------------------------- 1 | import json 2 | import numpy as np 3 | import os 4 | 5 | from maya import cmds 6 | 7 | from fdda import kBipedLimitsPath 8 | from fdda.maya.core import api_utils 9 | from fdda.maya.core.context import KeepCurrentFrame, DisableRefresh 10 | from fdda.maya.core.skin import Skin 11 | 12 | 13 | class PoseGenerator: 14 | 15 | def __init__(self, mesh: str): 16 | self._mesh = api_utils.get_node(mesh) 17 | self._skin = Skin.find(self._mesh) 18 | 19 | def __str__(self) -> str: 20 | return self.__repr__() 21 | 22 | def __repr__(self) -> str: 23 | return f"FDDA(class: {self.__class__.__name__})" 24 | 25 | @property 26 | def skin(self) -> Skin: 27 | return self._skin 28 | 29 | def _get_pose_data(self, data_path: str = None) -> np.array: 30 | data = {} 31 | if data_path and os.path.exists(data_path): 32 | with open(data_path, "r") as stream: 33 | data = json.load(stream) 34 | 35 | ranges = [] 36 | for inf in self._skin.influences_names: 37 | short_name = inf.split("|")[-1].split(":")[-1] 38 | ranges.append(data.get(short_name, api_utils.get_rotation_limits(inf))) 39 | 40 | return np.array(ranges, dtype=np.float32) 41 | 42 | def _get_random_rotation(self, samples: int, data_path: str = None): 43 | ranges = self._get_pose_data(data_path) 44 | return np.random.uniform(low=ranges[:, :, 0], 45 | high=ranges[:, :, 1], 46 | size=(samples, self.skin.influences_count(), 3)) 47 | 48 | @DisableRefresh() 49 | @KeepCurrentFrame() 50 | def generate(self, samples: int, data_path: str = kBipedLimitsPath): 51 | """!@Brief Generate and apply on the source mesh a set of N random rotations per joint.""" 52 | random_rotation = self._get_random_rotation(samples, data_path) 53 | api_utils.set_time_line(0, samples) 54 | frame = api_utils.start_frame() 55 | for rot in random_rotation: 56 | for i, joint_name in enumerate(self.skin.influences_names): 57 | cmds.currentTime(frame) 58 | cmds.rotate(rot[i][0], rot[i][1], rot[i][2], joint_name) 59 | cmds.setKeyframe(joint_name) 60 | frame += 1 61 | -------------------------------------------------------------------------------- /maya/scenes/CylinderTest.ma: -------------------------------------------------------------------------------- 1 | //Maya ASCII 2022 scene 2 | //Name: CylinderTest_bis.ma 3 | //Last modified: Fri, Sep 22, 2023 03:21:09 PM 4 | //Codeset: 1252 5 | requires maya "2022"; 6 | requires "stereoCamera" "10.0"; 7 | requires -nodeType "aiOptions" -nodeType "aiAOVDriver" -nodeType "aiAOVFilter" "mtoa" "5.0.0.4"; 8 | currentUnit -linear centimeter -angle degree -time ntsc; 9 | fileInfo "application" "maya"; 10 | fileInfo "product" "Maya 2022"; 11 | fileInfo "version" "2022"; 12 | fileInfo "cutIdentifier" "202205171752-c25c06f306"; 13 | fileInfo "osv" "Windows 10 Enterprise v2009 (Build: 19044)"; 14 | fileInfo "UUID" "95ADE7AA-40ED-F2F9-8529-05A4EDDBBDCA"; 15 | createNode transform -shared -name "persp"; 16 | rename -uuid "D913A6CE-415F-9BE2-9565-D5B1208FC596"; 17 | setAttr ".visibility" no; 18 | setAttr ".translate" -type "double3" 2.0287733216073045 3.8533769125881552 19.218637119607585 ; 19 | setAttr ".rotate" -type "double3" -3.338352729617029 -366.59999999996222 5.0027712273576584e-17 ; 20 | createNode camera -shared -name "perspShape" -parent "persp"; 21 | rename -uuid "3AC59194-474F-39B9-D278-1EB3EB112607"; 22 | setAttr -keyable off ".visibility" no; 23 | setAttr ".focalLength" 34.999999999999993; 24 | setAttr ".centerOfInterest" 20.051860646638076; 25 | setAttr ".imageName" -type "string" "persp"; 26 | setAttr ".depthName" -type "string" "persp_depth"; 27 | setAttr ".maskName" -type "string" "persp_mask"; 28 | setAttr ".homeCommand" -type "string" "viewSet -p %camera"; 29 | createNode transform -shared -name "top"; 30 | rename -uuid "F508EE17-4C1F-E75B-0F94-F0A144CCA2E7"; 31 | setAttr ".visibility" no; 32 | setAttr ".translate" -type "double3" 0 1000.1 0 ; 33 | setAttr ".rotate" -type "double3" -90 0 0 ; 34 | createNode camera -shared -name "topShape" -parent "top"; 35 | rename -uuid "3B13E480-4673-B1FF-44A6-D68CF4F8548B"; 36 | setAttr -keyable off ".visibility" no; 37 | setAttr ".renderable" no; 38 | setAttr ".centerOfInterest" 1000.1; 39 | setAttr ".orthographicWidth" 30; 40 | setAttr ".imageName" -type "string" "top"; 41 | setAttr ".depthName" -type "string" "top_depth"; 42 | setAttr ".maskName" -type "string" "top_mask"; 43 | setAttr ".homeCommand" -type "string" "viewSet -t %camera"; 44 | setAttr ".orthographic" yes; 45 | setAttr ".aiTranslator" -type "string" "orthographic"; 46 | createNode transform -shared -name "front"; 47 | rename -uuid "DFFBF7AC-4972-F653-6E1E-3E90F10B959D"; 48 | setAttr ".visibility" no; 49 | setAttr ".translate" -type "double3" 0 0 1000.1 ; 50 | createNode camera -shared -name "frontShape" -parent "front"; 51 | rename -uuid "28FD74E1-4DF0-1D7B-C77A-C68438FC6760"; 52 | setAttr -keyable off ".visibility" no; 53 | setAttr ".renderable" no; 54 | setAttr ".centerOfInterest" 1000.1; 55 | setAttr ".orthographicWidth" 30; 56 | setAttr ".imageName" -type "string" "front"; 57 | setAttr ".depthName" -type "string" "front_depth"; 58 | setAttr ".maskName" -type "string" "front_mask"; 59 | setAttr ".homeCommand" -type "string" "viewSet -f %camera"; 60 | setAttr ".orthographic" yes; 61 | setAttr ".aiTranslator" -type "string" "orthographic"; 62 | createNode transform -shared -name "side"; 63 | rename -uuid "C7F1F531-40C9-52F2-462D-B786E622859F"; 64 | setAttr ".visibility" no; 65 | setAttr ".translate" -type "double3" 1000.1 2.1921595882814922 -1.0272737719846559 ; 66 | setAttr ".rotate" -type "double3" 0 90 0 ; 67 | createNode camera -shared -name "sideShape" -parent "side"; 68 | rename -uuid "C24D6944-44CC-7174-6147-CDB78ECDC560"; 69 | setAttr -keyable off ".visibility" no; 70 | setAttr ".renderable" no; 71 | setAttr ".centerOfInterest" 1000.1; 72 | setAttr ".orthographicWidth" 14.43979809899435; 73 | setAttr ".imageName" -type "string" "side"; 74 | setAttr ".depthName" -type "string" "side_depth"; 75 | setAttr ".maskName" -type "string" "side_mask"; 76 | setAttr ".homeCommand" -type "string" "viewSet -s %camera"; 77 | setAttr ".orthographic" yes; 78 | setAttr ".aiTranslator" -type "string" "orthographic"; 79 | createNode transform -name "ROOT"; 80 | rename -uuid "EEFD0F21-47C4-DC11-41EE-F5A5E1C2AA60"; 81 | createNode transform -name "MESHES" -parent "ROOT"; 82 | rename -uuid "9DEC2C4E-4182-D975-8663-60A9BC65FAC5"; 83 | createNode transform -name "Cylinder_SRC" -parent "MESHES"; 84 | rename -uuid "9ED5801E-4814-AF82-14A3-DB976376FCF0"; 85 | setAttr ".translate" -type "double3" 0 3 0 ; 86 | setAttr -lock on ".translateX"; 87 | setAttr -lock on ".translateY"; 88 | setAttr -lock on ".translateZ"; 89 | setAttr -lock on ".rotateX"; 90 | setAttr -lock on ".rotateY"; 91 | setAttr -lock on ".rotateZ"; 92 | setAttr -lock on ".scaleX"; 93 | setAttr -lock on ".scaleY"; 94 | setAttr -lock on ".scaleZ"; 95 | createNode mesh -name "Cylinder_SRCShape" -parent "Cylinder_SRC"; 96 | rename -uuid "E532591F-4989-9649-E32D-9695C864DE4C"; 97 | setAttr -keyable off ".visibility"; 98 | setAttr ".visibleInReflections" yes; 99 | setAttr ".visibleInRefractions" yes; 100 | setAttr ".uvSet[0].uvSetName" -type "string" "map1"; 101 | setAttr ".currentUVSet" -type "string" "map1"; 102 | setAttr ".displayColorChannel" -type "string" "Ambient+Diffuse"; 103 | setAttr ".collisionOffsetVelocityMultiplier[0]" 0 1 1; 104 | setAttr ".collisionDepthVelocityMultiplier[0]" 0 1 1; 105 | setAttr ".vertexColorSource" 2; 106 | createNode mesh -name "Cylinder_SRCShapeOrig" -parent "Cylinder_SRC"; 107 | rename -uuid "89699AC0-4DE7-96DB-838D-A69B883468ED"; 108 | setAttr -keyable off ".visibility"; 109 | setAttr ".intermediateObject" yes; 110 | setAttr ".visibleInReflections" yes; 111 | setAttr ".visibleInRefractions" yes; 112 | setAttr ".uvPivot" -type "double2" 0.5 0.15000000596046448 ; 113 | setAttr ".uvSet[0].uvSetName" -type "string" "map1"; 114 | setAttr ".currentUVSet" -type "string" "map1"; 115 | setAttr ".displayColorChannel" -type "string" "Ambient+Diffuse"; 116 | setAttr ".collisionOffsetVelocityMultiplier[0]" 0 1 1; 117 | setAttr ".collisionDepthVelocityMultiplier[0]" 0 1 1; 118 | setAttr -size 2 ".pnts[140:141]" -type "float3" -0.074969575 0 -0.074452713 119 | 0.10046493 0 0.041402753; 120 | createNode transform -name "JOINTS" -parent "ROOT"; 121 | rename -uuid "C6EEC47F-40B8-433F-569D-CE8B9BA9CC57"; 122 | createNode joint -name "joint1" -parent "JOINTS"; 123 | rename -uuid "63749E5E-4179-CC53-0A9B-EB9A85FC4407"; 124 | addAttr -cachedInternally true -shortName "liw" -longName "lockInfluenceWeights" 125 | -minValue 0 -maxValue 1 -attributeType "bool"; 126 | setAttr ".useObjectColor" 1; 127 | setAttr ".minRotLimit" -type "double3" -360 -360 -360 ; 128 | setAttr ".maxRotLimit" -type "double3" 360 360 360 ; 129 | setAttr ".jointOrient" -type "double3" 0 0 90 ; 130 | setAttr ".bindPose" -type "matrix" 0 1 0 0 -1 0 0 0 0 0 1 0 0 0 0 1; 131 | setAttr ".radius" 0.55172413793103448; 132 | createNode joint -name "joint2" -parent "joint1"; 133 | rename -uuid "3F6AD6A4-4358-569E-D4AA-E8B8E0B37BE0"; 134 | addAttr -cachedInternally true -shortName "liw" -longName "lockInfluenceWeights" 135 | -minValue 0 -maxValue 1 -attributeType "bool"; 136 | setAttr ".useObjectColor" 1; 137 | setAttr ".objectColor" 1; 138 | setAttr ".translate" -type "double3" 2 0 0 ; 139 | setAttr ".minRotLimit" -type "double3" -45 -90 -90 ; 140 | setAttr ".maxRotLimit" -type "double3" 45 90 90 ; 141 | setAttr ".minRotXLimitEnable" yes; 142 | setAttr ".minRotYLimitEnable" yes; 143 | setAttr ".minRotZLimitEnable" yes; 144 | setAttr ".maxRotXLimitEnable" yes; 145 | setAttr ".maxRotYLimitEnable" yes; 146 | setAttr ".maxRotZLimitEnable" yes; 147 | setAttr ".bindPose" -type "matrix" 0 1 0 0 -1 0 0 0 0 0 1 0 0 2 0 1; 148 | setAttr ".radius" 0.55172413793103448; 149 | createNode joint -name "joint3" -parent "joint2"; 150 | rename -uuid "696E619B-4FA2-CFF3-BC2F-9FAFAE884808"; 151 | addAttr -cachedInternally true -shortName "liw" -longName "lockInfluenceWeights" 152 | -minValue 0 -maxValue 1 -attributeType "bool"; 153 | setAttr ".useObjectColor" 1; 154 | setAttr ".objectColor" 2; 155 | setAttr ".translate" -type "double3" 2 0 0 ; 156 | setAttr ".minRotLimit" -type "double3" -45 -90 -90 ; 157 | setAttr ".maxRotLimit" -type "double3" 45 90 90 ; 158 | setAttr ".minRotXLimitEnable" yes; 159 | setAttr ".minRotYLimitEnable" yes; 160 | setAttr ".minRotZLimitEnable" yes; 161 | setAttr ".maxRotXLimitEnable" yes; 162 | setAttr ".maxRotYLimitEnable" yes; 163 | setAttr ".maxRotZLimitEnable" yes; 164 | setAttr ".bindPose" -type "matrix" 0 1 0 0 -1 0 0 0 0 0 1 0 0 4 0 1; 165 | setAttr ".radius" 0.55172413793103448; 166 | createNode joint -name "joint4" -parent "joint3"; 167 | rename -uuid "F8823AC0-42FE-E202-CCB0-FB95CB863B58"; 168 | addAttr -cachedInternally true -shortName "liw" -longName "lockInfluenceWeights" 169 | -minValue 0 -maxValue 1 -attributeType "bool"; 170 | setAttr ".useObjectColor" 1; 171 | setAttr ".objectColor" 3; 172 | setAttr ".translate" -type "double3" 2 0 0 ; 173 | setAttr ".minRotLimit" -type "double3" -360 -360 -360 ; 174 | setAttr ".maxRotLimit" -type "double3" 360 360 360 ; 175 | setAttr ".jointOrient" -type "double3" 0 0 -90 ; 176 | setAttr ".bindPose" -type "matrix" 1 0 0 0 0 1 0 0 0 0 1 0 0 6 0 1; 177 | setAttr ".radius" 0.55172413793103448; 178 | createNode transform -name "FDDA"; 179 | rename -uuid "A901CE63-4FFA-1E3D-D00D-6FBCF500A13D"; 180 | createNode transform -name "Cylinder_DST" -parent "FDDA"; 181 | rename -uuid "DE9B75DF-4208-D288-6915-D9AE53D97979"; 182 | setAttr ".translate" -type "double3" 0 3 0 ; 183 | setAttr -lock on ".translateX"; 184 | setAttr -lock on ".translateY"; 185 | setAttr -lock on ".translateZ"; 186 | setAttr -lock on ".rotateX"; 187 | setAttr -lock on ".rotateY"; 188 | setAttr -lock on ".rotateZ"; 189 | setAttr -lock on ".scaleX"; 190 | setAttr -lock on ".scaleY"; 191 | setAttr -lock on ".scaleZ"; 192 | createNode mesh -name "Cylinder_DSTShape" -parent "Cylinder_DST"; 193 | rename -uuid "E43F6236-43AD-AF50-3320-9A8131BDEB48"; 194 | setAttr -keyable off ".visibility"; 195 | setAttr ".visibleInReflections" yes; 196 | setAttr ".visibleInRefractions" yes; 197 | setAttr ".uvSet[0].uvSetName" -type "string" "map1"; 198 | setAttr ".currentUVSet" -type "string" "map1"; 199 | setAttr ".displayColorChannel" -type "string" "Ambient+Diffuse"; 200 | setAttr ".collisionOffsetVelocityMultiplier[0]" 0 1 1; 201 | setAttr ".collisionDepthVelocityMultiplier[0]" 0 1 1; 202 | setAttr ".vertexColorSource" 2; 203 | createNode mesh -name "Cylinder_DSTShapeOrig" -parent "Cylinder_DST"; 204 | rename -uuid "3F5BAE62-4C08-4DC1-8814-96B3B17D1779"; 205 | setAttr -keyable off ".visibility"; 206 | setAttr ".intermediateObject" yes; 207 | setAttr ".visibleInReflections" yes; 208 | setAttr ".visibleInRefractions" yes; 209 | setAttr -size 10 ".componentTags"; 210 | setAttr ".componentTags[0].componentTagName" -type "string" "bottom"; 211 | setAttr ".componentTags[0].componentTagContents" -type "componentList" 1 "f[120:139]"; 212 | setAttr ".componentTags[1].componentTagName" -type "string" "bottomRing"; 213 | setAttr ".componentTags[1].componentTagContents" -type "componentList" 1 "e[0:19]"; 214 | setAttr ".componentTags[2].componentTagName" -type "string" "cylBottomCap"; 215 | setAttr ".componentTags[2].componentTagContents" -type "componentList" 2 "vtx[0:19]" "vtx[140]"; 216 | setAttr ".componentTags[3].componentTagName" -type "string" "cylBottomRing"; 217 | setAttr ".componentTags[3].componentTagContents" -type "componentList" 1 "vtx[0:19]"; 218 | setAttr ".componentTags[4].componentTagName" -type "string" "cylSides"; 219 | setAttr ".componentTags[4].componentTagContents" -type "componentList" 1 "vtx[0:139]"; 220 | setAttr ".componentTags[5].componentTagName" -type "string" "cylTopCap"; 221 | setAttr ".componentTags[5].componentTagContents" -type "componentList" 2 "vtx[120:139]" "vtx[141]"; 222 | setAttr ".componentTags[6].componentTagName" -type "string" "cylTopRing"; 223 | setAttr ".componentTags[6].componentTagContents" -type "componentList" 1 "vtx[120:139]"; 224 | setAttr ".componentTags[7].componentTagName" -type "string" "sides"; 225 | setAttr ".componentTags[7].componentTagContents" -type "componentList" 1 "f[0:119]"; 226 | setAttr ".componentTags[8].componentTagName" -type "string" "top"; 227 | setAttr ".componentTags[8].componentTagContents" -type "componentList" 1 "f[140:159]"; 228 | setAttr ".componentTags[9].componentTagName" -type "string" "topRing"; 229 | setAttr ".componentTags[9].componentTagContents" -type "componentList" 1 "e[120:139]"; 230 | setAttr ".uvPivot" -type "double2" 0.5 0.84062498807907104 ; 231 | setAttr ".uvSet[0].uvSetName" -type "string" "map1"; 232 | setAttr -size 189 ".uvSet[0].uvSetPoints[0:188]" -type "float2" 0.64860266 233 | 0.10796607 0.62640899 0.064408496 0.59184152 0.029841021 0.54828393 0.0076473355 234 | 0.5 -7.4505806e-08 0.45171607 0.0076473504 0.40815851 0.029841051 0.37359107 0.064408526 235 | 0.3513974 0.1079661 0.34374997 0.15625 0.3513974 0.2045339 0.37359107 0.24809146 236 | 0.40815854 0.28265893 0.4517161 0.3048526 0.5 0.3125 0.54828387 0.3048526 0.59184146 237 | 0.28265893 0.62640893 0.24809146 0.6486026 0.2045339 0.65625 0.15625 0.375 0.3125 238 | 0.38749999 0.3125 0.39999998 0.3125 0.41249996 0.3125 0.42499995 0.3125 0.43749994 239 | 0.3125 0.44999993 0.3125 0.46249992 0.3125 0.4749999 0.3125 0.48749989 0.3125 0.49999988 240 | 0.3125 0.51249987 0.3125 0.52499986 0.3125 0.53749985 0.3125 0.54999983 0.3125 0.56249982 241 | 0.3125 0.57499981 0.3125 0.5874998 0.3125 0.59999979 0.3125 0.61249977 0.3125 0.62499976 242 | 0.3125 0.375 0.375 0.38749999 0.375 0.39999998 0.375 0.41249996 0.375 0.42499995 243 | 0.375 0.43749994 0.375 0.44999993 0.375 0.46249992 0.375 0.4749999 0.375 0.48749989 244 | 0.375 0.49999988 0.375 0.51249987 0.375 0.52499986 0.375 0.53749985 0.375 0.54999983 245 | 0.375 0.56249982 0.375 0.57499981 0.375 0.5874998 0.375 0.59999979 0.375 0.61249977 246 | 0.375 0.62499976 0.375 0.375 0.4375 0.38749999 0.4375 0.39999998 0.4375 0.41249996 247 | 0.4375 0.42499995 0.4375 0.43749994 0.4375 0.44999993 0.4375 0.46249992 0.4375 0.4749999 248 | 0.4375 0.48749989 0.4375 0.49999988 0.4375 0.51249987 0.4375 0.52499986 0.4375 0.53749985 249 | 0.4375 0.54999983 0.4375 0.56249982 0.4375 0.57499981 0.4375 0.5874998 0.4375 0.59999979 250 | 0.4375 0.61249977 0.4375 0.62499976 0.4375 0.375 0.5 0.38749999 0.5 0.39999998 0.5 251 | 0.41249996 0.5 0.42499995 0.5 0.43749994 0.5 0.44999993 0.5 0.46249992 0.5 0.4749999 252 | 0.5 0.48749989 0.5 0.49999988 0.5 0.51249987 0.5 0.52499986 0.5 0.53749985 0.5 0.54999983 253 | 0.5 0.56249982 0.5 0.57499981 0.5 0.5874998 0.5 0.59999979 0.5 0.61249977 0.5 0.62499976 254 | 0.5 0.375 0.5625 0.38749999 0.5625 0.39999998 0.5625 0.41249996 0.5625 0.42499995 255 | 0.5625 0.43749994 0.5625 0.44999993 0.5625 0.46249992 0.5625 0.4749999 0.5625 0.48749989 256 | 0.5625 0.49999988 0.5625 0.51249987 0.5625 0.52499986 0.5625 0.53749985 0.5625 0.54999983 257 | 0.5625 0.56249982 0.5625 0.57499981 0.5625 0.5874998 0.5625 0.59999979 0.5625 0.61249977 258 | 0.5625 0.62499976 0.5625 0.375 0.625 0.38749999 0.625 0.39999998 0.625 0.41249996 259 | 0.625 0.42499995 0.625 0.43749994 0.625 0.44999993 0.625 0.46249992 0.625 0.4749999 260 | 0.625 0.48749989 0.625 0.49999988 0.625 0.51249987 0.625 0.52499986 0.625 0.53749985 261 | 0.625 0.54999983 0.625 0.56249982 0.625 0.57499981 0.625 0.5874998 0.625 0.59999979 262 | 0.625 0.61249977 0.625 0.62499976 0.625 0.375 0.6875 0.38749999 0.6875 0.39999998 263 | 0.6875 0.41249996 0.6875 0.42499995 0.6875 0.43749994 0.6875 0.44999993 0.6875 0.46249992 264 | 0.6875 0.4749999 0.6875 0.48749989 0.6875 0.49999988 0.6875 0.51249987 0.6875 0.52499986 265 | 0.6875 0.53749985 0.6875 0.54999983 0.6875 0.56249982 0.6875 0.57499981 0.6875 0.5874998 266 | 0.6875 0.59999979 0.6875 0.61249977 0.6875 0.62499976 0.6875 0.64860266 0.79546607 267 | 0.62640899 0.75190848 0.59184152 0.71734101 0.54828393 0.69514734 0.5 0.68749994 268 | 0.45171607 0.69514734 0.40815851 0.71734107 0.37359107 0.75190854 0.3513974 0.79546607 269 | 0.34374997 0.84375 0.3513974 0.89203393 0.37359107 0.93559146 0.40815854 0.97015893 270 | 0.4517161 0.9923526 0.5 1 0.54828387 0.9923526 0.59184146 0.97015893 0.62640893 0.93559146 271 | 0.6486026 0.89203393 0.65625 0.84375 0.5 0.15625 0.5 0.84375; 272 | setAttr ".currentUVSet" -type "string" "map1"; 273 | setAttr ".displayColorChannel" -type "string" "Ambient+Diffuse"; 274 | setAttr ".collisionOffsetVelocityMultiplier[0]" 0 1 1; 275 | setAttr ".collisionDepthVelocityMultiplier[0]" 0 1 1; 276 | setAttr -size 2 ".pnts[140:141]" -type "float3" -0.074969575 0 -0.074452706 277 | 0.10046494 0 0.041402739; 278 | setAttr -size 142 ".vrts[0:141]" 0.95105714 -3 -0.30901718 0.80901754 -3 -0.5877856 279 | 0.5877856 -3 -0.80901748 0.30901715 -3 -0.95105702 8.5404744e-18 -3 -1.000000476837 280 | -0.30901715 -3 -0.95105696 -0.58778548 -3 -0.8090173 -0.80901724 -3 -0.58778542 -0.95105678 -3 -0.30901706 281 | -1.000000238419 -3 3.1900953e-15 -0.95105678 -3 0.30901706 -0.80901718 -3 0.58778536 282 | -0.58778536 -3 0.80901712 -0.30901706 -3 0.95105666 -2.9802322e-08 -3 1.000000119209 283 | 0.30901697 -3 0.9510566 0.58778524 -3 0.80901706 0.809017 -3 0.5877853 0.95105654 -3 0.309017 284 | 1 -3 -9.6291383e-15 0.95105714 -2 -0.30901718 0.80901754 -2 -0.5877856 0.5877856 -2 -0.80901748 285 | 0.30901715 -2 -0.95105702 1.0270879e-10 -2 -1.000000476837 -0.30901715 -2 -0.95105696 286 | -0.58778548 -2 -0.8090173 -0.80901724 -2 -0.58778542 -0.95105678 -2 -0.30901706 -1.000000238419 -2 1.8552433e-10 287 | -0.95105678 -2 0.30901706 -0.80901718 -2 0.58778536 -0.58778536 -2 0.80901712 -0.30901706 -2 0.95105666 288 | -2.9647101e-08 -2 1.000000119209 0.30901697 -2 0.9510566 0.58778524 -2 0.80901706 289 | 0.809017 -2 0.5877853 0.95105654 -2 0.309017 1 -2 -1.6855843e-10 0.95105714 -1 -0.30901718 290 | 0.80901754 -1 -0.5877856 0.5877856 -1 -0.80901748 0.30901715 -1 -0.95105702 6.8639144e-12 -1 -1.000000476837 291 | -0.30901715 -1 -0.95105696 -0.58778548 -1 -0.8090173 -0.80901724 -1 -0.58778542 -0.95105678 -1 -0.30901706 292 | -1.000000238419 -1 3.4963872e-11 -0.95105678 -1 0.30901706 -0.80901718 -1 0.58778536 293 | -0.58778536 -1 0.80901712 -0.30901706 -1 0.95105666 -2.9816263e-08 -1 1.000000119209 294 | 0.30901697 -1 0.9510566 0.58778524 -1 0.80901706 0.809017 -1 0.5877853 0.95105654 -1 0.309017 295 | 1 -1 2.1249865e-11 0.95105714 2.103841e-16 -0.30901718 0.80901754 1.326843e-16 -0.5877856 296 | 0.5877856 5.4927874e-16 -0.80901748 0.30901715 2.7609796e-16 -0.95105702 -9.899372e-17 1.5672987e-16 -1.000000476837 297 | -0.30901715 -1.6623416e-16 -0.95105696 -0.58778548 -1.9542388e-16 -0.8090173 -0.80901724 -8.2047608e-16 -0.58778542 298 | -0.95105678 8.1273817e-17 -0.30901706 -1.000000238419 0 0 -0.95105678 -1.3079905e-16 0.30901706 299 | -0.80901718 8.1273817e-17 0.58778536 -0.58778536 -2.8848314e-17 0.80901712 -0.30901706 7.4291976e-17 0.95105666 300 | -2.9802322e-08 4.4339226e-16 1.000000119209 0.30901697 2.5782277e-16 0.9510566 0.58778524 8.1273817e-17 0.80901706 301 | 0.809017 2.1496422e-16 0.5877853 0.95105654 6.5707591e-16 0.309017 1 -3.1793302e-16 5.5640123e-16 302 | 0.95105714 1 -0.30901718 0.80901754 1 -0.5877856 0.5877856 1 -0.80901748 0.30901715 1 -0.95105702 303 | -8.0129116e-13 1 -1.000000476837 -0.30901715 1 -0.95105696 -0.58778548 1 -0.8090173 304 | -0.80901724 1 -0.58778542 -0.95105678 1 -0.30901706 -1.000000238419 1 -2.3622816e-11 305 | -0.95105678 1 0.30901706 -0.80901718 1 0.58778536 -0.58778536 1 0.80901712 -0.30901706 1 0.95105666 306 | -2.9799752e-08 1 1.000000119209 0.30901697 1 0.9510566 0.58778524 1 0.80901706 0.809017 1 0.5877853 307 | 0.95105654 1 0.309017 1 1 1.4318295e-11 0.95105714 2 -0.30901718 0.80901754 2 -0.5877856 308 | 0.5877856 2 -0.80901748 0.30901715 2 -0.95105702 -2.3700519e-10 2 -1.000000476837 309 | -0.30901715 2 -0.95105696 -0.58778548 2 -0.8090173 -0.80901724 2 -0.58778542 -0.95105678 2 -0.30901706 310 | -1.000000238419 2 1.1550454e-12 -0.95105678 2 0.30901706 -0.80901718 2 0.58778536 311 | -0.58778536 2 0.80901712 -0.30901706 2 0.95105666 -2.9388584e-08 2 1.000000119209 312 | 0.30901697 2 0.9510566 0.58778524 2 0.80901706 0.809017 2 0.5877853 0.95105654 2 0.309017 313 | 1 2 3.3530032e-10 0.95105714 3 -0.30901718 0.80901754 3 -0.5877856 0.5877856 3 -0.80901748 314 | 0.30901715 3 -0.95105702 1.9893887e-10 3 -1.000000476837 -0.30901715 3 -0.95105696 315 | -0.58778548 3 -0.8090173 -0.80901724 3 -0.58778542 -0.95105678 3 -0.30901706 -1.000000238419 3 -1.3943724e-10 316 | -0.95105678 3 0.30901706 -0.80901718 3 0.58778536 -0.58778536 3 0.80901712 -0.30901706 3 0.95105666 317 | -2.9966106e-08 3 1.000000119209 0.30901697 3 0.9510566 0.58778524 3 0.80901706 0.809017 3 0.5877853 318 | 0.95105654 3 0.309017 1 3 -2.4098637e-10 1.6455601e-15 -3 -3.4082022e-16 1.0119225e-15 3 8.2678113e-16; 319 | setAttr -size 300 ".edge"; 320 | setAttr ".edge[0:165]" 0 1 0 1 2 0 2 3 0 3 4 0 4 5 0 5 6 0 6 7 0 7 8 0 8 9 0 321 | 9 10 0 10 11 0 11 12 0 12 13 0 13 14 0 14 15 0 15 16 0 16 17 0 17 18 0 18 19 0 19 0 0 322 | 20 21 1 21 22 1 22 23 1 23 24 1 24 25 1 25 26 1 26 27 1 27 28 1 28 29 1 29 30 1 30 31 1 323 | 31 32 1 32 33 1 33 34 1 34 35 1 35 36 1 36 37 1 37 38 1 38 39 1 39 20 1 40 41 1 41 42 1 324 | 42 43 1 43 44 1 44 45 1 45 46 1 46 47 1 47 48 1 48 49 1 49 50 1 50 51 1 51 52 1 52 53 1 325 | 53 54 1 54 55 1 55 56 1 56 57 1 57 58 1 58 59 1 59 40 1 60 61 1 61 62 1 62 63 1 63 64 1 326 | 64 65 1 65 66 1 66 67 1 67 68 1 68 69 1 69 70 1 70 71 1 71 72 1 72 73 1 73 74 1 74 75 1 327 | 75 76 1 76 77 1 77 78 1 78 79 1 79 60 1 80 81 1 81 82 1 82 83 1 83 84 1 84 85 1 85 86 1 328 | 86 87 1 87 88 1 88 89 1 89 90 1 90 91 1 91 92 1 92 93 1 93 94 1 94 95 1 95 96 1 96 97 1 329 | 97 98 1 98 99 1 99 80 1 100 101 1 101 102 1 102 103 1 103 104 1 104 105 1 105 106 1 330 | 106 107 1 107 108 1 108 109 1 109 110 1 110 111 1 111 112 1 112 113 1 113 114 1 114 115 1 331 | 115 116 1 116 117 1 117 118 1 118 119 1 119 100 1 120 121 0 121 122 0 122 123 0 123 124 0 332 | 124 125 0 125 126 0 126 127 0 127 128 0 128 129 0 129 130 0 130 131 0 131 132 0 132 133 0 333 | 133 134 0 134 135 0 135 136 0 136 137 0 137 138 0 138 139 0 139 120 0 0 20 1 1 21 1 334 | 2 22 1 3 23 1 4 24 1 5 25 1 6 26 1 7 27 1 8 28 1 9 29 1 10 30 1 11 31 1 12 32 1 13 33 1 335 | 14 34 1 15 35 1 16 36 1 17 37 1 18 38 1 19 39 1 20 40 1 21 41 1 22 42 1 23 43 1 24 44 1 336 | 25 45 1; 337 | setAttr ".edge[166:299]" 26 46 1 27 47 1 28 48 1 29 49 1 30 50 1 31 51 1 32 52 1 338 | 33 53 1 34 54 1 35 55 1 36 56 1 37 57 1 38 58 1 39 59 1 40 60 1 41 61 1 42 62 1 43 63 1 339 | 44 64 1 45 65 1 46 66 1 47 67 1 48 68 1 49 69 1 50 70 1 51 71 1 52 72 1 53 73 1 54 74 1 340 | 55 75 1 56 76 1 57 77 1 58 78 1 59 79 1 60 80 1 61 81 1 62 82 1 63 83 1 64 84 1 65 85 1 341 | 66 86 1 67 87 1 68 88 1 69 89 1 70 90 1 71 91 1 72 92 1 73 93 1 74 94 1 75 95 1 76 96 1 342 | 77 97 1 78 98 1 79 99 1 80 100 1 81 101 1 82 102 1 83 103 1 84 104 1 85 105 1 86 106 1 343 | 87 107 1 88 108 1 89 109 1 90 110 1 91 111 1 92 112 1 93 113 1 94 114 1 95 115 1 344 | 96 116 1 97 117 1 98 118 1 99 119 1 100 120 1 101 121 1 102 122 1 103 123 1 104 124 1 345 | 105 125 1 106 126 1 107 127 1 108 128 1 109 129 1 110 130 1 111 131 1 112 132 1 113 133 1 346 | 114 134 1 115 135 1 116 136 1 117 137 1 118 138 1 119 139 1 140 0 1 140 1 1 140 2 1 347 | 140 3 1 140 4 1 140 5 1 140 6 1 140 7 1 140 8 1 140 9 1 140 10 1 140 11 1 140 12 1 348 | 140 13 1 140 14 1 140 15 1 140 16 1 140 17 1 140 18 1 140 19 1 120 141 1 121 141 1 349 | 122 141 1 123 141 1 124 141 1 125 141 1 126 141 1 127 141 1 128 141 1 129 141 1 130 141 1 350 | 131 141 1 132 141 1 133 141 1 134 141 1 135 141 1 136 141 1 137 141 1 138 141 1 139 141 1; 351 | setAttr -size 160 -capacityHint 600 ".face[0:159]" -type "polyFaces" 352 | f 4 0 141 -21 -141 353 | mu 0 4 20 21 42 41 354 | f 4 1 142 -22 -142 355 | mu 0 4 21 22 43 42 356 | f 4 2 143 -23 -143 357 | mu 0 4 22 23 44 43 358 | f 4 3 144 -24 -144 359 | mu 0 4 23 24 45 44 360 | f 4 4 145 -25 -145 361 | mu 0 4 24 25 46 45 362 | f 4 5 146 -26 -146 363 | mu 0 4 25 26 47 46 364 | f 4 6 147 -27 -147 365 | mu 0 4 26 27 48 47 366 | f 4 7 148 -28 -148 367 | mu 0 4 27 28 49 48 368 | f 4 8 149 -29 -149 369 | mu 0 4 28 29 50 49 370 | f 4 9 150 -30 -150 371 | mu 0 4 29 30 51 50 372 | f 4 10 151 -31 -151 373 | mu 0 4 30 31 52 51 374 | f 4 11 152 -32 -152 375 | mu 0 4 31 32 53 52 376 | f 4 12 153 -33 -153 377 | mu 0 4 32 33 54 53 378 | f 4 13 154 -34 -154 379 | mu 0 4 33 34 55 54 380 | f 4 14 155 -35 -155 381 | mu 0 4 34 35 56 55 382 | f 4 15 156 -36 -156 383 | mu 0 4 35 36 57 56 384 | f 4 16 157 -37 -157 385 | mu 0 4 36 37 58 57 386 | f 4 17 158 -38 -158 387 | mu 0 4 37 38 59 58 388 | f 4 18 159 -39 -159 389 | mu 0 4 38 39 60 59 390 | f 4 19 140 -40 -160 391 | mu 0 4 39 40 61 60 392 | f 4 20 161 -41 -161 393 | mu 0 4 41 42 63 62 394 | f 4 21 162 -42 -162 395 | mu 0 4 42 43 64 63 396 | f 4 22 163 -43 -163 397 | mu 0 4 43 44 65 64 398 | f 4 23 164 -44 -164 399 | mu 0 4 44 45 66 65 400 | f 4 24 165 -45 -165 401 | mu 0 4 45 46 67 66 402 | f 4 25 166 -46 -166 403 | mu 0 4 46 47 68 67 404 | f 4 26 167 -47 -167 405 | mu 0 4 47 48 69 68 406 | f 4 27 168 -48 -168 407 | mu 0 4 48 49 70 69 408 | f 4 28 169 -49 -169 409 | mu 0 4 49 50 71 70 410 | f 4 29 170 -50 -170 411 | mu 0 4 50 51 72 71 412 | f 4 30 171 -51 -171 413 | mu 0 4 51 52 73 72 414 | f 4 31 172 -52 -172 415 | mu 0 4 52 53 74 73 416 | f 4 32 173 -53 -173 417 | mu 0 4 53 54 75 74 418 | f 4 33 174 -54 -174 419 | mu 0 4 54 55 76 75 420 | f 4 34 175 -55 -175 421 | mu 0 4 55 56 77 76 422 | f 4 35 176 -56 -176 423 | mu 0 4 56 57 78 77 424 | f 4 36 177 -57 -177 425 | mu 0 4 57 58 79 78 426 | f 4 37 178 -58 -178 427 | mu 0 4 58 59 80 79 428 | f 4 38 179 -59 -179 429 | mu 0 4 59 60 81 80 430 | f 4 39 160 -60 -180 431 | mu 0 4 60 61 82 81 432 | f 4 40 181 -61 -181 433 | mu 0 4 62 63 84 83 434 | f 4 41 182 -62 -182 435 | mu 0 4 63 64 85 84 436 | f 4 42 183 -63 -183 437 | mu 0 4 64 65 86 85 438 | f 4 43 184 -64 -184 439 | mu 0 4 65 66 87 86 440 | f 4 44 185 -65 -185 441 | mu 0 4 66 67 88 87 442 | f 4 45 186 -66 -186 443 | mu 0 4 67 68 89 88 444 | f 4 46 187 -67 -187 445 | mu 0 4 68 69 90 89 446 | f 4 47 188 -68 -188 447 | mu 0 4 69 70 91 90 448 | f 4 48 189 -69 -189 449 | mu 0 4 70 71 92 91 450 | f 4 49 190 -70 -190 451 | mu 0 4 71 72 93 92 452 | f 4 50 191 -71 -191 453 | mu 0 4 72 73 94 93 454 | f 4 51 192 -72 -192 455 | mu 0 4 73 74 95 94 456 | f 4 52 193 -73 -193 457 | mu 0 4 74 75 96 95 458 | f 4 53 194 -74 -194 459 | mu 0 4 75 76 97 96 460 | f 4 54 195 -75 -195 461 | mu 0 4 76 77 98 97 462 | f 4 55 196 -76 -196 463 | mu 0 4 77 78 99 98 464 | f 4 56 197 -77 -197 465 | mu 0 4 78 79 100 99 466 | f 4 57 198 -78 -198 467 | mu 0 4 79 80 101 100 468 | f 4 58 199 -79 -199 469 | mu 0 4 80 81 102 101 470 | f 4 59 180 -80 -200 471 | mu 0 4 81 82 103 102 472 | f 4 60 201 -81 -201 473 | mu 0 4 83 84 105 104 474 | f 4 61 202 -82 -202 475 | mu 0 4 84 85 106 105 476 | f 4 62 203 -83 -203 477 | mu 0 4 85 86 107 106 478 | f 4 63 204 -84 -204 479 | mu 0 4 86 87 108 107 480 | f 4 64 205 -85 -205 481 | mu 0 4 87 88 109 108 482 | f 4 65 206 -86 -206 483 | mu 0 4 88 89 110 109 484 | f 4 66 207 -87 -207 485 | mu 0 4 89 90 111 110 486 | f 4 67 208 -88 -208 487 | mu 0 4 90 91 112 111 488 | f 4 68 209 -89 -209 489 | mu 0 4 91 92 113 112 490 | f 4 69 210 -90 -210 491 | mu 0 4 92 93 114 113 492 | f 4 70 211 -91 -211 493 | mu 0 4 93 94 115 114 494 | f 4 71 212 -92 -212 495 | mu 0 4 94 95 116 115 496 | f 4 72 213 -93 -213 497 | mu 0 4 95 96 117 116 498 | f 4 73 214 -94 -214 499 | mu 0 4 96 97 118 117 500 | f 4 74 215 -95 -215 501 | mu 0 4 97 98 119 118 502 | f 4 75 216 -96 -216 503 | mu 0 4 98 99 120 119 504 | f 4 76 217 -97 -217 505 | mu 0 4 99 100 121 120 506 | f 4 77 218 -98 -218 507 | mu 0 4 100 101 122 121 508 | f 4 78 219 -99 -219 509 | mu 0 4 101 102 123 122 510 | f 4 79 200 -100 -220 511 | mu 0 4 102 103 124 123 512 | f 4 80 221 -101 -221 513 | mu 0 4 104 105 126 125 514 | f 4 81 222 -102 -222 515 | mu 0 4 105 106 127 126 516 | f 4 82 223 -103 -223 517 | mu 0 4 106 107 128 127 518 | f 4 83 224 -104 -224 519 | mu 0 4 107 108 129 128 520 | f 4 84 225 -105 -225 521 | mu 0 4 108 109 130 129 522 | f 4 85 226 -106 -226 523 | mu 0 4 109 110 131 130 524 | f 4 86 227 -107 -227 525 | mu 0 4 110 111 132 131 526 | f 4 87 228 -108 -228 527 | mu 0 4 111 112 133 132 528 | f 4 88 229 -109 -229 529 | mu 0 4 112 113 134 133 530 | f 4 89 230 -110 -230 531 | mu 0 4 113 114 135 134 532 | f 4 90 231 -111 -231 533 | mu 0 4 114 115 136 135 534 | f 4 91 232 -112 -232 535 | mu 0 4 115 116 137 136 536 | f 4 92 233 -113 -233 537 | mu 0 4 116 117 138 137 538 | f 4 93 234 -114 -234 539 | mu 0 4 117 118 139 138 540 | f 4 94 235 -115 -235 541 | mu 0 4 118 119 140 139 542 | f 4 95 236 -116 -236 543 | mu 0 4 119 120 141 140 544 | f 4 96 237 -117 -237 545 | mu 0 4 120 121 142 141 546 | f 4 97 238 -118 -238 547 | mu 0 4 121 122 143 142 548 | f 4 98 239 -119 -239 549 | mu 0 4 122 123 144 143 550 | f 4 99 220 -120 -240 551 | mu 0 4 123 124 145 144 552 | f 4 100 241 -121 -241 553 | mu 0 4 125 126 147 146 554 | f 4 101 242 -122 -242 555 | mu 0 4 126 127 148 147 556 | f 4 102 243 -123 -243 557 | mu 0 4 127 128 149 148 558 | f 4 103 244 -124 -244 559 | mu 0 4 128 129 150 149 560 | f 4 104 245 -125 -245 561 | mu 0 4 129 130 151 150 562 | f 4 105 246 -126 -246 563 | mu 0 4 130 131 152 151 564 | f 4 106 247 -127 -247 565 | mu 0 4 131 132 153 152 566 | f 4 107 248 -128 -248 567 | mu 0 4 132 133 154 153 568 | f 4 108 249 -129 -249 569 | mu 0 4 133 134 155 154 570 | f 4 109 250 -130 -250 571 | mu 0 4 134 135 156 155 572 | f 4 110 251 -131 -251 573 | mu 0 4 135 136 157 156 574 | f 4 111 252 -132 -252 575 | mu 0 4 136 137 158 157 576 | f 4 112 253 -133 -253 577 | mu 0 4 137 138 159 158 578 | f 4 113 254 -134 -254 579 | mu 0 4 138 139 160 159 580 | f 4 114 255 -135 -255 581 | mu 0 4 139 140 161 160 582 | f 4 115 256 -136 -256 583 | mu 0 4 140 141 162 161 584 | f 4 116 257 -137 -257 585 | mu 0 4 141 142 163 162 586 | f 4 117 258 -138 -258 587 | mu 0 4 142 143 164 163 588 | f 4 118 259 -139 -259 589 | mu 0 4 143 144 165 164 590 | f 4 119 240 -140 -260 591 | mu 0 4 144 145 166 165 592 | f 3 -1 -261 261 593 | mu 0 3 1 0 187 594 | f 3 -2 -262 262 595 | mu 0 3 2 1 187 596 | f 3 -3 -263 263 597 | mu 0 3 3 2 187 598 | f 3 -4 -264 264 599 | mu 0 3 4 3 187 600 | f 3 -5 -265 265 601 | mu 0 3 5 4 187 602 | f 3 -6 -266 266 603 | mu 0 3 6 5 187 604 | f 3 -7 -267 267 605 | mu 0 3 7 6 187 606 | f 3 -8 -268 268 607 | mu 0 3 8 7 187 608 | f 3 -9 -269 269 609 | mu 0 3 9 8 187 610 | f 3 -10 -270 270 611 | mu 0 3 10 9 187 612 | f 3 -11 -271 271 613 | mu 0 3 11 10 187 614 | f 3 -12 -272 272 615 | mu 0 3 12 11 187 616 | f 3 -13 -273 273 617 | mu 0 3 13 12 187 618 | f 3 -14 -274 274 619 | mu 0 3 14 13 187 620 | f 3 -15 -275 275 621 | mu 0 3 15 14 187 622 | f 3 -16 -276 276 623 | mu 0 3 16 15 187 624 | f 3 -17 -277 277 625 | mu 0 3 17 16 187 626 | f 3 -18 -278 278 627 | mu 0 3 18 17 187 628 | f 3 -19 -279 279 629 | mu 0 3 19 18 187 630 | f 3 -20 -280 260 631 | mu 0 3 0 19 187 632 | f 3 120 281 -281 633 | mu 0 3 185 184 188 634 | f 3 121 282 -282 635 | mu 0 3 184 183 188 636 | f 3 122 283 -283 637 | mu 0 3 183 182 188 638 | f 3 123 284 -284 639 | mu 0 3 182 181 188 640 | f 3 124 285 -285 641 | mu 0 3 181 180 188 642 | f 3 125 286 -286 643 | mu 0 3 180 179 188 644 | f 3 126 287 -287 645 | mu 0 3 179 178 188 646 | f 3 127 288 -288 647 | mu 0 3 178 177 188 648 | f 3 128 289 -289 649 | mu 0 3 177 176 188 650 | f 3 129 290 -290 651 | mu 0 3 176 175 188 652 | f 3 130 291 -291 653 | mu 0 3 175 174 188 654 | f 3 131 292 -292 655 | mu 0 3 174 173 188 656 | f 3 132 293 -293 657 | mu 0 3 173 172 188 658 | f 3 133 294 -294 659 | mu 0 3 172 171 188 660 | f 3 134 295 -295 661 | mu 0 3 171 170 188 662 | f 3 135 296 -296 663 | mu 0 3 170 169 188 664 | f 3 136 297 -297 665 | mu 0 3 169 168 188 666 | f 3 137 298 -298 667 | mu 0 3 168 167 188 668 | f 3 138 299 -299 669 | mu 0 3 167 186 188 670 | f 3 139 280 -300 671 | mu 0 3 186 185 188; 672 | setAttr ".creaseData" -type "dataPolyComponent" Index_Data Edge 0 ; 673 | setAttr ".creaseVertexData" -type "dataPolyComponent" Index_Data Vertex 0 ; 674 | setAttr ".pinData[0]" -type "dataPolyComponent" Index_Data UV 0 ; 675 | setAttr ".holeFaceData" -type "dataPolyComponent" Index_Data Face 0 ; 676 | setAttr ".vertexColorSource" 2; 677 | createNode lightLinker -shared -name "lightLinker1"; 678 | rename -uuid "B30825D0-40EE-0CBA-1DDB-118CA8C1001C"; 679 | setAttr -size 3 ".link"; 680 | setAttr -size 3 ".shadowLink"; 681 | createNode shapeEditorManager -name "shapeEditorManager"; 682 | rename -uuid "5C46140F-4600-98C2-B37C-4AA5F6B622A9"; 683 | createNode poseInterpolatorManager -name "poseInterpolatorManager"; 684 | rename -uuid "C1263F98-4E07-173B-729A-DC9183F79425"; 685 | createNode displayLayerManager -name "layerManager"; 686 | rename -uuid "4504DB18-4F73-FBE6-00CD-259363FCAE95"; 687 | setAttr -size 2 ".displayLayerId[1:2]" 1 2; 688 | setAttr -size 3 ".displayLayerId"; 689 | createNode displayLayer -name "defaultLayer"; 690 | rename -uuid "B0B57F93-452D-2502-78E9-2B8D332D397D"; 691 | createNode renderLayerManager -name "renderLayerManager"; 692 | rename -uuid "45E2E3CB-4D76-3F4F-F1C6-D48FE1CE9D8F"; 693 | createNode renderLayer -name "defaultRenderLayer"; 694 | rename -uuid "9EF1CBFA-4821-263B-2CEE-A091E0255C31"; 695 | setAttr ".global" yes; 696 | createNode aiOptions -shared -name "defaultArnoldRenderOptions"; 697 | rename -uuid "1220C71B-47F2-5442-3440-C68AA2814052"; 698 | setAttr ".version" -type "string" "5.3.1.1"; 699 | createNode aiAOVFilter -shared -name "defaultArnoldFilter"; 700 | rename -uuid "EFCD5F6B-4FA9-0D1D-F135-D491DB6FC9B4"; 701 | setAttr ".aiTranslator" -type "string" "gaussian"; 702 | createNode aiAOVDriver -shared -name "defaultArnoldDriver"; 703 | rename -uuid "B25FCDC5-4484-EC8F-3B1A-7299DB5D44F4"; 704 | setAttr ".aiTranslator" -type "string" "exr"; 705 | createNode aiAOVDriver -shared -name "defaultArnoldDisplayDriver"; 706 | rename -uuid "E60105A2-4870-404C-AE38-31846C5076DC"; 707 | setAttr ".outputMode" 0; 708 | setAttr ".aiTranslator" -type "string" "maya"; 709 | createNode polyCylinder -name "polyCylinder1"; 710 | rename -uuid "58CC1881-4E5D-2186-3D1D-84808E91ADC5"; 711 | setAttr ".height" 6; 712 | setAttr ".subdivisionsHeight" 6; 713 | setAttr ".subdivisionsCaps" 1; 714 | setAttr ".createUVs" 3; 715 | createNode dagPose -name "bindPose1"; 716 | rename -uuid "2CE88AA4-4287-E4D5-D52E-47ACAF7FCA08"; 717 | setAttr -size 6 ".worldMatrix"; 718 | setAttr ".worldMatrix[0]" -type "matrix" 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1; 719 | setAttr ".worldMatrix[1]" -type "matrix" 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1; 720 | setAttr -size 8 ".xformMatrix"; 721 | setAttr ".xformMatrix[0]" -type "matrix" "xform" 1 1 1 0 0 0 0 0 0 0 0 0 0 0 722 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 1 1 yes; 723 | setAttr ".xformMatrix[1]" -type "matrix" "xform" 1 1 1 0 0 0 0 0 0 0 0 0 0 0 724 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 1 1 yes; 725 | setAttr ".xformMatrix[2]" -type "matrix" "xform" 1 1 1 0 0 0 0 0 0 0 0 0 0 0 726 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0.70710678118654757 0.70710678118654757 1 1 1 yes; 727 | setAttr ".xformMatrix[3]" -type "matrix" "xform" 1 1 1 0 0 0 0 2 0 0 0 0 0 0 728 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 1 1 yes; 729 | setAttr ".xformMatrix[4]" -type "matrix" "xform" 1 1 1 0 0 0 0 2 0 0 0 0 0 0 730 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 1 1 yes; 731 | setAttr ".xformMatrix[6]" -type "matrix" "xform" 1 1 1 0 0 0 0 2 0 0 0 0 0 0 732 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -0.70710678118654757 0.70710678118654757 1 1 1 yes; 733 | setAttr ".xformMatrix[7]" -type "matrix" "xform" 1 1 1 0 0 0 0 2 0 0 0 0 0 0 734 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -0.70710678118654757 0.70710678118654757 1 1 1 yes; 735 | setAttr ".xformMatrix[8]" -type "matrix" "xform" 1 1 1 0 0 0 0 2 0 0 0 0 0 0 736 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -0.70710678118654757 0.70710678118654757 1 1 1 yes; 737 | setAttr -size 6 ".members"; 738 | setAttr -size 8 ".parents"; 739 | setAttr -size 2 ".global[0:1]" yes yes; 740 | setAttr ".bindPose" yes; 741 | createNode script -name "sceneConfigurationScriptNode"; 742 | rename -uuid "159C945F-42E8-158C-9D2E-338A41CD6EDE"; 743 | setAttr ".before" -type "string" "playbackOptions -min 0 -max 40 -ast 0 -aet 40 "; 744 | setAttr ".scriptType" 6; 745 | createNode nodeGraphEditorInfo -name "MayaNodeEditorSavedTabsInfo"; 746 | rename -uuid "251F3452-41C6-5A55-307F-A68965CCF688"; 747 | setAttr ".tabGraphInfo[0].tabName" -type "string" "Untitled_1"; 748 | setAttr ".tabGraphInfo[0].viewRectLow" -type "double2" -499.68485982944719 -243.87254233917042 ; 749 | setAttr ".tabGraphInfo[0].viewRectHigh" -type "double2" 481.82771768188337 271.25349363210154 ; 750 | setAttr -size 3 ".tabGraphInfo[0].nodeInfo"; 751 | setAttr ".tabGraphInfo[0].nodeInfo[0].positionX" 47.142856597900391; 752 | setAttr ".tabGraphInfo[0].nodeInfo[0].positionY" 170; 753 | setAttr ".tabGraphInfo[0].nodeInfo[0].nodeVisualState" 18304; 754 | setAttr ".tabGraphInfo[0].nodeInfo[1].positionX" 47.142856597900391; 755 | setAttr ".tabGraphInfo[0].nodeInfo[1].positionY" 40; 756 | setAttr ".tabGraphInfo[0].nodeInfo[1].nodeVisualState" 18304; 757 | setAttr ".tabGraphInfo[0].nodeInfo[2].positionX" -260; 758 | setAttr ".tabGraphInfo[0].nodeInfo[2].positionY" 170; 759 | setAttr ".tabGraphInfo[0].nodeInfo[2].nodeVisualState" 18304; 760 | createNode shadingEngine -name "lambert1SG"; 761 | rename -uuid "261C1EA2-422B-03F7-AD6D-3BA0A5F9F38F"; 762 | setAttr ".isHistoricallyInteresting" 0; 763 | setAttr -size 2 ".dagSetMembers"; 764 | setAttr ".renderableOnlySet" yes; 765 | createNode materialInfo -name "materialInfo1"; 766 | rename -uuid "50276A89-46BD-0A08-FC00-7FB47ADD0685"; 767 | createNode nodeGraphEditorInfo -name "hyperShadePrimaryNodeEditorSavedTabsInfo"; 768 | rename -uuid "8A2817CF-4344-DD52-FB79-E6BDCF062204"; 769 | setAttr ".tabGraphInfo[0].tabName" -type "string" "Untitled_1"; 770 | setAttr ".tabGraphInfo[0].viewRectLow" -type "double2" -330.95236780151544 -323.80951094248991 ; 771 | setAttr ".tabGraphInfo[0].viewRectHigh" -type "double2" 317.85713022663526 338.09522466054096 ; 772 | setAttr -size 33 ".tabGraphInfo[0].nodeInfo"; 773 | setAttr ".tabGraphInfo[0].nodeInfo[0].positionX" -2435.71435546875; 774 | setAttr ".tabGraphInfo[0].nodeInfo[0].positionY" 655.71429443359375; 775 | setAttr ".tabGraphInfo[0].nodeInfo[0].nodeVisualState" 1922; 776 | setAttr ".tabGraphInfo[0].nodeInfo[1].positionX" 1922.857177734375; 777 | setAttr ".tabGraphInfo[0].nodeInfo[1].positionY" 464.28570556640625; 778 | setAttr ".tabGraphInfo[0].nodeInfo[1].nodeVisualState" 1922; 779 | setAttr ".tabGraphInfo[0].nodeInfo[2].positionX" 1922.857177734375; 780 | setAttr ".tabGraphInfo[0].nodeInfo[2].positionY" 222.85714721679688; 781 | setAttr ".tabGraphInfo[0].nodeInfo[2].nodeVisualState" 1922; 782 | setAttr ".tabGraphInfo[0].nodeInfo[3].positionX" 1601.4285888671875; 783 | setAttr ".tabGraphInfo[0].nodeInfo[3].positionY" 371.42855834960938; 784 | setAttr ".tabGraphInfo[0].nodeInfo[3].nodeVisualState" 1922; 785 | setAttr ".tabGraphInfo[0].nodeInfo[4].positionX" 1601.4285888671875; 786 | setAttr ".tabGraphInfo[0].nodeInfo[4].positionY" 612.85711669921875; 787 | setAttr ".tabGraphInfo[0].nodeInfo[4].nodeVisualState" 1922; 788 | setAttr ".tabGraphInfo[0].nodeInfo[5].positionX" 1601.4285888671875; 789 | setAttr ".tabGraphInfo[0].nodeInfo[5].positionY" 187.14285278320312; 790 | setAttr ".tabGraphInfo[0].nodeInfo[5].nodeVisualState" 1922; 791 | setAttr ".tabGraphInfo[0].nodeInfo[6].positionX" 1922.857177734375; 792 | setAttr ".tabGraphInfo[0].nodeInfo[6].positionY" 705.71429443359375; 793 | setAttr ".tabGraphInfo[0].nodeInfo[6].nodeVisualState" 1922; 794 | setAttr ".tabGraphInfo[0].nodeInfo[7].positionX" 1601.4285888671875; 795 | setAttr ".tabGraphInfo[0].nodeInfo[7].positionY" 774.28570556640625; 796 | setAttr ".tabGraphInfo[0].nodeInfo[7].nodeVisualState" 1922; 797 | setAttr ".tabGraphInfo[0].nodeInfo[8].positionX" 1922.857177734375; 798 | setAttr ".tabGraphInfo[0].nodeInfo[8].positionY" 70; 799 | setAttr ".tabGraphInfo[0].nodeInfo[8].nodeVisualState" 1922; 800 | setAttr ".tabGraphInfo[0].nodeInfo[9].positionX" -2128.571533203125; 801 | setAttr ".tabGraphInfo[0].nodeInfo[9].positionY" 585.71429443359375; 802 | setAttr ".tabGraphInfo[0].nodeInfo[9].nodeVisualState" 1922; 803 | setAttr ".tabGraphInfo[0].nodeInfo[10].positionX" 1922.857177734375; 804 | setAttr ".tabGraphInfo[0].nodeInfo[10].positionY" -258.57144165039062; 805 | setAttr ".tabGraphInfo[0].nodeInfo[10].nodeVisualState" 1922; 806 | setAttr ".tabGraphInfo[0].nodeInfo[11].positionX" 1922.857177734375; 807 | setAttr ".tabGraphInfo[0].nodeInfo[11].positionY" -442.85714721679688; 808 | setAttr ".tabGraphInfo[0].nodeInfo[11].nodeVisualState" 1922; 809 | setAttr ".tabGraphInfo[0].nodeInfo[12].positionX" 1250; 810 | setAttr ".tabGraphInfo[0].nodeInfo[12].positionY" 170; 811 | setAttr ".tabGraphInfo[0].nodeInfo[12].nodeVisualState" 1922; 812 | setAttr ".tabGraphInfo[0].nodeInfo[13].positionX" 1922.857177734375; 813 | setAttr ".tabGraphInfo[0].nodeInfo[13].positionY" -82.857139587402344; 814 | setAttr ".tabGraphInfo[0].nodeInfo[13].nodeVisualState" 1922; 815 | setAttr ".tabGraphInfo[0].nodeInfo[14].positionX" 2238.571533203125; 816 | setAttr ".tabGraphInfo[0].nodeInfo[14].positionY" 762.85711669921875; 817 | setAttr ".tabGraphInfo[0].nodeInfo[14].nodeVisualState" 1922; 818 | setAttr ".tabGraphInfo[0].nodeInfo[15].positionX" 2238.571533203125; 819 | setAttr ".tabGraphInfo[0].nodeInfo[15].positionY" 521.4285888671875; 820 | setAttr ".tabGraphInfo[0].nodeInfo[15].nodeVisualState" 1922; 821 | setAttr ".tabGraphInfo[0].nodeInfo[16].positionX" 942.85711669921875; 822 | setAttr ".tabGraphInfo[0].nodeInfo[16].positionY" 74.285713195800781; 823 | setAttr ".tabGraphInfo[0].nodeInfo[16].nodeVisualState" 1922; 824 | setAttr ".tabGraphInfo[0].nodeInfo[17].positionX" 2238.571533203125; 825 | setAttr ".tabGraphInfo[0].nodeInfo[17].positionY" 280; 826 | setAttr ".tabGraphInfo[0].nodeInfo[17].nodeVisualState" 1922; 827 | setAttr ".tabGraphInfo[0].nodeInfo[18].positionX" 21.428571701049805; 828 | setAttr ".tabGraphInfo[0].nodeInfo[18].positionY" 764.28570556640625; 829 | setAttr ".tabGraphInfo[0].nodeInfo[18].nodeVisualState" 1922; 830 | setAttr ".tabGraphInfo[0].nodeInfo[19].positionX" 635.71429443359375; 831 | setAttr ".tabGraphInfo[0].nodeInfo[19].positionY" 774.28570556640625; 832 | setAttr ".tabGraphInfo[0].nodeInfo[19].nodeVisualState" 1922; 833 | setAttr ".tabGraphInfo[0].nodeInfo[20].positionX" 328.57144165039062; 834 | setAttr ".tabGraphInfo[0].nodeInfo[20].positionY" 684.28570556640625; 835 | setAttr ".tabGraphInfo[0].nodeInfo[20].nodeVisualState" 1922; 836 | setAttr ".tabGraphInfo[0].nodeInfo[21].positionX" -285.71429443359375; 837 | setAttr ".tabGraphInfo[0].nodeInfo[21].positionY" 674.28570556640625; 838 | setAttr ".tabGraphInfo[0].nodeInfo[21].nodeVisualState" 1922; 839 | setAttr ".tabGraphInfo[0].nodeInfo[22].positionX" -900; 840 | setAttr ".tabGraphInfo[0].nodeInfo[22].positionY" 774.28570556640625; 841 | setAttr ".tabGraphInfo[0].nodeInfo[22].nodeVisualState" 1922; 842 | setAttr ".tabGraphInfo[0].nodeInfo[23].positionX" -1207.142822265625; 843 | setAttr ".tabGraphInfo[0].nodeInfo[23].positionY" 717.14288330078125; 844 | setAttr ".tabGraphInfo[0].nodeInfo[23].nodeVisualState" 1922; 845 | setAttr ".tabGraphInfo[0].nodeInfo[24].positionX" -1514.2857666015625; 846 | setAttr ".tabGraphInfo[0].nodeInfo[24].positionY" 725.71429443359375; 847 | setAttr ".tabGraphInfo[0].nodeInfo[24].nodeVisualState" 1922; 848 | setAttr ".tabGraphInfo[0].nodeInfo[25].positionX" 942.85711669921875; 849 | setAttr ".tabGraphInfo[0].nodeInfo[25].positionY" 797.14288330078125; 850 | setAttr ".tabGraphInfo[0].nodeInfo[25].nodeVisualState" 1922; 851 | setAttr ".tabGraphInfo[0].nodeInfo[26].positionX" -1821.4285888671875; 852 | setAttr ".tabGraphInfo[0].nodeInfo[26].positionY" 650; 853 | setAttr ".tabGraphInfo[0].nodeInfo[26].nodeVisualState" 1922; 854 | setAttr ".tabGraphInfo[0].nodeInfo[27].positionX" 1601.4285888671875; 855 | setAttr ".tabGraphInfo[0].nodeInfo[27].positionY" -445.71429443359375; 856 | setAttr ".tabGraphInfo[0].nodeInfo[27].nodeVisualState" 1922; 857 | setAttr ".tabGraphInfo[0].nodeInfo[28].positionX" -592.85711669921875; 858 | setAttr ".tabGraphInfo[0].nodeInfo[28].positionY" 688.5714111328125; 859 | setAttr ".tabGraphInfo[0].nodeInfo[28].nodeVisualState" 1922; 860 | setAttr ".tabGraphInfo[0].nodeInfo[29].positionX" 1922.857177734375; 861 | setAttr ".tabGraphInfo[0].nodeInfo[29].positionY" -655.71429443359375; 862 | setAttr ".tabGraphInfo[0].nodeInfo[29].nodeVisualState" 1922; 863 | setAttr ".tabGraphInfo[0].nodeInfo[30].positionX" 2238.571533203125; 864 | setAttr ".tabGraphInfo[0].nodeInfo[30].positionY" -82.857139587402344; 865 | setAttr ".tabGraphInfo[0].nodeInfo[30].nodeVisualState" 1922; 866 | setAttr ".tabGraphInfo[0].nodeInfo[31].positionX" 1250; 867 | setAttr ".tabGraphInfo[0].nodeInfo[31].positionY" 522.85711669921875; 868 | setAttr ".tabGraphInfo[0].nodeInfo[31].nodeVisualState" 1922; 869 | setAttr ".tabGraphInfo[0].nodeInfo[32].positionX" -98.571426391601562; 870 | setAttr ".tabGraphInfo[0].nodeInfo[32].positionY" 81.428573608398438; 871 | setAttr ".tabGraphInfo[0].nodeInfo[32].nodeVisualState" 1923; 872 | createNode deltaMush -name "deltaMush1"; 873 | rename -uuid "8A069AA7-425A-6192-659F-0ABA804498AA"; 874 | setAttr ".smoothingIterations" 5; 875 | setAttr ".smoothingStep" 0.60000002384185791; 876 | setAttr ".inwardConstraint" 1; 877 | createNode skinCluster -name "skinCluster1"; 878 | rename -uuid "ADD18122-4B43-1BE2-EF8A-1DA88EE9CB2F"; 879 | setAttr -size 142 ".weightList"; 880 | setAttr ".weightList[0:141].weights" 881 | 1 0 1 882 | 1 0 1 883 | 1 0 1 884 | 1 0 1 885 | 1 0 1 886 | 1 0 1 887 | 1 0 1 888 | 1 0 1 889 | 1 0 1 890 | 1 0 1 891 | 1 0 1 892 | 1 0 1 893 | 1 0 1 894 | 1 0 1 895 | 1 0 1 896 | 1 0 1 897 | 1 0 1 898 | 1 0 1 899 | 1 0 1 900 | 1 0 1 901 | 1 0 1 902 | 1 0 1 903 | 1 0 1 904 | 1 0 1 905 | 1 0 1 906 | 1 0 1 907 | 1 0 1 908 | 1 0 1 909 | 1 0 1 910 | 1 0 1 911 | 1 0 1 912 | 1 0 1 913 | 1 0 1 914 | 1 0 1 915 | 1 0 1 916 | 1 0 1 917 | 1 0 1 918 | 1 0 1 919 | 1 0 1 920 | 1 0 1 921 | 2 0 0.5 1 0.5 922 | 2 0 0.5 1 0.5 923 | 2 0 0.5 1 0.5 924 | 2 0 0.5 1 0.5 925 | 2 0 0.5 1 0.5 926 | 2 0 0.5 1 0.5 927 | 2 0 0.5 1 0.5 928 | 2 0 0.5 1 0.5 929 | 2 0 0.5 1 0.5 930 | 2 0 0.5 1 0.5 931 | 2 0 0.5 1 0.5 932 | 2 0 0.5 1 0.5 933 | 2 0 0.5 1 0.5 934 | 2 0 0.5 1 0.5 935 | 2 0 0.5 1 0.5 936 | 2 0 0.5 1 0.5 937 | 2 0 0.5 1 0.5 938 | 2 0 0.5 1 0.5 939 | 2 0 0.5 1 0.5 940 | 2 0 0.5 1 0.5 941 | 1 1 1 942 | 1 1 1 943 | 1 1 1 944 | 1 1 1 945 | 1 1 1 946 | 1 1 1 947 | 1 1 1 948 | 1 1 1 949 | 1 1 1 950 | 1 1 1 951 | 1 1 1 952 | 1 1 1 953 | 1 1 1 954 | 1 1 1 955 | 1 1 1 956 | 1 1 1 957 | 1 1 1 958 | 1 1 1 959 | 1 1 1 960 | 1 1 1 961 | 2 1 0.5 2 0.5 962 | 2 1 0.5 2 0.5 963 | 2 1 0.5 2 0.5 964 | 2 1 0.5 2 0.5 965 | 2 1 0.5 2 0.5 966 | 2 1 0.5 2 0.5 967 | 2 1 0.5 2 0.5 968 | 2 1 0.5 2 0.5 969 | 2 1 0.5 2 0.5 970 | 2 1 0.5 2 0.5 971 | 2 1 0.5 2 0.5 972 | 2 1 0.5 2 0.5 973 | 2 1 0.5 2 0.5 974 | 2 1 0.5 2 0.5 975 | 2 1 0.5 2 0.5 976 | 2 1 0.5 2 0.5 977 | 2 1 0.5 2 0.5 978 | 2 1 0.5 2 0.5 979 | 2 1 0.5 2 0.5 980 | 2 1 0.5 2 0.5 981 | 1 2 1 982 | 1 2 1 983 | 1 2 1 984 | 1 2 1 985 | 1 2 1 986 | 1 2 1 987 | 1 2 1 988 | 1 2 1 989 | 1 2 1 990 | 1 2 1 991 | 1 2 1 992 | 1 2 1 993 | 1 2 1 994 | 1 2 1 995 | 1 2 1 996 | 1 2 1 997 | 1 2 1 998 | 1 2 1 999 | 1 2 1 1000 | 1 2 1 1001 | 1 2 1 1002 | 1 2 1 1003 | 1 2 1 1004 | 1 2 1 1005 | 1 2 1 1006 | 1 2 1 1007 | 1 2 1 1008 | 1 2 1 1009 | 1 2 1 1010 | 1 2 1 1011 | 1 2 1 1012 | 1 2 1 1013 | 1 2 1 1014 | 1 2 1 1015 | 1 2 1 1016 | 1 2 1 1017 | 1 2 1 1018 | 1 2 1 1019 | 1 2 1 1020 | 1 2 1 1021 | 1 0 1 1022 | 1 2 1; 1023 | setAttr -size 3 ".bindPreMatrix"; 1024 | setAttr ".bindPreMatrix[0]" -type "matrix" 0 -1 0 0 1 0 0 0 0 0 1 0 0 0 0 1; 1025 | setAttr ".bindPreMatrix[1]" -type "matrix" 0 -1 0 0 1 0 0 0 0 0 1 0 -2 0 0 1; 1026 | setAttr ".bindPreMatrix[2]" -type "matrix" 0 -1 0 0 1 0 0 0 0 0 1 0 -4 0 0 1; 1027 | setAttr ".geomMatrix" -type "matrix" 1 0 0 0 0 1 0 0 0 0 1 0 0 3 0 1; 1028 | setAttr -size 3 ".matrix"; 1029 | setAttr -size 3 ".dropoff[0:2]" 4 4 4; 1030 | setAttr -size 3 ".lockWeights"; 1031 | setAttr -size 3 ".lockWeights"; 1032 | setAttr ".maintainMaxInfluences" yes; 1033 | setAttr ".useComponentsMatrix" yes; 1034 | setAttr -size 3 ".influenceColor"; 1035 | setAttr -size 3 ".influenceColor"; 1036 | createNode skinCluster -name "skinCluster2"; 1037 | rename -uuid "5B4C84C1-41CE-C5B3-7CD2-098D84BAD9C0"; 1038 | setAttr -size 142 ".weightList"; 1039 | setAttr ".weightList[0:135].weights" 1040 | 4 0 0.99581973407469371 1 0.0041601713391968484 2 2.0094586109443044e-05 1041 | 3 -1.3037531124138191e-17 1042 | 4 0 0.99615835965464616 1 0.0038254832262618775 2 1.6157119092005156e-05 1043 | 3 -7.9659001766293862e-17 1044 | 4 0 0.99644658254416485 1 0.0035401442678105175 2 1.3273188024678485e-05 1045 | 3 -2.175519421727945e-17 1046 | 4 0 0.99675976261230292 1 0.003229775363565373 2 1.0462024131626272e-05 1047 | 3 1.4887451080941583e-17 1048 | 4 0 0.99697242990657986 1 0.0030185943326817635 2 8.9757607384249329e-06 1049 | 3 -3.5223018078622825e-17 1050 | 4 0 0.99704093581664155 1 0.0029504847054373749 2 8.5794779211777986e-06 1051 | 3 -4.9873299934333204e-18 1052 | 4 0 0.99703086428041265 1 0.0029603990028937589 2 8.7367166935934889e-06 1053 | 3 3.2539617701721202e-17 1054 | 4 0 0.99702372537871298 1 0.0029675515569732511 2 8.7230643138151015e-06 1055 | 3 -4.1843427594362437e-17 1056 | 4 0 0.99701992000122364 1 0.0029714113196944543 2 8.668679081824985e-06 1057 | 3 3.6618928375697912e-17 1058 | 4 0 0.9969391053573633 1 0.0030517432801428468 2 9.1513624938149613e-06 1059 | 3 1.0286368111456223e-17 1060 | 4 0 0.99671695285925899 1 0.0032723107491493607 2 1.073639159161487e-05 1061 | 3 2.7620050344068225e-17 1062 | 4 0 0.99639766565515309 1 0.0035889003568392343 2 1.3433988007715197e-05 1063 | 3 -4.4269329955298753e-17 1064 | 4 0 0.99610793701190892 1 0.0038756650404944701 2 1.6397947596620162e-05 1065 | 3 -3.8502729650391476e-17 1066 | 4 0 0.99595282396180018 1 0.0040289899864347518 2 1.8186051765053776e-05 1067 | 3 2.3361380443510417e-17 1068 | 4 0 0.99594560066718263 1 0.0040359548605995981 2 1.844447221789479e-05 1069 | 3 -1.0489656018797255e-17 1070 | 4 0 0.99601423325327876 1 0.003967967580298915 2 1.7799166422401481e-05 1071 | 3 -1.4277079139150134e-16 1072 | 4 0 0.99607587153133215 1 0.0039070575383713434 2 1.7070930296318933e-05 1073 | 3 3.1064086307604211e-17 1074 | 4 0 0.9960844242174679 1 0.003898557528003695 2 1.7018254528533181e-05 1075 | 3 2.4992765899922199e-17 1076 | 4 0 0.99603872123547554 1 0.0039436541863948375 2 1.762457812943518e-05 1077 | 3 1.460911605447382e-16 1078 | 4 0 0.99598317448554341 1 0.0039984980801391033 2 1.8327434317641241e-05 1079 | 3 -6.0157973979894919e-17 1080 | 4 0 0.98973895263886824 1 0.010261047361131722 2 -6.4337549405920913e-21 1081 | 3 -4.2351647362715017e-22 1082 | 3 0 0.99078931173327001 1 0.0092106882667300667 2 -4.4233161208586165e-22 1083 | 3 0 0.99230655594163764 1 0.0076934440583623651 2 -3.6629642651241191e-23 1084 | 3 0 0.99381266554530445 1 0.006187334454695579 2 7.858699543916929e-21 1085 | 4 0 0.99495862202203145 1 0.0050413779779685487 2 -9.8530311002242497e-21 1086 | 3 3.3881317890172014e-21 1087 | 2 0 0.99556775711946099 1 0.0044322428805390682 1088 | 3 0 0.99576355822260942 1 0.0042364417773906073 2 -1.2888871075538859e-21 1089 | 2 0 0.99575905880537363 1 0.0042409411946263027 1090 | 3 0 0.99555734791513695 1 0.0044426520848630064 3 3.3881317890172014e-21 1091 | 3 0 0.99494852832197378 1 0.0050514716780262012 2 -8.2856697319192245e-21 1092 | 3 0 0.99380244364867332 1 0.0061975563513267254 2 3.1658464742264908e-22 1093 | 3 0 0.9922909684850626 1 0.0077090315149373895 2 1.529377252447907e-20 1094 | 3 0 0.99077160830822419 1 0.009228391691775922 2 -2.2326121754293079e-21 1095 | 3 0 0.98951112845842459 1 0.010488871541575389 2 5.1423093484173486e-26 1096 | 4 0 0.98852566860835711 1 0.01147320994929241 2 1.1214423501143067e-06 1097 | 3 4.0097862096660775e-16 1098 | 4 0 0.98776885255070457 1 0.012223210393114147 2 7.9370561814935551e-06 1099 | 3 -1.6737709850923876e-16 1100 | 4 0 0.98732156595980747 1 0.012668229943122921 2 1.0204097069522653e-05 1101 | 3 9.7673063213787881e-17 1102 | 4 0 0.98731109528120342 1 0.01267865485125292 2 1.0249867543202739e-05 1103 | 3 4.4604077376053652e-16 1104 | 4 0 0.98774838806579157 1 0.01224369322570279 2 7.9187085059778325e-06 1105 | 3 -3.4979072589813587e-16 1106 | 4 0 0.98851465935071015 1 0.011484064506099583 2 1.2761431900816782e-06 1107 | 3 2.0453473983939041e-16 1108 | 3 0 0.71517202931037982 1 0.28482797068962018 2 9.7134691814642991e-20 1109 | 3 0 0.71436119831679823 1 0.28563880168320177 2 -2.0313386672379334e-19 1110 | 3 0 0.71362466658105128 1 0.28637533341894866 2 -5.9340102207165268e-20 1111 | 3 0 0.71288713985559182 1 0.28711286014440812 2 4.6425025454562898e-20 1112 | 3 0 0.71249041065444785 1 0.28750958934555215 2 6.7002576890809338e-20 1113 | 3 0 0.71253957423178083 1 0.28746042576821917 2 7.7882257532639523e-21 1114 | 2 0 0.71275962631884693 1 0.28724037368115313 1115 | 3 0 0.71276106065991762 1 0.28723893934008221 2 -4.3904924299110435e-20 1116 | 3 0 0.7125410475306978 1 0.28745895246930242 2 4.2123823250069137e-21 1117 | 2 0 0.71248539076041451 1 0.28751460923958544 1118 | 3 0 0.71287148060285255 1 0.2871285193971474 2 4.6996195843330763e-20 1119 | 3 0 0.71360092730582758 1 0.28639907269417247 2 -1.5661136816616705e-20 1120 | 2 0 0.71433702683262745 1 0.2856629731673726 1121 | 3 0 0.71483873014798927 1 0.28516126985201079 2 1.6119878081848395e-20 1122 | 3 0 0.71509768333592294 1 0.28490231666407706 2 1.2956698386915965e-20 1123 | 3 0 0.71519372586414898 1 0.28480627413585091 2 1.9847548885515024e-20 1124 | 3 0 0.71521431229091126 1 0.28478568770908874 2 -1.4036279363591347e-20 1125 | 3 0 0.71521343163451023 1 0.28478656836548982 2 -4.0518229592557462e-20 1126 | 3 0 0.71519376474982177 1 0.28480623525017817 2 -4.6960842432620641e-20 1127 | 3 0 0.71510415828806295 1 0.28489584171193705 2 -3.2129301265848763e-20 1128 | 4 0 0.10471588156410593 1 0.89106879478152268 2 0.004215323654375081 1129 | 3 -3.62383734131555e-15 1130 | 4 0 0.10198330596965988 1 0.89488840806134029 2 0.0031282859689950983 1131 | 3 4.7115089607530081e-15 1132 | 4 0 0.098542280660813136 1 0.89965061437773386 2 0.0018071049614554948 1133 | 3 -2.4771851236948805e-15 1134 | 4 0 0.095220467958688687 1 0.90427060644423263 2 0.0005089255970799711 1135 | 3 -1.1597710639077441e-15 1136 | 3 0 0.093013208889509702 1 0.9069867911104903 2 7.1669337234215308e-21 1137 | 3 0 0.09225228734096573 1 0.9077477126590342 2 -2.9295223979356247e-20 1138 | 2 0 0.09230115813053423 1 0.90769884186946559 1139 | 3 0 0.092301276216528477 1 0.90769872378347149 3 2.7105054312137611e-20 1140 | 3 0 0.092252563330453577 1 0.90774743666954627 2 -4.0940551247324633e-21 1141 | 3 0 0.093013405227952928 1 0.90698659477204713 2 4.1489746156807162e-21 1142 | 4 0 0.095220494805318495 1 0.90427573414120976 2 0.00050377105347136338 1143 | 3 3.4053434985054087e-16 1144 | 4 0 0.098542263626486604 1 0.89965616615952337 2 0.0018015702139924114 1145 | 3 -2.3630457399864691e-15 1146 | 4 0 0.10198324240338839 1 0.89489361811286572 2 0.0031231394837455263 1147 | 3 3.5079361290768496e-16 1148 | 4 0 0.10471611893399668 1 0.8910730136730588 2 0.004210867392945448 1149 | 3 -9.813384913709422e-16 1150 | 4 0 0.10656151216631266 1 0.88839309070743655 2 0.0050453971262496584 1151 | 3 1.0278778696248825e-15 1152 | 4 0 0.10768445772046377 1 0.88665571352889994 2 0.0056598287506362862 1153 | 3 2.3635607360183997e-17 1154 | 4 0 0.10822495270544122 1 0.88576940940258109 2 0.0060056378919765858 1155 | 3 1.0651202142497596e-15 1156 | 4 0 0.10822510551062432 1 0.88576845101172286 2 0.0060064434776553877 1157 | 3 -2.6242029382839149e-15 1158 | 4 0 0.10768476011284947 1 0.88665304665898426 2 0.0056621932281621188 1159 | 3 4.2162454083616296e-15 1160 | 4 0 0.10656173271322568 1 0.88838934824487648 2 0.0050489190419005115 1161 | 3 -2.6628005356243989e-15 1162 | 4 0 0.0091874907646665727 1 0.71237551782206887 2 0.27843699141326117 1163 | 3 3.4139358007223564e-15 1164 | 4 0 0.0085591333237553299 1 0.71330315880440476 2 0.27813770787185194 1165 | 3 -1.204505245544496e-14 1166 | 4 0 0.0076594264406608051 1 0.71407782574236578 2 0.2782627478169582 1167 | 3 1.5279444376403717e-14 1168 | 4 0 0.0068426052034682742 1 0.71476750705381054 2 0.27838988774272755 1169 | 3 -6.3777108594287313e-15 1170 | 4 0 0.006372207641324487 1 0.71527149538225498 2 0.27835629697641628 1171 | 3 4.1845867049250529e-15 1172 | 4 0 0.0062822570103879304 1 0.71558223502506024 2 0.27813550796454556 1173 | 3 6.1951312135821723e-15 1174 | 4 0 0.0063565095926212591 1 0.7157213698468945 2 0.27792212056049698 1175 | 3 -1.2720727249337926e-14 1176 | 4 0 0.0063580505787065016 1 0.71573232854645397 2 0.27790962087482579 1177 | 3 1.3589173189498815e-14 1178 | 4 0 0.0062855909798800267 1 0.71561969520301649 2 0.278094713817093 1179 | 3 1.0528036775703242e-14 1180 | 4 0 0.0063740673706817004 1 0.71534085239410039 2 0.27828508023521592 1181 | 3 2.0581477602928111e-15 1182 | 4 0 0.0068412002670297234 1 0.714864397437316 2 0.27829440229565661 1183 | 3 -2.4028088546623749e-15 1184 | 4 0 0.0076558142257552014 1 0.71418623401235304 2 0.27815795176190278 1185 | 3 -1.0915964313018556e-14 1186 | 4 0 0.0085560340949485617 1 0.71340407453841015 2 0.2780398913666432 1187 | 3 -1.9725974326201268e-15 1188 | 4 0 0.009262316863470307 1 0.71269062807042161 2 0.27804705506610689 1189 | 3 1.2353399553299838e-15 1190 | 4 0 0.0096638880169461882 1 0.71217680152991858 2 0.27815931045315434 1191 | 3 -1.9094819584015987e-14 1192 | 4 0 0.0098222493643608227 1 0.71189854663026764 2 0.27827920400536782 1193 | 3 3.8096695936795655e-15 1194 | 4 0 0.0098595641717236851 1 0.71179337434409218 2 0.27834706148418725 1195 | 3 -3.07783312725185e-15 1196 | 4 0 0.0098589417243032263 1 0.71178605544131557 2 0.27835500283437298 1197 | 3 8.3344789403305697e-15 1198 | 4 0 0.0098207695411773981 1 0.71187293838737353 2 0.27830629207144558 1199 | 3 3.5527136788005009e-15 1200 | 4 0 0.0096627583148640658 1 0.71212627188768829 2 0.27821096979743437 1201 | 3 1.3214256078253328e-14 1202 | 4 0 0.00086404364981123693 1 0.11540318556331612 2 0.88373277078689805 1203 | 3 -2.5458801733435621e-14 1204 | 4 0 0.00080497903252190644 1 0.11524687933114026 2 0.8839481416363475 1205 | 3 -9.6207763977673721e-15 1206 | 4 0 0.00063524035186532314 1 0.11119535429589938 2 0.88816940535220512 1207 | 3 3.015599922551182e-14 1208 | 4 0 0.00048676960639421128 1 0.10723058120627431 2 0.89228264918732936 1209 | 3 2.1662901507346621e-15 1210 | 4 0 0.00040882017948304177 1 0.10467595241209975 2 0.89491522740842389 1211 | 3 -6.7346302146109593e-15 1212 | 4 0 0.00040253808850965292 1 0.10399757301792106 2 0.89559988889357067 1213 | 3 -1.3947176746853529e-15 1214 | 4 0 0.00042314321952293885 1 0.1042958556778808 2 0.89528100110260633 1215 | 3 -9.8532293435482643e-15 1216 | 4 0 0.00042463476814694391 1 0.10436815103471944 2 0.89520721419711657 1217 | 3 1.704886232190006e-14 1218 | 4 0 0.00040547020108555387 1 0.10417385773879613 2 0.89542067206010956 1219 | 3 8.8680148294106864e-15 1220 | 4 0 0.00041017578917557144 1 0.10486405143696628 2 0.89472577277389431 1221 | 3 -3.6257130110739499e-14 1222 | 4 0 0.00048469606055657159 1 0.10736248348458427 2 0.89215282045484279 1223 | 3 1.6512846320350383e-14 1224 | 4 0 0.00063090876796336143 1 0.11127917613355927 2 0.88808991509845536 1225 | 3 2.2111435946103875e-14 1226 | 4 0 0.00080162184787619544 1 0.11533632050509439 2 0.88386205764700987 1227 | 3 1.9451888016996932e-14 1228 | 4 0 0.00093680294839332647 1 0.11849531258367713 2 0.88056788446794998 1229 | 3 -2.045802763306348e-14 1230 | 4 0 0.00100584585775641 1 0.12054587965577598 2 0.87844827448648755 1231 | 3 -1.9853042820816569e-14 1232 | 4 0 0.0010201181656514793 1 0.12174113268682286 2 0.87723874914751399 1233 | 3 1.1561498286516425e-14 1234 | 4 0 0.0010133062724724004 1 0.12229016595659284 2 0.87669652777093843 1235 | 3 -3.5704945944292632e-15 1236 | 4 0 0.0010123682398799987 1 0.12225546386539542 2 0.87673216789468034 1237 | 3 4.4294429235591792e-14 1238 | 4 0 0.0010179598228297669 1 0.12164416180664964 2 0.87733787837052579 1239 | 3 -5.2093745983583517e-15 1240 | 4 0 0.0010040900659411306 1 0.12041406112130713 2 0.87858184881276513 1241 | 3 -1.3440637491868301e-14 1242 | 4 0 0.00031143407409579349 1 0.032892594696718 2 0.96679597122895067 1243 | 3 2.3559019318719621e-13 1244 | 4 0 0.00025745534718285394 1 0.029636389956034643 2 0.97010615469676276 1245 | 3 1.9701471357103095e-14 1246 | 4 0 0.00020635770055934231 1 0.02713873408161406 2 0.97265490821767797 1247 | 3 1.4859012457957288e-13 1248 | 4 0 0.00016169655689470889 1 0.02486724571908739 2 0.97497105772394421 1249 | 3 7.3586102489198169e-14 1250 | 4 0 0.00013431443413598529 1 0.023354676468348719 2 0.97651100909746025 1251 | 3 5.5062291531848828e-14 1252 | 4 0 0.00012458170116509868 1 0.022708587665122744 2 0.97716683063373899 1253 | 3 -2.6757242255204261e-14 1254 | 4 0 0.000123968705560005 1 0.022584892515526048 2 0.97729113877890628 1255 | 3 7.5859457604465774e-15 1256 | 4 0 0.00012425311154513349 1 0.022607565337336835 2 0.97726818155112272 1257 | 3 -4.5284956340374549e-15 1258 | 4 0 0.00012526069790465811 1 0.022783505965097119 2 0.97709123333695436 1259 | 3 4.3725873616340394e-14 1260 | 4 0 0.00013568199137512437 1 0.023488047693331182 2 0.97637627031528351 1261 | 3 1.0275634509948617e-14 1262 | 4 0 0.00016362917492529738 1 0.025043409139926743 2 0.97479296168518725 1263 | 3 -3.9402509033337196e-14 1264 | 4 0 0.00020833077102955753 1 0.027319810458584576 2 0.97247185877037134 1265 | 3 1.4447644469672838e-14 1266 | 4 0 0.00025908102299922382 1 0.029778131390838049 2 0.96996278758615462 1267 | 3 8.0677652058991356e-15 1268 | 4 0 0.00030210587279602864 1 0.031859158100648689 2 0.96783873602656723 1269 | 3 -1.1922754450388595e-14 1270 | 4 0 0.00032872108518917806 1 0.033309679793123027 2 0.96636159912167896 1271 | 3 8.8631359196345016e-15 1272 | 4 0 0.00034009972826904344 1 0.034179976334993915 2 0.96547992393674142 1273 | 3 -4.3667326699026177e-15; 1274 | setAttr ".weightList[136:141].weights" 1275 | 4 0 0.00034296947834447231 1 0.034598964218205672 2 0.9650580663035031 1276 | 3 -5.3295692512000947e-14 1277 | 4 0 0.00034313742856601376 1 0.034624006965417307 2 0.96503285560589369 1278 | 3 1.2296912620113343e-13 1279 | 4 0 0.00034024578618522351 1 0.034227211881800473 2 0.9654325423318566 1280 | 3 1.5776247495880025e-13 1281 | 4 0 0.00032834181894767075 1 0.033320093087973339 2 0.96635156509293685 1282 | 3 1.4206561274598961e-13 1283 | 2 0 0.99999999999999978 1 5.222464424595126e-20 1284 | 4 0 5.0386572987813936e-05 1 0.0080470394377575652 2 0.99190257399591775 1285 | 3 -6.6630438146086934e-12; 1286 | setAttr -size 4 ".bindPreMatrix"; 1287 | setAttr ".bindPreMatrix[0]" -type "matrix" 0 -1 0 0 1 0 0 0 0 0 1 0 0 0 0 1; 1288 | setAttr ".bindPreMatrix[1]" -type "matrix" 0 -1 0 0 1 0 0 0 0 0 1 0 -2 0 0 1; 1289 | setAttr ".bindPreMatrix[2]" -type "matrix" 0 -1 0 0 1 0 0 0 0 0 1 0 -4 0 0 1; 1290 | setAttr ".bindPreMatrix[3]" -type "matrix" 1 0 0 0 0 1 0 0 0 0 1 0 0 -6 0 1; 1291 | setAttr ".geomMatrix" -type "matrix" 1 0 0 0 0 1 0 0 0 0 1 0 0 3 0 1; 1292 | setAttr -size 4 ".matrix"; 1293 | setAttr -size 4 ".dropoff[0:3]" 4 4 4 4; 1294 | setAttr -size 4 ".lockWeights"; 1295 | setAttr -size 4 ".lockWeights"; 1296 | setAttr ".maxInfluences" 3; 1297 | setAttr ".bindMethod" 1; 1298 | setAttr ".useComponentsMatrix" yes; 1299 | setAttr -size 4 ".influenceColor"; 1300 | setAttr -size 4 ".influenceColor"; 1301 | createNode displayLayer -name "L_SRC"; 1302 | rename -uuid "3F52AC42-4F61-24C3-02D1-9A961D51DC59"; 1303 | setAttr ".color" 13; 1304 | setAttr ".displayOrder" 1; 1305 | createNode displayLayer -name "L_DST"; 1306 | rename -uuid "8D7260B2-4ED7-CBF1-00F7-FD954C8350C9"; 1307 | setAttr ".color" 14; 1308 | setAttr ".displayOrder" 2; 1309 | select -noExpand :time1; 1310 | setAttr -alteredValue -keyable on ".caching"; 1311 | setAttr -keyable on ".frozen"; 1312 | setAttr -alteredValue -channelBox on ".isHistoricallyInteresting"; 1313 | setAttr -alteredValue -keyable on ".nodeState"; 1314 | setAttr -channelBox on ".binMembership"; 1315 | setAttr -keyable on ".outTime" 0; 1316 | setAttr -alteredValue -keyable on ".unwarpedTime"; 1317 | setAttr -alteredValue -keyable on ".enableTimewarp"; 1318 | setAttr -alteredValue -keyable on ".timecodeProductionStart"; 1319 | setAttr -alteredValue -keyable on ".timecodeMayaStart"; 1320 | select -noExpand :hardwareRenderingGlobals; 1321 | setAttr -alteredValue -keyable on ".caching"; 1322 | setAttr -alteredValue -keyable on ".isHistoricallyInteresting"; 1323 | setAttr -alteredValue -keyable on ".nodeState"; 1324 | setAttr -channelBox on ".binMembership"; 1325 | setAttr ".objectTypeFilterNameArray" -type "stringArray" 22 "NURBS Curves" "NURBS Surfaces" "Polygons" "Subdiv Surface" "Particles" "Particle Instance" "Fluids" "Strokes" "Image Planes" "UI" "Lights" "Cameras" "Locators" "Joints" "IK Handles" "Deformers" "Motion Trails" "Components" "Hair Systems" "Follicles" "Misc. UI" "Ornaments" ; 1326 | setAttr ".objectTypeFilterValueArray" -type "Int32Array" 22 0 1 1 1327 | 1 1 1 1 1 1 0 0 0 0 0 0 1328 | 0 0 0 0 0 0 0 ; 1329 | setAttr -keyable on ".hwInstancing"; 1330 | setAttr -alteredValue ".transparencyAlgorithm"; 1331 | setAttr -alteredValue ".transparencyQuality"; 1332 | setAttr -alteredValue ".enableTextureMaxRes"; 1333 | setAttr -alteredValue ".textureMaxResolution"; 1334 | setAttr -alteredValue ".ssaoEnable"; 1335 | setAttr -alteredValue ".ssaoAmount"; 1336 | setAttr -alteredValue ".ssaoRadius"; 1337 | setAttr -keyable on ".hwFogFalloff"; 1338 | setAttr -alteredValue -keyable on ".hwFogDensity"; 1339 | setAttr -alteredValue -keyable on ".hwFogStart"; 1340 | setAttr -alteredValue -keyable on ".hwFogEnd"; 1341 | setAttr -alteredValue ".hwFogColor"; 1342 | setAttr -alteredValue -keyable on ".hwFogColorR"; 1343 | setAttr -alteredValue -keyable on ".hwFogColorG"; 1344 | setAttr -alteredValue -keyable on ".hwFogColorB"; 1345 | setAttr -alteredValue -keyable on ".hwFogAlpha"; 1346 | setAttr -alteredValue ".motionBlurEnable"; 1347 | setAttr -alteredValue -keyable on ".motionBlurShutterOpenFraction"; 1348 | setAttr -keyable on ".bloomEnable"; 1349 | setAttr -keyable on ".bloomAmount"; 1350 | setAttr -alteredValue ".multiSampleEnable"; 1351 | select -noExpand :renderPartition; 1352 | setAttr -alteredValue -keyable on ".caching"; 1353 | setAttr -channelBox on ".isHistoricallyInteresting"; 1354 | setAttr -alteredValue -keyable on ".nodeState"; 1355 | setAttr -channelBox on ".binMembership"; 1356 | setAttr -size 3 ".sets"; 1357 | setAttr -channelBox on ".annotation"; 1358 | setAttr -channelBox on ".partitionType"; 1359 | select -noExpand :renderGlobalsList1; 1360 | setAttr -keyable on ".caching"; 1361 | setAttr -channelBox on ".isHistoricallyInteresting"; 1362 | setAttr -keyable on ".nodeState"; 1363 | setAttr -channelBox on ".binMembership"; 1364 | select -noExpand :defaultShaderList1; 1365 | setAttr -keyable on ".caching"; 1366 | setAttr -channelBox on ".isHistoricallyInteresting"; 1367 | setAttr -keyable on ".nodeState"; 1368 | setAttr -channelBox on ".binMembership"; 1369 | setAttr -size 5 ".shaders"; 1370 | select -noExpand :postProcessList1; 1371 | setAttr -keyable on ".caching"; 1372 | setAttr -channelBox on ".isHistoricallyInteresting"; 1373 | setAttr -keyable on ".nodeState"; 1374 | setAttr -channelBox on ".binMembership"; 1375 | setAttr -size 2 ".postProcesses"; 1376 | select -noExpand :defaultRenderingList1; 1377 | setAttr -keyable on ".isHistoricallyInteresting"; 1378 | select -noExpand :standardSurface1; 1379 | setAttr ".baseColor" -type "float3" 0.40000001 0.40000001 0.40000001 ; 1380 | setAttr ".specularRoughness" 0.5; 1381 | select -noExpand :initialShadingGroup; 1382 | setAttr -alteredValue -keyable on ".caching"; 1383 | setAttr -keyable on ".frozen"; 1384 | setAttr -channelBox on ".isHistoricallyInteresting"; 1385 | setAttr -alteredValue -keyable on ".nodeState"; 1386 | setAttr -channelBox on ".binMembership"; 1387 | setAttr -keyable on ".blackBox"; 1388 | setAttr -keyable on ".viewMode"; 1389 | setAttr -keyable on ".templateVersion"; 1390 | setAttr -keyable on ".uiTreatment"; 1391 | setAttr -keyable on ".memberWireframeColor"; 1392 | setAttr -alteredValue -channelBox on ".annotation"; 1393 | setAttr -channelBox on ".isLayer"; 1394 | setAttr -channelBox on ".verticesOnlySet"; 1395 | setAttr -channelBox on ".edgesOnlySet"; 1396 | setAttr -channelBox on ".facetsOnlySet"; 1397 | setAttr -channelBox on ".editPointsOnlySet"; 1398 | setAttr -keyable on ".renderableOnlySet" yes; 1399 | setAttr -channelBox on ".aiOverride"; 1400 | setAttr -keyable on ".aiSurfaceShader"; 1401 | setAttr -channelBox on ".aiSurfaceShaderR"; 1402 | setAttr -channelBox on ".aiSurfaceShaderG"; 1403 | setAttr -channelBox on ".aiSurfaceShaderB"; 1404 | setAttr -keyable on ".aiVolumeShader"; 1405 | setAttr -channelBox on ".aiVolumeShaderR"; 1406 | setAttr -channelBox on ".aiVolumeShaderG"; 1407 | setAttr -channelBox on ".aiVolumeShaderB"; 1408 | select -noExpand :initialParticleSE; 1409 | setAttr -alteredValue -keyable on ".caching"; 1410 | setAttr -channelBox on ".isHistoricallyInteresting"; 1411 | setAttr -alteredValue -keyable on ".nodeState"; 1412 | setAttr -channelBox on ".binMembership"; 1413 | setAttr -keyable on ".memberWireframeColor"; 1414 | setAttr -channelBox on ".annotation"; 1415 | setAttr -channelBox on ".isLayer"; 1416 | setAttr -channelBox on ".verticesOnlySet"; 1417 | setAttr -channelBox on ".edgesOnlySet"; 1418 | setAttr -channelBox on ".facetsOnlySet"; 1419 | setAttr -channelBox on ".editPointsOnlySet"; 1420 | setAttr -keyable on ".renderableOnlySet" yes; 1421 | setAttr -channelBox on ".aiOverride"; 1422 | setAttr -keyable on ".aiSurfaceShader"; 1423 | setAttr -channelBox on ".aiSurfaceShaderR"; 1424 | setAttr -channelBox on ".aiSurfaceShaderG"; 1425 | setAttr -channelBox on ".aiSurfaceShaderB"; 1426 | setAttr -keyable on ".aiVolumeShader"; 1427 | setAttr -channelBox on ".aiVolumeShaderR"; 1428 | setAttr -channelBox on ".aiVolumeShaderG"; 1429 | setAttr -channelBox on ".aiVolumeShaderB"; 1430 | select -noExpand :initialMaterialInfo; 1431 | select -noExpand :defaultRenderGlobals; 1432 | addAttr -cachedInternally true -hidden true -shortName "dss" -longName "defaultSurfaceShader" 1433 | -dataType "string"; 1434 | setAttr -alteredValue -keyable on ".caching"; 1435 | setAttr -channelBox on ".isHistoricallyInteresting"; 1436 | setAttr -alteredValue -keyable on ".nodeState"; 1437 | setAttr -channelBox on ".binMembership"; 1438 | setAttr -alteredValue -keyable on ".macCodec"; 1439 | setAttr -alteredValue -keyable on ".macDepth"; 1440 | setAttr -alteredValue -keyable on ".macQual"; 1441 | setAttr -alteredValue -keyable on ".comFrrt"; 1442 | setAttr -channelBox on ".ignoreFilmGate"; 1443 | setAttr -alteredValue -keyable on ".clipFinalShadedColor"; 1444 | setAttr -alteredValue -keyable on ".enableDepthMaps"; 1445 | setAttr -alteredValue -keyable on ".enableDefaultLight"; 1446 | setAttr -alteredValue -channelBox on ".currentRenderer" -type "string" "arnold"; 1447 | setAttr -alteredValue -keyable on ".enableStrokeRender"; 1448 | setAttr -alteredValue -keyable on ".onlyRenderStrokes"; 1449 | setAttr -channelBox on ".strokesDepthFile"; 1450 | setAttr -alteredValue -keyable on ".imageFormat"; 1451 | setAttr -alteredValue -channelBox on ".imfPluginKey"; 1452 | setAttr -alteredValue -keyable on ".gammaCorrection"; 1453 | setAttr -alteredValue -keyable on ".exrCompression"; 1454 | setAttr -alteredValue -keyable on ".exrPixelType"; 1455 | setAttr -alteredValue -keyable on ".animation"; 1456 | setAttr -channelBox on ".animationRange"; 1457 | setAttr -alteredValue -keyable on ".startFrame" 1; 1458 | setAttr -alteredValue -keyable on ".endFrame" 10; 1459 | setAttr -alteredValue -keyable on ".byFrameStep"; 1460 | setAttr -alteredValue -channelBox on ".modifyExtension"; 1461 | setAttr -channelBox on ".startExtension"; 1462 | setAttr -alteredValue -keyable on ".byExtension"; 1463 | setAttr -alteredValue -channelBox on ".extensionPadding"; 1464 | setAttr -alteredValue -keyable on ".fieldExtControl"; 1465 | setAttr -alteredValue -keyable on ".outFormatControl"; 1466 | setAttr -channelBox on ".oddFieldExt"; 1467 | setAttr -channelBox on ".evenFieldExt"; 1468 | setAttr -channelBox on ".outFormatExt"; 1469 | setAttr -channelBox on ".useMayaFileName"; 1470 | setAttr -channelBox on ".useFrameExt"; 1471 | setAttr -alteredValue -channelBox on ".putFrameBeforeExt"; 1472 | setAttr -alteredValue -channelBox on ".periodInExt"; 1473 | setAttr -alteredValue -channelBox on ".imageFilePrefix"; 1474 | setAttr -keyable on ".renderVersion"; 1475 | setAttr -alteredValue -keyable on ".composite"; 1476 | setAttr -alteredValue -keyable on ".compositeThreshold"; 1477 | setAttr -alteredValue -keyable on ".shadowsObeyLightLinking"; 1478 | setAttr -alteredValue -channelBox on ".shadowsObeyShadowLinking"; 1479 | setAttr -alteredValue -keyable on ".recursionDepth"; 1480 | setAttr -alteredValue -keyable on ".leafPrimitives"; 1481 | setAttr -alteredValue -keyable on ".subdivisionPower"; 1482 | setAttr -alteredValue -keyable on ".subdivisionHashSize"; 1483 | setAttr -alteredValue -keyable on ".logRenderPerformance"; 1484 | setAttr -channelBox on ".geometryVector"; 1485 | setAttr -channelBox on ".shadingVector"; 1486 | setAttr -alteredValue -keyable on ".maximumMemory"; 1487 | setAttr -alteredValue -keyable on ".numCpusToUse"; 1488 | setAttr -alteredValue -keyable on ".interruptFrequency"; 1489 | setAttr -alteredValue -keyable on ".shadowPass"; 1490 | setAttr -channelBox on ".iprShadowPass"; 1491 | setAttr -alteredValue -keyable on ".useFileCache"; 1492 | setAttr -alteredValue -keyable on ".optimizeInstances"; 1493 | setAttr -alteredValue -keyable on ".reuseTessellations"; 1494 | setAttr -alteredValue -keyable on ".matteOpacityUsesTransparency"; 1495 | setAttr -alteredValue -channelBox on ".motionBlur"; 1496 | setAttr -alteredValue -keyable on ".motionBlurByFrame"; 1497 | setAttr -alteredValue -keyable on ".motionBlurShutterOpen"; 1498 | setAttr -alteredValue -keyable on ".motionBlurShutterClose"; 1499 | setAttr -alteredValue -keyable on ".applyFogInPost"; 1500 | setAttr -alteredValue -keyable on ".postFogBlur"; 1501 | setAttr -alteredValue -keyable on ".preMel"; 1502 | setAttr -alteredValue -keyable on ".postMel"; 1503 | setAttr -alteredValue -keyable on ".preRenderLayerMel"; 1504 | setAttr -alteredValue -keyable on ".postRenderLayerMel"; 1505 | setAttr -alteredValue -channelBox on ".preRenderMel"; 1506 | setAttr -alteredValue -channelBox on ".postRenderMel"; 1507 | setAttr -channelBox on ".preFurRenderMel"; 1508 | setAttr -channelBox on ".postFurRenderMel"; 1509 | setAttr -alteredValue -keyable on ".blurLength"; 1510 | setAttr -alteredValue -keyable on ".blurSharpness"; 1511 | setAttr -alteredValue -keyable on ".smoothValue"; 1512 | setAttr -alteredValue -keyable on ".useBlur2DMemoryCap"; 1513 | setAttr -alteredValue -keyable on ".blur2DMemoryCap"; 1514 | setAttr -channelBox on ".motionBlurType"; 1515 | setAttr -alteredValue -keyable on ".useDisplacementBoundingBox"; 1516 | setAttr -alteredValue -keyable on ".smoothColor"; 1517 | setAttr -alteredValue -keyable on ".keepMotionVector"; 1518 | setAttr -channelBox on ".iprRenderShading"; 1519 | setAttr -channelBox on ".iprRenderShadowMaps"; 1520 | setAttr -channelBox on ".iprRenderMotionBlur"; 1521 | setAttr -alteredValue -keyable on ".renderLayerEnable"; 1522 | setAttr -alteredValue -keyable on ".forceTileSize"; 1523 | setAttr -alteredValue -keyable on ".tileWidth"; 1524 | setAttr -alteredValue -keyable on ".tileHeight"; 1525 | setAttr -alteredValue -keyable on ".jitterFinalColor"; 1526 | setAttr -channelBox on ".raysSeeBackground"; 1527 | setAttr -alteredValue -keyable on ".oversamplePaintEffects"; 1528 | setAttr -alteredValue -keyable on ".oversamplePfxPostFilter"; 1529 | setAttr -alteredValue -keyable on ".renderingColorProfile"; 1530 | setAttr -alteredValue -keyable on ".inputColorProfile"; 1531 | setAttr -alteredValue -keyable on ".outputColorProfile"; 1532 | setAttr -channelBox on ".hyperShadeBinList"; 1533 | setAttr ".defaultSurfaceShader" -type "string" "standardSurface1"; 1534 | select -noExpand :defaultResolution; 1535 | setAttr -alteredValue -keyable on ".caching"; 1536 | setAttr -alteredValue -keyable on ".isHistoricallyInteresting"; 1537 | setAttr -alteredValue -keyable on ".nodeState"; 1538 | setAttr -keyable on ".binMembership"; 1539 | setAttr -alteredValue -keyable on ".width"; 1540 | setAttr -alteredValue -keyable on ".height"; 1541 | setAttr -alteredValue -keyable on ".pixelAspect" 1; 1542 | setAttr -alteredValue -keyable on ".aspectLock"; 1543 | setAttr -alteredValue -keyable on ".deviceAspectRatio"; 1544 | setAttr -alteredValue -keyable on ".lockDeviceAspectRatio"; 1545 | setAttr -alteredValue -keyable on ".dotsPerInch"; 1546 | setAttr -alteredValue -keyable on ".oddFieldFirst"; 1547 | setAttr -alteredValue -keyable on ".fields"; 1548 | setAttr -alteredValue -keyable on ".zerothScanline"; 1549 | setAttr -alteredValue -keyable on ".imageSizeUnits"; 1550 | setAttr -alteredValue -keyable on ".pixelDensityUnits"; 1551 | select -noExpand :defaultColorMgtGlobals; 1552 | setAttr ".cmEnabled" no; 1553 | setAttr ".configFileEnabled" yes; 1554 | setAttr ".configFilePath" -type "string" "/OCIO-configs/Maya2022-default/config.ocio"; 1555 | setAttr ".viewTransformName" -type "string" "ACES 1.0 SDR-video (sRGB)"; 1556 | setAttr ".viewName" -type "string" "ACES 1.0 SDR-video"; 1557 | setAttr ".displayName" -type "string" "sRGB"; 1558 | setAttr ".workingSpaceName" -type "string" "ACEScg"; 1559 | setAttr ".outputTransformName" -type "string" "ACES 1.0 SDR-video (sRGB)"; 1560 | setAttr ".playblastOutputTransformName" -type "string" "ACES 1.0 SDR-video (sRGB)"; 1561 | select -noExpand :hardwareRenderGlobals; 1562 | setAttr -alteredValue -keyable on ".caching"; 1563 | setAttr -channelBox on ".isHistoricallyInteresting"; 1564 | setAttr -alteredValue -keyable on ".nodeState"; 1565 | setAttr -channelBox on ".binMembership"; 1566 | setAttr -alteredValue -keyable off -channelBox on ".colorTextureResolution" 256; 1567 | setAttr -alteredValue -keyable off -channelBox on ".bumpTextureResolution" 512; 1568 | setAttr -alteredValue -keyable off -channelBox on ".frameBufferFormat"; 1569 | setAttr -alteredValue -keyable off -channelBox on ".enableHighQualityLighting"; 1570 | setAttr -alteredValue -keyable off -channelBox on ".enableAcceleratedMultiSampling"; 1571 | setAttr -alteredValue -keyable off -channelBox on ".enableEdgeAntiAliasing"; 1572 | setAttr -alteredValue -keyable off -channelBox on ".enableGeometryMask"; 1573 | setAttr -alteredValue -keyable off -channelBox on ".numberOfSamples"; 1574 | setAttr -alteredValue -keyable off -channelBox on ".enableMotionBlur"; 1575 | setAttr -alteredValue -keyable off -channelBox on ".motionBlurByFrame"; 1576 | setAttr -alteredValue -keyable off -channelBox on ".numberOfExposures"; 1577 | setAttr -alteredValue -keyable off -channelBox on ".transparencySorting"; 1578 | setAttr -alteredValue -keyable off -channelBox on ".transparentShadowCasting"; 1579 | setAttr -alteredValue -keyable off -channelBox on ".enableNonPowerOfTwoTexture"; 1580 | setAttr -alteredValue -keyable off -channelBox on ".culling"; 1581 | setAttr -alteredValue -keyable off -channelBox on ".textureCompression"; 1582 | setAttr -alteredValue -keyable off -channelBox on ".lightIntensityThreshold"; 1583 | setAttr -alteredValue -keyable off -channelBox on ".smallObjectCulling"; 1584 | setAttr -alteredValue -keyable off -channelBox on ".cullingThreshold"; 1585 | setAttr -alteredValue -keyable off -channelBox on ".graphicsHardwareGeometryCachingData"; 1586 | setAttr -alteredValue -keyable off -channelBox on ".graphicsHardwareGeometryCachingIndexing"; 1587 | setAttr -alteredValue -keyable off -channelBox on ".maximumGeometryCacheSize"; 1588 | setAttr -alteredValue -keyable off -channelBox on ".writeAlphaAsColor"; 1589 | setAttr -alteredValue -keyable off -channelBox on ".writeZDepthAsColor"; 1590 | setAttr -keyable on ".hardwareCodec"; 1591 | setAttr -keyable on ".hardwareDepth"; 1592 | setAttr -keyable on ".hardwareQual"; 1593 | setAttr -keyable on ".hardwareFrameRate"; 1594 | setAttr -keyable on ".shadowsObeyLightLinking"; 1595 | setAttr -keyable on ".shadowsObeyShadowLinking"; 1596 | setAttr -keyable on ".blendSpecularWithAlpha"; 1597 | setAttr -keyable on ".shadingModel"; 1598 | setAttr -keyable on ".hardwareEnvironmentLookup"; 1599 | connectAttr "L_SRC.drawInfo" "Cylinder_SRC.drawOverride"; 1600 | connectAttr "deltaMush1.outputGeometry[0]" "Cylinder_SRCShape.inMesh"; 1601 | connectAttr "polyCylinder1.output" "Cylinder_SRCShapeOrig.inMesh"; 1602 | connectAttr "joint1.scale" "joint2.inverseScale"; 1603 | connectAttr "joint2.scale" "joint3.inverseScale"; 1604 | connectAttr "joint3.scale" "joint4.inverseScale"; 1605 | connectAttr "L_DST.drawInfo" "Cylinder_DST.drawOverride"; 1606 | connectAttr "skinCluster2.outputGeometry[0]" "Cylinder_DSTShape.inMesh"; 1607 | relationship "link" ":lightLinker1" ":initialShadingGroup.message" ":defaultLightSet.message"; 1608 | relationship "link" ":lightLinker1" ":initialParticleSE.message" ":defaultLightSet.message"; 1609 | relationship "link" ":lightLinker1" "lambert1SG.message" ":defaultLightSet.message"; 1610 | relationship "shadowLink" ":lightLinker1" ":initialShadingGroup.message" ":defaultLightSet.message"; 1611 | relationship "shadowLink" ":lightLinker1" ":initialParticleSE.message" ":defaultLightSet.message"; 1612 | relationship "shadowLink" ":lightLinker1" "lambert1SG.message" ":defaultLightSet.message"; 1613 | connectAttr "layerManager.displayLayerId[0]" "defaultLayer.identification"; 1614 | connectAttr "renderLayerManager.renderLayerId[0]" "defaultRenderLayer.identification" 1615 | ; 1616 | connectAttr ":defaultArnoldDisplayDriver.message" ":defaultArnoldRenderOptions.drivers" 1617 | -nextAvailable; 1618 | connectAttr ":defaultArnoldFilter.message" ":defaultArnoldRenderOptions.filter"; 1619 | connectAttr ":defaultArnoldDriver.message" ":defaultArnoldRenderOptions.driver"; 1620 | connectAttr "ROOT.message" "bindPose1.members[0]"; 1621 | connectAttr "JOINTS.message" "bindPose1.members[1]"; 1622 | connectAttr "joint1.message" "bindPose1.members[2]"; 1623 | connectAttr "joint2.message" "bindPose1.members[3]"; 1624 | connectAttr "joint3.message" "bindPose1.members[4]"; 1625 | connectAttr "joint4.message" "bindPose1.members[8]"; 1626 | connectAttr "bindPose1.world" "bindPose1.parents[0]"; 1627 | connectAttr "bindPose1.members[0]" "bindPose1.parents[1]"; 1628 | connectAttr "bindPose1.members[1]" "bindPose1.parents[2]"; 1629 | connectAttr "bindPose1.members[2]" "bindPose1.parents[3]"; 1630 | connectAttr "bindPose1.members[3]" "bindPose1.parents[4]"; 1631 | connectAttr "bindPose1.members[4]" "bindPose1.parents[6]"; 1632 | connectAttr "bindPose1.members[4]" "bindPose1.parents[7]"; 1633 | connectAttr "bindPose1.members[4]" "bindPose1.parents[8]"; 1634 | connectAttr "joint1.bindPose" "bindPose1.worldMatrix[2]"; 1635 | connectAttr "joint2.bindPose" "bindPose1.worldMatrix[3]"; 1636 | connectAttr "joint3.bindPose" "bindPose1.worldMatrix[4]"; 1637 | connectAttr "joint4.bindPose" "bindPose1.worldMatrix[8]"; 1638 | connectAttr ":initialShadingGroup.message" "MayaNodeEditorSavedTabsInfo.tabGraphInfo[0].nodeInfo[0].dependNode" 1639 | ; 1640 | connectAttr "Cylinder_DST.message" "MayaNodeEditorSavedTabsInfo.tabGraphInfo[0].nodeInfo[1].dependNode" 1641 | ; 1642 | connectAttr "Cylinder_DSTShape.message" "MayaNodeEditorSavedTabsInfo.tabGraphInfo[0].nodeInfo[2].dependNode" 1643 | ; 1644 | connectAttr ":lambert1.outColor" "lambert1SG.surfaceShader"; 1645 | connectAttr "Cylinder_DSTShape.instObjGroups" "lambert1SG.dagSetMembers" -nextAvailable 1646 | ; 1647 | connectAttr "Cylinder_SRCShape.instObjGroups" "lambert1SG.dagSetMembers" -nextAvailable 1648 | ; 1649 | connectAttr "lambert1SG.message" "materialInfo1.shadingGroup"; 1650 | connectAttr ":lambert1.message" "materialInfo1.material"; 1651 | connectAttr "lambert1SG.message" "hyperShadePrimaryNodeEditorSavedTabsInfo.tabGraphInfo[0].nodeInfo[32].dependNode" 1652 | ; 1653 | connectAttr "skinCluster1.outputGeometry[0]" "deltaMush1.input[0].inputGeometry" 1654 | ; 1655 | connectAttr "Cylinder_SRCShapeOrig.outMesh" "deltaMush1.originalGeometry[0]"; 1656 | connectAttr "Cylinder_SRCShapeOrig.worldMesh" "skinCluster1.input[0].inputGeometry" 1657 | ; 1658 | connectAttr "Cylinder_SRCShapeOrig.outMesh" "skinCluster1.originalGeometry[0]"; 1659 | connectAttr "bindPose1.message" "skinCluster1.bindPose"; 1660 | connectAttr "joint1.worldMatrix" "skinCluster1.matrix[0]"; 1661 | connectAttr "joint2.worldMatrix" "skinCluster1.matrix[1]"; 1662 | connectAttr "joint3.worldMatrix" "skinCluster1.matrix[2]"; 1663 | connectAttr "joint1.lockInfluenceWeights" "skinCluster1.lockWeights[0]"; 1664 | connectAttr "joint2.lockInfluenceWeights" "skinCluster1.lockWeights[1]"; 1665 | connectAttr "joint3.lockInfluenceWeights" "skinCluster1.lockWeights[2]"; 1666 | connectAttr "joint1.objectColorRGB" "skinCluster1.influenceColor[0]"; 1667 | connectAttr "joint2.objectColorRGB" "skinCluster1.influenceColor[1]"; 1668 | connectAttr "joint3.objectColorRGB" "skinCluster1.influenceColor[2]"; 1669 | connectAttr "joint2.message" "skinCluster1.paintTrans"; 1670 | connectAttr "Cylinder_DSTShapeOrig.worldMesh" "skinCluster2.input[0].inputGeometry" 1671 | ; 1672 | connectAttr "Cylinder_DSTShapeOrig.outMesh" "skinCluster2.originalGeometry[0]"; 1673 | connectAttr "joint1.worldMatrix" "skinCluster2.matrix[0]"; 1674 | connectAttr "joint2.worldMatrix" "skinCluster2.matrix[1]"; 1675 | connectAttr "joint3.worldMatrix" "skinCluster2.matrix[2]"; 1676 | connectAttr "joint4.worldMatrix" "skinCluster2.matrix[3]"; 1677 | connectAttr "joint1.lockInfluenceWeights" "skinCluster2.lockWeights[0]"; 1678 | connectAttr "joint2.lockInfluenceWeights" "skinCluster2.lockWeights[1]"; 1679 | connectAttr "joint3.lockInfluenceWeights" "skinCluster2.lockWeights[2]"; 1680 | connectAttr "joint4.lockInfluenceWeights" "skinCluster2.lockWeights[3]"; 1681 | connectAttr "joint1.objectColorRGB" "skinCluster2.influenceColor[0]"; 1682 | connectAttr "joint2.objectColorRGB" "skinCluster2.influenceColor[1]"; 1683 | connectAttr "joint3.objectColorRGB" "skinCluster2.influenceColor[2]"; 1684 | connectAttr "joint4.objectColorRGB" "skinCluster2.influenceColor[3]"; 1685 | connectAttr "bindPose1.message" "skinCluster2.bindPose"; 1686 | connectAttr "layerManager.displayLayerId[1]" "L_SRC.identification"; 1687 | connectAttr "layerManager.displayLayerId[2]" "L_DST.identification"; 1688 | connectAttr "lambert1SG.partition" ":renderPartition.sets" -nextAvailable; 1689 | connectAttr "defaultRenderLayer.message" ":defaultRenderingList1.rendering" -nextAvailable 1690 | ; 1691 | // End of CylinderTest_bis.ma 1692 | -------------------------------------------------------------------------------- /posedata/biped.json: -------------------------------------------------------------------------------- 1 | { 2 | "Ankle_L": [[-65.0, 65.0], [-25.0, 25.0], [-100.0, 52.0]], 3 | "Ankle_R": [[-65.0, 65.0], [-25.0, 25.0], [-100.0, 52.0]], 4 | "Chest_M": [[-20.0, 20.0], [-20.0, 20.0], [-20.0, 20.0]], 5 | "Elbow_L": [[0.0, 0.0], [0.0, 0.0], [-10.0, 150.0]], 6 | "Elbow_R": [[0.0, 0.0], [0.0, 0.0], [-10.0, 150.0]], 7 | "Head_M": [[-40.0, 40.0], [-40.0, 40.0], [-40.0, 40.0]], 8 | "Hip_L": [[-15.0, 15.0], [-90.0, 15.0], [-90.0, 90.0]], 9 | "Hip_R": [[-15.0, 15.0], [-90.0, 15.0], [-90.0, 90.0]], 10 | "IndexFinger1_L": [[0.0, 0.0], [-20.0, 90.0], [0.0, 0.0]], 11 | "IndexFinger1_R": [[0.0, 0.0], [-20.0, 90.0], [0.0, 0.0]], 12 | "IndexFinger2_L": [[0.0, 0.0], [-20.0, 90.0], [0.0, 0.0]], 13 | "IndexFinger2_R": [[0.0, 0.0], [-20.0, 90.0], [0.0, 0.0]], 14 | "IndexFinger3_L": [[0.0, 0.0], [-20.0, 90.0], [0.0, 0.0]], 15 | "IndexFinger3_R": [[0.0, 0.0], [-20.0, 90.0], [0.0, 0.0]], 16 | "IndexFinger5_L": [[-3.0, 3.0], [-3.0, 3.0], [-3.0, 3.0]], 17 | "IndexFinger5_R": [[-3.0, 3.0], [-3.0, 3.0], [-3.0, 3.0]], 18 | "Knee_L": [[0.0, 0.0], [0.0, 0.0], [-150.0, 8.0]], 19 | "Knee_R": [[0.0, 0.0], [0.0, 0.0], [-150.0, 8.0]], 20 | "MiddleFinger1_L": [[0.0, 0.0], [-20.0, 90.0], [0.0, 0.0]], 21 | "MiddleFinger1_R": [[0.0, 0.0], [-20.0, 90.0], [0.0, 0.0]], 22 | "MiddleFinger2_L": [[0.0, 0.0], [-20.0, 90.0], [0.0, 0.0]], 23 | "MiddleFinger2_R": [[0.0, 0.0], [-20.0, 90.0], [0.0, 0.0]], 24 | "MiddleFinger3_L": [[0.0, 0.0], [-20.0, 90.0], [0.0, 0.0]], 25 | "MiddleFinger3_R": [[0.0, 0.0], [-20.0, 90.0], [0.0, 0.0]], 26 | "MiddleFinger5_L": [[-3.0, 3.0], [-3.0, 3.0], [-3.0, 3.0]], 27 | "MiddleFinger5_R": [[-3.0, 3.0], [-3.0, 3.0], [-3.0, 3.0]], 28 | "NeckPart1_M": [[-40.0, 40.0], [-40.0, 40.0], [-40.0, 40.0]], 29 | "NeckPart2_M": [[-40.0, 40.0], [-40.0, 40.0], [-40.0, 40.0]], 30 | "Neck_M": [[-40.0, 40.0], [-40.0, 40.0], [-40.0, 40.0]], 31 | "PinkyFinger1_L": [[0.0, 0.0], [-20.0, 90.0], [0.0, 0.0]], 32 | "PinkyFinger1_R": [[0.0, 0.0], [-20.0, 90.0], [0.0, 0.0]], 33 | "PinkyFinger2_L": [[0.0, 0.0], [-20.0, 90.0], [0.0, 0.0]], 34 | "PinkyFinger2_R": [[0.0, 0.0], [-20.0, 90.0], [0.0, 0.0]], 35 | "PinkyFinger3_L": [[0.0, 0.0], [-20.0, 90.0], [0.0, 0.0]], 36 | "PinkyFinger3_R": [[0.0, 0.0], [-20.0, 90.0], [0.0, 0.0]], 37 | "PinkyFinger5_L": [[-3.0, 3.0], [-3.0, 3.0], [-3.0, 3.0]], 38 | "PinkyFinger5_R": [[-3.0, 3.0], [-3.0, 3.0], [-3.0, 3.0]], 39 | "RingFinger1_L": [[0.0, 0.0], [-20.0, 90.0], [0.0, 0.0]], 40 | "RingFinger1_R": [[0.0, 0.0], [-20.0, 90.0], [0.0, 0.0]], 41 | "RingFinger2_L": [[0.0, 0.0], [-20.0, 90.0], [0.0, 0.0]], 42 | "RingFinger2_R": [[0.0, 0.0], [-20.0, 90.0], [0.0, 0.0]], 43 | "RingFinger3_L": [[0.0, 0.0], [-20.0, 90.0], [0.0, 0.0]], 44 | "RingFinger3_R": [[0.0, 0.0], [-20.0, 90.0], [0.0, 0.0]], 45 | "RingFinger5_L": [[-3.0, 3.0], [-3.0, 3.0], [-3.0, 3.0]], 46 | "RingFinger5_R": [[-3.0, 3.0], [-3.0, 3.0], [-3.0, 3.0]], 47 | "Root_M": [[0.0, 0.0], [0.0, 0.0], [0.0, 0.0]], 48 | "Scapula_L": [[0.0, 0.0], [-35.0, 10.0], [-40.0, 30.0]], 49 | "Scapula_R": [[0.0, 0.0], [-35.0, 10.0], [-40.0, 30.0]], 50 | "Shoulder_L": [[-60.0, 20.0], [-20.0, 80.0], [-300.0, 120.0]], 51 | "Shoulder_R": [[-60.0, 20.0], [-20.0, 80.0], [-300.0, 120.0]], 52 | "Spine1Part1_M": [[-50.0, 50.0], [-30.0, 30.0], [-30.0, 30.0]], 53 | "Spine1_M": [[-50.0, 50.0], [-20.0, 20.0], [-45.0, 90.0]], 54 | "Spine2_M": [[-50.0, 50.0], [-30.0, 30.0], [-30.0, 30.0]], 55 | "ThumbFinger1_L": [[0.0, 0.0], [-30.0, 30.0], [-10.0, 10.0]], 56 | "ThumbFinger1_R": [[0.0, 0.0], [-30.0, 30.0], [-10.0, 10.0]], 57 | "ThumbFinger2_L": [[0.0, 0.0], [-10.0, 90.0], [0.0, 0.0]], 58 | "ThumbFinger2_R": [[0.0, 0.0], [-10.0, 90.0], [0.0, 0.0]], 59 | "ThumbFinger3_L": [[0.0, 0.0], [-10.0, 90.0], [0.0, 0.0]], 60 | "ThumbFinger3_R": [[0.0, 0.0], [-10.0, 90.0], [0.0, 0.0]], 61 | "Toes_L": [[0.0, 0.0], [0.0, 9.0], [0.0, 0.0]], 62 | "Toes_R": [[0.0, 0.0], [0.0, 9.0], [0.0, 0.0]], 63 | "Wrist_L": [[-50.0, 50.0], [-60.0, 80.0], [-45.0, 45.0]], 64 | "Wrist_R": [[-50.0, 50.0], [-60.0, 80.0], [-45.0, 45.0]] 65 | } -------------------------------------------------------------------------------- /training/PyTorch/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RDelet/FFDA/1525a5fd27aed938a439daa4812d1e20783b1eff/training/PyTorch/__init__.py -------------------------------------------------------------------------------- /training/PyTorch/architecture.py: -------------------------------------------------------------------------------- 1 | import os 2 | from collections import namedtuple 3 | from time import time 4 | from tqdm import tqdm 5 | 6 | import numpy as np 7 | from torch import inf as torchInf, no_grad, save as torchSave, from_numpy 8 | from torch.nn import Module, Linear, Sequential 9 | 10 | from fdda.core.logger import log 11 | from fdda.training.PyTorch.callbacks import EarlyStop 12 | from fdda.training.PyTorch.math import feature_standardization 13 | from fdda.training.PyTorch.settings import Settings, Activation 14 | 15 | 16 | TorchModel = namedtuple("TorchModel", ["model", "vertices"]) 17 | 18 | 19 | class MultiLayerPerceptron(Module): 20 | 21 | def __init__(self, 22 | settings: Settings, 23 | input_shape: np.array, 24 | output_shape: np.array, 25 | **kwargs): 26 | """!@Brief This class implements a vertex delta model that learns how to correct 27 | the deformation error in a mesh by learning a list of delta from the 28 | rotation of all bone rotation. 29 | """ 30 | super().__init__() 31 | 32 | layers = [] 33 | if settings.layers < 2: 34 | log.warning("A minimum of 2 layers is required.") 35 | settings.layers = 2 36 | 37 | for layer in range(settings.layers): 38 | if not layer: 39 | layers.append(Linear(in_features=input_shape[1], out_features=settings.units)) 40 | if settings.activation is not Activation.kLinear: 41 | layers.append(settings.activation) 42 | continue 43 | # Last layer should have a linear activation function. 44 | if layer == settings.layers - 1: 45 | layers.append(Linear(in_features=settings.units, out_features=output_shape[1])) 46 | continue 47 | 48 | layers.append(Linear(in_features=settings.units, out_features=settings.units)) 49 | if settings.activation is not Activation.kLinear: 50 | layers.append(settings.activation) 51 | 52 | self.net = Sequential(*layers) 53 | 54 | def __str__(self) -> str: 55 | return self.__repr__() 56 | 57 | def __repr__(self) -> str: 58 | return f"FDDA(class: {self.__class__.__name__}, module: Pytorch)" 59 | 60 | def forward(self, inputs): 61 | return self.net(inputs) 62 | 63 | 64 | # Training function 65 | def fit(model, train_loader, validation_loader, loss_func, optimizer, writer, save_dir, settings, 66 | input_shape, output_shape, epochs, batch_size=32, device='cpu'): 67 | """!@Brief Train function. 68 | 69 | @param model: The network to be trained. 70 | @param train_loader: The training set. 71 | @param validation_loader: The validation set. 72 | @param loss_func: The cost function. 73 | @param optimizer: The optimizer function. 74 | @param writer: Tensorboard writer. 75 | @param save_dir: directory where the model checkpoint will be saved. 76 | @param settings: parameters of the training. 77 | @param input_shape: input dimensions. 78 | @param output_shape: output dimensions. 79 | @param epochs: Number of training epochs. 80 | @param batch_size: Number of samples per batch. 81 | @param device: Device, by default the training run on cpu. 82 | """ 83 | log.info("train() called: model=%s, opt=%s(lr=%f), epochs=%d, batch_size=%d, device=%s\n" % 84 | (type(model).__name__, type(optimizer).__name__, optimizer.param_groups[0]['lr'], 85 | epochs, batch_size, device)) 86 | 87 | # Collects per-epoch loss and acc like Keras' fit(). 88 | history = {} 89 | history['loss'] = [] 90 | history['val_loss'] = [] 91 | 92 | callback = EarlyStop(patience=20) 93 | 94 | model_state_file = os.path.join(save_dir, 'optimal_ckpt.pt') 95 | 96 | for epoch in range(0, epochs): 97 | 98 | # Time measures. 99 | loading_time = 0.0 100 | processing_time = 0.0 101 | 102 | # Global epoch loss. 103 | epoch_loss = 0.0 104 | n_samples = 0 105 | 106 | # Make sure the model run in training mode. 107 | model.train() 108 | start = time() 109 | 110 | with tqdm(enumerate(train_loader), unit='batch', miniters=2) as pbar: 111 | for i, (joints, delta_true) in pbar: 112 | pbar.set_description(f"Epoch [{epoch}/{epochs}]") 113 | joints, delta_true = joints.to(device), delta_true.to(device) 114 | # Measure loading data process time to find any bottleneck. 115 | tmp_load_timer = (time() - start) 116 | loading_time += tmp_load_timer 117 | # Clear the gradients 118 | optimizer.zero_grad() 119 | # Forward Pass: Compute predictions. 120 | delta = model(joints) 121 | # Compute loss. 122 | loss = loss_func(delta, delta_true) 123 | # Backpropagation. 124 | loss.backward() 125 | optimizer.step() 126 | # Average loss along the dataset. 127 | n_samples += joints.size(0) 128 | epoch_loss += loss.item() * joints.size(0) 129 | # Measure processing time. 130 | processing_time += time() - (start + tmp_load_timer) 131 | # Logs 132 | pbar.set_postfix(loss=(epoch_loss / n_samples), computation_time=(processing_time / n_samples), 133 | loading_time=(loading_time / n_samples)) 134 | 135 | start = time() 136 | 137 | # Validation step 138 | if validation_loader is not None: 139 | model.eval() 140 | 141 | val_samples = 0 142 | v_loss = 0.0 143 | 144 | # Disable gradient computation and reduce memory consumption. 145 | with no_grad(): 146 | for i, (joints, delta_true) in enumerate(validation_loader): 147 | joints, delta_true = joints.to(device), delta_true.to(device) 148 | 149 | # Forward Pass: Compute predictions. 150 | delta = model(joints) 151 | 152 | # Compute loss. 153 | loss = loss_func(delta, delta_true) 154 | 155 | # Average loss along the dataset. 156 | val_samples += joints.size(0) 157 | v_loss += loss.item() * joints.size(0) 158 | 159 | writer.add_scalar('Loss/validation', (v_loss / val_samples), epoch) 160 | history['val_loss'].append((v_loss / val_samples)) 161 | 162 | # Update Tensorboard. 163 | writer.add_scalar('Loss/train', (epoch_loss / n_samples), epoch) 164 | 165 | # Update history. 166 | history['loss'].append((epoch_loss / n_samples)) 167 | 168 | # Save the best learned model. 169 | is_best = (v_loss / val_samples) < torchInf 170 | 171 | if is_best: 172 | torchSave({'model_state_dict': model.state_dict(), 173 | 'input_shape': input_shape, 174 | 'output_shape': output_shape, 175 | 'settings': settings}, model_state_file) 176 | 177 | if callback.early_stop((epoch_loss / n_samples)): 178 | log.info('=> '.format(save_dir)) 179 | break 180 | 181 | writer.flush() 182 | return history, model_state_file 183 | 184 | 185 | # Evaluation function 186 | def evaluation(model, inputs, loss_func, batch_size=32, device='cpu'): 187 | pass 188 | 189 | 190 | def get_prediction(model: TorchModel, inputs: np.array, 191 | mean: list, std: list, 192 | normalized: bool = True, device: str = "cpu") -> np.array: 193 | # Apply normalization 194 | if normalized: 195 | mean = np.array(mean, dtype=np.float32) 196 | std = np.array(std, dtype=np.float32) 197 | inputs = feature_standardization(inputs, mean, std) 198 | # Convert Numpy -> torch.Tensor 199 | inputs = from_numpy(inputs).to(device) 200 | # Prediction 201 | prediction = model.model(inputs) 202 | # Convert torch.Tensor -> Numpy 203 | prediction = prediction.detach().cpu().numpy() 204 | 205 | return prediction 206 | -------------------------------------------------------------------------------- /training/PyTorch/callbacks.py: -------------------------------------------------------------------------------- 1 | import torch 2 | 3 | 4 | class EarlyStop: 5 | 6 | def __init__(self, patience=1, min_delta=0): 7 | self.patience = patience 8 | self.min_delta = min_delta 9 | self.counter = 0 10 | self.min_validation_loss = torch.inf 11 | 12 | def __str__(self) -> str: 13 | return self.__repr__() 14 | 15 | def __repr__(self) -> str: 16 | return f"FDDA(class: {self.__class__.__name__}, module: Pytorch)" 17 | 18 | def early_stop(self, validation_loss): 19 | if validation_loss < self.min_validation_loss: 20 | self.min_validation_loss = validation_loss 21 | self.counter = 0 22 | elif validation_loss > (self.min_validation_loss + self.min_delta): 23 | self.counter += 1 24 | if self.counter >= self.patience: 25 | return True 26 | return False 27 | -------------------------------------------------------------------------------- /training/PyTorch/dataset.py: -------------------------------------------------------------------------------- 1 | from torch import is_tensor 2 | from torch.utils.data import Dataset 3 | 4 | 5 | class FDDADataset(Dataset): 6 | 7 | def __init__(self, data: dict): 8 | """@!Brief Initialize dataset 9 | Makes one dataset per joint. 10 | """ 11 | super().__init__() 12 | 13 | self.data = {} 14 | self.joints = data['joints'] 15 | self.delta = data['delta'] 16 | 17 | def __len__(self) -> int: 18 | return len(self.joints) 19 | 20 | def __str__(self) -> str: 21 | return self.__repr__() 22 | 23 | def __repr__(self) -> str: 24 | return f"{self.__class__.__name__}(input shape: {self.joints.shape}, " \ 25 | f"output shape: {self.delta.shape})" 26 | 27 | def __getitem__(self, idx): 28 | if is_tensor(idx): 29 | idx = idx.tolist() 30 | 31 | joint = self.joints[idx] 32 | delta = self.delta[idx] 33 | 34 | return joint, delta 35 | -------------------------------------------------------------------------------- /training/PyTorch/loader.py: -------------------------------------------------------------------------------- 1 | # coding=ascii 2 | 3 | import json 4 | import numpy as np 5 | import os 6 | import traceback 7 | 8 | from torch import cuda, load as torch_load 9 | 10 | from fdda.core import constant 11 | from fdda.core.logger import log 12 | from fdda.training.PyTorch.architecture import MultiLayerPerceptron, TorchModel 13 | 14 | 15 | class Loader: 16 | 17 | def __init__(self): 18 | 19 | self._models = [] 20 | self._means = [] 21 | self._stds = [] 22 | 23 | self._file_path = None 24 | self._device = constant.kCPU 25 | self._normalized = False 26 | self._global_mode = False 27 | 28 | def __str__(self) -> str: 29 | return self.__repr__() 30 | 31 | def __repr__(self) -> str: 32 | return f"FDDA(class: {self.__class__.__name__}, filePath: {self._file_path})" 33 | 34 | def clear(self): 35 | 36 | self._models = [] 37 | self._means = [] 38 | self._stds = [] 39 | 40 | self._file_path = None 41 | self._device = constant.kCPU 42 | self._normalized = False 43 | self._global_mode = False 44 | 45 | @property 46 | def models(self) -> list: 47 | return self._models 48 | 49 | @property 50 | def model_count(self) -> int: 51 | return len(self._models) 52 | 53 | @property 54 | def means(self) -> list: 55 | return self._means 56 | 57 | @property 58 | def stds(self) -> list: 59 | return self._stds 60 | 61 | @property 62 | def device(self) -> str: 63 | return self._device 64 | 65 | @property 66 | def normalized(self) -> bool: 67 | return self._normalized 68 | 69 | @property 70 | def file(self) -> str: 71 | return self._file_path 72 | 73 | def global_mode(self) -> bool: 74 | return self._global_mode 75 | 76 | def _load(self, data: dict): 77 | self._device = self._get_device(data) 78 | self._normalized = data.get(constant.kNormalized, False) 79 | self._global_mode = data.get(constant.kMode, False) 80 | 81 | for i, model_data in enumerate(data[constant.kModels]): 82 | model = None 83 | mean = None 84 | std = None 85 | 86 | if model_data: 87 | mean = model_data.get(constant.kMean) 88 | std = model_data.get(constant.kStd) 89 | if not mean or not std: 90 | raise RuntimeError("Error on get model data !") 91 | model = self._deserialize(i, data, model_data) 92 | 93 | self._models.append(model) 94 | self._means.append(mean) 95 | self._stds.append(std) 96 | 97 | def load(self, file_path: str) -> bool: 98 | """!@Brief Load models from the json file given.""" 99 | 100 | self.clear() 101 | data = self._read(file_path) 102 | if constant.kModels not in data: 103 | log.error(f"No models found !") 104 | return 105 | 106 | try: 107 | self._load(data) 108 | except Exception as e: 109 | log.error(e) 110 | log.debug(traceback.format_exc()) 111 | self.clear() 112 | return False 113 | 114 | return True 115 | 116 | def _get_device(self, data: dict): 117 | device = constant.kCPU 118 | if cuda.is_available() and data[self.kDevice] == "gpu": 119 | device = constant.kGPU 120 | 121 | return device 122 | 123 | def _read(self, file_path: str) -> dict: 124 | 125 | data = {} 126 | if not os.path.exists(file_path): 127 | log.error(f"Could not find file {file_path} !") 128 | return data 129 | 130 | self._file_path = file_path 131 | try: 132 | log.info(f"Loading models from {file_path}") 133 | with open(self._file_path, "r") as f: 134 | data = json.load(f) 135 | except Exception as e: 136 | log.error(e) 137 | log.debug(traceback.format_exc) 138 | self.clear() 139 | 140 | return data 141 | 142 | def _deserialize(self, model_ids: int, data: dict, model: dict) -> TorchModel: 143 | if self._global_mode: 144 | vertices = np.concatenate(data[constant.kJointMap], dtype=np.float32) 145 | vertices = vertices.astype(np.int32) 146 | else: 147 | vertices = data[constant.kJointMap][model_ids] 148 | 149 | checkpoint = torch_load(model[constant.kBestModel]) 150 | model = MultiLayerPerceptron(settings=checkpoint['settings'], 151 | input_shape=checkpoint['input_shape'], 152 | output_shape=checkpoint['output_shape']) 153 | model.to(self._device) 154 | model.load_state_dict(checkpoint['model_state_dict']) 155 | 156 | return TorchModel(model=model, vertices=vertices) -------------------------------------------------------------------------------- /training/PyTorch/math.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | EPSILON = np.finfo(np.float32).eps 4 | 5 | def feature_standardization(features, mean, std): 6 | """ !@Brief Normalize features by given mean and standard deviation.""" 7 | return (features - mean) / (std + EPSILON) 8 | -------------------------------------------------------------------------------- /training/PyTorch/settings.py: -------------------------------------------------------------------------------- 1 | from textwrap import dedent 2 | 3 | from torch import cuda as cuda 4 | from torch import nn as nn 5 | 6 | from fdda.core.logger import log 7 | 8 | 9 | class Activation: 10 | 11 | kRelu = nn.ReLU() 12 | kSigmoid = nn.Sigmoid() 13 | kTanH = nn.Tanh() 14 | kSoftmax = nn.Softmax() 15 | kElu = nn.ELU() 16 | kLeakyRelu = nn.LeakyReLU() 17 | kLinear = "linear" 18 | 19 | kDefault = kTanH 20 | 21 | 22 | class Architecture: 23 | kDense = "dense" 24 | 25 | 26 | class Settings: 27 | 28 | kRate = "rate" # The learning rate. Lower rates are more accurate but slower. 29 | kEpochs = "epochs" # The number of epochs to train for. 30 | kSplit = "split" # The training/testing split. Defaults to 0.3 for 70% training 30% test. 31 | kBatchSize = "batch_size" # The batch size to train with. If unspecified, batch_size will 32 | kUnits = "units" # What units to use for intermediate layers. 33 | kInputDim = "input_dim" # Input dimensions to use for intermediate layers. 34 | kLayers = "layers" # The number of layers to use. A minimum of 2 is enforced. 35 | kArchitecture = "architecture" # Type of neuronal architecture used. 36 | kActivation = "activation" # What kind of activation to use. Defaults to tanh 37 | kShuffle = "shuffle" # Enable/Disable the random shuffling of data. 38 | kEarlyStop = "early_stop" # The number of consecutive iterations in which the loss function no 39 | kDevice = "device" # GPU or CPU. 40 | 41 | kCpu = "cpu" 42 | kGpu = "gpu" 43 | 44 | __kRateDefault = 1e-3 45 | __kEpochsDefault = 800 46 | __kSplitDefault = 0.3 47 | __kBatchSizeDefault = 32 48 | __kShuffle = True 49 | __kUnitsDefault = 512 50 | __kInputDimDefault = 100 51 | __kLayersDefault = 4 52 | __kEarlyStop = 20 53 | __kArchitectureDefault = Architecture.kDense 54 | __kActivationDefault = Activation.kElu 55 | __kDevice = kCpu 56 | 57 | def __init__(self, **kwargs): 58 | self.rate = kwargs.get(self.kRate, self.__kRateDefault) 59 | self.epochs = kwargs.get(self.kEpochs, self.__kEpochsDefault) 60 | self.split = kwargs.get(self.kSplit, self.__kSplitDefault) 61 | self.batch_size = kwargs.get(self.kBatchSize, self.__kBatchSizeDefault) 62 | self.units = kwargs.get(self.kUnits, self.__kUnitsDefault) 63 | self.input_dim = kwargs.get(self.kInputDim, self.__kInputDimDefault) 64 | self.layers = kwargs.get(self.kLayers, self.__kLayersDefault) 65 | self.architecture = kwargs.get(self.kArchitecture, self.__kArchitectureDefault) 66 | self.activation = kwargs.get(self.kActivation, self.__kActivationDefault) 67 | self.shuffle = kwargs.get(self.kShuffle, self.__kShuffle) 68 | self.early_stop = kwargs.get(self.kEarlyStop, self.__kEarlyStop) 69 | self.device = kwargs.get(self.kDevice, self.__kDevice) 70 | 71 | if not(cuda.is_available()): 72 | self.device = self.kCpu 73 | 74 | def __str__(self): 75 | msg = dedent( 76 | f""" 77 | The model is train with: 78 | Learning rate: {self.rate} 79 | Batch size: {self.batch_size} 80 | Number of epochs: {self.epochs} 81 | """ 82 | ) 83 | log.info(msg) 84 | 85 | @classmethod 86 | def default(cls): 87 | return cls() 88 | -------------------------------------------------------------------------------- /training/PyTorch/training.py: -------------------------------------------------------------------------------- 1 | # coding=ascii 2 | import os 3 | import csv 4 | from time import time 5 | from datetime import datetime 6 | import json 7 | import random 8 | 9 | import numpy as np 10 | import pandas as pd 11 | import torch 12 | from torch import nn as nn 13 | from torchinfo import summary 14 | from torch.utils.tensorboard import SummaryWriter 15 | 16 | from fdda.core.logger import log 17 | from fdda.core import constant as cst 18 | from fdda.training.PyTorch.architecture import MultiLayerPerceptron, Activation, Settings, fit 19 | from fdda.training.PyTorch.dataset import FDDADataset 20 | from fdda.training.PyTorch.math import feature_standardization 21 | 22 | 23 | _plot = False 24 | try: 25 | import matplotlib.pyplot as plt 26 | except Exception as e: 27 | log.debug(e) 28 | _plot = False 29 | 30 | 31 | def read_inputs(directory: str) -> dict: 32 | """Read the input_data from the given directory""" 33 | input_file = os.path.normpath(os.path.join(directory, f"{cst.kInputName}.{cst.kExtension}")) 34 | with open(input_file) as f: 35 | return json.load(f) 36 | 37 | 38 | def make_plot(history, output, legend=None, show=True): 39 | """!@Brief Build a model from the trained keras model 40 | @param history: The output of the trained model 41 | @param output: Where to save the plot 42 | @param legend: Name of each traced curve 43 | @param show: Whether to show the plot 44 | """ 45 | plt.plot(history['loss']) 46 | plt.plot(history['val_loss']) 47 | plt.ylabel('mean_squared_error') 48 | plt.xlabel('epoch') 49 | if legend is not None: 50 | plt.legend(legend, loc='upper left') 51 | plt.savefig(output) 52 | if show: 53 | plt.show() 54 | return plt 55 | 56 | 57 | def merge_data(input_data: dict) -> tuple: 58 | csv_files = input_data.get('csv_files', list()) 59 | joint_columns = input_data.get('input_fields', cst.kInputHeading) 60 | joints_ids = input_data.get("joint_indexes", list()) 61 | joint_map = input_data.get("joint_map", list()) 62 | input_len = len(joint_columns) 63 | 64 | in_data = [] 65 | delta_data = [] 66 | input_header = [] 67 | output_header = [] 68 | 69 | for i, csv_file in enumerate(csv_files): 70 | df = pd.read_csv(csv_file) 71 | n_coord = len(joint_map[i]) * 3 72 | 73 | if i == 0: 74 | in_data = df.iloc[:, :input_len].values 75 | delta_data = df.iloc[:, input_len:n_coord+input_len].values 76 | else: 77 | in_data = np.concatenate((in_data, df.iloc[:, :input_len].values), axis=1) 78 | delta_data = np.concatenate((delta_data, df.iloc[:, input_len:n_coord+input_len].values), axis=1) 79 | 80 | input_header.extend([f"q{joints_ids[i]}x", f"q{joints_ids[i]}y", f"q{joints_ids[i]}z", f"q{joints_ids[i]}w"]) 81 | output_header.extend(list(df.columns[input_len:])) 82 | 83 | log.info(f"Merge data from {csv_file}") 84 | 85 | data = np.concatenate((in_data, delta_data), axis=1) 86 | heading = input_header + output_header 87 | input_len = len(input_header) 88 | joint_columns = input_header 89 | 90 | # clear memory 91 | del in_data 92 | del delta_data 93 | 94 | out_dir = os.path.split(csv_file)[0] 95 | file_path = os.path.join(out_dir, "GlobalJoints.csv") 96 | 97 | with open(file_path, 'w') as f: 98 | writer = csv.writer(f) 99 | writer.writerow(heading) 100 | writer.writerows(data.tolist()) 101 | 102 | csv_files = [file_path] 103 | 104 | return csv_files, input_len, joint_columns 105 | 106 | 107 | def build_models(input_directory: str, 108 | settings: Settings = Settings.default(), mode: bool = False, normalized: bool = False, 109 | debug: bool = False): 110 | """ 111 | !@Brief Build all the models from the 3d mesh and network parameters. 112 | 113 | @param input_directory: str, the path where the deep learning model will be saved 114 | @param settings: Settings, the network parameters. 115 | @param normalized: bool, if True, apply normalization on the data. 116 | @param debug: bool, if True the results will be reproducible. 117 | @param mode: bool, if True the bone rotations and associated vertices are saved in 118 | the same file. This mode is used to train a global model which learns 119 | delta for all vertices in a mesh. 120 | """ 121 | 122 | # GPU configuration. 123 | torch.backends.cudnn.benchmark = True 124 | torch.backends.cudnn.deterministic = False 125 | torch.backends.cudnn.enabled = True 126 | 127 | # To obtain reproducible results 128 | if debug: 129 | torch.backends.cudnn.benchmark = True 130 | random.seed(1) 131 | np.random.seed(1) 132 | torch.manual_seed(1) 133 | torch.cuda.manual_seed(1) 134 | 135 | # Take data stored from the input .json file 136 | input_data = read_inputs(input_directory) 137 | csv_files = input_data.get('csv_files', list()) 138 | joint_columns = input_data.get('input_fields', cst.kInputHeading) 139 | input_length = len(joint_columns) 140 | n_coordinates = input_data.get('n_vertices', int) * 3 141 | 142 | start = time() 143 | 144 | if mode: 145 | csv_files, input_length, joint_columns = merge_data(input_data) 146 | input_data['input_length'] = input_length 147 | input_data['csv_files'] = csv_files 148 | 149 | for i, csv_file in enumerate(csv_files): 150 | 151 | # Prepare the filesystem to write 152 | file_name, _ext = os.path.splitext(os.path.basename(csv_file)) 153 | export_directory = os.path.join(input_directory, file_name) 154 | if not os.path.exists(export_directory): 155 | os.mkdir(export_directory) 156 | 157 | # Read the csv of vert deltas to a pandas dataframe. 158 | df = pd.read_csv(csv_file) 159 | df = df.drop_duplicates(joint_columns) 160 | if not df.shape[0] or df.shape[1] <= input_length: 161 | input_data.setdefault('models', list()).append(None) 162 | continue 163 | 164 | # Check if the training set can be splitted. 165 | if (df.shape[0] * settings.split < 1.) and settings.split > 0.: 166 | input_data.setdefault('models', list()).append(None) 167 | continue 168 | 169 | # Split data into input and output data. 170 | data = {} 171 | data['joints'] = df.iloc[:, :input_length].values.astype(np.float32) 172 | data['delta'] = df.iloc[:, input_length:(n_coordinates+input_length)].values.astype(np.float32) 173 | 174 | # Compute statistics 175 | mean = np.mean(data['joints'], axis=0) 176 | std = np.std(data['joints'], axis=0) 177 | 178 | if normalized: 179 | data['joints'] = feature_standardization(data['joints'], mean, std) 180 | 181 | # Prepare data 182 | log.info(f"Training for {file_name}") 183 | 184 | # Split data into trainset and validset 185 | # L'avantage de la validation est de valider le modele sur un ensemble non appris. 186 | # Ce qui permet de visualiser la capacite du modele a generaliser. 187 | if settings.split > 0.: 188 | shuffle_ids = list(range(0, data['joints'].shape[0])) 189 | random.shuffle(shuffle_ids) 190 | validation_length = int(data['joints'].shape[0] * settings.split) 191 | validation_ids = shuffle_ids[:validation_length] 192 | train_ids = shuffle_ids[validation_length:] 193 | valid_set = FDDADataset({'joints': data['joints'][validation_ids, :], 194 | 'delta': data['delta'][validation_ids, :]} 195 | ) 196 | valid_loader = torch.utils.data.DataLoader( 197 | valid_set, 198 | batch_size=settings.batch_size, 199 | shuffle=False, 200 | num_workers=0, 201 | prefetch_factor=2, 202 | pin_memory=True) 203 | else: 204 | valid_loader = None 205 | train_ids = range(0, data['joints'].shape[0]) 206 | 207 | train_set = FDDADataset({'joints': data['joints'][train_ids, :], 208 | 'delta': data['delta'][train_ids, :]} 209 | ) 210 | train_loader = torch.utils.data.DataLoader( 211 | train_set, 212 | batch_size=settings.batch_size, 213 | shuffle=settings.shuffle, 214 | num_workers=0, 215 | prefetch_factor=2, 216 | pin_memory=True) 217 | 218 | # Tensorboard writer 219 | timestamp = datetime.now().strftime('%Y%m%d_%H%M%S') 220 | writer = SummaryWriter(log_dir=os.path.join(export_directory, 'tensorboard_{}'.format(timestamp))) 221 | 222 | # Instantiate network 223 | net = MultiLayerPerceptron(settings, 224 | input_shape=train_set.joints.shape, 225 | output_shape=train_set.delta.shape) 226 | 227 | optimizer = torch.optim.Adam(net.parameters(), lr=settings.rate) 228 | criterion = nn.MSELoss(reduction='mean') 229 | 230 | # If running on GPU 231 | device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu') 232 | if torch.cuda.is_available(): 233 | net = net.cuda() 234 | 235 | # Display network configuration like Keras's summary 236 | input_size = (settings.batch_size, train_set.joints.shape[1]) 237 | log.info(summary(net, input_size=input_size)) 238 | 239 | # Train network 240 | history, opti_model_state_file = fit(model=net, 241 | train_loader=train_loader, 242 | validation_loader=valid_loader, 243 | loss_func=criterion, 244 | optimizer=optimizer, 245 | writer=writer, 246 | save_dir=export_directory, 247 | settings=settings, 248 | input_shape=train_set.joints.shape, 249 | output_shape=train_set.delta.shape, 250 | epochs=settings.epochs, 251 | batch_size=settings.batch_size, 252 | device=device) 253 | 254 | writer.close() 255 | 256 | # Show the plots 257 | plot_image = None 258 | if _plot: 259 | plot_image = os.path.join(export_directory, f"{file_name}.png") 260 | curr_jnt = 'jnt_' + str(i + 1) 261 | legend = ['train_' + curr_jnt, 'valid_' + curr_jnt] 262 | make_plot(history, plot_image, legend=legend, show=debug) 263 | 264 | # Save the final model as pytorch model 265 | model_state_file = os.path.join(export_directory, 'final_ckpt.pt') 266 | torch.save({'model_state_dict': net.state_dict(), 267 | 'input_shape': train_set.joints.shape, 268 | 'output_shape': train_set.delta.shape, 269 | 'settings': settings}, model_state_file) 270 | 271 | # Store the data in a dict 272 | model_data = {'root': export_directory, 273 | 'model': model_state_file, 274 | 'best_model': opti_model_state_file, 275 | 'plot': plot_image, 276 | 'mean': mean.tolist(), 277 | 'std': std.tolist()} 278 | 279 | # Then write this dict to the master dict 280 | input_data.setdefault('models', []).append(model_data) 281 | 282 | elapsed_training_time = time() - start 283 | log.info("Finished... Done in {}h {}min, {}s".format(int(elapsed_training_time / 3600), 284 | int((elapsed_training_time % 3600) / 60), 285 | int((elapsed_training_time % 3600) % 60))) 286 | 287 | # Add the device used during the training 288 | input_data.setdefault('device', settings.device) 289 | 290 | input_data.setdefault('normalized', normalized) 291 | input_data.setdefault('global_mode', mode) 292 | 293 | 294 | # Finally write this out to disk. 295 | output_data = os.path.join(input_directory, f"{cst.kOutputName}.{cst.kExtension}") 296 | with open(output_data, 'w') as f: 297 | json.dump(input_data, f, indent=cst.kJsonIndent) 298 | 299 | return output_data 300 | 301 | 302 | """ 303 | if __name__ == '__main__': 304 | settings = Settings.default() 305 | settings.rate = 1e-3 306 | settings.layers = 4 307 | settings.epochs = 800 308 | settings.activation = Activation.kElu 309 | settings.split = 0.1 310 | settings.units = 256 311 | settings.batch_size = 128 312 | settings.device = 'gpu' 313 | 314 | build_models(input_directory=f"D:\Documents\Machine_Learning_Projects\MLDeformer\Scenes\Dana_fdda_low_without_muslce", 315 | settings=settings, mode=True, normalized=True, debug=True) 316 | """ -------------------------------------------------------------------------------- /training/TensorFlow/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RDelet/FFDA/1525a5fd27aed938a439daa4812d1e20783b1eff/training/TensorFlow/__init__.py -------------------------------------------------------------------------------- /training/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RDelet/FFDA/1525a5fd27aed938a439daa4812d1e20783b1eff/training/__init__.py --------------------------------------------------------------------------------