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

View file

@ -407,7 +407,7 @@ void ModelMeshPartPayload::setShapeKey(bool invalidateShapeKey, bool isWireframe
if (isWireframe) {
builder.withWireframe();
}
if (_useDualQuaternionSkinning) {
if (_useDualQuaternionSkinning && isSkinned) {
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
void computeAdjustedLocalBound(const std::vector<Model::TransformDualQuaternion>& clusterDualQuaternions);
void setUseDualQuaternionSkinning(bool value);
gpu::BufferPointer _clusterBuffer;
int _meshIndex;

View file

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

View file

@ -314,6 +314,7 @@ public:
void scaleToFit();
bool getUseDualQuaternionSkinning() const { return _useDualQuaternionSkinning; }
void setUseDualQuaternionSkinning(bool value);
void addMaterial(graphics::MaterialLayer 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(),
skinModelNormalMapFadeVertex, modelTranslucentNormalMapFadePixel, batchSetter, itemSetter);
// dual quatenion skinned
// dual quaternion skinned
addPipeline(
Key::Builder().withMaterial().withSkinned().withDualQuatSkinned(),
skinModelDualQuatVertex, modelPixel, nullptr, nullptr);

View file

@ -55,7 +55,7 @@ protected:
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;
}

View file

@ -601,3 +601,6 @@ glm::vec3 randVector() {
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
glm::vec3 randVector();
bool isNonUniformScale(const glm::vec3& scale);
//
// Safe replacement of glm_mat4_mul() for unaligned arguments instead of __m128
//