mirror of
https://github.com/lubosz/overte.git
synced 2025-08-07 18:01:15 +02:00
WIP check in of making the use of dq or mat dynamic per model
This commit is contained in:
parent
3377aaceea
commit
cf5452313a
8 changed files with 238 additions and 158 deletions
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue