From 4ce27f1483508be4fa4ddc7fea0bdf63fc1d3f73 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 2 Jun 2015 16:54:47 -0700 Subject: [PATCH] first cut at rendering avatars as individual model items --- interface/src/avatar/Avatar.cpp | 28 ++++++++++++++++++++- interface/src/avatar/Avatar.h | 6 +++++ interface/src/avatar/AvatarManager.cpp | 28 +++++++-------------- interface/src/avatar/MyAvatar.cpp | 15 ++++++++++- interface/src/avatar/SkeletonModel.cpp | 5 +++- libraries/render-utils/src/Model.cpp | 35 ++++++++++++++++---------- libraries/render-utils/src/Model.h | 2 ++ 7 files changed, 84 insertions(+), 35 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 65ab6b8d44..961747190d 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -292,6 +292,20 @@ static TextRenderer* textRenderer(TextRendererType type) { return displayNameRenderer; } +bool Avatar::addToScene(AvatarSharedPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges) { + auto avatarPayload = new render::Payload(self); + auto avatarPayloadPointer = Avatar::PayloadPointer(avatarPayload); + _renderItemID = scene->allocateID(); + pendingChanges.resetItem(_renderItemID, avatarPayloadPointer); + _skeletonModel.addToScene(scene, pendingChanges); + return true; +} + +void Avatar::removeFromScene(AvatarSharedPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges) { + pendingChanges.removeItem(_renderItemID); + _skeletonModel.removeFromScene(scene, pendingChanges); +} + void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, bool postLighting) { if (_referential) { _referential->update(); @@ -504,6 +518,17 @@ glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const { } void Avatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, bool postLighting, float glowLevel) { + // check to see if when we added our models to the scene they were ready, if they were not ready, then + // fix them up in the scene + if (_skeletonModel.needsFixupInScene()) { + qDebug() << "Avatar::renderBody() FIXING _skeletonModel"; + render::ScenePointer scene = Application::getInstance()->getMain3DScene(); + render::PendingChanges pendingChanges; + _skeletonModel.removeFromScene(scene, pendingChanges); + _skeletonModel.addToScene(scene, pendingChanges); + scene->enqueuePendingChanges(pendingChanges); + } + { Glower glower(renderArgs, glowLevel); @@ -518,7 +543,8 @@ void Avatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, bool if (postLighting) { getHand()->render(renderArgs, false); } else { - _skeletonModel.render(renderArgs, 1.0f); + // NOTE: we no longer call this here, because we've added all the model parts as renderable items in the scene + //_skeletonModel.render(renderArgs, 1.0f); renderAttachments(renderArgs); } } diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index b8f2d3a513..001ff8aa85 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -83,6 +83,12 @@ public: virtual void render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, bool postLighting = false); + bool addToScene(AvatarSharedPointer self, std::shared_ptr scene, + render::PendingChanges& pendingChanges); + + void removeFromScene(AvatarSharedPointer self, std::shared_ptr scene, + render::PendingChanges& pendingChanges); + //setters void setDisplayingLookatVectors(bool displayingLookatVectors) { getHead()->setRenderLookatVectors(displayingLookatVectors); } void setIsLookAtTarget(const bool isLookAtTarget) { _isLookAtTarget = isLookAtTarget; } diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 8f8a3a8ef3..7cef470c14 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -63,13 +63,8 @@ void AvatarManager::init() { _avatarHash.insert(MY_AVATAR_KEY, _myAvatar); render::ScenePointer scene = Application::getInstance()->getMain3DScene(); - auto avatarPayload = new render::Payload(_myAvatar); - auto avatarPayloadPointer = Avatar::PayloadPointer(avatarPayload); - static_cast(_myAvatar.get())->_renderItemID = scene->allocateID(); - render::PendingChanges pendingChanges; - pendingChanges.resetItem(static_cast(_myAvatar.get())->_renderItemID, avatarPayloadPointer); - + _myAvatar->addToScene(_myAvatar, scene, pendingChanges); scene->enqueuePendingChanges(pendingChanges); } @@ -145,18 +140,11 @@ AvatarSharedPointer AvatarManager::newSharedAvatar() { // virtual AvatarSharedPointer AvatarManager::addAvatar(const QUuid& sessionUUID, const QWeakPointer& mixerWeakPointer) { - AvatarSharedPointer avatar = AvatarHashMap::addAvatar(sessionUUID, mixerWeakPointer); - + std::shared_ptr avatar = std::dynamic_pointer_cast(AvatarHashMap::addAvatar(sessionUUID, mixerWeakPointer)); render::ScenePointer scene = Application::getInstance()->getMain3DScene(); - auto avatarPayload = new render::Payload(avatar); - auto avatarPayloadPointer = Avatar::PayloadPointer(avatarPayload); - static_cast(avatar.get())->_renderItemID = scene->allocateID(); - render::PendingChanges pendingChanges; - pendingChanges.resetItem(static_cast(avatar.get())->_renderItemID, avatarPayloadPointer); - + avatar->addToScene(avatar, scene, pendingChanges); scene->enqueuePendingChanges(pendingChanges); - return avatar; } @@ -177,17 +165,19 @@ void AvatarManager::removeAvatarMotionState(Avatar* avatar) { void AvatarManager::removeAvatar(const QUuid& sessionUUID) { AvatarHash::iterator avatarIterator = _avatarHash.find(sessionUUID); if (avatarIterator != _avatarHash.end()) { - Avatar* avatar = reinterpret_cast(avatarIterator.value().get()); - if (avatar != _myAvatar.get() && avatar->isInitialized()) { - removeAvatarMotionState(avatar); + //Avatar* avatar = reinterpret_cast(avatarIterator.value().get()); + std::shared_ptr avatar = std::dynamic_pointer_cast(avatarIterator.value()); + // FIX ME! Can we just say (avatar != _myAvatar) + if (avatar != _myAvatar && avatar->isInitialized()) { + removeAvatarMotionState(avatar.get()); _avatarFades.push_back(avatarIterator.value()); _avatarHash.erase(avatarIterator); } render::ScenePointer scene = Application::getInstance()->getMain3DScene(); render::PendingChanges pendingChanges; - pendingChanges.removeItem(avatar->_renderItemID); + avatar->removeFromScene(avatar, scene, pendingChanges); scene->enqueuePendingChanges(pendingChanges); } } diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index bdf66eb1b5..9e020c9733 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1168,10 +1168,21 @@ void MyAvatar::attach(const QString& modelURL, const QString& jointName, const g } void MyAvatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, bool postLighting, float glowLevel) { + if (!(_skeletonModel.isRenderable() && getHead()->getFaceModel().isRenderable())) { return; // wait until both models are loaded } + // check to see if when we added our models to the scene they were ready, if they were not ready, then + // fix them up in the scene + if (_skeletonModel.needsFixupInScene()) { + render::ScenePointer scene = Application::getInstance()->getMain3DScene(); + render::PendingChanges pendingChanges; + _skeletonModel.removeFromScene(scene, pendingChanges); + _skeletonModel.addToScene(scene, pendingChanges); + scene->enqueuePendingChanges(pendingChanges); + } + Camera *camera = Application::getInstance()->getCamera(); const glm::vec3 cameraPos = camera->getPosition(); @@ -1192,7 +1203,9 @@ void MyAvatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, bo // Render the body's voxels and head if (!postLighting) { - _skeletonModel.render(renderArgs, 1.0f); + + // NOTE: we no longer call this here, because we've added all the model parts as renderable items in the scene + //_skeletonModel.render(renderArgs, 1.0f); renderAttachments(renderArgs); } diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index e2f4ca51a0..2aa08d36f3 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -255,9 +255,12 @@ void SkeletonModel::applyPalmData(int jointIndex, PalmData& palm) { } void SkeletonModel::updateJointState(int index) { + if (index > _jointStates.size()) { + return; // bail + } JointState& state = _jointStates[index]; const FBXJoint& joint = state.getFBXJoint(); - if (joint.parentIndex != -1) { + if (joint.parentIndex != -1 && joint.parentIndex <= _jointStates.size()) { const JointState& parentState = _jointStates.at(joint.parentIndex); const FBXGeometry& geometry = _geometry->getFBXGeometry(); if (index == geometry.leanJointIndex) { diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index c58e84de9c..7340c0b1d1 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -406,6 +406,7 @@ void Model::reset() { } _meshGroupsKnown = false; + _readyWhenAdded = false; // in case any of our users are using scenes } bool Model::updateGeometry() { @@ -456,6 +457,7 @@ bool Model::updateGeometry() { _dilatedTextures.clear(); _geometry = geometry; _meshGroupsKnown = false; + _readyWhenAdded = false; // in case any of our users are using scenes initJointStates(newJointStates); needToRebuild = true; } else if (_jointStates.isEmpty()) { @@ -812,7 +814,7 @@ namespace render { template <> const Item::Bound payloadGetBound(const TransparentMeshPart::Pointer& payload) { if (payload) { - return payload->model->getPartBounds(payload->meshIndex, payload->partIndex); + //return payload->model->getPartBounds(payload->meshIndex, payload->partIndex); } return render::Item::Bound(); } @@ -857,6 +859,10 @@ namespace render { bool Model::addToScene(std::shared_ptr scene, render::PendingChanges& pendingChanges) { + if (!_meshGroupsKnown && isLoadedWithTextures()) { + segregateMeshGroups(); + } + bool somethingAdded = false; // allow the attachments to add to scene foreach (Model* attachment, _attachments) { @@ -880,6 +886,8 @@ bool Model::addToScene(std::shared_ptr scene, render::PendingChan _renderItems << item; somethingAdded = true; } + + _readyWhenAdded = readyToAddToScene(); return somethingAdded; } @@ -894,6 +902,7 @@ void Model::removeFromScene(std::shared_ptr scene, render::Pendin pendingChanges.removeItem(item); } _renderItems.clear(); + _readyWhenAdded = false; } bool Model::render(RenderArgs* renderArgs, float alpha) { @@ -1921,6 +1930,7 @@ void Model::applyNextGeometry() { _baseGeometry = _nextBaseGeometry; _geometry = _nextGeometry; _meshGroupsKnown = false; + _readyWhenAdded = false; // in case any of our users are using scenes _nextBaseGeometry.reset(); _nextGeometry.reset(); } @@ -2210,21 +2220,16 @@ AABox Model::getPartBounds(int meshIndex, int partIndex) { if (_calculatedMeshPartBoxesValid && _calculatedMeshPartBoxes.contains(QPair(meshIndex, partIndex))) { return _calculatedMeshPartBoxes[QPair(meshIndex, partIndex)]; } - if (!_calculatedMeshBoxesValid) { + if (!_calculatedMeshBoxesValid && _calculatedMeshBoxes.size() > meshIndex) { return _calculatedMeshBoxes[meshIndex]; } return AABox(); } void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool translucent) { - renderSetup(args); - - /* - if (translucent) { - renderCore(args, 1.0f); - return; + if (!_readyWhenAdded) { + return; // bail asap } - */ auto textureCache = DependencyManager::get(); gpu::Batch& batch = *(args->_batch); @@ -2236,23 +2241,25 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran } _transforms[0] = _viewState->getViewTransform(); - // apply entity translation offset to the viewTransform in one go (it's a preTranslate because viewTransform goes from world to eye space) _transforms[0].preTranslate(-_translation); - batch.setViewTransform(_transforms[0]); - const float OPAQUE_ALPHA_THRESHOLD = 0.5f; const float TRANSPARENT_ALPHA_THRESHOLD = 0.0f; auto alphaThreshold = translucent ? TRANSPARENT_ALPHA_THRESHOLD : OPAQUE_ALPHA_THRESHOLD; // FIX ME const FBXGeometry& geometry = _geometry->getFBXGeometry(); const QVector& networkMeshes = _geometry->getMeshes(); + // guard against partially loaded meshes + if (meshIndex >= networkMeshes.size() || meshIndex >= geometry.meshes.size() || meshIndex >= _meshStates.size() ) { + return; + } + const NetworkMesh& networkMesh = networkMeshes.at(meshIndex); const FBXMesh& mesh = geometry.meshes.at(meshIndex); const MeshState& state = _meshStates.at(meshIndex); - + bool translucentMesh = translucent; // networkMesh.getTranslucentPartCount(mesh) == networkMesh.parts.size(); bool hasTangents = !mesh.tangents.isEmpty(); bool hasSpecular = mesh.hasSpecularTexture(); @@ -2277,6 +2284,7 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran if (meshIndex < 0 || meshIndex >= networkMeshes.size() || meshIndex > geometry.meshes.size()) { _meshGroupsKnown = false; // regenerate these lists next time around. + _readyWhenAdded = false; // in case any of our users are using scenes return; // FIXME! } @@ -2606,6 +2614,7 @@ int Model::renderMeshesFromList(QVector& list, gpu::Batch& batch, RenderMod if (i < 0 || i >= networkMeshes.size() || i > geometry.meshes.size()) { _meshGroupsKnown = false; // regenerate these lists next time around. + _readyWhenAdded = false; // in case any of our users are using scenes continue; } diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 7b44dbee04..e4f725b653 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -123,6 +123,7 @@ public: static void endScene(RenderArgs* args); // new Scene/Engine rendering support + bool needsFixupInScene() { return !_readyWhenAdded && readyToAddToScene(); } bool readyToAddToScene(RenderArgs* renderArgs = nullptr) { return isRenderable() && isActive() && isLoadedWithTextures(); } bool addToScene(std::shared_ptr scene, render::PendingChanges& pendingChanges); void removeFromScene(std::shared_ptr scene, render::PendingChanges& pendingChanges); @@ -542,6 +543,7 @@ private: QSet> _transparentRenderItems; QSet> _opaqueRenderItems; QSet _renderItems; + bool _readyWhenAdded = false; }; Q_DECLARE_METATYPE(QPointer)