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
39#include "RenderUtilsLogging.h"39#include "RenderUtilsLogging.h"
40#include <Trace.h>40#include <Trace.h>
41 41
42#include <BlendshapeConstants.h>
43
42using namespace std;44using namespace std;
43 45
44int nakedModelPointerTypeId = qRegisterMetaType<ModelPointer>();46int nakedModelPointerTypeId = qRegisterMetaType<ModelPointer>();
45int weakGeometryResourceBridgePointerTypeId = qRegisterMetaType<Geometry::WeakPointer>();47int weakGeometryResourceBridgePointerTypeId = qRegisterMetaType<NetworkModel::WeakPointer>();
46int vec3VectorTypeId = qRegisterMetaType<QVector<glm::vec3>>();48int vec3VectorTypeId = qRegisterMetaType<QVector<glm::vec3>>();
47int normalTypeVecTypeId = qRegisterMetaType<QVector<NormalType>>("QVector<NormalType>");49int normalTypeVecTypeId = qRegisterMetaType<QVector<NormalType>>("QVector<NormalType>");
48float Model::FAKE_DIMENSION_PLACEHOLDER = -1.0f;50float Model::FAKE_DIMENSION_PLACEHOLDER = -1.0f;
49#define HTTP_INVALID_COM "http://invalid.com"51#define HTTP_INVALID_COM "http://invalid.com"
50 52
51Model::Model(QObject* parent, SpatiallyNestable* spatiallyNestableOverride) :53Model::Model(QObject* parent, SpatiallyNestable* spatiallyNestableOverride, uint64_t created) :
52 QObject(parent),54 QObject(parent),
53 _renderGeometry(),55 _renderGeometry(),
54 _renderWatcher(_renderGeometry),56 _renderWatcher(_renderGeometry),
@@ -62,7 +64,8 @@ Model::Model(QObject* parent, SpatiallyNestable* spatiallyNestableOverride) : · 7 unmodified lines
62 _snapModelToRegistrationPoint(false),64 _snapModelToRegistrationPoint(false),
63 _snappedToRegistrationPoint(false),65 _snappedToRegistrationPoint(false),
64 _url(HTTP_INVALID_COM),66 _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)
66{69{
67 // we may have been created in the network thread, but we live in the main thread70 // we may have been created in the network thread, but we live in the main thread
68 if (_viewState) {71 if (_viewState) {
@@ -71,7 +74,7 @@ Model::Model(QObject* parent, SpatiallyNestable* spatiallyNestableOverride) : · 2 unmodified lines
71 74
72 setSnapModelToRegistrationPoint(true, glm::vec3(0.5f));75 setSnapModelToRegistrationPoint(true, glm::vec3(0.5f));
73 76
74 connect(&_renderWatcher, &GeometryResourceWatcher::finished, this, &Model::loadURLFinished);77 connect(&_renderWatcher, &ModelResourceWatcher::finished, this, &Model::loadURLFinished);
75}78}
76 79
77Model::~Model() {80Model::~Model() {
@@ -151,7 +154,7 @@ void Model::setOffset(const glm::vec3& offset) { · 73 unmodified lines
151}154}
152 155
153void Model::calculateTextureInfo() {156void Model::calculateTextureInfo() {
154 if (!_hasCalculatedTextureInfo && isLoaded() && getGeometry()->areTexturesLoaded() && !_modelMeshRenderItems.isEmpty()) {157 if (!_hasCalculatedTextureInfo && isLoaded() && getNetworkModel()->areTexturesLoaded() && !_modelMeshRenderItems.isEmpty()) {
155 size_t textureSize = 0;158 size_t textureSize = 0;
156 int textureCount = 0;159 int textureCount = 0;
157 bool allTexturesLoaded = true;160 bool allTexturesLoaded = true;
@@ -178,15 +181,15 @@ int Model::getRenderInfoTextureCount() { · 20 unmodified lines
178}181}
179 182
180bool Model::shouldInvalidatePayloadShapeKey(int meshIndex) {183bool Model::shouldInvalidatePayloadShapeKey(int meshIndex) {
181 if (!getGeometry()) {184 if (!getNetworkModel()) {
182 return true;185 return true;
183 }186 }
184 187
185 const HFMModel& hfmModel = getHFMModel();188 const HFMModel& hfmModel = getHFMModel();
186 const auto& networkMeshes = getGeometry()->getMeshes();189 const auto& networkMeshes = getNetworkModel()->getMeshes();
187 // if our index is ever out of range for either meshes or networkMeshes, then skip it, and set our _meshGroupsKnown190 // if our index is ever out of range for either meshes or networkMeshes, then skip it, and set our _meshGroupsKnown
188 // to false to rebuild out mesh groups.191 // 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()) {
190 _needsFixupInScene = true; // trigger remove/add cycle193 _needsFixupInScene = true; // trigger remove/add cycle
191 invalidCalculatedMeshBoxes(); // if we have to reload, we need to assume our mesh boxes are all invalid194 invalidCalculatedMeshBoxes(); // if we have to reload, we need to assume our mesh boxes are all invalid
192 return true;195 return true;
@@ -228,44 +231,45 @@ void Model::updateRenderItems() { · 35 unmodified lines
228 231
229 render::Transaction transaction;232 render::Transaction transaction;
230 for (int i = 0; i < (int) self->_modelMeshRenderItemIDs.size(); i++) {233 for (int i = 0; i < (int) self->_modelMeshRenderItemIDs.size(); i++) {
231
232 auto itemID = self->_modelMeshRenderItemIDs[i];234 auto itemID = self->_modelMeshRenderItemIDs[i];
233 auto meshIndex = self->_modelMeshRenderItemShapes[i].meshIndex;
234 235
235 const auto& meshState = self->getMeshState(meshIndex);236 const auto& shapeState = self->getShapeState(i);
236 237
237 bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(meshIndex);238 auto skinDeformerIndex = shapeState._skinDeformerIndex;
238 bool useDualQuaternionSkinning = self->getUseDualQuaternionSkinning();
239 239
240 transaction.updateItem<ModelMeshPartPayload>(itemID, [modelTransform, meshState, useDualQuaternionSkinning,240 bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(shapeState._meshIndex);
241 invalidatePayloadShapeKey, primitiveMode, renderItemKeyGlobalFlags, cauterized](ModelMeshPartPayload& data) {
242 if (useDualQuaternionSkinning) {
243 data.updateClusterBuffer(meshState.clusterDualQuaternions);
244 } else {
245 data.updateClusterBuffer(meshState.clusterMatrices);
246 }
247 241
248 Transform renderTransform = modelTransform;242 if (skinDeformerIndex != hfm::UNDEFINED_KEY) {
243 const auto& meshState = self->getMeshState(skinDeformerIndex);
244 bool useDualQuaternionSkinning = self->getUseDualQuaternionSkinning();
249 245
250 if (useDualQuaternionSkinning) {246 transaction.updateItem<ModelMeshPartPayload>(itemID, [modelTransform, shapeState, meshState, useDualQuaternionSkinning,
251 if (meshState.clusterDualQuaternions.size() == 1 || meshState.clusterDualQuaternions.size() == 2) {247 invalidatePayloadShapeKey, primitiveMode, renderItemKeyGlobalFlags, cauterized](ModelMeshPartPayload& data) {
252 const auto& dq = meshState.clusterDualQuaternions[0];248 if (useDualQuaternionSkinning) {
253 Transform transform(dq.getRotation(),249 data.updateClusterBuffer(meshState.clusterDualQuaternions);
254 dq.getScale(),250 } else {
255 dq.getTranslation());251 data.updateClusterBuffer(meshState.clusterMatrices);
256 renderTransform = modelTransform.worldTransform(Transform(transform));
257 }252 }
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);
264 253
265 data.setCauterized(cauterized);254 Transform renderTransform = modelTransform;
266 data.updateKey(renderItemKeyGlobalFlags);255 data.updateTransform(renderTransform);
267 data.setShapeKey(invalidatePayloadShapeKey, primitiveMode, useDualQuaternionSkinning);256 data.updateTransformAndBound(modelTransform.worldTransform(shapeState._rootFromJointTransform));
268 });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 }
269 }273 }
270 274
271 AbstractViewStateInterface::instance()->getMain3DScene()->enqueueTransaction(transaction);275 AbstractViewStateInterface::instance()->getMain3DScene()->enqueueTransaction(transaction);
@@ -291,6 +295,15 @@ void Model::reset() { · 19 unmodified lines
291 }295 }
292}296}
293 297
298void 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
294bool Model::updateGeometry() {307bool Model::updateGeometry() {
295 bool needFullUpdate = false;308 bool needFullUpdate = false;
296 309
@@ -306,16 +319,27 @@ bool Model::updateGeometry() { · 9 unmodified lines
306 assert(_meshStates.empty());319 assert(_meshStates.empty());
307 320
308 const HFMModel& hfmModel = getHFMModel();321 const HFMModel& hfmModel = getHFMModel();
309 int i = 0;322
310 foreach (const HFMMesh& mesh, hfmModel.meshes) {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];
311 MeshState state;337 MeshState state;
312 state.clusterDualQuaternions.resize(mesh.clusters.size());338 state.clusterDualQuaternions.resize(dynT.clusters.size());
313 state.clusterMatrices.resize(mesh.clusters.size());339 state.clusterMatrices.resize(dynT.clusters.size());
314 _meshStates.push_back(state);340 _meshStates.push_back(state);
315 initializeBlendshapes(mesh, i);
316 i++;
317 }341 }
318 _blendshapeOffsetsInitialized = true;342
319 needFullUpdate = true;343 needFullUpdate = true;
320 emit rigReady();344 emit rigReady();
321 }345 }
@@ -445,7 +469,7 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g · 123 unmodified lines
445 }469 }
446 470
447 /**jsdoc471 /**jsdoc
448 * Information about a submesh intersection point.472 * A submesh intersection point.
449 * @typedef {object} SubmeshIntersection473 * @typedef {object} SubmeshIntersection
450 * @property {Vec3} worldIntersectionPoint - The intersection point in world coordinates.474 * @property {Vec3} worldIntersectionPoint - The intersection point in world coordinates.
451 * @property {Vec3} meshIntersectionPoint - The intersection point in model coordinates.475 * @property {Vec3} meshIntersectionPoint - The intersection point in model coordinates.
@@ -643,8 +667,8 @@ glm::mat4 Model::getWorldToHFMMatrix() const { · 191 unmodified lines
643// TODO: deprecate and remove667// TODO: deprecate and remove
644MeshProxyList Model::getMeshes() const {668MeshProxyList Model::getMeshes() const {
645 MeshProxyList result;669 MeshProxyList result;
646 const Geometry::Pointer& renderGeometry = getGeometry();670 const NetworkModel::Pointer& renderGeometry = getNetworkModel();
647 const Geometry::GeometryMeshes& meshes = renderGeometry->getMeshes();671 const NetworkModel::GeometryMeshes& meshes = renderGeometry->getMeshes();
648 672
649 if (!isLoaded()) {673 if (!isLoaded()) {
650 return result;674 return result;
@@ -713,9 +737,9 @@ bool Model::replaceScriptableModelMeshPart(scriptable::ScriptableModelBasePointe · 62 unmodified lines
713 render::Transaction transaction;737 render::Transaction transaction;
714 for (int i = 0; i < (int) _modelMeshRenderItemIDs.size(); i++) {738 for (int i = 0; i < (int) _modelMeshRenderItemIDs.size(); i++) {
715 auto itemID = _modelMeshRenderItemIDs[i];739 auto itemID = _modelMeshRenderItemIDs[i];
716 auto shape = _modelMeshRenderItemShapes[i];740 auto& shape = _shapeStates[i];
717 // TODO: check to see if .partIndex matches too741 // TODO: check to see if .partIndex matches too
718 if (shape.meshIndex == meshIndex) {742 if (shape._meshIndex == (uint32_t) meshIndex) {
719 transaction.updateItem<ModelMeshPartPayload>(itemID, [=](ModelMeshPartPayload& data) {743 transaction.updateItem<ModelMeshPartPayload>(itemID, [=](ModelMeshPartPayload& data) {
720 data.updateMeshPart(mesh, partIndex);744 data.updateMeshPart(mesh, partIndex);
721 });745 });
@@ -734,7 +758,7 @@ bool Model::replaceScriptableModelMeshPart(scriptable::ScriptableModelBasePointe · 12 unmodified lines
734 for (int partID = 0; partID < numParts; partID++) {758 for (int partID = 0; partID < numParts; partID++) {
735 HFMMeshPart part;759 HFMMeshPart part;
736 part.triangleIndices = buffer_helpers::bufferToVector<int>(mesh._mesh->getIndexBuffer(), "part.triangleIndices");760 part.triangleIndices = buffer_helpers::bufferToVector<int>(mesh._mesh->getIndexBuffer(), "part.triangleIndices");
737 mesh.parts << part;761 mesh.parts.push_back(part);
738 }762 }
739 {763 {
740 foreach (const glm::vec3& vertex, mesh.vertices) {764 foreach (const glm::vec3& vertex, mesh.vertices) {
@@ -745,7 +769,7 @@ bool Model::replaceScriptableModelMeshPart(scriptable::ScriptableModelBasePointe · 4 unmodified lines
745 mesh.meshExtents.maximum = glm::max(mesh.meshExtents.maximum, transformedVertex);769 mesh.meshExtents.maximum = glm::max(mesh.meshExtents.maximum, transformedVertex);
746 }770 }
747 }771 }
748 hfmModel.meshes << mesh;772 hfmModel.meshes.push_back(mesh);
749 }773 }
750 calculateTriangleSets(hfmModel);774 calculateTriangleSets(hfmModel);
751 }775 }
@@ -762,9 +786,9 @@ scriptable::ScriptableModelBase Model::getScriptableModel() { · 10 unmodified lines
762 }786 }
763 787
764 const HFMModel& hfmModel = getHFMModel();788 const HFMModel& hfmModel = getHFMModel();
765 int numberOfMeshes = hfmModel.meshes.size();789 uint32_t numberOfMeshes = (uint32_t)hfmModel.meshes.size();
766 int shapeID = 0;790 int shapeID = 0;
767 for (int i = 0; i < numberOfMeshes; i++) {791 for (uint32_t i = 0; i < numberOfMeshes; i++) {
768 const HFMMesh& hfmMesh = hfmModel.meshes.at(i);792 const HFMMesh& hfmMesh = hfmModel.meshes.at(i);
769 if (auto mesh = hfmMesh._mesh) {793 if (auto mesh = hfmMesh._mesh) {
770 result.append(mesh);794 result.append(mesh);
@@ -772,13 +796,16 @@ scriptable::ScriptableModelBase Model::getScriptableModel() { · 1 unmodified line
772 int numParts = (int)mesh->getNumParts();796 int numParts = (int)mesh->getNumParts();
773 for (int partIndex = 0; partIndex < numParts; partIndex++) {797 for (int partIndex = 0; partIndex < numParts; partIndex++) {
774 auto& materialName = _modelMeshMaterialNames[shapeID];798 auto& materialName = _modelMeshMaterialNames[shapeID];
775 result.appendMaterial(graphics::MaterialLayer(getGeometry()->getShapeMaterial(shapeID), 0), shapeID, materialName);799 result.appendMaterial(graphics::MaterialLayer(getNetworkModel()->getShapeMaterial(shapeID), 0), shapeID, materialName);
776 800
777 auto mappedMaterialIter = _materialMapping.find(shapeID);801 {
778 if (mappedMaterialIter != _materialMapping.end()) {802 std::unique_lock<std::mutex> lock(_materialMappingMutex);
779 auto mappedMaterials = mappedMaterialIter->second;803 auto mappedMaterialIter = _materialMapping.find(shapeID);
780 for (auto& mappedMaterial : mappedMaterials) {804 if (mappedMaterialIter != _materialMapping.end()) {
781 result.appendMaterial(mappedMaterial, shapeID, materialName);805 auto mappedMaterials = mappedMaterialIter->second;
806 for (auto& mappedMaterial : mappedMaterials) {
807 result.appendMaterial(mappedMaterial, shapeID, materialName);
808 }
782 }809 }
783 }810 }
784 shapeID++;811 shapeID++;
@@ -792,78 +819,70 @@ scriptable::ScriptableModelBase Model::getScriptableModel() { · 7 unmodified lines
792void Model::calculateTriangleSets(const HFMModel& hfmModel) {819void Model::calculateTriangleSets(const HFMModel& hfmModel) {
793 PROFILE_RANGE(render, __FUNCTION__);820 PROFILE_RANGE(render, __FUNCTION__);
794 821
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 }
796 830
797 _triangleSetsValid = true;831 _triangleSetsValid = true;
798 _modelSpaceMeshTriangleSets.clear();832 _modelSpaceMeshTriangleSets.clear();
799 _modelSpaceMeshTriangleSets.resize(numberOfMeshes);833 _modelSpaceMeshTriangleSets.reserve(meshInstanceCount);
800 834
801 for (int i = 0; i < numberOfMeshes; i++) {835 uint32_t lastMeshForTriangleBuilding = hfm::UNDEFINED_KEY;
802 const HFMMesh& mesh = hfmModel.meshes.at(i);836 glm::mat4 lastTransformForTriangleBuilding { 0 };
803 837 std::vector<glm::vec3> transformedPoints;
804 const int numberOfParts = mesh.parts.size();838 for (const auto& shape : hfmModel.shapes) {
805 auto& meshTriangleSets = _modelSpaceMeshTriangleSets[i];839 const uint32_t meshIndex = shape.mesh;
806 meshTriangleSets.resize(numberOfParts);840 const hfm::Mesh& mesh = hfmModel.meshes.at(meshIndex);
807 841 const auto& triangleListMesh = mesh.triangleListMesh;
808 for (int j = 0; j < numberOfParts; j++) {842 const glm::vec2 part = triangleListMesh.parts[shape.meshPart];
809 const HFMMeshPart& part = mesh.parts.at(j);843 glm::mat4 worldFromMeshTransform;
810 844 if (shape.joint != hfm::UNDEFINED_KEY) {
811 auto& partTriangleSet = meshTriangleSets[j];845 // globalTransform includes hfmModel.offset,
812 846 // which includes the scaling, rotation, and translation specified by the FST,
813 const int INDICES_PER_TRIANGLE = 3;847 // and the scaling from the unit conversion in FBX.
814 const int INDICES_PER_QUAD = 4;848 // This can't change at runtime, so we can safely store these in our TriangleSet.
815 const int TRIANGLES_PER_QUAD = 2;849 worldFromMeshTransform = hfmModel.joints[shape.joint].globalTransform;
816 850 }
817 // tell our triangleSet how many triangles to expect.851
818 int numberOfQuads = part.quadIndices.size() / INDICES_PER_QUAD;852 if (meshIndex != lastMeshForTriangleBuilding || worldFromMeshTransform != lastTransformForTriangleBuilding) {
819 int numberOfTris = part.triangleIndices.size() / INDICES_PER_TRIANGLE;853 lastMeshForTriangleBuilding = meshIndex;
820 int totalTriangles = (numberOfQuads * TRIANGLES_PER_QUAD) + numberOfTris;854 lastTransformForTriangleBuilding = worldFromMeshTransform;
821 partTriangleSet.reserve(totalTriangles);855 _modelSpaceMeshTriangleSets.emplace_back();
822 856 _modelSpaceMeshTriangleSets.back().reserve(mesh.parts.size());
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 }
847 857
848 if (part.triangleIndices.size() > 0) {858 transformedPoints = triangleListMesh.vertices;
849 int vIndex = 0;859 if (worldFromMeshTransform != glm::mat4()) {
850 for (int t = 0; t < numberOfTris; t++) {860 for (auto& point : transformedPoints) {
851 int i0 = part.triangleIndices[vIndex++];861 point = glm::vec3(worldFromMeshTransform * glm::vec4(point, 1.0f));
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);
864 }862 }
865 }863 }
866 }864 }
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 }
867 }886 }
868}887}
869 888
@@ -874,8 +893,8 @@ void Model::updateRenderItemsKey(const render::ScenePointer& scene) { · 4 unmodified lines
874 }893 }
875 auto renderItemsKey = _renderItemKeyGlobalFlags;894 auto renderItemsKey = _renderItemKeyGlobalFlags;
876 render::Transaction transaction;895 render::Transaction transaction;
877 foreach(auto item, _modelMeshRenderItemsMap.keys()) {896 for(auto itemID: _modelMeshRenderItemIDs) {
878 transaction.updateItem<ModelMeshPartPayload>(item, [renderItemsKey](ModelMeshPartPayload& data) {897 transaction.updateItem<ModelMeshPartPayload>(itemID, [renderItemsKey](ModelMeshPartPayload& data) {
879 data.updateKey(renderItemsKey);898 data.updateKey(renderItemsKey);
880 });899 });
881 }900 }
@@ -945,8 +964,8 @@ void Model::setCauterized(bool cauterized, const render::ScenePointer& scene) { · 63 unmodified lines
945 return;964 return;
946 }965 }
947 render::Transaction transaction;966 render::Transaction transaction;
948 foreach (auto item, _modelMeshRenderItemsMap.keys()) {967 for (auto itemID : _modelMeshRenderItemIDs) {
949 transaction.updateItem<ModelMeshPartPayload>(item, [cauterized](ModelMeshPartPayload& data) {968 transaction.updateItem<ModelMeshPartPayload>(itemID, [cauterized](ModelMeshPartPayload& data) {
950 data.setCauterized(cauterized);969 data.setCauterized(cauterized);
951 });970 });
952 }971 }
@@ -976,7 +995,9 @@ bool Model::addToScene(const render::ScenePointer& scene, · 23 unmodified lines
976 render::Transaction& transaction,995 render::Transaction& transaction,
977 render::Item::Status::Getters& statusGetters,996 render::Item::Status::Getters& statusGetters,
978 BlendShapeOperator modelBlendshapeOperator) {997 BlendShapeOperator modelBlendshapeOperator) {
998
979 if (!_addedToScene && isLoaded()) {999 if (!_addedToScene && isLoaded()) {
1000 updateGeometry();
980 updateClusterMatrices();1001 updateClusterMatrices();
981 if (_modelMeshRenderItems.empty()) {1002 if (_modelMeshRenderItems.empty()) {
982 createRenderItemSet();1003 createRenderItemSet();
@@ -987,26 +1008,25 @@ bool Model::addToScene(const render::ScenePointer& scene, · 4 unmodified lines
987 1008
988 bool somethingAdded = false;1009 bool somethingAdded = false;
989 1010
990 if (_modelMeshRenderItemsMap.empty()) {1011 if (_modelMeshRenderItemIDs.empty()) {
991 bool hasTransparent = false;1012 bool hasTransparent = false;
992 size_t verticesCount = 0;1013 size_t verticesCount = 0;
993 foreach(auto renderItem, _modelMeshRenderItems) {1014 foreach(auto renderItem, _modelMeshRenderItems) {
994 auto item = scene->allocateID();1015 auto item = scene->allocateID();
995 auto renderPayload = std::make_shared<ModelMeshPartPayload::Payload>(renderItem);1016 auto renderPayload = std::make_shared<ModelMeshPartPayload::Payload>(renderItem);
996 if (_modelMeshRenderItemsMap.empty() && statusGetters.size()) {1017 if (_modelMeshRenderItemIDs.empty() && statusGetters.size()) {
997 renderPayload->addStatusGetters(statusGetters);1018 renderPayload->addStatusGetters(statusGetters);
998 }1019 }
999 transaction.resetItem(item, renderPayload);1020 transaction.resetItem(item, renderPayload);
1000 1021
1001 hasTransparent = hasTransparent || renderItem.get()->getShapeKey().isTranslucent();1022 hasTransparent = hasTransparent || renderItem.get()->getShapeKey().isTranslucent();
1002 verticesCount += renderItem.get()->getVerticesCount();1023 verticesCount += renderItem.get()->getVerticesCount();
1003 _modelMeshRenderItemsMap.insert(item, renderPayload);
1004 _modelMeshRenderItemIDs.emplace_back(item);1024 _modelMeshRenderItemIDs.emplace_back(item);
1005 }1025 }
1006 somethingAdded = !_modelMeshRenderItemsMap.empty();1026 somethingAdded = !_modelMeshRenderItemIDs.empty();
1007 1027
1008 _renderInfoVertexCount = verticesCount;1028 _renderInfoVertexCount = verticesCount;
1009 _renderInfoDrawCalls = _modelMeshRenderItemsMap.count();1029 _renderInfoDrawCalls = (uint32_t) _modelMeshRenderItemIDs.size();
1010 _renderInfoHasTransparent = hasTransparent;1030 _renderInfoHasTransparent = hasTransparent;
1011 }1031 }
1012 1032
@@ -1021,19 +1041,14 @@ bool Model::addToScene(const render::ScenePointer& scene, · 8 unmodified lines
1021}1041}
1022 1042
1023void Model::removeFromScene(const render::ScenePointer& scene, render::Transaction& transaction) {1043void Model::removeFromScene(const render::ScenePointer& scene, render::Transaction& transaction) {
1024 foreach (auto item, _modelMeshRenderItemsMap.keys()) {1044 for (auto itemID: _modelMeshRenderItemIDs) {
1025 transaction.removeItem(item);1045 transaction.removeItem(itemID);
1026 }1046 }
1027 _modelMeshRenderItemIDs.clear();1047 _modelMeshRenderItemIDs.clear();
1028 _modelMeshRenderItemsMap.clear();
1029 _modelMeshRenderItems.clear();1048 _modelMeshRenderItems.clear();
1030 _modelMeshMaterialNames.clear();1049 _modelMeshMaterialNames.clear();
1031 _modelMeshRenderItemShapes.clear();
1032 _priorityMap.clear();1050 _priorityMap.clear();
1033 1051
1034 _blendshapeOffsets.clear();
1035 _blendshapeOffsetsInitialized = false;
1036
1037 _addedToScene = false;1052 _addedToScene = false;
1038 1053
1039 _renderInfoVertexCount = 0;1054 _renderInfoVertexCount = 0;
@@ -1042,7 +1057,7 @@ void Model::removeFromScene(const render::ScenePointer& scene, render::Transacti · 2 unmodified lines
1042 _renderInfoHasTransparent = false;1057 _renderInfoHasTransparent = false;
1043}1058}
1044 1059
1045void Model::renderDebugMeshBoxes(gpu::Batch& batch) {1060void Model::renderDebugMeshBoxes(gpu::Batch& batch, bool forward) {
1046 int colorNdx = 0;1061 int colorNdx = 0;
1047 _mutex.lock();1062 _mutex.lock();
1048 1063
@@ -1051,7 +1066,7 @@ void Model::renderDebugMeshBoxes(gpu::Batch& batch) { · 2 unmodified lines
1051 Transform meshToWorld(meshToWorldMatrix);1066 Transform meshToWorld(meshToWorldMatrix);
1052 batch.setModelTransform(meshToWorld);1067 batch.setModelTransform(meshToWorld);
1053 1068
1054 DependencyManager::get<GeometryCache>()->bindSimpleProgram(batch, false, false, false, true, true);1069 DependencyManager::get<GeometryCache>()->bindSimpleProgram(batch, false, false, false, true, true, forward);
1055 1070
1056 for (auto& meshTriangleSets : _modelSpaceMeshTriangleSets) {1071 for (auto& meshTriangleSets : _modelSpaceMeshTriangleSets) {
1057 for (auto &partTriangleSet : meshTriangleSets) {1072 for (auto &partTriangleSet : meshTriangleSets) {
@@ -1210,7 +1225,7 @@ void Model::setURL(const QUrl& url) { · 152 unmodified lines
1210 invalidCalculatedMeshBoxes();1225 invalidCalculatedMeshBoxes();
1211 deleteGeometry();1226 deleteGeometry();
1212 1227
1213 auto resource = DependencyManager::get<ModelCache>()->getGeometryResource(url);1228 auto resource = DependencyManager::get<ModelCache>()->getModelResource(url);
1214 if (resource) {1229 if (resource) {
1215 resource->setLoadPriority(this, _loadingPriority);1230 resource->setLoadPriority(this, _loadingPriority);
1216 _renderWatcher.setResource(resource);1231 _renderWatcher.setResource(resource);
@@ -1381,8 +1396,6 @@ void Model::simulate(float deltaTime, bool fullUpdate) { · 164 unmodified lines
1381 // update the world space transforms for all joints1396 // update the world space transforms for all joints
1382 glm::mat4 parentTransform = glm::scale(_scale) * glm::translate(_offset);1397 glm::mat4 parentTransform = glm::scale(_scale) * glm::translate(_offset);
1383 updateRig(deltaTime, parentTransform);1398 updateRig(deltaTime, parentTransform);
1384
1385 computeMeshPartLocalBounds();
1386 }1399 }
1387}1400}
1388 1401
@@ -1393,17 +1406,6 @@ void Model::updateRig(float deltaTime, glm::mat4 parentTransform) { · 4 unmodified lines
1393 _rig.updateAnimations(deltaTime, parentTransform, rigToWorldTransform);1406 _rig.updateAnimations(deltaTime, parentTransform, rigToWorldTransform);
1394}1407}
1395 1408
1396void 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
1407// virtual1409// virtual
1408void Model::updateClusterMatrices() {1410void Model::updateClusterMatrices() {
1409 DETAILED_PERFORMANCE_TIMER("Model::updateClusterMatrices");1411 DETAILED_PERFORMANCE_TIMER("Model::updateClusterMatrices");
@@ -1412,32 +1414,32 @@ void Model::updateClusterMatrices() { · 2 unmodified lines
1412 return;1414 return;
1413 }1415 }
1414 1416
1417 updateShapeStatesFromRig();
1418
1415 _needsUpdateClusterMatrices = false;1419 _needsUpdateClusterMatrices = false;
1416 const HFMModel& hfmModel = getHFMModel();1420
1417 for (int i = 0; i < (int) _meshStates.size(); i++) {1421 for (int skinDeformerIndex = 0; skinDeformerIndex < (int)_meshStates.size(); skinDeformerIndex++) {
1418 MeshState& state = _meshStates[i];1422 MeshState& state = _meshStates[skinDeformerIndex];
1419 int meshIndex = i;1423 auto numClusters = state.getNumClusters();
1420 const HFMMesh& mesh = hfmModel.meshes.at(i);1424 for (uint32_t clusterIndex = 0; clusterIndex < numClusters; clusterIndex++) {
1421 for (int j = 0; j < mesh.clusters.size(); j++) {1425 const auto& cbmov = _rig.getAnimSkeleton()->getClusterBindMatricesOriginalValues(skinDeformerIndex, clusterIndex);
1422 const HFMCluster& cluster = mesh.clusters.at(j);
1423 int clusterIndex = j;
1424 1426
1425 if (_useDualQuaternionSkinning) {1427 if (_useDualQuaternionSkinning) {
1426 auto jointPose = _rig.getJointPose(cluster.jointIndex);1428 auto jointPose = _rig.getJointPose(cbmov.jointIndex);
1427 Transform jointTransform(jointPose.rot(), jointPose.scale(), jointPose.trans());1429 Transform jointTransform(jointPose.rot(), jointPose.scale(), jointPose.trans());
1428 Transform clusterTransform;1430 Transform clusterTransform;
1429 Transform::mult(clusterTransform, jointTransform, _rig.getAnimSkeleton()->getClusterBindMatricesOriginalValues(meshIndex, clusterIndex).inverseBindTransform);1431 Transform::mult(clusterTransform, jointTransform, cbmov.inverseBindTransform);
1430 state.clusterDualQuaternions[j] = Model::TransformDualQuaternion(clusterTransform);1432 state.clusterDualQuaternions[clusterIndex] = Model::TransformDualQuaternion(clusterTransform);
1431 } else {1433 } else {
1432 auto jointMatrix = _rig.getJointTransform(cluster.jointIndex);1434 auto jointMatrix = _rig.getJointTransform(cbmov.jointIndex);
1433 glm_mat4u_mul(jointMatrix, _rig.getAnimSkeleton()->getClusterBindMatricesOriginalValues(meshIndex, clusterIndex).inverseBindMatrix, state.clusterMatrices[j]);1435 glm_mat4u_mul(jointMatrix, cbmov.inverseBindMatrix, state.clusterMatrices[clusterIndex]);
1434 }1436 }
1435 }1437 }
1436 }1438 }
1437 1439
1438 // post the blender if we're not currently waiting for one to finish1440 // post the blender if we're not currently waiting for one to finish
1439 auto modelBlender = DependencyManager::get<ModelBlender>();1441 auto modelBlender = DependencyManager::get<ModelBlender>();
1440 if (_blendshapeOffsetsInitialized && modelBlender->shouldComputeBlendshapes() && hfmModel.hasBlendedMeshes() && _blendshapeCoefficients != _blendedBlendshapeCoefficients) {1442 if (modelBlender->shouldComputeBlendshapes() && getHFMModel().hasBlendedMeshes() && _blendshapeCoefficients != _blendedBlendshapeCoefficients) {
1441 _blendedBlendshapeCoefficients = _blendshapeCoefficients;1443 _blendedBlendshapeCoefficients = _blendshapeCoefficients;
1442 modelBlender->noteRequiresBlend(getThisPointer());1444 modelBlender->noteRequiresBlend(getThisPointer());
1443 }1445 }
@@ -1445,8 +1447,7 @@ void Model::updateClusterMatrices() { · 1 unmodified line
1445 1447
1446void Model::deleteGeometry() {1448void Model::deleteGeometry() {
1447 _deleteGeometryCounter++;1449 _deleteGeometryCounter++;
1448 _blendshapeOffsets.clear();1450 _shapeStates.clear();
1449 _blendshapeOffsetsInitialized = false;
1450 _meshStates.clear();1451 _meshStates.clear();
1451 _rig.destroyAnimGraph();1452 _rig.destroyAnimGraph();
1452 _blendedBlendshapeCoefficients.clear();1453 _blendedBlendshapeCoefficients.clear();
@@ -1480,20 +1481,12 @@ const render::ItemIDs& Model::fetchRenderItemIDs() const { · 27 unmodified lines
1480 1481
1481void Model::createRenderItemSet() {1482void Model::createRenderItemSet() {
1482 assert(isLoaded());1483 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 }
1490 1484
1491 // We should not have any existing renderItems if we enter this section of code1485 // We should not have any existing renderItems if we enter this section of code
1492 Q_ASSERT(_modelMeshRenderItems.isEmpty());1486 Q_ASSERT(_modelMeshRenderItems.isEmpty());
1493 1487
1494 _modelMeshRenderItems.clear();1488 _modelMeshRenderItems.clear();
1495 _modelMeshMaterialNames.clear();1489 _modelMeshMaterialNames.clear();
1496 _modelMeshRenderItemShapes.clear();
1497 1490
1498 Transform transform;1491 Transform transform;
1499 transform.setTranslation(_translation);1492 transform.setTranslation(_translation);
@@ -1504,31 +1497,19 @@ void Model::createRenderItemSet() { · 4 unmodified lines
1504 offset.postTranslate(_offset);1497 offset.postTranslate(_offset);
1505 1498
1506 // Run through all of the meshes, and place them into their segregated, but unsorted buckets1499 // Run through all of the meshes, and place them into their segregated, but unsorted buckets
1507 int shapeID = 0;1500 const auto& shapes = _renderGeometry->getHFMModel().shapes;
1508 uint32_t numMeshes = (uint32_t)meshes.size();1501 for (uint32_t shapeID = 0; shapeID < shapes.size(); shapeID++) {
1509 auto& hfmModel = getHFMModel();1502 const auto& shape = shapes[shapeID];
1510 for (uint32_t i = 0; i < numMeshes; i++) {
1511 const auto& mesh = meshes.at(i);
1512 if (!mesh) {
1513 continue;
1514 }
1515 1503
1516 // Create the render payloads1504 _modelMeshRenderItems << std::make_shared<ModelMeshPartPayload>(shared_from_this(), shape.mesh, shape.meshPart, shapeID, transform, offset, _created);
1517 int numParts = (int)mesh->getNumParts();1505
1518 for (int partIndex = 0; partIndex < numParts; partIndex++) {1506 auto material = getNetworkModel()->getShapeMaterial(shapeID);
1519 initializeBlendshapes(hfmModel.meshes[i], i);1507 _modelMeshMaterialNames.push_back(material ? material->getName() : "");
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 }
1526 }1508 }
1527 _blendshapeOffsetsInitialized = true;
1528}1509}
1529 1510
1530bool Model::isRenderable() const {1511bool Model::isRenderable() const {
1531 return !_meshStates.empty() || (isLoaded() && _renderGeometry->getMeshes().empty());1512 return (!_shapeStates.empty()) || (isLoaded() && _renderGeometry->getMeshes().empty());
1532}1513}
1533 1514
1534std::set<unsigned int> Model::getMeshIDsFromMaterialID(QString parentMaterialName) {1515std::set<unsigned int> Model::getMeshIDsFromMaterialID(QString parentMaterialName) {
@@ -1583,6 +1564,13 @@ void Model::applyMaterialMapping() { · 48 unmodified lines
1583 auto renderItemsKey = _renderItemKeyGlobalFlags;1564 auto renderItemsKey = _renderItemKeyGlobalFlags;
1584 PrimitiveMode primitiveMode = getPrimitiveMode();1565 PrimitiveMode primitiveMode = getPrimitiveMode();
1585 bool useDualQuaternionSkinning = _useDualQuaternionSkinning;1566 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 }
1586 1574
1587 auto& materialMapping = getMaterialMapping();1575 auto& materialMapping = getMaterialMapping();
1588 for (auto& mapping : materialMapping) {1576 for (auto& mapping : materialMapping) {
@@ -1602,8 +1590,11 @@ void Model::applyMaterialMapping() { · 13 unmodified lines
1602 priorityMapPerResource[shapeID] = ++_priorityMap[shapeID];1590 priorityMapPerResource[shapeID] = ++_priorityMap[shapeID];
1603 }1591 }
1604 1592
1605 auto materialLoaded = [this, networkMaterialResource, shapeIDs, priorityMapPerResource, renderItemsKey, primitiveMode, useDualQuaternionSkinning]() {1593 std::weak_ptr<Model> weakSelf = shared_from_this();
1606 if (networkMaterialResource->isFailed() || networkMaterialResource->parsedMaterials.names.size() == 0) {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) {
1607 return;1598 return;
1608 }1599 }
1609 render::Transaction transaction;1600 render::Transaction transaction;
@@ -1625,12 +1616,15 @@ void Model::applyMaterialMapping() { · 15 unmodified lines
1625 }1616 }
1626 }1617 }
1627 for (auto shapeID : shapeIDs) {1618 for (auto shapeID : shapeIDs) {
1628 if (shapeID < _modelMeshRenderItemIDs.size()) {1619 if (shapeID < modelMeshRenderItemIDs.size()) {
1629 auto itemID = _modelMeshRenderItemIDs[shapeID];1620 auto itemID = modelMeshRenderItemIDs[shapeID];
1630 auto meshIndex = _modelMeshRenderItemShapes[shapeID].meshIndex;1621 auto meshIndex = shapeStates[shapeID]._meshIndex;
1631 bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex);1622 bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKeyMap.at(meshIndex);
1632 graphics::MaterialLayer material = graphics::MaterialLayer(networkMaterial, priorityMapPerResource.at(shapeID));1623 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 }
1634 transaction.updateItem<ModelMeshPartPayload>(itemID, [material, renderItemsKey,1628 transaction.updateItem<ModelMeshPartPayload>(itemID, [material, renderItemsKey,
1635 invalidatePayloadShapeKey, primitiveMode, useDualQuaternionSkinning](ModelMeshPartPayload& data) {1629 invalidatePayloadShapeKey, primitiveMode, useDualQuaternionSkinning](ModelMeshPartPayload& data) {
1636 data.addMaterial(material);1630 data.addMaterial(material);
@@ -1662,7 +1656,7 @@ void Model::addMaterial(graphics::MaterialLayer material, const std::string& par · 25 unmodified lines
1662 for (auto shapeID : shapeIDs) {1656 for (auto shapeID : shapeIDs) {
1663 if (shapeID < _modelMeshRenderItemIDs.size()) {1657 if (shapeID < _modelMeshRenderItemIDs.size()) {
1664 auto itemID = _modelMeshRenderItemIDs[shapeID];1658 auto itemID = _modelMeshRenderItemIDs[shapeID];
1665 auto meshIndex = _modelMeshRenderItemShapes[shapeID].meshIndex;1659 auto meshIndex = _shapeStates[shapeID]._meshIndex;
1666 bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex);1660 bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex);
1667 transaction.updateItem<ModelMeshPartPayload>(itemID, [material, renderItemsKey,1661 transaction.updateItem<ModelMeshPartPayload>(itemID, [material, renderItemsKey,
1668 invalidatePayloadShapeKey, primitiveMode, useDualQuaternionSkinning](ModelMeshPartPayload& data) {1662 invalidatePayloadShapeKey, primitiveMode, useDualQuaternionSkinning](ModelMeshPartPayload& data) {
@@ -1684,7 +1678,7 @@ void Model::removeMaterial(graphics::MaterialPointer material, const std::string · 15 unmodified lines
1684 auto itemID = _modelMeshRenderItemIDs[shapeID];1678 auto itemID = _modelMeshRenderItemIDs[shapeID];
1685 auto renderItemsKey = _renderItemKeyGlobalFlags;1679 auto renderItemsKey = _renderItemKeyGlobalFlags;
1686 PrimitiveMode primitiveMode = getPrimitiveMode();1680 PrimitiveMode primitiveMode = getPrimitiveMode();
1687 auto meshIndex = _modelMeshRenderItemShapes[shapeID].meshIndex;1681 auto meshIndex = _shapeStates[shapeID]._meshIndex;
1688 bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex);1682 bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex);
1689 bool useDualQuaternionSkinning = _useDualQuaternionSkinning;1683 bool useDualQuaternionSkinning = _useDualQuaternionSkinning;
1690 transaction.updateItem<ModelMeshPartPayload>(itemID, [material, renderItemsKey,1684 transaction.updateItem<ModelMeshPartPayload>(itemID, [material, renderItemsKey,
@@ -1699,21 +1693,17 @@ void Model::removeMaterial(graphics::MaterialPointer material, const std::string · 8 unmodified lines
1699 AbstractViewStateInterface::instance()->getMain3DScene()->enqueueTransaction(transaction);1693 AbstractViewStateInterface::instance()->getMain3DScene()->enqueueTransaction(transaction);
1700}1694}
1701 1695
1702class CollisionRenderGeometry : public Geometry {1696class CollisionRenderGeometry : public NetworkModel {
1703public:1697public:
1704 CollisionRenderGeometry(graphics::MeshPointer mesh) {1698 CollisionRenderGeometry(graphics::MeshPointer mesh) {
1705 _hfmModel = std::make_shared<HFMModel>();1699 _hfmModel = std::make_shared<HFMModel>();
1706 std::shared_ptr<GeometryMeshes> meshes = std::make_shared<GeometryMeshes>();1700 std::shared_ptr<GeometryMeshes> meshes = std::make_shared<GeometryMeshes>();
1707 meshes->push_back(mesh);1701 meshes->push_back(mesh);
1708 _meshes = meshes;1702 _meshes = meshes;
1709 _meshParts = std::shared_ptr<const GeometryMeshParts>();
1710 }1703 }
1711};1704};
1712 1705
1713 1706static void packBlendshapeOffsetTo_Pos_F32_3xSN10_Nor_3xSN10_Tan_3xSN10(glm::uvec4& packed, const BlendshapeOffsetUnpacked& unpacked) {
1714using packBlendshapeOffsetTo = void(glm::uvec4& packed, const BlendshapeOffsetUnpacked& unpacked);
1715
1716void packBlendshapeOffsetTo_Pos_F32_3xSN10_Nor_3xSN10_Tan_3xSN10(glm::uvec4& packed, const BlendshapeOffsetUnpacked& unpacked) {
1717 float len = glm::compMax(glm::abs(unpacked.positionOffset));1707 float len = glm::compMax(glm::abs(unpacked.positionOffset));
1718 glm::vec3 normalizedPos(unpacked.positionOffset);1708 glm::vec3 normalizedPos(unpacked.positionOffset);
1719 if (len > 0.0f) {1709 if (len > 0.0f) {
@@ -1730,125 +1720,143 @@ void packBlendshapeOffsetTo_Pos_F32_3xSN10_Nor_3xSN10_Tan_3xSN10(glm::uvec4& pac · 10 unmodified lines
1730 );1720 );
1731}1721}
1732 1722
1723static 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
1737void packBlendshapeOffsets_AVX2(float (*unpacked)[9], uint32_t (*packed)[4], int size);
1738
1739static 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
1751static auto& packBlendshapeOffsets = packBlendshapeOffsets_ref;
1752#endif
1753
1733class Blender : public QRunnable {1754class Blender : public QRunnable {
1734public:1755public:
1735 1756
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);
1737 1758
1738 virtual void run() override;1759 virtual void run() override;
1739 1760
1740private:1761private:
1741
1742 ModelPointer _model;1762 ModelPointer _model;
1763 HFMModel::ConstPointer _hfmModel;
1743 int _blendNumber;1764 int _blendNumber;
1744 Geometry::WeakPointer _geometry;
1745 QVector<float> _blendshapeCoefficients;1765 QVector<float> _blendshapeCoefficients;
1746};1766};
1747 1767
1748Blender::Blender(ModelPointer model, int blendNumber, const Geometry::WeakPointer& geometry, const QVector<float>& blendshapeCoefficients) :1768Blender::Blender(ModelPointer model, HFMModel::ConstPointer hfmModel, int blendNumber, const QVector<float>& blendshapeCoefficients) :
1749 _model(model),1769 _model(model),
1770 _hfmModel(hfmModel),
1750 _blendNumber(blendNumber),1771 _blendNumber(blendNumber),
1751 _geometry(geometry),
1752 _blendshapeCoefficients(blendshapeCoefficients) {1772 _blendshapeCoefficients(blendshapeCoefficients) {
1753}1773}
1754 1774
1755void Blender::run() {1775void Blender::run() {
1756 QVector<BlendshapeOffset> blendshapeOffsets;1776 DETAILED_PROFILE_RANGE_EX(simulation_animation, __FUNCTION__, 0xFFFF0000, 0, { { "url", _model->getURL().toString() } });
1757 QVector<int> blendedMeshSizes;1777 int numBlendshapeOffsets = 0; // number of offsets required for all meshes.
1758 if (_model && _model->isLoaded()) {1778 int maxBlendshapeOffsets = 0; // number of offsets in the largest mesh.
1759 DETAILED_PROFILE_RANGE_EX(simulation_animation, __FUNCTION__, 0xFFFF0000, 0, { { "url", _model->getURL().toString() } });1779 int numMeshes = 0; // number of meshes in this model.
1760 int offset = 0;1780 for (auto meshIter = _hfmModel->meshes.cbegin(); meshIter != _hfmModel->meshes.cend(); ++meshIter) {
1761 auto meshes = _model->getHFMModel().meshes;1781 numMeshes++;
1762 int meshIndex = 0;1782 if (meshIter->blendshapes.isEmpty()) {
1763 foreach(const HFMMesh& mesh, meshes) {1783 continue;
1764 auto modelMeshBlendshapeOffsets = _model->_blendshapeOffsets.find(meshIndex++);1784 }
1765 if (mesh.blendshapes.isEmpty() || modelMeshBlendshapeOffsets == _model->_blendshapeOffsets.end()) {1785 int numVertsInMesh = meshIter->vertices.size();
1766 // Not blendshaped or not initialized1786 numBlendshapeOffsets += numVertsInMesh;
1767 blendedMeshSizes.push_back(0);1787 maxBlendshapeOffsets = std::max(maxBlendshapeOffsets, numVertsInMesh);
1768 continue;1788 }
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 }
1791 1789
1792 float normalCoefficient = vertexCoefficient * NORMAL_COEFFICIENT_SCALE;1790 // allocate the required sizes
1793 const HFMBlendshape& blendshape = mesh.blendshapes.at(i);1791 QVector<int> blendedMeshSizes;
1792 blendedMeshSizes.reserve(numMeshes);
1794 1793
1795 tbb::parallel_for(tbb::blocked_range<int>(0, blendshape.indices.size()), [&](const tbb::blocked_range<int>& range) {1794 QVector<BlendshapeOffset> packedBlendshapeOffsets;
1796 for (auto j = range.begin(); j < range.end(); j++) {1795 packedBlendshapeOffsets.resize(numBlendshapeOffsets);
1797 int index = blendshape.indices.at(j);
1798 1796
1799 auto& currentBlendshapeOffset = unpackedBlendshapeOffsets[index];1797 QVector<BlendshapeOffsetUnpacked> unpackedBlendshapeOffsets;
1800 currentBlendshapeOffset.positionOffset += blendshape.vertices.at(j) * vertexCoefficient;1798 unpackedBlendshapeOffsets.resize(maxBlendshapeOffsets); // reuse for all meshes
1801 1799
1802 currentBlendshapeOffset.normalOffset += blendshape.normals.at(j) * normalCoefficient;1800 int offset = 0;
1803 if (j < blendshape.tangents.size()) {1801 for (auto meshIter = _hfmModel->meshes.cbegin(); meshIter != _hfmModel->meshes.cend(); ++meshIter) {
1804 currentBlendshapeOffset.tangentOffset += blendshape.tangents.at(j) * normalCoefficient;1802 if (meshIter->blendshapes.isEmpty()) {
1805 }1803 blendedMeshSizes.push_back(0);
1806 }1804 continue;
1807 });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;
1808 }1819 }
1809 1820
1810 // Blendshape offsets are generrated, now let's pack it on its way to gpu1821 float normalCoefficient = vertexCoefficient * NORMAL_COEFFICIENT_SCALE;
1811 tbb::parallel_for(tbb::blocked_range<int>(0, (int) unpackedBlendshapeOffsets.size()), [&](const tbb::blocked_range<int>& range) {1822 const HFMBlendshape& blendshape = meshIter->blendshapes.at(i);
1812 auto unpacked = unpackedBlendshapeOffsets.data() + range.begin();1823 for (int j = 0; j < blendshape.indices.size(); ++j) {
1813 auto packed = meshBlendshapeOffsets + range.begin();1824 int index = blendshape.indices.at(j);
1814 for (auto j = range.begin(); j < range.end(); j++) {
1815 packBlendshapeOffsetTo_Pos_F32_3xSN10_Nor_3xSN10_Tan_3xSN10((*packed).packedPosNorTan, (*unpacked));
1816 1825
1817 unpacked++;1826 auto& currentBlendshapeOffset = unpackedBlendshapeOffsets[index];
1818 packed++;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;
1819 }1831 }
1820 });1832 }
1821 }1833 }
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;
1822 }1841 }
1842 Q_ASSERT(offset == numBlendshapeOffsets);
1843
1823 // post the result to the ModelBlender, which will dispatch to the model if still alive1844 // post the result to the ModelBlender, which will dispatch to the model if still alive
1824 QMetaObject::invokeMethod(DependencyManager::get<ModelBlender>().data(), "setBlendedVertices",1845 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));
1826}1849}
1827 1850
1828bool Model::maybeStartBlender() {1851bool Model::maybeStartBlender() {
1829 if (isLoaded()) {1852 if (isLoaded()) {
1830 QThreadPool::globalInstance()->start(new Blender(getThisPointer(), ++_blendNumber, _renderGeometry, _blendshapeCoefficients));1853 QThreadPool::globalInstance()->start(new Blender(getThisPointer(), getNetworkModel()->getConstHFMModelPointer(),
1854 ++_blendNumber, _blendshapeCoefficients));
1831 return true;1855 return true;
1832 }1856 }
1833 return false;1857 return false;
1834}1858}
1835 1859
1836void 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
1852ModelBlender::ModelBlender() :1860ModelBlender::ModelBlender() :
1853 _pendingBlenders(0) {1861 _pendingBlenders(0) {
1854}1862}