diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index b22fa090eb..8ce1abb05b 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -301,7 +301,6 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) { deltaTime * _orientation.getUp(); } - } } @@ -382,11 +381,28 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) { const float ACCELERATION_PITCH_DECAY = 0.4f; const float ACCELERATION_YAW_DECAY = 0.4f; + const float OCULUS_ACCELERATION_PULL_THRESHOLD = 1.0f; + const int OCULUS_YAW_OFFSET_THRESHOLD = 10; + // Decay HeadPitch as a function of acceleration, so that you look straight ahead when // you start moving, but don't do this with an HMD like the Oculus. if (!OculusManager::isConnected()) { _head.setPitch(_head.getPitch() * (1.f - acceleration * ACCELERATION_PITCH_DECAY * deltaTime)); _head.setYaw(_head.getYaw() * (1.f - acceleration * ACCELERATION_YAW_DECAY * deltaTime)); + } else if (fabsf(acceleration) > OCULUS_ACCELERATION_PULL_THRESHOLD + && fabs(_head.getYaw()) > OCULUS_YAW_OFFSET_THRESHOLD) { + // if we're wearing the oculus + // and this acceleration is above the pull threshold + // and the head yaw if off the body by more than OCULUS_YAW_OFFSET_THRESHOLD + + // match the body yaw to the oculus yaw + _bodyYaw = getAbsoluteHeadYaw(); + + // set the head yaw to zero for this draw + _head.setYaw(0); + + // correct the oculus yaw offset + OculusManager::updateYawOffset(); } //apply the head lean values to the springy position... diff --git a/interface/src/OculusManager.cpp b/interface/src/OculusManager.cpp index e0272ac8ef..168616ec83 100644 --- a/interface/src/OculusManager.cpp +++ b/interface/src/OculusManager.cpp @@ -16,6 +16,7 @@ Ptr OculusManager::_deviceManager; Ptr OculusManager::_hmdDevice; Ptr OculusManager::_sensorDevice; SensorFusion OculusManager::_sensorFusion; +float OculusManager::_yawOffset = 0; #endif void OculusManager::connect() { @@ -36,12 +37,19 @@ void OculusManager::connect() { #endif } +void OculusManager::updateYawOffset() { + float yaw, pitch, roll; + _sensorFusion.GetOrientation().GetEulerAngles(&yaw, &pitch, &roll); + _yawOffset = yaw; +} + void OculusManager::getEulerAngles(float& yaw, float& pitch, float& roll) { #ifdef __APPLE__ _sensorFusion.GetOrientation().GetEulerAngles(&yaw, &pitch, &roll); // convert each angle to degrees - yaw = glm::degrees(yaw); + // remove the yaw offset from the returned yaw + yaw = glm::degrees(yaw - _yawOffset); pitch = glm::degrees(pitch); roll = glm::degrees(roll); #endif diff --git a/interface/src/OculusManager.h b/interface/src/OculusManager.h index 6570a2a4cc..7bfea8b419 100644 --- a/interface/src/OculusManager.h +++ b/interface/src/OculusManager.h @@ -21,12 +21,15 @@ public: static bool isConnected() { return _isConnected; } static void getEulerAngles(float& yaw, float& pitch, float& roll); + + static void updateYawOffset(); private: static bool _isConnected; static Ptr _deviceManager; static Ptr _hmdDevice; static Ptr _sensorDevice; static SensorFusion _sensorFusion; + static float _yawOffset; }; #endif /* defined(__hifi__OculusManager__) */ diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 68707355bb..ea8787a902 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -160,8 +160,9 @@ void VoxelSystem::setupNewVoxelsForDrawing() { } double sinceLastViewCulling = (start - _lastViewCulling) / 1000.0; - // If the view frustum has changed, since last time, then remove nodes that are out of view - if ((sinceLastViewCulling >= std::max(_lastViewCullingElapsed, VIEW_CULLING_RATE_IN_MILLISECONDS)) && hasViewChanged()) { + // If the view frustum is no longer changing, but has changed, since last time, then remove nodes that are out of view + if ((sinceLastViewCulling >= std::max(_lastViewCullingElapsed, VIEW_CULLING_RATE_IN_MILLISECONDS)) + && !isViewChanging() && hasViewChanged()) { _lastViewCulling = start; // When we call removeOutOfView() voxels, we don't actually remove the voxels from the VBOs, but we do remove @@ -883,8 +884,10 @@ bool VoxelSystem::removeOutOfViewOperation(VoxelNode* node, void* extraData) { return true; // keep going! } -bool VoxelSystem::hasViewChanged() { + +bool VoxelSystem::isViewChanging() { bool result = false; // assume the best + // If our viewFrustum has changed since our _lastKnowViewFrustum if (_viewFrustum && !_lastKnowViewFrustum.matches(_viewFrustum)) { result = true; _lastKnowViewFrustum = *_viewFrustum; // save last known @@ -892,6 +895,22 @@ bool VoxelSystem::hasViewChanged() { return result; } +bool VoxelSystem::hasViewChanged() { + bool result = false; // assume the best + + // If we're still changing, report no change yet. + if (isViewChanging()) { + return false; + } + + // If our viewFrustum has changed since our _lastKnowViewFrustum + if (_viewFrustum && !_lastStableViewFrustum.matches(_viewFrustum)) { + result = true; + _lastStableViewFrustum = *_viewFrustum; // save last stable + } + return result; +} + void VoxelSystem::removeOutOfView() { PerformanceWarning warn(_renderWarningsOn, "removeOutOfView()"); removeOutOfViewArgs args(this); diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index 21c1ec38ee..7bffb1d33c 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -66,6 +66,7 @@ public: void removeOutOfView(); bool hasViewChanged(); + bool isViewChanging(); bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, VoxelDetail& detail, float& distance, BoxFace& face); @@ -147,6 +148,7 @@ private: ViewFrustum* _viewFrustum; ViewFrustum _lastKnowViewFrustum; + ViewFrustum _lastStableViewFrustum; int newTreeToArrays(VoxelNode *currentNode); void cleanupRemovedVoxels(); diff --git a/libraries/audio/src/AudioRingBuffer.cpp b/libraries/audio/src/AudioRingBuffer.cpp index ee693ebde3..299ffcc2cb 100644 --- a/libraries/audio/src/AudioRingBuffer.cpp +++ b/libraries/audio/src/AudioRingBuffer.cpp @@ -68,23 +68,27 @@ int AudioRingBuffer::parseData(unsigned char* sourceBuffer, int numBytes) { _shouldLoopbackForAgent = false; } } - - if (!_endOfLastWrite) { - _endOfLastWrite = _buffer; - } else if (diffLastWriteNextOutput() > _ringBufferLengthSamples - _bufferLengthSamples) { - _endOfLastWrite = _buffer; - _nextOutput = _buffer; - _started = false; + + // make sure we have enough bytes left for this to be the right amount of audio + // otherwise we should not copy that data, and leave the buffer pointers where they are + if (numBytes - (dataBuffer - sourceBuffer) == _bufferLengthSamples * sizeof(int16_t)) { + if (!_endOfLastWrite) { + _endOfLastWrite = _buffer; + } else if (diffLastWriteNextOutput() > _ringBufferLengthSamples - _bufferLengthSamples) { + _endOfLastWrite = _buffer; + _nextOutput = _buffer; + _started = false; + } + + memcpy(_endOfLastWrite, dataBuffer, _bufferLengthSamples * sizeof(int16_t)); + + _endOfLastWrite += _bufferLengthSamples; + + if (_endOfLastWrite >= _buffer + _ringBufferLengthSamples) { + _endOfLastWrite = _buffer; + } } - - memcpy(_endOfLastWrite, dataBuffer, _bufferLengthSamples * sizeof(int16_t)); - - _endOfLastWrite += _bufferLengthSamples; - - if (_endOfLastWrite >= _buffer + _ringBufferLengthSamples) { - _endOfLastWrite = _buffer; - } - + return numBytes; } diff --git a/libraries/avatars/src/HeadData.h b/libraries/avatars/src/HeadData.h index 1f0a8181b5..0eb135b899 100644 --- a/libraries/avatars/src/HeadData.h +++ b/libraries/avatars/src/HeadData.h @@ -13,8 +13,8 @@ #include -const float MIN_HEAD_YAW = -85; -const float MAX_HEAD_YAW = 85; +const float MIN_HEAD_YAW = -110; +const float MAX_HEAD_YAW = 110; const float MIN_HEAD_PITCH = -60; const float MAX_HEAD_PITCH = 60; const float MIN_HEAD_ROLL = -50; diff --git a/libraries/voxels/src/ViewFrustum.cpp b/libraries/voxels/src/ViewFrustum.cpp index e58085e606..061727b003 100644 --- a/libraries/voxels/src/ViewFrustum.cpp +++ b/libraries/voxels/src/ViewFrustum.cpp @@ -220,57 +220,70 @@ ViewFrustum::location ViewFrustum::boxInFrustum(const AABox& box) const { } } return(result); - } - -bool ViewFrustum::matches(const ViewFrustum& compareTo) const { - bool debug = false; - bool result = compareTo._position == _position && - compareTo._direction == _direction && - compareTo._up == _up && - compareTo._right == _right && - compareTo._fieldOfView == _fieldOfView && - compareTo._aspectRatio == _aspectRatio && - compareTo._nearClip == _nearClip && - compareTo._farClip == _farClip && - compareTo._eyeOffsetPosition == _eyeOffsetPosition && - compareTo._eyeOffsetOrientation == _eyeOffsetOrientation; +} + +bool testMatches(glm::quat lhs, glm::quat rhs) { + return (fabs(lhs.x - rhs.x) <= EPSILON && fabs(lhs.y - rhs.y) <= EPSILON && fabs(lhs.z - rhs.z) <= EPSILON + && fabs(lhs.w - rhs.w) <= EPSILON); +} + +bool testMatches(glm::vec3 lhs, glm::vec3 rhs) { + return (fabs(lhs.x - rhs.x) <= EPSILON && fabs(lhs.y - rhs.y) <= EPSILON && fabs(lhs.z - rhs.z) <= EPSILON); +} + +bool testMatches(float lhs, float rhs) { + return (fabs(lhs - rhs) <= EPSILON); +} + +bool ViewFrustum::matches(const ViewFrustum& compareTo, bool debug) const { + bool result = + testMatches(compareTo._position, _position ) && + testMatches(compareTo._direction, _direction ) && + testMatches(compareTo._up, _up ) && + testMatches(compareTo._right, _right ) && + testMatches(compareTo._fieldOfView, _fieldOfView ) && + testMatches(compareTo._aspectRatio, _aspectRatio ) && + testMatches(compareTo._nearClip, _nearClip ) && + testMatches(compareTo._farClip, _farClip ) && + testMatches(compareTo._eyeOffsetPosition, _eyeOffsetPosition ) && + testMatches(compareTo._eyeOffsetOrientation, _eyeOffsetOrientation); if (!result && debug) { printLog("ViewFrustum::matches()... result=%s\n", debug::valueOf(result)); printLog("%s -- compareTo._position=%f,%f,%f _position=%f,%f,%f\n", - (compareTo._position == _position ? "MATCHES " : "NO MATCH"), + (testMatches(compareTo._position,_position) ? "MATCHES " : "NO MATCH"), compareTo._position.x, compareTo._position.y, compareTo._position.z, _position.x, _position.y, _position.z ); printLog("%s -- compareTo._direction=%f,%f,%f _direction=%f,%f,%f\n", - (compareTo._direction == _direction ? "MATCHES " : "NO MATCH"), + (testMatches(compareTo._direction, _direction) ? "MATCHES " : "NO MATCH"), compareTo._direction.x, compareTo._direction.y, compareTo._direction.z, _direction.x, _direction.y, _direction.z ); printLog("%s -- compareTo._up=%f,%f,%f _up=%f,%f,%f\n", - (compareTo._up == _up ? "MATCHES " : "NO MATCH"), + (testMatches(compareTo._up, _up) ? "MATCHES " : "NO MATCH"), compareTo._up.x, compareTo._up.y, compareTo._up.z, _up.x, _up.y, _up.z ); printLog("%s -- compareTo._right=%f,%f,%f _right=%f,%f,%f\n", - (compareTo._right == _right ? "MATCHES " : "NO MATCH"), + (testMatches(compareTo._right, _right) ? "MATCHES " : "NO MATCH"), compareTo._right.x, compareTo._right.y, compareTo._right.z, _right.x, _right.y, _right.z ); printLog("%s -- compareTo._fieldOfView=%f _fieldOfView=%f\n", - (compareTo._fieldOfView == _fieldOfView ? "MATCHES " : "NO MATCH"), + (testMatches(compareTo._fieldOfView, _fieldOfView) ? "MATCHES " : "NO MATCH"), compareTo._fieldOfView, _fieldOfView); printLog("%s -- compareTo._aspectRatio=%f _aspectRatio=%f\n", - (compareTo._aspectRatio == _aspectRatio ? "MATCHES " : "NO MATCH"), + (testMatches(compareTo._aspectRatio, _aspectRatio) ? "MATCHES " : "NO MATCH"), compareTo._aspectRatio, _aspectRatio); printLog("%s -- compareTo._nearClip=%f _nearClip=%f\n", - (compareTo._nearClip == _nearClip ? "MATCHES " : "NO MATCH"), + (testMatches(compareTo._nearClip, _nearClip) ? "MATCHES " : "NO MATCH"), compareTo._nearClip, _nearClip); printLog("%s -- compareTo._farClip=%f _farClip=%f\n", - (compareTo._farClip == _farClip ? "MATCHES " : "NO MATCH"), + (testMatches(compareTo._farClip, _farClip) ? "MATCHES " : "NO MATCH"), compareTo._farClip, _farClip); printLog("%s -- compareTo._eyeOffsetPosition=%f,%f,%f _eyeOffsetPosition=%f,%f,%f\n", - (compareTo._eyeOffsetPosition == _eyeOffsetPosition ? "MATCHES " : "NO MATCH"), + (testMatches(compareTo._eyeOffsetPosition, _eyeOffsetPosition) ? "MATCHES " : "NO MATCH"), compareTo._eyeOffsetPosition.x, compareTo._eyeOffsetPosition.y, compareTo._eyeOffsetPosition.z, _eyeOffsetPosition.x, _eyeOffsetPosition.y, _eyeOffsetPosition.z); printLog("%s -- compareTo._eyeOffsetOrientation=%f,%f,%f,%f _eyeOffsetOrientation=%f,%f,%f,%f\n", - (compareTo._eyeOffsetOrientation == _eyeOffsetOrientation ? "MATCHES " : "NO MATCH"), + (testMatches(compareTo._eyeOffsetOrientation, _eyeOffsetOrientation) ? "MATCHES " : "NO MATCH"), compareTo._eyeOffsetOrientation.x, compareTo._eyeOffsetOrientation.y, compareTo._eyeOffsetOrientation.z, compareTo._eyeOffsetOrientation.w, _eyeOffsetOrientation.x, _eyeOffsetOrientation.y, _eyeOffsetOrientation.z, _eyeOffsetOrientation.w); diff --git a/libraries/voxels/src/ViewFrustum.h b/libraries/voxels/src/ViewFrustum.h index 0170030b6c..1ae33d55ad 100644 --- a/libraries/voxels/src/ViewFrustum.h +++ b/libraries/voxels/src/ViewFrustum.h @@ -108,8 +108,8 @@ public: ViewFrustum::location boxInFrustum(const AABox& box) const; // some frustum comparisons - bool matches(const ViewFrustum& compareTo) const; - bool matches(const ViewFrustum* compareTo) const { return matches(*compareTo); }; + bool matches(const ViewFrustum& compareTo, bool debug = false) const; + bool matches(const ViewFrustum* compareTo, bool debug = false) const { return matches(*compareTo, debug); }; void computePickRay(float x, float y, glm::vec3& origin, glm::vec3& direction) const; diff --git a/voxel-server/src/VoxelAgentData.cpp b/voxel-server/src/VoxelAgentData.cpp index 07d19a7fb2..082fc5e7fc 100644 --- a/voxel-server/src/VoxelAgentData.cpp +++ b/voxel-server/src/VoxelAgentData.cpp @@ -66,7 +66,11 @@ bool VoxelAgentData::updateCurrentViewFrustum() { } void VoxelAgentData::updateLastKnownViewFrustum() { - // save our currentViewFrustum into our lastKnownViewFrustum - _lastKnownViewFrustum = _currentViewFrustum; + bool frustumChanges = !_lastKnownViewFrustum.matches(_currentViewFrustum); + + if (frustumChanges) { + // save our currentViewFrustum into our lastKnownViewFrustum + _lastKnownViewFrustum = _currentViewFrustum; + } }