Created Model::TransformComponents class

This commit is contained in:
Anthony J. Thibault 2017-12-19 15:57:06 -08:00
parent 515d13a4c1
commit 18113d824c
9 changed files with 237 additions and 304 deletions

View file

@ -20,19 +20,35 @@ 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<glm::mat4>& clusterMatrices, const std::vector<glm::mat4>& cauterizedClusterMatrices) { #ifdef SKIN_COMP
ModelMeshPartPayload::updateClusterBuffer(clusterMatrices); void CauterizedMeshPartPayload::updateClusterBuffer(const std::vector<Model::TransformComponents>& clusterTransforms, const std::vector<Model::TransformComponents>& cauterizedClusterTransforms) {
ModelMeshPartPayload::updateClusterBuffer(clusterTransforms);
if (cauterizedClusterMatrices.size() > 1) { if (cauterizedClusterTransforms.size() > 1) {
if (!_cauterizedClusterBuffer) { if (!_cauterizedClusterBuffer) {
_cauterizedClusterBuffer = std::make_shared<gpu::Buffer>(cauterizedClusterMatrices.size() * sizeof(glm::mat4), _cauterizedClusterBuffer = std::make_shared<gpu::Buffer>(cauterizedClusterTransforms.size() * sizeof(Model::TransformComponents),
(const gpu::Byte*) cauterizedClusterMatrices.data()); (const gpu::Byte*) cauterizedClusterTransforms.data());
} else { } else {
_cauterizedClusterBuffer->setSubData(0, cauterizedClusterMatrices.size() * sizeof(glm::mat4), _cauterizedClusterBuffer->setSubData(0, cauterizedClusterTransforms.size() * sizeof(Model::TransformComponents),
(const gpu::Byte*) cauterizedClusterMatrices.data()); (const gpu::Byte*) cauterizedClusterTransforms.data());
} }
} }
} }
#else
void CauterizedMeshPartPayload::updateClusterBuffer(const std::vector<glm::mat4>& clusterTransforms, const std::vector<glm::mat4>& cauterizedClusterTransforms) {
ModelMeshPartPayload::updateClusterBuffer(clusterTransforms);
if (cauterizedClusterTransforms.size() > 1) {
if (!_cauterizedClusterBuffer) {
_cauterizedClusterBuffer = std::make_shared<gpu::Buffer>(cauterizedClusterTransforms.size() * sizeof(glm::mat4),
(const gpu::Byte*) cauterizedClusterTransforms.data());
} else {
_cauterizedClusterBuffer->setSubData(0, cauterizedClusterTransforms.size() * sizeof(glm::mat4),
(const gpu::Byte*) cauterizedClusterTransforms.data());
}
}
}
#endif
void CauterizedMeshPartPayload::updateTransformForCauterizedMesh(const Transform& renderTransform) { void CauterizedMeshPartPayload::updateTransformForCauterizedMesh(const Transform& renderTransform) {
_cauterizedTransform = renderTransform; _cauterizedTransform = renderTransform;

View file

@ -14,8 +14,11 @@
class CauterizedMeshPartPayload : public ModelMeshPartPayload { 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);
#ifdef SKIN_COMP
void updateClusterBuffer(const std::vector<glm::mat4>& clusterMatrices, const std::vector<glm::mat4>& cauterizedClusterMatrices); void updateClusterBuffer(const std::vector<Model::TransformComponents>& clusterTransforms, const std::vector<Model::TransformComponents>& cauterizedClusterTransforms);
#else
void updateClusterBuffer(const std::vector<glm::mat4>& clusterTransforms, const std::vector<glm::mat4>& cauterizedClusterTransforms);
#endif
void updateTransformForCauterizedMesh(const Transform& renderTransform); void updateTransformForCauterizedMesh(const Transform& renderTransform);

View file

@ -35,7 +35,7 @@ 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.clusterMatrices.resize(mesh.clusters.size()); state.clusterTransforms.resize(mesh.clusters.size());
_cauterizeMeshStates.append(state); _cauterizeMeshStates.append(state);
} }
} }
@ -116,47 +116,14 @@ 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);
/* AJT: TODO REMOVE */
#ifdef SKIN_MATRIX
SKIN_ASSERT(false);
auto jointMatrix = _rig.getJointTransform(cluster.jointIndex); auto jointMatrix = _rig.getJointTransform(cluster.jointIndex);
glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterMatrices[j]);
#endif
#ifdef SKIN_COMP #ifdef SKIN_COMP
// AJT: TODO: optimize
if (debug) { glm::mat4 m;
qDebug() << "AJT: _meshState[" << i << "], cluster[" << j << "]"; glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, m);
} state.clusterTransforms[j] = Model::TransformComponents(m);
#else
AnimPose jointPose = _rig.getJointPose(cluster.jointIndex); glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterTransforms[j]);
AnimPose result = jointPose * AnimPose(cluster.inverseBindMatrix);
result.rot() = glm::normalize(result.rot());
// pack scale rotation and translation into a mat4.
state.clusterMatrices[j][0].x = result.scale().x;
state.clusterMatrices[j][0].y = result.scale().y;
state.clusterMatrices[j][0].z = result.scale().z;
state.clusterMatrices[j][1].x = result.rot().x;
state.clusterMatrices[j][1].y = result.rot().y;
state.clusterMatrices[j][1].z = result.rot().z;
state.clusterMatrices[j][1].w = result.rot().w;
state.clusterMatrices[j][2].x = result.trans().x;
state.clusterMatrices[j][2].y = result.trans().y;
state.clusterMatrices[j][2].z = result.trans().z;
// AJT REMOVE
if (debug) {
glm::mat4 jointMatrix = _rig.getJointTransform(cluster.jointIndex);
glm::mat4 m;
glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, m);
qDebug() << "AJT: m =" << m;
qDebug() << "AJT: (AnimPose)m =" << AnimPose(m);
qDebug() << "AJT: result =" << result;
qDebug() << "AJT: (mat4)result =" << (glm::mat4)result;
SKIN_ASSERT(result.fuzzyEqual(AnimPose(m)));
}
#endif #endif
} }
} }
@ -177,60 +144,18 @@ 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);
#ifdef SKIN_MATRIX
SKIN_ASSERT(false);
// AJT: TODO REMOVE:
auto jointMatrix = _rig.getJointTransform(cluster.jointIndex); auto jointMatrix = _rig.getJointTransform(cluster.jointIndex);
if (_cauterizeBoneSet.find(cluster.jointIndex) != _cauterizeBoneSet.end()) { if (_cauterizeBoneSet.find(cluster.jointIndex) != _cauterizeBoneSet.end()) {
jointMatrix = cauterizeMatrix; jointMatrix = cauterizeMatrix;
} }
glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterMatrices[j]);
#endif
#ifdef SKIN_COMP #ifdef SKIN_COMP
// AJT: TODO: optimize
if (debug) { glm::mat4 m;
qDebug() << "AJT: CAUTERIZED _meshState[" << i << "], cluster[" << j << "]"; glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, m);
} state.clusterTransforms[j] = Model::TransformComponents(m);
#else
auto jointPose = _rig.getJointPose(cluster.jointIndex); glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterTransforms[j]);
/*
if (_cauterizeBoneSet.find(cluster.jointIndex) != _cauterizeBoneSet.end()) {
jointPose = cauterizePose;
}
*/
AnimPose result = jointPose * AnimPose(cluster.inverseBindMatrix);
result.rot() = glm::normalize(result.rot());
// pack scale rotation and translation into a mat4.
state.clusterMatrices[j][0].x = result.scale().x;
state.clusterMatrices[j][0].y = result.scale().y;
state.clusterMatrices[j][0].z = result.scale().z;
state.clusterMatrices[j][1].x = result.rot().x;
state.clusterMatrices[j][1].y = result.rot().y;
state.clusterMatrices[j][1].z = result.rot().z;
state.clusterMatrices[j][1].w = result.rot().w;
state.clusterMatrices[j][2].x = result.trans().x;
state.clusterMatrices[j][2].y = result.trans().y;
state.clusterMatrices[j][2].z = result.trans().z;
// AJT REMOVE
auto jointMatrix = _rig.getJointTransform(cluster.jointIndex);
/*
if (_cauterizeBoneSet.find(cluster.jointIndex) != _cauterizeBoneSet.end()) {
jointMatrix = cauterizeMatrix;
}
*/
if (debug) {
glm::mat4 m;
glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, m);
qDebug() << "AJT: m =" << m;
qDebug() << "AJT: (AnimPose)m =" << AnimPose(m);
qDebug() << "AJT: result =" << result;
qDebug() << "AJT: (mat4)result =" << (glm::mat4)result;
SKIN_ASSERT(result.fuzzyEqual(AnimPose(m)));
}
#endif #endif
} }
} }
@ -288,43 +213,31 @@ 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 clusterMatrices(self->getMeshState(meshIndex).clusterMatrices); auto clusterTransforms(self->getMeshState(meshIndex).clusterTransforms);
auto clusterMatricesCauterized(self->getCauterizeMeshState(meshIndex).clusterMatrices); auto clusterTransformsCauterized(self->getCauterizeMeshState(meshIndex).clusterTransforms);
bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(meshIndex); bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(meshIndex);
transaction.updateItem<CauterizedMeshPartPayload>(itemID, [modelTransform, clusterMatrices, clusterMatricesCauterized, invalidatePayloadShapeKey, transaction.updateItem<CauterizedMeshPartPayload>(itemID, [modelTransform, clusterTransforms, clusterTransformsCauterized, invalidatePayloadShapeKey,
isWireframe, isVisible, isLayeredInFront, isLayeredInHUD, enableCauterization](CauterizedMeshPartPayload& data) { isWireframe, isVisible, isLayeredInFront, isLayeredInHUD, enableCauterization](CauterizedMeshPartPayload& data) {
data.updateClusterBuffer(clusterMatrices, clusterMatricesCauterized); data.updateClusterBuffer(clusterTransforms, clusterTransformsCauterized);
Transform renderTransform = modelTransform; Transform renderTransform = modelTransform;
if (clusterMatrices.size() == 1) { if (clusterTransforms.size() == 1) {
#ifdef SKIN_MATRIX
SKIN_ASSERT(false);
renderTransform = modelTransform.worldTransform(Transform(clusterMatrices[0]));
#endif
#ifdef SKIN_COMP #ifdef SKIN_COMP
glm::vec3 scale(clusterMatrices[0][0]); renderTransform = modelTransform.worldTransform(Transform(clusterTransforms[0].getMatrix()));
glm::quat rot(clusterMatrices[0][1].w, clusterMatrices[0][1].x, clusterMatrices[0][1].y, clusterMatrices[0][1].z); #else
glm::vec3 trans(clusterMatrices[0][2]); renderTransform = modelTransform.worldTransform(Transform(clusterTransforms[0]));
glm::mat4 m = createMatFromScaleQuatAndPos(scale, rot, trans);
renderTransform = modelTransform.worldTransform(Transform(m));
#endif #endif
} }
data.updateTransformForSkinnedMesh(renderTransform, modelTransform); data.updateTransformForSkinnedMesh(renderTransform, modelTransform);
renderTransform = modelTransform; renderTransform = modelTransform;
if (clusterMatricesCauterized.size() == 1) { if (clusterTransformsCauterized.size() == 1) {
#ifdef SKIN_MATRIX
SKIN_ASSERT(false);
renderTransform = modelTransform.worldTransform(Transform(clusterMatricesCauterized[0]));
#endif
#ifdef SKIN_COMP #ifdef SKIN_COMP
glm::vec3 scale(clusterMatricesCauterized[0][0]); renderTransform = modelTransform.worldTransform(Transform(clusterTransformsCauterized[0].getMatrix()));
glm::quat rot(clusterMatricesCauterized[0][1].w, clusterMatricesCauterized[0][1].x, clusterMatricesCauterized[0][1].y, clusterMatricesCauterized[0][1].z); #else
glm::vec3 trans(clusterMatricesCauterized[0][2]); renderTransform = modelTransform.worldTransform(Transform(clusterTransformsCauterized[0]));
glm::mat4 m = createMatFromScaleQuatAndPos(scale, rot, trans);
renderTransform = modelTransform.worldTransform(Transform(m));
#endif #endif
} }
data.updateTransformForCauterizedMesh(renderTransform); data.updateTransformForCauterizedMesh(renderTransform);

View file

@ -326,22 +326,17 @@ 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.clusterMatrices); computeAdjustedLocalBound(state.clusterTransforms);
updateTransform(transform, offsetTransform); updateTransform(transform, offsetTransform);
Transform renderTransform = transform; Transform renderTransform = transform;
if (state.clusterMatrices.size() == 1) { if (state.clusterTransforms.size() == 1) {
#ifdef SKIN_MATRIX
SKIN_ASSERT(false);
renderTransform = transform.worldTransform(Transform(state.clusterMatrices[0]));
#endif
#ifdef SKIN_COMP #ifdef SKIN_COMP
glm::vec3 scale(state.clusterMatrices[0][0]); renderTransform = transform.worldTransform(Transform(state.clusterTransforms[0].getMatrix()));
glm::quat rot(state.clusterMatrices[0][1].w, state.clusterMatrices[0][1].x, state.clusterMatrices[0][1].y, state.clusterMatrices[0][1].z); #else
glm::vec3 trans(state.clusterMatrices[0][2]); renderTransform = transform.worldTransform(Transform(state.clusterTransforms[0]));
glm::mat4 m = createMatFromScaleQuatAndPos(scale, rot, trans);
renderTransform = transform.worldTransform(Transform(m));
#endif #endif
} }
updateTransformForSkinnedMesh(renderTransform, transform); updateTransformForSkinnedMesh(renderTransform, transform);
@ -371,20 +366,36 @@ void ModelMeshPartPayload::notifyLocationChanged() {
} }
#ifdef SKIN_COMP
void ModelMeshPartPayload::updateClusterBuffer(const std::vector<glm::mat4>& clusterMatrices) { void ModelMeshPartPayload::updateClusterBuffer(const std::vector<Model::TransformComponents>& clusterTransforms) {
// Once computed the cluster matrices, update the buffer(s) // Once computed the cluster matrices, update the buffer(s)
if (clusterMatrices.size() > 1) { if (clusterTransforms.size() > 1) {
if (!_clusterBuffer) { if (!_clusterBuffer) {
_clusterBuffer = std::make_shared<gpu::Buffer>(clusterMatrices.size() * sizeof(glm::mat4), _clusterBuffer = std::make_shared<gpu::Buffer>(clusterTransforms.size() * sizeof(Model::TransformComponents),
(const gpu::Byte*) clusterMatrices.data()); (const gpu::Byte*) clusterTransforms.data());
} }
else { else {
_clusterBuffer->setSubData(0, clusterMatrices.size() * sizeof(glm::mat4), _clusterBuffer->setSubData(0, clusterTransforms.size() * sizeof(Model::TransformComponents),
(const gpu::Byte*) clusterMatrices.data()); (const gpu::Byte*) clusterTransforms.data());
} }
} }
} }
#else
void ModelMeshPartPayload::updateClusterBuffer(const std::vector<glm::mat4>& clusterTransforms) {
// Once computed the cluster matrices, update the buffer(s)
if (clusterTransforms.size() > 1) {
if (!_clusterBuffer) {
_clusterBuffer = std::make_shared<gpu::Buffer>(clusterTransforms.size() * sizeof(glm::mat4),
(const gpu::Byte*) clusterTransforms.data());
}
else {
_clusterBuffer->setSubData(0, clusterTransforms.size() * sizeof(glm::mat4),
(const gpu::Byte*) clusterTransforms.data());
}
}
}
#endif
void ModelMeshPartPayload::updateTransformForSkinnedMesh(const Transform& renderTransform, const Transform& boundTransform) { void ModelMeshPartPayload::updateTransformForSkinnedMesh(const Transform& renderTransform, const Transform& boundTransform) {
_transform = renderTransform; _transform = renderTransform;
@ -550,23 +561,27 @@ 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) {
_adjustedLocalBound = _localBound;
if (clusterMatrices.size() > 0) {
_adjustedLocalBound.transform(clusterMatrices[0]);
for (int i = 1; i < (int)clusterMatrices.size(); ++i) {
AABox clusterBound = _localBound;
#ifdef SKIN_MATRIX
SKIN_ASSERT(false);
clusterBound.transform(clusterMatrices[i]);
#endif
#ifdef SKIN_COMP #ifdef SKIN_COMP
// AJT: FIXME: TODO: SLOW AS SHIT void ModelMeshPartPayload::computeAdjustedLocalBound(const std::vector<Model::TransformComponents>& clusterTransforms) {
glm::vec3 scale(clusterMatrices[i][0]); #else
glm::quat rot(clusterMatrices[i][1].w, clusterMatrices[i][1].x, clusterMatrices[i][1].y, clusterMatrices[i][1].z); void ModelMeshPartPayload::computeAdjustedLocalBound(const std::vector<glm::mat4>& clusterTransforms) {
glm::vec3 trans(clusterMatrices[i][2]); #endif
glm::mat4 m = createMatFromScaleQuatAndPos(scale, rot, trans); _adjustedLocalBound = _localBound;
clusterBound.transform(m); if (clusterTransforms.size() > 0) {
#ifdef SKIN_COMP
// AJT: TODO: optimize
_adjustedLocalBound.transform(clusterTransforms[0].getMatrix());
#else
_adjustedLocalBound.transform(clusterTransforms[0]);
#endif
for (int i = 1; i < (int)clusterTransforms.size(); ++i) {
AABox clusterBound = _localBound;
#ifdef SKIN_COMP
// AJT: TODO: optimize
clusterBound.transform(clusterTransforms[i].getMatrix());
#else
clusterBound.transform(clusterTransforms[i]);
#endif #endif
_adjustedLocalBound += clusterBound; _adjustedLocalBound += clusterBound;
} }

View file

@ -87,7 +87,11 @@ public:
typedef Payload::DataPointer Pointer; typedef Payload::DataPointer Pointer;
void notifyLocationChanged() override; void notifyLocationChanged() override;
void updateClusterBuffer(const std::vector<glm::mat4>& clusterMatrices); #ifdef SKIN_COMP
void updateClusterBuffer(const std::vector<Model::TransformComponents>& clusterTransforms);
#else
void updateClusterBuffer(const std::vector<glm::mat4>& clusterTransforms);
#endif
void updateTransformForSkinnedMesh(const Transform& renderTransform, const Transform& boundTransform); void updateTransformForSkinnedMesh(const Transform& renderTransform, const Transform& boundTransform);
// Render Item interface // Render Item interface
@ -104,7 +108,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;
#ifdef SKIN_COMP
void computeAdjustedLocalBound(const std::vector<Model::TransformComponents>& clusterTransforms);
#else
void computeAdjustedLocalBound(const std::vector<glm::mat4>& clusterMatrices); void computeAdjustedLocalBound(const std::vector<glm::mat4>& clusterMatrices);
#endif
gpu::BufferPointer _clusterBuffer; gpu::BufferPointer _clusterBuffer;

View file

@ -266,25 +266,20 @@ 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 clusterMatrices(self->getMeshState(meshIndex).clusterMatrices); auto clusterTransforms(self->getMeshState(meshIndex).clusterTransforms);
bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(meshIndex); bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(meshIndex);
transaction.updateItem<ModelMeshPartPayload>(itemID, [modelTransform, clusterMatrices, invalidatePayloadShapeKey, transaction.updateItem<ModelMeshPartPayload>(itemID, [modelTransform, clusterTransforms, invalidatePayloadShapeKey,
isWireframe, isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) { isWireframe, isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) {
data.updateClusterBuffer(clusterMatrices); data.updateClusterBuffer(clusterTransforms);
Transform renderTransform = modelTransform; Transform renderTransform = modelTransform;
if (clusterMatrices.size() == 1) { if (clusterTransforms.size() == 1) {
#ifdef SKIN_MATRIX
SKIN_ASSERT(false);
renderTransform = modelTransform.worldTransform(Transform(clusterMatrices[0]));
#endif
#ifdef SKIN_COMP #ifdef SKIN_COMP
glm::vec3 scale(clusterMatrices[0][0]); renderTransform = modelTransform.worldTransform(Transform(clusterTransforms[0].getMatrix()));
glm::quat rot(clusterMatrices[0][1].w, clusterMatrices[0][1].x, clusterMatrices[0][1].y, clusterMatrices[0][1].z); #else
glm::vec3 trans(clusterMatrices[0][2]); renderTransform = modelTransform.worldTransform(Transform(clusterTransforms[0]));
glm::mat4 m = createMatFromScaleQuatAndPos(scale, rot, trans);
renderTransform = modelTransform.worldTransform(Transform(m));
#endif #endif
} }
data.updateTransformForSkinnedMesh(renderTransform, modelTransform); data.updateTransformForSkinnedMesh(renderTransform, modelTransform);
@ -338,7 +333,7 @@ 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.clusterMatrices.resize(mesh.clusters.size()); state.clusterTransforms.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
@ -1169,7 +1164,7 @@ 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.clusterMatrices); part->computeAdjustedLocalBound(state.clusterTransforms);
} }
} }
@ -1187,30 +1182,14 @@ 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);
// AJT: TODO FIXME
#ifdef SKIN_MATRIX
SKIN_ASSERT(false);
auto jointMatrix = _rig.getJointTransform(cluster.jointIndex); auto jointMatrix = _rig.getJointTransform(cluster.jointIndex);
glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterMatrices[j]);
#endif
#ifdef SKIN_COMP #ifdef SKIN_COMP
AnimPose jointPose = _rig.getJointPose(cluster.jointIndex); // AJT: TODO: optimize
AnimPose result = jointPose * AnimPose(cluster.inverseBindMatrix); glm::mat4 mat;
glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, mat);
// pack scale rotation and translation into a mat4. state.clusterTransforms[j] = TransformComponents(mat);
state.clusterMatrices[j][0].x = result.scale().x; #else
state.clusterMatrices[j][0].y = result.scale().y; glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterTransforms[j]);
state.clusterMatrices[j][0].z = result.scale().z;
state.clusterMatrices[j][1].x = result.rot().x;
state.clusterMatrices[j][1].y = result.rot().y;
state.clusterMatrices[j][1].z = result.rot().z;
state.clusterMatrices[j][1].w = result.rot().w;
state.clusterMatrices[j][2].x = result.trans().x;
state.clusterMatrices[j][2].y = result.trans().y;
state.clusterMatrices[j][2].z = result.trans().z;
#endif #endif
} }
} }

