WIP check in of making the use of dq or mat dynamic per model

This commit is contained in:
Anthony J. Thibault 2018-02-12 18:44:24 -08:00
parent 3377aaceea
commit cf5452313a
8 changed files with 238 additions and 158 deletions

View file

@ -20,16 +20,32 @@ using namespace render;
CauterizedMeshPartPayload::CauterizedMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform) CauterizedMeshPartPayload::CauterizedMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform)
: ModelMeshPartPayload(model, meshIndex, partIndex, shapeIndex, transform, offsetTransform) {} : ModelMeshPartPayload(model, meshIndex, partIndex, shapeIndex, transform, offsetTransform) {}
void CauterizedMeshPartPayload::updateClusterBuffer(const std::vector<TransformType>& clusterTransforms, const std::vector<TransformType>& cauterizedClusterTransforms) { void CauterizedMeshPartPayload::updateClusterBuffer(const std::vector<glm::mat4>& clusterMatrices,
ModelMeshPartPayload::updateClusterBuffer(clusterTransforms); const std::vector<glm::mat4>& cauterizedClusterMatrices) {
ModelMeshPartPayload::updateClusterBuffer(clusterMatrices);
if (cauterizedClusterTransforms.size() > 1) { if (cauterizedClusterMatrices.size() > 1) {
if (!_cauterizedClusterBuffer) { if (!_cauterizedClusterBuffer) {
_cauterizedClusterBuffer = std::make_shared<gpu::Buffer>(cauterizedClusterTransforms.size() * sizeof(TransformType), _cauterizedClusterBuffer = std::make_shared<gpu::Buffer>(cauterizedClusterMatrices.size() * sizeof(glm::mat4),
(const gpu::Byte*) cauterizedClusterTransforms.data()); (const gpu::Byte*) cauterizedClusterMatrices.data());
} else { } else {
_cauterizedClusterBuffer->setSubData(0, cauterizedClusterTransforms.size() * sizeof(TransformType), _cauterizedClusterBuffer->setSubData(0, cauterizedClusterMatrices.size() * sizeof(glm::mat4),
(const gpu::Byte*) cauterizedClusterTransforms.data()); (const gpu::Byte*) cauterizedClusterMatrices.data());
}
}
}
void CauterizedMeshPartPayload::updateClusterBuffer(const std::vector<Model::TransformDualQuaternion>& clusterDualQuaternions,
const std::vector<Model::TransformDualQuaternion>& cauterizedClusterDualQuaternions) {
ModelMeshPartPayload::updateClusterBuffer(clusterDualQuaternions);
if (cauterizedClusterDualQuaternions.size() > 1) {
if (!_cauterizedClusterBuffer) {
_cauterizedClusterBuffer = std::make_shared<gpu::Buffer>(cauterizedClusterDualQuaternions.size() * sizeof(Model::TransformDualQuaternion),
(const gpu::Byte*) cauterizedClusterDualQuaternions.data());
} else {
_cauterizedClusterBuffer->setSubData(0, cauterizedClusterDualQuaternions.size() * sizeof(Model::TransformDualQuaternion),
(const gpu::Byte*) cauterizedClusterDualQuaternions.data());
} }
} }
} }

View file

