diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index f5d599b5d3..76d701f0e3 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -1175,13 +1175,22 @@ void OctreeServer::aboutToFinish() { if (_jurisdictionSender) { _jurisdictionSender->terminating(); } + + QSet nodesToShutdown; - // force a shutdown of all of our OctreeSendThreads - at this point it has to be impossible for a - // linkedDataCreateCallback to be called for a new node - nodeList->eachNode([this](const SharedNodePointer& node) { + // Force a shutdown of all of our OctreeSendThreads. + // At this point it has to be impossible for a linkedDataCreateCallback to be called for a new node + nodeList->eachNode([&nodesToShutdown](const SharedNodePointer& node) { + nodesToShutdown << node; + }); + + // What follows is a hack to force OctreeSendThreads to cleanup before the OctreeServer is gone. + // I would prefer to allow the SharedNodePointer ref count drop to zero to do this automatically + // but that isn't possible as long as the OctreeSendThread has an OctreeServer* that it uses. + for (auto& node : nodesToShutdown) { qDebug() << qPrintable(_safeServerName) << "server about to finish while node still connected node:" << *node; forceNodeShutdown(node); - }); + } if (_persistThread) { _persistThread->aboutToFinish(); diff --git a/examples/edit.js b/examples/edit.js index b33f47c2b7..1af016958f 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -318,11 +318,15 @@ var toolBar = (function () { print("Resize failed: timed out waiting for model (" + url + ") to load"); } } else { - entityProperties.dimensions = naturalDimensions; - Entities.editEntity(entityId, entityProperties); + Entities.editEntity(entityId, { dimensions: naturalDimensions }); + + // Reset selection so that the selection overlays will be updated + selectionManager.setSelections([entityId]); } } + selectionManager.setSelections([entityId]); + Script.setTimeout(resize, RESIZE_INTERVAL); } else { print("Can't add model: Model would be out of bounds."); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 7de69ef602..8f825a2768 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -882,7 +882,7 @@ void Application::paintGL() { // NOTE: There is no batch associated with this renderArgs // the ApplicationOverlay class assumes it's viewport is setup to be the device size QSize size = qApp->getDeviceSize(); - renderArgs._viewport = glm::ivec4(0, 0, size.width(), size.height()); + renderArgs._viewport = glm::ivec4(0, 0, size.width(), size.height()); _applicationOverlay.renderOverlay(&renderArgs); } @@ -959,7 +959,7 @@ void Application::paintGL() { batch.setFramebuffer(primaryFbo); // clear the normal and specular buffers batch.clearFramebuffer( - gpu::Framebuffer::BUFFER_COLOR0 | + gpu::Framebuffer::BUFFER_COLOR0 | gpu::Framebuffer::BUFFER_COLOR1 | gpu::Framebuffer::BUFFER_COLOR2 | gpu::Framebuffer::BUFFER_DEPTH, @@ -1798,6 +1798,13 @@ void Application::idle() { } double timeSinceLastUpdate = (double)_lastTimeUpdated.nsecsElapsed() / 1000000.0; if (timeSinceLastUpdate > targetFramePeriod) { + + { + static const int IDLE_EVENT_PROCESS_MAX_TIME_MS = 2; + PerformanceTimer perfTimer("processEvents"); + processEvents(QEventLoop::AllEvents, IDLE_EVENT_PROCESS_MAX_TIME_MS); + } + _lastTimeUpdated.start(); { PerformanceTimer perfTimer("update"); @@ -1822,11 +1829,19 @@ void Application::idle() { _idleLoopMeasuredJitter = _idleLoopStdev.getStDev(); _idleLoopStdev.reset(); } - } + // After finishing all of the above work, ensure the idle timer is set to the proper interval, - // depending on whether we're throttling or not - idleTimer->start(_glWidget->isThrottleRendering() ? THROTTLED_IDLE_TIMER_DELAY : 1); + // depending on whether we're throttling or not. + // Once rendering is off on another thread we should be able to have Application::idle run at start(0) in + // perpetuity and not expect events to get backed up. + + static const int IDLE_TIMER_DELAY_MS = 0; + int desiredInterval = _glWidget->isThrottleRendering() ? THROTTLED_IDLE_TIMER_DELAY : IDLE_TIMER_DELAY_MS; + + if (idleTimer->interval() != desiredInterval) { + idleTimer->start(desiredInterval); + } } // check for any requested background downloads. @@ -3414,9 +3429,6 @@ void Application::renderRearViewMirror(RenderArgs* renderArgs, const QRect& regi renderArgs->_context->render(batch); } - bool updateViewFrustum = false; - loadViewFrustum(_mirrorCamera, _viewFrustum); - // render rear mirror view displaySide(renderArgs, _mirrorCamera, true, billboard); diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 26e218d05b..2bc7e788ad 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -317,15 +317,14 @@ void Avatar::removeFromScene(AvatarSharedPointer self, std::shared_ptrupdate(); } auto& batch = *renderArgs->_batch; - if (postLighting && - glm::distance(DependencyManager::get()->getMyAvatar()->getPosition(), _position) < 10.0f) { + if (glm::distance(DependencyManager::get()->getMyAvatar()->getPosition(), _position) < 10.0f) { auto geometryCache = DependencyManager::get(); auto deferredLighting = DependencyManager::get(); @@ -415,9 +414,9 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, boo : GLOW_FROM_AVERAGE_LOUDNESS; // render body - renderBody(renderArgs, frustum, postLighting, glowLevel); + renderBody(renderArgs, frustum, glowLevel); - if (!postLighting && renderArgs->_renderMode != RenderArgs::SHADOW_RENDER_MODE) { + if (renderArgs->_renderMode != RenderArgs::SHADOW_RENDER_MODE) { // add local lights const float BASE_LIGHT_DISTANCE = 2.0f; const float LIGHT_EXPONENT = 1.0f; @@ -432,21 +431,17 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, boo } } - if (postLighting) { - bool renderSkeleton = Menu::getInstance()->isOptionChecked(MenuOption::RenderSkeletonCollisionShapes); - bool renderHead = Menu::getInstance()->isOptionChecked(MenuOption::RenderHeadCollisionShapes); - bool renderBounding = Menu::getInstance()->isOptionChecked(MenuOption::RenderBoundingCollisionShapes); - - if (renderSkeleton) { - _skeletonModel.renderJointCollisionShapes(0.7f); - } - - if (renderHead && shouldRenderHead(renderArgs)) { - getHead()->getFaceModel().renderJointCollisionShapes(0.7f); - } - if (renderBounding && shouldRenderHead(renderArgs)) { - _skeletonModel.renderBoundingCollisionShapes(*renderArgs->_batch, 0.7f); - } + bool renderSkeleton = Menu::getInstance()->isOptionChecked(MenuOption::RenderSkeletonCollisionShapes); + bool renderHead = Menu::getInstance()->isOptionChecked(MenuOption::RenderHeadCollisionShapes); + bool renderBounding = Menu::getInstance()->isOptionChecked(MenuOption::RenderBoundingCollisionShapes); + if (renderSkeleton) { + _skeletonModel.renderJointCollisionShapes(0.7f); + } + if (renderHead && shouldRenderHead(renderArgs)) { + getHead()->getFaceModel().renderJointCollisionShapes(0.7f); + } + if (renderBounding && shouldRenderHead(renderArgs)) { + _skeletonModel.renderBoundingCollisionShapes(*renderArgs->_batch, 0.7f); } // Stack indicator spheres @@ -570,24 +565,20 @@ void Avatar::fixupModelsInScene() { scene->enqueuePendingChanges(pendingChanges); } -void Avatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, bool postLighting, float glowLevel) { +void Avatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, float glowLevel) { fixupModelsInScene(); { if (_shouldRenderBillboard || !(_skeletonModel.isRenderable() && getHead()->getFaceModel().isRenderable())) { - if (postLighting || renderArgs->_renderMode == RenderArgs::SHADOW_RENDER_MODE) { - // render the billboard until both models are loaded - renderBillboard(renderArgs); - } + // render the billboard until both models are loaded + renderBillboard(renderArgs); return; } - if (postLighting) { - getHand()->render(renderArgs, false); - } + getHand()->render(renderArgs, false); } - getHead()->render(renderArgs, 1.0f, renderFrustum, postLighting); + getHead()->render(renderArgs, 1.0f, renderFrustum); } bool Avatar::shouldRenderHead(const RenderArgs* renderArgs) const { @@ -832,7 +823,7 @@ QVector Avatar::getJointRotations() const { } QVector jointRotations(_skeletonModel.getJointStateCount()); for (int i = 0; i < _skeletonModel.getJointStateCount(); ++i) { - _skeletonModel.getJointState(i, jointRotations[i]); + _skeletonModel.getJointRotation(i, jointRotations[i]); } return jointRotations; } @@ -842,7 +833,7 @@ glm::quat Avatar::getJointRotation(int index) const { return AvatarData::getJointRotation(index); } glm::quat rotation; - _skeletonModel.getJointState(index, rotation); + _skeletonModel.getJointRotation(index, rotation); return rotation; } diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 096af5c229..a587e69642 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -81,8 +81,7 @@ public: void init(); void simulate(float deltaTime); - virtual void render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, - bool postLighting = false); + virtual void render(RenderArgs* renderArgs, const glm::vec3& cameraPosition); bool addToScene(AvatarSharedPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges); @@ -235,7 +234,7 @@ protected: Transform calculateDisplayNameTransform(const ViewFrustum& frustum, float fontSize, const glm::ivec4& viewport) const; void renderDisplayName(gpu::Batch& batch, const ViewFrustum& frustum, const glm::ivec4& viewport) const; - virtual void renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, bool postLighting, float glowLevel = 0.0f); + virtual void renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, float glowLevel = 0.0f); virtual bool shouldRenderHead(const RenderArgs* renderArgs) const; virtual void fixupModelsInScene(); diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index 0d07f171c0..81e1384d4a 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -293,7 +293,7 @@ void Head::relaxLean(float deltaTime) { _deltaLeanForward *= relaxationFactor; } -void Head::render(RenderArgs* renderArgs, float alpha, ViewFrustum* renderFrustum, bool postLighting) { +void Head::render(RenderArgs* renderArgs, float alpha, ViewFrustum* renderFrustum) { if (_renderLookatVectors) { renderLookatVectors(renderArgs, _leftEyePosition, _rightEyePosition, getCorrectedLookAtPosition()); } diff --git a/interface/src/avatar/Head.h b/interface/src/avatar/Head.h index d7a8462693..f6283c93ea 100644 --- a/interface/src/avatar/Head.h +++ b/interface/src/avatar/Head.h @@ -33,7 +33,7 @@ public: void init(); void reset(); void simulate(float deltaTime, bool isMine, bool billboard = false); - void render(RenderArgs* renderArgs, float alpha, ViewFrustum* renderFrustum, bool postLighting); + void render(RenderArgs* renderArgs, float alpha, ViewFrustum* renderFrustum); void setScale(float scale); void setPosition(glm::vec3 position) { _position = position; } void setAverageLoudness(float averageLoudness) { _averageLoudness = averageLoudness; } diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 36873f95ca..178ebc0487 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -216,10 +216,10 @@ void MyAvatar::simulate(float deltaTime) { { PerformanceTimer perfTimer("joints"); // copy out the skeleton joints from the model - _jointData.resize(_skeletonModel.getJointStateCount()); + _jointData.resize(_rig->getJointStateCount()); for (int i = 0; i < _jointData.size(); i++) { JointData& data = _jointData[i]; - data.valid = _skeletonModel.getJointState(i, data.rotation); + data.valid = _rig->getJointStateRotation(i, data.rotation); } } @@ -333,13 +333,13 @@ void MyAvatar::updateFromTrackers(float deltaTime) { // virtual -void MyAvatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, bool postLighting) { +void MyAvatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { // don't render if we've been asked to disable local rendering if (!_shouldRender) { return; // exit early } - Avatar::render(renderArgs, cameraPosition, postLighting); + Avatar::render(renderArgs, cameraPosition); // don't display IK constraints in shadow mode if (Menu::getInstance()->isOptionChecked(MenuOption::ShowIKConstraints) && @@ -1227,7 +1227,7 @@ void MyAvatar::attach(const QString& modelURL, const QString& jointName, const g Avatar::attach(modelURL, jointName, translation, rotation, scale, allowDuplicates, useSaved); } -void MyAvatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, bool postLighting, float glowLevel) { +void MyAvatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, float glowLevel) { if (!(_skeletonModel.isRenderable() && getHead()->getFaceModel().isRenderable())) { return; // wait until all models are loaded @@ -1237,7 +1237,7 @@ void MyAvatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, bo // Render head so long as the camera isn't inside it if (shouldRenderHead(renderArgs)) { - getHead()->render(renderArgs, 1.0f, renderFrustum, postLighting); + getHead()->render(renderArgs, 1.0f, renderFrustum); } getHand()->render(renderArgs, true); } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index ba84ab0e96..0c598c21be 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -46,8 +46,8 @@ public: void preRender(RenderArgs* renderArgs); void updateFromTrackers(float deltaTime); - virtual void render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, bool postLighting = false) override; - virtual void renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, bool postLighting, float glowLevel = 0.0f) override; + virtual void render(RenderArgs* renderArgs, const glm::vec3& cameraPositio) override; + virtual void renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, float glowLevel = 0.0f) override; virtual bool shouldRenderHead(const RenderArgs* renderArgs) const override; // setters diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 765dc9160e..2d9db1abb7 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -13,6 +13,7 @@ #include #include +#include #include #include "Application.h" @@ -787,31 +788,34 @@ void SkeletonModel::resetShapePositionsToDefaultPose() { void SkeletonModel::renderBoundingCollisionShapes(gpu::Batch& batch, float alpha) { const int BALL_SUBDIVISIONS = 10; if (_shapes.isEmpty()) { - // the bounding shape has not been propery computed + // the bounding shape has not been properly computed // so no need to render it return; } - // draw a blue sphere at the capsule endpoint + auto geometryCache = DependencyManager::get(); + auto deferredLighting = DependencyManager::get(); + Transform transform; // = Transform(); + + // draw a blue sphere at the capsule end point glm::vec3 endPoint; _boundingShape.getEndPoint(endPoint); endPoint = endPoint + _translation; - Transform transform = Transform(); transform.setTranslation(endPoint); batch.setModelTransform(transform); - auto geometryCache = DependencyManager::get(); - geometryCache->renderSphere(batch, _boundingShape.getRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS, + deferredLighting->bindSimpleProgram(batch); + geometryCache->renderSphere(batch, _boundingShape.getRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS, glm::vec4(0.6f, 0.6f, 0.8f, alpha)); - // draw a yellow sphere at the capsule startpoint + // draw a yellow sphere at the capsule start point glm::vec3 startPoint; _boundingShape.getStartPoint(startPoint); startPoint = startPoint + _translation; glm::vec3 axis = endPoint - startPoint; - Transform axisTransform = Transform(); - axisTransform.setTranslation(-axis); - batch.setModelTransform(axisTransform); - geometryCache->renderSphere(batch, _boundingShape.getRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS, + transform.setTranslation(startPoint); + batch.setModelTransform(transform); + deferredLighting->bindSimpleProgram(batch); + geometryCache->renderSphere(batch, _boundingShape.getRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS, glm::vec4(0.8f, 0.8f, 0.6f, alpha)); // draw a green cylinder between the two points diff --git a/interface/src/ui/overlays/BillboardOverlay.cpp b/interface/src/ui/overlays/BillboardOverlay.cpp index b2843230f3..d26ecc5c67 100644 --- a/interface/src/ui/overlays/BillboardOverlay.cpp +++ b/interface/src/ui/overlays/BillboardOverlay.cpp @@ -91,6 +91,7 @@ void BillboardOverlay::render(RenderArgs* args) { if (batch) { Transform transform = _transform; transform.postScale(glm::vec3(getDimensions(), 1.0f)); + transform.setRotation(rotation); batch->setModelTransform(transform); batch->setResourceTexture(0, _texture->getGPUTexture()); diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 12bfd606da..0a889fce88 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -41,6 +41,14 @@ bool Rig::isRunningAnimation(AnimationHandlePointer animationHandle) { return _runningAnimations.contains(animationHandle); } +void Rig::deleteAnimations() { + for (QSet::iterator it = _animationHandles.begin(); it != _animationHandles.end(); ) { + (*it)->clearJoints(); + it = _animationHandles.erase(it); + } +} + + float Rig::initJointStates(QVector states, glm::mat4 parentTransform) { _jointStates = states; initJointTransforms(parentTransform); @@ -235,7 +243,12 @@ glm::mat4 Rig::getJointVisibleTransform(int jointIndex) const { return _jointStates[jointIndex].getVisibleTransform(); } -void Rig::simulateInternal(glm::mat4 parentTransform) { +void Rig::simulateInternal(float deltaTime, glm::mat4 parentTransform) { + // update animations + foreach (const AnimationHandlePointer& handle, _runningAnimations) { + handle->simulate(deltaTime); + } + for (int i = 0; i < _jointStates.size(); i++) { updateJointState(i, parentTransform); } diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index 6d282bf8f4..e60116a35e 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -49,6 +49,7 @@ public: void addRunningAnimation(AnimationHandlePointer animationHandle); bool isRunningAnimation(AnimationHandlePointer animationHandle); const QList& getRunningAnimations() const { return _runningAnimations; } + void deleteAnimations(); float initJointStates(QVector states, glm::mat4 parentTransform); bool jointStatesEmpty() { return _jointStates.isEmpty(); }; @@ -81,7 +82,7 @@ public: void setJointTransform(int jointIndex, glm::mat4 newTransform); glm::mat4 getJointVisibleTransform(int jointIndex) const; void setJointVisibleTransform(int jointIndex, glm::mat4 newTransform); - void simulateInternal(glm::mat4 parentTransform); + void simulateInternal(float deltaTime, glm::mat4 parentTransform); bool setJointPosition(int jointIndex, const glm::vec3& position, const glm::quat& rotation, bool useRotation, int lastFreeIndex, bool allIntermediatesFree, const glm::vec3& alignment, float priority, const QVector& freeLineage, glm::mat4 parentTransform); diff --git a/libraries/physics/src/ShapeFactory.cpp b/libraries/physics/src/ShapeFactory.cpp index 74b0304ace..cfe7abd4db 100644 --- a/libraries/physics/src/ShapeFactory.cpp +++ b/libraries/physics/src/ShapeFactory.cpp @@ -43,9 +43,18 @@ btConvexHullShape* ShapeFactory::createConvexHull(const QVector& poin const float MIN_MARGIN = 0.01f; glm::vec3 diagonal = maxCorner - minCorner; - float minDimension = glm::min(diagonal[0], diagonal[1]); - minDimension = glm::min(minDimension, diagonal[2]); - margin = glm::min(glm::max(0.5f * minDimension, MIN_MARGIN), margin); + float smallestDimension = glm::min(diagonal[0], diagonal[1]); + smallestDimension = glm::min(smallestDimension, diagonal[2]); + const float MIN_DIMENSION = 2.0f * MIN_MARGIN + 0.001f; + if (smallestDimension < MIN_DIMENSION) { + for (int i = 0; i < 3; ++i) { + if (diagonal[i] < MIN_DIMENSION) { + diagonal[i] = MIN_DIMENSION; + } + } + smallestDimension = MIN_DIMENSION; + } + margin = glm::min(glm::max(0.5f * smallestDimension, MIN_MARGIN), margin); hull->setMargin(margin); // add the points, correcting for margin diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index af60c91664..bd33e75207 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1365,18 +1365,13 @@ void Model::updateClusterMatrices() { void Model::simulateInternal(float deltaTime) { // update the world space transforms for all joints - - // update animations - foreach (const AnimationHandlePointer& handle, _runningAnimations) { - handle->simulate(deltaTime); - } const FBXGeometry& geometry = _geometry->getFBXGeometry(); glm::mat4 parentTransform = glm::scale(_scale) * glm::translate(_offset) * geometry.offset; - _rig->simulateInternal(parentTransform); + _rig->simulateInternal(deltaTime, parentTransform); _shapesAreDirty = !_shapes.isEmpty(); - + glm::mat4 modelToWorld = glm::mat4_cast(_rotation); for (int i = 0; i < _meshStates.size(); i++) { MeshState& state = _meshStates[i]; @@ -1512,21 +1507,13 @@ void Model::deleteGeometry() { _rig->clearJointStates(); _meshStates.clear(); clearShapes(); - - for (QSet::iterator it = _animationHandles.begin(); it != _animationHandles.end(); ) { - AnimationHandlePointer handle = it->lock(); - if (handle) { - handle->clearJoints(); - it++; - } else { - it = _animationHandles.erase(it); - } - } - + + _rig->deleteAnimations(); + if (_geometry) { _geometry->clearLoadPriority(this); } - + _blendedBlendshapeCoefficients.clear(); } diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index f8d8cbbd74..30c5211990 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -57,7 +57,7 @@ inline uint qHash(const std::shared_ptr& a, uint seed) { /// A generic 3D model displaying geometry loaded from a URL. class Model : public QObject, public PhysicsEntity { Q_OBJECT - + public: typedef RenderArgs::RenderMode RenderMode; @@ -66,58 +66,7 @@ public: Model(RigPointer rig, QObject* parent = nullptr); virtual ~Model(); - - /// enables/disables scale to fit behavior, the model will be automatically scaled to the specified largest dimension - void setScaleToFit(bool scaleToFit, float largestDimension = 0.0f, bool forceRescale = false); - bool getScaleToFit() const { return _scaleToFit; } /// is scale to fit enabled - bool getIsScaledToFit() const { return _scaledToFit; } /// is model scaled to fit - const glm::vec3& getScaleToFitDimensions() const { return _scaleToFitDimensions; } /// the dimensions model is scaled to - void setScaleToFit(bool scaleToFit, const glm::vec3& dimensions); - void setSnapModelToCenter(bool snapModelToCenter) { - setSnapModelToRegistrationPoint(snapModelToCenter, glm::vec3(0.5f,0.5f,0.5f)); - }; - bool getSnapModelToCenter() { - return _snapModelToRegistrationPoint && _registrationPoint == glm::vec3(0.5f,0.5f,0.5f); - } - - void setSnapModelToRegistrationPoint(bool snapModelToRegistrationPoint, const glm::vec3& registrationPoint); - bool getSnapModelToRegistrationPoint() { return _snapModelToRegistrationPoint; } - - void setScale(const glm::vec3& scale); - const glm::vec3& getScale() const { return _scale; } - - void setOffset(const glm::vec3& offset); - const glm::vec3& getOffset() const { return _offset; } - - void setPupilDilation(float dilation) { _pupilDilation = dilation; } - float getPupilDilation() const { return _pupilDilation; } - - void setBlendshapeCoefficients(const QVector& coefficients) { _blendshapeCoefficients = coefficients; } - const QVector& getBlendshapeCoefficients() const { return _blendshapeCoefficients; } - - bool isActive() const { return _geometry && _geometry->isLoaded(); } - - bool isRenderable() const { return !_meshStates.isEmpty() || (isActive() && _geometry->getMeshes().isEmpty()); } - - void setVisibleInScene(bool newValue, std::shared_ptr scene); - bool isVisible() const { return _isVisible; } - - bool isLoaded() const { return _geometry && _geometry->isLoaded(); } - bool isLoadedWithTextures() const { return _geometry && _geometry->isLoadedWithTextures(); } - - void init(); - void reset(); - virtual void simulate(float deltaTime, bool fullUpdate = true); - - void renderSetup(RenderArgs* args); - - // new Scene/Engine rendering support - bool needsFixupInScene() { return !_readyWhenAdded && readyToAddToScene(); } - bool readyToAddToScene(RenderArgs* renderArgs = nullptr) { return !_needsReload && isRenderable() && isActive() && isLoaded(); } - bool addToScene(std::shared_ptr scene, render::PendingChanges& pendingChanges); - bool addToScene(std::shared_ptr scene, render::PendingChanges& pendingChanges, render::Item::Status::Getters& statusGetters); - void removeFromScene(std::shared_ptr scene, render::PendingChanges& pendingChanges); /// Sets the URL of the model to render. /// \param fallback the URL of a fallback model to render if the requested model fails to load @@ -127,22 +76,127 @@ public: bool retainCurrent = false, bool delayLoad = false); const QUrl& getURL() const { return _url; } + // new Scene/Engine rendering support + void setVisibleInScene(bool newValue, std::shared_ptr scene); + bool needsFixupInScene() { return !_readyWhenAdded && readyToAddToScene(); } + bool readyToAddToScene(RenderArgs* renderArgs = nullptr) { + return !_needsReload && isRenderable() && isActive() && isLoaded(); + } + bool initWhenReady(render::ScenePointer scene); + bool addToScene(std::shared_ptr scene, render::PendingChanges& pendingChanges); + bool addToScene(std::shared_ptr scene, + render::PendingChanges& pendingChanges, + render::Item::Status::Getters& statusGetters); + void removeFromScene(std::shared_ptr scene, render::PendingChanges& pendingChanges); + void renderSetup(RenderArgs* args); + bool isRenderable() const { return !_meshStates.isEmpty() || (isActive() && _geometry->getMeshes().isEmpty()); } + virtual void renderJointCollisionShapes(float alpha); + + bool isVisible() const { return _isVisible; } + + AABox getPartBounds(int meshIndex, int partIndex); + void renderPart(RenderArgs* args, int meshIndex, int partIndex, bool translucent); + + bool maybeStartBlender(); + + /// Sets blended vertices computed in a separate thread. + void setBlendedVertices(int blendNumber, const QWeakPointer& geometry, + const QVector& vertices, const QVector& normals); + + bool isLoaded() const { return _geometry && _geometry->isLoaded(); } + bool isLoadedWithTextures() const { return _geometry && _geometry->isLoadedWithTextures(); } + + void setIsWireframe(bool isWireframe) { _isWireframe = isWireframe; } + bool isWireframe() const { return _isWireframe; } + + void init(); + void reset(); + + void setScaleToFit(bool scaleToFit, const glm::vec3& dimensions); + + void setSnapModelToRegistrationPoint(bool snapModelToRegistrationPoint, const glm::vec3& registrationPoint); + bool getSnapModelToRegistrationPoint() { return _snapModelToRegistrationPoint; } + + virtual void simulate(float deltaTime, bool fullUpdate = true); + + /// Returns a reference to the shared geometry. + const QSharedPointer& getGeometry() const { return _geometry; } + + bool isActive() const { return _geometry && _geometry->isLoaded(); } + + Q_INVOKABLE void setTextureWithNameToURL(const QString& name, const QUrl& url) + { _geometry->setTextureWithNameToURL(name, url); } + + bool convexHullContains(glm::vec3 point); + + QStringList getJointNames() const; + + /// Sets the joint state at the specified index. + void setJointState(int index, bool valid, const glm::quat& rotation = glm::quat(), float priority = 1.0f); + + bool findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const glm::vec3& direction, float& distance, + BoxFace& face, QString& extraInfo, bool pickAgainstTriangles = false); + // Set the model to use for collisions Q_INVOKABLE void setCollisionModelURL(const QUrl& url); const QUrl& getCollisionURL() const { return _collisionUrl; } - - void setIsWireframe(bool isWireframe) { _isWireframe = isWireframe; } - bool isWireframe() const { return _isWireframe; } - + + /// Returns a reference to the shared collision geometry. + const QSharedPointer getCollisionGeometry(bool delayLoad = true); + + void setOffset(const glm::vec3& offset); + const glm::vec3& getOffset() const { return _offset; } + /// Sets the distance parameter used for LOD computations. void setLODDistance(float distance) { _lodDistance = distance; } - + + const QList& getRunningAnimations() const { return _rig->getRunningAnimations(); } + /// Clear the joint animation priority + void clearJointAnimationPriority(int index); + + void setScaleToFit(bool scaleToFit, float largestDimension = 0.0f, bool forceRescale = false); + bool getScaleToFit() const { return _scaleToFit; } /// is scale to fit enabled + + void setSnapModelToCenter(bool snapModelToCenter) { + setSnapModelToRegistrationPoint(snapModelToCenter, glm::vec3(0.5f,0.5f,0.5f)); + }; + bool getSnapModelToCenter() { + return _snapModelToRegistrationPoint && _registrationPoint == glm::vec3(0.5f,0.5f,0.5f); + } + + /// Returns the number of joint states in the model. + int getJointStateCount() const { return _rig->getJointStateCount(); } + bool getJointPositionInWorldFrame(int jointIndex, glm::vec3& position) const; + bool getJointRotationInWorldFrame(int jointIndex, glm::quat& rotation) const; + bool getJointCombinedRotation(int jointIndex, glm::quat& rotation) const; + /// \param jointIndex index of joint in model structure + /// \param rotation[out] rotation of joint in model-frame + /// \return true if joint exists + bool getJointRotation(int jointIndex, glm::quat& rotation) const; + + void inverseKinematics(int jointIndex, glm::vec3 position, const glm::quat& rotation, float priority); + /// Returns the extents of the model in its bind pose. Extents getBindExtents() const; /// Returns the extents of the model's mesh Extents getMeshExtents() const; + void setScale(const glm::vec3& scale); + const glm::vec3& getScale() const { return _scale; } + + /// enables/disables scale to fit behavior, the model will be automatically scaled to the specified largest dimension + bool getIsScaledToFit() const { return _scaledToFit; } /// is model scaled to fit + const glm::vec3& getScaleToFitDimensions() const { return _scaleToFitDimensions; } /// the dimensions model is scaled to + +protected: + + void setPupilDilation(float dilation) { _pupilDilation = dilation; } + float getPupilDilation() const { return _pupilDilation; } + + void setBlendshapeCoefficients(const QVector& coefficients) { _blendshapeCoefficients = coefficients; } + const QVector& getBlendshapeCoefficients() const { return _blendshapeCoefficients; } + /// Returns the unscaled extents of the model's mesh Extents getUnscaledMeshExtents() const; @@ -155,15 +209,6 @@ public: /// Returns the scaled equivalent of a point in model space. glm::vec3 calculateScaledOffsetPoint(const glm::vec3& point) const; - /// Returns a reference to the shared geometry. - const QSharedPointer& getGeometry() const { return _geometry; } - - /// Returns a reference to the shared collision geometry. - const QSharedPointer getCollisionGeometry(bool delayLoad = true); - - /// Returns the number of joint states in the model. - int getJointStateCount() const { return _rig->getJointStateCount(); } - /// Fetches the joint state at the specified index. /// \return whether or not the joint state is "valid" (that is, non-default) bool getJointState(int index, glm::quat& rotation) const; @@ -171,25 +216,15 @@ public: /// Fetches the visible joint state at the specified index. /// \return whether or not the joint state is "valid" (that is, non-default) bool getVisibleJointState(int index, glm::quat& rotation) const; - + /// Clear the joint states void clearJointState(int index); - - /// Clear the joint animation priority - void clearJointAnimationPriority(int index); - - /// Sets the joint state at the specified index. - void setJointState(int index, bool valid, const glm::quat& rotation = glm::quat(), float priority = 1.0f); - + /// Returns the index of the parent of the indexed joint, or -1 if not found. int getParentJointIndex(int jointIndex) const; - + /// Returns the index of the last free ancestor of the indexed joint, or -1 if not found. int getLastFreeJointIndex(int jointIndex) const; - - bool getJointPositionInWorldFrame(int jointIndex, glm::vec3& position) const; - bool getJointRotationInWorldFrame(int jointIndex, glm::quat& rotation) const; - bool getJointCombinedRotation(int jointIndex, glm::quat& rotation) const; bool getVisibleJointPositionInWorldFrame(int jointIndex, glm::vec3& position) const; bool getVisibleJointRotationInWorldFrame(int jointIndex, glm::quat& rotation) const; @@ -199,52 +234,15 @@ public: /// \return true if joint exists bool getJointPosition(int jointIndex, glm::vec3& position) const; - /// \param jointIndex index of joint in model structure - /// \param rotation[out] rotation of joint in model-frame - /// \return true if joint exists - bool getJointRotation(int jointIndex, glm::quat& rotation) const; - - QStringList getJointNames() const; - - AnimationHandlePointer createAnimationHandle(); - - const QList& getRunningAnimations() const { return _runningAnimations; } - // virtual overrides from PhysicsEntity virtual void buildShapes(); virtual void updateShapePositions(); - virtual void renderJointCollisionShapes(float alpha); - - bool maybeStartBlender(); - - /// Sets blended vertices computed in a separate thread. - void setBlendedVertices(int blendNumber, const QWeakPointer& geometry, - const QVector& vertices, const QVector& normals); - void setShowTrueJointTransforms(bool show) { _showTrueJointTransforms = show; } - // QVector& getJointStates() { return _rig->getJointStates(); } - // const QVector& getJointStates() const { return _jointStates; } - - void inverseKinematics(int jointIndex, glm::vec3 position, const glm::quat& rotation, float priority); - - Q_INVOKABLE void setTextureWithNameToURL(const QString& name, const QUrl& url) - { _geometry->setTextureWithNameToURL(name, url); } - - bool findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const glm::vec3& direction, float& distance, - BoxFace& face, QString& extraInfo, bool pickAgainstTriangles = false); - bool convexHullContains(glm::vec3 point); - - AABox getPartBounds(int meshIndex, int partIndex); - void renderPart(RenderArgs* args, int meshIndex, int partIndex, bool translucent); - - bool initWhenReady(render::ScenePointer scene); - -protected: QSharedPointer _geometry; void setGeometry(const QSharedPointer& newGeometry); - + glm::vec3 _scale; glm::vec3 _offset; @@ -257,21 +255,21 @@ protected: bool _snapModelToRegistrationPoint; /// is the model's offset automatically adjusted to a registration point in model space bool _snappedToRegistrationPoint; /// are we currently snapped to a registration point glm::vec3 _registrationPoint = glm::vec3(0.5f); /// the point in model space our center is snapped to - + bool _showTrueJointTransforms; class MeshState { public: QVector clusterMatrices; }; - + QVector _meshStates; - + // returns 'true' if needs fullUpdate after geometry change bool updateGeometry(); virtual void initJointStates(QVector states); - + void setScaleInternal(const glm::vec3& scale); void scaleToFit(); void snapToRegistrationPoint(); @@ -298,11 +296,11 @@ protected: /// the original position /// \return true if the joint was found bool restoreJointPosition(int jointIndex, float fraction = 1.0f, float priority = 0.0f); - + /// Computes and returns the extended length of the limb terminating at the specified joint and starting at the joint's /// first free ancestor. float getLimbLength(int jointIndex) const; - + /// Allow sub classes to force invalidating the bboxes void invalidCalculatedMeshBoxes() { _calculatedMeshBoxesValid = false; @@ -316,28 +314,25 @@ protected: // hook for derived classes to be notified when setUrl invalidates the current model. virtual void onInvalidate() {}; -protected slots: void geometryRefreshed(); - + private: - - friend class AnimationHandle; - + void applyNextGeometry(); void deleteGeometry(); QVector createJointStates(const FBXGeometry& geometry); void initJointTransforms(); - + QSharedPointer _nextGeometry; float _lodDistance; float _lodHysteresis; float _nextLODHysteresis; QSharedPointer _collisionGeometry; - + float _pupilDilation; QVector _blendshapeCoefficients; - + QUrl _url; QUrl _collisionUrl; bool _isVisible; @@ -347,10 +342,6 @@ private: gpu::Batch _renderBatch; QVector > > _dilatedTextures; - - QSet _animationHandles; - - QList _runningAnimations; QVector _blendedBlendshapeCoefficients; int _blendNumber; @@ -375,12 +366,12 @@ private: QHash, AABox> _calculatedMeshPartBoxes; // world coordinate AABoxes for all sub mesh part boxes QHash, qint64> _calculatedMeshPartOffset; bool _calculatedMeshPartOffsetValid; - - + + bool _calculatedMeshPartBoxesValid; QVector _calculatedMeshBoxes; // world coordinate AABoxes for all sub mesh boxes bool _calculatedMeshBoxesValid; - + QVector< QVector > _calculatedMeshTriangles; // world coordinate triangles for all sub meshes bool _calculatedMeshTrianglesValid; QMutex _mutex; @@ -420,10 +411,10 @@ private: IS_SHADOW_FLAG, IS_MIRROR_FLAG, //THis means that the mesh is rendered mirrored, not the same as "Rear view mirror" IS_WIREFRAME_FLAG, - + NUM_FLAGS, }; - + enum Flag { IS_TRANSLUCENT = (1 << IS_TRANSLUCENT_FLAG), HAS_LIGHTMAP = (1 << HAS_LIGHTMAP_FLAG), @@ -489,7 +480,7 @@ private: RenderKey(int bitmask) : _flags(bitmask) {} }; - + class RenderPipeline { public: gpu::PipelinePointer _pipeline; @@ -503,7 +494,7 @@ private: public: typedef RenderKey Key; - + void addRenderPipeline(Key key, gpu::ShaderPointer& vertexShader, gpu::ShaderPointer& pixelShader); void initLocations(gpu::ShaderPointer& program, Locations& locations); @@ -511,8 +502,8 @@ private: static RenderPipelineLib _renderPipelineLib; bool _renderCollisionHull; - - + + QSet> _transparentRenderItems; QSet> _opaqueRenderItems; QMap _renderItems;