Showing the changes to libraries/render-utils/src/Model.cpp (1 of 2941 files). Show all
Unified · Split
| @@ -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 | |||
| 42 | using namespace std; | 44 | using namespace std; |
| 43 | 45 | ||
| 44 | int nakedModelPointerTypeId = qRegisterMetaType<ModelPointer>(); | 46 | int nakedModelPointerTypeId = qRegisterMetaType<ModelPointer>(); |
| 45 | int weakGeometryResourceBridgePointerTypeId = qRegisterMetaType<Geometry::WeakPointer>(); | 47 | int weakGeometryResourceBridgePointerTypeId = qRegisterMetaType<NetworkModel::WeakPointer>(); |
| 46 | int vec3VectorTypeId = qRegisterMetaType<QVector<glm::vec3>>(); | 48 | int vec3VectorTypeId = qRegisterMetaType<QVector<glm::vec3>>(); |
| 47 | int normalTypeVecTypeId = qRegisterMetaType<QVector<NormalType>>("QVector<NormalType>"); | 49 | int normalTypeVecTypeId = qRegisterMetaType<QVector<NormalType>>("QVector<NormalType>"); |
| 48 | float Model::FAKE_DIMENSION_PLACEHOLDER = -1.0f; | 50 | float Model::FAKE_DIMENSION_PLACEHOLDER = -1.0f; |
| 49 | #define HTTP_INVALID_COM "http://invalid.com" | 51 | #define HTTP_INVALID_COM "http://invalid.com" |
| 50 | 52 | ||
| 51 | Model::Model(QObject* parent, SpatiallyNestable* spatiallyNestableOverride) : | 53 | Model::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 thread | 70 | // 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 | ||
| 77 | Model::~Model() { | 80 | Model::~Model() { |
| @@ -151,7 +154,7 @@ void Model::setOffset(const glm::vec3& offset) { · 73 unmodified lines | |||
| 151 | } | 154 | } |
| 152 | 155 | ||
| 153 | void Model::calculateTextureInfo() { | 156 | void 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 | ||
| 180 | bool Model::shouldInvalidatePayloadShapeKey(int meshIndex) { | 183 | bool 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 _meshGroupsKnown | 190 | // 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 cycle | 193 | _needsFixupInScene = true; // trigger remove/add cycle |
| 191 | invalidCalculatedMeshBoxes(); // if we have to reload, we need to assume our mesh boxes are all invalid | 194 | 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 | ||
| 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 | |||
| 294 | bool Model::updateGeometry() { | 307 | bool 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 | /**jsdoc | 471 | /**jsdoc |
| 448 | * Information about a submesh intersection point. | 472 | * A submesh intersection point. |
| 449 | * @typedef {object} SubmeshIntersection | 473 | * @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 remove | 667 | // TODO: deprecate and remove |
| 644 | MeshProxyList Model::getMeshes() const { | 668 | MeshProxyList 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 too | 741 | // 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 | |||
| 792 | void Model::calculateTriangleSets(const HFMModel& hfmModel) { | 819 | void 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 | ||
| 1023 | void Model::removeFromScene(const render::ScenePointer& scene, render::Transaction& transaction) { | 1043 | void 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 | ||
| 1045 | void Model::renderDebugMeshBoxes(gpu::Batch& batch) { | 1060 | void 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 joints | 1396 | // 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 | ||
| 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 | |||
| 1407 | // virtual | 1409 | // virtual |
| 1408 | void Model::updateClusterMatrices() { | 1410 | void 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 finish | 1440 | // 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 | ||
| 1446 | void Model::deleteGeometry() { | 1448 | void 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 | ||
| 1481 | void Model::createRenderItemSet() { | 1482 | void 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 code | 1485 | // 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 buckets | 1499 | // 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 payloads | 1504 | _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 | ||
| 1530 | bool Model::isRenderable() const { | 1511 | bool Model::isRenderable() const { |
| 1531 | return !_meshStates.empty() || (isLoaded() && _renderGeometry->getMeshes().empty()); | 1512 | return (!_shapeStates.empty()) || (isLoaded() && _renderGeometry->getMeshes().empty()); |
| 1532 | } | 1513 | } |
| 1533 | 1514 | ||
| 1534 | std::set<unsigned int> Model::getMeshIDsFromMaterialID(QString parentMaterialName) { | 1515 | std::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 | ||
| 1702 | class CollisionRenderGeometry : public Geometry { | 1696 | class CollisionRenderGeometry : public NetworkModel { |
| 1703 | public: | 1697 | public: |
| 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 | 1706 | static void packBlendshapeOffsetTo_Pos_F32_3xSN10_Nor_3xSN10_Tan_3xSN10(glm::uvec4& packed, const BlendshapeOffsetUnpacked& unpacked) { | |
| 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) { | ||
| 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 | ||
| 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 | |||
| 1733 | class Blender : public QRunnable { | 1754 | class Blender : public QRunnable { |
| 1734 | public: | 1755 | public: |
| 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 | ||
| 1740 | private: | 1761 | private: |
| 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 | ||
| 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) : |
| 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 | ||
| 1755 | void Blender::run() { | 1775 | void 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 initialized | 1786 | 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 gpu | 1821 | 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 alive | 1844 | // 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 | ||
| 1828 | bool Model::maybeStartBlender() { | 1851 | bool 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 | ||
| 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 | |||
| 1852 | ModelBlender::ModelBlender() : | 1860 | ModelBlender::ModelBlender() : |
| 1853 | _pendingBlenders(0) { | 1861 | _pendingBlenders(0) { |
| 1854 | } | 1862 | } |