Skip to content

Commit

Permalink
Merge pull request #193 from Colorbleed/skinUsePeBindMatrixAndMesh
Browse files Browse the repository at this point in the history
Use skinCluster input shape and preBindMatrix instead of initial values time
  • Loading branch information
ziriax authored Oct 25, 2022
2 parents e52b221 + f7eb42b commit 159fbd3
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 9 deletions.
3 changes: 3 additions & 0 deletions src/Arguments.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ const auto animationClipStartTime = "ast";
const auto animationClipEndTime = "aet";

const auto initialValuesTime = "ivt";
const auto skinUsePreBindMatrixAndMesh = "pbm";

const auto redrawViewport = "rvp";

Expand Down Expand Up @@ -172,6 +173,7 @@ SyntaxFactory::SyntaxFactory() {
registerFlag(ss, flag::animationClipEndTime, "animationClipEndTime", true, kTime);

registerFlag(ss, flag::initialValuesTime, "initialValuesTime", kTime);
registerFlag(ss, flag::skinUsePreBindMatrixAndMesh, "skinUsePreBindMatrixAndMesh", kNoArg);

registerFlag(ss, flag::meshPrimitiveAttributes, "meshPrimitiveAttributes", kString);
registerFlag(ss, flag::blendPrimitiveAttributes, "blendPrimitiveAttributes", kString);
Expand Down Expand Up @@ -565,6 +567,7 @@ Arguments::Arguments(const MArgList &args, const MSyntax &syntax) {

initialValuesTime = clipCount > 0 ? MTime(0, MTime::kSeconds) : MAnimControl::currentTime();
adb.optional(flag::initialValuesTime, initialValuesTime);
skinUsePreBindMatrixAndMesh = adb.isFlagSet(flag::skinUsePreBindMatrixAndMesh);

const auto fpsCount = adb.flagUsageCount(flag::animationClipFrameRate);

Expand Down
6 changes: 6 additions & 0 deletions src/Arguments.h
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,12 @@ class Arguments {
*/
MTime initialValuesTime;

/**
* Use the skinCluster's preBindMatrix values and input mesh for initial base bind
* instead of the visible output mesh from at initialValuesTime.
*/
bool skinUsePreBindMatrixAndMesh = false;

/** Redraw the viewport while exporting? True in debug builds by default,
* false otherwise (for speed) */
#ifdef _DEBUG
Expand Down
42 changes: 36 additions & 6 deletions src/MeshSkeleton.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,23 @@ MeshSkeleton::MeshSkeleton(ExportableScene &scene, const ExportableNode &node,

m_joints.reserve(jointCount);

// Gather the relevant input mesh data for the skinCluster
const auto shapeDagPath = mesh.dagPath(&status);
THROW_ON_FAILURE(status);
int inputShapeIndex = fnSkin.indexForOutputShape(mesh.object(), &status);
THROW_ON_FAILURE(status);

// Get the MPlug for input[index].inputGeometry
// Note: This is used over 'inputShapeAtIndex' so it includes any
// potential vertex tweaks after the shape but before the skinCluster
MPlug inputGeoPlug = fnSkin.findPlug("input", &status); // .input
THROW_ON_FAILURE(status);
inputGeoPlug = inputGeoPlug.elementByPhysicalIndex(inputShapeIndex, &status); // .input[0]
THROW_ON_FAILURE(status);
inputGeoPlug = inputGeoPlug.child(0, &status); // .input[0].inputGeometry
THROW_ON_FAILURE(status);
m_inputShape = inputGeoPlug.asMObject(&status);
THROW_ON_FAILURE(status);

const auto bakeScaleFactor = args.getBakeScaleFactor();
auto meshMatrix = shapeDagPath.inclusiveMatrix(&status);
Expand All @@ -60,13 +75,28 @@ MeshSkeleton::MeshSkeleton(ExportableScene &scene, const ExportableNode &node,
auto &jointDagPath =
jointDagPaths[static_cast<unsigned int>(index)];
auto *jointNode = scene.getNode(jointDagPath);
auto jointMatrix = jointDagPath.inclusiveMatrix(&status);
THROW_ON_FAILURE(status);
scaleTranslation(jointMatrix, bakeScaleFactor);

const auto inverseJointMatrix = jointMatrix.inverse();

MMatrix inverseBindMatrix = meshMatrix * inverseJointMatrix;
MMatrix inverseBindMatrix;
if (args.skinUsePreBindMatrixAndMesh) {
// Use bindPreMatrix from skinCluster
MPlug plug = fnSkin.findPlug("bindPreMatrix", true, &status);
THROW_ON_FAILURE(status);
size_t logical_index = fnSkin.indexForInfluenceObject(jointDagPath, &status);
THROW_ON_FAILURE(status);
plug = plug.elementByLogicalIndex(logical_index, &status);
THROW_ON_FAILURE(status);
MObject matrixData = plug.asMObject();
MFnMatrixData fnMatrixData(matrixData, &status);
THROW_ON_FAILURE(status);
inverseBindMatrix = fnMatrixData.matrix(&status);
THROW_ON_FAILURE(status);
} else {
// Use initial values time joint position
auto inverseJointMatrix = jointDagPath.inclusiveMatrixInverse(&status);
THROW_ON_FAILURE(status);
inverseBindMatrix = meshMatrix * inverseJointMatrix;
}
scaleTranslation(inverseBindMatrix, bakeScaleFactor);

if (inverseBindMatrix.isSingular()) {
cerr << prefix << "WARNING: Inverse bind matrix of joint '"
Expand Down
5 changes: 5 additions & 0 deletions src/MeshSkeleton.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ class MeshSkeleton {

size_t vertexJointAssignmentSetCount() const;

MObject inputShape() const {
return m_inputShape;
}

private:
DISALLOW_COPY_MOVE_ASSIGN(MeshSkeleton);

Expand All @@ -74,6 +78,7 @@ class MeshSkeleton {
std::vector<VertexJointAssignment> m_vertexJointAssignmentsVector;
VertexJointAssignmentTable m_vertexJointAssignmentsTable;
size_t m_maxVertexJointAssignmentCount;
MObject m_inputShape;

static MObject
tryExtractSkinCluster(const MFnMesh &fnMesh,
Expand Down
15 changes: 12 additions & 3 deletions src/MeshVertices.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,9 +168,18 @@ MeshVertices::MeshVertices(const MeshIndices &meshIndices, const MeshSkeleton *m

auto &semantics = meshIndices.semantics;

MFnMesh input_mesh;
if (args.skinUsePreBindMatrixAndMesh && meshSkeleton && !meshSkeleton->inputShape().isNull()) {
// Use skincluster input mesh data to retrieve pre-bind point positions and normals
input_mesh.setObject(meshSkeleton->inputShape());
} else {
// Use output mesh data at 'initialValuesTime' as bind pose point positions and normals
input_mesh.setObject(mesh.dagPath());
}

// Get points
MPointArray mPoints;
THROW_ON_FAILURE(mesh.getPoints(mPoints, MSpace::kTransform));
THROW_ON_FAILURE(input_mesh.getPoints(mPoints, MSpace::kTransform));
const int numPoints = mPoints.length();
m_positions.reserve(numPoints);

Expand All @@ -185,7 +194,7 @@ MeshVertices::MeshVertices(const MeshIndices &meshIndices, const MeshSkeleton *m

const auto positionsSpan = floats(span(m_positions));
m_table.at(Semantic::POSITION).push_back(positionsSpan);

// Get normals
auto oppositePlug = mesh.findPlug("opposite", true, &status);
THROW_ON_FAILURE(status);
Expand All @@ -198,7 +207,7 @@ MeshVertices::MeshVertices(const MeshIndices &meshIndices, const MeshSkeleton *m
const float normalSign = shouldFlipNormals ? -1.0f : 1.0f;

MFloatVectorArray mNormals;
THROW_ON_FAILURE(mesh.getNormals(mNormals, MSpace::kWorld));
THROW_ON_FAILURE(input_mesh.getNormals(mNormals, MSpace::kWorld));
const int numNormals = mNormals.length();
m_normals.reserve(numNormals);
for (int i = 0; i < numNormals; ++i) {
Expand Down

0 comments on commit 159fbd3

Please sign in to comment.