View file

@ -43,8 +43,6 @@
} \ } \
} while(false) } while(false)
//#define SKIN_MATRIX
//#define SKIN_DUAL_QUAT
#define SKIN_COMP #define SKIN_COMP
class AbstractViewStateInterface; class AbstractViewStateInterface;
@ -257,9 +255,50 @@ public:
int getRenderInfoDrawCalls() const { return _renderInfoDrawCalls; } int getRenderInfoDrawCalls() const { return _renderInfoDrawCalls; }
bool getRenderInfoHasTransparent() const { return _renderInfoHasTransparent; } bool getRenderInfoHasTransparent() const { return _renderInfoHasTransparent; }
class TransformComponents {
public:
TransformComponents() {}
TransformComponents(const glm::mat4& m) {
AnimPose p(m);
_scale.x = p.scale().x;
_scale.y = p.scale().y;
_scale.z = p.scale().z;
_rot = p.rot();
_trans.x = p.trans().x;
_trans.y = p.trans().y;
_trans.z = p.trans().z;
}
TransformComponents(const glm::vec3& scale, const glm::quat& rot, const glm::vec3& trans) {
_scale.x = scale.x;
_scale.y = scale.y;
_scale.z = scale.z;
_rot = rot;
_trans.x = trans.x;
_trans.y = trans.y;
_trans.z = trans.z;
}
glm::vec3 getScale() const { return glm::vec3(_scale); }
glm::quat getRot() const { return _rot; }
glm::vec3 getTrans() const { return glm::vec3(_trans); }
glm::mat4 getMatrix() const { return createMatFromScaleQuatAndPos(getScale(), getRot(), getTrans()); };
protected:
glm::vec4 _scale { 1.0f, 1.0f, 1.0f, 0.0f };
glm::quat _rot { 1.0f, 0.0f, 0.0f, 0.0f };
glm::vec4 _trans { 0.0f, 0.0f, 0.0f, 0.0f };
glm::vec4 _padding { 0.0f, 0.0f, 0.0f, 0.0f };
};
class MeshState { class MeshState {
public: public:
std::vector<glm::mat4> clusterMatrices; #ifdef SKIN_COMP
std::vector<TransformComponents> clusterTransforms;
#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); }

View file

@ -38,60 +38,11 @@ void dqMul(vec4 lhsReal, vec4 lhsImag, vec4 rhsReal, vec4 rhsImag, out vec4 real
imagOut = quatMul(lhsReal, rhsImag) + quatMul(lhsImag, rhsReal); imagOut = quatMul(lhsReal, rhsImag) + quatMul(lhsImag, rhsReal);
} }
// dual quat blend void skinPosition(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, out vec4 skinnedPosition) {
void blendClusters_dual_quat(ivec4 skinClusterIndex, vec4 skinClusterWeight, out vec3 scaleOut, out vec4 rotOut, out vec3 posOut) { vec3 sAccum = vec3(0.0, 0.0, 0.0);
vec3 scale = vec3(0.0, 0.0, 0.0); vec4 rAccum = vec4(0.0, 0.0, 0.0, 0.0);
vec4 dqReal = vec4(0.0, 0.0, 0.0, 0.0); vec3 tAccum = vec3(0.0, 0.0, 0.0);
vec4 dqImag = vec4(0.0, 0.0, 0.0, 0.0);
for (int i = 0; i < INDICES_PER_VERTEX; i++) {
mat4 clusterMatrix = clusterMatrices[(skinClusterIndex[i])];
float clusterWeight = skinClusterWeight[i];
vec3 s = vec3(clusterMatrix[0][0], clusterMatrix[0][1], clusterMatrix[0][2]);
vec4 dqr = vec4(clusterMatrix[1][0], clusterMatrix[1][1], clusterMatrix[1][2], clusterMatrix[1][3]);
vec4 dqi = vec4(clusterMatrix[2][0], clusterMatrix[2][1], clusterMatrix[2][2], clusterMatrix[2][3]);
scale += s * clusterWeight;
dqReal += dqr * clusterWeight;
dqImag += dqi * clusterWeight;
}
scaleOut = scale;
float dqLen = length(dqReal);
dqReal *= 1.0 / dqLen;
dqImag *= 1.0 / dqLen;
rotOut = dqReal;
vec4 invReal = quatConj(dqReal);
posOut.xyz = 2.0 * quatMul(dqImag, invReal).xyz;
}
// rigid dual quat blend
void blendClusters_rigid_dual_quat(ivec4 skinClusterIndex, vec4 skinClusterWeight, out vec3 scaleOut, out vec4 rotOut, out vec3 posOut) {
float maxWeight = 0.0;
for (int i = 0; i < INDICES_PER_VERTEX; i++) {
mat4 clusterMatrix = clusterMatrices[(skinClusterIndex[i])];
float clusterWeight = skinClusterWeight[i];
vec3 s = vec3(clusterMatrix[0][0], clusterMatrix[0][1], clusterMatrix[0][2]);
vec4 dqr = vec4(clusterMatrix[1][0], clusterMatrix[1][1], clusterMatrix[1][2], clusterMatrix[1][3]);
vec4 dqi = vec4(clusterMatrix[2][0], clusterMatrix[2][1], clusterMatrix[2][2], clusterMatrix[2][3]);
if (clusterWeight > maxWeight) {
maxWeight = clusterWeight;
scaleOut = s;
rotOut = dqr;
vec4 invReal = quatConj(dqr);
posOut = 2.0 * quatMul(dqi, invReal).xyz;
}
}
}
// rigid componentwise blend
void blendClusters(ivec4 skinClusterIndex, vec4 skinClusterWeight, out vec3 scaleOut, out vec4 rotOut, out vec3 posOut) {
float maxWeight = 0.0;
for (int i = 0; i < INDICES_PER_VERTEX; i++) { for (int i = 0; i < INDICES_PER_VERTEX; i++) {
mat4 clusterMatrix = clusterMatrices[(skinClusterIndex[i])]; mat4 clusterMatrix = clusterMatrices[(skinClusterIndex[i])];
float clusterWeight = skinClusterWeight[i]; float clusterWeight = skinClusterWeight[i];
@ -100,51 +51,83 @@ void blendClusters(ivec4 skinClusterIndex, vec4 skinClusterWeight, out vec3 scal
vec4 r = vec4(clusterMatrix[1][0], clusterMatrix[1][1], clusterMatrix[1][2], clusterMatrix[1][3]); vec4 r = vec4(clusterMatrix[1][0], clusterMatrix[1][1], clusterMatrix[1][2], clusterMatrix[1][3]);
vec3 t = vec3(clusterMatrix[2][0], clusterMatrix[2][1], clusterMatrix[2][2]); vec3 t = vec3(clusterMatrix[2][0], clusterMatrix[2][1], clusterMatrix[2][2]);
if (clusterWeight > maxWeight) { if (dot(r, rAccum) < 0) {
maxWeight = clusterWeight; r = -r;
scaleOut = s;
rotOut = r;
posOut = t;
} }
sAccum += s * clusterWeight;
rAccum += r * clusterWeight;
tAccum += t * clusterWeight;
} }
}
void skinPosition(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, out vec4 skinnedPosition) { rAccum = normalize(rAccum);
vec3 scale, pos; skinnedPosition = vec4(rotateByQuat(rAccum, (vec3(inPosition) * sAccum)) + tAccum, 1);
vec4 rot;
blendClusters(skinClusterIndex, skinClusterWeight, scale, rot, pos);
skinnedPosition.xyz = rotateByQuat(rot, (vec3(inPosition) * scale)) + pos;
skinnedPosition.w = 1;
} }
void skinPositionNormal(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, vec3 inNormal, void skinPositionNormal(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, vec3 inNormal,
out vec4 skinnedPosition, out vec3 skinnedNormal) { out vec4 skinnedPosition, out vec3 skinnedNormal) {
vec3 scale, pos; vec3 sAccum = vec3(0.0, 0.0, 0.0);
vec4 rot; vec4 rAccum = vec4(0.0, 0.0, 0.0, 0.0);
blendClusters(skinClusterIndex, skinClusterWeight, scale, rot, pos); vec3 tAccum = vec3(0.0, 0.0, 0.0);
skinnedNormal.xyz = rotateByQuat(rot, inNormal * scale); for (int i = 0; i < INDICES_PER_VERTEX; i++) {
mat4 clusterMatrix = clusterMatrices[(skinClusterIndex[i])];
float clusterWeight = skinClusterWeight[i];
vec3 s = vec3(clusterMatrix[0][0], clusterMatrix[0][1], clusterMatrix[0][2]);
vec4 r = vec4(clusterMatrix[1][0], clusterMatrix[1][1], clusterMatrix[1][2], clusterMatrix[1][3]);
vec3 t = vec3(clusterMatrix[2][0], clusterMatrix[2][1], clusterMatrix[2][2]);
if (dot(r, rAccum) < 0) {
r = -r;
}
sAccum += s * clusterWeight;
rAccum += r * clusterWeight;
tAccum += t * clusterWeight;
}
rAccum = normalize(rAccum);
skinnedPosition = vec4(rotateByQuat(rAccum, (vec3(inPosition) * sAccum)) + tAccum, 1);
skinnedNormal = rotateByQuat(rAccum, inNormal);
} }
void skinPositionNormalTangent(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, vec3 inNormal, vec3 inTangent, void skinPositionNormalTangent(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, vec3 inNormal, vec3 inTangent,
out vec4 skinnedPosition, out vec3 skinnedNormal, out vec3 skinnedTangent) { out vec4 skinnedPosition, out vec3 skinnedNormal, out vec3 skinnedTangent) {
vec3 scale, pos; vec3 sAccum = vec3(0.0, 0.0, 0.0);
vec4 rot; vec4 rAccum = vec4(0.0, 0.0, 0.0, 0.0);
blendClusters(skinClusterIndex, skinClusterWeight, scale, rot, pos); vec3 tAccum = vec3(0.0, 0.0, 0.0);
skinnedPosition.xyz = rotateByQuat(rot, (vec3(inPosition) * scale)) + pos; for (int i = 0; i < INDICES_PER_VERTEX; i++) {
skinnedPosition.w = 1; mat4 clusterMatrix = clusterMatrices[(skinClusterIndex[i])];
float clusterWeight = skinClusterWeight[i];
skinnedNormal = rotateByQuat(rot, inNormal * scale); vec3 s = vec3(clusterMatrix[0][0], clusterMatrix[0][1], clusterMatrix[0][2]);
skinnedTangent = rotateByQuat(rot, inTangent * scale); vec4 r = vec4(clusterMatrix[1][0], clusterMatrix[1][1], clusterMatrix[1][2], clusterMatrix[1][3]);
vec3 t = vec3(clusterMatrix[2][0], clusterMatrix[2][1], clusterMatrix[2][2]);
if (dot(r, rAccum) < 0) {
r = -r;
}
sAccum += s * clusterWeight;
rAccum += r * clusterWeight;
tAccum += t * clusterWeight;
}
rAccum = normalize(rAccum);
skinnedPosition = vec4(rotateByQuat(rAccum, (vec3(inPosition) * sAccum)) + tAccum, 1);
skinnedNormal = rotateByQuat(rAccum, inNormal);
skinnedTangent = rotateByQuat(rAccum, inTangent);
} }
// ORIGINAL
/* /*
// ORIGINAL
void skinPosition(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, out vec4 skinnedPosition) { void skinPosition(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, out vec4 skinnedPosition) {
vec4 newPosition = vec4(0.0, 0.0, 0.0, 0.0); vec4 newPosition = vec4(0.0, 0.0, 0.0, 0.0);
@ -193,5 +176,4 @@ void skinPositionNormalTangent(ivec4 skinClusterIndex, vec4 skinClusterWeight, v
} }
*/ */
<@endif@> <@endif@>

View file

@ -50,7 +50,6 @@ void SoftAttachmentModel::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);
#ifdef SKIN_MATRIX
// 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);
glm::mat4 jointMatrix; glm::mat4 jointMatrix;
@ -59,35 +58,14 @@ void SoftAttachmentModel::updateClusterMatrices() {
} else { } else {
jointMatrix = _rig.getJointTransform(cluster.jointIndex); jointMatrix = _rig.getJointTransform(cluster.jointIndex);
} }
SKIN_ASSERT(false);
glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterMatrices[j]);
#endif
#ifdef SKIN_COMP #ifdef SKIN_COMP
// TODO: cache these look-ups as an optimization // AJT: TODO: Optimize
int jointIndexOverride = getJointIndexOverride(cluster.jointIndex); glm::mat4 m;
AnimPose jointPose; glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, m);
if (jointIndexOverride >= 0 && jointIndexOverride < _rigOverride.getJointStateCount()) { state.clusterTransforms[j] = Model::TransformComponents(m);
jointPose = _rigOverride.getJointPose(jointIndexOverride); #else
} else { glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterTransforms[j]);
jointPose = _rig.getJointPose(cluster.jointIndex);
}
AnimPose result = jointPose * AnimPose(cluster.inverseBindMatrix);
// pack scale rotation and translation into a mat4.
state.clusterMatrices[j][0].x = result.scale().x;
state.clusterMatrices[j][0].y = result.scale().y;
state.clusterMatrices[j][0].z = result.scale().z;
state.clusterMatrices[j][1].x = result.rot().x;
state.clusterMatrices[j][1].y = result.rot().y;
state.clusterMatrices[j][1].z = result.rot().z;
state.clusterMatrices[j][1].w = result.rot().w;
state.clusterMatrices[j][2].x = result.trans().x;
state.clusterMatrices[j][2].y = result.trans().y;
state.clusterMatrices[j][2].z = result.trans().z;
#endif #endif
} }
} }