|
8 | 8 | #define DEFAULT_LOG_CHANNEL "convert_model" |
9 | 9 |
|
10 | 10 | #include <momentum/character/character.h> |
| 11 | +#include <momentum/character/character_utility.h> |
11 | 12 | #include <momentum/character/inverse_parameter_transform.h> |
| 13 | +#include <momentum/character/skeleton_state.h> |
12 | 14 | #include <momentum/common/log.h> |
13 | 15 | #include <momentum/io/character_io.h> |
14 | 16 | #include <momentum/io/fbx/fbx_io.h> |
@@ -180,25 +182,55 @@ int main(int argc, char** argv) { |
180 | 182 | options->input_locator_file, character.skeleton, character.parameterTransform); |
181 | 183 | } |
182 | 184 | } |
| 185 | + |
183 | 186 | // Validate model compatibility |
184 | 187 | if (c.skeleton.joints.size() != character.skeleton.joints.size()) { |
185 | 188 | MT_LOGE("The motion is not on a compatible character"); |
186 | 189 | } else if (motionIndex >= 0) { |
187 | | - if (character.parameterTransform.numAllModelParameters() == motions.at(0).rows()) { |
188 | | - poses = std::move(motions.at(motionIndex)); |
189 | | - } else { |
190 | | - // Use inverse parameter transform to convet from joint params to model params; may lose |
191 | | - // info. |
192 | | - const auto motion = motions.at(motionIndex); |
193 | | - const size_t nFrames = motion.cols(); |
194 | | - poses.setZero(character.parameterTransform.numAllModelParameters(), nFrames); |
195 | | - InverseParameterTransform inversePt(character.parameterTransform); |
196 | | - for (size_t iFrame = 0; iFrame < nFrames; ++iFrame) { |
197 | | - poses.col(iFrame) = inversePt.apply(motion.col(iFrame)).pose.v; |
| 190 | + // To account for differences in the rest pose, we will go from joint state to joint |
| 191 | + // parameters then to model parameters |
| 192 | + const auto motion = motions.at(motionIndex); |
| 193 | + const size_t nFrames = motion.cols(); |
| 194 | + const size_t nJoints = c.skeleton.joints.size(); |
| 195 | + poses.setZero(character.parameterTransform.numAllModelParameters(), nFrames); |
| 196 | + InverseParameterTransform inversePt(character.parameterTransform); |
| 197 | + SkeletonState sourceState; |
| 198 | + TransformList transforms(nJoints); |
| 199 | + |
| 200 | + // name mapping: index_map[target_index] = source_index |
| 201 | + const auto jointNames = character.skeleton.getJointNames(); |
| 202 | + std::vector<size_t> indexMap(nJoints, kInvalidIndex); |
| 203 | + for (size_t iJoint = 0; iJoint < nJoints; ++iJoint) { |
| 204 | + indexMap[iJoint] = c.skeleton.getJointIdByName(jointNames[iJoint]); |
| 205 | + } |
| 206 | + |
| 207 | + for (size_t iFrame = 0; iFrame < nFrames; ++iFrame) { |
| 208 | + sourceState.set(motion.col(iFrame), c.skeleton); |
| 209 | + |
| 210 | + for (size_t jJoint = 0; jJoint < nJoints; ++jJoint) { |
| 211 | + if (indexMap[jJoint] == kInvalidIndex) { |
| 212 | + // no correspondence in source |
| 213 | + const Joint& joint = character.skeleton.joints[jJoint]; |
| 214 | + const Transform local(joint.translationOffset, joint.preRotation); |
| 215 | + const size_t parentIndex = character.skeleton.joints[jJoint].parent; |
| 216 | + if (parentIndex == kInvalidIndex) { |
| 217 | + transforms[jJoint] = local; |
| 218 | + } else { |
| 219 | + transforms[jJoint] = transforms[parentIndex] * local; |
| 220 | + } |
| 221 | + } else { |
| 222 | + transforms[jJoint] = sourceState.jointState[indexMap[jJoint]].transform; |
| 223 | + } |
198 | 224 | } |
| 225 | + const auto jointParams = skeletonStateToJointParameters(transforms, character.skeleton); |
| 226 | + poses.col(iFrame) = inversePt.apply(jointParams).pose.v; |
199 | 227 | } |
200 | 228 | fps = framerate; |
201 | | - offsets = character.parameterTransform.zero().v; |
| 229 | + if (offsets.size() > 0) { |
| 230 | + offsets = mapIdentityToCharacter({c.skeleton.getJointNames(), offsets}, character); |
| 231 | + } else { |
| 232 | + offsets = character.parameterTransform.zero().v; |
| 233 | + } |
202 | 234 | } |
203 | 235 |
|
204 | 236 | if (saveMarkers) { |
|
0 commit comments