History

merge with master

HifiExperiments committed 6 years ago

Commit 3dfd63d2 parents 0bcd8b8 37efdfd2941 files · +167605 −30056Browse files

Showing the changes to libraries/render-utils/src/Model.cpp (1 of 2941 files). Show all

Unified · Split

libraries/render-utils/src/Model.cpp+305−297
@@ -39,16 +39,18 @@ · 38 unmodified lines
3939 #include "RenderUtilsLogging.h"
4040 #include <Trace.h>
4141
42+#include <BlendshapeConstants.h>
43+
4244 using namespace std;
4345
4446 int nakedModelPointerTypeId = qRegisterMetaType<ModelPointer>();
45−int weakGeometryResourceBridgePointerTypeId = qRegisterMetaType<Geometry::WeakPointer>();
47+int weakGeometryResourceBridgePointerTypeId = qRegisterMetaType<NetworkModel::WeakPointer>();
4648 int vec3VectorTypeId = qRegisterMetaType<QVector<glm::vec3>>();
4749 int normalTypeVecTypeId = qRegisterMetaType<QVector<NormalType>>("QVector<NormalType>");
4850 float Model::FAKE_DIMENSION_PLACEHOLDER = -1.0f;
4951 #define HTTP_INVALID_COM "http://invalid.com"
5052
51−Model::Model(QObject* parent, SpatiallyNestable* spatiallyNestableOverride) :
53+Model::Model(QObject* parent, SpatiallyNestable* spatiallyNestableOverride, uint64_t created) :
5254 QObject(parent),
5355 _renderGeometry(),
5456 _renderWatcher(_renderGeometry),
@@ -62,7 +64,8 @@ Model::Model(QObject* parent, SpatiallyNestable* spatiallyNestableOverride) : · 7 unmodified lines
6264 _snapModelToRegistrationPoint(false),
6365 _snappedToRegistrationPoint(false),
6466 _url(HTTP_INVALID_COM),
65− _renderItemKeyGlobalFlags(render::ItemKey::Builder().withVisible().withTagBits(render::hifi::TAG_ALL_VIEWS).build())
67+ _renderItemKeyGlobalFlags(render::ItemKey::Builder().withVisible().withTagBits(render::hifi::TAG_ALL_VIEWS).build()),
68+ _created(created)
6669 {
6770 // we may have been created in the network thread, but we live in the main thread
6871 if (_viewState) {
@@ -71,7 +74,7 @@ Model::Model(QObject* parent, SpatiallyNestable* spatiallyNestableOverride) : · 2 unmodified lines
7174
7275 setSnapModelToRegistrationPoint(true, glm::vec3(0.5f));
7376
74− connect(&_renderWatcher, &GeometryResourceWatcher::finished, this, &Model::loadURLFinished);
77+ connect(&_renderWatcher, &ModelResourceWatcher::finished, this, &Model::loadURLFinished);
7578 }
7679
7780 Model::~Model() {
@@ -151,7 +154,7 @@ void Model::setOffset(const glm::vec3& offset) { · 73 unmodified lines
151154 }
152155
153156 void Model::calculateTextureInfo() {
154− if (!_hasCalculatedTextureInfo && isLoaded() && getGeometry()->areTexturesLoaded() && !_modelMeshRenderItems.isEmpty()) {
157+ if (!_hasCalculatedTextureInfo && isLoaded() && getNetworkModel()->areTexturesLoaded() && !_modelMeshRenderItems.isEmpty()) {
155158 size_t textureSize = 0;
156159 int textureCount = 0;
157160 bool allTexturesLoaded = true;
@@ -178,15 +181,15 @@ int Model::getRenderInfoTextureCount() { · 20 unmodified lines
178181 }
179182
180183 bool Model::shouldInvalidatePayloadShapeKey(int meshIndex) {
181− if (!getGeometry()) {
184+ if (!getNetworkModel()) {
182185 return true;
183186 }
184187
185188 const HFMModel& hfmModel = getHFMModel();
186− const auto& networkMeshes = getGeometry()->getMeshes();
189+ const auto& networkMeshes = getNetworkModel()->getMeshes();
187190 // if our index is ever out of range for either meshes or networkMeshes, then skip it, and set our _meshGroupsKnown
188191 // to false to rebuild out mesh groups.
189− if (meshIndex < 0 || meshIndex >= (int)networkMeshes.size() || meshIndex >= (int)hfmModel.meshes.size() || meshIndex >= (int)_meshStates.size()) {
192+ if (meshIndex < 0 || meshIndex >= (int)networkMeshes.size() || meshIndex >= (int)hfmModel.meshes.size()) {
190193 _needsFixupInScene = true; // trigger remove/add cycle
191194 invalidCalculatedMeshBoxes(); // if we have to reload, we need to assume our mesh boxes are all invalid
192195 return true;
@@ -228,44 +231,45 @@ void Model::updateRenderItems() { · 35 unmodified lines
228231
229232 render::Transaction transaction;
230233 for (int i = 0; i < (int) self->_modelMeshRenderItemIDs.size(); i++) {
231−
232234 auto itemID = self->_modelMeshRenderItemIDs[i];
233− auto meshIndex = self->_modelMeshRenderItemShapes[i].meshIndex;
234235
235− const auto& meshState = self->getMeshState(meshIndex);
236+ const auto& shapeState = self->getShapeState(i);
236237
237− bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(meshIndex);
238− bool useDualQuaternionSkinning = self->getUseDualQuaternionSkinning();
238+ auto skinDeformerIndex = shapeState._skinDeformerIndex;
239239
240− transaction.updateItem<ModelMeshPartPayload>(itemID, [modelTransform, meshState, useDualQuaternionSkinning,
241− invalidatePayloadShapeKey, primitiveMode, renderItemKeyGlobalFlags, cauterized](ModelMeshPartPayload& data) {
242− if (useDualQuaternionSkinning) {
243− data.updateClusterBuffer(meshState.clusterDualQuaternions);
244− } else {
245− data.updateClusterBuffer(meshState.clusterMatrices);
246− }
240+ bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(shapeState._meshIndex);
247241
248− Transform renderTransform = modelTransform;
242+ if (skinDeformerIndex != hfm::UNDEFINED_KEY) {
243+ const auto& meshState = self->getMeshState(skinDeformerIndex);
244+ bool useDualQuaternionSkinning = self->getUseDualQuaternionSkinning();
249245
250− if (useDualQuaternionSkinning) {
251− if (meshState.clusterDualQuaternions.size() == 1 || meshState.clusterDualQuaternions.size() == 2) {
252− const auto& dq = meshState.clusterDualQuaternions[0];
253− Transform transform(dq.getRotation(),
254− dq.getScale(),
255− dq.getTranslation());
256− renderTransform = modelTransform.worldTransform(Transform(transform));
246+ transaction.updateItem<ModelMeshPartPayload>(itemID, [modelTransform, shapeState, meshState, useDualQuaternionSkinning,
247+ invalidatePayloadShapeKey, primitiveMode, renderItemKeyGlobalFlags, cauterized](ModelMeshPartPayload& data) {
248+ if (useDualQuaternionSkinning) {
249+ data.updateClusterBuffer(meshState.clusterDualQuaternions);
250+ } else {
251+ data.updateClusterBuffer(meshState.clusterMatrices);
257252 }
258− } else {
259− if (meshState.clusterMatrices.size() == 1 || meshState.clusterMatrices.size() == 2) {
260− renderTransform = modelTransform.worldTransform(Transform(meshState.clusterMatrices[0]));
261− }
262− }
263− data.updateTransformForSkinnedMesh(renderTransform, modelTransform);
264253
265− data.setCauterized(cauterized);
266− data.updateKey(renderItemKeyGlobalFlags);
267− data.setShapeKey(invalidatePayloadShapeKey, primitiveMode, useDualQuaternionSkinning);
268− });
254+ Transform renderTransform = modelTransform;
255+ data.updateTransform(renderTransform);
256+ data.updateTransformAndBound(modelTransform.worldTransform(shapeState._rootFromJointTransform));
257+
258+ data.setCauterized(cauterized);
259+ data.updateKey(renderItemKeyGlobalFlags);
260+ data.setShapeKey(invalidatePayloadShapeKey, primitiveMode, useDualQuaternionSkinning);
261+ });
262+ } else {
263+ transaction.updateItem<ModelMeshPartPayload>(itemID, [modelTransform, shapeState, invalidatePayloadShapeKey, primitiveMode, renderItemKeyGlobalFlags](ModelMeshPartPayload& data) {
264+
265+ Transform renderTransform = modelTransform;
266+ renderTransform = modelTransform.worldTransform(shapeState._rootFromJointTransform);
267+ data.updateTransform(renderTransform);
268+
269+ data.updateKey(renderItemKeyGlobalFlags);
270+ data.setShapeKey(invalidatePayloadShapeKey, primitiveMode, false);
271+ });
272+ }
269273 }
270274
271275 AbstractViewStateInterface::instance()->getMain3DScene()->enqueueTransaction(transaction);
@@ -291,6 +295,15 @@ void Model::reset() { · 19 unmodified lines
291295 }
292296 }
293297
298+void Model::updateShapeStatesFromRig() {
299+ for (auto& shape : _shapeStates) {
300+ uint32_t jointId = shape._jointIndex;
301+ if (jointId < (uint32_t) _rig.getJointStateCount()) {
302+ shape._rootFromJointTransform = _rig.getJointTransform(jointId);
303+ }
304+ }
305+}
306+
294307 bool Model::updateGeometry() {
295308 bool needFullUpdate = false;
296309
@@ -306,16 +319,27 @@ bool Model::updateGeometry() { · 9 unmodified lines
306319 assert(_meshStates.empty());
307320
308321 const HFMModel& hfmModel = getHFMModel();
309− int i = 0;
310− foreach (const HFMMesh& mesh, hfmModel.meshes) {
322+
323+ const auto& shapes = hfmModel.shapes;
324+ _shapeStates.resize(shapes.size());
325+ for (uint32_t s = 0; s < (uint32_t) shapes.size(); ++s) {
326+ auto& shapeState = _shapeStates[s];
327+ shapeState._jointIndex = shapes[s].joint;
328+ shapeState._meshIndex = shapes[s].mesh;
329+ shapeState._meshPartIndex = shapes[s].meshPart;
330+ shapeState._skinDeformerIndex = shapes[s].skinDeformer;
331+ }
332+ updateShapeStatesFromRig();
333+
334+ const auto& hfmSkinDeformers = hfmModel.skinDeformers;
335+ for (uint32_t i = 0; i < (uint32_t) hfmSkinDeformers.size(); i++) {
336+ const auto& dynT = hfmSkinDeformers[i];
311337 MeshState state;
312− state.clusterDualQuaternions.resize(mesh.clusters.size());
313− state.clusterMatrices.resize(mesh.clusters.size());
338+ state.clusterDualQuaternions.resize(dynT.clusters.size());
339+ state.clusterMatrices.resize(dynT.clusters.size());
314340 _meshStates.push_back(state);
315− initializeBlendshapes(mesh, i);
316− i++;
317341 }
318− _blendshapeOffsetsInitialized = true;
342+
319343 needFullUpdate = true;
320344 emit rigReady();
321345 }
@@ -445,7 +469,7 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g · 123 unmodified lines
445469 }
446470
447471 /**jsdoc
448− * Information about a submesh intersection point.
472+ * A submesh intersection point.
449473 * @typedef {object} SubmeshIntersection
450474 * @property {Vec3} worldIntersectionPoint - The intersection point in world coordinates.
451475 * @property {Vec3} meshIntersectionPoint - The intersection point in model coordinates.
@@ -643,8 +667,8 @@ glm::mat4 Model::getWorldToHFMMatrix() const { · 191 unmodified lines
643667 // TODO: deprecate and remove
644668 MeshProxyList Model::getMeshes() const {
645669 MeshProxyList result;
646− const Geometry::Pointer& renderGeometry = getGeometry();
647− const Geometry::GeometryMeshes& meshes = renderGeometry->getMeshes();
670+ const NetworkModel::Pointer& renderGeometry = getNetworkModel();
671+ const NetworkModel::GeometryMeshes& meshes = renderGeometry->getMeshes();
648672
649673 if (!isLoaded()) {
650674 return result;
@@ -713,9 +737,9 @@ bool Model::replaceScriptableModelMeshPart(scriptable::ScriptableModelBasePointe · 62 unmodified lines
713737 render::Transaction transaction;
714738 for (int i = 0; i < (int) _modelMeshRenderItemIDs.size(); i++) {
715739 auto itemID = _modelMeshRenderItemIDs[i];
716− auto shape = _modelMeshRenderItemShapes[i];
740+ auto& shape = _shapeStates[i];
717741 // TODO: check to see if .partIndex matches too
718− if (shape.meshIndex == meshIndex) {
742+ if (shape._meshIndex == (uint32_t) meshIndex) {
719743 transaction.updateItem<ModelMeshPartPayload>(itemID, [=](ModelMeshPartPayload& data) {
720744 data.updateMeshPart(mesh, partIndex);
721745 });
@@ -734,7 +758,7 @@ bool Model::replaceScriptableModelMeshPart(scriptable::ScriptableModelBasePointe · 12 unmodified lines
734758 for (int partID = 0; partID < numParts; partID++) {
735759 HFMMeshPart part;
736760 part.triangleIndices = buffer_helpers::bufferToVector<int>(mesh._mesh->getIndexBuffer(), "part.triangleIndices");
737− mesh.parts << part;
761+ mesh.parts.push_back(part);
738762 }
739763 {
740764 foreach (const glm::vec3& vertex, mesh.vertices) {
@@ -745,7 +769,7 @@ bool Model::replaceScriptableModelMeshPart(scriptable::ScriptableModelBasePointe · 4 unmodified lines
745769 mesh.meshExtents.maximum = glm::max(mesh.meshExtents.maximum, transformedVertex);
746770 }
747771 }
748− hfmModel.meshes << mesh;
772+ hfmModel.meshes.push_back(mesh);
749773 }
750774 calculateTriangleSets(hfmModel);
751775 }
@@ -762,9 +786,9 @@ scriptable::ScriptableModelBase Model::getScriptableModel() { · 10 unmodified lines
762786 }
763787
764788 const HFMModel& hfmModel = getHFMModel();
765− int numberOfMeshes = hfmModel.meshes.size();
789+ uint32_t numberOfMeshes = (uint32_t)hfmModel.meshes.size();
766790 int shapeID = 0;
767− for (int i = 0; i < numberOfMeshes; i++) {
791+ for (uint32_t i = 0; i < numberOfMeshes; i++) {
768792 const HFMMesh& hfmMesh = hfmModel.meshes.at(i);
769793 if (auto mesh = hfmMesh._mesh) {
770794 result.append(mesh);
@@ -772,13 +796,16 @@ scriptable::ScriptableModelBase Model::getScriptableModel() { · 1 unmodified line
772796 int numParts = (int)mesh->getNumParts();
773797 for (int partIndex = 0; partIndex < numParts; partIndex++) {
774798 auto& materialName = _modelMeshMaterialNames[shapeID];
775− result.appendMaterial(graphics::MaterialLayer(getGeometry()->getShapeMaterial(shapeID), 0), shapeID, materialName);
776−
777− auto mappedMaterialIter = _materialMapping.find(shapeID);
778− if (mappedMaterialIter != _materialMapping.end()) {
779− auto mappedMaterials = mappedMaterialIter->second;
780− for (auto& mappedMaterial : mappedMaterials) {
781− result.appendMaterial(mappedMaterial, shapeID, materialName);
799+ result.appendMaterial(graphics::MaterialLayer(getNetworkModel()->getShapeMaterial(shapeID), 0), shapeID, materialName);
800+
801+ {
802+ std::unique_lock<std::mutex> lock(_materialMappingMutex);
803+ auto mappedMaterialIter = _materialMapping.find(shapeID);
804+ if (mappedMaterialIter != _materialMapping.end()) {
805+ auto mappedMaterials = mappedMaterialIter->second;
806+ for (auto& mappedMaterial : mappedMaterials) {
807+ result.appendMaterial(mappedMaterial, shapeID, materialName);
808+ }
782809 }
783810 }
784811 shapeID++;
@@ -792,78 +819,70 @@ scriptable::ScriptableModelBase Model::getScriptableModel() { · 7 unmodified lines
792819 void Model::calculateTriangleSets(const HFMModel& hfmModel) {
793820 PROFILE_RANGE(render, __FUNCTION__);
794821
795− int numberOfMeshes = hfmModel.meshes.size();
822+ uint32_t meshInstanceCount = 0;
823+ uint32_t lastMeshForInstanceCount = hfm::UNDEFINED_KEY;
824+ for (const auto& shape : hfmModel.shapes) {
825+ if (shape.mesh != lastMeshForInstanceCount) {
826+ ++meshInstanceCount;
827+ }
828+ lastMeshForInstanceCount = shape.mesh;
829+ }
796830
797831 _triangleSetsValid = true;
798832 _modelSpaceMeshTriangleSets.clear();
799− _modelSpaceMeshTriangleSets.resize(numberOfMeshes);
800−
801− for (int i = 0; i < numberOfMeshes; i++) {
802− const HFMMesh& mesh = hfmModel.meshes.at(i);
803−
804− const int numberOfParts = mesh.parts.size();
805− auto& meshTriangleSets = _modelSpaceMeshTriangleSets[i];
806− meshTriangleSets.resize(numberOfParts);
807−
808− for (int j = 0; j < numberOfParts; j++) {
809− const HFMMeshPart& part = mesh.parts.at(j);
810−
811− auto& partTriangleSet = meshTriangleSets[j];
812−
813− const int INDICES_PER_TRIANGLE = 3;
814− const int INDICES_PER_QUAD = 4;
815− const int TRIANGLES_PER_QUAD = 2;
816−
817− // tell our triangleSet how many triangles to expect.
818− int numberOfQuads = part.quadIndices.size() / INDICES_PER_QUAD;
819− int numberOfTris = part.triangleIndices.size() / INDICES_PER_TRIANGLE;
820− int totalTriangles = (numberOfQuads * TRIANGLES_PER_QUAD) + numberOfTris;
821− partTriangleSet.reserve(totalTriangles);
822−
823− auto meshTransform = hfmModel.offset * mesh.modelTransform;
824−
825− if (part.quadIndices.size() > 0) {
826− int vIndex = 0;
827− for (int q = 0; q < numberOfQuads; q++) {
828− int i0 = part.quadIndices[vIndex++];
829− int i1 = part.quadIndices[vIndex++];
830− int i2 = part.quadIndices[vIndex++];
831− int i3 = part.quadIndices[vIndex++];
832−
833− // track the model space version... these points will be transformed by the FST's offset,
834− // which includes the scaling, rotation, and translation specified by the FST/FBX,
835− // this can't change at runtime, so we can safely store these in our TriangleSet
836− glm::vec3 v0 = glm::vec3(meshTransform * glm::vec4(mesh.vertices[i0], 1.0f));
837− glm::vec3 v1 = glm::vec3(meshTransform * glm::vec4(mesh.vertices[i1], 1.0f));
838− glm::vec3 v2 = glm::vec3(meshTransform * glm::vec4(mesh.vertices[i2], 1.0f));
839− glm::vec3 v3 = glm::vec3(meshTransform * glm::vec4(mesh.vertices[i3], 1.0f));
840−
841− Triangle tri1 = { v0, v1, v3 };
842− Triangle tri2 = { v1, v2, v3 };
843− partTriangleSet.insert(tri1);
844− partTriangleSet.insert(tri2);
845− }
846− }
833+ _modelSpaceMeshTriangleSets.reserve(meshInstanceCount);
834+
835+ uint32_t lastMeshForTriangleBuilding = hfm::UNDEFINED_KEY;
836+ glm::mat4 lastTransformForTriangleBuilding { 0 };
837+ std::vector<glm::vec3> transformedPoints;
838+ for (const auto& shape : hfmModel.shapes) {
839+ const uint32_t meshIndex = shape.mesh;
840+ const hfm::Mesh& mesh = hfmModel.meshes.at(meshIndex);
841+ const auto& triangleListMesh = mesh.triangleListMesh;
842+ const glm::vec2 part = triangleListMesh.parts[shape.meshPart];
843+ glm::mat4 worldFromMeshTransform;
844+ if (shape.joint != hfm::UNDEFINED_KEY) {
845+ // globalTransform includes hfmModel.offset,
846+ // which includes the scaling, rotation, and translation specified by the FST,
847+ // and the scaling from the unit conversion in FBX.
848+ // This can't change at runtime, so we can safely store these in our TriangleSet.
849+ worldFromMeshTransform = hfmModel.joints[shape.joint].globalTransform;
850+ }
851+
852+ if (meshIndex != lastMeshForTriangleBuilding || worldFromMeshTransform != lastTransformForTriangleBuilding) {
853+ lastMeshForTriangleBuilding = meshIndex;
854+ lastTransformForTriangleBuilding = worldFromMeshTransform;
855+ _modelSpaceMeshTriangleSets.emplace_back();
856+ _modelSpaceMeshTriangleSets.back().reserve(mesh.parts.size());
847857
848− if (part.triangleIndices.size() > 0) {
849− int vIndex = 0;
850− for (int t = 0; t < numberOfTris; t++) {
851− int i0 = part.triangleIndices[vIndex++];
852− int i1 = part.triangleIndices[vIndex++];
853− int i2 = part.triangleIndices[vIndex++];
854−
855− // track the model space version... these points will be transformed by the FST's offset,
856− // which includes the scaling, rotation, and translation specified by the FST/FBX,
857− // this can't change at runtime, so we can safely store these in our TriangleSet
858− glm::vec3 v0 = glm::vec3(meshTransform * glm::vec4(mesh.vertices[i0], 1.0f));
859− glm::vec3 v1 = glm::vec3(meshTransform * glm::vec4(mesh.vertices[i1], 1.0f));
860− glm::vec3 v2 = glm::vec3(meshTransform * glm::vec4(mesh.vertices[i2], 1.0f));
861−
862− Triangle tri = { v0, v1, v2 };
863− partTriangleSet.insert(tri);
858+ transformedPoints = triangleListMesh.vertices;
859+ if (worldFromMeshTransform != glm::mat4()) {
860+ for (auto& point : transformedPoints) {
861+ point = glm::vec3(worldFromMeshTransform * glm::vec4(point, 1.0f));
864862 }
865863 }
866864 }
865+ auto& meshTriangleSets = _modelSpaceMeshTriangleSets.back();
866+ meshTriangleSets.emplace_back();
867+ auto& partTriangleSet = meshTriangleSets.back();
868+
869+ const static size_t INDICES_PER_TRIANGLE = 3;
870+ const size_t triangleCount = (size_t)(part.y) / INDICES_PER_TRIANGLE;
871+ partTriangleSet.reserve(triangleCount);
872+ const size_t indexStart = (uint32_t)part.x;
873+ const size_t indexEnd = indexStart + (triangleCount * INDICES_PER_TRIANGLE);
874+ for (size_t i = indexStart; i < indexEnd; i += INDICES_PER_TRIANGLE) {
875+ const int i0 = triangleListMesh.indices[i];
876+ const int i1 = triangleListMesh.indices[i + 1];
877+ const int i2 = triangleListMesh.indices[i + 2];
878+
879+ const glm::vec3 v0 = transformedPoints[i0];
880+ const glm::vec3 v1 = transformedPoints[i1];
881+ const glm::vec3 v2 = transformedPoints[i2];
882+
883+ const Triangle tri = { v0, v1, v2 };
884+ partTriangleSet.insert(tri);
885+ }
867886 }
868887 }
869888
@@ -874,8 +893,8 @@ void Model::updateRenderItemsKey(const render::ScenePointer& scene) { · 4 unmodified lines
874893 }
875894 auto renderItemsKey = _renderItemKeyGlobalFlags;
876895 render::Transaction transaction;
877− foreach(auto item, _modelMeshRenderItemsMap.keys()) {
878− transaction.updateItem<ModelMeshPartPayload>(item, [renderItemsKey](ModelMeshPartPayload& data) {
896+ for(auto itemID: _modelMeshRenderItemIDs) {
897+ transaction.updateItem<ModelMeshPartPayload>(itemID, [renderItemsKey](ModelMeshPartPayload& data) {
879898 data.updateKey(renderItemsKey);
880899 });
881900 }
@@ -945,8 +964,8 @@ void Model::setCauterized(bool cauterized, const render::ScenePointer& scene) { · 63 unmodified lines
945964 return;
946965 }
947966 render::Transaction transaction;
948− foreach (auto item, _modelMeshRenderItemsMap.keys()) {
949− transaction.updateItem<ModelMeshPartPayload>(item, [cauterized](ModelMeshPartPayload& data) {
967+ for (auto itemID : _modelMeshRenderItemIDs) {
968+ transaction.updateItem<ModelMeshPartPayload>(itemID, [cauterized](ModelMeshPartPayload& data) {
950969 data.setCauterized(cauterized);
951970 });
952971 }
@@ -976,7 +995,9 @@ bool Model::addToScene(const render::ScenePointer& scene, · 23 unmodified lines
976995 render::Transaction& transaction,
977996 render::Item::Status::Getters& statusGetters,
978997 BlendShapeOperator modelBlendshapeOperator) {
998+
979999 if (!_addedToScene && isLoaded()) {
1000+ updateGeometry();
9801001 updateClusterMatrices();
9811002 if (_modelMeshRenderItems.empty()) {
9821003 createRenderItemSet();
@@ -987,26 +1008,25 @@ bool Model::addToScene(const render::ScenePointer& scene, · 4 unmodified lines
9871008
9881009 bool somethingAdded = false;
9891010
990− if (_modelMeshRenderItemsMap.empty()) {
1011+ if (_modelMeshRenderItemIDs.empty()) {
9911012 bool hasTransparent = false;
9921013 size_t verticesCount = 0;
9931014 foreach(auto renderItem, _modelMeshRenderItems) {
9941015 auto item = scene->allocateID();
9951016 auto renderPayload = std::make_shared<ModelMeshPartPayload::Payload>(renderItem);
996− if (_modelMeshRenderItemsMap.empty() && statusGetters.size()) {
1017+ if (_modelMeshRenderItemIDs.empty() && statusGetters.size()) {
9971018 renderPayload->addStatusGetters(statusGetters);
9981019 }
9991020 transaction.resetItem(item, renderPayload);
10001021
10011022 hasTransparent = hasTransparent || renderItem.get()->getShapeKey().isTranslucent();
10021023 verticesCount += renderItem.get()->getVerticesCount();
1003− _modelMeshRenderItemsMap.insert(item, renderPayload);
10041024 _modelMeshRenderItemIDs.emplace_back(item);
10051025 }
1006− somethingAdded = !_modelMeshRenderItemsMap.empty();
1026+ somethingAdded = !_modelMeshRenderItemIDs.empty();
10071027
10081028 _renderInfoVertexCount = verticesCount;
1009− _renderInfoDrawCalls = _modelMeshRenderItemsMap.count();
1029+ _renderInfoDrawCalls = (uint32_t) _modelMeshRenderItemIDs.size();
10101030 _renderInfoHasTransparent = hasTransparent;
10111031 }
10121032
@@ -1021,19 +1041,14 @@ bool Model::addToScene(const render::ScenePointer& scene, · 8 unmodified lines
10211041 }
10221042
10231043 void Model::removeFromScene(const render::ScenePointer& scene, render::Transaction& transaction) {
1024− foreach (auto item, _modelMeshRenderItemsMap.keys()) {
1025− transaction.removeItem(item);
1044+ for (auto itemID: _modelMeshRenderItemIDs) {
1045+ transaction.removeItem(itemID);
10261046 }
10271047 _modelMeshRenderItemIDs.clear();
1028− _modelMeshRenderItemsMap.clear();
10291048 _modelMeshRenderItems.clear();
10301049 _modelMeshMaterialNames.clear();
1031− _modelMeshRenderItemShapes.clear();
10321050 _priorityMap.clear();
10331051
1034− _blendshapeOffsets.clear();
1035− _blendshapeOffsetsInitialized = false;
1036−
10371052 _addedToScene = false;
10381053
10391054 _renderInfoVertexCount = 0;
@@ -1042,7 +1057,7 @@ void Model::removeFromScene(const render::ScenePointer& scene, render::Transacti · 2 unmodified lines
10421057 _renderInfoHasTransparent = false;
10431058 }
10441059
1045−void Model::renderDebugMeshBoxes(gpu::Batch& batch) {
1060+void Model::renderDebugMeshBoxes(gpu::Batch& batch, bool forward) {
10461061 int colorNdx = 0;
10471062 _mutex.lock();
10481063
@@ -1051,7 +1066,7 @@ void Model::renderDebugMeshBoxes(gpu::Batch& batch) { · 2 unmodified lines
10511066 Transform meshToWorld(meshToWorldMatrix);
10521067 batch.setModelTransform(meshToWorld);
10531068
1054− DependencyManager::get<GeometryCache>()->bindSimpleProgram(batch, false, false, false, true, true);
1069+ DependencyManager::get<GeometryCache>()->bindSimpleProgram(batch, false, false, false, true, true, forward);
10551070
10561071 for (auto& meshTriangleSets : _modelSpaceMeshTriangleSets) {
10571072 for (auto &partTriangleSet : meshTriangleSets) {
@@ -1210,7 +1225,7 @@ void Model::setURL(const QUrl& url) { · 152 unmodified lines
12101225 invalidCalculatedMeshBoxes();
12111226 deleteGeometry();
12121227
1213− auto resource = DependencyManager::get<ModelCache>()->getGeometryResource(url);
1228+ auto resource = DependencyManager::get<ModelCache>()->getModelResource(url);
12141229 if (resource) {
12151230 resource->setLoadPriority(this, _loadingPriority);
12161231 _renderWatcher.setResource(resource);
@@ -1381,8 +1396,6 @@ void Model::simulate(float deltaTime, bool fullUpdate) { · 164 unmodified lines
13811396 // update the world space transforms for all joints
13821397 glm::mat4 parentTransform = glm::scale(_scale) * glm::translate(_offset);
13831398 updateRig(deltaTime, parentTransform);
1384−
1385− computeMeshPartLocalBounds();
13861399 }
13871400 }
13881401
@@ -1393,17 +1406,6 @@ void Model::updateRig(float deltaTime, glm::mat4 parentTransform) { · 4 unmodified lines
13931406 _rig.updateAnimations(deltaTime, parentTransform, rigToWorldTransform);
13941407 }
13951408
1396−void Model::computeMeshPartLocalBounds() {
1397− for (auto& part : _modelMeshRenderItems) {
1398− const Model::MeshState& state = _meshStates.at(part->_meshIndex);
1399− if (_useDualQuaternionSkinning) {
1400− part->computeAdjustedLocalBound(state.clusterDualQuaternions);
1401− } else {
1402− part->computeAdjustedLocalBound(state.clusterMatrices);
1403− }
1404− }
1405−}
1406−
14071409 // virtual
14081410 void Model::updateClusterMatrices() {
14091411 DETAILED_PERFORMANCE_TIMER("Model::updateClusterMatrices");
@@ -1412,32 +1414,32 @@ void Model::updateClusterMatrices() { · 2 unmodified lines
14121414 return;
14131415 }
14141416
1417+ updateShapeStatesFromRig();
1418+
14151419 _needsUpdateClusterMatrices = false;
1416− const HFMModel& hfmModel = getHFMModel();
1417− for (int i = 0; i < (int) _meshStates.size(); i++) {
1418− MeshState& state = _meshStates[i];
1419− int meshIndex = i;
1420− const HFMMesh& mesh = hfmModel.meshes.at(i);
1421− for (int j = 0; j < mesh.clusters.size(); j++) {
1422− const HFMCluster& cluster = mesh.clusters.at(j);
1423− int clusterIndex = j;
1420+
1421+ for (int skinDeformerIndex = 0; skinDeformerIndex < (int)_meshStates.size(); skinDeformerIndex++) {
1422+ MeshState& state = _meshStates[skinDeformerIndex];
1423+ auto numClusters = state.getNumClusters();
1424+ for (uint32_t clusterIndex = 0; clusterIndex < numClusters; clusterIndex++) {
1425+ const auto& cbmov = _rig.getAnimSkeleton()->getClusterBindMatricesOriginalValues(skinDeformerIndex, clusterIndex);
14241426
14251427 if (_useDualQuaternionSkinning) {
1426− auto jointPose = _rig.getJointPose(cluster.jointIndex);
1428+ auto jointPose = _rig.getJointPose(cbmov.jointIndex);
14271429 Transform jointTransform(jointPose.rot(), jointPose.scale(), jointPose.trans());
14281430 Transform clusterTransform;
1429− Transform::mult(clusterTransform, jointTransform, _rig.getAnimSkeleton()->getClusterBindMatricesOriginalValues(meshIndex, clusterIndex).inverseBindTransform);
1430− state.clusterDualQuaternions[j] = Model::TransformDualQuaternion(clusterTransform);
1431+ Transform::mult(clusterTransform, jointTransform, cbmov.inverseBindTransform);
1432+ state.clusterDualQuaternions[clusterIndex] = Model::TransformDualQuaternion(clusterTransform);
14311433 } else {
1432− auto jointMatrix = _rig.getJointTransform(cluster.jointIndex);
1433− glm_mat4u_mul(jointMatrix, _rig.getAnimSkeleton()->getClusterBindMatricesOriginalValues(meshIndex, clusterIndex).inverseBindMatrix, state.clusterMatrices[j]);
1434+ auto jointMatrix = _rig.getJointTransform(cbmov.jointIndex);
1435+ glm_mat4u_mul(jointMatrix, cbmov.inverseBindMatrix, state.clusterMatrices[clusterIndex]);
14341436 }
14351437 }
14361438 }
14371439
14381440 // post the blender if we're not currently waiting for one to finish
14391441 auto modelBlender = DependencyManager::get<ModelBlender>();
1440− if (_blendshapeOffsetsInitialized && modelBlender->shouldComputeBlendshapes() && hfmModel.hasBlendedMeshes() && _blendshapeCoefficients != _blendedBlendshapeCoefficients) {
1442+ if (modelBlender->shouldComputeBlendshapes() && getHFMModel().hasBlendedMeshes() && _blendshapeCoefficients != _blendedBlendshapeCoefficients) {
14411443 _blendedBlendshapeCoefficients = _blendshapeCoefficients;
14421444 modelBlender->noteRequiresBlend(getThisPointer());
14431445 }
@@ -1445,8 +1447,7 @@ void Model::updateClusterMatrices() { · 1 unmodified line
14451447
14461448 void Model::deleteGeometry() {
14471449 _deleteGeometryCounter++;
1448− _blendshapeOffsets.clear();
1449− _blendshapeOffsetsInitialized = false;
1450+ _shapeStates.clear();
14501451 _meshStates.clear();
14511452 _rig.destroyAnimGraph();
14521453 _blendedBlendshapeCoefficients.clear();
@@ -1480,20 +1481,12 @@ const render::ItemIDs& Model::fetchRenderItemIDs() const { · 27 unmodified lines
14801481
14811482 void Model::createRenderItemSet() {
14821483 assert(isLoaded());
1483− const auto& meshes = _renderGeometry->getMeshes();
1484−
1485− // all of our mesh vectors must match in size
1486− if (meshes.size() != _meshStates.size()) {
1487− qCDebug(renderutils) << "WARNING!!!! Mesh Sizes don't match! " << meshes.size() << _meshStates.size() << " We will not segregate mesh groups yet.";
1488− return;
1489− }
14901484
14911485 // We should not have any existing renderItems if we enter this section of code
14921486 Q_ASSERT(_modelMeshRenderItems.isEmpty());
14931487
14941488 _modelMeshRenderItems.clear();
14951489 _modelMeshMaterialNames.clear();
1496− _modelMeshRenderItemShapes.clear();
14971490
14981491 Transform transform;
14991492 transform.setTranslation(_translation);
@@ -1504,31 +1497,19 @@ void Model::createRenderItemSet() { · 4 unmodified lines
15041497 offset.postTranslate(_offset);
15051498
15061499 // Run through all of the meshes, and place them into their segregated, but unsorted buckets
1507− int shapeID = 0;
1508− uint32_t numMeshes = (uint32_t)meshes.size();
1509− auto& hfmModel = getHFMModel();
1510− for (uint32_t i = 0; i < numMeshes; i++) {
1511− const auto& mesh = meshes.at(i);
1512− if (!mesh) {
1513− continue;
1514− }
1500+ const auto& shapes = _renderGeometry->getHFMModel().shapes;
1501+ for (uint32_t shapeID = 0; shapeID < shapes.size(); shapeID++) {
1502+ const auto& shape = shapes[shapeID];
15151503
1516− // Create the render payloads
1517− int numParts = (int)mesh->getNumParts();
1518− for (int partIndex = 0; partIndex < numParts; partIndex++) {
1519− initializeBlendshapes(hfmModel.meshes[i], i);
1520− _modelMeshRenderItems << std::make_shared<ModelMeshPartPayload>(shared_from_this(), i, partIndex, shapeID, transform, offset);
1521− auto material = getGeometry()->getShapeMaterial(shapeID);
1522− _modelMeshMaterialNames.push_back(material ? material->getName() : "");
1523− _modelMeshRenderItemShapes.emplace_back(ShapeInfo{ (int)i });
1524− shapeID++;
1525− }
1504+ _modelMeshRenderItems << std::make_shared<ModelMeshPartPayload>(shared_from_this(), shape.mesh, shape.meshPart, shapeID, transform, offset, _created);
1505+
1506+ auto material = getNetworkModel()->getShapeMaterial(shapeID);
1507+ _modelMeshMaterialNames.push_back(material ? material->getName() : "");
15261508 }
1527− _blendshapeOffsetsInitialized = true;
15281509 }
15291510
15301511 bool Model::isRenderable() const {
1531− return !_meshStates.empty() || (isLoaded() && _renderGeometry->getMeshes().empty());
1512+ return (!_shapeStates.empty()) || (isLoaded() && _renderGeometry->getMeshes().empty());
15321513 }
15331514
15341515 std::set<unsigned int> Model::getMeshIDsFromMaterialID(QString parentMaterialName) {
@@ -1583,6 +1564,13 @@ void Model::applyMaterialMapping() { · 48 unmodified lines
15831564 auto renderItemsKey = _renderItemKeyGlobalFlags;
15841565 PrimitiveMode primitiveMode = getPrimitiveMode();
15851566 bool useDualQuaternionSkinning = _useDualQuaternionSkinning;
1567+ auto modelMeshRenderItemIDs = _modelMeshRenderItemIDs;
1568+ auto shapeStates = _shapeStates;
1569+ std::unordered_map<int, bool> shouldInvalidatePayloadShapeKeyMap;
1570+
1571+ for (auto& shape : _shapeStates) {
1572+ shouldInvalidatePayloadShapeKeyMap[shape._meshIndex] = shouldInvalidatePayloadShapeKey(shape._meshIndex);
1573+ }
15861574
15871575 auto& materialMapping = getMaterialMapping();
15881576 for (auto& mapping : materialMapping) {
@@ -1602,8 +1590,11 @@ void Model::applyMaterialMapping() { · 13 unmodified lines
16021590 priorityMapPerResource[shapeID] = ++_priorityMap[shapeID];
16031591 }
16041592
1605− auto materialLoaded = [this, networkMaterialResource, shapeIDs, priorityMapPerResource, renderItemsKey, primitiveMode, useDualQuaternionSkinning]() {
1606− if (networkMaterialResource->isFailed() || networkMaterialResource->parsedMaterials.names.size() == 0) {
1593+ std::weak_ptr<Model> weakSelf = shared_from_this();
1594+ auto materialLoaded = [networkMaterialResource, shapeIDs, priorityMapPerResource, renderItemsKey, primitiveMode, useDualQuaternionSkinning,
1595+ modelMeshRenderItemIDs, shapeStates, shouldInvalidatePayloadShapeKeyMap, weakSelf]() {
1596+ std::shared_ptr<Model> self = weakSelf.lock();
1597+ if (!self || networkMaterialResource->isFailed() || networkMaterialResource->parsedMaterials.names.size() == 0) {
16071598 return;
16081599 }
16091600 render::Transaction transaction;
@@ -1625,12 +1616,15 @@ void Model::applyMaterialMapping() { · 15 unmodified lines
16251616 }
16261617 }
16271618 for (auto shapeID : shapeIDs) {
1628− if (shapeID < _modelMeshRenderItemIDs.size()) {
1629− auto itemID = _modelMeshRenderItemIDs[shapeID];
1630− auto meshIndex = _modelMeshRenderItemShapes[shapeID].meshIndex;
1631− bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex);
1619+ if (shapeID < modelMeshRenderItemIDs.size()) {
1620+ auto itemID = modelMeshRenderItemIDs[shapeID];
1621+ auto meshIndex = shapeStates[shapeID]._meshIndex;
1622+ bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKeyMap.at(meshIndex);
16321623 graphics::MaterialLayer material = graphics::MaterialLayer(networkMaterial, priorityMapPerResource.at(shapeID));
1633− _materialMapping[shapeID].push_back(material);
1624+ {
1625+ std::unique_lock<std::mutex> lock(self->_materialMappingMutex);
1626+ self->_materialMapping[shapeID].push_back(material);
1627+ }
16341628 transaction.updateItem<ModelMeshPartPayload>(itemID, [material, renderItemsKey,
16351629 invalidatePayloadShapeKey, primitiveMode, useDualQuaternionSkinning](ModelMeshPartPayload& data) {
16361630 data.addMaterial(material);
@@ -1662,7 +1656,7 @@ void Model::addMaterial(graphics::MaterialLayer material, const std::string& par · 25 unmodified lines
16621656 for (auto shapeID : shapeIDs) {
16631657 if (shapeID < _modelMeshRenderItemIDs.size()) {
16641658 auto itemID = _modelMeshRenderItemIDs[shapeID];
1665− auto meshIndex = _modelMeshRenderItemShapes[shapeID].meshIndex;
1659+ auto meshIndex = _shapeStates[shapeID]._meshIndex;
16661660 bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex);
16671661 transaction.updateItem<ModelMeshPartPayload>(itemID, [material, renderItemsKey,
16681662 invalidatePayloadShapeKey, primitiveMode, useDualQuaternionSkinning](ModelMeshPartPayload& data) {
@@ -1684,7 +1678,7 @@ void Model::removeMaterial(graphics::MaterialPointer material, const std::string · 15 unmodified lines
16841678 auto itemID = _modelMeshRenderItemIDs[shapeID];
16851679 auto renderItemsKey = _renderItemKeyGlobalFlags;
16861680 PrimitiveMode primitiveMode = getPrimitiveMode();
1687− auto meshIndex = _modelMeshRenderItemShapes[shapeID].meshIndex;
1681+ auto meshIndex = _shapeStates[shapeID]._meshIndex;
16881682 bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex);
16891683 bool useDualQuaternionSkinning = _useDualQuaternionSkinning;
16901684 transaction.updateItem<ModelMeshPartPayload>(itemID, [material, renderItemsKey,
@@ -1699,21 +1693,17 @@ void Model::removeMaterial(graphics::MaterialPointer material, const std::string · 8 unmodified lines
16991693 AbstractViewStateInterface::instance()->getMain3DScene()->enqueueTransaction(transaction);
17001694 }
17011695
1702−class CollisionRenderGeometry : public Geometry {
1696+class CollisionRenderGeometry : public NetworkModel {
17031697 public:
17041698 CollisionRenderGeometry(graphics::MeshPointer mesh) {
17051699 _hfmModel = std::make_shared<HFMModel>();
17061700 std::shared_ptr<GeometryMeshes> meshes = std::make_shared<GeometryMeshes>();
17071701 meshes->push_back(mesh);
17081702 _meshes = meshes;
1709− _meshParts = std::shared_ptr<const GeometryMeshParts>();
17101703 }
17111704 };
17121705
1713−
1714−using packBlendshapeOffsetTo = void(glm::uvec4& packed, const BlendshapeOffsetUnpacked& unpacked);
1715−
1716−void packBlendshapeOffsetTo_Pos_F32_3xSN10_Nor_3xSN10_Tan_3xSN10(glm::uvec4& packed, const BlendshapeOffsetUnpacked& unpacked) {
1706+static void packBlendshapeOffsetTo_Pos_F32_3xSN10_Nor_3xSN10_Tan_3xSN10(glm::uvec4& packed, const BlendshapeOffsetUnpacked& unpacked) {
17171707 float len = glm::compMax(glm::abs(unpacked.positionOffset));
17181708 glm::vec3 normalizedPos(unpacked.positionOffset);
17191709 if (len > 0.0f) {
@@ -1730,125 +1720,143 @@ void packBlendshapeOffsetTo_Pos_F32_3xSN10_Nor_3xSN10_Tan_3xSN10(glm::uvec4& pac · 10 unmodified lines
17301720 );
17311721 }
17321722
1723+static void packBlendshapeOffsets_ref(BlendshapeOffsetUnpacked* unpacked, BlendshapeOffsetPacked* packed, int size) {
1724+ for (int i = 0; i < size; ++i) {
1725+ packBlendshapeOffsetTo_Pos_F32_3xSN10_Nor_3xSN10_Tan_3xSN10((*packed).packedPosNorTan, (*unpacked));
1726+ ++unpacked;
1727+ ++packed;
1728+ }
1729+}
1730+
1731+#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__x86_64__)
1732+//
1733+// Runtime CPU dispatch
1734+//
1735+#include <CPUDetect.h>
1736+
1737+void packBlendshapeOffsets_AVX2(float (*unpacked)[9], uint32_t (*packed)[4], int size);
1738+
1739+static void packBlendshapeOffsets(BlendshapeOffsetUnpacked* unpacked, BlendshapeOffsetPacked* packed, int size) {
1740+ static bool _cpuSupportsAVX2 = cpuSupportsAVX2();
1741+ if (_cpuSupportsAVX2) {
1742+ static_assert(sizeof(BlendshapeOffsetUnpacked) == 9 * sizeof(float), "struct BlendshapeOffsetUnpacked size doesn't match.");
1743+ static_assert(sizeof(BlendshapeOffsetPacked) == 4 * sizeof(uint32_t), "struct BlendshapeOffsetPacked size doesn't match.");
1744+ packBlendshapeOffsets_AVX2((float(*)[9])unpacked, (uint32_t(*)[4])packed, size);
1745+ } else {
1746+ packBlendshapeOffsets_ref(unpacked, packed, size);
1747+ }
1748+}
1749+
1750+#else // portable reference code
1751+static auto& packBlendshapeOffsets = packBlendshapeOffsets_ref;
1752+#endif
1753+
17331754 class Blender : public QRunnable {
17341755 public:
17351756
1736− Blender(ModelPointer model, int blendNumber, const Geometry::WeakPointer& geometry, const QVector<float>& blendshapeCoefficients);
1757+ Blender(ModelPointer model, HFMModel::ConstPointer hfmModel, int blendNumber, const QVector<float>& blendshapeCoefficients);
17371758
17381759 virtual void run() override;
17391760
17401761 private:
1741−
17421762 ModelPointer _model;
1763+ HFMModel::ConstPointer _hfmModel;
17431764 int _blendNumber;
1744− Geometry::WeakPointer _geometry;
17451765 QVector<float> _blendshapeCoefficients;
17461766 };
17471767
1748−Blender::Blender(ModelPointer model, int blendNumber, const Geometry::WeakPointer& geometry, const QVector<float>& blendshapeCoefficients) :
1768+Blender::Blender(ModelPointer model, HFMModel::ConstPointer hfmModel, int blendNumber, const QVector<float>& blendshapeCoefficients) :
17491769 _model(model),
1770+ _hfmModel(hfmModel),
17501771 _blendNumber(blendNumber),
1751− _geometry(geometry),
17521772 _blendshapeCoefficients(blendshapeCoefficients) {
17531773 }
17541774
17551775 void Blender::run() {
1756− QVector<BlendshapeOffset> blendshapeOffsets;
1757− QVector<int> blendedMeshSizes;
1758− if (_model && _model->isLoaded()) {
1759− DETAILED_PROFILE_RANGE_EX(simulation_animation, __FUNCTION__, 0xFFFF0000, 0, { { "url", _model->getURL().toString() } });
1760− int offset = 0;
1761− auto meshes = _model->getHFMModel().meshes;
1762− int meshIndex = 0;
1763− foreach(const HFMMesh& mesh, meshes) {
1764− auto modelMeshBlendshapeOffsets = _model->_blendshapeOffsets.find(meshIndex++);
1765− if (mesh.blendshapes.isEmpty() || modelMeshBlendshapeOffsets == _model->_blendshapeOffsets.end()) {
1766− // Not blendshaped or not initialized
1767− blendedMeshSizes.push_back(0);
1768− continue;
1769− }
1770−
1771− if (mesh.vertices.size() != modelMeshBlendshapeOffsets->second.size()) {
1772− // Mesh sizes don't match. Something has gone wrong
1773− blendedMeshSizes.push_back(0);
1774− continue;
1775− }
1776−
1777− blendshapeOffsets += modelMeshBlendshapeOffsets->second;
1778− BlendshapeOffset* meshBlendshapeOffsets = blendshapeOffsets.data() + offset;
1779− int numVertices = modelMeshBlendshapeOffsets->second.size();
1780− blendedMeshSizes.push_back(numVertices);
1781− offset += numVertices;
1782− std::vector<BlendshapeOffsetUnpacked> unpackedBlendshapeOffsets(modelMeshBlendshapeOffsets->second.size());
1783−
1784− const float NORMAL_COEFFICIENT_SCALE = 0.01f;
1785− for (int i = 0, n = qMin(_blendshapeCoefficients.size(), mesh.blendshapes.size()); i < n; i++) {
1786− float vertexCoefficient = _blendshapeCoefficients.at(i);
1787− const float EPSILON = 0.0001f;
1788− if (vertexCoefficient < EPSILON) {
1789− continue;
1790− }
1776+ DETAILED_PROFILE_RANGE_EX(simulation_animation, __FUNCTION__, 0xFFFF0000, 0, { { "url", _model->getURL().toString() } });
1777+ int numBlendshapeOffsets = 0; // number of offsets required for all meshes.
1778+ int maxBlendshapeOffsets = 0; // number of offsets in the largest mesh.
1779+ int numMeshes = 0; // number of meshes in this model.
1780+ for (auto meshIter = _hfmModel->meshes.cbegin(); meshIter != _hfmModel->meshes.cend(); ++meshIter) {
1781+ numMeshes++;
1782+ if (meshIter->blendshapes.isEmpty()) {
1783+ continue;
1784+ }
1785+ int numVertsInMesh = meshIter->vertices.size();
1786+ numBlendshapeOffsets += numVertsInMesh;
1787+ maxBlendshapeOffsets = std::max(maxBlendshapeOffsets, numVertsInMesh);
1788+ }
17911789
1792− float normalCoefficient = vertexCoefficient * NORMAL_COEFFICIENT_SCALE;
1793− const HFMBlendshape& blendshape = mesh.blendshapes.at(i);
1790+ // allocate the required sizes
1791+ QVector<int> blendedMeshSizes;
1792+ blendedMeshSizes.reserve(numMeshes);
17941793
1795− tbb::parallel_for(tbb::blocked_range<int>(0, blendshape.indices.size()), [&](const tbb::blocked_range<int>& range) {
1796− for (auto j = range.begin(); j < range.end(); j++) {
1797− int index = blendshape.indices.at(j);
1794+ QVector<BlendshapeOffset> packedBlendshapeOffsets;
1795+ packedBlendshapeOffsets.resize(numBlendshapeOffsets);
17981796
1799− auto& currentBlendshapeOffset = unpackedBlendshapeOffsets[index];
1800− currentBlendshapeOffset.positionOffset += blendshape.vertices.at(j) * vertexCoefficient;
1797+ QVector<BlendshapeOffsetUnpacked> unpackedBlendshapeOffsets;
1798+ unpackedBlendshapeOffsets.resize(maxBlendshapeOffsets); // reuse for all meshes
18011799
1802− currentBlendshapeOffset.normalOffset += blendshape.normals.at(j) * normalCoefficient;
1803− if (j < blendshape.tangents.size()) {
1804− currentBlendshapeOffset.tangentOffset += blendshape.tangents.at(j) * normalCoefficient;
1805− }
1806− }
1807− });
1800+ int offset = 0;
1801+ for (auto meshIter = _hfmModel->meshes.cbegin(); meshIter != _hfmModel->meshes.cend(); ++meshIter) {
1802+ if (meshIter->blendshapes.isEmpty()) {
1803+ blendedMeshSizes.push_back(0);
1804+ continue;
1805+ }
1806+ int numVertsInMesh = meshIter->vertices.size();
1807+ blendedMeshSizes.push_back(numVertsInMesh);
1808+
1809+ // initialize offsets to zero
1810+ memset(unpackedBlendshapeOffsets.data(), 0, numVertsInMesh * sizeof(BlendshapeOffsetUnpacked));
1811+
1812+ // for each blendshape in this mesh, accumulate the offsets into unpackedBlendshapeOffsets.
1813+ const float NORMAL_COEFFICIENT_SCALE = 0.01f;
1814+ for (int i = 0, n = qMin(_blendshapeCoefficients.size(), meshIter->blendshapes.size()); i < n; i++) {
1815+ float vertexCoefficient = _blendshapeCoefficients.at(i);
1816+ const float EPSILON = 0.0001f;
1817+ if (vertexCoefficient < EPSILON) {
1818+ continue;
18081819 }
18091820
1810− // Blendshape offsets are generrated, now let's pack it on its way to gpu
1811− tbb::parallel_for(tbb::blocked_range<int>(0, (int) unpackedBlendshapeOffsets.size()), [&](const tbb::blocked_range<int>& range) {
1812− auto unpacked = unpackedBlendshapeOffsets.data() + range.begin();
1813− auto packed = meshBlendshapeOffsets + range.begin();
1814− for (auto j = range.begin(); j < range.end(); j++) {
1815− packBlendshapeOffsetTo_Pos_F32_3xSN10_Nor_3xSN10_Tan_3xSN10((*packed).packedPosNorTan, (*unpacked));
1821+ float normalCoefficient = vertexCoefficient * NORMAL_COEFFICIENT_SCALE;
1822+ const HFMBlendshape& blendshape = meshIter->blendshapes.at(i);
1823+ for (int j = 0; j < blendshape.indices.size(); ++j) {
1824+ int index = blendshape.indices.at(j);
18161825
1817− unpacked++;
1818− packed++;
1826+ auto& currentBlendshapeOffset = unpackedBlendshapeOffsets[index];
1827+ currentBlendshapeOffset.positionOffset += blendshape.vertices.at(j) * vertexCoefficient;
1828+ currentBlendshapeOffset.normalOffset += blendshape.normals.at(j) * normalCoefficient;
1829+ if (j < blendshape.tangents.size()) {
1830+ currentBlendshapeOffset.tangentOffset += blendshape.tangents.at(j) * normalCoefficient;
18191831 }
1820− });
1832+ }
18211833 }
1834+
1835+ // convert unpackedBlendshapeOffsets into packedBlendshapeOffsets for the gpu.
1836+ auto unpacked = unpackedBlendshapeOffsets.data();
1837+ auto packed = packedBlendshapeOffsets.data() + offset;
1838+ packBlendshapeOffsets(unpacked, packed, numVertsInMesh);
1839+
1840+ offset += numVertsInMesh;
18221841 }
1842+ Q_ASSERT(offset == numBlendshapeOffsets);
1843+
18231844 // post the result to the ModelBlender, which will dispatch to the model if still alive
18241845 QMetaObject::invokeMethod(DependencyManager::get<ModelBlender>().data(), "setBlendedVertices",
1825− Q_ARG(ModelPointer, _model), Q_ARG(int, _blendNumber), Q_ARG(QVector<BlendshapeOffset>, blendshapeOffsets), Q_ARG(QVector<int>, blendedMeshSizes));
1846+ Q_ARG(ModelPointer, _model), Q_ARG(int, _blendNumber),
1847+ Q_ARG(QVector<BlendshapeOffset>, packedBlendshapeOffsets),
1848+ Q_ARG(QVector<int>, blendedMeshSizes));
18261849 }
18271850
18281851 bool Model::maybeStartBlender() {
18291852 if (isLoaded()) {
1830− QThreadPool::globalInstance()->start(new Blender(getThisPointer(), ++_blendNumber, _renderGeometry, _blendshapeCoefficients));
1853+ QThreadPool::globalInstance()->start(new Blender(getThisPointer(), getNetworkModel()->getConstHFMModelPointer(),
1854+ ++_blendNumber, _blendshapeCoefficients));
18311855 return true;
18321856 }
18331857 return false;
18341858 }
18351859
1836−void Model::initializeBlendshapes(const HFMMesh& mesh, int index) {
1837− if (mesh.blendshapes.empty()) {
1838− // mesh doesn't have blendshape, did we allocate one though ?
1839− if (_blendshapeOffsets.find(index) != _blendshapeOffsets.end()) {
1840− qWarning() << "Mesh does not have Blendshape yet the blendshapeOffsets are allocated ?";
1841− }
1842− return;
1843− }
1844− // Mesh has blendshape, let s allocate the local buffer if not done yet
1845− if (_blendshapeOffsets.find(index) == _blendshapeOffsets.end()) {
1846− QVector<BlendshapeOffset> blendshapeOffset;
1847− blendshapeOffset.fill(BlendshapeOffset(), mesh.vertices.size());
1848− _blendshapeOffsets[index] = blendshapeOffset;
1849− }
1850−}
1851−
18521860 ModelBlender::ModelBlender() :
18531861 _pendingBlenders(0) {
18541862 }