From f0f5f8871cbd83acdaf4e25ee027cc0eee7d8a04 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 23 Jan 2017 16:08:01 -0800 Subject: [PATCH 01/24] Fix Overlay-as-child of model entity with reg point This fixes as issue where when you set the parent of an overlay to be a model entity with a non-(0.5, 0.5, 0.5) registration point, the overlay would still be positioned relative to the center of the model. The issue is that the default parent joint index was 0, which is the center of the model. Entities had a default parent joint index of -1 (technically 65535 because it is a uint16). Avatars previously defaulted to 0, and that is maintained here. --- libraries/avatars/src/AvatarData.cpp | 1 + libraries/shared/src/SpatiallyNestable.h | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 1fb68fce14..faac0224cf 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -133,6 +133,7 @@ AvatarData::AvatarData() : setBodyPitch(0.0f); setBodyYaw(-90.0f); setBodyRoll(0.0f); + setParentJointIndex(0); ASSERT(sizeof(AvatarDataPacket::Header) == AvatarDataPacket::HEADER_SIZE); ASSERT(sizeof(AvatarDataPacket::MinimalAvatarInfo) == AvatarDataPacket::MINIMAL_AVATAR_INFO_SIZE); diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index f58e2c906c..04ed14f72e 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -26,6 +26,8 @@ using SpatiallyNestableWeakConstPointer = std::weak_ptr using SpatiallyNestablePointer = std::shared_ptr; using SpatiallyNestableConstPointer = std::shared_ptr; +static const uint16_t INVALID_JOINT_INDEX = -1; + enum class NestableType { Entity, Avatar, @@ -180,7 +182,7 @@ protected: const NestableType _nestableType; // EntityItem or an AvatarData QUuid _id; QUuid _parentID; // what is this thing's transform relative to? - quint16 _parentJointIndex { 0 }; // which joint of the parent is this relative to? + quint16 _parentJointIndex { INVALID_JOINT_INDEX }; // which joint of the parent is this relative to? mutable SpatiallyNestableWeakPointer _parent; From 1b05ae8a82e87f7cfb1345891a9b8fd94a81f8be Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 25 Jan 2017 11:00:07 +1300 Subject: [PATCH 02/24] Make handling of Clara.io download-ready state transition more robust --- scripts/system/html/js/marketplacesInject.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/system/html/js/marketplacesInject.js b/scripts/system/html/js/marketplacesInject.js index d5f0f4cb06..9af84455dd 100644 --- a/scripts/system/html/js/marketplacesInject.js +++ b/scripts/system/html/js/marketplacesInject.js @@ -241,11 +241,12 @@ return; } + isDownloading = false; + EventBridge.emitWebEvent(CLARA_IO_DOWNLOAD + " " + zipFileURL); console.log("Clara.io FBX: File download initiated for " + zipFileURL); xmlHttpRequest = null; - isDownloading = false; } isDownloading = true; From 7e56d0fae6d14fd70b721639bdda5e60f5a4de75 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 25 Jan 2017 16:36:06 +1300 Subject: [PATCH 03/24] Fix up Clara.io error handling --- scripts/system/html/js/marketplacesInject.js | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/scripts/system/html/js/marketplacesInject.js b/scripts/system/html/js/marketplacesInject.js index 9af84455dd..a9b35a34e4 100644 --- a/scripts/system/html/js/marketplacesInject.js +++ b/scripts/system/html/js/marketplacesInject.js @@ -226,26 +226,22 @@ return; } + isDownloading = false; + var HTTP_OK = 200; if (this.status !== HTTP_OK) { statusMessage = "Zip file request terminated with " + this.status + " " + this.statusText; console.log("ERROR: Clara.io FBX: " + statusMessage); EventBridge.emitWebEvent(CLARA_IO_STATUS + " " + statusMessage); - return; - } - - if (zipFileURL.slice(-4) !== ".zip") { + } else if (zipFileURL.slice(-4) !== ".zip") { statusMessage = "Error creating zip file for download."; console.log("ERROR: Clara.io FBX: " + statusMessage + ": " + zipFileURL); EventBridge.emitWebEvent(CLARA_IO_STATUS + " " + statusMessage); - return; + } else { + EventBridge.emitWebEvent(CLARA_IO_DOWNLOAD + " " + zipFileURL); + console.log("Clara.io FBX: File download initiated for " + zipFileURL); } - isDownloading = false; - - EventBridge.emitWebEvent(CLARA_IO_DOWNLOAD + " " + zipFileURL); - console.log("Clara.io FBX: File download initiated for " + zipFileURL); - xmlHttpRequest = null; } From dcd632013f719076a14c0e05790628b10c06c3fc Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 25 Jan 2017 16:37:35 +1300 Subject: [PATCH 04/24] Better variable name --- scripts/system/html/js/marketplacesInject.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/scripts/system/html/js/marketplacesInject.js b/scripts/system/html/js/marketplacesInject.js index a9b35a34e4..10970a7749 100644 --- a/scripts/system/html/js/marketplacesInject.js +++ b/scripts/system/html/js/marketplacesInject.js @@ -24,7 +24,7 @@ var canWriteAssets = false; var xmlHttpRequest = null; - var isDownloading = false; // Explicitly track download request status. + var isPreparing = false; // Explicitly track download request status. function injectCommonCode(isDirectoryPage) { @@ -139,7 +139,7 @@ function startAutoDownload() { // One file request at a time. - if (isDownloading) { + if (isPreparing) { console.log("WARNIKNG: Clara.io FBX: Prepare only one download at a time"); return; } @@ -178,7 +178,7 @@ var message = this.responseText.slice(responseTextIndex); var statusMessage = ""; - if (isDownloading) { // Ignore messages in flight after finished/cancelled. + if (isPreparing) { // Ignore messages in flight after finished/cancelled. var lines = message.split(/[\n\r]+/); for (var i = 0, length = lines.length; i < length; i++) { @@ -222,11 +222,11 @@ xmlHttpRequest.onload = function () { var statusMessage = ""; - if (!isDownloading) { + if (!isPreparing) { return; } - isDownloading = false; + isPreparing = false; var HTTP_OK = 200; if (this.status !== HTTP_OK) { @@ -245,7 +245,7 @@ xmlHttpRequest = null; } - isDownloading = true; + isPreparing = true; console.log("Clara.io FBX: Request zip file for " + uuid); EventBridge.emitWebEvent(CLARA_IO_STATUS + " Initiating download"); @@ -298,7 +298,7 @@ } function cancelClaraDownload() { - isDownloading = false; + isPreparing = false; if (xmlHttpRequest) { xmlHttpRequest.abort(); From 74b878a276778960d01f20d6650bafdff9743fe0 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 25 Jan 2017 17:48:58 +1300 Subject: [PATCH 05/24] Fix threading of message box updates --- .../src/scripting/WindowScriptingInterface.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp index 7cfbfb174e..fbeddf41e0 100644 --- a/interface/src/scripting/WindowScriptingInterface.cpp +++ b/interface/src/scripting/WindowScriptingInterface.cpp @@ -253,6 +253,16 @@ int WindowScriptingInterface::createMessageBox(QString title, QString text, int void WindowScriptingInterface::updateMessageBox(int id, QString title, QString text, int buttons, int defaultButton) { auto messageBox = _messageBoxes.value(id); if (messageBox) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "updateMessageBox", + Q_ARG(int, id), + Q_ARG(QString, title), + Q_ARG(QString, text), + Q_ARG(int, buttons), + Q_ARG(int, defaultButton)); + return; + } + messageBox->setProperty("title", title); messageBox->setProperty("text", text); messageBox->setProperty("buttons", buttons); @@ -263,6 +273,12 @@ void WindowScriptingInterface::updateMessageBox(int id, QString title, QString t void WindowScriptingInterface::closeMessageBox(int id) { auto messageBox = _messageBoxes.value(id); if (messageBox) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "closeMessageBox", + Q_ARG(int, id)); + return; + } + disconnect(messageBox); messageBox->setVisible(false); messageBox->deleteLater(); From 9e4f47d57f6101c2107e0f37ee1204f84140f182 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 25 Jan 2017 09:08:54 -0800 Subject: [PATCH 06/24] Update AvatarData to use the default parent joint index --- libraries/avatars/src/AvatarData.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index faac0224cf..1fb68fce14 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -133,7 +133,6 @@ AvatarData::AvatarData() : setBodyPitch(0.0f); setBodyYaw(-90.0f); setBodyRoll(0.0f); - setParentJointIndex(0); ASSERT(sizeof(AvatarDataPacket::Header) == AvatarDataPacket::HEADER_SIZE); ASSERT(sizeof(AvatarDataPacket::MinimalAvatarInfo) == AvatarDataPacket::MINIMAL_AVATAR_INFO_SIZE); From 70664b64eb1becb11ddbee7bc221af8ef832ccd2 Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Wed, 25 Jan 2017 10:59:49 -0800 Subject: [PATCH 07/24] Attempt to account for sparse texture memory overhead --- libraries/gpu-gl/src/gpu/gl45/GL45Backend.h | 27 +-- .../src/gpu/gl45/GL45BackendTexture.cpp | 177 ++---------------- 2 files changed, 21 insertions(+), 183 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h index c338d6e641..2242bba5d9 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h +++ b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h @@ -48,39 +48,18 @@ public: void update(); uvec3 getPageCounts(const uvec3& dimensions) const; uint32_t getPageCount(const uvec3& dimensions) const; + uint32_t getSize() const; GL45Texture& texture; bool sparse { false }; uvec3 pageDimensions { DEFAULT_PAGE_DIMENSION }; GLuint maxSparseLevel { DEFAULT_MAX_SPARSE_LEVEL }; + uint32_t allocatedPages { 0 }; uint32_t maxPages { 0 }; uint32_t pageBytes { 0 }; GLint pageDimensionsIndex { 0 }; }; -#if INCREMENTAL_TRANSFER - struct TransferState { - TransferState(GL45Texture& texture); - uvec3 currentPageSize() const; - void updateMip(); - void populatePage(std::vector& dest); - bool increment(); - - GL45Texture& texture; - GLTexelFormat texelFormat; - uint8_t face { 0 }; - uint16_t mipLevel { 0 }; - uint32_t bytesPerLine { 0 }; - uint32_t bytesPerPixel { 0 }; - uint32_t bytesPerPage { 0 }; - uvec3 mipDimensions; - uvec3 mipOffset; - const uint8_t* srcPointer { nullptr }; - }; - protected: - TransferState _transferState; -#endif - protected: void updateMips() override; void stripToMip(uint16_t newMinMip); @@ -98,8 +77,6 @@ public: void derez(); SparseInfo _sparseInfo; - uint32_t _allocatedPages { 0 }; - uint32_t _lastMipAllocatedPages { 0 }; uint16_t _mipOffset { 0 }; friend class GL45Backend; }; diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index 9b16908244..6632bf936e 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -116,6 +116,8 @@ void SparseInfo::maybeMakeSparse() { } } +#define SPARSE_PAGE_SIZE_OVERHEAD_ESTIMATE 1.3f + // This can only be called after we've established our storage size void SparseInfo::update() { if (!sparse) { @@ -124,6 +126,9 @@ void SparseInfo::update() { glGetTextureParameterIuiv(texture._id, GL_NUM_SPARSE_LEVELS_ARB, &maxSparseLevel); pageBytes = texture._gpuObject.getTexelFormat().getSize(); pageBytes *= pageDimensions.x * pageDimensions.y * pageDimensions.z; + // Testing with a simple texture allocating app shows an estimated 20% GPU memory overhead for + // sparse textures as compared to non-sparse, so we acount for that here. + pageBytes = (uint32_t)(pageBytes * SPARSE_PAGE_SIZE_OVERHEAD_ESTIMATE); for (uint16_t mipLevel = 0; mipLevel <= maxSparseLevel; ++mipLevel) { auto mipDimensions = texture._gpuObject.evalMipDimensions(mipLevel); @@ -146,6 +151,11 @@ uint32_t SparseInfo::getPageCount(const uvec3& dimensions) const { return pageCounts.x * pageCounts.y * pageCounts.z; } + +uint32_t SparseInfo::getSize() const { + return allocatedPages * pageBytes; +} + void GL45Backend::initTextureManagementStage() { // enable the Sparse Texture on gl45 _textureManagement._sparseCapable = true; @@ -160,93 +170,6 @@ void GL45Backend::initTextureManagementStage() { } } -#if INCREMENTAL_TRANSFER - -using TransferState = GL45Backend::GL45Texture::TransferState; - -TransferState::TransferState(GL45Texture& texture) : texture(texture) { -} - -void TransferState::updateMip() { - mipDimensions = texture._gpuObject.evalMipDimensions(mipLevel); - mipOffset = uvec3(); - if (!texture._gpuObject.isStoredMipFaceAvailable(mipLevel, face)) { - srcPointer = nullptr; - return; - } - - auto mip = texture._gpuObject.accessStoredMipFace(mipLevel, face); - texelFormat = gl::GLTexelFormat::evalGLTexelFormat(texture._gpuObject.getTexelFormat(), mip->getFormat()); - srcPointer = mip->readData(); - bytesPerLine = (uint32_t)mip->getSize() / mipDimensions.y; - bytesPerPixel = bytesPerLine / mipDimensions.x; -} - -bool TransferState::increment() { - const SparseInfo& sparse = texture._sparseInfo; - if ((mipOffset.x + sparse.pageDimensions.x) < mipDimensions.x) { - mipOffset.x += sparse.pageDimensions.x; - return true; - } - - if ((mipOffset.y + sparse.pageDimensions.y) < mipDimensions.y) { - mipOffset.x = 0; - mipOffset.y += sparse.pageDimensions.y; - return true; - } - - if (mipOffset.z + sparse.pageDimensions.z < mipDimensions.z) { - mipOffset.x = 0; - mipOffset.y = 0; - ++mipOffset.z; - return true; - } - - // Done with this mip?, move on to the next mip - if (mipLevel + 1 < texture.usedMipLevels()) { - mipOffset = uvec3(0); - ++mipLevel; - updateMip(); - return true; - } - - uint8_t maxFace = (uint8_t)((texture._target == GL_TEXTURE_CUBE_MAP) ? GLTexture::CUBE_NUM_FACES : 1); - uint8_t nextFace = face + 1; - // Done with this face? Move on to the next - if (nextFace < maxFace) { - ++face; - mipOffset = uvec3(0); - mipLevel = 0; - updateMip(); - return true; - } - - return false; -} - -void TransferState::populatePage(std::vector& buffer) { - uvec3 pageSize = currentPageSize(); - auto bytesPerPageLine = bytesPerPixel * pageSize.x; - if (0 != (bytesPerPageLine % DEFAULT_GL_PIXEL_ALIGNMENT)) { - bytesPerPageLine += DEFAULT_GL_PIXEL_ALIGNMENT - (bytesPerPageLine % DEFAULT_GL_PIXEL_ALIGNMENT); - assert(0 == (bytesPerPageLine % DEFAULT_GL_PIXEL_ALIGNMENT)); - } - auto totalPageSize = bytesPerPageLine * pageSize.y; - if (totalPageSize > buffer.size()) { - buffer.resize(totalPageSize); - } - uint8_t* dst = &buffer[0]; - for (uint32_t y = 0; y < pageSize.y; ++y) { - uint32_t srcOffset = (bytesPerLine * (mipOffset.y + y)) + (bytesPerPixel * mipOffset.x); - uint32_t dstOffset = bytesPerPageLine * y; - memcpy(dst + dstOffset, srcPointer + srcOffset, pageSize.x * bytesPerPixel); - } -} - -uvec3 TransferState::currentPageSize() const { - return glm::clamp(mipDimensions - mipOffset, uvec3(1), texture._sparseInfo.pageDimensions); -} -#endif GLuint GL45Texture::allocate(const Texture& texture) { GLuint result; @@ -260,17 +183,11 @@ GLuint GL45Backend::getTextureID(const TexturePointer& texture, bool transfer) { GL45Texture::GL45Texture(const std::weak_ptr& backend, const Texture& texture, GLuint externalId) : GLTexture(backend, texture, externalId), _sparseInfo(*this) -#if INCREMENTAL_TRANSFER -, _transferState(*this) -#endif { } GL45Texture::GL45Texture(const std::weak_ptr& backend, const Texture& texture, bool transferrable) : GLTexture(backend, texture, allocate(texture), transferrable), _sparseInfo(*this) -#if INCREMENTAL_TRANSFER -, _transferState(*this) -#endif { auto theBackend = _backend.lock(); @@ -316,12 +233,12 @@ GL45Texture::~GL45Texture() { }); auto deallocatedPages = _sparseInfo.getPageCount(mipDimensions) * maxFace; - assert(deallocatedPages <= _allocatedPages); - _allocatedPages -= deallocatedPages; + assert(deallocatedPages <= _sparseInfo.allocatedPages); + _sparseInfo.allocatedPages -= deallocatedPages; } - if (0 != _allocatedPages) { - qCWarning(gpugl45logging) << "Allocated pages remaining " << _id << " " << _allocatedPages; + if (0 != _sparseInfo.allocatedPages) { + qCWarning(gpugl45logging) << "Allocated pages remaining " << _id << " " << _sparseInfo.allocatedPages; } auto size = _size; @@ -365,9 +282,9 @@ void GL45Texture::updateSize() const { } if (_transferrable && _sparseInfo.sparse) { - auto size = _allocatedPages * _sparseInfo.pageBytes; + auto size = _sparseInfo.getSize(); Backend::updateTextureGPUSparseMemoryUsage(_size, size); - setSize(_allocatedPages * _sparseInfo.pageBytes); + setSize(size); } else { setSize(_gpuObject.evalTotalSize(_mipOffset)); } @@ -376,20 +293,16 @@ void GL45Texture::updateSize() const { void GL45Texture::startTransfer() { Parent::startTransfer(); _sparseInfo.update(); -#if INCREMENTAL_TRANSFER - _transferState.updateMip(); -#endif } bool GL45Texture::continueTransfer() { -#if !INCREMENTAL_TRANSFER size_t maxFace = GL_TEXTURE_CUBE_MAP == _target ? CUBE_NUM_FACES : 1; for (uint8_t face = 0; face < maxFace; ++face) { for (uint16_t mipLevel = _minMip; mipLevel <= _maxMip; ++mipLevel) { auto size = _gpuObject.evalMipDimensions(mipLevel); if (_sparseInfo.sparse && mipLevel <= _sparseInfo.maxSparseLevel) { glTexturePageCommitmentEXT(_id, mipLevel, 0, 0, face, size.x, size.y, 1, GL_TRUE); - _allocatedPages += _sparseInfo.getPageCount(size); + _sparseInfo.allocatedPages += _sparseInfo.getPageCount(size); } if (_gpuObject.isStoredMipFaceAvailable(mipLevel, face)) { auto mip = _gpuObject.accessStoredMipFace(mipLevel, face); @@ -413,58 +326,6 @@ bool GL45Texture::continueTransfer() { } } return false; -#else - static std::vector buffer; - if (buffer.empty()) { - buffer.resize(DEFAULT_PAGE_BUFFER_SIZE); - } - const uvec3 pageSize = _transferState.currentPageSize(); - const uvec3& offset = _transferState.mipOffset; - - if (_sparseInfo.sparse && _transferState.mipLevel <= _sparseInfo.maxSparseLevel) { - if (_allocatedPages > _sparseInfo.maxPages) { - qCWarning(gpugl45logging) << "Exceeded max page allocation!"; - } - glTexturePageCommitmentEXT(_id, _transferState.mipLevel, - offset.x, offset.y, _transferState.face, - pageSize.x, pageSize.y, pageSize.z, - GL_TRUE); - ++_allocatedPages; - } - - if (_transferState.srcPointer) { - // Transfer the mip data - _transferState.populatePage(buffer); - if (GL_TEXTURE_2D == _target) { - glTextureSubImage2D(_id, _transferState.mipLevel, - offset.x, offset.y, - pageSize.x, pageSize.y, - _transferState.texelFormat.format, _transferState.texelFormat.type, &buffer[0]); - } else if (GL_TEXTURE_CUBE_MAP == _target) { - auto target = CUBE_FACE_LAYOUT[_transferState.face]; - // DSA ARB does not work on AMD, so use EXT - // glTextureSubImage3D(_id, mipLevel, 0, 0, face, size.x, size.y, 1, texelFormat.format, texelFormat.type, mip->readData()); - glTextureSubImage2DEXT(_id, target, _transferState.mipLevel, - offset.x, offset.y, - pageSize.x, pageSize.y, - _transferState.texelFormat.format, _transferState.texelFormat.type, &buffer[0]); - } - } - - serverWait(); - auto currentMip = _transferState.mipLevel; - auto result = _transferState.increment(); - if (_sparseInfo.sparse && _transferState.mipLevel != currentMip && currentMip <= _sparseInfo.maxSparseLevel) { - auto mipDimensions = _gpuObject.evalMipDimensions(currentMip); - auto mipExpectedPages = _sparseInfo.getPageCount(mipDimensions); - auto newPages = _allocatedPages - _lastMipAllocatedPages; - if (newPages != mipExpectedPages) { - qCWarning(gpugl45logging) << "Unexpected page allocation size... " << newPages << " " << mipExpectedPages; - } - _lastMipAllocatedPages = _allocatedPages; - } - return result; -#endif } void GL45Texture::finishTransfer() { @@ -545,8 +406,8 @@ void GL45Texture::stripToMip(uint16_t newMinMip) { }); auto deallocatedPages = _sparseInfo.getPageCount(mipDimensions) * maxFace; - assert(deallocatedPages < _allocatedPages); - _allocatedPages -= deallocatedPages; + assert(deallocatedPages < _sparseInfo.allocatedPages); + _sparseInfo.allocatedPages -= deallocatedPages; } _minMip = newMinMip; } else { From 7b896f961b2f7b5d6909bd3149b433684d1c8b4e Mon Sep 17 00:00:00 2001 From: kunalgosar Date: Wed, 25 Jan 2017 13:00:57 -0800 Subject: [PATCH 08/24] change server to default to not auto-muting --- assignment-client/src/audio/AudioMixer.cpp | 4 ++-- domain-server/resources/describe-settings.json | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 07639867eb..06ab06116c 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -38,7 +38,7 @@ static const float LOUDNESS_TO_DISTANCE_RATIO = 0.00001f; static const float DEFAULT_ATTENUATION_PER_DOUBLING_IN_DISTANCE = 0.5f; // attenuation = -6dB * log2(distance) -static const float DEFAULT_NOISE_MUTING_THRESHOLD = 0.003f; +static const float DEFAULT_NOISE_MUTING_THRESHOLD = 1.0f; static const QString AUDIO_MIXER_LOGGING_TARGET_NAME = "audio-mixer"; static const QString AUDIO_ENV_GROUP_KEY = "audio_env"; static const QString AUDIO_BUFFER_GROUP_KEY = "audio_buffer"; @@ -69,7 +69,7 @@ AudioMixer::AudioMixer(ReceivedMessage& message) : packetReceiver.registerListener(PacketType::KillAvatar, this, "handleKillAvatarPacket"); packetReceiver.registerListener(PacketType::NodeMuteRequest, this, "handleNodeMuteRequestPacket"); packetReceiver.registerListener(PacketType::RadiusIgnoreRequest, this, "handleRadiusIgnoreRequestPacket"); - packetReceiver.registerListener(PacketType::RequestsDomainListData, this, "handleRequestsDomainListDataPacket"); + packetReceiver.registerListener(PacketType::RequestsDomainListData, this, "handleRequestsDomainListDataPacket"); packetReceiver.registerListener(PacketType::PerAvatarGainSet, this, "handlePerAvatarGainSetDataPacket"); connect(nodeList.data(), &NodeList::nodeKilled, this, &AudioMixer::handleNodeKilled); diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index 0084e51239..84fccdafe7 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -1089,9 +1089,9 @@ { "name": "noise_muting_threshold", "label": "Noise Muting Threshold", - "help": "Loudness value for noise background between 0 and 1.0 (0: mute everyone, 1.0: never mute)", - "placeholder": "0.003", - "default": "0.003", + "help": "Loudness value for noise background between 0 and 1.0 (0: mute everyone, 1.0: never mute). 0.003 is a typical setting to mute loud people.", + "placeholder": "1.0", + "default": "1.0", "advanced": false }, { From 08bba5f45f221ea9d0ec3cce11a8d8526abfd08b Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 19 Jan 2017 17:31:29 -0800 Subject: [PATCH 09/24] add and remove some profile data points --- interface/src/avatar/Avatar.cpp | 44 ++++++++++++++-------------- libraries/animation/src/Rig.cpp | 1 + libraries/render-utils/src/Model.cpp | 2 -- 3 files changed, 23 insertions(+), 24 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 6061812d2a..a3eaeab46a 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -308,6 +308,7 @@ void Avatar::setShouldDie() { } void Avatar::simulate(float deltaTime) { + PROFILE_RANGE(simulation, "simulate"); PerformanceTimer perfTimer("simulate"); if (!isDead() && !_motionState) { @@ -317,8 +318,8 @@ void Avatar::simulate(float deltaTime) { bool avatarInView = false; { // update the shouldAnimate flag to match whether or not we will render the avatar. - PerformanceTimer perfTimer("cull"); { + PROFILE_RANGE(simulation, "cull"); // simple frustum check PerformanceTimer perfTimer("inView"); ViewFrustum viewFrustum; @@ -326,7 +327,7 @@ void Avatar::simulate(float deltaTime) { avatarInView = viewFrustum.sphereIntersectsFrustum(getPosition(), getBoundingRadius()) || viewFrustum.boxIntersectsFrustum(_skeletonModel->getRenderableMeshBound()); } - PerformanceTimer lodPerfTimer("LOD"); + PROFILE_RANGE(simulation, "LOD"); if (avatarInView) { const float MINIMUM_VISIBILITY_FOR_ON = 0.4f; const float MAXIMUM_VISIBILITY_FOR_OFF = 0.6f; @@ -346,19 +347,17 @@ void Avatar::simulate(float deltaTime) { } } - uint64_t start = usecTimestampNow(); - // CRUFT? _shouldSkipRender is never set 'true' - if (_shouldAnimate && avatarInView && !_shouldSkipRender) { - { - PerformanceTimer perfTimer("skeleton"); + { + PROFILE_RANGE(simulation, "updateJoints"); + uint64_t start = usecTimestampNow(); + // CRUFT? _shouldSkipRender is never set 'true' + if (_shouldAnimate && avatarInView && !_shouldSkipRender) { _skeletonModel->getRig()->copyJointsFromJointData(_jointData); _skeletonModel->simulate(deltaTime, _hasNewJointRotations || _hasNewJointTranslations); locationChanged(); // joints changed, so if there are any children, update them. _hasNewJointRotations = false; _hasNewJointTranslations = false; - } - { - PerformanceTimer perfTimer("head"); + glm::vec3 headPosition = getPosition(); if (!_skeletonModel->getHeadPosition(headPosition)) { headPosition = getPosition(); @@ -367,15 +366,14 @@ void Avatar::simulate(float deltaTime) { head->setPosition(headPosition); head->setScale(getUniformScale()); head->simulate(deltaTime, false, !_shouldAnimate); + } else { + // a non-full update is still required so that the position, rotation, scale and bounds of the skeletonModel are updated. + getHead()->setPosition(getPosition()); + _skeletonModel->simulate(deltaTime, false); } - } else { - // a non-full update is still required so that the position, rotation, scale and bounds of the skeletonModel are updated. - getHead()->setPosition(getPosition()); - PerformanceTimer perfTimer("skeleton"); - _skeletonModel->simulate(deltaTime, false); + timeProcessingJoints += usecTimestampNow() - start; + numJointsProcessed += _jointData.size(); } - timeProcessingJoints += usecTimestampNow() - start; - numJointsProcessed += _jointData.size(); // update animation for display name fade in/out if ( _displayNameTargetAlpha != _displayNameAlpha) { @@ -394,11 +392,13 @@ void Avatar::simulate(float deltaTime) { _displayNameAlpha = abs(_displayNameAlpha - _displayNameTargetAlpha) < 0.01f ? _displayNameTargetAlpha : _displayNameAlpha; } - measureMotionDerivatives(deltaTime); - - simulateAttachments(deltaTime); - updatePalms(); - updateAvatarEntities(); + { + PROFILE_RANGE(simulation, "misc"); + measureMotionDerivatives(deltaTime); + simulateAttachments(deltaTime); + updatePalms(); + updateAvatarEntities(); + } } bool Avatar::isLookingAtMe(AvatarSharedPointer avatar) const { diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index fdeeb01739..ac16b16c1d 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -1269,6 +1269,7 @@ void Rig::copyJointsIntoJointData(QVector& jointDataVec) const { void Rig::copyJointsFromJointData(const QVector& jointDataVec) { PerformanceTimer perfTimer("copyJoints"); + PROFILE_RANGE(simulation_animation_detail, "copyJoints"); if (_animSkeleton && jointDataVec.size() == (int)_internalPoseSet._relativePoses.size()) { // make a vector of rotations in absolute-geometry-frame const AnimPoseVec& absoluteDefaultPoses = _animSkeleton->getAbsoluteDefaultPoses(); diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index b79e69a9b7..d3fddc96d9 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -272,8 +272,6 @@ void Model::reset() { } bool Model::updateGeometry() { - PROFILE_RANGE(render_detail, __FUNCTION__); - PerformanceTimer perfTimer("Model::updateGeometry"); bool needFullUpdate = false; if (!isLoaded()) { From 88bf12616833f8be17b121a0af20126b81c488d4 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 20 Jan 2017 14:22:13 -0800 Subject: [PATCH 10/24] remove old avatar culling and LOD logic --- interface/src/avatar/Avatar.cpp | 50 ++++++-------------------- interface/src/avatar/Avatar.h | 6 +--- interface/src/avatar/AvatarManager.cpp | 6 ++-- libraries/avatars/src/AvatarData.cpp | 9 +++-- libraries/avatars/src/AvatarData.h | 3 +- 5 files changed, 21 insertions(+), 53 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index a3eaeab46a..73c8a7553b 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -307,7 +307,7 @@ void Avatar::setShouldDie() { _owningAvatarMixer.clear(); } -void Avatar::simulate(float deltaTime) { +void Avatar::simulate(float deltaTime, bool inView) { PROFILE_RANGE(simulation, "simulate"); PerformanceTimer perfTimer("simulate"); @@ -316,47 +316,18 @@ void Avatar::simulate(float deltaTime) { } animateScaleChanges(deltaTime); - bool avatarInView = false; - { // update the shouldAnimate flag to match whether or not we will render the avatar. - { - PROFILE_RANGE(simulation, "cull"); - // simple frustum check - PerformanceTimer perfTimer("inView"); - ViewFrustum viewFrustum; - qApp->copyDisplayViewFrustum(viewFrustum); - avatarInView = viewFrustum.sphereIntersectsFrustum(getPosition(), getBoundingRadius()) - || viewFrustum.boxIntersectsFrustum(_skeletonModel->getRenderableMeshBound()); - } - PROFILE_RANGE(simulation, "LOD"); - if (avatarInView) { - const float MINIMUM_VISIBILITY_FOR_ON = 0.4f; - const float MAXIMUM_VISIBILITY_FOR_OFF = 0.6f; - ViewFrustum viewFrustum; - qApp->copyViewFrustum(viewFrustum); - float visibility = calculateRenderAccuracy(viewFrustum.getPosition(), - getBounds(), DependencyManager::get()->getOctreeSizeScale()); - if (!_shouldAnimate) { - if (visibility > MINIMUM_VISIBILITY_FOR_ON) { - _shouldAnimate = true; - qCDebug(interfaceapp) << "Restoring" << (isMyAvatar() ? "myself" : getSessionUUID()) << "for visibility" << visibility; - } - } else if (visibility < MAXIMUM_VISIBILITY_FOR_OFF) { - _shouldAnimate = false; - qCDebug(interfaceapp) << "Optimizing" << (isMyAvatar() ? "myself" : getSessionUUID()) << "for visibility" << visibility; - } - } - } - { PROFILE_RANGE(simulation, "updateJoints"); uint64_t start = usecTimestampNow(); - // CRUFT? _shouldSkipRender is never set 'true' - if (_shouldAnimate && avatarInView && !_shouldSkipRender) { + if (inView) { + // adebug BOOKMARK: can avoid copying duplicate joint data + // - can avoid some work when transform not changed (see SkeletonModel::simulate() and Model::setTranslation()) + // - can maybe use _hasNewFoo instead of AvatarData::_jointDataVersion + // - can maybe avoid stuff if blendShapes haven't changed _skeletonModel->getRig()->copyJointsFromJointData(_jointData); - _skeletonModel->simulate(deltaTime, _hasNewJointRotations || _hasNewJointTranslations); + _skeletonModel->simulate(deltaTime, _hasNewJointData); locationChanged(); // joints changed, so if there are any children, update them. - _hasNewJointRotations = false; - _hasNewJointTranslations = false; + _hasNewJointData = false; glm::vec3 headPosition = getPosition(); if (!_skeletonModel->getHeadPosition(headPosition)) { @@ -365,7 +336,8 @@ void Avatar::simulate(float deltaTime) { Head* head = getHead(); head->setPosition(headPosition); head->setScale(getUniformScale()); - head->simulate(deltaTime, false, !_shouldAnimate); + const bool useBillboard = false; // HACK + head->simulate(deltaTime, false, useBillboard); } else { // a non-full update is still required so that the position, rotation, scale and bounds of the skeletonModel are updated. getHead()->setPosition(getPosition()); @@ -1106,7 +1078,7 @@ int Avatar::parseDataFromBuffer(const QByteArray& buffer) { if (_moving && _motionState) { _motionState->addDirtyFlags(Simulation::DIRTY_POSITION); } - if (_moving || _hasNewJointRotations || _hasNewJointTranslations) { + if (_moving || _hasNewJointData) { locationChanged(); } diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index d370402865..75af330452 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -68,7 +68,7 @@ public: void init(); void updateAvatarEntities(); - void simulate(float deltaTime); + void simulate(float deltaTime, bool inView); virtual void simulateAttachments(float deltaTime); virtual void render(RenderArgs* renderArgs, const glm::vec3& cameraPosition); @@ -141,8 +141,6 @@ public: Q_INVOKABLE glm::vec3 getAcceleration() const { return _acceleration; } - Q_INVOKABLE bool getShouldRender() const { return !_shouldSkipRender; } - /// Scales a world space position vector relative to the avatar position and scale /// \param vector position to be scaled. Will store the result void scaleVectorRelativeToPosition(glm::vec3 &positionToScale) const; @@ -265,8 +263,6 @@ private: int _rightPointerGeometryID { 0 }; int _nameRectGeometryID { 0 }; bool _initialized; - bool _shouldAnimate { true }; - bool _shouldSkipRender { false }; bool _isLookAtTarget { false }; bool _inScene { false }; diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index b0dc9922ff..4ba3cbdc1a 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -165,7 +165,8 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { ++avatarIterator; } else { avatar->ensureInScene(avatar); - avatar->simulate(deltaTime); + const bool inView = true; // HACK + avatar->simulate(deltaTime, inView); ++avatarIterator; avatar->updateRenderItem(pendingChanges); @@ -210,7 +211,8 @@ void AvatarManager::simulateAvatarFades(float deltaTime) { ++fadingIterator; } } else { - avatar->simulate(deltaTime); + const bool inView = true; // HACK + avatar->simulate(deltaTime, inView); ++fadingIterator; } } diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 1fb68fce14..1aacb00c04 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -120,8 +120,7 @@ AvatarData::AvatarData() : _handState(0), _keyState(NO_KEY_DOWN), _forceFaceTrackerConnected(false), - _hasNewJointRotations(true), - _hasNewJointTranslations(true), + _hasNewJointData(true), _headData(NULL), _displayNameTargetAlpha(1.0f), _displayNameAlpha(1.0f), @@ -553,7 +552,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { glm::vec3 newEulerAngles(pitch, yaw, roll); glm::quat newOrientation = glm::quat(glm::radians(newEulerAngles)); if (currentOrientation != newOrientation) { - _hasNewJointRotations = true; + _hasNewJointData = true; setLocalOrientation(newOrientation); } @@ -680,7 +679,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { JointData& data = _jointData[i]; if (validRotations[i]) { sourceBuffer += unpackOrientationQuatFromSixBytes(sourceBuffer, data.rotation); - _hasNewJointRotations = true; + _hasNewJointData = true; data.rotationSet = true; } } @@ -715,7 +714,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { JointData& data = _jointData[i]; if (validTranslations[i]) { sourceBuffer += unpackFloatVec3FromSignedTwoByteFixed(sourceBuffer, data.translation, TRANSLATION_COMPRESSION_RADIX); - _hasNewJointTranslations = true; + _hasNewJointData = true; data.translationSet = true; } } diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index db06d52092..a3c9e537ca 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -427,8 +427,7 @@ protected: KeyState _keyState; bool _forceFaceTrackerConnected; - bool _hasNewJointRotations; // set in AvatarData, cleared in Avatar - bool _hasNewJointTranslations; // set in AvatarData, cleared in Avatar + bool _hasNewJointData; // set in AvatarData, cleared in Avatar HeadData* _headData; From d8a10320d1377652d8e7281a6c93047be6558843 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 23 Jan 2017 14:04:24 -0800 Subject: [PATCH 11/24] fix warning about implicit cast --- libraries/shared/src/ViewFrustum.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/shared/src/ViewFrustum.cpp b/libraries/shared/src/ViewFrustum.cpp index b4ed462639..a0b7d17e46 100644 --- a/libraries/shared/src/ViewFrustum.cpp +++ b/libraries/shared/src/ViewFrustum.cpp @@ -729,7 +729,7 @@ void ViewFrustum::evalProjectionMatrix(glm::mat4& proj) const { glm::mat4 ViewFrustum::evalProjectionMatrixRange(float rangeNear, float rangeFar) const { // make sure range near far make sense - assert(rangeNear > 0.0); + assert(rangeNear > 0.0f); assert(rangeFar > rangeNear); // recreate a projection matrix for only a range of depth of this frustum. @@ -738,7 +738,7 @@ glm::mat4 ViewFrustum::evalProjectionMatrixRange(float rangeNear, float rangeFar glm::mat4 rangeProj = _projection; float A = -(rangeFar + rangeNear) / (rangeFar - rangeNear); - float B = -2 * rangeFar*rangeNear / ((rangeFar - rangeNear)); + float B = -2.0f * rangeFar*rangeNear / ((rangeFar - rangeNear)); rangeProj[2][2] = A; rangeProj[3][2] = B; From 09707217ec40c64470583c2e58adc397629d583a Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 23 Jan 2017 14:04:33 -0800 Subject: [PATCH 12/24] remove Model::simulateInternal() --- libraries/render-utils/src/Model.cpp | 10 +++------- libraries/render-utils/src/Model.h | 1 - 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index d3fddc96d9..1e83a874dc 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1126,7 +1126,9 @@ void Model::simulate(float deltaTime, bool fullUpdate) { if (_snapModelToRegistrationPoint && !_snappedToRegistrationPoint) { snapToRegistrationPoint(); } - simulateInternal(deltaTime); + // update the world space transforms for all joints + glm::mat4 parentTransform = glm::scale(_scale) * glm::translate(_offset); + updateRig(deltaTime, parentTransform); } } @@ -1136,12 +1138,6 @@ void Model::updateRig(float deltaTime, glm::mat4 parentTransform) { _rig->updateAnimations(deltaTime, parentTransform); } -void Model::simulateInternal(float deltaTime) { - // update the world space transforms for all joints - glm::mat4 parentTransform = glm::scale(_scale) * glm::translate(_offset); - updateRig(deltaTime, parentTransform); -} - // virtual void Model::updateClusterMatrices() { PerformanceTimer perfTimer("Model::updateClusterMatrices"); diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 246d67180e..3f673b0250 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -312,7 +312,6 @@ protected: void scaleToFit(); void snapToRegistrationPoint(); - void simulateInternal(float deltaTime); virtual void updateRig(float deltaTime, glm::mat4 parentTransform); /// Restores the indexed joint to its default position. From e3634239921cc09c20096195203cd5d7114e8929 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 23 Jan 2017 14:05:25 -0800 Subject: [PATCH 13/24] compute priority of avatar and sort before update --- interface/src/avatar/Avatar.cpp | 5 +- interface/src/avatar/Avatar.h | 4 ++ interface/src/avatar/AvatarManager.cpp | 87 +++++++++++++++++++------- 3 files changed, 69 insertions(+), 27 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 73c8a7553b..260373bf50 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -127,6 +127,7 @@ Avatar::Avatar(RigPointer rig) : _nameRectGeometryID = geometryCache->allocateID(); _leftPointerGeometryID = geometryCache->allocateID(); _rightPointerGeometryID = geometryCache->allocateID(); + _lastRenderUpdateTime = usecTimestampNow(); } Avatar::~Avatar() { @@ -320,10 +321,6 @@ void Avatar::simulate(float deltaTime, bool inView) { PROFILE_RANGE(simulation, "updateJoints"); uint64_t start = usecTimestampNow(); if (inView) { - // adebug BOOKMARK: can avoid copying duplicate joint data - // - can avoid some work when transform not changed (see SkeletonModel::simulate() and Model::setTranslation()) - // - can maybe use _hasNewFoo instead of AvatarData::_jointDataVersion - // - can maybe avoid stuff if blendShapes haven't changed _skeletonModel->getRig()->copyJointsFromJointData(_jointData); _skeletonModel->simulate(deltaTime, _hasNewJointData); locationChanged(); // joints changed, so if there are any children, update them. diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 75af330452..3276eaff47 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -177,6 +177,9 @@ public: glm::vec3 getUncachedRightPalmPosition() const; glm::quat getUncachedRightPalmRotation() const; + uint64_t getLastRenderUpdateTime() const { return _lastRenderUpdateTime; } + void setLastRenderUpdateTime(uint64_t time) { _lastRenderUpdateTime = time; } + Q_INVOKABLE void setShouldDie(); public slots: @@ -259,6 +262,7 @@ protected: void ensureInScene(AvatarSharedPointer self); private: + uint64_t _lastRenderUpdateTime { 0 }; int _leftPointerGeometryID { 0 }; int _rightPointerGeometryID { 0 }; int _nameRectGeometryID { 0 }; diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 4ba3cbdc1a..e3d3164b68 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -132,53 +132,94 @@ void AvatarManager::updateMyAvatar(float deltaTime) { Q_LOGGING_CATEGORY(trace_simulation_avatar, "trace.simulation.avatar"); +class AvatarPriority { +public: + AvatarPriority(AvatarSharedPointer a, float p) : avatar(a), priority(p) {} + AvatarSharedPointer avatar; + float priority; + // NOTE: we invert the less-than operator to sort high priorities to front + bool operator<(const AvatarPriority& other) const { return priority > other.priority; } +}; + void AvatarManager::updateOtherAvatars(float deltaTime) { // lock the hash for read to check the size QReadLocker lock(&_hashLock); - if (_avatarHash.size() < 2 && _avatarFades.isEmpty()) { return; } - lock.unlock(); bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::updateAvatars()"); PerformanceTimer perfTimer("otherAvatars"); - render::PendingChanges pendingChanges; - // simulate avatars - auto hashCopy = getHashCopy(); + auto avatarMap = getHashCopy(); + QList avatarList = avatarMap.values(); + uint64_t now = usecTimestampNow(); + ViewFrustum cameraView; + qApp->copyDisplayViewFrustum(cameraView); + glm::vec3 frustumCenter = cameraView.getPosition(); - uint64_t start = usecTimestampNow(); - AvatarHash::iterator avatarIterator = hashCopy.begin(); - while (avatarIterator != hashCopy.end()) { - auto avatar = std::static_pointer_cast(avatarIterator.value()); + const float OUT_OF_VIEW_PENALTY = -10.0; + std::priority_queue sortedAvatars; + for (int32_t i = 0; i < avatarList.size(); ++i) { + const auto& avatar = std::static_pointer_cast(avatarList.at(i)); if (avatar == _myAvatar || !avatar->isInitialized()) { // DO NOT update _myAvatar! Its update has already been done earlier in the main loop. // DO NOT update or fade out uninitialized Avatars - ++avatarIterator; - } else if (avatar->shouldDie()) { - removeAvatar(avatarIterator.key()); - ++avatarIterator; - } else { - avatar->ensureInScene(avatar); - const bool inView = true; // HACK - avatar->simulate(deltaTime, inView); - ++avatarIterator; - - avatar->updateRenderItem(pendingChanges); + continue; } + if (avatar->shouldDie()) { + removeAvatar(avatar->getID()); + continue; + } + + // priority = weighted linear combination of: + // (a) apparentSize + // (b) proximity to center of view, and + // (c) time since last update + glm::vec3 avatarPosition = avatar->getPosition(); + glm::vec3 offset = avatarPosition - frustumCenter; + float distance = glm::length(offset) + 0.001f; // add 1mm to avoid divide by zero + float radius = avatar->getBoundingRadius(); + const glm::vec3& forward = cameraView.getDirection(); + float apparentSize = radius / distance; + float cosineAngle = glm::length(offset - glm::dot(offset, forward) * forward) / distance; + float age = (float)(now - avatar->getLastRenderUpdateTime()) / (float)(USECS_PER_SECOND); + float priority = 2.0f * apparentSize + 0.25f * cosineAngle + age; + + // decrement priority of avatars outside keyhole + if (distance > cameraView.getCenterRadius()) { + if (!cameraView.sphereIntersectsFrustum(avatarPosition, radius)) { + priority += OUT_OF_VIEW_PENALTY; + } + } + sortedAvatars.push(AvatarPriority(avatar, priority)); + } + + render::PendingChanges pendingChanges; + const uint64_t AVATAR_RENDER_UPDATE_TIME_BUDGET = 2 * USECS_PER_MSEC; + uint64_t expiry = now + AVATAR_RENDER_UPDATE_TIME_BUDGET; + while (!sortedAvatars.empty()) { + const AvatarPriority& sortData = sortedAvatars.top(); + const auto& avatar = std::static_pointer_cast(sortData.avatar); + avatar->ensureInScene(avatar); + const bool inView = sortData.priority > 0.5f * OUT_OF_VIEW_PENALTY; + avatar->simulate(deltaTime, inView); + if (expiry > usecTimestampNow()) { + avatar->updateRenderItem(pendingChanges); + avatar->setLastRenderUpdateTime(now); + } + sortedAvatars.pop(); } qApp->getMain3DScene()->enqueuePendingChanges(pendingChanges); - // simulate avatar fades simulateAvatarFades(deltaTime); - PROFILE_COUNTER(simulation_avatar, "NumAvatarsPerSec", - { { "NumAvatarsPerSec", (float)(size() * USECS_PER_SECOND) / (float)(usecTimestampNow() - start) } }); + //PROFILE_COUNTER(simulation_avatar, "NumAvatarsPerSec", + // { { "NumAvatarsPerSec", (float)((size() - sortedAvatars.size()) * USECS_PER_SECOND) / (float)(usecTimestampNow() - now) } }); PROFILE_COUNTER(simulation_avatar, "NumJointsPerSec", { { "NumJointsPerSec", Avatar::getNumJointsProcessedPerSecond() } }); } From e65d9309b3592e2b97b3861bf1cf6511985b2c73 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 23 Jan 2017 14:56:10 -0800 Subject: [PATCH 14/24] remove cruft: Avatar::setShouldDie() --- interface/src/avatar/Avatar.cpp | 6 +++--- interface/src/avatar/Avatar.h | 2 +- libraries/avatars/src/AvatarData.h | 4 ---- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 260373bf50..c5c5dacfc6 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -303,9 +303,9 @@ void Avatar::updateAvatarEntities() { } } -void Avatar::setShouldDie() { - // This will cause the avatar to be shrunk away and removed (the actual Avatar gets removed), but then it comes back. - _owningAvatarMixer.clear(); +bool Avatar::shouldDie() const { + const qint64 AVATAR_SILENCE_THRESHOLD_USECS = 5 * USECS_PER_SECOND; + return _owningAvatarMixer.isNull() || getUsecsSinceLastUpdate() > AVATAR_SILENCE_THRESHOLD_USECS; } void Avatar::simulate(float deltaTime, bool inView) { diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 3276eaff47..d6f588c47e 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -180,7 +180,7 @@ public: uint64_t getLastRenderUpdateTime() const { return _lastRenderUpdateTime; } void setLastRenderUpdateTime(uint64_t time) { _lastRenderUpdateTime = time; } - Q_INVOKABLE void setShouldDie(); + bool shouldDie() const; public slots: diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index a3c9e537ca..093530235b 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -81,8 +81,6 @@ const quint32 AVATAR_MOTION_DEFAULTS = const quint32 AVATAR_MOTION_SCRIPTABLE_BITS = AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED; -const qint64 AVATAR_SILENCE_THRESHOLD_USECS = 5 * USECS_PER_SECOND; - // Bitset of state flags - we store the key state, hand state, Faceshift, eye tracking, and existence of // referential data in this bit set. The hand state is an octal, but is split into two sections to maintain // backward compatibility. The bits are ordered as such (0-7 left to right). @@ -371,8 +369,6 @@ public: const glm::vec3& getTargetVelocity() const { return _targetVelocity; } - bool shouldDie() const { return _owningAvatarMixer.isNull() || getUsecsSinceLastUpdate() > AVATAR_SILENCE_THRESHOLD_USECS; } - void clearRecordingBasis(); TransformPointer getRecordingBasis() const; void setRecordingBasis(TransformPointer recordingBasis = TransformPointer()); From b8afc87ad976513f6bfa6025887081de523237d4 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 23 Jan 2017 16:12:36 -0800 Subject: [PATCH 15/24] remove cruft --- interface/src/ui/PreferencesDialog.cpp | 2 +- libraries/avatars/src/AvatarData.cpp | 5 ----- libraries/avatars/src/AvatarData.h | 3 +-- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index a4cb62cc13..828e2e772d 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -157,7 +157,7 @@ void setupPreferences() { } { auto getter = [=]()->float { return myAvatar->getUniformScale(); }; - auto setter = [=](float value) { myAvatar->setTargetScaleVerbose(value); }; // The hell? + auto setter = [=](float value) { myAvatar->setTargetScale(value); }; auto preference = new SpinnerPreference(AVATAR_TUNING, "Avatar scale (default is 1.0)", getter, setter); preference->setMin(0.01f); preference->setMax(99.9f); diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 1aacb00c04..701fae1b2b 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -179,11 +179,6 @@ void AvatarData::setTargetScale(float targetScale) { _targetScale = glm::clamp(targetScale, MIN_AVATAR_SCALE, MAX_AVATAR_SCALE); } -void AvatarData::setTargetScaleVerbose(float targetScale) { - setTargetScale(targetScale); - qCDebug(avatars) << "Changed scale to " << _targetScale; -} - glm::vec3 AvatarData::getHandPosition() const { return getOrientation() * _handPosition + getPosition(); } diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 093530235b..f07d9a2ba6 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -262,8 +262,7 @@ public: // Scale float getTargetScale() const; - void setTargetScale(float targetScale); - void setTargetScaleVerbose(float targetScale); + virtual void setTargetScale(float targetScale); float getDomainLimitedScale() const { return glm::clamp(_targetScale, _domainMinimumScale, _domainMaximumScale); } void setDomainMinimumScale(float domainMinimumScale) From 69a7b1ef76c4892f7ee28b4080c132f392d074b1 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 23 Jan 2017 16:12:47 -0800 Subject: [PATCH 16/24] move some stuff out of Avatar::simulate() call it explicity in AvatarManager::updateOtherAvatars() --- interface/src/avatar/Avatar.cpp | 28 +++++++++++++++----------- interface/src/avatar/Avatar.h | 5 +++-- interface/src/avatar/AvatarManager.cpp | 22 ++++++++++++++++++++ interface/src/avatar/AvatarManager.h | 2 +- 4 files changed, 42 insertions(+), 15 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index c5c5dacfc6..208d265dcd 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -188,25 +188,35 @@ AABox Avatar::getBounds() const { } void Avatar::animateScaleChanges(float deltaTime) { - float currentScale = getUniformScale(); - auto desiredScale = getDomainLimitedScale(); - if (currentScale != desiredScale) { + if (_isAnimatingScale) { + float currentScale = getUniformScale(); + float desiredScale = getDomainLimitedScale(); + // use exponential decay toward the domain limit clamped scale const float SCALE_ANIMATION_TIMESCALE = 0.5f; float blendFactor = glm::clamp(deltaTime / SCALE_ANIMATION_TIMESCALE, 0.0f, 1.0f); float animatedScale = (1.0f - blendFactor) * currentScale + blendFactor * desiredScale; // snap to the end when we get close enough - const float MIN_RELATIVE_SCALE_ERROR = 0.03f; - if (fabsf(desiredScale - currentScale) / desiredScale < MIN_RELATIVE_SCALE_ERROR) { + const float MIN_RELATIVE_ERROR = 0.03f; + float relativeError = fabsf(desiredScale - currentScale) / desiredScale; + if (relativeError < MIN_RELATIVE_ERROR) { animatedScale = desiredScale; + _isAnimatingScale = false; } - setScale(glm::vec3(animatedScale)); // avatar scale is uniform + + // TODO: rebuilding the shape constantly is somehwat expensive. + // We should only rebuild after significant change. rebuildCollisionShape(); } } +void Avatar::setTargetScale(float targetScale) { + AvatarData::setTargetScale(targetScale); + _isAnimatingScale = true; +} + void Avatar::updateAvatarEntities() { PerformanceTimer perfTimer("attachments"); // - if queueEditEntityMessage sees clientOnly flag it does _myAvatar->updateAvatarEntity() @@ -311,12 +321,6 @@ bool Avatar::shouldDie() const { void Avatar::simulate(float deltaTime, bool inView) { PROFILE_RANGE(simulation, "simulate"); PerformanceTimer perfTimer("simulate"); - - if (!isDead() && !_motionState) { - DependencyManager::get()->addAvatarToSimulation(this); - } - animateScaleChanges(deltaTime); - { PROFILE_RANGE(simulation, "updateJoints"); uint64_t start = usecTimestampNow(); diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index d6f588c47e..a6c5bbf16f 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -181,6 +181,8 @@ public: void setLastRenderUpdateTime(uint64_t time) { _lastRenderUpdateTime = time; } bool shouldDie() const; + void animateScaleChanges(float deltaTime); + void setTargetScale(float targetScale) override; public slots: @@ -231,8 +233,6 @@ protected: // protected methods... bool isLookingAtMe(AvatarSharedPointer avatar) const; - virtual void animateScaleChanges(float deltaTime); - glm::vec3 getBodyRightDirection() const { return getOrientation() * IDENTITY_RIGHT; } glm::vec3 getBodyUpDirection() const { return getOrientation() * IDENTITY_UP; } glm::vec3 getBodyFrontDirection() const { return getOrientation() * IDENTITY_FRONT; } @@ -269,6 +269,7 @@ private: bool _initialized; bool _isLookAtTarget { false }; bool _inScene { false }; + bool _isAnimatingScale { false }; float getBoundingRadius() const; diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index e3d3164b68..fa2ee2190c 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -175,6 +175,9 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { removeAvatar(avatar->getID()); continue; } + if (avatar->isDead()) { + continue; + } // priority = weighted linear combination of: // (a) apparentSize @@ -205,7 +208,24 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { while (!sortedAvatars.empty()) { const AvatarPriority& sortData = sortedAvatars.top(); const auto& avatar = std::static_pointer_cast(sortData.avatar); + + // for ALL avatars... avatar->ensureInScene(avatar); + if (!avatar->getMotionState()) { + ShapeInfo shapeInfo; + avatar->computeShapeInfo(shapeInfo); + btCollisionShape* shape = const_cast(ObjectMotionState::getShapeManager()->getShape(shapeInfo)); + if (shape) { + // don't add to the simulation now, instead put it on a list to be added later + AvatarMotionState* motionState = new AvatarMotionState(avatar.get(), shape); + avatar->setMotionState(motionState); + _motionStatesToAddToPhysics.insert(motionState); + _motionStatesThatMightUpdate.insert(motionState); + } + } + avatar->animateScaleChanges(deltaTime); + + // for avatars in view... const bool inView = sortData.priority > 0.5f * OUT_OF_VIEW_PENALTY; avatar->simulate(deltaTime, inView); if (expiry > usecTimestampNow()) { @@ -429,6 +449,7 @@ void AvatarManager::handleCollisionEvents(const CollisionEvents& collisionEvents } } +/* void AvatarManager::addAvatarToSimulation(Avatar* avatar) { assert(!avatar->getMotionState()); @@ -443,6 +464,7 @@ void AvatarManager::addAvatarToSimulation(Avatar* avatar) { _motionStatesThatMightUpdate.insert(motionState); } } +*/ void AvatarManager::updateAvatarRenderStatus(bool shouldRenderAvatars) { if (DependencyManager::get()->shouldRenderAvatars()) { diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index a423e34f8f..efb01e071f 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -69,7 +69,7 @@ public: void handleOutgoingChanges(const VectorOfMotionStates& motionStates); void handleCollisionEvents(const CollisionEvents& collisionEvents); - void addAvatarToSimulation(Avatar* avatar); + //void addAvatarToSimulation(Avatar* avatar); Q_INVOKABLE RayToAvatarIntersectionResult findRayIntersection(const PickRay& ray, const QScriptValue& avatarIdsToInclude = QScriptValue(), From 887707426eb7e383604ff1964a37bc37b8811da3 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 23 Jan 2017 17:03:26 -0800 Subject: [PATCH 17/24] remove cruft: Head::getScalePivot() --- interface/src/avatar/Head.cpp | 4 ---- interface/src/avatar/Head.h | 2 -- 2 files changed, 6 deletions(-) diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index 928f46facb..66beafcdd8 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -378,10 +378,6 @@ glm::quat Head::getEyeRotation(const glm::vec3& eyePosition) const { return rotationBetween(orientation * IDENTITY_FRONT, lookAtDelta + glm::length(lookAtDelta) * _saccade) * orientation; } -glm::vec3 Head::getScalePivot() const { - return _position; -} - void Head::setFinalPitch(float finalPitch) { _deltaPitch = glm::clamp(finalPitch, MIN_HEAD_PITCH, MAX_HEAD_PITCH) - _basePitch; } diff --git a/interface/src/avatar/Head.h b/interface/src/avatar/Head.h index 29cd06865c..b1ea36df3d 100644 --- a/interface/src/avatar/Head.h +++ b/interface/src/avatar/Head.h @@ -70,8 +70,6 @@ public: bool getReturnToCenter() const { return _returnHeadToCenter; } // Do you want head to try to return to center (depends on interface detected) float getAverageLoudness() const { return _averageLoudness; } - /// \return the point about which scaling occurs. - glm::vec3 getScalePivot() const; void setDeltaPitch(float pitch) { _deltaPitch = pitch; } float getDeltaPitch() const { return _deltaPitch; } From d3dcc2b41559e5c122fd7abb18f2857e94525fa6 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 23 Jan 2017 17:28:54 -0800 Subject: [PATCH 18/24] remove cruft: billboard option for Head::simulate() --- interface/src/avatar/Head.cpp | 6 +++--- interface/src/avatar/Head.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index 66beafcdd8..d7bf2b79bf 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -70,7 +70,7 @@ void Head::reset() { _baseYaw = _basePitch = _baseRoll = 0.0f; } -void Head::simulate(float deltaTime, bool isMine, bool billboard) { +void Head::simulate(float deltaTime, bool isMine) { // Update audio trailing average for rendering facial animations const float AUDIO_AVERAGING_SECS = 0.05f; const float AUDIO_LONG_TERM_AVERAGING_SECS = 30.0f; @@ -117,7 +117,7 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) { } } - if (!(_isFaceTrackerConnected || billboard)) { + if (!_isFaceTrackerConnected) { if (!_isEyeTrackerConnected) { // Update eye saccades @@ -220,7 +220,7 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) { _leftEyePosition = _rightEyePosition = getPosition(); _eyePosition = getPosition(); - if (!billboard && _owningAvatar) { + if (_owningAvatar) { auto skeletonModel = static_cast(_owningAvatar)->getSkeletonModel(); if (skeletonModel) { skeletonModel->getEyePositions(_leftEyePosition, _rightEyePosition); diff --git a/interface/src/avatar/Head.h b/interface/src/avatar/Head.h index b1ea36df3d..3d25c79087 100644 --- a/interface/src/avatar/Head.h +++ b/interface/src/avatar/Head.h @@ -31,7 +31,7 @@ public: void init(); void reset(); - void simulate(float deltaTime, bool isMine, bool billboard = false); + void simulate(float deltaTime, bool isMine); void setScale(float scale); void setPosition(glm::vec3 position) { _position = position; } void setAverageLoudness(float averageLoudness) { _averageLoudness = averageLoudness; } From ac180758ad87dab53efd4747c237f99f0fe58fba Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 24 Jan 2017 10:36:42 -0800 Subject: [PATCH 19/24] sort, optimize, and timebox process avatar updates --- interface/src/avatar/Avatar.cpp | 15 ++-- interface/src/avatar/AvatarManager.cpp | 112 ++++++++++++++----------- interface/src/avatar/SkeletonModel.cpp | 18 ++-- 3 files changed, 83 insertions(+), 62 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 208d265dcd..cdf9323ace 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -323,10 +323,13 @@ void Avatar::simulate(float deltaTime, bool inView) { PerformanceTimer perfTimer("simulate"); { PROFILE_RANGE(simulation, "updateJoints"); - uint64_t start = usecTimestampNow(); - if (inView) { + if (inView && _hasNewJointData) { + uint64_t start = usecTimestampNow(); _skeletonModel->getRig()->copyJointsFromJointData(_jointData); - _skeletonModel->simulate(deltaTime, _hasNewJointData); + _skeletonModel->simulate(deltaTime, true); + timeProcessingJoints += usecTimestampNow() - start; + numJointsProcessed += _jointData.size(); + locationChanged(); // joints changed, so if there are any children, update them. _hasNewJointData = false; @@ -337,15 +340,11 @@ void Avatar::simulate(float deltaTime, bool inView) { Head* head = getHead(); head->setPosition(headPosition); head->setScale(getUniformScale()); - const bool useBillboard = false; // HACK - head->simulate(deltaTime, false, useBillboard); + head->simulate(deltaTime, false); } else { // a non-full update is still required so that the position, rotation, scale and bounds of the skeletonModel are updated. - getHead()->setPosition(getPosition()); _skeletonModel->simulate(deltaTime, false); } - timeProcessingJoints += usecTimestampNow() - start; - numJointsProcessed += _jointData.size(); } // update animation for display name fade in/out diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index fa2ee2190c..73f3fb0f38 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -149,14 +149,11 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { } lock.unlock(); - bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); - PerformanceWarning warn(showWarnings, "Application::updateAvatars()"); - PerformanceTimer perfTimer("otherAvatars"); + uint64_t startTime = usecTimestampNow(); auto avatarMap = getHashCopy(); QList avatarList = avatarMap.values(); - uint64_t now = usecTimestampNow(); ViewFrustum cameraView; qApp->copyDisplayViewFrustum(cameraView); glm::vec3 frustumCenter = cameraView.getPosition(); @@ -164,47 +161,56 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { const float OUT_OF_VIEW_PENALTY = -10.0; std::priority_queue sortedAvatars; - for (int32_t i = 0; i < avatarList.size(); ++i) { - const auto& avatar = std::static_pointer_cast(avatarList.at(i)); - if (avatar == _myAvatar || !avatar->isInitialized()) { - // DO NOT update _myAvatar! Its update has already been done earlier in the main loop. - // DO NOT update or fade out uninitialized Avatars - continue; - } - if (avatar->shouldDie()) { - removeAvatar(avatar->getID()); - continue; - } - if (avatar->isDead()) { - continue; - } - - // priority = weighted linear combination of: - // (a) apparentSize - // (b) proximity to center of view, and - // (c) time since last update - glm::vec3 avatarPosition = avatar->getPosition(); - glm::vec3 offset = avatarPosition - frustumCenter; - float distance = glm::length(offset) + 0.001f; // add 1mm to avoid divide by zero - float radius = avatar->getBoundingRadius(); - const glm::vec3& forward = cameraView.getDirection(); - float apparentSize = radius / distance; - float cosineAngle = glm::length(offset - glm::dot(offset, forward) * forward) / distance; - float age = (float)(now - avatar->getLastRenderUpdateTime()) / (float)(USECS_PER_SECOND); - float priority = 2.0f * apparentSize + 0.25f * cosineAngle + age; - - // decrement priority of avatars outside keyhole - if (distance > cameraView.getCenterRadius()) { - if (!cameraView.sphereIntersectsFrustum(avatarPosition, radius)) { - priority += OUT_OF_VIEW_PENALTY; + { + PROFILE_RANGE(simulation, "sort"); + for (int32_t i = 0; i < avatarList.size(); ++i) { + const auto& avatar = std::static_pointer_cast(avatarList.at(i)); + if (avatar == _myAvatar || !avatar->isInitialized()) { + // DO NOT update _myAvatar! Its update has already been done earlier in the main loop. + // DO NOT update or fade out uninitialized Avatars + continue; } + if (avatar->shouldDie()) { + removeAvatar(avatar->getID()); + continue; + } + if (avatar->isDead()) { + continue; + } + + // priority = weighted linear combination of: + // (a) apparentSize + // (b) proximity to center of view + // (c) time since last update + // (d) TIME_PENALTY to help recently updated entries sort toward back + glm::vec3 avatarPosition = avatar->getPosition(); + glm::vec3 offset = avatarPosition - frustumCenter; + float distance = glm::length(offset) + 0.001f; // add 1mm to avoid divide by zero + float radius = avatar->getBoundingRadius(); + const glm::vec3& forward = cameraView.getDirection(); + float apparentSize = radius / distance; + float cosineAngle = glm::length(offset - glm::dot(offset, forward) * forward) / distance; + const float TIME_PENALTY = 0.080f; // seconds + float age = (float)(startTime - avatar->getLastRenderUpdateTime()) / (float)(USECS_PER_SECOND) - TIME_PENALTY; + float priority = apparentSize + 0.25f * cosineAngle + age; + + // decrement priority of avatars outside keyhole + if (distance > cameraView.getCenterRadius()) { + if (!cameraView.sphereIntersectsFrustum(avatarPosition, radius)) { + priority += OUT_OF_VIEW_PENALTY; + } + } + sortedAvatars.push(AvatarPriority(avatar, priority)); } - sortedAvatars.push(AvatarPriority(avatar, priority)); } render::PendingChanges pendingChanges; - const uint64_t AVATAR_RENDER_UPDATE_TIME_BUDGET = 2 * USECS_PER_MSEC; - uint64_t expiry = now + AVATAR_RENDER_UPDATE_TIME_BUDGET; + // NOTE: the copy of hash and sort above takes about 300 usec + const uint64_t RENDER_UPDATE_BUDGET = 1500; // usec + const uint64_t MAX_UPDATE_BUDGET = 2000; // usec + uint64_t renderExpiry = startTime + RENDER_UPDATE_BUDGET; + uint64_t maxExpiry = startTime + MAX_UPDATE_BUDGET; + size_t numAvatarsProcessed = sortedAvatars.size(); while (!sortedAvatars.empty()) { const AvatarPriority& sortData = sortedAvatars.top(); const auto& avatar = std::static_pointer_cast(sortData.avatar); @@ -225,12 +231,23 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { } avatar->animateScaleChanges(deltaTime); - // for avatars in view... - const bool inView = sortData.priority > 0.5f * OUT_OF_VIEW_PENALTY; - avatar->simulate(deltaTime, inView); - if (expiry > usecTimestampNow()) { + uint64_t now = usecTimestampNow(); + if (now < renderExpiry) { + // we're within budget + bool inView = sortData.priority > 0.5f * OUT_OF_VIEW_PENALTY; + avatar->simulate(deltaTime, inView); avatar->updateRenderItem(pendingChanges); - avatar->setLastRenderUpdateTime(now); + avatar->setLastRenderUpdateTime(startTime); + } else if (now < maxExpiry) { + // we've spent most of our time budget, but we still simulate() the avatar as it if were out of view + // --> some avatars may freeze until their priority trickles up + const bool inView = false; + avatar->simulate(deltaTime, inView); + } else { + // we've spent ALL of our time budget --> bail on the rest of the avatar updates + // --> some scale or fade animations may glitch + // --> some avatar velocity measurements may be a little off + break; } sortedAvatars.pop(); } @@ -238,8 +255,9 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { simulateAvatarFades(deltaTime); - //PROFILE_COUNTER(simulation_avatar, "NumAvatarsPerSec", - // { { "NumAvatarsPerSec", (float)((size() - sortedAvatars.size()) * USECS_PER_SECOND) / (float)(usecTimestampNow() - now) } }); + numAvatarsProcessed -= sortedAvatars.size(); + float numAvatarsPerSec = (float)(numAvatarsProcessed * USECS_PER_SECOND) / (float)(usecTimestampNow() - startTime); + PROFILE_COUNTER(simulation_avatar, "NumAvatarsPerSec", { { "NumAvatarsPerSec", numAvatarsPerSec } }); PROFILE_COUNTER(simulation_avatar, "NumJointsPerSec", { { "NumJointsPerSec", Avatar::getNumJointsProcessedPerSecond() } }); } diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 54f6682191..4b77323bba 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -220,15 +220,19 @@ void SkeletonModel::updateAttitude() { // Called by Avatar::simulate after it has set the joint states (fullUpdate true if changed), // but just before head has been simulated. void SkeletonModel::simulate(float deltaTime, bool fullUpdate) { - updateAttitude(); - setBlendshapeCoefficients(_owningAvatar->getHead()->getBlendshapeCoefficients()); + if (fullUpdate) { + updateAttitude(); + setBlendshapeCoefficients(_owningAvatar->getHead()->getBlendshapeCoefficients()); - Model::simulate(deltaTime, fullUpdate); + Model::simulate(deltaTime, fullUpdate); - // let rig compute the model offset - glm::vec3 registrationPoint; - if (_rig->getModelRegistrationPoint(registrationPoint)) { - setOffset(registrationPoint); + // let rig compute the model offset + glm::vec3 registrationPoint; + if (_rig->getModelRegistrationPoint(registrationPoint)) { + setOffset(registrationPoint); + } + } else { + Model::simulate(deltaTime, fullUpdate); } if (!isActive() || !_owningAvatar->isMyAvatar()) { From 01e14eec471cb65eb6aa8bb97851b69e52c490d5 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 24 Jan 2017 12:09:03 -0800 Subject: [PATCH 20/24] remove commented out cruft --- interface/src/avatar/AvatarManager.cpp | 17 ----------------- interface/src/avatar/AvatarManager.h | 2 -- 2 files changed, 19 deletions(-) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 73f3fb0f38..fe0b49728b 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -467,23 +467,6 @@ void AvatarManager::handleCollisionEvents(const CollisionEvents& collisionEvents } } -/* -void AvatarManager::addAvatarToSimulation(Avatar* avatar) { - assert(!avatar->getMotionState()); - - ShapeInfo shapeInfo; - avatar->computeShapeInfo(shapeInfo); - btCollisionShape* shape = const_cast(ObjectMotionState::getShapeManager()->getShape(shapeInfo)); - if (shape) { - // we don't add to the simulation now, we put it on a list to be added later - AvatarMotionState* motionState = new AvatarMotionState(avatar, shape); - avatar->setMotionState(motionState); - _motionStatesToAddToPhysics.insert(motionState); - _motionStatesThatMightUpdate.insert(motionState); - } -} -*/ - void AvatarManager::updateAvatarRenderStatus(bool shouldRenderAvatars) { if (DependencyManager::get()->shouldRenderAvatars()) { for (auto avatarData : _avatarHash) { diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index efb01e071f..817a3e580f 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -69,8 +69,6 @@ public: void handleOutgoingChanges(const VectorOfMotionStates& motionStates); void handleCollisionEvents(const CollisionEvents& collisionEvents); - //void addAvatarToSimulation(Avatar* avatar); - Q_INVOKABLE RayToAvatarIntersectionResult findRayIntersection(const PickRay& ray, const QScriptValue& avatarIdsToInclude = QScriptValue(), const QScriptValue& avatarIdsToDiscard = QScriptValue()); From 0f09e60acdcc8dc872609cad7ca88fc7366fe0e1 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 24 Jan 2017 12:13:01 -0800 Subject: [PATCH 21/24] remove unhelpful comment --- interface/src/avatar/AvatarManager.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index fe0b49728b..ff7180f95e 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -205,7 +205,6 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { } render::PendingChanges pendingChanges; - // NOTE: the copy of hash and sort above takes about 300 usec const uint64_t RENDER_UPDATE_BUDGET = 1500; // usec const uint64_t MAX_UPDATE_BUDGET = 2000; // usec uint64_t renderExpiry = startTime + RENDER_UPDATE_BUDGET; From 2264c2960443fd6591007ec06277e69b6709cd89 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 24 Jan 2017 14:22:39 -0800 Subject: [PATCH 22/24] less magic --- interface/src/avatar/AvatarManager.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index ff7180f95e..4eac5bc2a4 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -192,6 +192,10 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { float cosineAngle = glm::length(offset - glm::dot(offset, forward) * forward) / distance; const float TIME_PENALTY = 0.080f; // seconds float age = (float)(startTime - avatar->getLastRenderUpdateTime()) / (float)(USECS_PER_SECOND) - TIME_PENALTY; + // NOTE: we are adding values of different units to get a single measure of "priority". + // Thus we multiply each component by a conversion "weight" that scales its units + // relative to the others. These weights are pure magic tuning and are hard coded in the + // relation below: (hint: unitary weights are not explicityly shown) float priority = apparentSize + 0.25f * cosineAngle + age; // decrement priority of avatars outside keyhole @@ -233,7 +237,8 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { uint64_t now = usecTimestampNow(); if (now < renderExpiry) { // we're within budget - bool inView = sortData.priority > 0.5f * OUT_OF_VIEW_PENALTY; + const float OUT_OF_VIEW_THRESHOLD = 0.5f * OUT_OF_VIEW_PENALTY; + bool inView = sortData.priority > OUT_OF_VIEW_THRESHOLD; avatar->simulate(deltaTime, inView); avatar->updateRenderItem(pendingChanges); avatar->setLastRenderUpdateTime(startTime); From 82f52b9658e3dd41f1014b2f24ab23f13c53ffd8 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 25 Jan 2017 10:52:12 -0800 Subject: [PATCH 23/24] fix bug: Avatar instance not getting deleted --- interface/src/avatar/AvatarManager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 4eac5bc2a4..658ee8ed97 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -285,6 +285,7 @@ void AvatarManager::simulateAvatarFades(float deltaTime) { while (fadingIterator != _avatarFades.end()) { auto avatar = std::static_pointer_cast(*fadingIterator); avatar->setTargetScale(avatar->getUniformScale() * SHRINK_RATE); + avatar->animateScaleChanges(deltaTime); if (avatar->getTargetScale() <= MIN_FADE_SCALE) { avatar->removeFromScene(*fadingIterator, scene, pendingChanges); // only remove from _avatarFades if we're sure its motionState has been removed from PhysicsEngine From 5783db910bc20098469d23fd59e856540fe8690e Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 25 Jan 2017 10:57:48 -0800 Subject: [PATCH 24/24] remove some unhelpful trace profiling data --- interface/src/avatar/Avatar.cpp | 16 ---------------- interface/src/avatar/Avatar.h | 2 -- interface/src/avatar/AvatarManager.cpp | 6 ------ 3 files changed, 24 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index cdf9323ace..7ab1e7e8bd 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -85,19 +85,6 @@ namespace render { } } -static uint64_t timeProcessingJoints = 0; -static int32_t numJointsProcessed = 0; - -float Avatar::getNumJointsProcessedPerSecond() { - float rate = 0.0f; - if (timeProcessingJoints > 0) { - rate = (float)(numJointsProcessed * USECS_PER_SECOND) / (float)timeProcessingJoints; - } - timeProcessingJoints = 0; - numJointsProcessed = 0; - return rate; -} - Avatar::Avatar(RigPointer rig) : AvatarData(), _skeletonOffset(0.0f), @@ -324,11 +311,8 @@ void Avatar::simulate(float deltaTime, bool inView) { { PROFILE_RANGE(simulation, "updateJoints"); if (inView && _hasNewJointData) { - uint64_t start = usecTimestampNow(); _skeletonModel->getRig()->copyJointsFromJointData(_jointData); _skeletonModel->simulate(deltaTime, true); - timeProcessingJoints += usecTimestampNow() - start; - numJointsProcessed += _jointData.size(); locationChanged(); // joints changed, so if there are any children, update them. _hasNewJointData = false; diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index a6c5bbf16f..8f2b0817c1 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -58,8 +58,6 @@ class Avatar : public AvatarData { Q_PROPERTY(glm::vec3 skeletonOffset READ getSkeletonOffset WRITE setSkeletonOffset) public: - static float getNumJointsProcessedPerSecond(); - explicit Avatar(RigPointer rig = nullptr); ~Avatar(); diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 658ee8ed97..2d0860b355 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -213,7 +213,6 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { const uint64_t MAX_UPDATE_BUDGET = 2000; // usec uint64_t renderExpiry = startTime + RENDER_UPDATE_BUDGET; uint64_t maxExpiry = startTime + MAX_UPDATE_BUDGET; - size_t numAvatarsProcessed = sortedAvatars.size(); while (!sortedAvatars.empty()) { const AvatarPriority& sortData = sortedAvatars.top(); const auto& avatar = std::static_pointer_cast(sortData.avatar); @@ -258,11 +257,6 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { qApp->getMain3DScene()->enqueuePendingChanges(pendingChanges); simulateAvatarFades(deltaTime); - - numAvatarsProcessed -= sortedAvatars.size(); - float numAvatarsPerSec = (float)(numAvatarsProcessed * USECS_PER_SECOND) / (float)(usecTimestampNow() - startTime); - PROFILE_COUNTER(simulation_avatar, "NumAvatarsPerSec", { { "NumAvatarsPerSec", numAvatarsPerSec } }); - PROFILE_COUNTER(simulation_avatar, "NumJointsPerSec", { { "NumJointsPerSec", Avatar::getNumJointsProcessedPerSecond() } }); } void AvatarManager::postUpdate(float deltaTime) {