From 3dd8fd838b7a81b2b6ff0b0c892006dde802c176 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 18 Jan 2017 10:34:41 -0800 Subject: [PATCH] move cauterization out of Model class --- .../src/avatar/CauterizedMeshPartPayload.cpp | 72 ++++++ .../src/avatar/CauterizedMeshPartPayload.h | 29 +++ interface/src/avatar/CauterizedModel.cpp | 236 ++++++++++++++++++ interface/src/avatar/CauterizedModel.h | 49 ++++ interface/src/avatar/SkeletonModel.cpp | 8 +- interface/src/avatar/SkeletonModel.h | 13 +- interface/src/avatar/SoftAttachmentModel.cpp | 3 +- interface/src/avatar/SoftAttachmentModel.h | 9 +- .../render-utils/src/MeshPartPayload.cpp | 41 +-- libraries/render-utils/src/MeshPartPayload.h | 8 +- libraries/render-utils/src/Model.cpp | 37 +-- libraries/render-utils/src/Model.h | 40 ++- 12 files changed, 430 insertions(+), 115 deletions(-) create mode 100644 interface/src/avatar/CauterizedMeshPartPayload.cpp create mode 100644 interface/src/avatar/CauterizedMeshPartPayload.h create mode 100644 interface/src/avatar/CauterizedModel.cpp create mode 100644 interface/src/avatar/CauterizedModel.h diff --git a/interface/src/avatar/CauterizedMeshPartPayload.cpp b/interface/src/avatar/CauterizedMeshPartPayload.cpp new file mode 100644 index 0000000000..e073b2cedf --- /dev/null +++ b/interface/src/avatar/CauterizedMeshPartPayload.cpp @@ -0,0 +1,72 @@ +// +// MeshPartPayload.cpp +// interface/src/renderer +// +// Created by Sam Gateau on 10/3/15. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "CauterizedMeshPartPayload.h" + +#include + +#include "SkeletonModel.h" +//#include "EntityItem.h" + +using namespace render; + +CauterizedMeshPartPayload::CauterizedMeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform) + : ModelMeshPartPayload(model, meshIndex, partIndex, shapeIndex, transform, offsetTransform) {} + +void CauterizedMeshPartPayload::updateTransformForSkinnedCauterizedMesh(const Transform& transform, + const QVector& clusterMatrices, + const QVector& cauterizedClusterMatrices) { + _transform = transform; + _cauterizedTransform = transform; + + if (clusterMatrices.size() > 0) { + _worldBound = AABox(); + for (auto& clusterMatrix : clusterMatrices) { + AABox clusterBound = _localBound; + clusterBound.transform(clusterMatrix); + _worldBound += clusterBound; + } + + _worldBound.transform(transform); + if (clusterMatrices.size() == 1) { + _transform = _transform.worldTransform(Transform(clusterMatrices[0])); + if (cauterizedClusterMatrices.size() != 0) { + _cauterizedTransform = _cauterizedTransform.worldTransform(Transform(cauterizedClusterMatrices[0])); + } else { + _cauterizedTransform = _transform; + } + } + } +} + +void CauterizedMeshPartPayload::bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const { + // Still relying on the raw data from the model + const Model::MeshState& state = _model->getMeshState(_meshIndex); + SkeletonModel* skeleton = static_cast(_model); + bool canCauterize = (renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE); + + if (state.clusterBuffer) { + if (canCauterize && skeleton->getCauterizeBones()) { + const Model::MeshState& cState = skeleton->getCauterizeMeshState(_meshIndex); + batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::SKINNING, cState.clusterBuffer); + } else { + batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::SKINNING, state.clusterBuffer); + } + batch.setModelTransform(_transform); + } else { + if (canCauterize && skeleton->getCauterizeBones()) { + batch.setModelTransform(_cauterizedTransform); + } else { + batch.setModelTransform(_transform); + } + } +} + diff --git a/interface/src/avatar/CauterizedMeshPartPayload.h b/interface/src/avatar/CauterizedMeshPartPayload.h new file mode 100644 index 0000000000..f4319ead6f --- /dev/null +++ b/interface/src/avatar/CauterizedMeshPartPayload.h @@ -0,0 +1,29 @@ +// +// CauterizedModelMeshPartPayload.h +// interface/src/avatar +// +// Created by AndrewMeadows 2017.01.17 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_CauterizedMeshPartPayload_h +#define hifi_CauterizedMeshPartPayload_h + +#include + +class CauterizedMeshPartPayload : public ModelMeshPartPayload { +public: + CauterizedMeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform); + void updateTransformForSkinnedCauterizedMesh(const Transform& transform, + const QVector& clusterMatrices, + const QVector& cauterizedClusterMatrices); + + void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const override; +private: + Transform _cauterizedTransform; +}; + +#endif // hifi_CauterizedMeshPartPayload_h diff --git a/interface/src/avatar/CauterizedModel.cpp b/interface/src/avatar/CauterizedModel.cpp new file mode 100644 index 0000000000..d58d392bb0 --- /dev/null +++ b/interface/src/avatar/CauterizedModel.cpp @@ -0,0 +1,236 @@ +// +// CauterizedModel.cpp +// interface/src/avatar +// +// Created by Andrew Meadows 2017.01.17 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +//#include +//#include + +#include "CauterizedModel.h" + +#include +#include +#include + +#include "CauterizedMeshPartPayload.h" + + +CauterizedModel::CauterizedModel(RigPointer rig, QObject* parent) : Model(rig, parent) { +} + +CauterizedModel::~CauterizedModel() { +} + +void CauterizedModel::deleteGeometry() { + Model::deleteGeometry(); + _cauterizeMeshStates.clear(); +} + +// Called within Model::simulate call, below. +void CauterizedModel::updateRig(float deltaTime, glm::mat4 parentTransform) { + Model::updateRig(deltaTime, parentTransform); + _needsUpdateClusterMatrices = true; +} + +void CauterizedModel::createVisibleRenderItemSet() { + // Temporary HACK: use base class method for now + Model::createVisibleRenderItemSet(); +} + +void CauterizedModel::createCollisionRenderItemSet() { + // Temporary HACK: use base class method for now + Model::createCollisionRenderItemSet(); +} + +bool CauterizedModel::updateGeometry() { + bool returnValue = Model::updateGeometry(); + if (_rig->jointStatesEmpty() && getFBXGeometry().joints.size() > 0) { + const FBXGeometry& fbxGeometry = getFBXGeometry(); + foreach (const FBXMesh& mesh, fbxGeometry.meshes) { + Model::MeshState state; + state.clusterMatrices.resize(mesh.clusters.size()); + _cauterizeMeshStates.append(state); + } + } + return returnValue; +} + +void CauterizedModel::updateClusterMatrices() { + PerformanceTimer perfTimer("CauterizedModel::updateClusterMatrices"); + + if (!_needsUpdateClusterMatrices || !isLoaded()) { + return; + } + _needsUpdateClusterMatrices = false; + const FBXGeometry& geometry = getFBXGeometry(); + + for (int i = 0; i < _meshStates.size(); i++) { + Model::MeshState& state = _meshStates[i]; + const FBXMesh& mesh = geometry.meshes.at(i); + for (int j = 0; j < mesh.clusters.size(); j++) { + const FBXCluster& cluster = mesh.clusters.at(j); + auto jointMatrix = _rig->getJointTransform(cluster.jointIndex); +#if GLM_ARCH & GLM_ARCH_SSE2 + glm::mat4 out, inverseBindMatrix = cluster.inverseBindMatrix; + glm_mat4_mul((glm_vec4*)&jointMatrix, (glm_vec4*)&inverseBindMatrix, (glm_vec4*)&out); + state.clusterMatrices[j] = out; +#else + state.clusterMatrices[j] = jointMatrix * cluster.inverseBindMatrix; +#endif + } + + // Once computed the cluster matrices, update the buffer(s) + if (mesh.clusters.size() > 1) { + if (!state.clusterBuffer) { + state.clusterBuffer = std::make_shared(state.clusterMatrices.size() * sizeof(glm::mat4), + (const gpu::Byte*) state.clusterMatrices.constData()); + } else { + state.clusterBuffer->setSubData(0, state.clusterMatrices.size() * sizeof(glm::mat4), + (const gpu::Byte*) state.clusterMatrices.constData()); + } + } + } + + // as an optimization, don't build cautrizedClusterMatrices if the boneSet is empty. + if (!_cauterizeBoneSet.empty()) { + static const glm::mat4 zeroScale( + glm::vec4(0.0f, 0.0f, 0.0f, 0.0f), + glm::vec4(0.0f, 0.0f, 0.0f, 0.0f), + glm::vec4(0.0f, 0.0f, 0.0f, 0.0f), + glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)); + auto cauterizeMatrix = _rig->getJointTransform(geometry.neckJointIndex) * zeroScale; + + for (int i = 0; i < _cauterizeMeshStates.size(); i++) { + Model::MeshState& state = _cauterizeMeshStates[i]; + const FBXMesh& mesh = geometry.meshes.at(i); + for (int j = 0; j < mesh.clusters.size(); j++) { + const FBXCluster& cluster = mesh.clusters.at(j); + auto jointMatrix = _rig->getJointTransform(cluster.jointIndex); + if (_cauterizeBoneSet.find(cluster.jointIndex) != _cauterizeBoneSet.end()) { + jointMatrix = cauterizeMatrix; + } +#if GLM_ARCH & GLM_ARCH_SSE2 + glm::mat4 out, inverseBindMatrix = cluster.inverseBindMatrix; + glm_mat4_mul((glm_vec4*)&jointMatrix, (glm_vec4*)&inverseBindMatrix, (glm_vec4*)&out); + state.clusterMatrices[j] = out; +#else + state.clusterMatrices[j] = jointMatrix * cluster.inverseBindMatrix; +#endif + } + + if (!_cauterizeBoneSet.empty() && (state.clusterMatrices.size() > 1)) { + if (!state.clusterBuffer) { + state.clusterBuffer = + std::make_shared(state.clusterMatrices.size() * sizeof(glm::mat4), + (const gpu::Byte*) state.clusterMatrices.constData()); + } else { + state.clusterBuffer->setSubData(0, state.clusterMatrices.size() * sizeof(glm::mat4), + (const gpu::Byte*) state.clusterMatrices.constData()); + } + } + } + } + + // post the blender if we're not currently waiting for one to finish + if (geometry.hasBlendedMeshes() && _blendshapeCoefficients != _blendedBlendshapeCoefficients) { + _blendedBlendshapeCoefficients = _blendshapeCoefficients; + DependencyManager::get()->noteRequiresBlend(getThisPointer()); + } +} + +void CauterizedModel::updateRenderItems() { + // Temporary HACK: use base class method for now + Model::updateRenderItems(); +} + +#ifdef FOO +// TODO: finish implementing this +void CauterizedModel::updateRenderItems() { + if (!_addedToScene) { + return; + } + + glm::vec3 scale = getScale(); + if (_collisionGeometry) { + // _collisionGeometry is already scaled + scale = glm::vec3(1.0f); + } + _needsUpdateClusterMatrices = true; + _renderItemsNeedUpdate = false; + + // queue up this work for later processing, at the end of update and just before rendering. + // the application will ensure only the last lambda is actually invoked. + void* key = (void*)this; + std::weak_ptr weakSelf = shared_from_this(); + AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [weakSelf, scale]() { + + // do nothing, if the model has already been destroyed. + auto self = weakSelf.lock(); + if (!self) { + return; + } + + render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene(); + + Transform modelTransform; + modelTransform.setTranslation(self->getTranslation()); + modelTransform.setRotation(self->getRotation()); + + Transform scaledModelTransform(modelTransform); + scaledModelTransform.setScale(scale); + + uint32_t deleteGeometryCounter = self->getGeometryCounter(); + + // TODO: handle two cases: + // (a) our payloads are of type ModelMeshPartPayload + // (b) our payloads are of type ModelMeshPartPayload + render::PendingChanges pendingChanges; + QList keys = self->getRenderItems().keys(); + foreach (auto itemID, keys) { + pendingChanges.updateItem(itemID, [modelTransform, deleteGeometryCounter](CauterizedMeshPartPayload& data) { + if (data._model && data._model->isLoaded()) { + if (!data.hasStartedFade() && data._model->getGeometry()->areTexturesLoaded()) { + data.startFade(); + } + // Ensure the model geometry was not reset between frames + if (deleteGeometryCounter == data._model->getGeometryCounter()) { + // lazy update of cluster matrices used for rendering. We need to update them here, so we can correctly update the bounding box. + data._model->updateClusterMatrices(); + + // update the model transform and bounding box for this render item. + const Model::MeshState& state = data._model->getMeshState(data._meshIndex); + CauterizedModel* cModel = static_cast(data._model); + const Model::MeshState& cState = cModel->_cauterizeMeshStates.at(data._meshIndex); + data.updateTransformForSkinnedCauterizedMesh(modelTransform, state.clusterMatrices, cState.clusterMatrices); + } + } + }); + } + + /* + // collision mesh does not share the same unit scale as the FBX file's mesh: only apply offset + Transform collisionMeshOffset; + collisionMeshOffset.setIdentity(); + foreach (auto itemID, self->_collisionRenderItems.keys()) { + pendingChanges.updateItem(itemID, [scaledModelTransform, collisionMeshOffset](MeshPartPayload& data) { + // update the model transform for this render item. + data.updateTransform(scaledModelTransform, collisionMeshOffset); + }); + } + */ + + scene->enqueuePendingChanges(pendingChanges); + }); +} +#endif // FOO + +const Model::MeshState& CauterizedModel::getCauterizeMeshState(int index) const { + assert(index < _meshStates.size()); + return _cauterizeMeshStates.at(index); +} diff --git a/interface/src/avatar/CauterizedModel.h b/interface/src/avatar/CauterizedModel.h new file mode 100644 index 0000000000..12a9723dd4 --- /dev/null +++ b/interface/src/avatar/CauterizedModel.h @@ -0,0 +1,49 @@ +// +// CauterizeableModel.h +// interface/src/avatar +// +// Created by Andrew Meadows 2016.01.17 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_CauterizedModel_h +#define hifi_CauterizedModel_h + + +#include + +class CauterizedModel : public Model { + Q_OBJECT + +public: + CauterizedModel(RigPointer rig, QObject* parent); + virtual ~CauterizedModel(); + + void deleteGeometry() override; + virtual void updateRig(float deltaTime, glm::mat4 parentTransform) override; + + void setCauterizeBones(bool flag) { _cauterizeBones = flag; } + bool getCauterizeBones() const { return _cauterizeBones; } + + const std::unordered_set& getCauterizeBoneSet() const { return _cauterizeBoneSet; } + void setCauterizeBoneSet(const std::unordered_set& boneSet) { _cauterizeBoneSet = boneSet; } + + void createVisibleRenderItemSet() override; + void createCollisionRenderItemSet() override; + + bool updateGeometry() override; + virtual void updateClusterMatrices() override; + void updateRenderItems() override; + + const Model::MeshState& getCauterizeMeshState(int index) const; + +protected: + std::unordered_set _cauterizeBoneSet; + QVector _cauterizeMeshStates; + bool _cauterizeBones { false }; +}; + +#endif // hifi_CauterizedModel_h diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 889f0ef36b..54f6682191 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -24,7 +24,7 @@ #include "AnimDebugDraw.h" SkeletonModel::SkeletonModel(Avatar* owningAvatar, QObject* parent, RigPointer rig) : - Model(rig, parent), + CauterizedModel(rig, parent), _owningAvatar(owningAvatar), _boundingCapsuleLocalOffset(0.0f), _boundingCapsuleRadius(0.0f), @@ -166,7 +166,7 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { _rig->computeMotionAnimationState(deltaTime, position, velocity, orientation, ccState); // evaluate AnimGraph animation and update jointStates. - Model::updateRig(deltaTime, parentTransform); + CauterizedModel::updateRig(deltaTime, parentTransform); Rig::EyeParameters eyeParams; eyeParams.worldHeadOrientation = headParams.worldHeadOrientation; @@ -178,10 +178,8 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { eyeParams.rightEyeJointIndex = geometry.rightEyeJointIndex; _rig->updateFromEyeParameters(eyeParams); - } else { - - Model::updateRig(deltaTime, parentTransform); + CauterizedModel::updateRig(deltaTime, parentTransform); // This is a little more work than we really want. // diff --git a/interface/src/avatar/SkeletonModel.h b/interface/src/avatar/SkeletonModel.h index 8e61e6f3ca..7a6081a010 100644 --- a/interface/src/avatar/SkeletonModel.h +++ b/interface/src/avatar/SkeletonModel.h @@ -12,8 +12,7 @@ #ifndef hifi_SkeletonModel_h #define hifi_SkeletonModel_h - -#include +#include "CauterizedModel.h" class Avatar; class MuscleConstraint; @@ -23,7 +22,7 @@ using SkeletonModelPointer = std::shared_ptr; using SkeletonModelWeakPointer = std::weak_ptr; /// A skeleton loaded from a model. -class SkeletonModel : public Model { +class SkeletonModel : public CauterizedModel { Q_OBJECT public: @@ -31,10 +30,10 @@ public: SkeletonModel(Avatar* owningAvatar, QObject* parent = nullptr, RigPointer rig = nullptr); ~SkeletonModel(); - virtual void initJointStates() override; + void initJointStates() override; - virtual void simulate(float deltaTime, bool fullUpdate = true) override; - virtual void updateRig(float deltaTime, glm::mat4 parentTransform) override; + void simulate(float deltaTime, bool fullUpdate = true) override; + void updateRig(float deltaTime, glm::mat4 parentTransform) override; void updateAttitude(); /// Returns the index of the left hand joint, or -1 if not found. @@ -105,7 +104,7 @@ public: float getHeadClipDistance() const { return _headClipDistance; } - virtual void onInvalidate() override; + void onInvalidate() override; signals: diff --git a/interface/src/avatar/SoftAttachmentModel.cpp b/interface/src/avatar/SoftAttachmentModel.cpp index 6351495598..530801007e 100644 --- a/interface/src/avatar/SoftAttachmentModel.cpp +++ b/interface/src/avatar/SoftAttachmentModel.cpp @@ -13,7 +13,7 @@ #include "InterfaceLogging.h" SoftAttachmentModel::SoftAttachmentModel(RigPointer rig, QObject* parent, RigPointer rigOverride) : - Model(rig, parent), + CauterizedModel(rig, parent), _rigOverride(rigOverride) { assert(_rig); assert(_rigOverride); @@ -38,6 +38,7 @@ int SoftAttachmentModel::getJointIndexOverride(int i) const { // virtual // use the _rigOverride matrices instead of the Model::_rig void SoftAttachmentModel::updateClusterMatrices() { + // adebug TODO: this needs work? if (!_needsUpdateClusterMatrices) { return; } diff --git a/interface/src/avatar/SoftAttachmentModel.h b/interface/src/avatar/SoftAttachmentModel.h index cdf957514c..fea679839a 100644 --- a/interface/src/avatar/SoftAttachmentModel.h +++ b/interface/src/avatar/SoftAttachmentModel.h @@ -12,7 +12,7 @@ #ifndef hifi_SoftAttachmentModel_h #define hifi_SoftAttachmentModel_h -#include +#include "CauterizedModel.h" // A model that allows the creator to specify a secondary rig instance. // When the cluster matrices are created for rendering, the @@ -22,16 +22,15 @@ // This is used by Avatar instances to wear clothing that follows the same // animated pose as the SkeletonModel. -class SoftAttachmentModel : public Model { +class SoftAttachmentModel : public CauterizedModel { Q_OBJECT public: - SoftAttachmentModel(RigPointer rig, QObject* parent, RigPointer rigOverride); ~SoftAttachmentModel(); - virtual void updateRig(float deltaTime, glm::mat4 parentTransform) override; - virtual void updateClusterMatrices() override; + void updateRig(float deltaTime, glm::mat4 parentTransform) override; + void updateClusterMatrices() override; protected: int getJointIndexOverride(int i) const; diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index e3b2527e67..52eb006b9f 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -251,7 +251,7 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat } } -void MeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline::LocationsPointer locations, bool canCauterize) const { +void MeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const { batch.setModelTransform(_drawTransform); } @@ -265,7 +265,7 @@ void MeshPartPayload::render(RenderArgs* args) const { assert(locations); // Bind the model transform and the skinCLusterMatrices if needed - bindTransform(batch, locations); + bindTransform(batch, locations, args->_renderMode); //Bind the index buffer and vertex buffer and Blend shapes if needed bindMesh(batch); @@ -359,11 +359,8 @@ void ModelMeshPartPayload::notifyLocationChanged() { } -void ModelMeshPartPayload::updateTransformForSkinnedMesh(const Transform& transform, - const QVector& clusterMatrices, - const QVector& cauterizedClusterMatrices) { +void ModelMeshPartPayload::updateTransformForSkinnedMesh(const Transform& transform, const QVector& clusterMatrices) { _transform = transform; - _cauterizedTransform = transform; if (clusterMatrices.size() > 0) { _worldBound = AABox(); @@ -372,16 +369,7 @@ void ModelMeshPartPayload::updateTransformForSkinnedMesh(const Transform& transf clusterBound.transform(clusterMatrix); _worldBound += clusterBound; } - _worldBound.transform(transform); - if (clusterMatrices.size() == 1) { - _transform = _transform.worldTransform(Transform(clusterMatrices[0])); - if (cauterizedClusterMatrices.size() != 0) { - _cauterizedTransform = _cauterizedTransform.worldTransform(Transform(cauterizedClusterMatrices[0])); - } else { - _cauterizedTransform = _transform; - } - } } } @@ -525,24 +513,13 @@ void ModelMeshPartPayload::bindMesh(gpu::Batch& batch) const { } } -void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline::LocationsPointer locations, bool canCauterize) const { +void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const { // Still relying on the raw data from the model - const Model::MeshState& state = _model->_meshStates.at(_meshIndex); - + const Model::MeshState& state = _model->getMeshState(_meshIndex); if (state.clusterBuffer) { - if (canCauterize && _model->getCauterizeBones()) { - batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::SKINNING, state.cauterizedClusterBuffer); - } else { - batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::SKINNING, state.clusterBuffer); - } - batch.setModelTransform(_transform); - } else { - if (canCauterize && _model->getCauterizeBones()) { - batch.setModelTransform(_cauterizedTransform); - } else { - batch.setModelTransform(_transform); - } + batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::SKINNING, state.clusterBuffer); } + batch.setModelTransform(_transform); } void ModelMeshPartPayload::startFade() { @@ -596,9 +573,8 @@ void ModelMeshPartPayload::render(RenderArgs* args) const { assert(locations); // Bind the model transform and the skinCLusterMatrices if needed - bool canCauterize = args->_renderMode != RenderArgs::SHADOW_RENDER_MODE; _model->updateClusterMatrices(); - bindTransform(batch, locations, canCauterize); + bindTransform(batch, locations, args->_renderMode); //Bind the index buffer and vertex buffer and Blend shapes if needed bindMesh(batch); @@ -621,4 +597,3 @@ void ModelMeshPartPayload::render(RenderArgs* args) const { args->_details._trianglesRendered += _drawPart._numIndices / INDICES_PER_TRIANGLE; } } - diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index b7a8cf63f0..53160db91e 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -48,7 +48,7 @@ public: void drawCall(gpu::Batch& batch) const; virtual void bindMesh(gpu::Batch& batch) const; virtual void bindMaterial(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations) const; - virtual void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, bool canCauterize = true) const; + virtual void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const; // Payload resource cached values std::shared_ptr _drawMesh; @@ -86,8 +86,7 @@ public: void notifyLocationChanged() override; void updateTransformForSkinnedMesh(const Transform& transform, - const QVector& clusterMatrices, - const QVector& cauterizedClusterMatrices); + const QVector& clusterMatrices); // Entity fade in void startFade(); @@ -102,13 +101,12 @@ public: // ModelMeshPartPayload functions to perform render void bindMesh(gpu::Batch& batch) const override; - void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, bool canCauterize = true) const override; + void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const override; void initCache(); Model* _model; - Transform _cauterizedTransform; int _meshIndex; int _shapeID; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 14391b9f16..ef613e8c14 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -91,7 +91,6 @@ Model::Model(RigPointer rig, QObject* parent) : _scaledToFit(false), _snapModelToRegistrationPoint(false), _snappedToRegistrationPoint(false), - _cauterizeBones(false), _url(HTTP_INVALID_COM), _isVisible(true), _blendNumber(0), @@ -238,7 +237,7 @@ void Model::updateRenderItems() { // update the model transform and bounding box for this render item. const Model::MeshState& state = data._model->_meshStates.at(data._meshIndex); - data.updateTransformForSkinnedMesh(modelTransform, state.clusterMatrices, state.cauterizedClusterMatrices); + data.updateTransformForSkinnedMesh(modelTransform, state.clusterMatrices); } } }); @@ -294,8 +293,6 @@ bool Model::updateGeometry() { foreach (const FBXMesh& mesh, fbxGeometry.meshes) { MeshState state; state.clusterMatrices.resize(mesh.clusters.size()); - state.cauterizedClusterMatrices.resize(mesh.clusters.size()); - _meshStates.append(state); // Note: we add empty buffers for meshes that lack blendshapes so we can access the buffers by index @@ -1159,13 +1156,6 @@ void Model::updateClusterMatrices() { } _needsUpdateClusterMatrices = false; const FBXGeometry& geometry = getFBXGeometry(); - static const glm::mat4 zeroScale( - glm::vec4(0.0f, 0.0f, 0.0f, 0.0f), - glm::vec4(0.0f, 0.0f, 0.0f, 0.0f), - glm::vec4(0.0f, 0.0f, 0.0f, 0.0f), - glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)); - auto cauterizeMatrix = _rig->getJointTransform(geometry.neckJointIndex) * zeroScale; - for (int i = 0; i < _meshStates.size(); i++) { MeshState& state = _meshStates[i]; const FBXMesh& mesh = geometry.meshes.at(i); @@ -1179,20 +1169,6 @@ void Model::updateClusterMatrices() { #else state.clusterMatrices[j] = jointMatrix * cluster.inverseBindMatrix; #endif - - // as an optimization, don't build cautrizedClusterMatrices if the boneSet is empty. - if (!_cauterizeBoneSet.empty()) { - if (_cauterizeBoneSet.find(cluster.jointIndex) != _cauterizeBoneSet.end()) { - jointMatrix = cauterizeMatrix; - } -#if GLM_ARCH & GLM_ARCH_SSE2 - glm::mat4 out, inverseBindMatrix = cluster.inverseBindMatrix; - glm_mat4_mul((glm_vec4*)&jointMatrix, (glm_vec4*)&inverseBindMatrix, (glm_vec4*)&out); - state.cauterizedClusterMatrices[j] = out; -#else - state.cauterizedClusterMatrices[j] = jointMatrix * cluster.inverseBindMatrix; -#endif - } } // Once computed the cluster matrices, update the buffer(s) @@ -1204,17 +1180,6 @@ void Model::updateClusterMatrices() { state.clusterBuffer->setSubData(0, state.clusterMatrices.size() * sizeof(glm::mat4), (const gpu::Byte*) state.clusterMatrices.constData()); } - - if (!_cauterizeBoneSet.empty() && (state.cauterizedClusterMatrices.size() > 1)) { - if (!state.cauterizedClusterBuffer) { - state.cauterizedClusterBuffer = - std::make_shared(state.cauterizedClusterMatrices.size() * sizeof(glm::mat4), - (const gpu::Byte*) state.cauterizedClusterMatrices.constData()); - } else { - state.cauterizedClusterBuffer->setSubData(0, state.cauterizedClusterMatrices.size() * sizeof(glm::mat4), - (const gpu::Byte*) state.cauterizedClusterMatrices.constData()); - } - } } } diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index a11d6d511e..246d67180e 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -101,7 +101,7 @@ public: bool isLayeredInFront() const { return _isLayeredInFront; } - void updateRenderItems(); + virtual void updateRenderItems(); void setRenderItemsNeedUpdate() { _renderItemsNeedUpdate = true; } bool getRenderItemsNeedUpdate() { return _renderItemsNeedUpdate; } AABox getRenderableMeshBound() const; @@ -215,12 +215,6 @@ public: bool getIsScaledToFit() const { return _scaledToFit; } /// is model scaled to fit glm::vec3 getScaleToFitDimensions() const; /// the dimensions model is scaled to, including inferred y/z - void setCauterizeBones(bool flag) { _cauterizeBones = flag; } - bool getCauterizeBones() const { return _cauterizeBones; } - - const std::unordered_set& getCauterizeBoneSet() const { return _cauterizeBoneSet; } - void setCauterizeBoneSet(const std::unordered_set& boneSet) { _cauterizeBoneSet = boneSet; } - int getBlendshapeCoefficientsNum() const { return _blendshapeCoefficients.size(); } float getBlendshapeCoefficient(int index) const { return ((index < 0) && (index >= _blendshapeCoefficients.size())) ? 0.0f : _blendshapeCoefficients.at(index); @@ -231,7 +225,7 @@ public: const glm::vec3& getRegistrationPoint() const { return _registrationPoint; } // returns 'true' if needs fullUpdate after geometry change - bool updateGeometry(); + virtual bool updateGeometry(); void setCollisionMesh(model::MeshPointer mesh); void setLoadingPriority(float priority) { _loadingPriority = priority; } @@ -242,6 +236,18 @@ public: int getRenderInfoDrawCalls() const { return _renderInfoDrawCalls; } bool getRenderInfoHasTransparent() const { return _renderInfoHasTransparent; } + class MeshState { + public: + QVector clusterMatrices; + gpu::BufferPointer clusterBuffer; + + }; + + const MeshState& getMeshState(int index) { return _meshStates.at(index); } + + uint32_t getGeometryCounter() const { return _deleteGeometryCounter; } + const QMap& getRenderItems() const { return _modelMeshRenderItems; } + public slots: void loadURLFinished(bool success); @@ -298,18 +304,7 @@ protected: bool _snappedToRegistrationPoint; /// are we currently snapped to a registration point glm::vec3 _registrationPoint = glm::vec3(0.5f); /// the point in model space our center is snapped to - class MeshState { - public: - QVector clusterMatrices; - QVector cauterizedClusterMatrices; - gpu::BufferPointer clusterBuffer; - gpu::BufferPointer cauterizedClusterBuffer; - - }; - QVector _meshStates; - std::unordered_set _cauterizeBoneSet; - bool _cauterizeBones; virtual void initJointStates(); @@ -342,7 +337,7 @@ protected: protected: - void deleteGeometry(); + virtual void deleteGeometry(); void initJointTransforms(); QVector _blendshapeCoefficients; @@ -371,12 +366,11 @@ protected: void recalculateMeshBoxes(bool pickAgainstTriangles = false); void createRenderItemSet(); - void createVisibleRenderItemSet(); - void createCollisionRenderItemSet(); + virtual void createVisibleRenderItemSet(); + virtual void createCollisionRenderItemSet(); bool _isWireframe; - // debug rendering support void renderDebugMeshBoxes(gpu::Batch& batch); int _debugMeshBoxesID = GeometryCache::UNKNOWN_ID;