From 91a06ea3c4f516853764640fff622b1cf57d6053 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 5 May 2015 10:50:19 -0700 Subject: [PATCH 01/16] Add "Calibrate Camera" menu item for DDE face tracking --- interface/src/Application.cpp | 1 + interface/src/Menu.cpp | 3 +++ interface/src/Menu.h | 1 + interface/src/devices/DdeFaceTracker.cpp | 3 +++ interface/src/devices/DdeFaceTracker.h | 1 + 5 files changed, 9 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e20ee73877..5e557dd772 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1853,6 +1853,7 @@ void Application::setActiveFaceTracker() { bool isUsingDDE = Menu::getInstance()->isOptionChecked(MenuOption::UseCamera); Menu::getInstance()->getActionForOption(MenuOption::UseAudioForMouth)->setVisible(isUsingDDE); Menu::getInstance()->getActionForOption(MenuOption::VelocityFilter)->setVisible(isUsingDDE); + Menu::getInstance()->getActionForOption(MenuOption::CalibrateCamera)->setVisible(isUsingDDE); DependencyManager::get()->setEnabled(isUsingDDE); #endif } diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 8070bd5555..55fec541f8 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -393,6 +393,9 @@ Menu::Menu() { useAudioForMouth->setVisible(false); QAction* ddeFiltering = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::VelocityFilter, 0, true); ddeFiltering->setVisible(false); + QAction* ddeCalibrate = addActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::CalibrateCamera, 0, + DependencyManager::get().data(), SLOT(calibrate())); + ddeCalibrate->setVisible(false); #endif auto avatarManager = DependencyManager::get(); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 7d105687ab..f57e050831 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -154,6 +154,7 @@ namespace MenuOption { const QString Bookmarks = "Bookmarks"; const QString CascadedShadows = "Cascaded"; const QString CachesSize = "RAM Caches Size"; + const QString CalibrateCamera = "Calibrate Camera"; const QString Chat = "Chat..."; const QString Collisions = "Collisions"; const QString Console = "Console..."; diff --git a/interface/src/devices/DdeFaceTracker.cpp b/interface/src/devices/DdeFaceTracker.cpp index 98f1636a32..37686d575b 100644 --- a/interface/src/devices/DdeFaceTracker.cpp +++ b/interface/src/devices/DdeFaceTracker.cpp @@ -503,3 +503,6 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) { } _lastReceiveTimestamp = usecTimestampNow(); } + +void DdeFaceTracker::calibrate() { +} diff --git a/interface/src/devices/DdeFaceTracker.h b/interface/src/devices/DdeFaceTracker.h index 9fb0e943f2..7b006b6c7c 100644 --- a/interface/src/devices/DdeFaceTracker.h +++ b/interface/src/devices/DdeFaceTracker.h @@ -50,6 +50,7 @@ public: public slots: void setEnabled(bool enabled); + void calibrate(); private slots: void processFinished(int exitCode, QProcess::ExitStatus exitStatus); From ceeb1dd81fa0ee47303b63acddbda56a92f701fe Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 5 May 2015 11:03:36 -0700 Subject: [PATCH 02/16] Remove unused DDE member variables --- interface/src/devices/DdeFaceTracker.cpp | 4 +--- interface/src/devices/DdeFaceTracker.h | 3 --- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/interface/src/devices/DdeFaceTracker.cpp b/interface/src/devices/DdeFaceTracker.cpp index 37686d575b..73ab436e70 100644 --- a/interface/src/devices/DdeFaceTracker.cpp +++ b/interface/src/devices/DdeFaceTracker.cpp @@ -178,9 +178,7 @@ DdeFaceTracker::DdeFaceTracker(const QHostAddress& host, quint16 serverPort, qui _filteredBrowUp(0.0f), _lastEyeBlinks(), _filteredEyeBlinks(), - _lastEyeCoefficients(), - _isCalculatingFPS(false), - _frameCount(0) + _lastEyeCoefficients() { _coefficients.resize(NUM_FACESHIFT_BLENDSHAPES); diff --git a/interface/src/devices/DdeFaceTracker.h b/interface/src/devices/DdeFaceTracker.h index 7b006b6c7c..8dcebabb95 100644 --- a/interface/src/devices/DdeFaceTracker.h +++ b/interface/src/devices/DdeFaceTracker.h @@ -121,9 +121,6 @@ private: float _lastEyeBlinks[2]; float _filteredEyeBlinks[2]; float _lastEyeCoefficients[2]; - - bool _isCalculatingFPS; - int _frameCount; }; #endif // hifi_DdeFaceTracker_h From e1b5e7caf65d5c5a396c8684fc302dbaa6abf5c1 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 6 May 2015 11:13:19 -0700 Subject: [PATCH 03/16] Add DDE calibration count-down --- interface/src/devices/DdeFaceTracker.cpp | 89 +++++++++++++++++++++++- interface/src/devices/DdeFaceTracker.h | 10 +++ 2 files changed, 97 insertions(+), 2 deletions(-) diff --git a/interface/src/devices/DdeFaceTracker.cpp b/interface/src/devices/DdeFaceTracker.cpp index 73ab436e70..5736717419 100644 --- a/interface/src/devices/DdeFaceTracker.cpp +++ b/interface/src/devices/DdeFaceTracker.cpp @@ -20,6 +20,7 @@ #include #include +#include "Application.h" #include "DdeFaceTracker.h" #include "FaceshiftConstants.h" #include "InterfaceLogging.h" @@ -135,7 +136,9 @@ struct Packet { char name[MAX_NAME_SIZE + 1]; }; -const float STARTING_DDE_MESSAGE_TIME = 0.033f; +static const float STARTING_DDE_MESSAGE_TIME = 0.033f; + +static const quint64 CALIBRATION_SAMPLES = 150; #ifdef WIN32 // warning C4351: new behavior: elements of array 'DdeFaceTracker::_lastEyeBlinks' will be default initialized @@ -178,7 +181,12 @@ DdeFaceTracker::DdeFaceTracker(const QHostAddress& host, quint16 serverPort, qui _filteredBrowUp(0.0f), _lastEyeBlinks(), _filteredEyeBlinks(), - _lastEyeCoefficients() + _lastEyeCoefficients(), + _isCalibrating(false), + _calibrationCount(0), + _calibrationBillboard(NULL), + _calibrationBillboardID(0), + _calibrationMessage(QString()) { _coefficients.resize(NUM_FACESHIFT_BLENDSHAPES); @@ -195,6 +203,10 @@ DdeFaceTracker::DdeFaceTracker(const QHostAddress& host, quint16 serverPort, qui DdeFaceTracker::~DdeFaceTracker() { setEnabled(false); + + if (_isCalibrating) { + cancelCalibration(); + } } #ifdef WIN32 @@ -203,6 +215,12 @@ DdeFaceTracker::~DdeFaceTracker() { void DdeFaceTracker::setEnabled(bool enabled) { #ifdef HAVE_DDE + + if (_isCalibrating) { + cancelCalibration(); + } + + // isOpen() does not work as one might expect on QUdpSocket; don't test isOpen() before closing socket. _udpSocket.close(); if (enabled) { @@ -371,6 +389,11 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) { _coefficients[DDE_TO_FACESHIFT_MAPPING[i]] = packet.expressions[i]; } + // Calibration + if (_isCalibrating) { + addCalibrationDatum(); + } + // Use BrowsU_C to control both brows' up and down float browUp = _coefficients[_browUpCenterIndex]; if (isFiltering) { @@ -500,7 +523,69 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) { qCWarning(interfaceapp) << "DDE Face Tracker: Decode error"; } _lastReceiveTimestamp = usecTimestampNow(); + + if (_isCalibrating && _calibrationCount > CALIBRATION_SAMPLES) { + finishCalibration(); + } } +static const int CALIBRATION_BILLBOARD_WIDTH = 240; +static const int CALIBRATION_BILLBOARD_HEIGHT = 180; +static const int CALIBRATION_BILLBOARD_TOP_MARGIN = 60; +static const int CALIBRATION_BILLBOARD_LEFT_MARGIN = 30; +static const int CALIBRATION_BILLBOARD_FONT_SIZE = 16; +static const float CALIBRATION_BILLBOARD_ALPHA = 0.5f; +static QString CALIBRATION_INSTRUCTION_MESSAGE = "Hold still to calibrate"; + void DdeFaceTracker::calibrate() { + if (!_isCalibrating) { + qCDebug(interfaceapp) << "DDE Face Tracker: Calibration started"; + + _isCalibrating = true; + _calibrationCount = 0; + _calibrationMessage = CALIBRATION_INSTRUCTION_MESSAGE + "\n\n"; + + _calibrationBillboard = new TextOverlay(); + _calibrationBillboard->setTopMargin(CALIBRATION_BILLBOARD_TOP_MARGIN); + _calibrationBillboard->setLeftMargin(CALIBRATION_BILLBOARD_LEFT_MARGIN); + _calibrationBillboard->setFontSize(CALIBRATION_BILLBOARD_FONT_SIZE); + _calibrationBillboard->setText(CALIBRATION_INSTRUCTION_MESSAGE); + _calibrationBillboard->setAlpha(CALIBRATION_BILLBOARD_ALPHA); + glm::vec2 viewport = qApp->getViewportDimensions(); + _calibrationBillboard->setX((viewport.x - CALIBRATION_BILLBOARD_WIDTH) / 2); + _calibrationBillboard->setY((viewport.y - CALIBRATION_BILLBOARD_HEIGHT) / 2); + _calibrationBillboard->setWidth(CALIBRATION_BILLBOARD_WIDTH); + _calibrationBillboard->setHeight(CALIBRATION_BILLBOARD_HEIGHT); + _calibrationBillboardID = qApp->getOverlays().addOverlay(_calibrationBillboard); + + } +} + +void DdeFaceTracker::addCalibrationDatum() { + const int LARGE_TICK_INTERVAL = 30; + const int SMALL_TICK_INTERVAL = 6; + int samplesLeft = CALIBRATION_SAMPLES - _calibrationCount; + if (samplesLeft % LARGE_TICK_INTERVAL == 0) { + _calibrationMessage += QString::number(samplesLeft / LARGE_TICK_INTERVAL); + _calibrationBillboard->setText(_calibrationMessage); + } else if (samplesLeft % SMALL_TICK_INTERVAL == 0) { + _calibrationMessage += "."; + _calibrationBillboard->setText(_calibrationMessage); + } + + _calibrationCount += 1; +} + +void DdeFaceTracker::cancelCalibration() { + qApp->getOverlays().deleteOverlay(_calibrationBillboardID); + _calibrationBillboard = NULL; + _isCalibrating = false; + qCDebug(interfaceapp) << "DDE Face Tracker: Calibration cancelled"; +} + +void DdeFaceTracker::finishCalibration() { + qApp->getOverlays().deleteOverlay(_calibrationBillboardID); + _calibrationBillboard = NULL; + _isCalibrating = false; + qCDebug(interfaceapp) << "DDE Face Tracker: Calibration finished"; } diff --git a/interface/src/devices/DdeFaceTracker.h b/interface/src/devices/DdeFaceTracker.h index 8dcebabb95..0078cbcd61 100644 --- a/interface/src/devices/DdeFaceTracker.h +++ b/interface/src/devices/DdeFaceTracker.h @@ -20,6 +20,7 @@ #include #include +#include #include "FaceTracker.h" @@ -121,6 +122,15 @@ private: float _lastEyeBlinks[2]; float _filteredEyeBlinks[2]; float _lastEyeCoefficients[2]; + + bool _isCalibrating; + int _calibrationCount; + TextOverlay* _calibrationBillboard; + int _calibrationBillboardID; + QString _calibrationMessage; + void addCalibrationDatum(); + void cancelCalibration(); + void finishCalibration(); }; #endif // hifi_DdeFaceTracker_h From a6dd08fea89d4d06ac9b1b9ecd84c18bea64369c Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 6 May 2015 11:38:14 -0700 Subject: [PATCH 04/16] Calculate average coefficient values --- interface/src/devices/DdeFaceTracker.cpp | 17 +++++++++++++++-- interface/src/devices/DdeFaceTracker.h | 1 + 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/interface/src/devices/DdeFaceTracker.cpp b/interface/src/devices/DdeFaceTracker.cpp index 5736717419..3bb6a3530a 100644 --- a/interface/src/devices/DdeFaceTracker.cpp +++ b/interface/src/devices/DdeFaceTracker.cpp @@ -138,7 +138,7 @@ struct Packet { static const float STARTING_DDE_MESSAGE_TIME = 0.033f; -static const quint64 CALIBRATION_SAMPLES = 150; +static const int CALIBRATION_SAMPLES = 150; #ifdef WIN32 // warning C4351: new behavior: elements of array 'DdeFaceTracker::_lastEyeBlinks' will be default initialized @@ -183,14 +183,15 @@ DdeFaceTracker::DdeFaceTracker(const QHostAddress& host, quint16 serverPort, qui _filteredEyeBlinks(), _lastEyeCoefficients(), _isCalibrating(false), + _calibrationValues(), _calibrationCount(0), _calibrationBillboard(NULL), _calibrationBillboardID(0), _calibrationMessage(QString()) { _coefficients.resize(NUM_FACESHIFT_BLENDSHAPES); - _blendshapeCoefficients.resize(NUM_FACESHIFT_BLENDSHAPES); + _calibrationValues.resize(NUM_FACESHIFT_BLENDSHAPES); _eyeStates[0] = EYE_OPEN; _eyeStates[1] = EYE_OPEN; @@ -558,6 +559,9 @@ void DdeFaceTracker::calibrate() { _calibrationBillboard->setHeight(CALIBRATION_BILLBOARD_HEIGHT); _calibrationBillboardID = qApp->getOverlays().addOverlay(_calibrationBillboard); + for (int i = 0; i < NUM_FACESHIFT_BLENDSHAPES; i++) { + _calibrationValues[i] += 0.0f; + } } } @@ -573,6 +577,10 @@ void DdeFaceTracker::addCalibrationDatum() { _calibrationBillboard->setText(_calibrationMessage); } + for (int i = 0; i < NUM_FACESHIFT_BLENDSHAPES; i++) { + _calibrationValues[i] += _coefficients[i]; + } + _calibrationCount += 1; } @@ -587,5 +595,10 @@ void DdeFaceTracker::finishCalibration() { qApp->getOverlays().deleteOverlay(_calibrationBillboardID); _calibrationBillboard = NULL; _isCalibrating = false; + + for (int i = 0; i < NUM_FACESHIFT_BLENDSHAPES; i++) { + _calibrationValues[i] = _calibrationValues[i] / (float)CALIBRATION_SAMPLES; + } + qCDebug(interfaceapp) << "DDE Face Tracker: Calibration finished"; } diff --git a/interface/src/devices/DdeFaceTracker.h b/interface/src/devices/DdeFaceTracker.h index 0078cbcd61..342ef1c3ec 100644 --- a/interface/src/devices/DdeFaceTracker.h +++ b/interface/src/devices/DdeFaceTracker.h @@ -125,6 +125,7 @@ private: bool _isCalibrating; int _calibrationCount; + QVector _calibrationValues; TextOverlay* _calibrationBillboard; int _calibrationBillboardID; QString _calibrationMessage; From 4cd4dee84de3e9d71b906d93ad676082cbc3cfc3 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 6 May 2015 12:26:44 -0700 Subject: [PATCH 05/16] Use average coefficient values to zero out bias Adjust control thresholds to suit. --- interface/src/devices/DdeFaceTracker.cpp | 28 ++++++++++++++---------- interface/src/devices/DdeFaceTracker.h | 1 + 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/interface/src/devices/DdeFaceTracker.cpp b/interface/src/devices/DdeFaceTracker.cpp index 3bb6a3530a..5fb2c5baf6 100644 --- a/interface/src/devices/DdeFaceTracker.cpp +++ b/interface/src/devices/DdeFaceTracker.cpp @@ -87,16 +87,16 @@ static const float DDE_COEFFICIENT_SCALES[] = { 3.0f, // BrowsU_L 3.0f, // BrowsU_R 1.0f, // JawFwd - 1.5f, // JawLeft + 2.0f, // JawLeft 1.8f, // JawOpen 1.0f, // JawChew - 1.5f, // JawRight + 2.0f, // JawRight 1.5f, // MouthLeft 1.5f, // MouthRight 1.5f, // MouthFrown_L 1.5f, // MouthFrown_R - 1.5f, // MouthSmile_L - 1.5f, // MouthSmile_R + 2.5f, // MouthSmile_L + 2.5f, // MouthSmile_R 1.0f, // MouthDimple_L 1.0f, // MouthDimple_R 1.0f, // LipsStretch_L @@ -107,8 +107,8 @@ static const float DDE_COEFFICIENT_SCALES[] = { 1.0f, // LipsLowerDown 1.0f, // LipsUpperOpen 1.0f, // LipsLowerOpen - 2.5f, // LipsFunnel - 2.0f, // LipsPucker + 1.5f, // LipsFunnel + 2.5f, // LipsPucker 1.5f, // ChinLowerRaise 1.5f, // ChinUpperRaise 1.0f, // Sneer @@ -191,6 +191,7 @@ DdeFaceTracker::DdeFaceTracker(const QHostAddress& host, quint16 serverPort, qui { _coefficients.resize(NUM_FACESHIFT_BLENDSHAPES); _blendshapeCoefficients.resize(NUM_FACESHIFT_BLENDSHAPES); + _coefficientAverages.resize(NUM_FACESHIFT_BLENDSHAPES); _calibrationValues.resize(NUM_FACESHIFT_BLENDSHAPES); _eyeStates[0] = EYE_OPEN; @@ -394,11 +395,14 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) { if (_isCalibrating) { addCalibrationDatum(); } + for (int i = 0; i < NUM_FACESHIFT_BLENDSHAPES; i++) { + _coefficients[i] -= _coefficientAverages[i]; + } // Use BrowsU_C to control both brows' up and down float browUp = _coefficients[_browUpCenterIndex]; if (isFiltering) { - const float BROW_VELOCITY_FILTER_STRENGTH = 0.75f; + const float BROW_VELOCITY_FILTER_STRENGTH = 0.5f; float velocity = fabs(browUp - _lastBrowUp) / _averageMessageTime; float velocityFilter = glm::clamp(velocity * BROW_VELOCITY_FILTER_STRENGTH, 0.0f, 1.0f); _filteredBrowUp = velocityFilter * browUp + (1.0f - velocityFilter) * _filteredBrowUp; @@ -412,11 +416,11 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) { _coefficients[_browDownRightIndex] = -browUp; // Offset jaw open coefficient - static const float JAW_OPEN_THRESHOLD = 0.16f; + static const float JAW_OPEN_THRESHOLD = 0.1f; _coefficients[_jawOpenIndex] = _coefficients[_jawOpenIndex] - JAW_OPEN_THRESHOLD; // Offset smile coefficients - static const float SMILE_THRESHOLD = 0.18f; + static const float SMILE_THRESHOLD = 0.5f; _coefficients[_mouthSmileLeftIndex] = _coefficients[_mouthSmileLeftIndex] - SMILE_THRESHOLD; _coefficients[_mouthSmileRightIndex] = _coefficients[_mouthSmileRightIndex] - SMILE_THRESHOLD; @@ -443,7 +447,7 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) { // Change to closing or opening states const float EYE_CONTROL_HYSTERISIS = 0.25f; - const float EYE_CLOSING_THRESHOLD = 0.95f; + const float EYE_CLOSING_THRESHOLD = 0.8f; const float EYE_OPENING_THRESHOLD = EYE_CONTROL_THRESHOLD - EYE_CONTROL_HYSTERISIS; if ((_eyeStates[i] == EYE_OPEN || _eyeStates[i] == EYE_OPENING) && eyeCoefficients[i] > EYE_CLOSING_THRESHOLD) { _eyeStates[i] = EYE_CLOSING; @@ -560,7 +564,7 @@ void DdeFaceTracker::calibrate() { _calibrationBillboardID = qApp->getOverlays().addOverlay(_calibrationBillboard); for (int i = 0; i < NUM_FACESHIFT_BLENDSHAPES; i++) { - _calibrationValues[i] += 0.0f; + _calibrationValues[i] = 0.0f; } } } @@ -597,7 +601,7 @@ void DdeFaceTracker::finishCalibration() { _isCalibrating = false; for (int i = 0; i < NUM_FACESHIFT_BLENDSHAPES; i++) { - _calibrationValues[i] = _calibrationValues[i] / (float)CALIBRATION_SAMPLES; + _coefficientAverages[i] = _calibrationValues[i] / (float)CALIBRATION_SAMPLES; } qCDebug(interfaceapp) << "DDE Face Tracker: Calibration finished"; diff --git a/interface/src/devices/DdeFaceTracker.h b/interface/src/devices/DdeFaceTracker.h index 342ef1c3ec..a0cdc1db9c 100644 --- a/interface/src/devices/DdeFaceTracker.h +++ b/interface/src/devices/DdeFaceTracker.h @@ -122,6 +122,7 @@ private: float _lastEyeBlinks[2]; float _filteredEyeBlinks[2]; float _lastEyeCoefficients[2]; + QVector _coefficientAverages; bool _isCalibrating; int _calibrationCount; From c31d36be596b37dc9f46f8ad889cf40466ffdc6b Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Thu, 7 May 2015 12:01:56 -0700 Subject: [PATCH 06/16] Fixing scale resolution issues --- interface/src/Application.cpp | 74 +++++++++++++---------- interface/src/Application.h | 6 +- interface/src/GLCanvas.cpp | 2 +- interface/src/Menu.h | 2 +- interface/src/devices/OculusManager.cpp | 2 +- interface/src/devices/TV3DManager.cpp | 14 ++++- interface/src/ui/ApplicationOverlay.cpp | 15 +++-- libraries/render-utils/src/FboCache.cpp | 3 + libraries/render-utils/src/FboCache.h | 2 + libraries/render-utils/src/GlowEffect.cpp | 36 +++++------ libraries/render-utils/src/GlowEffect.h | 2 +- libraries/shared/src/GLMHelpers.h | 5 ++ libraries/ui/src/OffscreenUi.cpp | 7 ++- 13 files changed, 99 insertions(+), 71 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index cc99181fe1..b952b27c2f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -807,8 +807,7 @@ void Application::initializeUi() { if (devicePixelRatio != oldDevicePixelRatio) { oldDevicePixelRatio = devicePixelRatio; qDebug() << "Device pixel ratio changed, triggering GL resize"; - resizeGL(_glWidget->width(), - _glWidget->height()); + resizeGL(); } }); } @@ -825,15 +824,7 @@ void Application::paintGL() { PerformanceWarning::setSuppressShortTimings(Menu::getInstance()->isOptionChecked(MenuOption::SuppressShortTimings)); bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::paintGL()"); - - // Set the desired FBO texture size. If it hasn't changed, this does nothing. - // Otherwise, it must rebuild the FBOs - if (OculusManager::isConnected()) { - DependencyManager::get()->setFrameBufferSize(OculusManager::getRenderTargetSize()); - } else { - QSize fbSize = _glWidget->getDeviceSize() * getRenderResolutionScale(); - DependencyManager::get()->setFrameBufferSize(fbSize); - } + resizeGL(); glEnable(GL_LINE_SMOOTH); @@ -910,7 +901,14 @@ void Application::paintGL() { renderRearViewMirror(_mirrorViewRect); } - DependencyManager::get()->render(); + auto finalFbo = DependencyManager::get()->render(); + + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + glBindFramebuffer(GL_READ_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(finalFbo)); + glBlitFramebuffer(0, 0, _renderResolution.x, _renderResolution.y, + 0, 0, _glWidget->getDeviceSize().width(), _glWidget->getDeviceSize().height(), + GL_COLOR_BUFFER_BIT, GL_NEAREST); + { PerformanceTimer perfTimer("renderOverlay"); @@ -955,33 +953,47 @@ void Application::showEditEntitiesHelp() { InfoView::show(INFO_EDIT_ENTITIES_PATH); } -void Application::resetCamerasOnResizeGL(Camera& camera, int width, int height) { +void Application::resetCamerasOnResizeGL(Camera& camera, const glm::uvec2& size) { if (OculusManager::isConnected()) { - OculusManager::configureCamera(camera, width, height); + OculusManager::configureCamera(camera, size.x, size.y); } else if (TV3DManager::isConnected()) { - TV3DManager::configureCamera(camera, width, height); + TV3DManager::configureCamera(camera, size.x, size.y); } else { - camera.setAspectRatio((float)width / height); + camera.setAspectRatio((float)size.x / size.y); camera.setFieldOfView(_fieldOfView.get()); } } -void Application::resizeGL(int width, int height) { - DependencyManager::get()->setFrameBufferSize(QSize(width, height)); - resetCamerasOnResizeGL(_myCamera, width, height); +void Application::resizeGL() { + // Set the desired FBO texture size. If it hasn't changed, this does nothing. + // Otherwise, it must rebuild the FBOs + QSize renderSize; + if (OculusManager::isConnected()) { + renderSize = OculusManager::getRenderTargetSize(); + } else { + renderSize = _glWidget->getDeviceSize() * getRenderResolutionScale(); + } + if (_renderResolution == toGlm(renderSize)) { + return; + } - glViewport(0, 0, width, height); // shouldn't this account for the menu??? + _renderResolution = toGlm(renderSize); + DependencyManager::get()->setFrameBufferSize(renderSize); + resetCamerasOnResizeGL(_myCamera, _renderResolution); + + glViewport(0, 0, _renderResolution.x, _renderResolution.y); // shouldn't this account for the menu??? updateProjectionMatrix(); glLoadIdentity(); auto offscreenUi = DependencyManager::get(); offscreenUi->resize(_glWidget->size()); + _glWidget->makeCurrent(); // update Stats width // let's set horizontal offset to give stats some margin to mirror int horizontalOffset = MIRROR_VIEW_WIDTH + MIRROR_VIEW_LEFT_PADDING * 2; - Stats::getInstance()->resetWidth(width, horizontalOffset); + Stats::getInstance()->resetWidth(_renderResolution.x, horizontalOffset); } void Application::updateProjectionMatrix() { @@ -1819,7 +1831,7 @@ void Application::setFullscreen(bool fullscreen) { } void Application::setEnable3DTVMode(bool enable3DTVMode) { - resizeGL(_glWidget->getDeviceWidth(), _glWidget->getDeviceHeight()); + resizeGL(); } void Application::setEnableVRMode(bool enableVRMode) { @@ -1844,7 +1856,7 @@ void Application::setEnableVRMode(bool enableVRMode) { _myCamera.setHmdRotation(glm::quat()); } - resizeGL(_glWidget->getDeviceWidth(), _glWidget->getDeviceHeight()); + resizeGL(); updateCursorVisibility(); } @@ -3200,12 +3212,12 @@ void Application::displaySide(Camera& theCamera, bool selfAvatarOnly, RenderArgs _stars.render(theCamera.getFieldOfView(), theCamera.getAspectRatio(), theCamera.getNearClip(), alpha); } - // draw the sky dome - if (!selfAvatarOnly && Menu::getInstance()->isOptionChecked(MenuOption::Atmosphere)) { - PerformanceTimer perfTimer("atmosphere"); - PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), - "Application::displaySide() ... atmosphere..."); - _environment.renderAtmospheres(theCamera); + // draw the sky dome + if (!selfAvatarOnly && Menu::getInstance()->isOptionChecked(MenuOption::Atmosphere)) { + PerformanceTimer perfTimer("atmosphere"); + PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), + "Application::displaySide() ... atmosphere..."); + _environment.renderAtmospheres(theCamera); } } @@ -4605,7 +4617,3 @@ PickRay Application::computePickRay() const { bool Application::hasFocus() const { return _glWidget->hasFocus(); } - -void Application::resizeGL() { - this->resizeGL(_glWidget->getDeviceWidth(), _glWidget->getDeviceHeight()); -} diff --git a/interface/src/Application.h b/interface/src/Application.h index c4a3509b50..79bc37cd03 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -161,7 +161,7 @@ public: void initializeGL(); void initializeUi(); void paintGL(); - void resizeGL(int width, int height); + void resizeGL(); void resizeEvent(QResizeEvent * size); @@ -192,7 +192,6 @@ public: bool hasFocus() const; PickRay computePickRay() const; PickRay computeViewPickRay(float xRatio, float yRatio) const; - void resizeGL(); bool isThrottleRendering() const; @@ -460,7 +459,7 @@ private slots: void setCursorVisible(bool visible); private: - void resetCamerasOnResizeGL(Camera& camera, int width, int height); + void resetCamerasOnResizeGL(Camera& camera, const glm::uvec2& size); void updateProjectionMatrix(); void updateProjectionMatrix(Camera& camera, bool updateViewFrustum = true); @@ -657,6 +656,7 @@ private: QHash _acceptedExtensions; QList _domainConnectionRefusals; + glm::uvec2 _renderResolution; }; #endif // hifi_Application_h diff --git a/interface/src/GLCanvas.cpp b/interface/src/GLCanvas.cpp index 2cbec1b258..995e1908a9 100644 --- a/interface/src/GLCanvas.cpp +++ b/interface/src/GLCanvas.cpp @@ -64,7 +64,7 @@ void GLCanvas::paintGL() { } void GLCanvas::resizeGL(int width, int height) { - Application::getInstance()->resizeGL(width, height); + Application::getInstance()->resizeGL(); } void GLCanvas::activeChanged(Qt::ApplicationState state) { diff --git a/interface/src/Menu.h b/interface/src/Menu.h index b15607df8f..d4ff3dead2 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -181,7 +181,7 @@ namespace MenuOption { const QString EditEntitiesHelp = "Edit Entities Help..."; const QString Enable3DTVMode = "Enable 3DTV Mode"; const QString EnableCharacterController = "Enable avatar collisions"; - const QString EnableGlowEffect = "Enable Glow Effect (Warning: Poor Oculus Performance)"; + const QString EnableGlowEffect = "Enable Glow Effect"; const QString EnableVRMode = "Enable VR Mode"; const QString ExpandMyAvatarSimulateTiming = "Expand /myAvatar/simulation"; const QString ExpandMyAvatarTiming = "Expand /myAvatar"; diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index 065b7499d3..f4693d3c08 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -627,7 +627,7 @@ void OculusManager::display(QGLWidget * glCanvas, const glm::quat &bodyOrientati if (Menu::getInstance()->isOptionChecked(MenuOption::EnableGlowEffect)) { //Full texture viewport for glow effect glViewport(0, 0, _renderTargetSize.w, _renderTargetSize.h); - finalFbo = DependencyManager::get()->render(true); + finalFbo = DependencyManager::get()->render(); } else { finalFbo = DependencyManager::get()->getPrimaryFramebuffer(); glBindFramebuffer(GL_FRAMEBUFFER, 0); diff --git a/interface/src/devices/TV3DManager.cpp b/interface/src/devices/TV3DManager.cpp index 9d5dd2faae..5d60bf7e19 100644 --- a/interface/src/devices/TV3DManager.cpp +++ b/interface/src/devices/TV3DManager.cpp @@ -14,7 +14,7 @@ #include #include - +#include "gpu/GLBackend.h" #include "Application.h" #include "TV3DManager.h" @@ -163,10 +163,18 @@ void TV3DManager::display(Camera& whichCamera) { glPopMatrix(); glDisable(GL_SCISSOR_TEST); + auto finalFbo = DependencyManager::get()->render(); + auto fboSize = finalFbo->getSize(); + // Get the ACTUAL device size for the BLIT + deviceSize = qApp->getDeviceSize(); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + glBindFramebuffer(GL_READ_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(finalFbo)); + glBlitFramebuffer(0, 0, fboSize.x, fboSize.y, + 0, 0, deviceSize.width(), deviceSize.height(), + GL_COLOR_BUFFER_BIT, GL_NEAREST); + // reset the viewport to how we started glViewport(0, 0, deviceSize.width(), deviceSize.height()); - - DependencyManager::get()->render(); } void TV3DManager::overrideOffAxisFrustum(float& left, float& right, float& bottom, float& top, float& nearVal, diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 5c878b484c..1bfdf88032 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -190,8 +190,8 @@ void ApplicationOverlay::renderOverlay() { Overlays& overlays = qApp->getOverlays(); _textureFov = glm::radians(_hmdUIAngularSize); - glm::vec2 deviceSize = qApp->getCanvasSize(); - _textureAspectRatio = (float)deviceSize.x / (float)deviceSize.y; + glm::vec2 size = qApp->getCanvasSize(); + _textureAspectRatio = aspect(size); //Handle fading and deactivation/activation of UI @@ -204,12 +204,13 @@ void ApplicationOverlay::renderOverlay() { _overlays.buildFramebufferObject(); _overlays.bind(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glViewport(0, 0, size.x, size.y); glPushMatrix(); { const float NEAR_CLIP = -10000; const float FAR_CLIP = 10000; glLoadIdentity(); - glOrtho(0, deviceSize.x, deviceSize.y, 0, NEAR_CLIP, FAR_CLIP); + glOrtho(0, size.x, size.y, 0, NEAR_CLIP, FAR_CLIP); glMatrixMode(GL_MODELVIEW); @@ -269,6 +270,7 @@ void ApplicationOverlay::displayOverlayTexture() { if (_alpha < 1.0) { glEnable(GL_BLEND); } + glViewport(0, 0, qApp->getDeviceSize().width(), qApp->getDeviceSize().height()); static const glm::vec2 topLeft(-1, 1); static const glm::vec2 bottomRight(1, -1); @@ -1129,8 +1131,9 @@ void ApplicationOverlay::TexturedHemisphere::cleanupVBO() { } void ApplicationOverlay::TexturedHemisphere::buildFramebufferObject() { - auto deviceSize = qApp->getDeviceSize(); - if (_framebufferObject != NULL && deviceSize == _framebufferObject->size()) { + auto canvasSize = qApp->getCanvasSize(); + QSize fboSize = QSize(canvasSize.x, canvasSize.y); + if (_framebufferObject != NULL && fboSize == _framebufferObject->size()) { // Already build return; } @@ -1139,7 +1142,7 @@ void ApplicationOverlay::TexturedHemisphere::buildFramebufferObject() { delete _framebufferObject; } - _framebufferObject = new QOpenGLFramebufferObject(deviceSize, QOpenGLFramebufferObject::Depth); + _framebufferObject = new QOpenGLFramebufferObject(fboSize, QOpenGLFramebufferObject::Depth); glBindTexture(GL_TEXTURE_2D, getTexture()); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); diff --git a/libraries/render-utils/src/FboCache.cpp b/libraries/render-utils/src/FboCache.cpp index de2b483573..b6cca8116b 100644 --- a/libraries/render-utils/src/FboCache.cpp +++ b/libraries/render-utils/src/FboCache.cpp @@ -95,4 +95,7 @@ void FboCache::setSize(const QSize& newSize) { }); } +const QSize& FboCache::getSize() { + return _size; +} diff --git a/libraries/render-utils/src/FboCache.h b/libraries/render-utils/src/FboCache.h index 30278470fd..78c3194eb5 100644 --- a/libraries/render-utils/src/FboCache.h +++ b/libraries/render-utils/src/FboCache.h @@ -37,6 +37,8 @@ public: // internal locks and pointers but execute no OpenGL opreations. void lockTexture(int texture); void releaseTexture(int texture); + + const QSize& getSize(); protected: QMap> _fboMap; diff --git a/libraries/render-utils/src/GlowEffect.cpp b/libraries/render-utils/src/GlowEffect.cpp index 3040088ce5..bb18729f12 100644 --- a/libraries/render-utils/src/GlowEffect.cpp +++ b/libraries/render-utils/src/GlowEffect.cpp @@ -129,7 +129,7 @@ static void maybeRelease(const gpu::FramebufferPointer& fbo) { } } -gpu::FramebufferPointer GlowEffect::render(bool toTexture) { +gpu::FramebufferPointer GlowEffect::render() { PerformanceTimer perfTimer("glowEffect"); auto textureCache = DependencyManager::get(); @@ -151,26 +151,24 @@ gpu::FramebufferPointer GlowEffect::render(bool toTexture) { glDisable(GL_DEPTH_TEST); glDepthMask(GL_FALSE); - gpu::FramebufferPointer destFBO = toTexture ? - textureCache->getSecondaryFramebuffer() : nullptr; + gpu::FramebufferPointer destFBO = textureCache->getSecondaryFramebuffer(); if (!_enabled || _isEmpty) { // copy the primary to the screen - if (destFBO && QOpenGLFramebufferObject::hasOpenGLFramebufferBlit()) { - glBindFramebuffer(GL_READ_FRAMEBUFFER, primaryFBO); + if (QOpenGLFramebufferObject::hasOpenGLFramebufferBlit()) { glBindFramebuffer(GL_DRAW_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(destFBO)); - glBlitFramebuffer(0, 0, framebufferSize.width(), framebufferSize.height(), 0, 0, framebufferSize.width(), framebufferSize.height(), GL_COLOR_BUFFER_BIT, GL_NEAREST); + glBindFramebuffer(GL_READ_FRAMEBUFFER, primaryFBO); + glBlitFramebuffer(0, 0, framebufferSize.width(), framebufferSize.height(), + 0, 0, framebufferSize.width(), framebufferSize.height(), + GL_COLOR_BUFFER_BIT, GL_NEAREST); } else { - maybeBind(destFBO); - if (!destFBO) { - //destFBO->getSize(); - glViewport(0, 0, framebufferSize.width(), framebufferSize.height()); - } + glBindFramebuffer(GL_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(destFBO)); + glViewport(0, 0, framebufferSize.width(), framebufferSize.height()); glEnable(GL_TEXTURE_2D); glDisable(GL_LIGHTING); renderFullscreenQuad(); glDisable(GL_TEXTURE_2D); glEnable(GL_LIGHTING); - maybeRelease(destFBO); + glBindFramebuffer(GL_FRAMEBUFFER, 0); } } else { // diffuse into the secondary/tertiary (alternating between frames) @@ -199,22 +197,18 @@ gpu::FramebufferPointer GlowEffect::render(bool toTexture) { _diffuseProgram->release(); } - glBindFramebuffer(GL_FRAMEBUFFER, 0); + destFBO = oldDiffusedFBO; + glBindFramebuffer(GL_FRAMEBUFFER, 0); // add diffused texture to the primary glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(newDiffusedFBO->getRenderBuffer(0))); - if (toTexture) { - destFBO = oldDiffusedFBO; - } - maybeBind(destFBO); - if (!destFBO) { - glViewport(0, 0, framebufferSize.width(), framebufferSize.height()); - } + glBindFramebuffer(GL_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(destFBO)); + glViewport(0, 0, framebufferSize.width(), framebufferSize.height()); _addSeparateProgram->bind(); renderFullscreenQuad(); _addSeparateProgram->release(); - maybeRelease(destFBO); + glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindTexture(GL_TEXTURE_2D, 0); glActiveTexture(GL_TEXTURE0); diff --git a/libraries/render-utils/src/GlowEffect.h b/libraries/render-utils/src/GlowEffect.h index 1cee7b2e9d..73c512ecf5 100644 --- a/libraries/render-utils/src/GlowEffect.h +++ b/libraries/render-utils/src/GlowEffect.h @@ -52,7 +52,7 @@ public: /// Renders the glow effect. To be called after rendering the scene. /// \param toTexture whether to render to a texture, rather than to the frame buffer /// \return the framebuffer object to which we rendered, or NULL if to the frame buffer - gpu::FramebufferPointer render(bool toTexture = false); + gpu::FramebufferPointer render(); public slots: void toggleGlowEffect(bool enabled); diff --git a/libraries/shared/src/GLMHelpers.h b/libraries/shared/src/GLMHelpers.h index a06f6f26cf..9b7cca70ee 100644 --- a/libraries/shared/src/GLMHelpers.h +++ b/libraries/shared/src/GLMHelpers.h @@ -117,6 +117,11 @@ QMatrix4x4 fromGlm(const glm::mat4 & m); QRectF glmToRect(const glm::vec2 & pos, const glm::vec2 & size); +template +float aspect(const T& t) { + return (float)t.x / (float)t.y; +} + #define YAW(euler) euler.y #define PITCH(euler) euler.x #define ROLL(euler) euler.z diff --git a/libraries/ui/src/OffscreenUi.cpp b/libraries/ui/src/OffscreenUi.cpp index 9b32aca96f..7d13a00324 100644 --- a/libraries/ui/src/OffscreenUi.cpp +++ b/libraries/ui/src/OffscreenUi.cpp @@ -117,8 +117,13 @@ void OffscreenUi::addImportPath(const QString& path) { void OffscreenUi::resize(const QSize& newSize) { makeCurrent(); - // Clear out any fbos with the old size qreal pixelRatio = _renderControl->_renderWindow ? _renderControl->_renderWindow->devicePixelRatio() : 1.0; + QSize newOffscreenSize = newSize * pixelRatio; + if (newOffscreenSize == _fboCache.getSize()) { + return; + } + + // Clear out any fbos with the old size qDebug() << "Offscreen UI resizing to " << newSize.width() << "x" << newSize.height() << " with pixel ratio " << pixelRatio; _fboCache.setSize(newSize * pixelRatio); From ada48bcb70647e035176bcb72036af6b382b63fd Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 8 May 2015 09:06:31 -0700 Subject: [PATCH 07/16] fix for glitchy physics updates --- libraries/physics/src/EntityMotionState.cpp | 148 +++++++++----------- 1 file changed, 70 insertions(+), 78 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index c897da3ef9..b5d14e4814 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -151,10 +151,10 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { _movingStepsWithoutSimulationOwner = 0; } - int ownershipClaimDelay = 50; // TODO -- how to pick this? based on meters from our characterController? + uint32_t ownershipClaimDelay = 50; // TODO -- how to pick this? based on meters from our characterController? if (_movingStepsWithoutSimulationOwner > ownershipClaimDelay) { - qDebug() << "Warning -- claiming something I saw moving." << getName(); + //qDebug() << "Warning -- claiming something I saw moving." << getName(); setShouldClaimSimulationOwnership(true); } @@ -178,7 +178,7 @@ void EntityMotionState::computeObjectShapeInfo(ShapeInfo& shapeInfo) { const int MAX_NUM_NON_MOVING_UPDATES = 5; bool EntityMotionState::doesNotNeedToSendUpdate() const { - return !_body->isActive() && _numNonMovingUpdates > MAX_NUM_NON_MOVING_UPDATES; + return !_body || (_body->isActive() && _numNonMovingUpdates > MAX_NUM_NON_MOVING_UPDATES); } bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { @@ -232,6 +232,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { _serverPosition += dt * _serverVelocity; } + // TODO: compensate for simulation offset here btTransform worldTrans = _body->getWorldTransform(); glm::vec3 position = bulletToGLM(worldTrans.getOrigin()); @@ -310,86 +311,60 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ return; // never update entities that are unknown } + bool active = _body->isActive(); + if (!active) { + if (_sentMoving) { + // make sure all derivatives are zero + glm::vec3 zero(0.0f); + _entity->setVelocity(zero); + _entity->setAngularVelocity(zero); + _entity->setAcceleration(zero); + } + + } else { + float gravityLength = glm::length(_entity->getGravity()); + float accVsGravity = glm::abs(glm::length(_measuredAcceleration) - gravityLength); + if (accVsGravity < ACCELERATION_EQUIVALENT_EPSILON_RATIO * gravityLength) { + // acceleration measured during the most recent simulation step was close to gravity. + if (getAccelerationNearlyGravityCount() < STEPS_TO_DECIDE_BALLISTIC) { + // only increment this if we haven't reached the threshold yet. this is to avoid + // overflowing the counter. + incrementAccelerationNearlyGravityCount(); + } + } else { + // acceleration wasn't similar to this entities gravity, so reset the went-ballistic counter + resetAccelerationNearlyGravityCount(); + } + + // if this entity has been accelerated at close to gravity for a certain number of simulation-steps, let + // the entity server's estimates include gravity. + if (getAccelerationNearlyGravityCount() >= STEPS_TO_DECIDE_BALLISTIC) { + _entity->setAcceleration(_entity->getGravity()); + } else { + _entity->setAcceleration(glm::vec3(0.0f)); + } + } + + // remember properties for local server prediction + _serverPosition = _entity->getPosition(); + _serverRotation = _entity->getRotation(); + _serverVelocity = _entity->getVelocity(); + _serverAcceleration = _entity->getAcceleration(); + _serverAngularVelocity = _entity->getAngularVelocity(); + + _sentMoving = _serverVelocity != glm::vec3(0.0f) || _serverAngularVelocity != glm::vec3(0.0f); + EntityItemProperties properties = _entity->getProperties(); - float gravityLength = glm::length(_entity->getGravity()); - float accVsGravity = glm::abs(glm::length(_measuredAcceleration) - gravityLength); - if (accVsGravity < ACCELERATION_EQUIVALENT_EPSILON_RATIO * gravityLength) { - // acceleration measured during the most recent simulation step was close to gravity. - if (getAccelerationNearlyGravityCount() < STEPS_TO_DECIDE_BALLISTIC) { - // only increment this if we haven't reached the threshold yet. this is to avoid - // overflowing the counter. - incrementAccelerationNearlyGravityCount(); - } - } else { - // acceleration wasn't similar to this entities gravity, so reset the went-ballistic counter - resetAccelerationNearlyGravityCount(); - } - - // if this entity has been accelerated at close to gravity for a certain number of simulation-steps, let - // the entity server's estimates include gravity. - if (getAccelerationNearlyGravityCount() >= STEPS_TO_DECIDE_BALLISTIC) { - _entity->setAcceleration(_entity->getGravity()); - } else { - _entity->setAcceleration(glm::vec3(0.0f)); - } - - btTransform worldTrans = _body->getWorldTransform(); - _serverPosition = bulletToGLM(worldTrans.getOrigin()); - properties.setPosition(_serverPosition + ObjectMotionState::getWorldOffset()); - - _serverRotation = bulletToGLM(worldTrans.getRotation()); + // explicitly set the properties that changed + properties.setPosition(_serverPosition); properties.setRotation(_serverRotation); - - bool zeroSpeed = true; - bool zeroSpin = true; - - if (_body->isActive()) { - _serverVelocity = bulletToGLM(_body->getLinearVelocity()); - _serverAngularVelocity = bulletToGLM(_body->getAngularVelocity()); - - // if the speeds are very small we zero them out - const float MINIMUM_EXTRAPOLATION_SPEED_SQUARED = 1.0e-4f; // 1cm/sec - zeroSpeed = (glm::length2(_serverVelocity) < MINIMUM_EXTRAPOLATION_SPEED_SQUARED); - if (zeroSpeed) { - _serverVelocity = glm::vec3(0.0f); - } - const float MINIMUM_EXTRAPOLATION_SPIN_SQUARED = 0.004f; // ~0.01 rotation/sec - zeroSpin = glm::length2(_serverAngularVelocity) < MINIMUM_EXTRAPOLATION_SPIN_SQUARED; - if (zeroSpin) { - _serverAngularVelocity = glm::vec3(0.0f); - } - - _sentMoving = ! (zeroSpeed && zeroSpin); - } else { - _serverVelocity = _serverAngularVelocity = glm::vec3(0.0f); - _sentMoving = false; - } properties.setVelocity(_serverVelocity); - _serverGravity = _entity->getGravity(); - properties.setGravity(_entity->getGravity()); - _serverAcceleration = _entity->getAcceleration(); properties.setAcceleration(_serverAcceleration); properties.setAngularVelocity(_serverAngularVelocity); - auto nodeList = DependencyManager::get(); - QUuid myNodeID = nodeList->getSessionUUID(); - QUuid simulatorID = _entity->getSimulatorID(); - - if (getShouldClaimSimulationOwnership()) { - properties.setSimulatorID(myNodeID); - setShouldClaimSimulationOwnership(false); - } else if (simulatorID == myNodeID && zeroSpeed && zeroSpin) { - // we are the simulator and the entity has stopped. give up "simulator" status - _entity->setSimulatorID(QUuid()); - properties.setSimulatorID(QUuid()); - } else if (simulatorID == myNodeID && !_body->isActive()) { - // it's not active. don't keep simulation ownership. - _entity->setSimulatorID(QUuid()); - properties.setSimulatorID(QUuid()); - } - - // RELIABLE_SEND_HACK: count number of updates for entities at rest so we can stop sending them after some limit. + // RELIABLE_SEND_HACK: count number of updates for entities at rest + // so we can stop sending them after some limit. if (_sentMoving) { _numNonMovingUpdates = 0; } else { @@ -397,8 +372,6 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ } if (_numNonMovingUpdates <= 1) { // we only update lastEdited when we're sending new physics data - // (i.e. NOT when we just simulate the positions forward, nor when we resend non-moving data) - // NOTE: Andrew & Brad to discuss. Let's make sure we're using lastEdited, lastSimulated, and lastUpdated correctly quint64 lastSimulated = _entity->getLastSimulated(); _entity->setLastEdited(lastSimulated); properties.setLastEdited(lastSimulated); @@ -415,6 +388,25 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ properties.setLastEdited(_entity->getLastEdited()); } + auto nodeList = DependencyManager::get(); + QUuid myNodeID = nodeList->getSessionUUID(); + QUuid simulatorID = _entity->getSimulatorID(); + + if (getShouldClaimSimulationOwnership()) { + // we think we should own it, so we tell the server that we do, + // but we don't remember that we own it... + // instead we expect the sever to tell us later whose ownership it has accepted + properties.setSimulatorID(myNodeID); + setShouldClaimSimulationOwnership(false); + } else if (simulatorID == myNodeID + && !_sentMoving + && _numNonMovingUpdates == MAX_NUM_NON_MOVING_UPDATES) { + // we own it, the entity has stopped, and we're sending the last non-moving update + // --> give up ownership + _entity->setSimulatorID(QUuid()); + properties.setSimulatorID(QUuid()); + } + if (EntityItem::getSendPhysicsUpdates()) { EntityItemID id(_entity->getID()); EntityEditPacketSender* entityPacketSender = static_cast(packetSender); From de6a63c69ae8f778e0429aba15b823b885f76414 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Fri, 8 May 2015 09:49:58 -0700 Subject: [PATCH 08/16] add delete button to clear existing dice --- examples/dice.js | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/examples/dice.js b/examples/dice.js index ee48d59617..f313e606b8 100644 --- a/examples/dice.js +++ b/examples/dice.js @@ -32,7 +32,7 @@ var BUTTON_SIZE = 32; var PADDING = 3; var offButton = Overlays.addOverlay("image", { - x: screenSize.x / 2 - BUTTON_SIZE, + x: screenSize.x / 2 - BUTTON_SIZE * 2 + PADDING, y: screenSize.y- (BUTTON_SIZE + PADDING), width: BUTTON_SIZE, height: BUTTON_SIZE, @@ -40,6 +40,17 @@ var offButton = Overlays.addOverlay("image", { color: { red: 255, green: 255, blue: 255}, alpha: 1 }); + +var deleteButton = Overlays.addOverlay("image", { + x: screenSize.x / 2 - BUTTON_SIZE, + y: screenSize.y- (BUTTON_SIZE + PADDING), + width: BUTTON_SIZE, + height: BUTTON_SIZE, + imageURL: HIFI_PUBLIC_BUCKET + "images/delete.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); + var diceButton = Overlays.addOverlay("image", { x: screenSize.x / 2 + PADDING, y: screenSize.y - (BUTTON_SIZE + PADDING), @@ -108,6 +119,8 @@ function mousePressEvent(event) { if (clickedOverlay == offButton) { deleteDice(); Script.stop(); + } else if (clickedOverlay == deleteButton) { + deleteDice(); } else if (clickedOverlay == diceButton) { var HOW_HARD = 2.0; var position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation())); @@ -120,6 +133,7 @@ function mousePressEvent(event) { function scriptEnding() { Overlays.deleteOverlay(offButton); Overlays.deleteOverlay(diceButton); + Overlays.deleteOverlay(deleteButton); } Entities.entityCollisionWithEntity.connect(entityCollisionWithEntity); From e8f43c7f4bfe0e0959eb661d2360629603602a2b Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 8 May 2015 10:03:24 -0700 Subject: [PATCH 09/16] set default atmosphere properties to match the default atmosphere --- .../entities/src/AtmospherePropertyGroup.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/libraries/entities/src/AtmospherePropertyGroup.cpp b/libraries/entities/src/AtmospherePropertyGroup.cpp index c1210be24e..2e0a043749 100644 --- a/libraries/entities/src/AtmospherePropertyGroup.cpp +++ b/libraries/entities/src/AtmospherePropertyGroup.cpp @@ -16,12 +16,19 @@ #include "EntityItemPropertiesMacros.h" AtmospherePropertyGroup::AtmospherePropertyGroup() { - _center = glm::vec3(0.0f); - _innerRadius = 0.0f; - _outerRadius = 0.0f; - _mieScattering = 0.0f; - _rayleighScattering = 0.0f; - _scatteringWavelengths = glm::vec3(0.0f); + const glm::vec3 DEFAULT_CENTER = glm::vec3(0.0f, -1000.0f, 0.0f); + const float DEFAULT_INNER_RADIUS = 1000.0f; + const float DEFAULT_OUTER_RADIUS = 1025.0f; + const float DEFAULT_RAYLEIGH_SCATTERING = 0.0025f; + const float DEFAULT_MIE_SCATTERING = 0.0010f; + const glm::vec3 DEFAULT_SCATTERING_WAVELENGTHS = glm::vec3(0.650f, 0.570f, 0.475f); + + _center = DEFAULT_CENTER; + _innerRadius = DEFAULT_INNER_RADIUS; + _outerRadius = DEFAULT_OUTER_RADIUS; + _mieScattering = DEFAULT_MIE_SCATTERING; + _rayleighScattering = DEFAULT_RAYLEIGH_SCATTERING; + _scatteringWavelengths = DEFAULT_SCATTERING_WAVELENGTHS; _hasStars = true; } From b1d5b2643f0a5a8655c51704ff19051850bf247f Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 8 May 2015 13:17:39 -0700 Subject: [PATCH 10/16] add has stars to edit.js --- examples/html/entityProperties.html | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index e525818e51..9c984ea373 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -26,6 +26,20 @@ ); }; } + function createEmitGroupCheckedPropertyUpdateFunction(group, propertyName) { + return function() { + var properties = {}; + properties[group] = {}; + properties[group][propertyName] = this.checked; + EventBridge.emitWebEvent( + JSON.stringify({ + type: "update", + properties: properties + }) + ); + }; + } + function createEmitNumberPropertyUpdateFunction(propertyName) { return function() { EventBridge.emitWebEvent( @@ -286,6 +300,8 @@ var elZoneAtmosphereScatteringWavelengthsX = document.getElementById("property-zone-atmosphere-scattering-wavelengths-x"); var elZoneAtmosphereScatteringWavelengthsY = document.getElementById("property-zone-atmosphere-scattering-wavelengths-y"); var elZoneAtmosphereScatteringWavelengthsZ = document.getElementById("property-zone-atmosphere-scattering-wavelengths-z"); + var elZoneAtmosphereHasStars = document.getElementById("property-zone-atmosphere-has-stars"); + if (window.EventBridge !== undefined) { EventBridge.scriptEventReceived.connect(function(data) { @@ -486,7 +502,7 @@ elZoneAtmosphereScatteringWavelengthsX.value = properties.atmosphere.scatteringWavelengths.x; elZoneAtmosphereScatteringWavelengthsY.value = properties.atmosphere.scatteringWavelengths.y; elZoneAtmosphereScatteringWavelengthsZ.value = properties.atmosphere.scatteringWavelengths.z; - + elZoneAtmosphereHasStars.checked = properties.atmosphere.hasStars; } @@ -650,6 +666,8 @@ elZoneAtmosphereScatteringWavelengthsX.addEventListener('change', zoneAtmosphereScatterWavelengthsChangeFunction); elZoneAtmosphereScatteringWavelengthsY.addEventListener('change', zoneAtmosphereScatterWavelengthsChangeFunction); elZoneAtmosphereScatteringWavelengthsZ.addEventListener('change', zoneAtmosphereScatterWavelengthsChangeFunction); + elZoneAtmosphereHasStars.addEventListener('change', createEmitGroupCheckedPropertyUpdateFunction('atmosphere','hasStars')); + elMoveSelectionToGrid.addEventListener("click", function() { EventBridge.emitWebEvent(JSON.stringify({ @@ -1153,6 +1171,12 @@
Z
+
+ Atmosphere Has Stars + + + +
From 1936f4c11489260e9fcaa43fd1097cf0e988b5ec Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 8 May 2015 14:03:58 -0700 Subject: [PATCH 11/16] fix zone:nothing bug --- libraries/entities-renderer/src/EntityTreeRenderer.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index b268ba6031..e4c476c6f7 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -450,8 +450,8 @@ void EntityTreeRenderer::render(RenderArgs::RenderMode renderMode, } else { _viewState->endOverrideEnvironmentData(); + auto stage = scene->getSkyStage(); if (_bestZone->getBackgroundMode() == BACKGROUND_MODE_SKYBOX) { - auto stage = scene->getSkyStage(); stage->getSkybox()->setColor(_bestZone->getSkyboxProperties().getColorVec3()); if (_bestZone->getSkyboxProperties().getURL().isEmpty()) { stage->getSkybox()->clearCubemap(); @@ -461,6 +461,8 @@ void EntityTreeRenderer::render(RenderArgs::RenderMode renderMode, stage->getSkybox()->setCubemap(cubeMap->getGPUTexture()); } stage->setBackgroundMode(model::SunSkyStage::SKY_BOX); + } else { + stage->setBackgroundMode(model::SunSkyStage::SKY_DOME); // let the application atmosphere through } } @@ -478,7 +480,7 @@ void EntityTreeRenderer::render(RenderArgs::RenderMode renderMode, _hasPreviousZone = false; } _viewState->endOverrideEnvironmentData(); - scene->getSkyStage()->setBackgroundMode(model::SunSkyStage::SKY_DOME); + scene->getSkyStage()->setBackgroundMode(model::SunSkyStage::SKY_DOME); // let the application atmosphere through } // we must call endScene while we still have the tree locked so that no one deletes a model From d40e4b721876c3c6f691e655e87234d5d6138cf4 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Fri, 8 May 2015 14:05:32 -0700 Subject: [PATCH 12/16] don't apply changes to velocity unless needed --- examples/grab.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/examples/grab.js b/examples/grab.js index 312d21dd43..df2042350e 100644 --- a/examples/grab.js +++ b/examples/grab.js @@ -193,12 +193,15 @@ function update(deltaTime) { // Add Damping newVelocity = Vec3.subtract(newVelocity, Vec3.multiply(newVelocity, DAMPING_RATE)); // Update entity - - //add damping to angular velocity: + } else { + newVelocity = entityProps.velocity; } if (shouldRotate) { angularVelocity = Vec3.subtract(angularVelocity, Vec3.multiply(angularVelocity, ANGULAR_DAMPING_RATE)); + } else { + angularVelocity = entityProps.angularVelocity; } + Entities.editEntity(grabbedEntity, { velocity: newVelocity, angularVelocity: angularVelocity From 603afefaab7833d3fc70de79874130df3b6a432e Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 8 May 2015 14:16:38 -0700 Subject: [PATCH 13/16] silence verbose no-very-helpful log message --- libraries/physics/src/PhysicalEntitySimulation.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/physics/src/PhysicalEntitySimulation.cpp b/libraries/physics/src/PhysicalEntitySimulation.cpp index ed7b986800..50e81b4788 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.cpp +++ b/libraries/physics/src/PhysicalEntitySimulation.cpp @@ -167,7 +167,8 @@ VectorOfMotionStates& PhysicalEntitySimulation::getObjectsToAdd() { _tempVector.push_back(motionState); entityItr = _pendingAdds.erase(entityItr); } else { - qDebug() << "Warning! Failed to generate new shape for entity." << entity->getName(); + // TODO: Seth to look into why this case is hit. + //qDebug() << "Warning! Failed to generate new shape for entity." << entity->getName(); ++entityItr; } } else { From a2ffc1029b9d32ddc38ed875a9fdd9106277f892 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 8 May 2015 14:18:44 -0700 Subject: [PATCH 14/16] clear MotionState pointer in body on delete --- libraries/physics/src/PhysicsEngine.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index ea74a87286..bfd0b6cb28 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -147,6 +147,7 @@ void PhysicsEngine::deleteObjects(VectorOfMotionStates& objects) { // NOTE: setRigidBody() modifies body->m_userPointer so we should clear the MotionState's body BEFORE deleting it. btRigidBody* body = object->getRigidBody(); object->setRigidBody(nullptr); + body->setMotionState(nullptr); delete body; object->releaseShape(); delete object; @@ -161,6 +162,7 @@ void PhysicsEngine::deleteObjects(SetOfMotionStates& objects) { // NOTE: setRigidBody() modifies body->m_userPointer so we should clear the MotionState's body BEFORE deleting it. object->setRigidBody(nullptr); + body->setMotionState(nullptr); delete body; object->releaseShape(); delete object; From 9f229dc3b37084d9185448fdf751c2b62dd4fe50 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 8 May 2015 15:03:04 -0700 Subject: [PATCH 15/16] remove spinners from scatter values --- examples/html/entityProperties.html | 10 +++++----- examples/html/style.css | 8 ++++++++ 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index 9c984ea373..26bcc63f15 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -1154,21 +1154,21 @@
Atmosphere Mie Scattering
- +
Atmosphere Rayleigh Scattering
- +
Atmosphere Scattering Wavelenghts
-
X
-
Y
-
Z
+
X
+
Y
+
Z
diff --git a/examples/html/style.css b/examples/html/style.css index 8be9b92a51..c87201da4b 100644 --- a/examples/html/style.css +++ b/examples/html/style.css @@ -121,6 +121,14 @@ input.coord { display: block; } +input.no-spin::-webkit-outer-spin-button, +input.no-spin::-webkit-inner-spin-button { + display: none; + -webkit-appearance: none; + -moz-appearance: none; + margin: 0; /* <-- Apparently some margin are still there even though it's hidden */ +} + table#entity-table { border-collapse: collapse; font-family: Sans-Serif; From abc99267afd317b3450dfd9941322d7606cec71f Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Fri, 8 May 2015 16:19:39 -0700 Subject: [PATCH 16/16] Typo was making edit.js fail and impossible to debug. --- examples/libraries/entitySelectionTool.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index 80ba4c0f56..f3ea18aef3 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -203,7 +203,7 @@ SelectionManager = (function() { try { listeners[i](); } catch (e) { - print("EntitySelectionTool got exception: " = JSON.stringify(e)); + print("EntitySelectionTool got exception: " + JSON.stringify(e)); } } };