diff --git a/PYProjects/.projects/SkinPlusPlus.sublime-project b/PYProjects/.projects/SkinPlusPlus.sublime-project index 2895164..3964320 100644 --- a/PYProjects/.projects/SkinPlusPlus.sublime-project +++ b/PYProjects/.projects/SkinPlusPlus.sublime-project @@ -2,7 +2,13 @@ "folders": [ { - "path": "../../../SkinPlusPlus", - } + "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/skin_plus_plus/.vscode/launch.json b/PYProjects/skin_plus_plus/.vscode/launch.json new file mode 100644 index 0000000..ad3d7cb --- /dev/null +++ b/PYProjects/skin_plus_plus/.vscode/launch.json @@ -0,0 +1,18 @@ +{ + // 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 index 7f8b906..01aded5 100644 --- a/PYProjects/skin_plus_plus/__init__.py +++ b/PYProjects/skin_plus_plus/__init__.py @@ -10,13 +10,21 @@ get_skin_data = None set_skin_weights = 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 __get_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: @@ -34,6 +42,11 @@ def __get_skin_plus_plus_py(python_version: str, debug: bool = False): 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 @@ -47,6 +60,8 @@ def __get_dcc_backend(dcc:str, version: str, api:str): import_path = f"{__name__}.dccs.{dcc}.{sub_module_name}.skin_plus_plus_{api}" backend = importlib.import_module(import_path) + if is_reloading: + importlib.reload(backend) global get_skin_data global set_skin_weights @@ -171,3 +186,6 @@ def __getattr__(name: str) -> Any: "max_to_maya", "maya_to_max" ) + +def __dir__(): + return __all__ diff --git a/PYProjects/skin_plus_plus/__init__.pyi b/PYProjects/skin_plus_plus/__init__.pyi index fc54ebf..c4eefbe 100644 --- a/PYProjects/skin_plus_plus/__init__.pyi +++ b/PYProjects/skin_plus_plus/__init__.pyi @@ -1,5 +1,6 @@ import numpy as np import numpy.typing as np_typing +import typing from .core import FileType as _FileType from .core import export_skin_data as _export_skin_data @@ -45,11 +46,30 @@ class SkinData: - `weights`: The weights of each influence assigned to each vertext. - `positions`: The positions of each vertex. """ + bone_names: list[str] bone_ids: np_typing.NDArray[np.int64] weights: np_typing.NDArray[np.float32] positions: np_typing.NDArray[np.float32] + @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], ...], + ): + ... + + +def get_skin_data(mesh_name: str) -> SkinData: + ... + -def get_skin_data(mesh_name: str) -> SkinData: ... -def set_skin_weights(mesh_name: str, skin_data: SkinData) -> bool: ... +def set_skin_weights(mesh_name: str, skin_data: SkinData) -> bool: + ... diff --git a/PYProjects/skin_plus_plus/core.py b/PYProjects/skin_plus_plus/core.py index bd156a8..75502ab 100644 --- a/PYProjects/skin_plus_plus/core.py +++ b/PYProjects/skin_plus_plus/core.py @@ -115,6 +115,8 @@ def import_skin_data( tuple(data["positions"]) ) + print(f"skin_data.bone_ids: {skin_data.bone_ids}") + return set_skin_weights(mesh_name, skin_data) # if import_type == ImportType.nearest: diff --git a/PYProjects/skin_plus_plus/dccs/max/skin_plus_plus_pymxs_2023/skin_plus_plus_pymxs.exp b/PYProjects/skin_plus_plus/dccs/max/skin_plus_plus_pymxs_2023/skin_plus_plus_pymxs.exp index 0b7af57..3a22b0f 100644 Binary files a/PYProjects/skin_plus_plus/dccs/max/skin_plus_plus_pymxs_2023/skin_plus_plus_pymxs.exp and b/PYProjects/skin_plus_plus/dccs/max/skin_plus_plus_pymxs_2023/skin_plus_plus_pymxs.exp differ diff --git a/PYProjects/skin_plus_plus/dccs/max/skin_plus_plus_pymxs_2023/skin_plus_plus_pymxs.pyd b/PYProjects/skin_plus_plus/dccs/max/skin_plus_plus_pymxs_2023/skin_plus_plus_pymxs.pyd index 84a2ac3..52de632 100644 Binary files a/PYProjects/skin_plus_plus/dccs/max/skin_plus_plus_pymxs_2023/skin_plus_plus_pymxs.pyd and b/PYProjects/skin_plus_plus/dccs/max/skin_plus_plus_pymxs_2023/skin_plus_plus_pymxs.pyd differ diff --git a/PYProjects/skin_plus_plus/dccs/maya/skin_plus_plus_pymaya_2023/skin_plus_plus_pymaya.exp b/PYProjects/skin_plus_plus/dccs/maya/skin_plus_plus_pymaya_2023/skin_plus_plus_pymaya.exp index 3feb3eb..702c2f4 100644 Binary files a/PYProjects/skin_plus_plus/dccs/maya/skin_plus_plus_pymaya_2023/skin_plus_plus_pymaya.exp and b/PYProjects/skin_plus_plus/dccs/maya/skin_plus_plus_pymaya_2023/skin_plus_plus_pymaya.exp 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 index 4794a05..6f25b0e 100644 Binary files a/PYProjects/skin_plus_plus/dccs/maya/skin_plus_plus_pymaya_2023/skin_plus_plus_pymaya.pyd and b/PYProjects/skin_plus_plus/dccs/maya/skin_plus_plus_pymaya_2023/skin_plus_plus_pymaya.pyd differ diff --git a/PYProjects/skin_plus_plus/dccs/maya/skin_plus_plus_pymaya_debug_2023/skin_plus_plus_pymaya.pyd b/PYProjects/skin_plus_plus/dccs/maya/skin_plus_plus_pymaya_debug_2023/skin_plus_plus_pymaya.pyd new file mode 100644 index 0000000..e69de29 diff --git a/PYProjects/skin_plus_plus/py/39/skin_plus_plus_py.exp b/PYProjects/skin_plus_plus/py/39/skin_plus_plus_py.exp index f870b25..3f0d760 100644 Binary files a/PYProjects/skin_plus_plus/py/39/skin_plus_plus_py.exp and b/PYProjects/skin_plus_plus/py/39/skin_plus_plus_py.exp differ 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 index ec09a67..cb2ef9a 100644 Binary files a/PYProjects/skin_plus_plus/py/39/skin_plus_plus_py.pyd and b/PYProjects/skin_plus_plus/py/39/skin_plus_plus_py.pyd differ diff --git a/PYProjects/skin_plus_plus/py/debug_39/skin_plus_plus_py.exp b/PYProjects/skin_plus_plus/py/debug_39/skin_plus_plus_py.exp index bfbc911..52d98a5 100644 Binary files a/PYProjects/skin_plus_plus/py/debug_39/skin_plus_plus_py.exp and b/PYProjects/skin_plus_plus/py/debug_39/skin_plus_plus_py.exp differ diff --git a/PYProjects/skin_plus_plus/py/debug_39/skin_plus_plus_py.pyd b/PYProjects/skin_plus_plus/py/debug_39/skin_plus_plus_py.pyd index 9955bb8..d246c96 100644 Binary files a/PYProjects/skin_plus_plus/py/debug_39/skin_plus_plus_py.pyd and b/PYProjects/skin_plus_plus/py/debug_39/skin_plus_plus_py.pyd differ diff --git a/PYProjects/skin_plus_plus_test/ordering_test.py b/PYProjects/skin_plus_plus_test/ordering_test.py new file mode 100644 index 0000000..cdaa908 --- /dev/null +++ b/PYProjects/skin_plus_plus_test/ordering_test.py @@ -0,0 +1,58 @@ +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"] +bone_ids = [[0, 1, -1], [-1, 1, 2], [0, 1, 2]] +weights = [[0.25, 0.75, None], [None, 0.5, 0.5], [0.25, 0.25, 0.5]] + +m_weights = get_flat_weights(bone_ids, weights) + +print(m_weights) +print(m_weights == [0.25, 0.75, 0.0, 0.0, 0.5, 0.5, 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: + 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 + + +sorted_bone_ids = get_sorted_bone_ids(bone_ids, new_bone_ids) +print(bone_ids) +print(bone_ids == [[1, 2, -1], [-1, 2, 0], [1, 2, 0]]) + +m_weights = get_flat_weights(sorted_bone_ids, weights) + +print(m_weights) +print(m_weights == [0.0, 0.25, 0.75, 0.5, 0.0, 0.5, 0.5, 0.25, 0.25]) diff --git a/PYProjects/skin_plus_plus_test/skin_plus_plus_test.py b/PYProjects/skin_plus_plus_test/skin_plus_plus_test.py index 9c27ed6..c34287e 100644 --- a/PYProjects/skin_plus_plus_test/skin_plus_plus_test.py +++ b/PYProjects/skin_plus_plus_test/skin_plus_plus_test.py @@ -1,14 +1,9 @@ from __future__ import annotations -import functools + import inspect -import numpy as np import pathlib -import random import site -import sys -import time -import unittest if __name__ == "__main__": @@ -24,15 +19,23 @@ def __setup__(): __setup__() +import functools +import numpy as np +import random +import sys +import time +import unittest + + import skin_plus_plus # 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) + # reload(skin_plus_plus.core) + # reload(skin_plus_plus.io) + # reload(skin_plus_plus) _typing = False if _typing: @@ -673,9 +676,39 @@ def add_bones(): if __name__ == "__main__": - skin_plus_plus.io.max_to_maya(file_type=skin_plus_plus.FileType.pickle) + pass + # skin_plus_plus.io.max_to_maya(file_type=skin_plus_plus.FileType.pickle) + # skin_plus_plus + # bones = ["one", "two"] + # ids = np.array([[0, 1], [1, 0]], dtype=np.float64) + # weights = np.array([[0.25, 0.75], [0.25, 0.75]], dtype=np.float64) + # pos = np.array([[0.1, 0.75, 2.0], [0.25, 0.75, 30]], dtype=np.float64) + # sd = skin_plus_plus.skin_plus_plus_py.SkinData(bones, ids, weights, pos) + # print(sd) + + # print(sd.bone_ids) # skin_plus_plus.io.save(file_type=skin_plus_plus.FileType.json) - skin_plus_plus.io.load(file_type=skin_plus_plus.FileType.json) + # skin_plus_plus.io.load(file_type=skin_plus_plus.FileType.json) + import json + import pickle + + path = r"" + + with open(path, "r") as file: + data = json.load(file) + skin_data = skin_plus_plus.SkinData( + tuple(data["bone_names"]), + tuple(data["bone_ids"]), + tuple(data["weights"]), + tuple(data["positions"]) + ) + # with open(path, "rb") as file: + # skin_data = pickle.load(file) + + print(skin_data) + # for ids in skin_data.bone_ids: + # print(ids) + skin_plus_plus.set_skin_weights("Skeleton", skin_data) # skin_data = skin_plus_plus.get_skin_data("Weapon_Shield_1H_001_Model_Main_01_:Shield_GEO") # print(skin_data) # skin_plus_plus.set_skin_weights("SM_EliteEnemy_Axe_GEO", skin_data) 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 index 6c4e5d7..a38172f 100644 --- 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 @@ -105,8 +105,8 @@ struct PySkinData final PySkinData(UINT vertexCount, UINT maxInfluenceCount) { - this->boneIDs = BoneIDsMatrix(vertexCount, maxInfluenceCount); - this->weights = WeightsMatrix(vertexCount, maxInfluenceCount); + this->boneIDs = BoneIDsMatrix::Constant(vertexCount, maxInfluenceCount, -1); + this->weights = WeightsMatrix::Zero(vertexCount, maxInfluenceCount); this->positions = PositionMatrix(vertexCount, 3); } @@ -142,8 +142,8 @@ struct PySkinData final // Set a new maximum influence count void setMaximumVertexWeightCount(int influenceCount) { - this->boneIDs.resize(eg::NoChange, influenceCount); - this->weights.resize(eg::NoChange, 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 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 index d2b4621..063fdd6 100644 --- a/PYProjects/source/skin_plus_plus_py/skin_plus_plus_py.vcxproj +++ b/PYProjects/source/skin_plus_plus_py/skin_plus_plus_py.vcxproj @@ -47,9 +47,9 @@ DynamicLibrary - false + true v142 - true + false Unicode @@ -90,7 +90,7 @@ false .pyd - $(SolutionDir)..\..\PYProjects\skin_plus_plus\py\39 + $(SolutionDir)..\..\PYProjects\skin_plus_plus\py\39\ $(THIRD_PARTY_EIGEN);$(THIRD_PARTY_FMT)\include;$(ProjectDir)headers;$(PYTHON_39)\include;$(PYBIND11_39)\include;$(IncludePath) 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 index 8038338..ffc3f50 100644 --- a/PYProjects/source/skin_plus_plus_pymaya/skin_plus_plus_pymaya.cpp +++ b/PYProjects/source/skin_plus_plus_pymaya/skin_plus_plus_pymaya.cpp @@ -248,6 +248,63 @@ PySkinData SkinManagerMaya::getData() } + +void sortBoneIDs(BoneIDsMatrix& boneIDs, std::vector newIDOrder, const int vertexCount, const int influenceCount) +{ + BoneIDsMatrix sortedBoneIDs = BoneIDsMatrix(boneIDs); + for (size_t vertexIndex = 0; vertexIndex < vertexCount; vertexIndex++) + { + for (size_t 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 int vertexCount, const int influenceCount) +{ + const UINT arraySize = vertexCount * influenceCount; + MDoubleArray mWeights(arraySize); + for (size_t vertexIndex = 0; vertexIndex < vertexCount; vertexIndex++) + { + const int baseIndex = vertexIndex * influenceCount; + for (size_t influenceIndex = 0; influenceIndex < influenceCount; influenceIndex++) + { + const int boneID = boneIDs(vertexIndex, influenceIndex); + if (boneID == -1) + { + continue; + } + double weight = weights(vertexIndex, influenceIndex); + const UINT mWeightsIndex = baseIndex + boneID; + mWeights[mWeightsIndex] = weight; + } + } + return mWeights; +} + + bool SkinManagerMaya::setSkinWeights(PySkinData& skinData) { auto vertexCount = skinData.boneIDs.rows(); @@ -284,13 +341,13 @@ bool SkinManagerMaya::setSkinWeights(PySkinData& skinData) { throw std::exception("Error querying bones!"); } - auto skinBoneCount = skinnedBones.length(); - auto currentBoneNames = std::vector(skinBoneCount); - for (UINT boneIndex = 0; boneIndex < skinBoneCount; boneIndex++) + auto skinnedBoneCount = skinnedBones.length(); + auto currentBoneNames = std::vector(skinnedBoneCount); + for (UINT boneIndex = 0; boneIndex < skinnedBoneCount; boneIndex++) { currentBoneNames[boneIndex] = fmt::format("{}", skinnedBones[boneIndex].partialPathName().asChar()); } - if (skinBoneCount == 0) + if (skinnedBoneCount == 0) { this->addMissingBones(skinData.boneNames, skinnedBones); this->fnSkinCluster.influenceObjects(skinnedBones, &status); @@ -301,36 +358,31 @@ bool SkinManagerMaya::setSkinWeights(PySkinData& skinData) skinnedBones.clear(); this->addMissingBones(sortedBoneIDs.unfoundBoneNames, skinnedBones); this->fnSkinCluster.influenceObjects(skinnedBones, &status); + auto sortedBoneIDs = skinData.getSortedBoneIDs(currentBoneNames); } //validateBindPose(bindPoseMembersArray, skinnedBones); - auto arraySize = vertexCount * influenceCount; - MIntArray mBoneIDs(influenceCount); - MDoubleArray mWeights(arraySize); - for (UINT influenceIndex = 0; influenceIndex < influenceCount; influenceIndex++) - { - mBoneIDs[influenceIndex] = sortedBoneIDs.sortedBoneIDs[influenceIndex]; - } - // Unpack nested arrays like so: [[0, 1], [2, 3]] -> [0, 1, 2, 3] - for (UINT vertexIndex = 0; vertexIndex < vertexCount; vertexIndex++) - { - UINT arrayIndex = vertexIndex * influenceCount; - for (UINT influenceIndex = 0; influenceIndex < influenceCount; influenceIndex++) - { - arrayIndex += influenceIndex; - auto boneID = skinData.boneIDs(vertexIndex, influenceIndex); - auto vertexWeight = skinData.weights(vertexIndex, influenceIndex); - mWeights[arrayIndex] = vertexWeight; - } - } - py::print("mWeights length: ", mWeights.length()); - for (UINT i = 0; i < mWeights.length(); i++) + + MIntArray mBoneIDs(skinnedBoneCount); + auto sortedBoneSize = sortedBoneIDs.sortedBoneIDs.size(); + //if (skinnedBoneCount != sortedBoneSize) + //{ + // auto exceptionText = convertStringToChar( + // fmt::format( + // "Skinned bone count {} does not match sorted bone count {}", + // skinnedBoneCount, + // sortedBoneSize + // ) + // ); + // throw std::length_error(exceptionText); + //} + for (UINT index = 0; index < skinnedBoneCount; index++) { - py::print(mWeights[i]); - py::print(mBoneIDs[i]); - py::print("---"); + mBoneIDs[index] = index; } + sortBoneIDs(skinData.boneIDs, sortedBoneIDs.sortedBoneIDs, vertexCount, influenceCount); + MDoubleArray mWeights = getWeightsAsMDoubleArray(skinData.boneIDs, skinData.weights, vertexCount, influenceCount); status = this->fnSkinCluster.setWeights( this->dagPath, this->component, 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 index f6fa2f7..a377dcf 100644 --- a/PYProjects/source/skin_plus_plus_pymaya/skin_plus_plus_pymaya.vcxproj +++ b/PYProjects/source/skin_plus_plus_pymaya/skin_plus_plus_pymaya.vcxproj @@ -52,9 +52,9 @@ DynamicLibrary - false + true v142 - true + false Unicode x64 @@ -83,13 +83,13 @@ .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_2022 + $(SolutionDir)..\..\PYProjects\skin_plus_plus\dccs\maya\$(ProjectName)_debug_2023\ true .pyd - $(THIRD_PARTY_EIGEN);$(THIRD_PARTY_FMT)\include;$(ProjectDir);$(ProjectDir)..\skin_plus_plus_py\headers;$(ADSK_MAYA_SDK_2023)\include; - $(ADSK_MAYA_SDK_2023)\lib;C:\Program Files\Python39\libs + $(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 @@ -104,7 +104,7 @@ .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 + $(SolutionDir)..\..\PYProjects\skin_plus_plus\dccs\maya\$(ProjectName)_2023\ true @@ -132,8 +132,8 @@ true _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true - stdcpp20 - stdc17 + stdcpp14 + Default Console 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 index 6f91373..8ad3dc1 100644 --- a/PYProjects/source/skin_plus_plus_pymxs/skin_plus_plus_pymxs.vcxproj +++ b/PYProjects/source/skin_plus_plus_pymxs/skin_plus_plus_pymxs.vcxproj @@ -60,7 +60,7 @@ DynamicLibrary - false + true v142 false Unicode 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 index 367654c..8a5935c 100644 --- 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 @@ -141,6 +141,12 @@ void SkinManager::collectWeightsAndBoneIDs(UINT vertexIndex) 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)); + }*/ } } @@ -154,12 +160,34 @@ PySkinData* SkinManager::getData() 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++) { - pySkinData->boneNames[boneIndex] = convertWCharToString(iSkin->GetBoneName(boneIndex)); + auto boneName = iSkin->GetBoneName(boneIndex); + if (boneName == NULL) + { + auto bone = iSkin->GetBone(boneIndex); + boneName = bone->GetActualINode()->GetName(); + if (boneName == NULL) + { + 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) @@ -301,6 +329,7 @@ bool SkinManager::setSkinWeights(PySkinData& skinData) 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); @@ -317,10 +346,30 @@ bool SkinManager::setSkinWeights(PySkinData& skinData) weights.Resize(boneIDsCols); for (auto influenceIndex = 0; influenceIndex < boneIDsCols; influenceIndex++) { - auto sortedBoneID = sortedBoneIDs.sortedBoneIDs[influenceIndex]; - auto boneID = skinData.boneIDs(vertexIndex, sortedBoneID); - float influenceWeight = skinData.weights(vertexIndex, sortedBoneID); - bones.Append(1, &skinBones[boneID]); + 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); }