├── .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
--------------------------------------------------------------------------------