Switch between dualQuats and matrix skinning based on model entity scale factor.

This commit is contained in:
Anthony J. Thibault 2018-02-22 18:35:16 -08:00
parent 86351f19a9
commit 0469eafbe4
9 changed files with 37 additions and 11 deletions

View file

@ -133,6 +133,9 @@ void RenderableModelEntityItem::doInitialModelSimulation() {
model->setRotation(getWorldOrientation()); model->setRotation(getWorldOrientation());
model->setTranslation(getWorldPosition()); model->setTranslation(getWorldPosition());
glm::vec3 scale = model->getScale();
model->setUseDualQuaternionSkinning(!isNonUniformScale(scale));
if (_needsInitialSimulation) { if (_needsInitialSimulation) {
model->simulate(0.0f); model->simulate(0.0f);
_needsInitialSimulation = false; _needsInitialSimulation = false;
@ -243,6 +246,8 @@ void RenderableModelEntityItem::updateModelBounds() {
} }
if (updateRenderItems) { if (updateRenderItems) {
glm::vec3 scale = model->getScale();
model->setUseDualQuaternionSkinning(!isNonUniformScale(scale));
model->updateRenderItems(); model->updateRenderItems();
} }
} }
@ -1500,4 +1505,4 @@ void ModelEntityRenderer::processMaterials() {
material.pop(); material.pop();
} }
} }
} }

View file

@ -407,7 +407,7 @@ void ModelMeshPartPayload::setShapeKey(bool invalidateShapeKey, bool isWireframe
if (isWireframe) { if (isWireframe) {
builder.withWireframe(); builder.withWireframe();
} }
if (_useDualQuaternionSkinning) { if (_useDualQuaternionSkinning && isSkinned) {
builder.withDualQuatSkinned(); builder.withDualQuatSkinned();
} }
@ -497,3 +497,10 @@ void ModelMeshPartPayload::computeAdjustedLocalBound(const std::vector<Model::Tr
} }
} }
} }
void ModelMeshPartPayload::setUseDualQuaternionSkinning(bool value) {
if (value != _useDualQuaternionSkinning) {
_clusterBuffer.reset();
}
_useDualQuaternionSkinning = value;
}

View file

@ -120,6 +120,8 @@ public:
// dual quaternion skinning // dual quaternion skinning
void computeAdjustedLocalBound(const std::vector<Model::TransformDualQuaternion>& clusterDualQuaternions); void computeAdjustedLocalBound(const std::vector<Model::TransformDualQuaternion>& clusterDualQuaternions);
void setUseDualQuaternionSkinning(bool value);
gpu::BufferPointer _clusterBuffer; gpu::BufferPointer _clusterBuffer;
int _meshIndex; int _meshIndex;

View file

@ -288,6 +288,7 @@ void Model::updateRenderItems() {
invalidatePayloadShapeKey, isWireframe, isVisible, invalidatePayloadShapeKey, isWireframe, isVisible,
viewTagBits, isLayeredInFront, viewTagBits, isLayeredInFront,
isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) { isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) {
data.setUseDualQuaternionSkinning(useDualQuaternionSkinning);
if (useDualQuaternionSkinning) { if (useDualQuaternionSkinning) {
data.updateClusterBuffer(meshState.clusterDualQuaternions); data.updateClusterBuffer(meshState.clusterDualQuaternions);
} else { } else {
@ -388,11 +389,8 @@ 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;
if (_useDualQuaternionSkinning) { state.clusterDualQuaternions.resize(mesh.clusters.size());
state.clusterDualQuaternions.resize(mesh.clusters.size()); state.clusterMatrices.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
@ -1248,6 +1246,10 @@ void Model::snapToRegistrationPoint() {
_snappedToRegistrationPoint = true; _snappedToRegistrationPoint = true;
} }
void Model::setUseDualQuaternionSkinning(bool value) {
_useDualQuaternionSkinning = value;
}
void Model::simulate(float deltaTime, bool fullUpdate) { void Model::simulate(float deltaTime, bool fullUpdate) {
DETAILED_PROFILE_RANGE(simulation_detail, __FUNCTION__); DETAILED_PROFILE_RANGE(simulation_detail, __FUNCTION__);
fullUpdate = updateGeometry() || fullUpdate || (_scaleToFit && !_scaledToFit) fullUpdate = updateGeometry() || fullUpdate || (_scaleToFit && !_scaledToFit)
@ -1583,11 +1585,13 @@ void Model::addMaterial(graphics::MaterialLayer material, const std::string& par
bool wireframe = isWireframe(); bool wireframe = isWireframe();
auto meshIndex = _modelMeshRenderItemShapes[shapeID].meshIndex; auto meshIndex = _modelMeshRenderItemShapes[shapeID].meshIndex;
bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex); bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex);
bool useDualQuaternionSkinning = _useDualQuaternionSkinning;
transaction.updateItem<ModelMeshPartPayload>(itemID, [material, visible, layeredInFront, layeredInHUD, viewTagBits, transaction.updateItem<ModelMeshPartPayload>(itemID, [material, visible, layeredInFront, layeredInHUD, viewTagBits,
invalidatePayloadShapeKey, wireframe](ModelMeshPartPayload& data) { invalidatePayloadShapeKey, wireframe, useDualQuaternionSkinning](ModelMeshPartPayload& data) {
data.addMaterial(material); data.addMaterial(material);
// if the material changed, we might need to update our item key or shape key // if the material changed, we might need to update our item key or shape key
data.updateKey(visible, layeredInFront || layeredInHUD, viewTagBits); data.updateKey(visible, layeredInFront || layeredInHUD, viewTagBits);
data.setUseDualQuaternionSkinning(useDualQuaternionSkinning);
data.setShapeKey(invalidatePayloadShapeKey, wireframe); data.setShapeKey(invalidatePayloadShapeKey, wireframe);
}); });
} }
@ -1608,11 +1612,13 @@ void Model::removeMaterial(graphics::MaterialPointer material, const std::string
bool wireframe = isWireframe(); bool wireframe = isWireframe();
auto meshIndex = _modelMeshRenderItemShapes[shapeID].meshIndex; auto meshIndex = _modelMeshRenderItemShapes[shapeID].meshIndex;
bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex); bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex);
bool useDualQuaternionSkinning = _useDualQuaternionSkinning;
transaction.updateItem<ModelMeshPartPayload>(itemID, [material, visible, layeredInFront, layeredInHUD, viewTagBits, transaction.updateItem<ModelMeshPartPayload>(itemID, [material, visible, layeredInFront, layeredInHUD, viewTagBits,
invalidatePayloadShapeKey, wireframe](ModelMeshPartPayload& data) { invalidatePayloadShapeKey, wireframe, useDualQuaternionSkinning](ModelMeshPartPayload& data) {
data.removeMaterial(material); data.removeMaterial(material);
// if the material changed, we might need to update our item key or shape key // if the material changed, we might need to update our item key or shape key
data.updateKey(visible, layeredInFront || layeredInHUD, viewTagBits); data.updateKey(visible, layeredInFront || layeredInHUD, viewTagBits);
data.setUseDualQuaternionSkinning(useDualQuaternionSkinning);
data.setShapeKey(invalidatePayloadShapeKey, wireframe); data.setShapeKey(invalidatePayloadShapeKey, wireframe);
}); });
} }

