diff --git a/PYProjects/.projects/SkinPlusPlus.sublime-project b/PYProjects/.projects/SkinPlusPlus.sublime-project deleted file mode 100644 index 3964320..0000000 --- a/PYProjects/.projects/SkinPlusPlus.sublime-project +++ /dev/null @@ -1,14 +0,0 @@ -{ - "folders": - [ - { - "path": "C:\\p4ws\\sharkmob\\Tools\\tech_art\\base\\_standalone\\c++\\SkinPlusPlus", - }, - { - "path": "C:\\p4ws\\sharkmob\\Tools\\tech_art\\base\\_standalone\\python\\_third_party" - }, - ], - "debugger_configurations": - [ - ], -} diff --git a/PYProjects/SkinPlusPlus.sublime-project b/PYProjects/SkinPlusPlus.sublime-project deleted file mode 100644 index 938b952..0000000 --- a/PYProjects/SkinPlusPlus.sublime-project +++ /dev/null @@ -1,11 +0,0 @@ -{ - "folders": - [ - { - "path": ".", - } - ], - "debugger_configurations": - [ - ], -} diff --git a/PYProjects/pyrightconfig.json b/PYProjects/pyrightconfig.json deleted file mode 100644 index 35152ff..0000000 --- a/PYProjects/pyrightconfig.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "include": [ - "./skin_plus_plus", - "./skin_plus_plus_test" - ], - "extraPaths": [ - "C:/Program Files/Autodesk/Maya2022/devkit/devkitBase/devkit/other/Python27/pymel/extras/completion/pyi", - "C:/Program Files/Autodesk/Maya2023/Python39/Lib/site-packages" - ], - "venvPath": "./venvs", - "venv": "37", - "stubPath": "./.stubs", - "reportMissingImports": true, - "reportMissingTypeStubs": false, - "pythonVersion": "3.7", - "pythonPlatform": "Windows" - // "executionEnvironments": [ - // { - // "root": ".", - // "pythonVersion": "3.8", - // "pythonPlatform": "Windows", - // "extraPaths": [ - // "C:/Program Files/Sublime Text/Lib/python38", - // "./sublack/vendor/lib", - // ] - // } - // ] -} \ No newline at end of file diff --git a/PYProjects/skin_plus_plus/.vscode/launch.json b/PYProjects/skin_plus_plus/.vscode/launch.json deleted file mode 100644 index ad3d7cb..0000000 --- a/PYProjects/skin_plus_plus/.vscode/launch.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "name": "3DsMax", - "type": "python", - "request": "attach", - "connect": { - "host": "localhost", - "port": 6000 - }, - "justMyCode": false - } - ] -} \ No newline at end of file diff --git a/PYProjects/skin_plus_plus/__init__.py b/PYProjects/skin_plus_plus/__init__.py deleted file mode 100644 index f6997c0..0000000 --- a/PYProjects/skin_plus_plus/__init__.py +++ /dev/null @@ -1,174 +0,0 @@ -from __future__ import annotations - -import importlib -import os -import pathlib -import sys - -current_dcc = None -current_host_interface = None - -extract_skin_data = None -apply_skin_data = None -skin_plus_plus_py = None -SkinData = None -# get_vertex_positions = None - -try: - is_reloading # type: ignore - is_reloading = True -except NameError: - is_reloading = False - -__py_version__ = f"{sys.version_info.major}{sys.version_info.minor}" - - -def _activate_skin_plus_plus_py_(python_version: str, debug: bool = False): - global skin_plus_plus_py - global SkinData - - debug = bool(os.environ.get("SKIN_PLUS_PLUS_DEBUG", False)) or debug - if debug: - python_version = f"debug_{python_version}" - - current_directory = pathlib.Path(__file__).parent - sub_module_path = current_directory / f"py/{python_version}" - - if not sub_module_path.exists(): - raise FileNotFoundError(f"Unsupported Python version: {python_version}") - - import_path = f"skin_plus_plus.py.{python_version}.skin_plus_plus_py" - if "skin_plus_plus_py" in sys.modules: - del sys.modules["skin_plus_plus_py"] - - skin_plus_plus_py = importlib.import_module(import_path) - if is_reloading: - importlib.reload(skin_plus_plus_py) - - SkinData = skin_plus_plus_py.SkinData - - return skin_plus_plus_py - - -def _activate_host_(): - global current_host_interface - - global apply_skin_data - global extract_skin_data - - executable = sys.executable.lower() - if "3ds max" in executable: - from .dccs.max import IHost - - current_host_interface = IHost() - - elif "maya" in executable: - from .dccs.maya import Host - - current_host_interface = IHost() - - else: - raise RuntimeError(f"Unsupported executable: {executable}") - - extract_skin_data = current_host_interface.extract_skin_data - apply_skin_data = current_host_interface.apply_skin_data - - -def set_debug(value: bool) -> None: - """ - Toggle debug mode on or off. - - --- - - Debug mode is off by default. - - Arguments: - ---------- - - `value`: Boolean to control the state of debug mode. - - Returns: - -------- - - `None` - """ - _activate_skin_plus_plus_py_(__py_version__, debug=value) - - -_activate_skin_plus_plus_py_(__py_version__) -_activate_host_() - - -_typing = False -if _typing: - from typing import Any - - from . import dccs - from . import py - - from . import core - from . import io - from . import mesh - - from .core import export_skin_data - from .core import import_skin_data - from .core import FileType - - from .io import save - from .io import load - from .io import max_to_maya - from .io import maya_to_max -del _typing - - -# this avoids having to import every sub-package to find where -# the object should be imported from: -_object_import_map = { - "export_skin_data": "core", - "import_skin_data": "core", - "FileType": "core", - "save": "io", - "load": "io", - "max_to_maya": "io", - "maya_to_max": "io", -} - - -def __getattr__(name: str) -> Any: - if name in _object_import_map: - package_name = _object_import_map[name] - module = importlib.import_module(f"{__package__}.{package_name}") - return getattr(module, name) - - return importlib.import_module(f"{__package__}.{name}") - - -__all__ = ( - "SkinData", - - "dccs", - "py", - - "core", - "io", - "mesh", - - "current_dcc", - "current_host_interface", - - "extract_skin_data", - "apply_skin_data", - - "export_skin_data", - "import_skin_data", - "FileType", - "save", - "load", - - "max_to_maya", - "maya_to_max", - - "set_debug", -) - - -def __dir__(): - return __all__ diff --git a/PYProjects/skin_plus_plus/__init__.pyi b/PYProjects/skin_plus_plus/__init__.pyi deleted file mode 100644 index adeb115..0000000 --- a/PYProjects/skin_plus_plus/__init__.pyi +++ /dev/null @@ -1,43 +0,0 @@ -from __future__ import annotations - -from . import _types -from .dccs import core as _dccs_core -from . import skin_plus_plus_py -from .core import FileType as _FileType -from .core import export_skin_data as _export_skin_data -from .core import import_skin_data as _import_skin_data -from .io import save as _save -from .io import load as _load -from .io import max_to_maya as _max_to_maya -from .io import maya_to_max as _maya_to_max - - -FileType = _FileType -export_skin_data = _export_skin_data -import_skin_data = _import_skin_data -save = _save -load = _load -max_to_maya = _max_to_maya -maya_to_max = _maya_to_max - -current_dcc: str = ... -""" -The name of the current DCC. -""" -current_host_interface: _dccs_core.IHost = ... -""" -The interface to the current Host -""" - -SkinData = skin_plus_plus_py.SkinData - -def extract_skin_data(node: _types.T_Node) -> SkinData: - """ - Extract skin data from the given DCC node. - """ - ... -def apply_skin_data(node: _types.T_Node, skin_data: SkinData) -> bool: - """ - Apply the given skin data to the given DCC node. - """ - ... \ No newline at end of file diff --git a/PYProjects/skin_plus_plus/_types.py b/PYProjects/skin_plus_plus/_types.py deleted file mode 100644 index 4c95382..0000000 --- a/PYProjects/skin_plus_plus/_types.py +++ /dev/null @@ -1,12 +0,0 @@ -from pymel.core import nodetypes as pm_ntypes -from pymxs import runtime as mxrt -from typing import Callable -from typing import TypeVar -from typing import Union - -from . import SkinData - -T_Node = TypeVar("T_Node", mxrt.Node, pm_ntypes.DagNode) -T_Handle = Union[int, str] -T_CExSD = Callable[[T_Handle], SkinData] -T_CApSD = Callable[[T_Handle, SkinData], None] \ No newline at end of file diff --git a/PYProjects/skin_plus_plus/core.py b/PYProjects/skin_plus_plus/core.py deleted file mode 100644 index bd156a8..0000000 --- a/PYProjects/skin_plus_plus/core.py +++ /dev/null @@ -1,123 +0,0 @@ -from __future__ import annotations - -from . import get_skin_data - -# from . import get_vertex_positions -from . import set_skin_weights - -import enum -import json -import numpy -import pathlib -import pickle -import skin_plus_plus - -# import scipy.sparse - -_typing = False -if _typing: - pass -del _typing - - -class ImportType(enum.Enum): - order = 0 - nearest = 1 - nearest_n = 2 - barycentric = 3 - - -class FileType(enum.Enum): - """ - Enum to specify the type of file to save skin data as. - - Arguments: - ---------- - - - `json` - - `pickle` - """ - json = 0 - pickle = 1 - - -def export_skin_data(mesh_name: str, path: pathlib.Path, file_type: FileType = FileType.pickle): - """ - Get skin data from the given mesh and save it to disk. - """ - - skin_data = get_skin_data(mesh_name) - if not path.parent.exists(): - path.parent.mkdir(parents=True) - - if file_type == FileType.pickle: - if path.suffix != ".skpp": - path = path.with_suffix(".skpp") - - with open(path, "wb") as file: - pickle.dump(skin_data, file) - - elif file_type == FileType.json: - if path.suffix != ".skpp-json": - path = path.with_suffix(".skpp-json") - - with open(path, "w") as file: - weights = skin_data.weights.copy() - weights[numpy.isnan(weights)] = 0 - _skin_data = { - "bone_names": skin_data.bone_names, - "bone_ids": skin_data.bone_ids.tolist(), - "weights": weights.tolist(), - "positions": skin_data.positions.tolist(), - } - json.dump(_skin_data, file, indent=4) - - print(f"Exported '{mesh_name}' skin data to: {path}") - - -def import_skin_data( - mesh_name: str, - path: pathlib.Path, - file_type: FileType = FileType.pickle, - import_type: ImportType = ImportType.order, -): - """ - Load skin data from disk and apply it to the given mesh. - """ - - if file_type == FileType.pickle: - if path.suffix != ".skpp": - path = path.with_suffix(".skpp") - - if not path.exists(): - raise IOError( - f"File path does not exist: {path} - check mesh is named correctly: {mesh_name}" - ) - - with open(path, "rb") as file: - skin_data = pickle.load(file) - - elif file_type == FileType.json: - if path.suffix != ".skpp-json": - path = path.with_suffix(".skpp-json") - - if not path.exists(): - raise IOError( - f"File path does not exist: {path} - check mesh is named correctly: {mesh_name}" - ) - - with open(path, "r") as file: - data = json.load(file) - skin_data = skin_plus_plus.skin_plus_plus_py.SkinData( - tuple(data["bone_names"]), - tuple(data["bone_ids"]), - tuple(data["weights"]), - tuple(data["positions"]) - ) - - return set_skin_weights(mesh_name, skin_data) - - # if import_type == ImportType.nearest: - # vertex_positions = get_vertex_positions(mesh_name) - # kd_tree = scipy.sparse.ckdtree(skin_data.positions) - # matching_indices = kd_tree.query(vertex_positions) diff --git a/PYProjects/skin_plus_plus/dccs/__init__.py b/PYProjects/skin_plus_plus/dccs/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/PYProjects/skin_plus_plus/dccs/core.py b/PYProjects/skin_plus_plus/dccs/core.py deleted file mode 100644 index e600441..0000000 --- a/PYProjects/skin_plus_plus/dccs/core.py +++ /dev/null @@ -1,96 +0,0 @@ -from __future__ import annotations - -import abc -import importlib -import pathlib - - -_typing = False -if _typing: - - from .. import _types - from .. import SkinData - -del _typing - - -class IHost(metaclass=abc.ABCMeta): - _extract_skin_data: _types.T_CExSD - _apply_skin_data: _types.T_CApSD - _get_vertex_positions: _types.Callable - - def __init__(self) -> None: - self._get_dcc_backend() - - @property - @abc.abstractmethod - def name(self) -> str: - """ - The name of the host - """ - - @property - @abc.abstractmethod - def api_name(self) -> str: - """ - The api name of the compiled backend for the host. - i.e. pymxs or pymaya - """ - - def _get_dcc_backend(self): - version = self._get_version_number() - current_directory = pathlib.Path(__file__).parent - sub_module_path = current_directory / self.name / str(version) - - if not sub_module_path.exists(): - raise FileNotFoundError(f"Unsupported DCC version: {version}") - - import_path = f"{__name__.rstrip('core')}{self.name}.{version}.skin_plus_plus_{self.api_name}" - backend = importlib.import_module(import_path) - # if is_reloading: - # importlib.reload(backend) - - self._extract_skin_data: _types.T_CExSD = backend.extract_skin_data - self._apply_skin_data: _types.T_CApSD = backend.apply_skin_data - self._get_vertex_positions: _types.Callable = backend.get_vertex_positions - - return backend - - @abc.abstractmethod - def _get_version_number(self) -> int | str: - """ - Get the version number of the host - """ - - @abc.abstractmethod - def get_current_file_path(self) -> pathlib.Path: - """ - Get the file path of the current host scene - """ - - @abc.abstractmethod - def get_selection(self) -> tuple[_types.T_Node, ...]: - """ - Get the selection of the current host scene - """ - - @abc.abstractmethod - def get_node_name(self, node: _types.T_Node) -> str: - """ - Get the name of the given node - """ - - @abc.abstractmethod - def get_node_handle(self, node: _types.T_Node) -> _types.T_Handle: - """ - Get the unique handle of the given node - """ - - - def extract_skin_data(self, node: _types.T_Node) -> SkinData: - handle = self.get_node_handle(node) - return self._extract_skin_data(handle) - - def apply_skin_data(self, node: _types.T_Node, skin_data: SkinData): - handle = self.get_node_handle(node) - return self._apply_skin_data(handle, skin_data) \ No newline at end of file diff --git a/PYProjects/skin_plus_plus/dccs/max/2021/skin_plus_plus_pymxs.pyd b/PYProjects/skin_plus_plus/dccs/max/2021/skin_plus_plus_pymxs.pyd deleted file mode 100644 index 4ad7123..0000000 Binary files a/PYProjects/skin_plus_plus/dccs/max/2021/skin_plus_plus_pymxs.pyd and /dev/null differ diff --git a/PYProjects/skin_plus_plus/dccs/max/2022/skin_plus_plus_pymxs.pyd b/PYProjects/skin_plus_plus/dccs/max/2022/skin_plus_plus_pymxs.pyd deleted file mode 100644 index 7f8158f..0000000 Binary files a/PYProjects/skin_plus_plus/dccs/max/2022/skin_plus_plus_pymxs.pyd and /dev/null differ diff --git a/PYProjects/skin_plus_plus/dccs/max/2023/skin_plus_plus_pymxs.pyd b/PYProjects/skin_plus_plus/dccs/max/2023/skin_plus_plus_pymxs.pyd deleted file mode 100644 index fa12965..0000000 Binary files a/PYProjects/skin_plus_plus/dccs/max/2023/skin_plus_plus_pymxs.pyd and /dev/null differ diff --git a/PYProjects/skin_plus_plus/dccs/max/2024/skin_plus_plus_pymxs.pyd b/PYProjects/skin_plus_plus/dccs/max/2024/skin_plus_plus_pymxs.pyd deleted file mode 100644 index 4333b69..0000000 Binary files a/PYProjects/skin_plus_plus/dccs/max/2024/skin_plus_plus_pymxs.pyd and /dev/null differ diff --git a/PYProjects/skin_plus_plus/dccs/max/__init__.py b/PYProjects/skin_plus_plus/dccs/max/__init__.py deleted file mode 100644 index 4394503..0000000 --- a/PYProjects/skin_plus_plus/dccs/max/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -from .core import IHost - - -__all__ = ("IHost",) \ No newline at end of file diff --git a/PYProjects/skin_plus_plus/dccs/max/core.py b/PYProjects/skin_plus_plus/dccs/max/core.py deleted file mode 100644 index 8502c88..0000000 --- a/PYProjects/skin_plus_plus/dccs/max/core.py +++ /dev/null @@ -1,39 +0,0 @@ -from __future__ import annotations - -import pathlib - -from pymxs import runtime as mxrt - -from .. import core - - -class IHost(core.IHost): - - @property - def name(self) -> str: - return "max" - - @property - def api_name(self) -> str: - return "pymxs" - - def _get_version_number(self): - version_info = mxrt.MaxVersion() - version_number = version_info[7] - return version_number - - def get_current_file_path(self) -> pathlib.Path: - max_file_path = mxrt.MaxFilePath - if not max_file_path: - raise RuntimeError("File is not saved!") - - return pathlib.Path(max_file_path, mxrt.MaxFileName) - - def get_selection(self) -> tuple[mxrt.Node, ...]: - return tuple(mxrt.Selection) - - def get_node_name(self, node: mxrt.Node) -> str: - return node.Name - - def get_node_handle(self, node: mxrt.Node) -> int: - return node.Handle diff --git a/PYProjects/skin_plus_plus/dccs/maya/skin_plus_plus_pymaya_2021/skin_plus_plus_pymaya.pyd b/PYProjects/skin_plus_plus/dccs/maya/skin_plus_plus_pymaya_2021/skin_plus_plus_pymaya.pyd deleted file mode 100644 index bed4c46..0000000 Binary files a/PYProjects/skin_plus_plus/dccs/maya/skin_plus_plus_pymaya_2021/skin_plus_plus_pymaya.pyd and /dev/null differ diff --git a/PYProjects/skin_plus_plus/dccs/maya/skin_plus_plus_pymaya_2022/skin_plus_plus_pymaya.pyd b/PYProjects/skin_plus_plus/dccs/maya/skin_plus_plus_pymaya_2022/skin_plus_plus_pymaya.pyd deleted file mode 100644 index b492e01..0000000 Binary files a/PYProjects/skin_plus_plus/dccs/maya/skin_plus_plus_pymaya_2022/skin_plus_plus_pymaya.pyd and /dev/null differ diff --git a/PYProjects/skin_plus_plus/dccs/maya/skin_plus_plus_pymaya_2023/skin_plus_plus_pymaya.pyd b/PYProjects/skin_plus_plus/dccs/maya/skin_plus_plus_pymaya_2023/skin_plus_plus_pymaya.pyd deleted file mode 100644 index 6e7352f..0000000 Binary files a/PYProjects/skin_plus_plus/dccs/maya/skin_plus_plus_pymaya_2023/skin_plus_plus_pymaya.pyd and /dev/null differ diff --git a/PYProjects/skin_plus_plus/dccs/maya/skin_plus_plus_pymaya_2024/skin_plus_plus_pymaya.pyd b/PYProjects/skin_plus_plus/dccs/maya/skin_plus_plus_pymaya_2024/skin_plus_plus_pymaya.pyd deleted file mode 100644 index bd4553e..0000000 Binary files a/PYProjects/skin_plus_plus/dccs/maya/skin_plus_plus_pymaya_2024/skin_plus_plus_pymaya.pyd and /dev/null differ diff --git a/PYProjects/skin_plus_plus/io.py b/PYProjects/skin_plus_plus/io.py deleted file mode 100644 index 5c00628..0000000 --- a/PYProjects/skin_plus_plus/io.py +++ /dev/null @@ -1,103 +0,0 @@ -from __future__ import annotations - -import pathlib - -from . import core -from . import current_dcc -from . import FileType - - -def _get_current_file_path(): - if current_dcc == "max": - from pymxs import runtime as mxrt - - max_file_path = mxrt.MaxFilePath - if not max_file_path: - raise RuntimeError("File is not saved!") - - return pathlib.Path(max_file_path, mxrt.MaxFileName) - - if current_dcc == "maya": - import pymel.core as pm_core - - scene_name = pm_core.sceneName() - if not scene_name: - raise RuntimeError("File is not saved!") - - return pathlib.Path(scene_name) - - raise RuntimeError("Unsupported DCC") - - -def _get_selection(): - if current_dcc == "max": - from pymxs import runtime as mxrt - - return tuple(mxrt.Selection) - - if current_dcc == "maya": - import pymel.core as pm_core - - return pm_core.ls(selection=True) - - raise RuntimeError("Unsupported DCC") - - -def _get_node_name(node): - if current_dcc == "max": - return node.Name - - elif current_dcc == "maya": - return node.name() - - else: - raise RuntimeError("Unsupported DCC") - - -def _get_clean_file_name(name: str, suffix: str | None = None) -> str: - name = f"{name}{suffix}" if suffix and not name.endswith(suffix) else name - return name.split(":")[-1] - - -def save(file_name_suffix: str = "_GEO", file_type: FileType = FileType.pickle): - scene_path = _get_current_file_path() - data_path = scene_path.parent / "_Data" - selection = _get_selection() - if not selection: - raise RuntimeError("No nodes are selected!") - - for node in selection: - node_name = _get_node_name(node) - path_name = _get_clean_file_name(node_name, suffix=file_name_suffix) - skin_data_path = data_path / f"{path_name}.skpp" - core.export_skin_data(node_name, skin_data_path, file_type=file_type) - - -def load(file_name_suffix: str = "_GEO", file_type: FileType = FileType.pickle): - scene_path = _get_current_file_path() - data_path = scene_path.parent / "_Data" - selection = _get_selection() - if not selection: - raise RuntimeError("No nodes are selected!") - - for node in selection: - node_name = _get_node_name(node) - path_name = _get_clean_file_name(node_name, suffix=file_name_suffix) - skin_data_path = data_path / f"{path_name}.skpp" - core.import_skin_data(node_name, skin_data_path, file_type=file_type) - - -def max_to_maya(file_type: FileType = FileType.pickle): - if current_dcc == "max": - return save(file_type=file_type) - - if current_dcc == "maya": - return load(file_type=file_type) - - -def maya_to_max(file_type: FileType = FileType.pickle): - if current_dcc == "maya": - return save(file_type=file_type) - - if current_dcc == "max": - return load(file_type=file_type) diff --git a/PYProjects/skin_plus_plus/mesh.py b/PYProjects/skin_plus_plus/mesh.py deleted file mode 100644 index e69de29..0000000 diff --git a/PYProjects/skin_plus_plus/py/310/skin_plus_plus_py.pyd b/PYProjects/skin_plus_plus/py/310/skin_plus_plus_py.pyd deleted file mode 100644 index 50a32f5..0000000 Binary files a/PYProjects/skin_plus_plus/py/310/skin_plus_plus_py.pyd and /dev/null differ diff --git a/PYProjects/skin_plus_plus/py/37/__init__.py b/PYProjects/skin_plus_plus/py/37/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/PYProjects/skin_plus_plus/py/37/skin_plus_plus_py.pyd b/PYProjects/skin_plus_plus/py/37/skin_plus_plus_py.pyd deleted file mode 100644 index 6e2d20f..0000000 Binary files a/PYProjects/skin_plus_plus/py/37/skin_plus_plus_py.pyd and /dev/null differ diff --git a/PYProjects/skin_plus_plus/py/39/__init__.py b/PYProjects/skin_plus_plus/py/39/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/PYProjects/skin_plus_plus/py/39/skin_plus_plus_py.pyd b/PYProjects/skin_plus_plus/py/39/skin_plus_plus_py.pyd deleted file mode 100644 index 2374d32..0000000 Binary files a/PYProjects/skin_plus_plus/py/39/skin_plus_plus_py.pyd and /dev/null differ diff --git a/PYProjects/skin_plus_plus/py/__init__.py b/PYProjects/skin_plus_plus/py/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/PYProjects/skin_plus_plus/skin_plus_plus_py.pyi b/PYProjects/skin_plus_plus/skin_plus_plus_py.pyi deleted file mode 100644 index 6d848dd..0000000 --- a/PYProjects/skin_plus_plus/skin_plus_plus_py.pyi +++ /dev/null @@ -1,52 +0,0 @@ -import numpy as np -import numpy.typing as np_typing -import typing - -class SkinData: - """ - Class containing data for a given skin object. - - --- - - This class is a wrapped c++ struct exposed to Python with Pybind11. - - # Note: It cannot be extended! - - --- - - Attributes: - ----------- - - `bone_names`: The names of the bones in the skin object. - - `bone_ids`: The ids of each influence assigned to each vertext. - These are used to map to the bone names. - - `weights`: The weights of each influence assigned to each vertext. - - `positions`: The positions of each vertex. - """ - - bone_names: list[str] - """The names of the bones in the SkinData""" - bone_ids: np_typing.NDArray[np.int64] - """The bone ids for each influence on each vertex""" - weights: np_typing.NDArray[np.float32] - """The weights for each influence on each vertex""" - positions: np_typing.NDArray[np.float32] - """The position of each vertex in the SkinData's mesh""" - vertex_ids: np_typing.NDArray[np.int64] | None = None - """ - The specific vertex ids that make up the SkinData. - If `None` then all vertices are used to make up the SkinData. - """ - - @typing.overload - def __init__(self): - ... - - @typing.overload - def __init__( - self, - names: tuple[str, ...], - bone_ids: tuple[tuple[int, ...], ...], - weights: tuple[tuple[float, ...], ...], - positions: tuple[tuple[float, float, float], ...], - ): - ... diff --git a/PYProjects/skin_plus_plus_test/__init__.py b/PYProjects/skin_plus_plus_test/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/PYProjects/skin_plus_plus_test/dcc_test_files/test_skin_data.sknd b/PYProjects/skin_plus_plus_test/dcc_test_files/test_skin_data.sknd deleted file mode 100644 index dcf3397..0000000 Binary files a/PYProjects/skin_plus_plus_test/dcc_test_files/test_skin_data.sknd and /dev/null differ diff --git a/PYProjects/skin_plus_plus_test/ordering_test.py b/PYProjects/skin_plus_plus_test/ordering_test.py deleted file mode 100644 index 9ee4687..0000000 --- a/PYProjects/skin_plus_plus_test/ordering_test.py +++ /dev/null @@ -1,70 +0,0 @@ -from __future__ import annotations - - -def get_flat_weights(bone_ids: list[list[int]], weights: list[list[float]], max_influence_count: int = 3): - vertex_count = len(bone_ids) - m_weights = [0.0] * vertex_count * max_influence_count - for vertex_index in range(vertex_count): - vertex_bone_ids = bone_ids[vertex_index] - array_index = vertex_index * max_influence_count - for influence_index in range(len(vertex_bone_ids)): - bone_id = vertex_bone_ids[influence_index] - if bone_id == -1: - continue - index = array_index + bone_id - m_weights[index] = weights[vertex_index][influence_index] - - return m_weights - - -# names = ["one", "two", "three"] -# new_names = ["FART", "three", "one", "two", "RANDOM"] -names = ["Point005", "Point002", "Point003", "Point004"] -new_names = ["Point001", "Point002", "Point003", "Point004", "Point005", "Point006"] -bone_ids = [[0, 1, 2, -1], [1, 2, 3, -1], [0, 1, 3, 2]] -weights = [[0.25, 0.25, 0.5, None], [0.333, 0.333, 0.333, None], [0.25, 0.25, 0.25, 0.25]] - -m_weights = get_flat_weights(bone_ids, weights, max_influence_count=len(names)) - -# print(m_weights) -# print(m_weights == [0.25, 0.75, 0.0, 0.5, 0.5, 0.0, 0.25, 0.25, 0.5]) - - -name_map = {} -for index, name in enumerate(new_names): - name_map[name] = index - -new_bone_ids = [] -for name in names: - if name not in name_map: - continue - new_index = name_map[name] - new_bone_ids.append(new_index) - - -def get_sorted_bone_ids(bone_ids: list[list[int]], new_bone_id_order: list[int]): - for vertex in bone_ids: - for i, bone_id in enumerate(vertex): - if bone_id == -1: - continue - - new_index = new_bone_id_order[bone_id] - vertex[i] = new_index - - return bone_ids - - -print(f"new_bone_ids: {new_bone_ids}") -sorted_bone_ids = get_sorted_bone_ids(bone_ids, new_bone_ids) -# print(f"sorted_bone_ids: {sorted_bone_ids}") - -m_weights = get_flat_weights(sorted_bone_ids, weights, max_influence_count=len(new_names)) - -print(f"m_weights: {m_weights}") -for i in range(3): - span = 5 * i - vert = m_weights[span:span+5] - for j, weight in enumerate(vert): - print(f"{new_names[j]}: {weight}") - print("-----") - diff --git a/PYProjects/skin_plus_plus_test/skin_plus_plus_test.ms b/PYProjects/skin_plus_plus_test/skin_plus_plus_test.ms deleted file mode 100644 index 285e4e9..0000000 --- a/PYProjects/skin_plus_plus_test/skin_plus_plus_test.ms +++ /dev/null @@ -1,182 +0,0 @@ -pyTime = python.import "time" - - -_SKINPPOPS = SkinPPOps() --- getPropNames _SKINPPOPS --- vals = _SKINPPOPS.GetSkinWeights $Sphere002 --- vals[3].Count --- _SKINPPOPS.getPositions $Sphere001 - --- SkinPP.GetSkinWeights $Sphere001 - -fn mxsGetSkinWeights node = ( - skops = SkinOps() - skopGetVertexWeight = skops.GetVertexWeight - skopGetVertexWeightCount = skops.GetVertexWeightCount - skopGetVertexWeightBoneID = skops.GetVertexWeightBoneID - - _polyOp = PolyOp() - polyOpGetVert = _polyOp.GetVert - getVertPosition = polyOpGetVert - if ClassOf node == Editable_mesh do - ( - _meshOp = MeshOp() - getVertPosition = _meshOp.GetVert - ) - - skinModifier = node.Modifiers[Skin] - vertexCount = skops.GetNumberVertices(skinModifier) - skinWeights = #() - skinBoneIDs = #() - positions = #() - for vertexIndex = 1 to vertexCount do - ( - influenceCount = skopGetVertexWeightCount skinModifier vertexIndex - vertexWeights = for influenceIndex = 1 to influenceCount collect skopGetVertexWeight skinModifier vertexIndex influenceIndex - vertexBoneIDs = for influenceIndex = 1 to influenceCount collect skopGetVertexWeightBoneID skinModifier vertexIndex influenceIndex - position = getVertPosition node vertexIndex - Append skinWeights vertexWeights - Append skinBoneIDs vertexBoneIDs - Append positions #(position.X, position.Y, position.Z) - ) - - #(skinWeights, skinBoneIDs, positions) -) - -fn mxsSetSkinWeights node boneIDs weights = ( - skops = SkinOps() - skopGetVertexWeight = skops.GetVertexWeight - skopGetVertexWeightCount = skops.GetVertexWeightCount - skopGetVertexWeightBoneID = skops.GetVertexWeightBoneID - skopReplaceVertexWeights = skops.ReplaceVertexWeights - -- skinOps.ReplaceVertexWeights \ ( | ) \ - -- ( | ) [(node: | name:)] - skinModifier = node.Modifiers[Skin] - vertexCount = skops.GetNumberVertices(skinModifier) - for vertexIndex = 1 to vertexCount do - ( - skopReplaceVertexWeights skinModifier vertexIndex boneIDs[vertexIndex] weights[vertexIndex] - ) -) - - -fn mxs_GetSkinWeights _obj _loopCount = ( - startTime = pyTime.time() - for a = 1 to _loopCount do GetSkinWeights _obj - timeTaken = (pyTime.time() - startTime) - print("mxs: " + (timeTaken as string)) - - timeTaken -) - -fn cppfp_GetSkinWeights _obj _loopCount = ( - SkinPPGetSkinWeights = SkinPP.GetSkinWeights - startTime = pyTime.time() - for a = 1 to _loopCount do SkinPPGetSkinWeights _obj - timeTaken = (pyTime.time() - startTime) - print("c++ function publish: " + (timeTaken as string)) - - timeTaken -) - -fn cpppm_GetSkinWeights _obj _loopCount = ( - SkinPPOpss = SkinPPOps() - SkinPPOpssGetSkinWeights = SkinPPOpss.GetSkinWeights - startTime = pyTime.time() - for a = 1 to _loopCount do SkinPPOpssGetSkinWeights _obj - timeTaken = (pyTime.time() - startTime) - print("c++ primative method: " + (timeTaken as string)) - - timeTaken -) - -fn cpppm2_GetSkinWeights _obj _loopCount = ( - SkinPPOpss = SkinPPOps() - SkinPPOpssGetSkinWeights2 = SkinPPOpss.GetSkinWeights2 - startTime = pyTime.time() - for a = 1 to _loopCount do SkinPPOpssGetSkinWeights2 _obj - timeTaken = (pyTime.time() - startTime) - print("c++ primative method2: " + (timeTaken as string)) - - timeTaken -) - -fn cpppf_GetSkinWeights _obj _loopCount = ( - startTime = pyTime.time() - for a = 1 to _loopCount do SPPGetSkinWeights _obj - timeTaken = (pyTime.time() - startTime) - print("c++ primative function: " + (timeTaken as string)) - - timeTaken -) - - -fn mxs_SetSkinWeights _obj _loopCount _boneIDs _weights = ( - startTime = pyTime.time() - for a = 1 to _loopCount do SetSkinWeights _obj _boneIDs _weights - timeTaken = (pyTime.time() - startTime) - print("mxs taken: " + (timeTaken as string)) - - timeTaken -) - -fn cppfp_SetSkinWeights _obj _loopCount _boneIDs _weights = ( - SkinPPSetSkinWeights = SkinPP.SetSkinWeights - startTime = pyTime.time() - for a = 1 to _loopCount do SkinPPSetSkinWeights _obj _boneIDs _weights - timeTaken = (pyTime.time() - startTime) - print("c++ function publish: " + (timeTaken as string)) - - timeTaken -) - -fn cpppm_SetSkinWeights _obj _loopCount _boneIDs _weights = ( - SkinPPOpss = SkinPPOps() - SkinPPOpssSetSkinWeights = SkinPPOpss.SetSkinWeights - startTime = pyTime.time() - for a = 1 to _loopCount do SkinPPOpssSetSkinWeights _obj _boneIDs _weights #() - timeTaken = (pyTime.time() - startTime) - print("c++ primative method: " + (timeTaken as string)) - - timeTaken -) - -fn cpppf_SetSkinWeights _obj _loopCount _boneIDs _weights = ( - startTime = pyTime.time() - for a = 1 to _loopCount do SPPSetSkinWeights _obj _boneIDs _weights #() - timeTaken = (pyTime.time() - startTime) - print("c++ primative function: " + (timeTaken as string)) - - timeTaken -) - -if False do -( - obj = $Sphere002 - loopCount = 1 - - mxsGetSkinWeights obj - getFunctions = #( - mxs_GetSkinWeights, - cppfp_GetSkinWeights, - cpppm_GetSkinWeights, - cpppm2_GetSkinWeights, - cpppf_GetSkinWeights - ) - - fn comparePerformance functs = ( - times = for funct in functs collect ( - funct obj loopCount - ) - maxTime = amax times - print(maxTime) - - for t in times collect ( format maxTime / t ) - ) -) --- comparePerformance getFunctions - - --- weights = for a = 1 to obj.Verts.Count collect #(0.5, 0.5) --- ids = for a = 1 to obj.Verts.Count collect #(1, 2) --- "---" \ No newline at end of file diff --git a/PYProjects/skin_plus_plus_test/skin_plus_plus_test.py b/PYProjects/skin_plus_plus_test/skin_plus_plus_test.py deleted file mode 100644 index 267c1b6..0000000 --- a/PYProjects/skin_plus_plus_test/skin_plus_plus_test.py +++ /dev/null @@ -1,722 +0,0 @@ -from __future__ import annotations - - -import inspect -import json -import pathlib -import site - -if __name__ == "__main__": - - def __setup__(): - current_file = pathlib.Path(inspect.getfile(lambda: None)) - if str(current_file) == "": - # maya is a piece of shit: - current_file = pathlib.Path( - r"D:\Code\Git\SkinPlusPlus\PYProjects\skin_plus_plus_test\skin_plus_plus_test.py" - ) - current_directory = current_file.parent - site.addsitedir(str(current_directory.parent)) - - __setup__() - -import functools -import numpy as np -import random -import sys -import time -import unittest - - -import skin_plus_plus - -print(skin_plus_plus.current_host) - -# skin_plus_plus.set_debug(False) - -if __name__ == "__main__": - from importlib import reload - - # reload(skin_plus_plus.core) - # reload(skin_plus_plus.io) - # reload(skin_plus_plus) - -_typing = False -if _typing: - from typing import Any - from typing import Callable -del _typing - - -_loops = 1 - - -def set_loops(value: int): - global _loops - _loops = value - - -def get_loops() -> int: - global _loops - return _loops - - -def timer(data_dict: dict[str, tuple[float, Any, str]]) -> Callable: - def wrapper(function: Callable) -> Callable: - @functools.wraps(function) - def wrapper_timer(*args, **kwargs) -> Any: - start_time = time.perf_counter() - value: Any = None - for _ in range(get_loops()): - value = function(*args, **kwargs) - run_time = time.perf_counter() - start_time - data_dict[f"{repr(function.__name__)}"] = ( - run_time, - value, - function.__name__, - ) - return value - - return wrapper_timer - - return wrapper - - -class SkinPlusPlusTestBase(unittest.TestCase): - nodes_to_delete = [] - - @classmethod - def setUpClass(cls): - try: - file = __file__ - except NameError: - file = r"D:\Code\Git\SkinPlusPlus\PYProjects\skin_plus_plus_test\skin_plus_plus_test.py" - cls._current_directory = pathlib.Path(file).parent - cls._dcc_test_files_directory = cls._current_directory / "dcc_test_files" - cls._skin_data_file = cls._dcc_test_files_directory / "test_skin_data.sknd" - - @classmethod - def tearDownClass(cls): - # print("tearDownClass") - # print(f"cls.nodes_to_delete: {cls.nodes_to_delete}") - cls.delete_nodes(cls.nodes_to_delete) - - @classmethod - def delete_nodes(cls, nodes): - raise NotImplementedError() - - @staticmethod - def run_functions(function_list, _obj, *args, loop_count: int = 1): - set_loops(loop_count) - for function in function_list: - result = function(_obj, *args) - if result is None: - continue - print(type(result)) - # print(len(result)) - - @staticmethod - def process_results(time_data: dict[str, tuple[float, Any, str]]): - data = list(time_data.values()) - data.sort(key=lambda x: x[0]) - max_time = data[-1][0] - data.reverse() - for time, _, function_name in data: - percentage_ratio = max_time / time - message = f"{function_name}: {time} -" - if percentage_ratio == 1.0: - message = f"{message} base line" - else: - percentage_increase = percentage_ratio * 100.0 - message = ( - f"{message} {percentage_ratio}x / {percentage_increase}% faster" - ) - print(message) - - def test_export_skin_data(self): - skin_plus_plus.export_skin_data("test_mesh", self._skin_data_file) - - def test_import_skin_data(self): - skin_plus_plus.import_skin_data("test_mesh", self._skin_data_file) - - -class SkinPlusPlusTestMax(SkinPlusPlusTestBase): - @classmethod - def setUpClass(cls): - super().setUpClass() - executable = sys.executable.lower() - assert "3ds max" in executable - cls.setup_mxs_environment() - - @classmethod - def delete_nodes(cls, nodes): - return cls.mxRt.Delete(nodes) - - @classmethod - def setup_mxs_environment(cls): - from pymxs import runtime as mxRt - - cls.mxRt = mxRt - - skinOps = mxRt.SkinOps() - cls.skinOps_GetNumberVertices = skinOps.GetNumberVertices - cls.skinOps_GetVertexWeight = skinOps.GetVertexWeight - cls.skinOps_GetVertexWeightCount = skinOps.GetVertexWeightCount - cls.skinOps_GetVertexWeightBoneID = skinOps.GetVertexWeightBoneID - cls.skinOps_ReplaceVertexWeights = skinOps.ReplaceVertexWeights - - cls.skinPPOps = mxRt.SkinPPOps() - cls.sdk_primative_method_get_skin_weights = cls.skinPPOps.GetSkinWeights - cls.SkinPP_GetSkinWeights = mxRt.SkinPP.GetSkinWeights - cls.SPP_GetSkinWeights = mxRt.SPPGetSkinWeights - - cls.SKINPP_SetSkinWeights = mxRt.SkinPP.SetSkinWeights - cls.SKINPPOPS_SetSkinWeights = cls.skinPPOps.SetSkinWeights - cls.SPPSetSkinWeights = mxRt.SPPSetSkinWeights - - meshOp = mxRt.MeshOp() - cls.meshOp_GetVert = meshOp.GetVert - - polyOp = mxRt.PolyOp() - cls.polyOp_GetVert = polyOp.GetVert - - cls.mxs_get_skin_weights, cls.mxs_set_skin_weights = cls.get_mxs_functions() - - cls.skinned_sphere = mxRt.Sphere(Name="SkinnedSphere") - cls.skin_modifier = mxRt.Skin() - mxRt.AddModifier(cls.skinned_sphere, cls.skin_modifier) - cls.skinned_points = [] - for num in range(4): - skinned_point = mxRt.Point(Name=f"SkinnedPoint_{num}") - update = -1 if num < 3 else 0 - skinOps.AddBone(cls.skin_modifier, skinned_point, update) - cls.skinned_points.append(skinned_point) - - cls.nodes_to_delete.append(cls.skinned_sphere) - cls.nodes_to_delete.extend(cls.skinned_points) - cls.weights = np.zeros((cls.skinned_sphere.Verts.Count, 4), dtype=float) - for index in range(cls.skinned_sphere.Verts.Count): - weights = [random.random() for _ in range(4)] - weights_total = sum(weights) - weights = [float(i) / weights_total for i in weights] - cls.weights[index] = np.array(weights, dtype=float) - cls.skinOps_ReplaceVertexWeights( - cls.skin_modifier, index + 1, [1, 2, 3, 4], weights - ) - - @classmethod - def get_mxs_functions(cls): - current_file = pathlib.Path(__file__) - cls.mxRt.FileIn(str(current_file.with_suffix(".ms"))) - return cls.mxRt.mxsGetSkinWeights, cls.mxRt.mxsSetSkinWeights - - def test_get_performance(self): - return - get_timer_dict: dict[str, tuple[float, Any, str]] = {} - - @timer(get_timer_dict) - def mxs_get_skin_weights(_obj): - data = self.mxs_get_skin_weights(_obj) - weights = np.array( - [np.array(list(weights), dtype=float) for weights in data[0]], - dtype=float, - ) - boneIDs = np.array( - [np.array(list(boneIDs), dtype=float) for boneIDs in data[1]], - dtype=float, - ) - positions = np.array( - [np.array(list(positions), dtype=float) for positions in data[2]], - dtype=float, - ) - - return weights, boneIDs, positions - - @timer(get_timer_dict) - def pymxs_get_skin_weights( - _obj, - ) -> tuple[ - np.ndarray[float, Any], np.ndarray[int, Any], np.ndarray[float, Any] - ]: - skinModifier = _obj.Modifiers[self.mxRt.Skin] - vertexCount = self.skinOps_GetNumberVertices(skinModifier) - getVertPosition = self.polyOp_GetVert - if self.mxRt.ClassOf(_obj) == self.mxRt.Editable_Mesh: - getVertPosition = self.meshOp_GetVert - - skinWeights: np.ndarray[float, Any] = np.empty( - (vertexCount, 6), dtype=float - ) - skinBoneIDs: np.ndarray[float, Any] = np.empty((vertexCount, 6), dtype=int) - positions: np.ndarray[float, Any] = np.empty((vertexCount, 3), dtype=float) - for vertexIndex in range(1, vertexCount + 1): - influenceCount = self.skinOps_GetVertexWeightCount( - skinModifier, vertexIndex - ) - vertexWeights = np.array( - [ - self.skinOps_GetVertexWeight( - skinModifier, vertexIndex, influenceIndex - ) - for influenceIndex in range(1, influenceCount + 1) - ], - dtype=float, - ) - vertexBoneIDs = np.array( - [ - self.skinOps_GetVertexWeightBoneID( - skinModifier, vertexIndex, influenceIndex - ) - for influenceIndex in range(1, influenceCount + 1) - ], - dtype=float, - ) - mxs_position = list(getVertPosition(_obj, vertexIndex)) - position = np.array(mxs_position, dtype=float) - vertexIndexZero = vertexIndex - 1 - skinWeights[vertexIndexZero] = vertexWeights - skinBoneIDs[vertexIndexZero] = vertexBoneIDs - positions[vertexIndexZero] = position - - return skinWeights, skinBoneIDs, positions - - @timer(get_timer_dict) - def sdk_primative_method_get_skin_weights(_obj): - weights, boneIDs, positions = self.sdk_primative_method_get_skin_weights( - _obj - ) - - weights = np.array([list(weights) for weights in weights], dtype=float) - boneIDs = np.array([list(boneIDs) for boneIDs in boneIDs], dtype=int) - positions = np.array( - [list(position) for position in positions], dtype=float - ) - - return weights, boneIDs, positions - - @timer(get_timer_dict) - def skin_plus_plus_get_skin_data(_obj): - return skin_plus_plus.get_skin_data(_obj.Name) - - get_function_list = ( - mxs_get_skin_weights, - pymxs_get_skin_weights, - sdk_primative_method_get_skin_weights, - skin_plus_plus_get_skin_data, - ) - - obj = self.mxRt.GetNodeByName("test_mesh_high") - self.run_functions(get_function_list, obj) - self.process_results(get_timer_dict) - - def test_get_skin_data(self): - skin_data = skin_plus_plus.get_skin_data(self.skinned_sphere.Name) - # because the values returned from 3ds max are 32bit, there can be rounding errors - # which can cause a direct comparison to fail, so we use np.allclose instead: - # https://numpy.org/doc/stable/reference/generated/numpy.allclose.html#numpy.allclose - self.assertTrue(np.allclose(skin_data.weights, self.weights)) - - def test_set_performance(self): - return - - def _as_mxs_array(value, dtype=float): - mxsArray = self.mxRt.Array() - array_length = len(value) - mxsArray[array_length - 1] = None - for index in range(array_length): - sub_value = value[index] - if isinstance(sub_value, np.ndarray): - mxsArray[index] = _as_mxs_array(sub_value, dtype=dtype) - else: - mxsArray[index] = dtype(sub_value) - - return mxsArray - - set_timer_dict: dict[str, tuple[float, Any, str]] = {} - - def SetSkinWeights(_obj, _bone_ids, _weights) -> None: - skinModifier = _obj.Modifiers[self.mxRt.Skin] - vertexCount = self.skinOps_GetNumberVertices(skinModifier) + 1 - for vertex_index in range(1, vertexCount): - vertex_index_zero = vertex_index - 1 - self.skinOps_ReplaceVertexWeights( - skinModifier, - vertex_index, - _bone_ids[vertex_index_zero], - _weights[vertex_index_zero], - ) - - @timer(set_timer_dict) - def set_skin_weights(_obj, _bone_ids, _weights): - skin_plus_plus.set_skin_weights(_obj.Name, _bone_ids, _weights) - - @timer(set_timer_dict) - def mxs_SetSkinWeights(_obj, _bone_ids, _weights): - mxsBoneIDs = _as_mxs_array(_bone_ids, dtype=int) - mxsWeights = _as_mxs_array(_weights) - return self.mxs_set_skin_weights(_obj, mxsBoneIDs, mxsWeights) - - @timer(set_timer_dict) - def pymxs_SetSkinWeights(_obj, _bone_ids, _weights): - mxsBoneIDs = _as_mxs_array(_bone_ids, dtype=int) - mxsWeights = _as_mxs_array(_weights) - return SetSkinWeights(_obj, mxsBoneIDs, mxsWeights) - - @timer(set_timer_dict) - def cppfp_SetSkinWeights(_obj, _bone_ids, _weights): - mxsBoneIDs = _as_mxs_array(_bone_ids, dtype=int) - mxsWeights = _as_mxs_array(_weights) - return self.SKINPP_SetSkinWeights(_obj, mxsBoneIDs, mxsWeights) - - @timer(set_timer_dict) - def cpppm_SetSkinWeights(_obj, _bone_ids, _weights): - mxsBoneIDs = _as_mxs_array(_bone_ids, dtype=int) - mxsWeights = _as_mxs_array(_weights) - return self.SKINPPOPS_SetSkinWeights(_obj, mxsBoneIDs, mxsWeights, []) - - @timer(set_timer_dict) - def cpppf_SetSkinWeights(_obj, _bone_ids, _weights): - mxsBoneIDs = _as_mxs_array(_bone_ids, dtype=int) - mxsWeights = _as_mxs_array(_weights) - return self.SPPSetSkinWeights(_obj, mxsBoneIDs, mxsWeights, []) - - set_function_list = ( - SetSkinWeights, - set_skin_weights, - mxs_SetSkinWeights, - pymxs_SetSkinWeights, - cppfp_SetSkinWeights, - cpppm_SetSkinWeights, - cpppf_SetSkinWeights, - ) - - obj = self.mxRt.GetNodeByName("test_mesh_high") - self.run_functions(set_function_list, obj) - self.process_results(set_timer_dict) - - -class SkinPlusPlusTestMaya(SkinPlusPlusTestBase): - @classmethod - def setUpClass(cls): - super().setUpClass() - executable = sys.executable.lower() - assert "maya" in executable - - from maya import cmds - from maya import mel - - import maya.api.OpenMaya as om - import maya.api.OpenMayaAnim as oman - import pymel.core as pm - - cls.cmds = cmds - cls.mel = mel - cls.om = om - cls.oman = oman - cls.pm = pm - - # version_info = cls.cmds.MaxVersion() - # max_file_path = pathlib.Path( - # f"{cls._dcc_test_files_directory}/max/test_skin_data_{version_info[0]}.max" - # ) - # current_max_file_path = pathlib.Path(cls.cmds.MaxFilePath) / cls.cmds.MaxFileName - # if current_max_file_path == max_file_path: - # return - - # if not max_file_path.exists(): - # raise FileNotFoundError(f"No test file for current max version:\n - {max_file_path}") - - # cls.cmds.LoadMaxFile(str(max_file_path)) - - @classmethod - def setup_maya_environment(cls): - pass - - def test_get_performance(self): - get_timer_dict: dict[str, tuple[float, Any, str]] = {} - - def find_related_skin_cluster(geometry): - if not self.cmds.objExists(geometry): - raise Exception(f"Object {geometry} does not exist!") - - if self.cmds.objectType(geometry) == "transform": - try: - geometry = self.cmds.listRelatives( - geometry, s=True, ni=True, pa=True - )[0] - except: - raise Exception(f"Object {geometry} has no deformable geometry!") - - skin = self.mel.eval(f"findRelatedSkinCluster '{geometry}'") - if not skin: - skin = self.cmds.ls(self.cmds.listHistory(geometry), type="skinCluster") - skin = skin[0] if skin else None - - if not skin: - raise RuntimeError(f"{geometry} has no skin cluster!") - - return skin - - @timer(get_timer_dict) - def cmds_get_skin_weights(_obj: str): - vertex_count = self.cmds.polyEvaluate(_obj, vertex=True) - skin_cluster = find_related_skin_cluster(_obj) - skin_weights = np.empty((vertex_count, 6), dtype=float) - skin_bone_names = [None] * vertex_count - positions: np.ndarray[float, Any] = np.empty((vertex_count, 3), dtype=float) - for vertex_index in range(vertex_count): - vertex_index_str = f"{_obj}.vtx[{vertex_index}]" - vertex_weights = np.array( - self.cmds.skinPercent( - skin_cluster, - vertex_index_str, - query=True, - value=True, - ib=0.00001, - ), - dtype=float, - ) - bone_names = self.cmds.skinPercent( - skin_cluster, - vertex_index_str, - transform=None, - query=True, - ib=0.00001, - ) - positions[vertex_index] = np.array( - self.cmds.xform( - vertex_index_str, query=True, translation=True, worldSpace=False - ), - dtype=float, - ) - skin_weights[vertex_index] = vertex_weights - skin_bone_names[vertex_index] = bone_names - - return skin_weights, positions, skin_bone_names - - @timer(get_timer_dict) - def pymel_get_skin_weights(_obj: str): - def get_skin_cluster(__obj): - """Get the skincluster of a given object - Arguments: - __obj (dagNode): The object to get skincluster - Returns: - pyNode: The skin cluster pynode object - """ - - skin_cluster = None - if isinstance(__obj, str): - __obj = self.pm.PyNode(__obj) - try: - if self.pm.nodeType(__obj.getShape()) not in ( - "mesh", - "nurbsSurface", - "nurbsCurve", - ): - return - for shape in __obj.getShapes(): - try: - for _skin_cluster in self.pm.listHistory( - shape, type="skinCluster" - ): - try: - if _skin_cluster.getGeometry()[0] == shape: - skin_cluster = _skin_cluster - except IndexError: - pass - except Exception: - pass - except Exception: - self.pm.displayWarning("%s: is not supported." % __obj.name()) - - return skin_cluster - - def get_mesh_components_from_tag_expression(skin_cls, tag="*"): - """Get the mesh components from the component tag expression - Thanks to Roy Nieterau a.k.a BigRoyNL from colorBleed for the snippet - Args: - skin_cls (PyNode): Skin cluster node - tag (str, optional): Component tag expression - Returns: - dag_path, MObject: The dagpath tho the shpe and the MObject components - """ - mesh_types = ("mesh", "nurbsSurface", "nurbsCurve") - mesh = None - for mesh_type in mesh_types: - obj = skin_cls.listConnections(et=True, type=mesh_type) - if not obj: - continue - mesh = obj[0].getShape().name() - - if mesh is None: - raise RuntimeError("No mesh found!") - - # Get the mesh out attribute for the shape - out_attr = self.cmds.deformableShape(mesh, localShapeOutAttr=True)[0] - - # Get the output geometry data as MObject - sel = self.om.MSelectionList() - sel.add(mesh) - # dep = self.om.MObject() - dep = sel.getDependNode(0) - fn_dep = self.om.MFnDependencyNode(dep) - plug = fn_dep.findPlug(out_attr, True) - obj = plug.asMObject() - - # Use the MFnGeometryData class to query the components for a tag - # expression - fn_geodata = self.om.MFnGeometryData(obj) - - # Components MObject - components = fn_geodata.resolveComponentTagExpression(tag) - dag_path = self.om.MDagPath.getAPathTo(dep) - fn_mesh = self.om.MFnMesh(dag_path) - - return dag_path, components, fn_mesh - - def get_geometry_components(skin_cls): - """Get the geometry components from skincluster - Arguments: - skin_cls (PyNode): The skincluster node - Returns: - dag_path: The dagpath for the components - componets: The skincluster componets - """ - # Brute force to try the old method using deformerSet. If fail will try - # to use Maya 2022 component tag expression - try: - fnSet = self.om.MFnSet(skin_cls.__apimfn__().deformerSet()) - members = self.om.MSelectionList() - fnSet.getMembers(members, False) - dag_path = self.om.MDagPath() - components = self.om.MObject() - members.getDagPath(0, dag_path, components) - fn_mesh = self.om.MFnMesh(dag_path) - - return dag_path, components, fn_mesh - except: - return get_mesh_components_from_tag_expression(skin_cls) - - def collect_data(skin_cls): - dag_path, _, fn_mesh = get_geometry_components(skin_cls) - space = self.om.MSpace.kObject - vertex_count = fn_mesh.numVertices - positions: np.ndarray[float, Any] = np.empty( - (vertex_count, 3), dtype=float - ) - for index in range(vertex_count): - position = fn_mesh.getPoint(index, space) - positions[index] = np.array( - [position.x, position.y, position.z], dtype=float - ) - - weights = skin_cls.getWeights(dag_path) - weights = np.array( - [np.array(weight, dtype=float) for weight in weights], dtype=float - ) - return weights, positions - - skin_cluster = get_skin_cluster(_obj) - if skin_cluster is None: - raise RuntimeError("No skin cluster found!") - - return collect_data(skin_cluster) - - @timer(get_timer_dict) - def skin_plus_plus_get_skin_data(_obj: str): - return skin_plus_plus.get_skin_data(_obj) - - get_function_list = ( - cmds_get_skin_weights, - pymel_get_skin_weights, - skin_plus_plus_get_skin_data, - ) - - obj = "test_mesh_high" - self.run_functions(get_function_list, obj) - self.process_results(get_timer_dict) - - def test_set_performance(self): - set_timer_dict: dict[str, tuple[float, Any, str]] = {} - - @timer(set_timer_dict) - def set_skin_weights_om( - _obj: str, - _bone_ids: tuple[tuple[int, ...]], - _weights: tuple[tuple[float, ...]], - ): - # Get API handles - selection_list = self.om.MSelectionList() - selection_list.add(_obj) - dag, components = selection_list.getComponent(0) - fn_skin = self.oman.MFnSkinCluster(selection_list.getDependNode(1)) - fn_mesh = self.om.MFnMesh(dag) - - influences = [item for sublist in _bone_ids for item in sublist] - influences.sort() - influences_set = set(influences) - # Set skin weights - influences = self.om.MIntArray() - for influence in influences_set: - influences.append(influence) - - vertex_count = fn_mesh.numVertices - array_count = len(influences * vertex_count) - weights = self.om.MDoubleArray(array_count, 0) - - # Tried to match your for loop setup (first iterate vertices, then influences) - for vertex_index, vertex_weights in _weights: - for influence_index, influence in enumerate(influences): - weights_index = (len(influences) * vertex_index) + influence_index - weights[weights_index] = 0.2 # Set some random weight for now - - fn_skin.setWeights(dag, components, influences, weights, normalize=True) - - @timer(set_timer_dict) - def set_skin_weights(_obj, _bone_ids, _weights): - skin_plus_plus.set_skin_weights(_obj.Name, _bone_ids, _weights) - - set_function_list = ( - set_skin_weights_om, - set_skin_weights, - ) - - obj = self.cmds.GetNodeByName("test_mesh_high") - self.run_functions(set_function_list, obj) - self.process_results(set_timer_dict) - - -def get_sorted_indicies( - indicies: list[list[int]], old_names: list[str], new_names: list[str] -): - name_mapping = {old_name: new_index for new_index, old_name in enumerate(new_names)} - - sorted_bone_ids: list[list[int]] = [] - for index, vert_bone_ids in enumerate(indicies): - sorted_bone_ids[index] = [ - name_mapping[old_names[bone_id]] for bone_id in vert_bone_ids - ] - - -def add_bones(): - from maya import cmds - from maya import mel - - import maya.OpenMaya as om - import maya.OpenMayaAnim as oman - import pymel.core as pm - - selection_list = om.MSelectionList() - # status = om.MStatus() - mobject = om.MObject() - print(mobject) - fnInfluence = oman.MFnIkJoint(mobject) - - -if __name__ == "__main__": - pass - - node = skin_plus_plus.current_host.get_selection()[0] - # skin_data = skin_plus_plus.extract_skin_data(node) - # print(skin_data) - skin_plus_plus.apply_skin_data(node, skin_data) diff --git a/PYProjects/skin_plus_plus_test/wip.py b/PYProjects/skin_plus_plus_test/wip.py deleted file mode 100644 index 54fd50e..0000000 --- a/PYProjects/skin_plus_plus_test/wip.py +++ /dev/null @@ -1,148 +0,0 @@ -from __future__ import annotations - -import maya.OpenMaya as om # type: ignore -import maya.OpenMayaAnim as om_anim # type: ignore -import traceback - - -def get_skin_cluster(name: str) -> om_anim.MFnSkinCluster: - selection_list = om.MSelectionList() - selection_list.add(name) - mobject = om.MObject() - selection_list.getDependNode(0, mobject) - return om_anim.MFnSkinCluster(mobject) - - -def get_skin_cluster_lock_weights_plug(skin_cluster: om_anim.MFnSkinCluster) -> om.MPlug: - return skin_cluster.findPlug("lockWeights", False) - - -def get_skin_cluster_matrix_array_plug(skin_cluster: om_anim.MFnSkinCluster) -> om.MPlug: - return skin_cluster.findPlug("matrix", False) - - -def get_skin_cluster_joints_iter(skin_cluster_matrix_array: om.MPlug): - plug_array = om.MPlugArray() - for index in range(skin_cluster_matrix_array.numConnectedElements()): - plug = skin_cluster_matrix_array.connectionByPhysicalIndex(index) - plug.connectedTo(plug_array, True, False) - joint = om_anim.MFnIkJoint(plug_array[0].node()) - yield joint - - -def get_skin_cluster_joint_names_iter(skin_cluster_matrix_array: om.MPlug, full_name: bool = False): - dag_path = om.MDagPath() - for joint in get_skin_cluster_joints_iter(skin_cluster_matrix_array): - joint.getPath(dag_path) - name = dag_path.fullPathName() if full_name else dag_path.partialPathName() - yield name - - -def get_bind_pose(skin_cluster: om_anim.MFnSkinCluster) -> om.MFnDependencyNode: - bind_pose_plug: om.MPlug = skin_cluster.findPlug("bindPose", False) - connected_plugs = om.MPlugArray() - connected = bind_pose_plug.connectedTo(connected_plugs, True, False) - if not connected: - raise RuntimeError("bindPose not connected to array") - - bind_pose = om.MFnDependencyNode(connected_plugs[0].node()) - if not bind_pose.typeName() == "dagPose": - raise RuntimeError("Dependency node not dagPose") - - return bind_pose - - -def get_bind_pose_members(bind_pose: om.MFnDependencyNode) -> om.MPlug: - return bind_pose.findPlug("members", False) - - -def get_bind_pose_world_matrix_array(bind_pose: om.MFnDependencyNode) -> om.MPlug: - return bind_pose.findPlug("worldMatrix", False) - - -def get_joint(name: str): - selection_list = om.MSelectionList() - selection_list.add(name) - mobject = om.MObject() - selection_list.getDependNode(0, mobject) - if not mobject.hasFn(om.MFn.kJoint): - raise RuntimeError(f"Node is not a joint: '{name}'") - - return om_anim.MFnIkJoint(mobject) - - -def get_joint_world_matrix(joint: om_anim.MFnIkJoint) -> om.MPlug: - try: - plug = joint.findPlug("worldMatrix", False) - return plug.elementByLogicalIndex(0) - except RuntimeError: - dag_path = om.MDagPath() - joint.getPath(dag_path) - print(dag_path.fullPathName()) - raise - - -def add_joints_to_skin_cluster(skin_cluster: om_anim.MFnSkinCluster, joint_names: list[str]): - skin_cluster_matrix_array = get_skin_cluster_matrix_array_plug(skin_cluster) - skin_cluster_lock_weights_plug = get_skin_cluster_lock_weights_plug(skin_cluster) - skin_cluster_joint_names = set(get_skin_cluster_joint_names_iter(skin_cluster_matrix_array)) - - bind_pose = get_bind_pose(skin_cluster) - bind_pose_members = get_bind_pose_members(bind_pose) - bind_pose_world_matrix_array = get_bind_pose_world_matrix_array(bind_pose) - - current_joint_count = skin_cluster_matrix_array.numConnectedElements() - dag_modifier = om.MDagModifier() - for index, joint_name in enumerate(joint_names, 1): - if joint_name in skin_cluster_joint_names: - print(f"Joint alreadty in skin cluster: {joint_name}") - continue - - new_bone_index = index + current_joint_count - joint = get_joint(joint_name) - joint_world_matrix_plug = get_joint_world_matrix(joint) - joint_lock_influence_weights_plug: om.MPlug = joint.findPlug("lockInfluenceWeights", False) - joint_message_plug = joint.findPlug("message", False) - joint_bind_pose_plug = joint.findPlug("bindPose", False) - - skin_cluster_new_matrix_plug: om.MPlug = skin_cluster_matrix_array.elementByLogicalIndex( - new_bone_index - ) - skin_cluster_new_lock_weights_plug: om.MPlug = ( - skin_cluster_lock_weights_plug.elementByLogicalIndex(new_bone_index) - ) - dag_modifier.connect(joint_world_matrix_plug, skin_cluster_new_matrix_plug) - dag_modifier.connect(joint_lock_influence_weights_plug, skin_cluster_new_lock_weights_plug) - - bind_pose_matrix_plug = bind_pose_world_matrix_array.elementByLogicalIndex(new_bone_index) - member_plug = bind_pose_members.elementByLogicalIndex(new_bone_index) - dag_modifier.connect(joint_message_plug, bind_pose_matrix_plug) - dag_modifier.connect(joint_bind_pose_plug, member_plug) - - dag_modifier.doIt() - - -skin_cluster = get_skin_cluster("skinCluster2") -add_joints_to_skin_cluster( - skin_cluster, ["Point009", "Point010", "Point011", "Point012"] -) - - -# print("done") - -# new_bind_pose_index: om.MPlug = bind_pose_members.elementByLogicalIndex() -# bind_pose_world_matrix_array_index: om.MPlug = bind_pose_world_matrix_array.elementByLogicalIndex() - -# joint_message_plug = joint.findPlug("message", False) - -# MPlug bindPoseMatrixArrayPlug = fn_bind_pose.findPlug("worldMatrix", false, &status) - -# MPlug bind_pose_matrix_plug = bindPoseMatrixArrayPlug.elementByLogicalIndex(new_bone_index) - - -# print(f"joint_message_plug: {joint_message_plug}") - - -# bind_pose_plug = joint.findPlug("bindPose", False) - -# dag_modifier.connect() diff --git a/PYProjects/source/.1-install_vcpkg.ps1 b/PYProjects/source/.1-install_vcpkg.ps1 deleted file mode 100644 index 9aeca26..0000000 --- a/PYProjects/source/.1-install_vcpkg.ps1 +++ /dev/null @@ -1,2 +0,0 @@ -iex (iwr -useb https://aka.ms/vcpkg-init.ps1) -pause diff --git a/PYProjects/source/.2-install_dependencies.ps1 b/PYProjects/source/.2-install_dependencies.ps1 deleted file mode 100644 index 8fd988a..0000000 --- a/PYProjects/source/.2-install_dependencies.ps1 +++ /dev/null @@ -1,4 +0,0 @@ -vcpkg install eigen3:x64-windows -vcpkg install fmt:x64-windows -vcpkg install pybind11:x64-windows -pause diff --git a/PYProjects/source/.sln.ps1 b/PYProjects/source/.sln.ps1 deleted file mode 100644 index 6d4141b..0000000 --- a/PYProjects/source/.sln.ps1 +++ /dev/null @@ -1,24 +0,0 @@ -# Set dependency variables here: -$PSScriptRoot -Set-Location "$PSScriptRoot\..\3rdParty" -$Env:THIRD_PARTY_EIGEN = (Resolve-Path -Path "./eigen-3.4.0") -$Env:THIRD_PARTY_FMT = (Resolve-Path -Path "./fmt-10.2.1") - -$Env:ADSK_MAYA_SDK_2022 = "C:\Program Files\Autodesk\Maya2022\devkit\devkitBase" -$Env:ADSK_MAYA_SDK_2023 = "C:\Program Files\Autodesk\Maya2023\devkit\devkitBase" -$Env:ADSK_MAYA_SDK_2024 = "C:\Program Files\Autodesk\Maya2024\devkit\devkitBase" - -$installedVersions = pyenv versions --bare -foreach ($version in $installedVersions) { - pyenv local $version - $pythonPath = pyenv which python - $pythonRootPath = (Get-Item $pythonPath).Directory.FullName - $majorMinor = $version -replace '(\d+\.\d+).*', '$1' -replace '\.', '' - New-Item -Path Env: -Name "PYTHON_$majorMinor" -Value $pythonRootPath - - $pybindPath = (Resolve-Path -Path "..\.venvs\py$majorMinor\.venv\Lib\site-packages\pybind11" -ErrorAction SilentlyContinue) - New-Item -Path Env: -Name "PYBIND11_$majorMinor" -Value $pybindPath -} - -Set-Location $PSScriptRoot -.\skin_plus_plus.sln diff --git a/PYProjects/source/open_skin_plus_plus_sln.bat b/PYProjects/source/open_skin_plus_plus_sln.bat deleted file mode 100644 index a27b830..0000000 --- a/PYProjects/source/open_skin_plus_plus_sln.bat +++ /dev/null @@ -1,3 +0,0 @@ -rem This allows the sln to be opened by double clicking, rather than right click -> run with powershell. -@echo off -PowerShell .sln.ps1 \ No newline at end of file diff --git a/PYProjects/source/post_build.py b/PYProjects/source/post_build.py deleted file mode 100644 index ca44db1..0000000 --- a/PYProjects/source/post_build.py +++ /dev/null @@ -1,97 +0,0 @@ -from __future__ import annotations - -# import pathlib -# import inspect -# import traceback - - -# current_folder = pathlib.Path(inspect.getfile(lambda: None)) - - -# def get_parent_sibling_folder(sibling_name: str): -# for parent in current_folder.parents: -# for sub_path in parent.iterdir(): -# if sub_path.name != sibling_name: -# continue - -# return sub_path - -# raise FileNotFoundError(f"{sibling_name} folder not found!") - - -# build_folder = get_parent_sibling_folder("build") -# build_x64_folder = build_folder / "x64" - -# skin_plus_plus_folder = get_parent_sibling_folder("skin_plus_plus") -# skin_plus_plus_dccs_folder = skin_plus_plus_folder / "dccs" -# skin_plus_plus_py_folder = skin_plus_plus_folder / "py" - - -# folder_map_py = { -# "2021": "37", -# "2022": "37", -# "2023": "39", -# } - -# folder_map_max = { -# "2021": "skin_plus_plus_pymxs_23000", -# "2022": "skin_plus_plus_pymxs_24000", -# "2023": "skin_plus_plus_pymxs_25000", -# } - - -# def move_pyd_files( -# folder_map: dict[str, str], -# target_folder: pathlib.Path, -# suffix: str | None = None, -# dcc: str | None = None, -# ): -# suffix = f"_{suffix}" if suffix else "" -# dcc = dcc or "" -# for year, target_folder_name in folder_map.items(): -# source_folder = build_x64_folder / f"{year}-Release" -# source_file = source_folder / f"skin_plus_plus{suffix}/skin_plus_plus{suffix}.pyd" -# if not source_file.exists(): -# print(f"Source file not found - skipping: {source_file}") -# continue - -# target_file = target_folder / dcc / target_folder_name / f"skin_plus_plus{suffix}.pyd" -# if target_file.exists(): -# target_file.unlink() - -# print(f"Moving: {source_file} -> {target_file}") -# source_file.rename(target_file) - - -# print("Moving pyd files into package") -# try: -# move_pyd_files(folder_map_py, skin_plus_plus_py_folder, suffix="py") -# except Exception: -# traceback.print_exc() - -# try: -# move_pyd_files(folder_map_max, skin_plus_plus_dccs_folder, suffix="pymxs", dcc="max") -# except Exception: -# traceback.print_exc() - -# try: -# move_pyd_files(folder_map_max, skin_plus_plus_dccs_folder, suffix="pymaya", dcc="maya") -# except Exception: -# traceback.print_exc() - -# # for year, target_folder_name in folder_map_py.items(): -# # source_folder = build_x64_folder / f"{year}-Release" -# # source_file = source_folder / "skin_plus_plus_pymxs/skin_plus_plus_pymxs.pyd" -# # if not source_file.exists(): -# # continue - -# # target_file = skin_plus_plus_py_folder / target_folder_name / "skin_plus_plus.pyd" -# # if target_file.exists(): -# # target_file.unlink() - -# # source_file.rename(target_file) - -import os - -PYBIND11_PYTHON_VERSION = os.environ.get("PYBIND11_PYTHON_VERSION") -print(f"PYBIND11_PYTHON_VERSION: {PYBIND11_PYTHON_VERSION}") diff --git a/PYProjects/source/skin_plus_plus.sln b/PYProjects/source/skin_plus_plus.sln deleted file mode 100644 index bc25008..0000000 --- a/PYProjects/source/skin_plus_plus.sln +++ /dev/null @@ -1,69 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.0.31912.275 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "skin_plus_plus_pymxs", "skin_plus_plus_pymxs\skin_plus_plus_pymxs.vcxproj", "{7BF5EA8D-2105-425A-967C-590AD47EC6CB}" - ProjectSection(ProjectDependencies) = postProject - {6A977F79-6449-4D2F-8B5F-9363A19F5046} = {6A977F79-6449-4D2F-8B5F-9363A19F5046} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "skin_plus_plus_py", "skin_plus_plus_py\skin_plus_plus_py.vcxproj", "{6A977F79-6449-4D2F-8B5F-9363A19F5046}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "skin_plus_plus_pymaya", "skin_plus_plus_pymaya\skin_plus_plus_pymaya.vcxproj", "{1A82B795-46D9-40C8-9AE2-4C4D2D71BBFD}" - ProjectSection(ProjectDependencies) = postProject - {6A977F79-6449-4D2F-8B5F-9363A19F5046} = {6A977F79-6449-4D2F-8B5F-9363A19F5046} - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - 2021-Release|x64 = 2021-Release|x64 - 2022-Debug|x64 = 2022-Debug|x64 - 2022-Release|x64 = 2022-Release|x64 - 2023-Debug|x64 = 2023-Debug|x64 - 2023-Release|x64 = 2023-Release|x64 - 2024-Release|x64 = 2024-Release|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {7BF5EA8D-2105-425A-967C-590AD47EC6CB}.2021-Release|x64.ActiveCfg = 2021-Release|x64 - {7BF5EA8D-2105-425A-967C-590AD47EC6CB}.2021-Release|x64.Build.0 = 2021-Release|x64 - {7BF5EA8D-2105-425A-967C-590AD47EC6CB}.2022-Debug|x64.ActiveCfg = 2022-Debug|x64 - {7BF5EA8D-2105-425A-967C-590AD47EC6CB}.2022-Debug|x64.Build.0 = 2022-Debug|x64 - {7BF5EA8D-2105-425A-967C-590AD47EC6CB}.2022-Release|x64.ActiveCfg = 2022-Release|x64 - {7BF5EA8D-2105-425A-967C-590AD47EC6CB}.2022-Release|x64.Build.0 = 2022-Release|x64 - {7BF5EA8D-2105-425A-967C-590AD47EC6CB}.2023-Debug|x64.ActiveCfg = 2023-Debug|x64 - {7BF5EA8D-2105-425A-967C-590AD47EC6CB}.2023-Debug|x64.Build.0 = 2023-Debug|x64 - {7BF5EA8D-2105-425A-967C-590AD47EC6CB}.2023-Release|x64.ActiveCfg = 2023-Release|x64 - {7BF5EA8D-2105-425A-967C-590AD47EC6CB}.2023-Release|x64.Build.0 = 2023-Release|x64 - {7BF5EA8D-2105-425A-967C-590AD47EC6CB}.2024-Release|x64.ActiveCfg = 2024-Release|x64 - {7BF5EA8D-2105-425A-967C-590AD47EC6CB}.2024-Release|x64.Build.0 = 2024-Release|x64 - {6A977F79-6449-4D2F-8B5F-9363A19F5046}.2021-Release|x64.ActiveCfg = 2021-Release|x64 - {6A977F79-6449-4D2F-8B5F-9363A19F5046}.2021-Release|x64.Build.0 = 2021-Release|x64 - {6A977F79-6449-4D2F-8B5F-9363A19F5046}.2022-Debug|x64.ActiveCfg = 2022-Debug|x64 - {6A977F79-6449-4D2F-8B5F-9363A19F5046}.2022-Debug|x64.Build.0 = 2022-Debug|x64 - {6A977F79-6449-4D2F-8B5F-9363A19F5046}.2022-Release|x64.ActiveCfg = 2022-Release|x64 - {6A977F79-6449-4D2F-8B5F-9363A19F5046}.2022-Release|x64.Build.0 = 2022-Release|x64 - {6A977F79-6449-4D2F-8B5F-9363A19F5046}.2023-Debug|x64.ActiveCfg = 2023-Debug|x64 - {6A977F79-6449-4D2F-8B5F-9363A19F5046}.2023-Debug|x64.Build.0 = 2023-Debug|x64 - {6A977F79-6449-4D2F-8B5F-9363A19F5046}.2023-Release|x64.ActiveCfg = 2023-Release|x64 - {6A977F79-6449-4D2F-8B5F-9363A19F5046}.2023-Release|x64.Build.0 = 2023-Release|x64 - {6A977F79-6449-4D2F-8B5F-9363A19F5046}.2024-Release|x64.ActiveCfg = 2024-Release|x64 - {6A977F79-6449-4D2F-8B5F-9363A19F5046}.2024-Release|x64.Build.0 = 2024-Release|x64 - {1A82B795-46D9-40C8-9AE2-4C4D2D71BBFD}.2021-Release|x64.ActiveCfg = 2021-Release|x64 - {1A82B795-46D9-40C8-9AE2-4C4D2D71BBFD}.2022-Debug|x64.ActiveCfg = 2022-Debug|x64 - {1A82B795-46D9-40C8-9AE2-4C4D2D71BBFD}.2022-Debug|x64.Build.0 = 2022-Debug|x64 - {1A82B795-46D9-40C8-9AE2-4C4D2D71BBFD}.2022-Release|x64.ActiveCfg = 2022-Release|x64 - {1A82B795-46D9-40C8-9AE2-4C4D2D71BBFD}.2022-Release|x64.Build.0 = 2022-Release|x64 - {1A82B795-46D9-40C8-9AE2-4C4D2D71BBFD}.2023-Debug|x64.ActiveCfg = 2023-Debug|x64 - {1A82B795-46D9-40C8-9AE2-4C4D2D71BBFD}.2023-Debug|x64.Build.0 = 2023-Debug|x64 - {1A82B795-46D9-40C8-9AE2-4C4D2D71BBFD}.2023-Release|x64.ActiveCfg = 2023-Release|x64 - {1A82B795-46D9-40C8-9AE2-4C4D2D71BBFD}.2023-Release|x64.Build.0 = 2023-Release|x64 - {1A82B795-46D9-40C8-9AE2-4C4D2D71BBFD}.2024-Release|x64.ActiveCfg = 2024-Release|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {6267C530-5EEA-421D-9185-C6D78DC18581} - EndGlobalSection -EndGlobal diff --git a/PYProjects/source/skin_plus_plus_py/headers/skin_plus_plus_py.h b/PYProjects/source/skin_plus_plus_py/headers/skin_plus_plus_py.h deleted file mode 100644 index 7724dbf..0000000 --- a/PYProjects/source/skin_plus_plus_py/headers/skin_plus_plus_py.h +++ /dev/null @@ -1,219 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#define FMT_HEADER_ONLY -#define FMT_DEPRECATED_INCLUDE_XCHAR -#include -//#include - -namespace py = pybind11; -namespace eg = Eigen; - - -typedef std::vector BoneNamesVector; -typedef eg::MatrixXi BoneIDsMatrix; -typedef eg::MatrixXd WeightsMatrix; -typedef eg::MatrixXd PositionMatrix; -typedef unsigned int UINT; - - -template -UINT getItemIndex(std::vector& vector, T item) { - UINT index = std::distance(vector.begin(), find(vector.begin(), vector.end(), item)); - if (index >= vector.size()) - { - return UINT(-1); - } - return index; -} - - -char convertWCharToChar(const wchar_t* text) -{ - std::wstring ws(text); - std::string str(ws.begin(), ws.end()); - - return str[0]; -} - - -std::string convertWCharToString(const wchar_t* text) -{ - std::wstring ws(text); - std::string str(ws.begin(), ws.end()); - - return str; -} - - -std::wstring convertStringToWString(const std::string& multi) { - std::wstring wide; - wchar_t w; - mbstate_t mb{}; - size_t n = 0, len = multi.length() + 1; - while (auto res = mbrtowc(&w, multi.c_str() + n, len - n, &mb)) { - if (res == size_t(-1) || res == size_t(-2)) - throw "invalid encoding"; - - n += res; - wide += w; - } - return wide; -} - - -const char* convertStringToChar(std::string text) -{ - const char* charArray; - charArray = &text[0]; - return charArray; -} - - -struct SortedBoneNameData -{ - std::vector sortedBoneIDs; - std::vector unfoundBoneNames; - SortedBoneNameData(UINT boneCount) - { - sortedBoneIDs = std::vector(boneCount); - unfoundBoneNames = std::vector(); - }; - ~SortedBoneNameData() {} -}; - - -struct PySkinData final -{ -public: - BoneNamesVector boneNames; - BoneIDsMatrix boneIDs; - WeightsMatrix weights; - PositionMatrix positions; - - PySkinData() {} - - PySkinData(UINT vertexCount, UINT maxInfluenceCount) - { - this->boneIDs = BoneIDsMatrix::Constant(vertexCount, maxInfluenceCount, -1); - this->weights = WeightsMatrix::Zero(vertexCount, maxInfluenceCount); - this->positions = PositionMatrix(vertexCount, 3); - } - - PySkinData(BoneNamesVector boneNames, BoneIDsMatrix boneIDs, WeightsMatrix weights, PositionMatrix positions) - { - this->boneNames = boneNames; - this->boneIDs = boneIDs; - this->weights = weights; - this->positions = positions; - } - - PySkinData(py::tuple data) - { - this->setInternalState(data); - } - - ~PySkinData() {} - - // Set the internal state of the object, replacing all data. - // The tuple structure is: (boneNames, boneIDs, weights, positions). - void setInternalState(py::tuple data) - { - if (data.size() != 4) - throw std::runtime_error("Invalid state - The tuple structure is: (bone_names, bone_ids, weights, positions)"); - - this->boneNames = py::cast(data[0]); - this->boneIDs = py::cast(data[1]); - this->weights = py::cast(data[2]); - this->positions = py::cast(data[3]); - } - - // Set a new maximum influence count - void setMaximumVertexWeightCount(int influenceCount) - { - this->boneIDs.conservativeResize(eg::NoChange, influenceCount); - this->weights.conservativeResize(eg::NoChange, influenceCount); - } - - // Get the bone ids in their correct order as well as any missing bones - // for the current skin modifier. - SortedBoneNameData getSortedBoneIDs(BoneNamesVector& currentBoneNames) - { - const size_t cachedBoneCount = this->boneNames.size(); - auto sortedBoneNameData = SortedBoneNameData(cachedBoneCount); - std::unordered_map nameMap; - for (size_t index = 0; index < currentBoneNames.size(); index++) - { - nameMap[currentBoneNames[index]] = index; - } - - for (size_t boneIndex = 0; boneIndex < cachedBoneCount; boneIndex++) - { - const std::string nameToFind = this->boneNames[boneIndex]; - const auto lookup = nameMap.find(nameToFind); - if (lookup != nameMap.end()) - { - sortedBoneNameData.sortedBoneIDs[boneIndex] = lookup->second; - } - else - { - sortedBoneNameData.unfoundBoneNames.push_back(nameToFind); - } - } - if (!sortedBoneNameData.unfoundBoneNames.empty()) - { - std::string message = "The following bones are not in the skin definition:"; - for (const std::string& name : sortedBoneNameData.unfoundBoneNames) - { - message += fmt::format("\n- {}", name); - } - py::print(message); - - } - return sortedBoneNameData; - } -}; - - - -//class PySkinManager -//{ -//private: -// // Whether or not the skin manager is in a valid state. -// // Either no node with the given name can be found, or -// // the given node has no skin modifier on it. -// bool isValid = false; -// -// // Used to track the maximum number of vertex weights, allowing data to be resized only when needed -// int maximumVertexWeightCount; -// -// PySkinData* pySkinData; -// -// // Get the vertex weights and bone ids and add them to the given PySkinData -// void collectWeightsAndBoneIDs(unsigned int vertexIndex); -// -//public: -// PySkinManager(const wchar_t* name) { this->initialise(name); } -// ~PySkinManager() {} -// -// // Initialise the skin manager with the given node name -// virtual bool initialise(const wchar_t* name) { return true; }; -// -// // Get the skin weights from the given node's skin modifier -// std::vector>> getSkinWeights(); -// -// // Get the vertex weights, bone ids and positions from the given node -// PySkinData* getData(); -// -// // Set the skin weights to the given node's skin modifier -// bool setSkinWeights(PySkinData& skinData); -//}; diff --git a/PYProjects/source/skin_plus_plus_py/skin_plus_plus_py.vcxproj b/PYProjects/source/skin_plus_plus_py/skin_plus_plus_py.vcxproj deleted file mode 100644 index 5440725..0000000 --- a/PYProjects/source/skin_plus_plus_py/skin_plus_plus_py.vcxproj +++ /dev/null @@ -1,291 +0,0 @@ - - - - - 2024-Release - x64 - - - 2023-Debug - x64 - - - 2023-Release - x64 - - - 2022-Debug - x64 - - - 2022-Release - x64 - - - 2021-Release - x64 - - - - 16.0 - Win32Proj - {6a977f79-6449-4d2f-8b5f-9363a19f5046} - skin_plus_plus_py - 10.0.19041.0 - - - - DynamicLibrary - false - v141 - true - Unicode - - - DynamicLibrary - true - v141 - Unicode - - - DynamicLibrary - false - v141 - true - Unicode - - - DynamicLibrary - true - v141 - Unicode - - - DynamicLibrary - false - v142 - false - Unicode - x64 - - - DynamicLibrary - false - v142 - false - Unicode - x64 - - - - - - - - - - - - - - - - - - - - - - - - - - true - .pyd - $(SolutionDir)..\..\PYProjects\skin_plus_plus\py\debug_37 - $(THIRD_PARTY_EIGEN);$(THIRD_PARTY_FMT)\include;$(ProjectDir)headers;$(PYTHON_37)\include;$(PYBIND11_37)\include;$(IncludePath) - - - false - .pyd - $(SolutionDir)..\..\PYProjects\skin_plus_plus\py\37 - $(THIRD_PARTY_EIGEN);$(THIRD_PARTY_FMT)\include;$(WindowsSDK_IncludePath);$(VC_IncludePath);$(ProjectDir)headers;$(PYTHON_37)\include;$(PYBIND11_37)\include;$(IncludePath) - - - false - .pyd - $(SolutionDir)..\..\PYProjects\skin_plus_plus\py\37 - $(THIRD_PARTY_EIGEN);$(THIRD_PARTY_FMT)\include;$(WindowsSDK_IncludePath);$(VC_IncludePath);$(ProjectDir)headers;$(PYTHON_37)\include;$(PYBIND11_37)\include;$(IncludePath) - - - true - .pyd - $(SolutionDir)..\..\PYProjects\skin_plus_plus\py\debug_39 - $(THIRD_PARTY_EIGEN);$(THIRD_PARTY_FMT)\include;$(ProjectDir)headers;$(PYTHON_39)\include;$(PYBIND11_39)\include;$(IncludePath) - - - false - .pyd - $(SolutionDir)..\..\PYProjects\skin_plus_plus\py\39\ - $(THIRD_PARTY_EIGEN);$(THIRD_PARTY_FMT)\include;$(ProjectDir)headers;$(PYTHON_39)\include;$(PYBIND11_39)\include;$(IncludePath) - - - false - .pyd - $(SolutionDir)..\..\PYProjects\skin_plus_plus\py\310\ - $(THIRD_PARTY_EIGEN);$(THIRD_PARTY_FMT)\include;$(ProjectDir)headers;$(PYTHON_310)\include;$(PYBIND11_310)\include;$(IncludePath) - - - true - false - - - - Level3 - true - NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - $(PYTHON_37)\include;$(ProjectDir)\headers;%(AdditionalIncludeDirectories) - - - Console - true - $(PYTHON_37)\libs;%(AdditionalLibraryDirectories) - - - - - Level3 - true - NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - $(PYTHON_37)\include;$(ProjectDir)\headers;%(AdditionalIncludeDirectories) - - - Console - true - $(PYTHON_37)\libs;%(AdditionalLibraryDirectories) - - - - - Level3 - true - true - true - NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - %(AdditionalIncludeDirectories) - - - Console - true - true - true - $(PYTHON_37)\libs;%(AdditionalLibraryDirectories) - $(OutDir)$(TargetName)$(TargetExt) - $(OutDir)obj\$(TargetName).pdb - $(OutDir)obj\$(TargetName).pgd - $(OutDir)obj\$(TargetName).lib - UseLinkTimeCodeGeneration - - - $(OutDir)obj\$(TargetName).xml - - - $(OutDir)obj\$(TargetName).bsc - - - - - - - Copy compiled files into correct python module structure - - - - - Level3 - true - true - true - NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - %(AdditionalIncludeDirectories) - - - Console - true - true - true - $(PYTHON_37)\libs;%(AdditionalLibraryDirectories) - $(OutDir)$(TargetName)$(TargetExt) - $(OutDir)obj\$(TargetName).pdb - $(OutDir)obj\$(TargetName).pgd - $(OutDir)obj\$(TargetName).lib - UseLinkTimeCodeGeneration - - - $(OutDir)obj\$(TargetName).xml - - - $(OutDir)obj\$(TargetName).bsc - - - - - - - Copy compiled files into correct python module structure - - - - - Level3 - true - true - true - NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - %(AdditionalIncludeDirectories) - Default - stdc17 - - - Console - true - true - true - $(PYTHON_39)\libs;%(AdditionalLibraryDirectories) - - - - - Level3 - true - true - true - NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - %(AdditionalIncludeDirectories) - stdcpp17 - stdc17 - - - Console - true - true - true - $(PYTHON_310)\libs;%(AdditionalLibraryDirectories) - - - - - - - - - - - - \ No newline at end of file diff --git a/PYProjects/source/skin_plus_plus_py/skin_plus_plus_py.vcxproj.filters b/PYProjects/source/skin_plus_plus_py/skin_plus_plus_py.vcxproj.filters deleted file mode 100644 index a462284..0000000 --- a/PYProjects/source/skin_plus_plus_py/skin_plus_plus_py.vcxproj.filters +++ /dev/null @@ -1,27 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Source Files - - - - - Header Files - - - \ No newline at end of file diff --git a/PYProjects/source/skin_plus_plus_py/source/skin_plus_plus_py.cpp b/PYProjects/source/skin_plus_plus_py/source/skin_plus_plus_py.cpp deleted file mode 100644 index d28b788..0000000 --- a/PYProjects/source/skin_plus_plus_py/source/skin_plus_plus_py.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once -#include - - -PYBIND11_MODULE(skin_plus_plus_py, m) { - - py::class_(m, "SkinData") - .def(py::init()) - .def(py::init()) - .def(py::init()) - .def_readwrite("bone_names", &PySkinData::boneNames) - .def_readwrite("bone_ids", &PySkinData::boneIDs) - .def_readwrite("weights", &PySkinData::weights) - .def_readwrite("positions", &PySkinData::positions) - .def( - py::pickle( - [](const PySkinData& pySkinData) { // __getstate__ - return py::make_tuple( - pySkinData.boneNames, - pySkinData.boneIDs, - pySkinData.weights, - pySkinData.positions - ); - }, - [](py::tuple data) { // __setstate__ - - PySkinData pySkinData(data); - - return pySkinData; - } - ) - ) - .def( - "__repr__", [](const PySkinData& o) { - auto vertexCount = o.boneIDs.rows(); - auto influenceCount = o.boneIDs.cols(); - return fmt::format("", vertexCount, influenceCount); - } - ); -}; diff --git a/PYProjects/source/skin_plus_plus_pymaya/skin_plus_plus_pymaya.cpp b/PYProjects/source/skin_plus_plus_pymaya/skin_plus_plus_pymaya.cpp deleted file mode 100644 index 2b8c2e7..0000000 --- a/PYProjects/source/skin_plus_plus_pymaya/skin_plus_plus_pymaya.cpp +++ /dev/null @@ -1,548 +0,0 @@ -#include -#include -#include -#include - - - -//bool getMeshPositions(const MDagPath& dagPath, Array* pointArray) -//{ -// nvDebugCheck(pointArray != NULL); -// -// MStatus status; -// MFnMesh fnMesh(dagPath, &status); -// -// MItMeshPolygon polyIt(dagPath, MObject::kNullObj, &status); -// if (MS::kSuccess != status) return false; -// -// // Add positions. -// MPointArray positionArray; -// status = fnMesh.getPoints(positionArray, MSpace::kObject); -// if (MS::kSuccess != status) return false; -// -// const uint positionCount = positionArray.length(); -// pointArray->reserve(positionCount); -// -// for (uint i = 0; i < positionCount; i++) -// { -// MPoint point = positionArray[i]; -// pointArray->append(Vector3(point.x, point.y, point.z)); -// } -// -// return true; -//} - - -//MStatus getNodesByName(const MStringArray& nodeNames, MObject& node) -//{ -// MSelectionList selectionList; -// MStatus status = MGlobal::getSelectionListByName(nodeNames, selectionList); -// if (status == MS::kSuccess) -// { -// status = selectionList.getDependNode(0, node); -// } -// return status; -//} - - -bool SkinManagerMaya::initialise(const wchar_t* name) -{ - MStatus status; - this->name = MString(name); - if (getDagPathAndComponent(name, this->dagPath, this->component) == false) - { - return false; - } - MFnMesh fnMesh1(this->dagPath, &status); - MObject meshObj = fnMesh1.object(&status); - this->fnMesh.setObject(meshObj); - status = getMeshAndSkinFns(this->fnMesh, this->fnSkinCluster, this->name); - if (status != MS::kSuccess) - { - this->isValid = false; - return false; - } - py::print("Initialised successfully!"); - - this->isValid = true; - return true; -}; - - -void removeBonesFromBindPose( - MPlug bindPoseMatrixArrayPlug, - MPlug bindPoseMemberArrayPlug, - MPlugArray connectedPlugs, - MDGModifier& dgModifier -) -{ - MStatus status; - for (unsigned i = 0; i < bindPoseMatrixArrayPlug.numConnectedElements(); i++) - { - MPlug matrixPlug = bindPoseMatrixArrayPlug.connectionByPhysicalIndex(i, &status); - matrixPlug.connectedTo(connectedPlugs, true, false); - if (connectedPlugs.length()) - { - dgModifier.disconnect(connectedPlugs[0], matrixPlug); - } - } - for (unsigned i = 0; i < bindPoseMemberArrayPlug.numConnectedElements(); i++) - { - MPlug memberPlug = bindPoseMemberArrayPlug.connectionByPhysicalIndex(i, &status); - memberPlug.connectedTo(connectedPlugs, true, false); - if (connectedPlugs.length()) - { - dgModifier.disconnect(connectedPlugs[0], memberPlug); - } - } -} - - -std::unordered_set getBoneNamesSet(MDagPathArray skinnedBones) -{ - std::vector skinnedBoneNames(skinnedBones.length()); - for (UINT i = 0; i < skinnedBones.length(); i++) - { - skinnedBoneNames[i] = skinnedBones[i].partialPathName().asChar(); - } - std::unordered_set skinnedBoneNamesSet(skinnedBoneNames.begin(), skinnedBoneNames.end()); - return skinnedBoneNamesSet; -} - - -//void validateBindPose(MObject bindPoseNode, MDagPathArray skinnedBones) -//{ -// MPlug element; -// MStatus status; -// MPlugArray connectedPlugs; -// -// auto bindPose = MFnDependencyNode(bindPoseNode); -// auto bindPoseMembersArray = bindPose.findPlug("members", false); -// -// auto boneNames = getBoneNamesSet(skinnedBones); -// -// for (UINT i = 0; i < bindPoseMembersArray.numElements(); i++) -// { -// element = bindPoseMembersArray.elementByPhysicalIndex(i); -// auto elementName = element.partialName().asChar(); -// if (!boneNames.count(elementName)) -// { -// break; -// } -// -// //py::print(fmt::format("bind joint name: {}", joint.name().asChar())); -// //MFnIkJoint(node); -// } -//} - -bool isNodeValid(MObject* node) -{ - if (node->hasFn(MFn::kJoint)) return true; - if (node->hasFn(MFn::kTransform)) return true; - return false; -} - - -UINT getFirstFreeIndex(MPlug* arrayPlug) -{ - UINT freeIndex = arrayPlug->numElements(); - static MPlug elementIndex = arrayPlug->elementByLogicalIndex(freeIndex); - while (elementIndex.isConnected()) - { - freeIndex += 1; - elementIndex = arrayPlug->elementByLogicalIndex(freeIndex); - } - return freeIndex; -} - - -MObject SkinManagerMaya::addMissingBones(BoneNamesVector& missingBoneNames, const UINT& skinnedBoneCount) -{ - for (std::string& name : missingBoneNames) - { - auto command = fmt::format("skinCluster -e -ai {} {}", name, this->fnSkinCluster.name().asChar()); - MGlobal::executeCommand(MString(command.c_str())); - } -} - - -//MObject SkinManagerMaya::addMissingBones(BoneNamesVector& missingBoneNames, const UINT& skinnedBoneCount) -//{ -// MStatus status; -// MSelectionList selectionList; -// MObject dependNode; -// auto bindPosePlug = this->fnSkinCluster.findPlug("bindPose", false, &status); -// if (status != MS::kSuccess) -// { -// throw std::runtime_error("Failed to find bindPose plug on skin cluster!"); -// } -// MPlugArray connectedPlugs; -// bindPosePlug.connectedTo(connectedPlugs, true, false, &status); -// if (status != MS::kSuccess) throw std::runtime_error("bindPose not connected to array"); -// -// auto bindPoseNode = connectedPlugs[0].node(); -// MFnDependencyNode bindPose; -// bindPose.setObject(bindPoseNode); -// if (bindPose.typeName() != "dagPose") throw std::runtime_error("Dependency node not dagPose"); -// -// auto skinClusterMatrixArray = this->fnSkinCluster.findPlug("matrix", false, &status); -// auto skinClusterLockWeightsArray = this->fnSkinCluster.findPlug("lockWeights", false, &status); -// -// const UINT skinClusterMatrixArrayFreeIndex = getFirstFreeIndex(&skinClusterMatrixArray); -// const UINT skinClusterLockWeightsArrayFreeIndex = getFirstFreeIndex(&skinClusterLockWeightsArray); -// -// auto bindPoseMembersArray = bindPose.findPlug("members", false); -// auto bindPoseParentsArray = bindPose.findPlug("parents", false); -// auto bindPoseWorldMatrixArray = bindPose.findPlug("worldMatrix", false); -// -// const UINT bindPoseMemberFreeIndex = getFirstFreeIndex(&bindPoseMembersArray); -// const UINT bindPoseParentsArrayFreeIndex = getFirstFreeIndex(&bindPoseParentsArray); -// const UINT bindPoseWorldMatrixArrayFreeIndex = getFirstFreeIndex(&bindPoseWorldMatrixArray); -// -// MDGModifier dagModifier; -// for (UINT i = 0; i < missingBoneNames.size(); i++) -// { -// auto i_plus_one = i + 1; -// const auto newBoneIndex = skinnedBoneCount + i; -// selectionList.add(missingBoneNames[i].c_str()); -// status = selectionList.getDependNode(i, dependNode); -// if (status != MS::kSuccess) -// { -// auto message = fmt::format("Failed to get depend node for: {}!", missingBoneNames[i]); -// throw std::runtime_error(message); -// } -// if (!isNodeValid(&dependNode)) -// { -// auto message = fmt::format("Node is not a joint or transform: {}", missingBoneNames[i]); -// throw std::runtime_error(message); -// } -// MFnIkJoint joint; -// status = joint.setObject(dependNode); -// if (status != MS::kSuccess) -// { -// auto message = fmt::format("Failed to get MFnIkJoint for: {}!", missingBoneNames[i]); -// throw std::runtime_error(message); -// } -// auto jointMessage = joint.findPlug("message", false); -// auto jointWorldMatrix = joint.findPlug("worldMatrix", false).elementByLogicalIndex(0); -// auto jointLockInfluenceWeightsArray = joint.findPlug("lockInfluenceWeights", false); -// auto jointBindPose = joint.findPlug("bindPose", false, &status); -// if (status != MS::kSuccess) -// { -// -// auto message = fmt::format("Failed to find bindPose attribute for: {}!", missingBoneNames[i]); -// throw std::runtime_error(message); -// } -// -// auto skinClusterMatrixIndex = skinClusterMatrixArray.elementByLogicalIndex(skinClusterMatrixArrayFreeIndex + i_plus_one); -// auto skinClusterLockWeightsIndex = skinClusterLockWeightsArray.elementByLogicalIndex(skinClusterLockWeightsArrayFreeIndex + i_plus_one); -// -// auto bindPoseMemberIndex = bindPoseMembersArray.elementByLogicalIndex(bindPoseMemberFreeIndex + i_plus_one); -// auto bindPoseWorldMatrixIndex = bindPoseWorldMatrixArray.elementByLogicalIndex(bindPoseWorldMatrixArrayFreeIndex + i_plus_one); -// auto bindPoseParentIndex = bindPoseParentsArray.elementByLogicalIndex(bindPoseParentsArrayFreeIndex + i_plus_one); -// -// dagModifier.connect(jointWorldMatrix, skinClusterMatrixIndex); -// dagModifier.connect(jointLockInfluenceWeightsArray, skinClusterLockWeightsIndex); -// -// dagModifier.connect(jointMessage, bindPoseMemberIndex); -// dagModifier.connect(jointBindPose, bindPoseWorldMatrixIndex); -// dagModifier.connect(bindPoseMemberIndex, bindPoseParentIndex); -// } -// status = dagModifier.doIt(); -// if (status != MS::kSuccess) -// { -// throw std::runtime_error("Failed to add missing bones!"); -// } -// std::string message = "Successfully added missing bones:"; -// for (std::string& name : missingBoneNames) -// { -// message += fmt::format(" - ", name); -// } -// py::print(message); -// return bindPoseNode; -//} - - -PySkinData SkinManagerMaya::extractSkinData(const bool safeMode) -{ - if (!this->isValid) - { - throw std::runtime_error("SkinData node is invalid. Cannot get skin weights."); - } - const UINT vertexCount = this->fnMesh.numVertices(); - if (vertexCount == 0) - { - throw std::runtime_error("Mesh has no vertices!"); - } - MDoubleArray weights; - UINT boneCount; - this->fnSkinCluster.getWeights(this->dagPath, this->component, weights, boneCount); - PySkinData pySkinData = PySkinData(vertexCount, this->maximumVertexWeightCount); - MDagPathArray skinnedBones; - MStatus status; - this->fnSkinCluster.influenceObjects(skinnedBones, &status); - if (status != MS::kSuccess) - { - throw std::runtime_error("Failed to find influence objects!"); - } - pySkinData.boneNames = std::vector(skinnedBones.length()); - for (UINT boneIndex = 0; boneIndex < skinnedBones.length(); boneIndex++) - { - pySkinData.boneNames[boneIndex] = fmt::format("{}", skinnedBones[boneIndex].partialPathName().asChar()); - } - MPoint mPoint; - pySkinData.setMaximumVertexWeightCount(boneCount); - for (UINT vertexIndex = 0; vertexIndex < vertexCount; vertexIndex++) - { - UINT influenceIndex = 0; - UINT weightIndexBase = vertexIndex * boneCount; - for (UINT boneIndex = 0; boneIndex < boneCount; boneIndex++) - { - UINT weightIndex = weightIndexBase + boneIndex; - double influenceWeight = weights[weightIndex]; - pySkinData.weights(vertexIndex, influenceIndex) = influenceWeight; - pySkinData.boneIDs(vertexIndex, influenceIndex) = boneIndex; - influenceIndex += 1; - } - fnMesh.getPoint(vertexIndex, mPoint, MSpace::kObject); - pySkinData.positions(vertexIndex, 0) = mPoint.x; - pySkinData.positions(vertexIndex, 1) = mPoint.y; - pySkinData.positions(vertexIndex, 2) = mPoint.z; - } - if (safeMode) - { - if (pySkinData.weights.hasNaN()) - { - std::string errorMessage = "Weights contain none-numbers:\n"; - for (eg::Index i = 0; i < pySkinData.weights.rows(); ++i) - { - for (eg::Index j = 0; j < pySkinData.weights.cols(); ++j) - { - if (std::isnan(pySkinData.weights(i, j))) - { - errorMessage += fmt::format("Vertex: {} Influence: {}\n", i, j); - } - } - } - throw std::runtime_error(errorMessage); - } - } - - return pySkinData; -} - - -void sortBoneIDs(BoneIDsMatrix& boneIDs, std::vector newIDOrder, const eg::Index vertexCount, const eg::Index influenceCount) -{ - BoneIDsMatrix sortedBoneIDs = BoneIDsMatrix(boneIDs); - for (eg::Index vertexIndex = 0; vertexIndex < vertexCount; vertexIndex++) - { - for (eg::Index influenceIndex = 0; influenceIndex < influenceCount; influenceIndex++) - { - const int boneID = boneIDs(vertexIndex, influenceIndex); - if (boneID == -1) - { - continue; - } - const int newIndex = newIDOrder[boneID]; - boneIDs(vertexIndex, influenceIndex) = newIndex; - } - } -} - - -/// -/// Convert an eigen::MatrixXd weights matrix to a MDoubleArray. -/// This array is flat, so the weights which are passed in as a vertex count x influence count matrix, need to be -/// structured so they are flat but each number of elements in the array still represents vertex count x influence count. -/// -/// For example: -/// matrix[0][3] == MDoubleArray[3] -/// matrix[3][3] == MDoubleArray[9] -/// -/// -/// -/// -/// -/// -/// -MDoubleArray getWeightsAsMDoubleArray(BoneIDsMatrix& boneIDs, WeightsMatrix& weights, const eg::Index& vertexCount, const eg::Index& influenceCount, const eg::Index& maxInfluenceCount) -{ - const UINT arraySize = vertexCount * maxInfluenceCount; - MDoubleArray mWeights(arraySize, 0.0); - for (eg::Index vertexIndex = 0; vertexIndex < vertexCount; vertexIndex++) - { - const UINT baseIndex = vertexIndex * maxInfluenceCount; - for (eg::Index influenceIndex = 0; influenceIndex < influenceCount; influenceIndex++) - { - const int boneID = boneIDs(vertexIndex, influenceIndex); - if (boneID == -1) - { - continue; - } - const double weight = weights(vertexIndex, influenceIndex); - const UINT mWeightsIndex = baseIndex + boneID; - mWeights[mWeightsIndex] = weight; - } - } - //for (eg::Index i = 0; i < vertexCount; i++) - //{ - // auto message = fmt::format("Vertex: {} - ", i); - // for (UINT j = 0; j < influenceCount; j++) - // { - // if (j == 0) - // { - // message += "["; - // } - // auto mIndex = i * influenceCount + j; - // message += fmt::format("{}: {}", mIndex, mWeights[mIndex]); - // if (j < influenceCount - 1) - // { - // message += ", "; - // } - // } - // message += "]"; - // py::print(message); - //} - //for (size_t i = 0; i < mWeights.length(); i++) - //{ - // py::print(mWeights[i]); - //} - return mWeights; -} - - -void getBoneNames(std::vector& currentBoneNames, const MDagPathArray& skinnedBones, const UINT& skinnedBoneCount) -{ - currentBoneNames.clear(); - currentBoneNames.resize(skinnedBoneCount); - for (UINT boneIndex = 0; boneIndex < skinnedBoneCount; boneIndex++) - { - currentBoneNames[boneIndex] = fmt::format("{}", skinnedBones[boneIndex].partialPathName().asChar()); - } -} - - -bool SkinManagerMaya::applySkinData(PySkinData& skinData) -{ - auto vertexCount = skinData.boneIDs.rows(); - auto vertexWeightsRows = skinData.weights.rows(); - auto influenceCount = skinData.boneIDs.cols(); - auto vertexWeightsCols = skinData.weights.cols(); - if (vertexCount != vertexWeightsRows) - { - auto exceptionText = convertStringToChar( - fmt::format( - "boneIDs row size: {} does not match vertexWeights row size: {}", - vertexCount, - vertexWeightsRows - ) - ); - throw std::length_error(exceptionText); - } - if (influenceCount != vertexWeightsCols) - { - const char* exceptionText = convertStringToChar( - fmt::format( - "boneIDs column size: {} does not match vertexWeights column size: {}", - influenceCount, - vertexWeightsCols - ) - ); - throw std::length_error(exceptionText); - } - MDagPathArray skinnedBones; - MStatus status; - this->fnSkinCluster.influenceObjects(skinnedBones, &status); - if (status != MS::kSuccess) - { - throw std::runtime_error("Error querying bones!"); - } - auto skinnedBoneCount = skinnedBones.length(); - auto currentBoneNames = std::vector(skinnedBoneCount); - getBoneNames(currentBoneNames, skinnedBones, skinnedBoneCount); - bool bonesAdded = false; - if (skinnedBoneCount == 0) - { - this->addMissingBones(skinData.boneNames, skinnedBoneCount); - bonesAdded = true; - } - auto sortedBoneIDs = skinData.getSortedBoneIDs(currentBoneNames); - if (sortedBoneIDs.unfoundBoneNames.size() != 0) - { - this->addMissingBones(sortedBoneIDs.unfoundBoneNames, skinnedBoneCount); - bonesAdded = true; - } - if (bonesAdded) - { - skinnedBones.clear(); - this->fnSkinCluster.influenceObjects(skinnedBones, &status); - skinnedBoneCount = skinnedBones.length(); - getBoneNames(currentBoneNames, skinnedBones, skinnedBoneCount); - if (status != MS::kSuccess) - { - throw std::runtime_error("Error querying bones!"); - } - sortedBoneIDs = skinData.getSortedBoneIDs(currentBoneNames); - if (sortedBoneIDs.unfoundBoneNames.size() != 0) - { - throw std::runtime_error("Could not find all bones required!"); - } - } - const auto sortedBoneSize = sortedBoneIDs.sortedBoneIDs.size(); - MIntArray mBoneIDs(sortedBoneSize); - for (size_t index = 0; index < sortedBoneSize; index++) - { - mBoneIDs[index] = sortedBoneIDs.sortedBoneIDs[index]; - } - - MDoubleArray mWeights = getWeightsAsMDoubleArray(skinData.boneIDs, skinData.weights, vertexCount, influenceCount, sortedBoneSize); - status = this->fnSkinCluster.setWeights( - this->dagPath, - this->component, - mBoneIDs, - mWeights, - true - //MDoubleArray * oldValues = NULL - ); - if (status != MS::kSuccess) return false; - py::print("Applied Skin Data Successfully!"); - return true; -} - - -PYBIND11_MODULE(skin_plus_plus_pymaya, m) { - // This makes the base SkinData class available to the module: - #include - - m.def("extract_skin_data", [&](wchar_t* name, bool* safeMode) - { - SkinManagerMaya skinManager(name); - PySkinData pySkinData = skinManager.extractSkinData(safeMode=safeMode); - return pySkinData; - - }, - "Extract SkinData from the mesh with the given name", - py::arg("name"), - py::arg("safeMode") = true - ); - m.def("apply_skin_data", [&](wchar_t* name, PySkinData& skinData) - { - SkinManagerMaya skinManager(name); - return skinManager.applySkinData(skinData); - }, - "Apply SkinData to the mesh with the given name", - py::arg("name"), - py::arg("skin_data") - ); - m.def("get_vertex_positions", [&](wchar_t* name, bool* safeMode) - { - SkinManagerMaya skinData(name); - PySkinData pySkinData = skinData.extractSkinData(safeMode = safeMode); - return pySkinData.positions; - - }, - "Get Vertex Positions", - py::arg("name") - ); -} diff --git a/PYProjects/source/skin_plus_plus_pymaya/skin_plus_plus_pymaya.h b/PYProjects/source/skin_plus_plus_pymaya/skin_plus_plus_pymaya.h deleted file mode 100644 index 26e0062..0000000 --- a/PYProjects/source/skin_plus_plus_pymaya/skin_plus_plus_pymaya.h +++ /dev/null @@ -1,250 +0,0 @@ -#pragma once -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - - -bool getDagPathAndComponent(MString name, MDagPath& dagPath, MObject& component) -{ - MObject node; - MSelectionList selectionList; - selectionList.clear(); - selectionList.add(name, true); - if (selectionList.isEmpty()) - { - return false; - } - for (UINT i = 0; i < selectionList.length(); i++) - { - MStatus status = selectionList.getDependNode(i, node); - if (status == MS::kSuccess) // && node.hasFn(MFn::kSkinClusterFilter)) - { - selectionList.getDagPath(i, dagPath, component); - if (component.isNull()) - { - //Try to get the skin from the sel: - MStatus status; - dagPath.extendToShape(); - - MFnSingleIndexedComponent singleIndexComponent; - singleIndexComponent.setComplete(true); - component = singleIndexComponent.create(MFn::kMeshVertComponent, &status); - if (status != MS::kSuccess || component.isNull()) py::print("Component not defined!"); - } - } - - - return dagPath.isValid(); - - } - throw std::exception("Given node is invalid or is not compatible with skin clusters"); -} - - -bool getDagPathsAndComponents(MStringArray names, MDagPathArray& dagPaths, MObjectArray& components) -{ - auto nameLength = names.length(); - dagPaths.setLength(nameLength); - components.setLength(nameLength); - for (UINT i = 0; i < nameLength; i++) - { - auto dagPath = MDagPath(); - auto component = MObject(); - getDagPathAndComponent(names[i], dagPath, component); - dagPaths[i] = dagPath; - components[i] = component; - } - return true; -} - - -MDagPathArray getNodesFromNames(MStringArray names) -{ - MStatus status; - MObject node; - MDagPathArray dagPaths; - MSelectionList selectionList; - selectionList.clear(); - for (MString name: names) - { - selectionList.add(name, true); - } - if (selectionList.isEmpty()) - { - return dagPaths; - } - for (UINT i = 0; i < selectionList.length(); i++) - { - status = selectionList.getDependNode(i, node); - if (status == MS::kSuccess) // && node.hasFn(MFn::kSkinClusterFilter)) - { - MDagPath dagPath; - MObject component; - selectionList.getDagPath(i, dagPath, component); - if (component.isNull()) - { - //Try to get the skin from the sel: - dagPath.extendToShape(); - MFnSingleIndexedComponent singleIndexComponent; - singleIndexComponent.setComplete(true); - component = singleIndexComponent.create(MFn::kMeshVertComponent, &status); - if (status != MS::kSuccess || component.isNull()) py::print("Component not defined!"); - } - - if (dagPath.isValid()) - { - dagPaths.append(dagPath); - } - } - } - return dagPaths; -} - - -bool getDagPathAndComponent(const wchar_t* name, MDagPath& dagPath, MObject& component) -{ - MString mName(name); - return getDagPathAndComponent(mName, dagPath, component); -} - - -bool isSkinClusterValid(MObject& meshNode, bool throwExceptions = true) -{ - MStatus status; - MFnDependencyNode meshDepNode(meshNode); - MPlug skinClusterPlug = meshDepNode.findPlug("inMesh", false, &status); - - if (!status) - { - auto message = fmt::format("The node: '{}' is not connected to a skin cluster!", meshDepNode.name().asChar()); - if (throwExceptions) - { - throw std::exception(message.c_str()); - } - return false; - } - - MPlugArray skinClusterConnections; - skinClusterPlug.connectedTo(skinClusterConnections, true, false, &status); - if (!status || skinClusterConnections.length() > 1) - { - auto message = fmt::format("The node: '{}' is connected to multiple skin clusters: ", meshDepNode.name().asChar()); - std::vector skinClusterNames; - for (UINT i = 0; i < skinClusterConnections.length(); ++i) - { - MObject skinClusterNode = skinClusterConnections[i].node(); - MFnSkinCluster skinClusterFn(skinClusterNode); - skinClusterNames.push_back(skinClusterFn.name()); - message += fmt::format("{}{}", skinClusterNames[i].asChar(), (i < skinClusterNames.size() - 1) ? ", " : "."); - } - if (throwExceptions) - { - throw std::exception(message.c_str()); - } - return false; - } - return true; -} - - -MStatus getMeshAndSkinFns(MFnMesh& fnMesh, MFnSkinCluster& fnSkinCluster, MString name) -{ - MStatus status; - MObject meshObj = fnMesh.object(&status); - if (status != MS::kSuccess) - { - return status; - } - MItDependencyGraph itDependencyGraph( - meshObj, - MFn::kSkinClusterFilter, - MItDependencyGraph::kUpstream, - MItDependencyGraph::kBreadthFirst, - MItDependencyGraph::kNodeLevel, - &status - ); - if (status != MS::kSuccess) - { - return status; - } - if (itDependencyGraph.isDone()) - { - auto message = fmt::format("Given node: '{}' is invalid or is not compatible with skin clusters!", name.asChar()); - throw std::exception(message.c_str()); - } - //return fnSkinCluster.setObject(itDependencyGraph.currentItem()); - - auto isSkinClusterValidResult = isSkinClusterValid(meshObj, true); - if (isSkinClusterValidResult) - { - return fnSkinCluster.setObject(itDependencyGraph.currentItem()); - } - - return MS::kFailure; -} - - -class SkinManagerMaya -{ -private: - // Whether or not the skin manager is in a valid state. - // Either no node with the given name can be found, or - // the given node has no skin modifier on it. - bool isValid = false; - - // Used to track the maximum number of vertex weights, allowing data to be resized only when needed - int maximumVertexWeightCount; - - // Get the vertex weights and bone ids and add them to the given PySkinData - void collectWeightsAndBoneIDs(PySkinData* pySkinData, MDoubleArray weights, unsigned influenceCount, unsigned vertexIndex); - - //MFnMesh* fnMesh; - MFnMesh fnMesh; - - MFnSkinCluster fnSkinCluster; - - MDagPath dagPath; - - MObject component; - - MString name; - -public: - SkinManagerMaya(const wchar_t* name) { - this->initialise(name); - } - //~SkinManagerMaya() { delete this->fnMesh; } - ~SkinManagerMaya() {} - - // Initialise the skin manager with the given node name - bool initialise(const wchar_t* name); - - // Get the skin weights from the given node's skin modifier - //std::vector>> getSkinWeights(); - MObject addMissingBones(std::vector& missingBoneNames, const UINT& skinnedBoneCount); - - // Get the vertex weights, bone ids and positions from the given node - PySkinData extractSkinData(const bool safeMode = true); - - // Set the skin weights to the given node's skin modifier - bool applySkinData(PySkinData& skinData); -}; diff --git a/PYProjects/source/skin_plus_plus_pymaya/skin_plus_plus_pymaya.vcxproj b/PYProjects/source/skin_plus_plus_pymaya/skin_plus_plus_pymaya.vcxproj deleted file mode 100644 index 0be614d..0000000 --- a/PYProjects/source/skin_plus_plus_pymaya/skin_plus_plus_pymaya.vcxproj +++ /dev/null @@ -1,271 +0,0 @@ - - - - - 2021-Release - x64 - - - 2022-Debug - x64 - - - 2022-Release - x64 - - - 2023-Debug - x64 - - - 2023-Release - x64 - - - 2024-Release - x64 - - - - - 16.0 - Win32Proj - {1a82b795-46d9-40c8-9ae2-4c4d2d71bbfd} - skinplusplusmayapy - 10.0.19041.0 - - - - - DynamicLibrary - true - v142 - Unicode - x64 - - - DynamicLibrary - true - v142 - Unicode - x64 - - - DynamicLibrary - false - v142 - true - Unicode - x64 - - - DynamicLibrary - false - v142 - true - Unicode - x64 - - - DynamicLibrary - false - v142 - false - Unicode - x64 - - - DynamicLibrary - false - v143 - false - Unicode - x64 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - false - .pyd - $(THIRD_PARTY_EIGEN);$(THIRD_PARTY_FMT)\include;$(ProjectDir);$(ProjectDir)..\skin_plus_plus_py\headers;$(ADSK_MAYA_SDK_2022)\include;$(PYBIND11_37)\include;$(PYTHON_37)\include;$(IncludePath) - $(ADSK_MAYA_SDK_2022)\lib;$(PYTHON_37)\libs;$(LibraryPath) - $(SolutionDir)..\..\PYProjects\skin_plus_plus\dccs\maya\$(ProjectName)_2021 - - - false - .pyd - $(THIRD_PARTY_EIGEN);$(THIRD_PARTY_FMT)\include;$(ProjectDir);$(ProjectDir)..\skin_plus_plus_py\headers;$(ADSK_MAYA_SDK_2022)\include;$(PYBIND11_37)\include;$(PYTHON_37)\include;$(IncludePath) - $(ADSK_MAYA_SDK_2022)\lib;$(PYTHON_37)\libs;$(LibraryPath) - $(SolutionDir)..\..\PYProjects\skin_plus_plus\dccs\maya\$(ProjectName)_2021 - - - true - .pyd - $(THIRD_PARTY_EIGEN);$(THIRD_PARTY_FMT)\include;$(ProjectDir);$(ProjectDir)..\skin_plus_plus_py\headers;$(ADSK_MAYA_SDK_2022)\include;$(PYTHON_37)\include; - $(ADSK_MAYA_SDK_2022)\lib;$(PYTHON_37)\libs - $(SolutionDir)..\..\PYProjects\skin_plus_plus\dccs\maya\$(ProjectName)_debug_2023\ - - - false - .pyd - $(THIRD_PARTY_EIGEN);$(THIRD_PARTY_FMT)\include;$(ProjectDir);$(ProjectDir)..\skin_plus_plus_py\headers;$(ADSK_MAYA_SDK_2023)\include;$(PYTHON_39)\include;$(PYBIND11_39)\include;$(IncludePath) - $(ADSK_MAYA_SDK_2023)\lib;$(PYTHON_39)\libs;$(LibraryPath) - $(SolutionDir)..\..\PYProjects\skin_plus_plus\dccs\maya\$(ProjectName)_2023\ - - - false - .pyd - $(THIRD_PARTY_EIGEN);$(THIRD_PARTY_FMT)\include;$(ProjectDir);$(ProjectDir)..\skin_plus_plus_py\headers;$(ADSK_MAYA_SDK_2024)\include;$(PYTHON_310)\include;$(PYBIND11_310)\include;$(IncludePath) - $(ADSK_MAYA_SDK_2024)\lib;$(PYTHON_310)\libs;$(LibraryPath) - $(SolutionDir)..\..\PYProjects\skin_plus_plus\dccs\maya\$(ProjectName)_2024\ - - - true - .pyd - $(THIRD_PARTY_EIGEN);$(THIRD_PARTY_FMT)\include;$(ProjectDir);$(ProjectDir)..\skin_plus_plus_py\headers;$(ADSK_MAYA_SDK_2023)\include;$(PYTHON_39)\include;$(PYBIND11_39)\include;$(IncludePath) - $(ADSK_MAYA_SDK_2023)\lib;$(PYTHON_39)\libs;$(LibraryPath) - $(SolutionDir)..\..\PYProjects\skin_plus_plus\dccs\maya\$(ProjectName)_debug_2023 - - - true - false - - - - Level3 - true - _DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - stdcpp20 - stdc17 - - - Console - true - Foundation.lib;OpenMaya.lib;OpenMayaUI.lib;OpenMayaAnim.lib;OpenMayaFX.lib;OpenMayaRender.lib;Image.lib;opengl32.lib;%(AdditionalDependencies) - /export:initializePlugin /export:uninitializePlugin - - - - - Level3 - true - _DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - stdcpp14 - Default - - - Console - true - OpenMaya.lib;OpenMayaAnim.lib;Foundation.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;%(AdditionalDependencies) - /export:initializePlugin /export:uninitializePlugin - - - - - Level3 - true - true - true - NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - stdcpp20 - stdc17 - - - Console - true - true - true - OpenMaya.lib;OpenMayaAnim.lib;Foundation.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;%(AdditionalDependencies) - - - - - Level3 - true - true - true - NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - stdcpp20 - stdc17 - - - Console - true - true - true - OpenMaya.lib;OpenMayaAnim.lib;Foundation.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;%(AdditionalDependencies) - - - - - Level3 - true - true - true - NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - - - Console - true - true - true - OpenMaya.lib;OpenMayaAnim.lib;Foundation.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;%(AdditionalDependencies) - - - - - Level3 - true - true - true - NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - stdcpp17 - - - Console - true - true - true - OpenMaya.lib;OpenMayaAnim.lib;Foundation.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;%(AdditionalDependencies) - - - - - - - - - - - - \ No newline at end of file diff --git a/PYProjects/source/skin_plus_plus_pymaya/skin_plus_plus_pymaya.vcxproj.filters b/PYProjects/source/skin_plus_plus_pymaya/skin_plus_plus_pymaya.vcxproj.filters deleted file mode 100644 index 77b012a..0000000 --- a/PYProjects/source/skin_plus_plus_pymaya/skin_plus_plus_pymaya.vcxproj.filters +++ /dev/null @@ -1,27 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Source Files - - - - - Header Files - - - \ No newline at end of file diff --git a/PYProjects/source/skin_plus_plus_pymaya/skin_plus_plus_pymaya_example.cpp b/PYProjects/source/skin_plus_plus_pymaya/skin_plus_plus_pymaya_example.cpp deleted file mode 100644 index dadf159..0000000 --- a/PYProjects/source/skin_plus_plus_pymaya/skin_plus_plus_pymaya_example.cpp +++ /dev/null @@ -1,428 +0,0 @@ -#include - - -//bool getMeshPositions(const MDagPath& dagPath, Array* pointArray) -//{ -// nvDebugCheck(pointArray != NULL); -// -// MStatus status; -// MFnMesh fnMesh(dagPath, &status); -// -// MItMeshPolygon polyIt(dagPath, MObject::kNullObj, &status); -// if (MS::kSuccess != status) return false; -// -// // Add positions. -// MPointArray positionArray; -// status = fnMesh.getPoints(positionArray, MSpace::kObject); -// if (MS::kSuccess != status) return false; -// -// const uint positionCount = positionArray.length(); -// pointArray->reserve(positionCount); -// -// for (uint i = 0; i < positionCount; i++) -// { -// MPoint point = positionArray[i]; -// pointArray->append(Vector3(point.x, point.y, point.z)); -// } -// -// return true; -//} - -#include -#include -#include - - -//MStatus getNodesByName(const MStringArray& nodeNames, MObject& node) -//{ -// MSelectionList selectionList; -// MStatus status = MGlobal::getSelectionListByName(nodeNames, selectionList); -// if (status == MS::kSuccess) -// { -// status = selectionList.getDependNode(0, node); -// } -// return status; -//} - - -bool SkinManagerMaya::initialise(const wchar_t* name) -{ - MStatus status; - this->name = MString(name); - if (getDagPathAndComponent(name, this->dagPath, this->component) == false) - { - return false; - } - MFnMesh fnMesh1(this->dagPath, &status); - MObject meshObj = fnMesh1.object(&status); - this->fnMesh.setObject(meshObj); - status = getMeshAndSkinFns(this->fnMesh, this->fnSkinCluster); - if (status != MS::kSuccess) - { - this->isValid = false; - return false; - } - py::print("success!"); - - this->isValid = true; - return true; -}; - -void removeBonesFromBindPose(MPlug bindPoseMatrixArrayPlug, MPlug bindPoseMemberArrayPlug, MPlugArray connectedPlugs, MDGModifier& dgModifier) -{ - MStatus status; - for (unsigned i = 0; i < bindPoseMatrixArrayPlug.numConnectedElements(); i++) - { - MPlug matrixPlug = bindPoseMatrixArrayPlug.connectionByPhysicalIndex(i, &status); - matrixPlug.connectedTo(connectedPlugs, true, false); - if (connectedPlugs.length()) - { - dgModifier.disconnect(connectedPlugs[0], matrixPlug); - } - } - for (unsigned i = 0; i < bindPoseMemberArrayPlug.numConnectedElements(); i++) - { - MPlug memberPlug = bindPoseMemberArrayPlug.connectionByPhysicalIndex(i, &status); - memberPlug.connectedTo(connectedPlugs, true, false); - if (connectedPlugs.length()) - { - dgModifier.disconnect(connectedPlugs[0], memberPlug); - } - } -} - - -void SkinManagerMaya::addMissingBones(std::vector missingBoneNames, long currentBoneCount) -{ - long newBoneCount = currentBoneCount; - MStatus status; - MStringArray boneNames; - boneNames.setLength(missingBoneNames.size()); - for (size_t i = 0; i < missingBoneNames.size(); i++) - { - boneNames[i] = MString(missingBoneNames[i].c_str()); - } - auto missingBones = getNodesFromNames(boneNames); - - MPlugArray connectedPlugs; - - bool bindPoseExists = true; - MPlug bindPlug = this->fnSkinCluster.findPlug("bindPose", false, &status); - if (status == MStatus::kFailure) - { - bool bindPoseExists = false; - //auto errorMessage = fmt::format("Failed to find bind pose: {}!", this->fnSkinCluster.name()); - //throw std::exception(errorMessage.c_str()); - } - if (!bindPlug.connectedTo(connectedPlugs, true, false)) - { - auto errorMessage = fmt::format("Failed to find bind pose: {}!", this->fnSkinCluster.name()); - throw std::exception(errorMessage.c_str()); - } - MFnDependencyNode fnBindPose(connectedPlugs[0].node()); - if (fnBindPose.typeName() != "dagPose") - { - auto errorMessage = fmt::format("Invalid bindPose: {}!", fnBindPose.name()); - throw std::exception(errorMessage.c_str()); - } - - MPlug bindPoseMatrixArrayPlug = fnBindPose.findPlug("worldMatrix", false, &status); - if (status == MStatus::kFailure) - { - auto errorMessage = fmt::format("Failed to get worldMatrix plug: {}!", fnBindPose.name()); - throw std::exception(errorMessage.c_str()); - } - MPlug bindPoseMemberArrayPlug = fnBindPose.findPlug("members", false, &status); - if (status == MStatus::kFailure) - { - auto errorMessage = fmt::format("Failed to get members plug: {}!", fnBindPose.name()); - throw std::exception(errorMessage.c_str()); - } - - MDGModifier dgModifier; - MMatrixArray ignoredPreMatrices; - MPlug matrixArrayPlug = this->fnSkinCluster.findPlug("matrix", false, &status); - MPlug bindPreMatrixArrayPlug = this->fnSkinCluster.findPlug("bindPreMatrix", false, &status); - - MSelectionList missingBoneSelectionList; - for (MDagPath bone : missingBones) - { - missingBoneSelectionList.add(bone); - } - MObject mObject; - MDagPath dagPath; - for (unsigned i = 0; i < matrixArrayPlug.numConnectedElements(); i++) - { - MPlug matrixPlug = matrixArrayPlug.connectionByPhysicalIndex(i, &status); - matrixPlug.connectedTo(connectedPlugs, true, false); - if (!connectedPlugs.length()) - { - continue; - } - - MFnIkJoint fnIkJoint(connectedPlugs[0].node()); - fnIkJoint.getPath(dagPath); - - if (!missingBoneSelectionList.hasItem(dagPath)) - { - MPlug preMatrixPlug = bindPreMatrixArrayPlug.elementByLogicalIndex(i); - preMatrixPlug.getValue(mObject); - MFnMatrixData fnMatrixData(mObject); - ignoredPreMatrices.append(fnMatrixData.matrix()); - //ignoreInfluence.push_back(false); - //indexMap.push_back(missingBoneSelectionList.length()); - missingBoneSelectionList.add(connectedPlugs[0].node()); - newBoneCount++; - } - dgModifier.disconnect(connectedPlugs[0], matrixPlug); - } - - MPlug lockWeightsArrayPlug = this->fnSkinCluster.findPlug("lockWeights", false, &status); - for (unsigned i = 0; i < lockWeightsArrayPlug.numConnectedElements(); i++) - { - MPlug lockWeightsPlug = lockWeightsArrayPlug.connectionByPhysicalIndex(i, &status); - lockWeightsPlug.connectedTo(connectedPlugs, true, false); - if (connectedPlugs.length()) - { - dgModifier.disconnect(connectedPlugs[0], lockWeightsPlug); - } - } - MPlug paintPlug = this->fnSkinCluster.findPlug("paintTrans", false, &status); - paintPlug.connectedTo(connectedPlugs, true, false); - if (connectedPlugs.length()) - { - dgModifier.disconnect(connectedPlugs[0], paintPlug); - } - - if (bindPoseExists) - { - removeBonesFromBindPose(bindPoseMatrixArrayPlug, bindPoseMemberArrayPlug, connectedPlugs, dgModifier); - } - - if (!dgModifier.doIt()) - { - dgModifier.undoIt(); - throw std::exception("Failed to reset bone connections!"); - } - - - // make connections from influences to skinCluster and bindPose - for (size_t i = 0; i < missingBoneSelectionList.length(); i++) - { - //if (ignoreInfluence[i]) - //{ - // continue; - //} - - //int index = indexMap[i]; - int newBoneIndex = currentBoneCount + i; - status = missingBoneSelectionList.getDependNode(i, mObject); - MFnIkJoint fnInfluence(mObject, &status); - MPlug influenceMatrixPlug = fnInfluence.findPlug("worldMatrix", false, &status).elementByLogicalIndex(0, &status); - MPlug influenceMessagePlug = fnInfluence.findPlug("message", false, &status); - MPlug influenceBindPosePlug = fnInfluence.findPlug("bindPose", false, &status); - MPlug influenceLockPlug = fnInfluence.findPlug("lockInfluenceWeights", false, &status); - if (!status) - { - // add the lockInfluenceWeights attribute if it doesn't exist - MFnNumericAttribute fnNumericAttribute; - MObject attribute = fnNumericAttribute.create("lockInfluenceWeights", "liw", MFnNumericData::kBoolean, false); - fnInfluence.addAttribute(attribute); - influenceLockPlug = fnInfluence.findPlug("lockInfluenceWeights", false, &status); - } - - // connect influence to the skinCluster - MPlug matrixPlug = matrixArrayPlug.elementByLogicalIndex(newBoneIndex); - MPlug lockPlug = lockWeightsArrayPlug.elementByLogicalIndex(newBoneIndex); - dgModifier.connect(influenceMatrixPlug, matrixPlug); - dgModifier.connect(influenceLockPlug, lockPlug); - - // connect influence to the bindPose - if (!ignoreBindPose) - { - MPlug bindPoseMatrixPlug = bindPoseMatrixArrayPlug.elementByLogicalIndex(newBoneIndex); - MPlug memberPlug = bindPoseMemberArrayPlug.elementByLogicalIndex(newBoneIndex); - dgModifier.connect(influenceMessagePlug, bindPoseMatrixPlug); - dgModifier.connect(influenceBindPosePlug, memberPlug); - } - } - -} - - -PySkinData SkinManagerMaya::getData() -{ - if (!this->isValid) - { - throw std::exception("SkinData object is invalid. Cannot get skin weights."); - } - auto vertexCount = this->fnMesh.numVertices(); - if (vertexCount == 0) - { - throw std::exception("Mesh has no vertices!"); - } - MDoubleArray weights; - unsigned boneCount; - this->fnSkinCluster.getWeights(this->dagPath, this->component, weights, boneCount); - PySkinData pySkinData = PySkinData(vertexCount, this->maximumVertexWeightCount); - - MDagPathArray skinnedBones; - MStatus status; - this->fnSkinCluster.influenceObjects(skinnedBones, &status); - if (status != MS::kSuccess) - { - throw std::exception("Failed to find influence objects!"); - } - //std::vector boneNames(skinnedBones.length()); - pySkinData.boneNames = std::vector(skinnedBones.length()); - for (size_t boneIndex = 0; boneIndex < skinnedBones.length(); boneIndex++) - { - pySkinData.boneNames[boneIndex] = fmt::format("{}", skinnedBones[boneIndex].partialPathName().asChar()); - } - MPoint mPoint; - pySkinData.setMaximumVertexWeightCount(boneCount); - for (size_t vertexIndex = 0; vertexIndex < vertexCount; vertexIndex++) - { - size_t influenceIndex = 0; - size_t weightIndex = vertexIndex * boneCount; - for (size_t boneIndex = 0; boneIndex < boneCount; boneIndex++) - { - weightIndex += boneIndex; - double influenceWeight = weights[weightIndex]; - pySkinData.weights(vertexIndex, influenceIndex) = influenceWeight; - pySkinData.boneIDs(vertexIndex, influenceIndex) = boneIndex; - influenceIndex += 1; - } - fnMesh.getPoint(vertexIndex, mPoint, MSpace::kObject); - pySkinData.positions(vertexIndex, 0) = mPoint.x; - pySkinData.positions(vertexIndex, 1) = mPoint.y; - pySkinData.positions(vertexIndex, 2) = mPoint.z; - } - - return pySkinData; -} - - -bool SkinManagerMaya::setSkinWeights(PySkinData& skinData) -{ - size_t vertexCount = skinData.boneIDs.rows(); - size_t vertexWeightsRows = skinData.weights.rows(); - size_t influenceCount = skinData.boneIDs.cols(); - size_t vertexWeightsCols = skinData.weights.cols(); - if (vertexCount != vertexWeightsRows) - { - const char* exceptionText = convertStringToChar( - fmt::format( - "boneIDs row size: {} does not match vertexWeights row size: {}", - vertexCount, - vertexWeightsRows - ) - ); - throw std::length_error(exceptionText); - } - if (influenceCount != vertexWeightsCols) - { - const char* exceptionText = convertStringToChar( - fmt::format( - "boneIDs column size: {} does not match vertexWeights column size: {}", - influenceCount, - vertexWeightsCols - ) - ); - throw std::length_error(exceptionText); - } - - MDagPathArray skinnedBones; - MStatus status; - this->fnSkinCluster.influenceObjects(skinnedBones, &status); - if (status != MS::kSuccess) - { - throw std::exception("Failed to find any bones!"); - } - auto skinBoneCount = skinnedBones.length(); - auto currentBoneNames = std::vector(skinBoneCount); - for (size_t boneIndex = 0; boneIndex < skinBoneCount; boneIndex++) - { - currentBoneNames[boneIndex] = fmt::format("{}", skinnedBones[boneIndex].partialPathName().asChar()); - } - if (skinBoneCount == 0) - { - this->addMissingBones(skinData.boneNames, skinBoneCount); - this->fnSkinCluster.influenceObjects(skinnedBones, &status); - } - auto sortedBoneIDs = skinData.getSortedBoneIDs(currentBoneNames); - if (sortedBoneIDs.unfoundBoneNames.size() != 0) - { - this->addMissingBones(sortedBoneIDs.unfoundBoneNames); - this->fnSkinCluster.influenceObjects(skinnedBones, &status); - } - size_t arraySize = vertexCount * influenceCount; - MIntArray mBoneIDs(influenceCount); - MDoubleArray mWeights(arraySize); - for (size_t influenceIndex = 0; influenceIndex < influenceCount; influenceIndex++) - { - mBoneIDs[influenceIndex] = sortedBoneIDs.sortedBoneIDs[influenceIndex]; - } - // Unpack nested arrays like so: [[0, 1], [2, 3]] -> [0, 1, 2, 3] - for (size_t vertexIndex = 0; vertexIndex < vertexCount; vertexIndex++) - { - size_t arrayIndex = vertexIndex * influenceCount; - for (size_t influenceIndex = 0; influenceIndex < influenceCount; influenceIndex++) - { - arrayIndex += influenceIndex; - auto boneID = skinData.boneIDs(vertexIndex, influenceIndex); - auto vertexWeight = skinData.weights(vertexIndex, influenceIndex); - mWeights[arrayIndex] = vertexWeight; - } - } - - status = this->fnSkinCluster.setWeights( - this->dagPath, - this->component, - mBoneIDs, - mWeights, - true - //MDoubleArray * oldValues = NULL - ); - if (status != MS::kSuccess) return false; - py::print("Applied Skin Data Successfully!"); - return true; -} - - - - -PYBIND11_MODULE(skin_plus_plus_pymaya, m) { - // This makes the base SkinData class available to the module: - #include - - m.def("get_skin_data", [&](wchar_t* name) - { - SkinManagerMaya skinData(name); - PySkinData pySkinData = skinData.getData(); - return pySkinData; - - }, - "Get Skin Data", - py::arg("name") - ); - m.def("get_vertex_positions", [&](wchar_t* name) - { - SkinManagerMaya skinData(name); - PySkinData pySkinData = skinData.getData(); - return pySkinData.positions; - - }, - "Get Vertex Positions", - py::arg("name") - ); - m.def("set_skin_weights", [&](wchar_t* name, PySkinData& skinData) - { - SkinManagerMaya skinManager(name); - return skinManager.setSkinWeights(skinData); - }, - "Set Skin Weights", - py::arg("name"), - py::arg("skin_data") - ); -} \ No newline at end of file diff --git a/PYProjects/source/skin_plus_plus_pymxs/headers/skin_plus_plus_pymxs.h b/PYProjects/source/skin_plus_plus_pymxs/headers/skin_plus_plus_pymxs.h deleted file mode 100644 index 11439db..0000000 --- a/PYProjects/source/skin_plus_plus_pymxs/headers/skin_plus_plus_pymxs.h +++ /dev/null @@ -1,79 +0,0 @@ -#pragma once -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -class SkinManager -{ -private: - // Whether or not the skin manager is in a valid state. - // Either no node with the given name can be found, or - // the given node has no skin modifier on it. - bool isValid = false; - - // The node with the skin modifier on it: - INode* node; - - // Skin modifier, used to get the interfaces - Modifier* skinModifier; - - // Interface for the skin modifier, used to query bone objects when setting skin weights - ISkin* iSkin; - - // Used to query skin data without selecting skin modifier - ISkinContextData* iSkinContextData; - - // Used to modify skin data without selecting skin modifier - ISkinImportData* iSkinImportData; - - // Used to track the maximum number of vertex weights, allowing data to be resized only when needed - UINT maximumVertexWeightCount; - - PySkinData* pySkinData; - - // Get the vertex weights and bone ids and add them to the given PySkinData - void collectWeightsAndBoneIDs(UINT vertexIndex); - - // Get the vertex weights, bone ids and positions - on an editable mesh: - PySkinData* getDataMesh(UINT vertexCount); - - // Get the vertex weights, bone ids and positions - on an editable poly: - PySkinData* getDataPoly(UINT vertexCount); - - // Add missing bones to the skin modifier based on the given vector of missing bone names - void addMissingBones(std::vector missingBoneNames); - - // Initialise skinModifier, iSkin, iSkinContextData, iSkinImportData - bool initialiseSkin(); - -public: - SkinManager(const wchar_t* name) { this->initialise(name); } - SkinManager(ULONG handle) { this->initialise(handle); } - ~SkinManager(){} - - // Initialise the skin manager with the given node handle - bool initialise(ULONG handle); - - // Initialise the skin manager with the given node name - bool initialise(const wchar_t* name); - - // Get the vertex weights, bone ids and positions from the given node - PySkinData* extractSkinData(); - - // Set the skin weights to the given node's skin modifier - bool applySkinData(PySkinData& skinData); -}; diff --git a/PYProjects/source/skin_plus_plus_pymxs/skin_plus_plus_pymxs.vcxproj b/PYProjects/source/skin_plus_plus_pymxs/skin_plus_plus_pymxs.vcxproj deleted file mode 100644 index 84a2bc7..0000000 --- a/PYProjects/source/skin_plus_plus_pymxs/skin_plus_plus_pymxs.vcxproj +++ /dev/null @@ -1,300 +0,0 @@ - - - - - 2021-Release - x64 - - - 2022-Debug - x64 - - - 2022-Release - x64 - - - 2023-Debug - x64 - - - 2023-Release - x64 - - - 2024-Release - x64 - - - - - 16.0 - Win32Proj - {7bf5ea8d-2105-425a-967c-590ad47ec6cb} - skin_plus_plus_pymxs - 10.0.19041.0 - - - - - DynamicLibrary - false - v141 - false - Unicode - - - DynamicLibrary - true - v141 - Unicode - - - DynamicLibrary - false - v141 - false - Unicode - - - DynamicLibrary - true - v142 - Unicode - - - DynamicLibrary - false - v142 - false - Unicode - x64 - - - DynamicLibrary - false - v142 - false - Unicode - x64 - - - - - - - - - - - - - - - - - - - - - - - - - - true - $(ProjectName) - .pyd - $(THIRD_PARTY_EIGEN);$(THIRD_PARTY_FMT)\include;$(ProjectDir)..\skin_plus_plus_py\headers;$(ProjectDir)headers;$(ADSK_3DSMAX_SDK_2022)\include;$(ADSK_3DSMAX_SDK_2022)\include\geom;$(PYTHON_37)\include;$(PYBIND11_37)\include;$(IncludePath) - $(PYTHON_37)\libs;$(ADSK_3DSMAX_SDK_2022)\lib\x64\Release;$(LibraryPath) - $(SolutionDir)..\..\PYProjects\skin_plus_plus\dccs\max\$(ProjectName)_debug_2022 - - - true - $(ProjectName) - .pyd - $(THIRD_PARTY_EIGEN);$(THIRD_PARTY_FMT)\include;$(ProjectDir)..\skin_plus_plus_py\headers;$(ProjectDir)headers;$(ADSK_3DSMAX_SDK_2023)\include;$(ADSK_3DSMAX_SDK_2023)\include\geom;$(PYTHON_39)\include;$(PYBIND11_39)\include;$(IncludePath) - $(PYTHON_39)\libs;$(ADSK_3DSMAX_SDK_2023)\lib\x64\Release;$(LibraryPath) - $(SolutionDir)..\..\PYProjects\skin_plus_plus\dccs\max\$(ProjectName)_debug_2023 - - - false - .pyd - $(THIRD_PARTY_EIGEN);$(THIRD_PARTY_FMT)\include;$(ProjectDir)..\skin_plus_plus_py\headers;$(ProjectDir)headers;$(ADSK_3DSMAX_SDK_2022)\include;$(ADSK_3DSMAX_SDK_2022)\include\geom;$(PYTHON_37)\include;$(PYBIND11_37)\include;$(IncludePath) - $(SolutionDir)..\..\PYProjects\skin_plus_plus\dccs\max\$(ProjectName)_2021 - - - false - .pyd - $(THIRD_PARTY_EIGEN);$(THIRD_PARTY_FMT)\include;$(ProjectDir)..\skin_plus_plus_py\headers;$(ProjectDir)headers;$(ADSK_3DSMAX_SDK_2022)\include;$(ADSK_3DSMAX_SDK_2022)\include\geom;$(PYTHON_37)\include;$(PYBIND11_37)\include;$(IncludePath) - $(PYTHON_37)\libs;$(ADSK_3DSMAX_SDK_2022)\lib\x64\Release;$(LibraryPath) - $(SolutionDir)..\..\PYProjects\skin_plus_plus\dccs\max\$(ProjectName)_2022 - - - false - .pyd - $(THIRD_PARTY_EIGEN);$(THIRD_PARTY_FMT)\include;$(ProjectDir)\headers;$(ProjectDir)..\skin_plus_plus_py\headers;$(ADSK_3DSMAX_SDK_2023)\include;$(ADSK_3DSMAX_SDK_2023)\include\geom;$(PYTHON_39)\include;$(PYBIND11_39)\include;$(IncludePath) - $(PYTHON_39)\libs;$(ADSK_3DSMAX_SDK_2023)\lib\x64\Release;$(LibraryPath) - $(SolutionDir)..\..\PYProjects\skin_plus_plus\dccs\max\$(ProjectName)_2023 - - - false - .pyd - $(THIRD_PARTY_EIGEN);$(THIRD_PARTY_FMT)\include;$(ProjectDir)\headers;$(ProjectDir)..\skin_plus_plus_py\headers;$(ADSK_3DSMAX_SDK_2024)\include;$(ADSK_3DSMAX_SDK_2024)\include\geom;$(PYTHON_310)\include;$(PYBIND11_310)\include;$(IncludePath) - $(PYTHON_310)\libs;$(ADSK_3DSMAX_SDK_2024)\lib\x64\Release;$(LibraryPath) - $(SolutionDir)..\..\PYProjects\skin_plus_plus\dccs\max\2024\ - $(ProjectName) - - - true - false - - - - Level4 - true - NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - $(ADSK_3DSMAX_SDK_2022)\include;$(ProjectDir)..\skin_plus_plus_py\headers;$(PYTHON_37)\include;$(ProjectDir)\headers;%(AdditionalIncludeDirectories) - MultiThreadedDLL - $(MSBuildProgramFiles32)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0;%(AdditionalUsingDirectories) - true - - - Console - true - $(ADSK_3DSMAX_SDK_2022)\lib\x64\Release\;C:\Program Files\Python37\libs;%(AdditionalLibraryDirectories) - bmm.lib;core.lib;geom.lib;gfx.lib;mesh.lib;maxutil.lib;maxscrpt.lib;gup.lib;paramblk2.lib;%(AdditionalDependencies) - - - - - Level4 - true - NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - %(AdditionalIncludeDirectories) - MultiThreadedDLL - true - - - Console - true - %(AdditionalLibraryDirectories) - bmm.lib;core.lib;geom.lib;gfx.lib;mesh.lib;maxutil.lib;maxscrpt.lib;gup.lib;paramblk2.lib;%(AdditionalDependencies) - - - - - Level4 - true - true - true - NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - $(ProjectDir)..\skin_plus_plus_py\headers;C:\Program Files\Autodesk\3ds Max 2021 SDK\maxsdk\include;$(PYTHON_37)\include;$(ProjectDir)headers;%(AdditionalIncludeDirectories) - $(MSBuildProgramFiles32)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0;%(AdditionalUsingDirectories) - true - - - Console - true - true - true - C:\Program Files\Autodesk\3ds Max 2021 SDK\maxsdk\lib\x64\Release\;C:\Program Files\Python37\libs;%(AdditionalLibraryDirectories) - bmm.lib;core.lib;geom.lib;gfx.lib;mesh.lib;maxutil.lib;maxscrpt.lib;gup.lib;paramblk2.lib;%(AdditionalDependencies) - - - - - Level4 - true - true - true - NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - $(MSBuildProgramFiles32)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0;%(AdditionalUsingDirectories) - true - - - Console - true - true - true - %(AdditionalLibraryDirectories) - bmm.lib;core.lib;geom.lib;gfx.lib;mesh.lib;maxutil.lib;maxscrpt.lib;gup.lib;paramblk2.lib;%(AdditionalDependencies) - - - - - Level4 - true - true - true - NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - %(AdditionalIncludeDirectories) - $(MSBuildProgramFiles32)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0;%(AdditionalUsingDirectories) - true - - - Console - true - true - true - %(AdditionalLibraryDirectories) - bmm.lib;core.lib;geom.lib;gfx.lib;mesh.lib;maxutil.lib;maxscrpt.lib;gup.lib;paramblk2.lib;%(AdditionalDependencies) - - - - - Level4 - true - true - true - NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - %(AdditionalIncludeDirectories) - $(MSBuildProgramFiles32)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0;%(AdditionalUsingDirectories) - true - - - Console - true - true - true - %(AdditionalLibraryDirectories) - bmm.lib;core.lib;geom.lib;gfx.lib;mesh.lib;maxutil.lib;maxscrpt.lib;gup.lib;paramblk2.lib;%(AdditionalDependencies) - - - - - - - - - - - - - - - - - - - - - - $(OutDir)obj/$(TargetName).pgd - - - $(OutDir)obj\$(TargetName).lib - $(OutDir)obj\$(TargetName).pdb - - - stdcpp17 - Speed - - - \ No newline at end of file diff --git a/PYProjects/source/skin_plus_plus_pymxs/skin_plus_plus_pymxs.vcxproj.filters b/PYProjects/source/skin_plus_plus_pymxs/skin_plus_plus_pymxs.vcxproj.filters deleted file mode 100644 index b453f46..0000000 --- a/PYProjects/source/skin_plus_plus_pymxs/skin_plus_plus_pymxs.vcxproj.filters +++ /dev/null @@ -1,27 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Source Files - - - - - Header Files - - - \ No newline at end of file diff --git a/PYProjects/source/skin_plus_plus_pymxs/source/skin_plus_plus_pymxs.cpp b/PYProjects/source/skin_plus_plus_pymxs/source/skin_plus_plus_pymxs.cpp deleted file mode 100644 index cb467ae..0000000 --- a/PYProjects/source/skin_plus_plus_pymxs/source/skin_plus_plus_pymxs.cpp +++ /dev/null @@ -1,472 +0,0 @@ -#pragma once -#include - - - -//std::string convertWChartoString(const wchar_t* text) -//{ -// //fmt::format(text); -// auto text_ = fmt::to_string(text); -// std::wstring ws(text); -// return std::string(ws.begin(), ws.end()); -//} - - -INode* getChildByName(const wchar_t* name, INode* parent) -{ - INode* parent_ = parent; - if (!parent) - { - Interface* ip = GetCOREInterface(); - parent_ = ip->GetRootNode(); - } - INode* node; - const wchar_t* nodeName; - for (int i = 0; i < parent_->NumberOfChildren(); i++) - { - node = parent_->GetChildNode(i); - nodeName = node->GetName(); - if (wcscmp(nodeName, name) == 0) return node; - try { node = getChildByName(name, parent = node); } - catch (const std::invalid_argument&) { continue; } - return node; - } - throw std::invalid_argument("No node with name: " + convertWCharToChar(name)); -} - - -TriObject* getTriObjectFromNode(INode* node, TimeValue time) -{ - Object* object = node->EvalWorldState(time).obj; - auto classID = Class_ID(TRIOBJ_CLASS_ID, 0); - if (object->CanConvertToType(classID)) - { - TriObject* triObject = (TriObject*)object->ConvertToType(time, classID); - return triObject; - } - else - { - return NULL; - } -} - - -PolyObject* getPolyObjectFromNode(INode* inNode, TimeValue inTime, bool& deleteIt) -{ - Object* object = inNode->GetObjectRef(); - auto classID = Class_ID(POLYOBJ_CLASS_ID, 0); - if (object->CanConvertToType(classID)) - { - PolyObject* polyObject = (PolyObject*)object->ConvertToType(inTime, classID); - // Note that the polyObject should only be deleted - // if the pointer to it is not equal to the object - - // pointer that called ConvertToType() - if (object != polyObject) deleteIt = true; - return polyObject; - } - else - { - return NULL; - } -} - - -const inline auto getMeshType(INode* node) -{ - ObjectState objectState = node->EvalWorldState(0); - - if (objectState.obj) - { - Object* object = objectState.obj->FindBaseObject(); - if (object->CanConvertToType(Class_ID(POLYOBJ_CLASS_ID, 0))) return 0; - else if (object->CanConvertToType(Class_ID(TRIOBJ_CLASS_ID, 0))) return 1; - } - return -1; -} - - -bool SkinManager::initialiseSkin() -{ - if (!this->node) - { - throw py::type_error("SkinData init failed. No node initialised!"); - } - Object* object = this->node->GetObjectRef(); - if (!object || (object->SuperClassID() != GEN_DERIVOB_CLASS_ID)) - { - throw py::type_error("SkinData init failed. Node is incorrect type " + convertWCharToChar(this->node->GetName())); - } - IDerivedObject* iDerivedObject = (IDerivedObject*)(object); - if (!iDerivedObject) - { - this->isValid = false; - return this->isValid; - } - - for (int modifierIndex = 0; modifierIndex < iDerivedObject->NumModifiers(); modifierIndex++) - { - this->skinModifier = iDerivedObject->GetModifier(modifierIndex); - if (this->skinModifier->ClassID() != SKIN_CLASSID) continue; - - this->iSkin = (ISkin*)this->skinModifier->GetInterface(I_SKIN); - if (!this->iSkin) continue; - - this->iSkinContextData = this->iSkin->GetContextInterface(this->node); - if (!this->iSkinContextData) continue; - - this->iSkinImportData = (ISkinImportData*)this->skinModifier->GetInterface(I_SKINIMPORTDATA); - if (!this->iSkinImportData) continue; - - this->isValid = true; - return this->isValid; - } -} - - -bool SkinManager::initialise(const wchar_t* name) -{ - this->node = GetCOREInterface()->GetINodeByName(name); - if (!this->node) - { - throw py::type_error("SkinData init failed. No node with name: " + convertWCharToChar(name)); - } - if (this->initialiseSkin()) - { - return true; - } - throw std::runtime_error("SkinData init failed on node: " + convertWCharToChar(name)); -} - - -bool SkinManager::initialise(ULONG handle) -{ - this->node = GetCOREInterface()->GetINodeByHandle(handle); - if (!this->node) - { - throw py::type_error(fmt::format("SkinData init failed. No node with handle: {}", handle)); - } - if (this->initialiseSkin()) - { - return true; - } - throw std::runtime_error(fmt::format("SkinData init failed on node with handle: {}", handle)); -} - - -void SkinManager::collectWeightsAndBoneIDs(UINT vertexIndex) -{ - UINT influenceCount = this->iSkinContextData->GetNumAssignedBones(vertexIndex); - if (influenceCount > this->maximumVertexWeightCount) - { - this->pySkinData->setMaximumVertexWeightCount(influenceCount); - this->maximumVertexWeightCount = influenceCount; - } - for (UINT influenceIndex = 0; influenceIndex < influenceCount; influenceIndex++) - { - double infuenceWeight = this->iSkinContextData->GetBoneWeight(vertexIndex, influenceIndex); - int influenceBoneID = this->iSkinContextData->GetAssignedBone(vertexIndex, influenceIndex); - this->pySkinData->weights(vertexIndex, influenceIndex) = infuenceWeight; - this->pySkinData->boneIDs(vertexIndex, influenceIndex) = influenceBoneID; - /* if (vertexIndex == 0 && influenceIndex == 0) - { - py::print("infuenceWeight: ", infuenceWeight); - py::print("influenceBoneID: ", influenceBoneID); - py::print("this->pySkinData->boneID: ", this->pySkinData->boneIDs(vertexIndex, influenceIndex)); - }*/ - } -} - - -PySkinData* SkinManager::extractSkinData() -{ - if (!isValid) - { - throw std::exception("SkinData object is invalid. Cannot get skin weights."); - } - - unsigned int vertexCount = iSkinContextData->GetNumPoints(); - maximumVertexWeightCount = iSkinContextData->GetNumAssignedBones(0); - for (UINT i = 1; i < vertexCount; i++) - { - auto influenceCount = iSkinContextData->GetNumAssignedBones(i); - if (influenceCount > maximumVertexWeightCount) - { - maximumVertexWeightCount = influenceCount; - } - } - pySkinData = new PySkinData(vertexCount, maximumVertexWeightCount); - auto skinBoneCount = iSkin->GetNumBones(); - pySkinData->boneNames = std::vector(skinBoneCount); - for (auto boneIndex = 0; boneIndex < skinBoneCount; boneIndex++) - { - // we don't use GetBoneName as that can return nulls depending on how the skin modifier has been setup - auto bone = iSkin->GetBone(boneIndex); - if (!bone) - { - bone->GetActualINode(); - } - auto boneName = bone->GetName(); - if (!boneName) - { - auto handle = bone->GetHandle(); - auto exceptionText = convertStringToChar( - fmt::format("Name is NULL on skinned bone at index: {} with handle: {}", boneIndex + 1, handle) - ); - throw std::exception(exceptionText); - } - pySkinData->boneNames[boneIndex] = convertWCharToString(boneName); - } - auto meshType = getMeshType(node); - if (meshType == 0) - { - return getDataMesh(vertexCount); - } - else if (meshType == 1) - { - return getDataPoly(vertexCount); - } - - throw std::exception("Unsupported mesh type, convert to EditablePoly or EditableMesh!"); -} - - -PySkinData* SkinManager::getDataPoly(UINT vertexCount) -{ - - Matrix3 nodeTransform = node->GetObjectTM(0); - bool deleteIt; - PolyObject* polyObject = getPolyObjectFromNode(node, GetCOREInterface()->GetTime(), deleteIt); - MNMesh& mnMesh = polyObject->GetMesh(); - for (UINT vertexIndex = 0; vertexIndex < vertexCount; vertexIndex++) - { - Point3 worldPosition = nodeTransform.PointTransform(mnMesh.V(vertexIndex)->p); - pySkinData->positions(vertexIndex, 0) = worldPosition.x; - pySkinData->positions(vertexIndex, 1) = worldPosition.y; - pySkinData->positions(vertexIndex, 2) = worldPosition.z; - collectWeightsAndBoneIDs(vertexIndex); - //py::print("Influence 0 weight: ", pySkinData->weights(vertexIndex, 0)); - //py::print("------"); - }; - return pySkinData; -} - - -PySkinData* SkinManager::getDataMesh(UINT vertexCount) -{ - Matrix3 nodeTransform = node->GetObjectTM(0); - TriObject* triObject = getTriObjectFromNode(node, GetCOREInterface()->GetTime()); - Mesh& mesh = triObject->GetMesh(); - for (UINT vertexIndex = 0; vertexIndex < vertexCount; vertexIndex++) - { - Point3 worldPosition = nodeTransform.PointTransform(mesh.getVert(vertexIndex)); - pySkinData->positions(vertexIndex, 0) = worldPosition.x; - pySkinData->positions(vertexIndex, 1) = worldPosition.y; - pySkinData->positions(vertexIndex, 2) = worldPosition.z; - collectWeightsAndBoneIDs(vertexIndex); - //py::print("Influence 0 weight: ", pySkinData->weights(vertexIndex, 0)); - //py::print("------"); - }; - return pySkinData; -} - - -void SkinManager::addMissingBones(std::vector missingBoneNames) -{ - std::vector missingBones(missingBoneNames.size()); - for (UINT index = 0; index < missingBoneNames.size(); index++) - { - auto missingBoneName = convertStringToWString(missingBoneNames[index]); - auto missingBone = GetCOREInterface()->GetINodeByName(missingBoneName.c_str()); - if (!missingBone) - { - throw py::value_error( - "No node in scene with name: '" + convertWCharToString(missingBoneName.c_str()) + "'" - ); - } - missingBones[index] = missingBone; - } - - for (int index = 0; index < missingBones.size(); index++) - { - INode* bone = missingBones[index]; - if (index == missingBones.size()) - { - this->iSkinImportData->AddBoneEx(bone, true); - } - else - { - this->iSkinImportData->AddBoneEx(bone, false); - } - } -} - - -struct BoneData -{ - std::vector names; - Tab nodes; - BoneData(int boneCount) - { - names = std::vector(boneCount); - nodes = Tab(); - nodes.Resize(boneCount); - }; - ~BoneData() {} -}; - - -BoneData getBoneData(ISkin* iSkin, int skinBoneCount) -{ - BoneData boneData(skinBoneCount); - for (auto boneIndex = 0; boneIndex < skinBoneCount; boneIndex++) - { - INode* bone = iSkin->GetBone(boneIndex); - auto wcharBoneName = bone->GetName(); - auto stringBoneName = convertWCharToString(wcharBoneName); - boneData.nodes.Append(1, &bone); - boneData.names[boneIndex] = stringBoneName; - } - return boneData; -} - - -bool SkinManager::applySkinData(PySkinData& skinData) -{ - auto boneIDsRows = skinData.boneIDs.rows(); - auto vertexWeightsRows = skinData.weights.rows(); - auto boneIDsCols = skinData.boneIDs.cols(); - auto vertexWeightsCols = skinData.weights.cols(); - if (boneIDsRows != vertexWeightsRows) throw std::length_error( - "skin bone ids count does not match skin weights count: " + convertWCharToChar(this->node->GetName()) - ); - if (boneIDsCols != vertexWeightsCols) throw std::length_error( - "skin bone ids count does not match skin weights count: " + convertWCharToChar(this->node->GetName()) - ); - auto vertexCount = this->iSkinContextData->GetNumPoints(); - if (boneIDsRows != vertexCount) throw std::length_error( - "skin vertex count does not match provided data count: " + convertWCharToChar(this->node->GetName()) - ); - auto skinBoneCount = this->iSkin->GetNumBones(); - if (skinBoneCount == 0) - { - this->addMissingBones(skinData.boneNames); - skinBoneCount = this->iSkin->GetNumBones(); - } - - BoneData boneData = getBoneData(this->iSkin, skinBoneCount); - SortedBoneNameData sortedBoneIDs = skinData.getSortedBoneIDs(boneData.names); - Tab skinBones = boneData.nodes; - size_t sortedBoneIDCount = sortedBoneIDs.sortedBoneIDs.size(); - if (sortedBoneIDs.unfoundBoneNames.size() > 0) - { - this->addMissingBones(sortedBoneIDs.unfoundBoneNames); - skinBoneCount = this->iSkin->GetNumBones(); - boneData = getBoneData(this->iSkin, skinBoneCount); - sortedBoneIDs = skinData.getSortedBoneIDs(boneData.names); - skinBones = boneData.nodes; - } - for (auto vertexIndex = 0; vertexIndex < boneIDsRows; vertexIndex++) - { - Tab bones = Tab(); - Tab weights = Tab(); - bones.Resize(boneIDsCols); - weights.Resize(boneIDsCols); - for (auto influenceIndex = 0; influenceIndex < boneIDsCols; influenceIndex++) - { - const int boneID = skinData.boneIDs(vertexIndex, influenceIndex); - if (boneID == -1) - { - // If boneID is -1, then there are no more influence weights for this vertex so break out of the loop. - break; - } - if (boneID > skinBoneCount) - { - continue; - } - if (boneID > sortedBoneIDCount) - { - auto exceptionText = convertStringToChar( - fmt::format( - "Influence ID {} is out of range of sorted bone count {}!", - boneID, - sortedBoneIDCount - ) - ); - throw std::length_error(exceptionText); - } - float influenceWeight = skinData.weights(vertexIndex, influenceIndex); - const UINT sortedBoneID = sortedBoneIDs.sortedBoneIDs[boneID]; - bones.Append(1, &skinBones[sortedBoneID]); - weights.Append(1, &influenceWeight); - } - - if (!this->iSkinImportData->AddWeights(this->node, vertexIndex, bones, weights)) - { - return false; - } - } - - this->skinModifier->NotifyDependents(FOREVER, PART_GEOM, REFMSG_CHANGE); - GetCOREInterface()->RedrawViews(GetCOREInterface()->GetTime()); - return true; -} - - -bool setSkinWeights(wchar_t* name, PySkinData& skinData) -{ - SkinManager skinData_(name); - return skinData_.applySkinData(skinData); -} - - -PYBIND11_MODULE(skin_plus_plus_pymxs, m) { - // This makes the base SkinData class available to the module: -#include - - m.def("extract_skin_data", [&](wchar_t* name) - { - SkinManager skinData(name); - PySkinData* pySkinData = skinData.extractSkinData(); - return pySkinData; - }, - "Extract SkinData from the mesh with the given name", - py::arg("name") - ); - m.def("extract_skin_data", [&](ULONG handle) - { - SkinManager skinData(handle); - PySkinData* pySkinData = skinData.extractSkinData(); - return pySkinData; - }, - "Extract SkinData from the mesh with the given handle", - py::arg("handle") - ); - m.def("apply_skin_data", [&](wchar_t* name, PySkinData& skinData) - { - SkinManager skinManager(name); - return skinManager.applySkinData(skinData); - }, - "Apply SkinData to the mesh with the given name", - py::arg("name"), - py::arg("skin_data") - ); - m.def("apply_skin_data", [&](ULONG handle, PySkinData& skinData) - { - SkinManager skinManager(handle); - return skinManager.applySkinData(skinData); - }, - "Apply SkinData to the mesh with the given name", - py::arg("name"), - py::arg("skin_data") - ); - m.def("get_vertex_positions", [&](wchar_t* name) - { - SkinManager skinData(name); - PySkinData* pySkinData = skinData.extractSkinData(); - return pySkinData->positions; - }, - "Get Skin Data", - py::arg("name") - ); -} diff --git a/PYProjects/source/skin_plus_plus_pymxs/test/skin_plus_plus_pymxs_test.py b/PYProjects/source/skin_plus_plus_pymxs/test/skin_plus_plus_pymxs_test.py deleted file mode 100644 index 5d69b56..0000000 --- a/PYProjects/source/skin_plus_plus_pymxs/test/skin_plus_plus_pymxs_test.py +++ /dev/null @@ -1,12 +0,0 @@ -import site -site.addsitedir(r"D:\Code\Git\SkinPlusPlus\PyModules\skin_plus_plus\x64\Release") - -import SkinPlusPlusPymxs - -print(SkinPlusPlusPymxs) - -weights = SkinPlusPlusPymxs.get_skin_weights("Sphere001") -print(type(weights)) -print(len(weights[0])) - -print(weights[0][0]) \ No newline at end of file diff --git a/PYProjects/source/vcpkg.json b/PYProjects/source/vcpkg.json deleted file mode 100644 index ec43466..0000000 --- a/PYProjects/source/vcpkg.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "name": "skin-plus-plus", - "version-semver": "0.3.1", - "supports": "(windows & x64)", - "dependencies": - [ - { - "name": "eigen3", - "host": true, - "version>=": "3.4.0#2" - }, - { - "name": "fmt", - "host": true, - "version>=": "9.1.0#1" - } - ], - "builtin-baseline": "dafff8267e0685baa86140e5a5dcf4d9d7383592" -}