@ -15,13 +15,13 @@ class CauterizedMeshPartPayload : public ModelMeshPartPayload {
public: public:
CauterizedMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform); CauterizedMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform);
#if defined(SKIN_DQ) // matrix palette skinning
using TransformType = Model::TransformDualQuaternion; void updateClusterBuffer(const std::vector<glm::mat4>& clusterMatrices,
#else const std::vector<glm::mat4>& cauterizedClusterMatrices);
using TransformType = glm::mat4;
#endif
void updateClusterBuffer(const std::vector<TransformType>& clusterTransforms, const std::vector<TransformType>& cauterizedClusterTransforms); // dual quaternion skinning
void updateClusterBuffer(const std::vector<Model::TransformDualQuaternion>& clusterDualQuaternions,
const std::vector<Model::TransformDualQuaternion>& cauterizedClusterQuaternions);
void updateTransformForCauterizedMesh(const Transform& renderTransform); void updateTransformForCauterizedMesh(const Transform& renderTransform);

View file

@ -35,8 +35,13 @@ bool CauterizedModel::updateGeometry() {
const FBXGeometry& fbxGeometry = getFBXGeometry(); const FBXGeometry& fbxGeometry = getFBXGeometry();
foreach (const FBXMesh& mesh, fbxGeometry.meshes) { foreach (const FBXMesh& mesh, fbxGeometry.meshes) {
Model::MeshState state; Model::MeshState state;
state.clusterTransforms.resize(mesh.clusters.size()); if (_useDualQuaternionSkinning) {
_cauterizeMeshStates.append(state); state.clusterDualQuaternions.resize(mesh.clusters.size());
_cauterizeMeshStates.append(state);
} else {
state.clusterMatrices.resize(mesh.clusters.size());
_cauterizeMeshStates.append(state);
}
} }
} }
return needsFullUpdate; return needsFullUpdate;
@ -109,33 +114,33 @@ void CauterizedModel::updateClusterMatrices() {
const FBXMesh& mesh = geometry.meshes.at(i); const FBXMesh& mesh = geometry.meshes.at(i);
for (int j = 0; j < mesh.clusters.size(); j++) { for (int j = 0; j < mesh.clusters.size(); j++) {
const FBXCluster& cluster = mesh.clusters.at(j); const FBXCluster& cluster = mesh.clusters.at(j);
#if defined(SKIN_DQ) if (_useDualQuaternionSkinning) {
auto jointPose = _rig.getJointPose(cluster.jointIndex); auto jointPose = _rig.getJointPose(cluster.jointIndex);
Transform jointTransform(jointPose.rot(), jointPose.scale(), jointPose.trans()); Transform jointTransform(jointPose.rot(), jointPose.scale(), jointPose.trans());
Transform clusterTransform; Transform clusterTransform;
Transform::mult(clusterTransform, jointTransform, cluster.inverseBindTransform); Transform::mult(clusterTransform, jointTransform, cluster.inverseBindTransform);
state.clusterTransforms[j] = Model::TransformDualQuaternion(clusterTransform); state.clusterDualQuaternions[j] = Model::TransformDualQuaternion(clusterTransform);
state.clusterTransforms[j].setCauterizationParameters(0.0f, jointPose.trans()); state.clusterDualQuaternions[j].setCauterizationParameters(0.0f, jointPose.trans());
#else } else {
auto jointMatrix = _rig.getJointTransform(cluster.jointIndex); auto jointMatrix = _rig.getJointTransform(cluster.jointIndex);
glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterTransforms[j]); glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterMatrices[j]);
#endif }
} }
} }
// as an optimization, don't build cautrizedClusterMatrices if the boneSet is empty. // as an optimization, don't build cautrizedClusterMatrices if the boneSet is empty.
if (!_cauterizeBoneSet.empty()) { if (!_cauterizeBoneSet.empty()) {
#if defined(SKIN_DQ)
AnimPose cauterizePose = _rig.getJointPose(geometry.neckJointIndex); AnimPose cauterizePose = _rig.getJointPose(geometry.neckJointIndex);
cauterizePose.scale() = glm::vec3(0.0001f, 0.0001f, 0.0001f); cauterizePose.scale() = glm::vec3(0.0001f, 0.0001f, 0.0001f);
#else
static const glm::mat4 zeroScale( static const glm::mat4 zeroScale(
glm::vec4(0.0001f, 0.0f, 0.0f, 0.0f), glm::vec4(0.0001f, 0.0f, 0.0f, 0.0f),
glm::vec4(0.0f, 0.0001f, 0.0f, 0.0f), glm::vec4(0.0f, 0.0001f, 0.0f, 0.0f),
glm::vec4(0.0f, 0.0f, 0.0001f, 0.0f), glm::vec4(0.0f, 0.0f, 0.0001f, 0.0f),
glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)); glm::vec4(0.0f, 0.0f, 0.0f, 1.0f));
auto cauterizeMatrix = _rig.getJointTransform(geometry.neckJointIndex) * zeroScale; auto cauterizeMatrix = _rig.getJointTransform(geometry.neckJointIndex) * zeroScale;
#endif
for (int i = 0; i < _cauterizeMeshStates.size(); i++) { for (int i = 0; i < _cauterizeMeshStates.size(); i++) {
Model::MeshState& state = _cauterizeMeshStates[i]; Model::MeshState& state = _cauterizeMeshStates[i];
const FBXMesh& mesh = geometry.meshes.at(i); const FBXMesh& mesh = geometry.meshes.at(i);
@ -143,19 +148,24 @@ void CauterizedModel::updateClusterMatrices() {
for (int j = 0; j < mesh.clusters.size(); j++) { for (int j = 0; j < mesh.clusters.size(); j++) {
const FBXCluster& cluster = mesh.clusters.at(j); const FBXCluster& cluster = mesh.clusters.at(j);
if (_cauterizeBoneSet.find(cluster.jointIndex) == _cauterizeBoneSet.end()) { if (_useDualQuaternionSkinning) {
// not cauterized so just copy the value from the non-cauterized version. if (_cauterizeBoneSet.find(cluster.jointIndex) == _cauterizeBoneSet.end()) {
state.clusterTransforms[j] = _meshStates[i].clusterTransforms[j]; // not cauterized so just copy the value from the non-cauterized version.
state.clusterDualQuaternions[j] = _meshStates[i].clusterDualQuaternions[j];
} else {
Transform jointTransform(cauterizePose.rot(), cauterizePose.scale(), cauterizePose.trans());
Transform clusterTransform;
Transform::mult(clusterTransform, jointTransform, cluster.inverseBindTransform);
state.clusterDualQuaternions[j] = Model::TransformDualQuaternion(clusterTransform);
state.clusterDualQuaternions[j].setCauterizationParameters(1.0f, cauterizePose.trans());
}
} else { } else {
#if defined(SKIN_DQ) if (_cauterizeBoneSet.find(cluster.jointIndex) == _cauterizeBoneSet.end()) {
Transform jointTransform(cauterizePose.rot(), cauterizePose.scale(), cauterizePose.trans()); // not cauterized so just copy the value from the non-cauterized version.
Transform clusterTransform; state.clusterMatrices[j] = _meshStates[i].clusterMatrices[j];
Transform::mult(clusterTransform, jointTransform, cluster.inverseBindTransform); } else {
state.clusterTransforms[j] = Model::TransformDualQuaternion(clusterTransform); glm_mat4u_mul(cauterizeMatrix, cluster.inverseBindMatrix, state.clusterMatrices[j]);
state.clusterTransforms[j].setCauterizationParameters(1.0f, cauterizePose.trans()); }
#else
glm_mat4u_mul(cauterizeMatrix, cluster.inverseBindMatrix, state.clusterTransforms[j]);
#endif
} }
} }
} }
@ -213,38 +223,51 @@ void CauterizedModel::updateRenderItems() {
auto itemID = self->_modelMeshRenderItemIDs[i]; auto itemID = self->_modelMeshRenderItemIDs[i];
auto meshIndex = self->_modelMeshRenderItemShapes[i].meshIndex; auto meshIndex = self->_modelMeshRenderItemShapes[i].meshIndex;
auto clusterTransforms(self->getMeshState(meshIndex).clusterTransforms);
auto clusterTransformsCauterized(self->getCauterizeMeshState(meshIndex).clusterTransforms); const auto& meshState = self->getMeshState(meshIndex);
const auto& cauterizedMeshState = self->getCauterizeMeshState(meshIndex);
bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(meshIndex); bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(meshIndex);
transaction.updateItem<CauterizedMeshPartPayload>(itemID, [modelTransform, clusterTransforms, clusterTransformsCauterized, invalidatePayloadShapeKey, transaction.updateItem<CauterizedMeshPartPayload>(itemID, [modelTransform, meshState, cauterizedMeshState, invalidatePayloadShapeKey,
isWireframe, isVisible, isLayeredInFront, isLayeredInHUD, enableCauterization](CauterizedMeshPartPayload& data) { isWireframe, isVisible, isLayeredInFront, isLayeredInHUD, enableCauterization](CauterizedMeshPartPayload& data) {
data.updateClusterBuffer(clusterTransforms, clusterTransformsCauterized); if (_useDualQuaternionSkinning) {
data.updateClusterBuffer(meshState.clusterDualQuaternions,
cauterizedMeshState.clusterDualQuaternions);
} else {
data.updateClusterBuffer(meshState.clusterMatrices,
cauterizedMeshState.clusterMatrices);
}
Transform renderTransform = modelTransform; Transform renderTransform = modelTransform;
if (clusterTransforms.size() == 1) { if (_useDualQuaternionSkinning) {
#if defined(SKIN_DQ) if (meshState.clusterDualQuaternions.size() == 1) {
Transform transform(clusterTransforms[0].getRotation(), const auto& dq = meshState.clusterDualQuaternions[0];
clusterTransforms[0].getScale(), Transform transform(dq.getRotation(),
clusterTransforms[0].getTranslation()); dq.getScale(),
renderTransform = modelTransform.worldTransform(transform); dq.getTranslation());
#else renderTransform = modelTransform.worldTransform(transform);
renderTransform = modelTransform.worldTransform(Transform(clusterTransforms[0])); }
#endif } else {
if (meshState.clusterMatrices.size() == 1) {
renderTransform = modelTransform.worldTransform(Transform(meshState.clusterMatrices[0]));
}
} }
data.updateTransformForSkinnedMesh(renderTransform, modelTransform); data.updateTransformForSkinnedMesh(renderTransform, modelTransform);
renderTransform = modelTransform; renderTransform = modelTransform;
if (clusterTransformsCauterized.size() == 1) { if (_useDualQuaternionSkinning) {
#if defined(SKIN_DQ) if (cauterizedMeshState.clusterDualQuaternions.size() == 1) {
Transform transform(clusterTransformsCauterized[0].getRotation(), const auto& dq = cauterizedMeshState.clusterDualQuaternions[0];
clusterTransformsCauterized[0].getScale(), Transform transform(dq.getRotation(),
clusterTransformsCauterized[0].getTranslation()); dq.getScale(),
renderTransform = modelTransform.worldTransform(Transform(transform)); dq.getTranslation());
#else renderTransform = modelTransform.worldTransform(Transform(transform));
renderTransform = modelTransform.worldTransform(Transform(clusterTransformsCauterized[0])); }
#endif } else {
if (cauterizedMeshState.clusterMatrices.size() == 1) {
renderTransform = modelTransform.worldTransform(Transform(cauterizedMeshState.clusterMatrices[0]));
}
} }
data.updateTransformForCauterizedMesh(renderTransform); data.updateTransformForCauterizedMesh(renderTransform);

View file

@ -340,20 +340,27 @@ ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, in
const Model::MeshState& state = model->getMeshState(_meshIndex); const Model::MeshState& state = model->getMeshState(_meshIndex);
updateMeshPart(modelMesh, partIndex); updateMeshPart(modelMesh, partIndex);
computeAdjustedLocalBound(state.clusterTransforms);
if (_useDualQuaternionSkinning) {
computeAdjustedLocalBound(state.clusterDualQuaternions);
} else {
computeAdjustedLocalBound(state.clusterMatrices);
}
updateTransform(transform, offsetTransform); updateTransform(transform, offsetTransform);
Transform renderTransform = transform; Transform renderTransform = transform;
if (state.clusterTransforms.size() == 1) { if (_useDualQuaternionSkinning) {
#if defined(SKIN_DQ) if (state.clusterDualQuaternions.size() == 1) {
Transform transform(state.clusterTransforms[0].getRotation(), const auto& dq = state.clusterDualQuaternions[0];
state.clusterTransforms[0].getScale(), Transform transform(dq.getRotation(),
state.clusterTransforms[0].getTranslation()); dq.getScale(),
renderTransform = transform.worldTransform(Transform(transform)); dq.getTranslation());
#else renderTransform = transform.worldTransform(Transform(transform));
renderTransform = transform.worldTransform(Transform(state.clusterTransforms[0])); }
#endif } else {
if (state.clusterMatrices.size() == 1) {
renderTransform = transform.worldTransform(Transform(state.clusterMatrices[0]));
}
} }
updateTransformForSkinnedMesh(renderTransform, transform); updateTransformForSkinnedMesh(renderTransform, transform);
@ -383,16 +390,30 @@ void ModelMeshPartPayload::notifyLocationChanged() {
} }
void ModelMeshPartPayload::updateClusterBuffer(const std::vector<TransformType>& clusterTransforms) { void ModelMeshPartPayload::updateClusterBuffer(const std::vector<glm::mat4>& clusterMatrices) {
// Once computed the cluster matrices, update the buffer(s) // Once computed the cluster matrices, update the buffer(s)
if (clusterTransforms.size() > 1) { if (clusterMatrices.size() > 1) {
if (!_clusterBuffer) { if (!_clusterBuffer) {
_clusterBuffer = std::make_shared<gpu::Buffer>(clusterTransforms.size() * sizeof(TransformType), _clusterBuffer = std::make_shared<gpu::Buffer>(clusterMatrices.size() * sizeof(glm::mat4),
(const gpu::Byte*) clusterTransforms.data()); (const gpu::Byte*) clusterMatrices.data());
} }
else { else {
_clusterBuffer->setSubData(0, clusterTransforms.size() * sizeof(TransformType), _clusterBuffer->setSubData(0, clusterMatrices.size() * sizeof(glm::mat4),
(const gpu::Byte*) clusterTransforms.data()); (const gpu::Byte*) clusterMatrices.data());
}
}
}
void ModelMeshPartPayload::updateClusterBuffer(const std::vector<Model::TransformDualQuaternion>& clusterDualQuaternions) {
// Once computed the cluster matrices, update the buffer(s)
if (clusterDualQuaternions.size() > 1) {
if (!_clusterBuffer) {
_clusterBuffer = std::make_shared<gpu::Buffer>(clusterDualQuaternions.size() * sizeof(Model::TransformDualQuaternion),
(const gpu::Byte*) clusterDualQuaternions.data());
}
else {
_clusterBuffer->setSubData(0, clusterDualQuaternions.size() * sizeof(Model::TransformDualQuaternion),
(const gpu::Byte*) clusterDualQuaternions.data());
} }
} }
} }
@ -550,29 +571,33 @@ void ModelMeshPartPayload::render(RenderArgs* args) {
args->_details._trianglesRendered += _drawPart._numIndices / INDICES_PER_TRIANGLE; args->_details._trianglesRendered += _drawPart._numIndices / INDICES_PER_TRIANGLE;
} }
void ModelMeshPartPayload::computeAdjustedLocalBound(const std::vector<glm::mat4>& clusterMatrices) {
void ModelMeshPartPayload::computeAdjustedLocalBound(const std::vector<TransformType>& clusterTransforms) {
_adjustedLocalBound = _localBound; _adjustedLocalBound = _localBound;
if (clusterTransforms.size() > 0) { if (clusterMatrices.size() > 0) {
#if defined(SKIN_DQ) _adjustedLocalBound.transform(clusterMatrices[0]);
Transform rootTransform(clusterTransforms[0].getRotation(),
clusterTransforms[0].getScale(),
clusterTransforms[0].getTranslation());
_adjustedLocalBound.transform(rootTransform);
#else
_adjustedLocalBound.transform(clusterTransforms[0]);
#endif
for (int i = 1; i < (int)clusterTransforms.size(); ++i) { for (int i = 1; i < (int)clusterMatrices.size(); ++i) {
AABox clusterBound = _localBound; AABox clusterBound = _localBound;
#if defined(SKIN_DQ) clusterBound.transform(clusterMatrices[i]);
Transform transform(clusterTransforms[i].getRotation(), _adjustedLocalBound += clusterBound;
clusterTransforms[i].getScale(), }
clusterTransforms[i].getTranslation()); }
clusterBound.transform(transform); }
#else
clusterBound.transform(clusterTransforms[i]); void ModelMeshPartPayload::computeAdjustedLocalBound(const std::vector<Model::TransformDualQuaternion>& clusterDualQuaternions) {
#endif _adjustedLocalBound = _localBound;
if (clusterDualQuaternions.size() > 0) {
Transform rootTransform(clusterDualQuaternions[0].getRotation(),
clusterDualQuaternions[0].getScale(),
clusterDualQuaternions[0].getTranslation());
_adjustedLocalBound.transform(rootTransform);
for (int i = 1; i < (int)clusterDualQuaternions.size(); ++i) {
AABox clusterBound = _localBound;
Transform transform(clusterDualQuaternions[i].getRotation(),
clusterDualQuaternions[i].getScale(),
clusterDualQuaternions[i].getTranslation());
clusterBound.transform(transform);
_adjustedLocalBound += clusterBound; _adjustedLocalBound += clusterBound;
} }
} }

View file

@ -93,14 +93,14 @@ public:
void notifyLocationChanged() override; void notifyLocationChanged() override;
#if defined(SKIN_DQ)
using TransformType = Model::TransformDualQuaternion;
#else
using TransformType = glm::mat4;
#endif
void updateKey(bool isVisible, bool isLayered, uint8_t tagBits) override; void updateKey(bool isVisible, bool isLayered, uint8_t tagBits) override;
void updateClusterBuffer(const std::vector<TransformType>& clusterTransforms);
// matrix palette skinning
void updateClusterBuffer(const std::vector<glm::mat4>& clusterMatrices);
// dual quaternion skinning
void updateClusterBuffer(const std::vector<Model::TransformDualQuaternion>& clusterDualQuaternions);
void updateTransformForSkinnedMesh(const Transform& renderTransform, const Transform& boundTransform); void updateTransformForSkinnedMesh(const Transform& renderTransform, const Transform& boundTransform);
// Render Item interface // Render Item interface
@ -115,7 +115,11 @@ public:
void bindMesh(gpu::Batch& batch) override; void bindMesh(gpu::Batch& batch) override;
void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const override; void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const override;
void computeAdjustedLocalBound(const std::vector<TransformType>& clusterTransforms); // matrix palette skinning
void computeAdjustedLocalBound(const std::vector<glm::mat4>& clusterMatrices);
// dual quaternion skinning
void computeAdjustedLocalBound(const std::vector<Model::TransformDualQuaternion>& clusterDualQuaternions);
gpu::BufferPointer _clusterBuffer; gpu::BufferPointer _clusterBuffer;

View file

@ -277,26 +277,35 @@ void Model::updateRenderItems() {
auto itemID = self->_modelMeshRenderItemIDs[i]; auto itemID = self->_modelMeshRenderItemIDs[i];
auto meshIndex = self->_modelMeshRenderItemShapes[i].meshIndex; auto meshIndex = self->_modelMeshRenderItemShapes[i].meshIndex;
auto clusterTransforms(self->getMeshState(meshIndex).clusterTransforms);
const auto& meshState = self->getMeshState(meshIndex);
bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(meshIndex); bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(meshIndex);
transaction.updateItem<ModelMeshPartPayload>(itemID, [modelTransform, clusterTransforms, transaction.updateItem<ModelMeshPartPayload>(itemID, [modelTransform, meshState,
invalidatePayloadShapeKey, isWireframe, isVisible, invalidatePayloadShapeKey, isWireframe, isVisible,
viewTagBits, isLayeredInFront, viewTagBits, isLayeredInFront,
isLayeredInHUD](ModelMeshPartPayload& data) { isLayeredInHUD](ModelMeshPartPayload& data) {
data.updateClusterBuffer(clusterTransforms); if (_useDualQuaternions) {
data.updateClusterBuffer(meshState.clusterDualQuaternions);
} else {
data.updateClusterBuffer(meshState.clusterMatrices);
}
Transform renderTransform = modelTransform; Transform renderTransform = modelTransform;
if (clusterTransforms.size() == 1) {
#if defined(SKIN_DQ) if (_useDualQuaternions) {
Transform transform(clusterTransforms[0].getRotation(), if (meshState.clusterDualQuaternions.size() == 1) {
clusterTransforms[0].getScale(), const auto& dq = meshState.clusterDualQuaternions[0];
clusterTransforms[0].getTranslation()); Transform transform(dq.getRotation(),
renderTransform = modelTransform.worldTransform(Transform(transform)); dq.getScale(),
#else dq.getTranslation());
renderTransform = modelTransform.worldTransform(Transform(clusterTransforms[0])); renderTransform = modelTransform.worldTransform(Transform(transform));
#endif }
} else {
if (meshState.clusterMatrices.size() == 1) {
renderTransform = modelTransform.worldTransform(Transform(meshState.clusterMatrices[0]));
}
} }
data.updateTransformForSkinnedMesh(renderTransform, modelTransform); data.updateTransformForSkinnedMesh(renderTransform, modelTransform);
@ -377,7 +386,11 @@ bool Model::updateGeometry() {
const FBXGeometry& fbxGeometry = getFBXGeometry(); const FBXGeometry& fbxGeometry = getFBXGeometry();
foreach (const FBXMesh& mesh, fbxGeometry.meshes) { foreach (const FBXMesh& mesh, fbxGeometry.meshes) {
MeshState state; MeshState state;
state.clusterTransforms.resize(mesh.clusters.size()); if (_useDualQuaternions) {
state.clusterDualQuaternions.resize(mesh.clusters.size());
} else {
state.clusterMatrices.resize(mesh.clusters.size());
}
_meshStates.push_back(state); _meshStates.push_back(state);
// Note: we add empty buffers for meshes that lack blendshapes so we can access the buffers by index // Note: we add empty buffers for meshes that lack blendshapes so we can access the buffers by index
@ -1262,7 +1275,11 @@ void Model::updateRig(float deltaTime, glm::mat4 parentTransform) {
void Model::computeMeshPartLocalBounds() { void Model::computeMeshPartLocalBounds() {
for (auto& part : _modelMeshRenderItems) { for (auto& part : _modelMeshRenderItems) {
const Model::MeshState& state = _meshStates.at(part->_meshIndex); const Model::MeshState& state = _meshStates.at(part->_meshIndex);
part->computeAdjustedLocalBound(state.clusterTransforms); if (_useDualQuaternions) {
part->computeAdjustedLocalBound(state.clusterDualQuaternions);
} else {
part->computeAdjustedLocalBound(state.clusterMatrices);
}
} }
} }
@ -1281,16 +1298,16 @@ void Model::updateClusterMatrices() {
const FBXMesh& mesh = geometry.meshes.at(i); const FBXMesh& mesh = geometry.meshes.at(i);
for (int j = 0; j < mesh.clusters.size(); j++) { for (int j = 0; j < mesh.clusters.size(); j++) {
const FBXCluster& cluster = mesh.clusters.at(j); const FBXCluster& cluster = mesh.clusters.at(j);
#if defined(SKIN_DQ) if (_useDualQuaternionSkinning) {
auto jointPose = _rig.getJointPose(cluster.jointIndex); auto jointPose = _rig.getJointPose(cluster.jointIndex);
Transform jointTransform(jointPose.rot(), jointPose.scale(), jointPose.trans()); Transform jointTransform(jointPose.rot(), jointPose.scale(), jointPose.trans());
Transform clusterTransform; Transform clusterTransform;
Transform::mult(clusterTransform, jointTransform, cluster.inverseBindTransform); Transform::mult(clusterTransform, jointTransform, cluster.inverseBindTransform);
state.clusterTransforms[j] = Model::TransformDualQuaternion(clusterTransform); state.clusterDualQuaternions[j] = Model::TransformDualQuaternion(clusterTransform);
#else } else {
auto jointMatrix = _rig.getJointTransform(cluster.jointIndex); auto jointMatrix = _rig.getJointTransform(cluster.jointIndex);
glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterTransforms[j]); glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterMatrices[j]);
#endif }
} }
} }

View file

@ -254,8 +254,6 @@ public:
int getRenderInfoDrawCalls() const { return _renderInfoDrawCalls; } int getRenderInfoDrawCalls() const { return _renderInfoDrawCalls; }
bool getRenderInfoHasTransparent() const { return _renderInfoHasTransparent; } bool getRenderInfoHasTransparent() const { return _renderInfoHasTransparent; }
#if defined(SKIN_DQ)
class TransformDualQuaternion { class TransformDualQuaternion {
public: public:
TransformDualQuaternion() {} TransformDualQuaternion() {}
@ -293,15 +291,11 @@ public:
DualQuaternion _dq; DualQuaternion _dq;
glm::vec4 _cauterizedPosition { 0.0f, 0.0f, 0.0f, 1.0f }; glm::vec4 _cauterizedPosition { 0.0f, 0.0f, 0.0f, 1.0f };
}; };
#endif
class MeshState { class MeshState {
public: public:
#if defined(SKIN_DQ) std::vector<TransformDualQuaternion> clusterDualQuaternions;
std::vector<TransformDualQuaternion> clusterTransforms; std::vector<glm::mat4> clusterMatrices;
#else
std::vector<glm::mat4> clusterTransforms;
#endif
}; };
const MeshState& getMeshState(int index) { return _meshStates.at(index); } const MeshState& getMeshState(int index) { return _meshStates.at(index); }
@ -420,6 +414,7 @@ protected:
virtual void createCollisionRenderItemSet(); virtual void createCollisionRenderItemSet();
bool _isWireframe; bool _isWireframe;
bool _useDualQuaternionSkinning { false };
// debug rendering support // debug rendering support
int _debugMeshBoxesID = GeometryCache::UNKNOWN_ID; int _debugMeshBoxesID = GeometryCache::UNKNOWN_ID;

View file

@ -52,27 +52,27 @@ void SoftAttachmentModel::updateClusterMatrices() {
// TODO: cache these look-ups as an optimization // TODO: cache these look-ups as an optimization
int jointIndexOverride = getJointIndexOverride(cluster.jointIndex); int jointIndexOverride = getJointIndexOverride(cluster.jointIndex);
#if defined(SKIN_DQ) if (_useDualQuaternionSkinning) {
glm::mat4 jointMatrix; glm::mat4 jointMatrix;
if (jointIndexOverride >= 0 && jointIndexOverride < _rigOverride.getJointStateCount()) { if (jointIndexOverride >= 0 && jointIndexOverride < _rigOverride.getJointStateCount()) {
jointMatrix = _rigOverride.getJointTransform(jointIndexOverride); jointMatrix = _rigOverride.getJointTransform(jointIndexOverride);
} else { } else {
jointMatrix = _rig.getJointTransform(cluster.jointIndex); jointMatrix = _rig.getJointTransform(cluster.jointIndex);
} }
glm::mat4 m; glm::mat4 m;
glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, m); glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, m);
state.clusterTransforms[j] = Model::TransformDualQuaternion(m); state.clusterDualQuaternions[j] = Model::TransformDualQuaternion(m);
#else
glm::mat4 jointMatrix;
if (jointIndexOverride >= 0 && jointIndexOverride < _rigOverride.getJointStateCount()) {
jointMatrix = _rigOverride.getJointTransform(jointIndexOverride);
} else { } else {
jointMatrix = _rig.getJointTransform(cluster.jointIndex); glm::mat4 jointMatrix;
} if (jointIndexOverride >= 0 && jointIndexOverride < _rigOverride.getJointStateCount()) {
jointMatrix = _rigOverride.getJointTransform(jointIndexOverride);
} else {
jointMatrix = _rig.getJointTransform(cluster.jointIndex);
}
glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterTransforms[j]); glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterMatrices[j]);
#endif }
} }
} }