View file

@ -314,6 +314,7 @@ public:
void scaleToFit(); void scaleToFit();
bool getUseDualQuaternionSkinning() const { return _useDualQuaternionSkinning; } bool getUseDualQuaternionSkinning() const { return _useDualQuaternionSkinning; }
void setUseDualQuaternionSkinning(bool value);
void addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName); void addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName);
void removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName); void removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName);

View file

@ -447,7 +447,7 @@ void initDeferredPipelines(render::ShapePlumber& plumber, const render::ShapePip
Key::Builder().withMaterial().withSkinned().withTranslucent().withTangents().withSpecular().withFade(), Key::Builder().withMaterial().withSkinned().withTranslucent().withTangents().withSpecular().withFade(),
skinModelNormalMapFadeVertex, modelTranslucentNormalMapFadePixel, batchSetter, itemSetter); skinModelNormalMapFadeVertex, modelTranslucentNormalMapFadePixel, batchSetter, itemSetter);
// dual quatenion skinned // dual quaternion skinned
addPipeline( addPipeline(
Key::Builder().withMaterial().withSkinned().withDualQuatSkinned(), Key::Builder().withMaterial().withSkinned().withDualQuatSkinned(),
skinModelDualQuatVertex, modelPixel, nullptr, nullptr); skinModelDualQuatVertex, modelPixel, nullptr, nullptr);

View file

@ -55,7 +55,7 @@ protected:
inline QDebug operator<<(QDebug debug, const DualQuaternion& dq) { inline QDebug operator<<(QDebug debug, const DualQuaternion& dq) {
debug << "AnimPose, real = (" << dq._real.x << dq._real.y << dq._real.z << dq._real.w << "), dual = (" << dq._dual.x << dq._dual.y << dq._dual.z << dq._dual.w << ")"; debug << "DualQuaternion, real = (" << dq._real.x << dq._real.y << dq._real.z << dq._real.w << "), dual = (" << dq._dual.x << dq._dual.y << dq._dual.z << dq._dual.w << ")";
return debug; return debug;
} }

View file

@ -601,3 +601,6 @@ glm::vec3 randVector() {
return glm::vec3(randFloat() - 0.5f, randFloat() - 0.5f, randFloat() - 0.5f) * 2.0f; return glm::vec3(randFloat() - 0.5f, randFloat() - 0.5f, randFloat() - 0.5f) * 2.0f;
} }
bool isNonUniformScale(const glm::vec3& scale) {
return fabsf(scale.x - scale.y) > EPSILON || fabsf(scale.y - scale.z) > EPSILON;
}

View file

@ -260,6 +260,8 @@ glm::mat4 orthoInverse(const glm::mat4& m);
// Return a random vector of average length 1 // Return a random vector of average length 1
glm::vec3 randVector(); glm::vec3 randVector();
bool isNonUniformScale(const glm::vec3& scale);
// //
// Safe replacement of glm_mat4_mul() for unaligned arguments instead of __m128 // Safe replacement of glm_mat4_mul() for unaligned arguments instead of __m128
// //