From 145e9337a2c3983b3e244d8f64d592f71af3420b Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 24 Oct 2013 15:20:46 -0700 Subject: [PATCH 1/7] Let's try actually using the average eye position as the camera location for first person and mirror mode. --- interface/src/Application.cpp | 14 +++----------- interface/src/avatar/Head.cpp | 12 +++++------- 2 files changed, 8 insertions(+), 18 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 8284477658..1f1e4182f1 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -371,12 +371,12 @@ void Application::paintGL() { _myCamera.setUpShift (0.0f); _myCamera.setDistance (0.0f); _myCamera.setTightness (0.0f); // Camera is directly connected to head without smoothing - _myCamera.setTargetPosition(_myAvatar.getHeadJointPosition()); + _myCamera.setTargetPosition(_myAvatar.getHead().calculateAverageEyePosition()); _myCamera.setTargetRotation(_myAvatar.getHead().getOrientation()); } else if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) { _myCamera.setTightness(0.0f); // In first person, camera follows head exactly without delay - _myCamera.setTargetPosition(_myAvatar.getEyeLevelPosition()); + _myCamera.setTargetPosition(_myAvatar.getHead().calculateAverageEyePosition()); _myCamera.setTargetRotation(_myAvatar.getHead().getCameraOrientation()); } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { @@ -386,15 +386,7 @@ void Application::paintGL() { } else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { _myCamera.setTightness(0.0f); _myCamera.setDistance(0.3f); - glm::vec3 targetPosition = _myAvatar.getUprightHeadPosition(); - if (_myAvatar.getHead().getFaceModel().isActive()) { - // make sure we're aligned to the blend face eyes - glm::vec3 leftEyePosition, rightEyePosition; - if (_myAvatar.getHead().getFaceModel().getEyePositions(leftEyePosition, rightEyePosition)) { - targetPosition = (leftEyePosition + rightEyePosition) * 0.5f; - } - } - _myCamera.setTargetPosition(targetPosition); + _myCamera.setTargetPosition(_myAvatar.getHead().calculateAverageEyePosition()); _myCamera.setTargetRotation(_myAvatar.getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PIf, 0.0f))); } diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index 57ad245032..25a72f805b 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -238,6 +238,11 @@ void Head::simulate(float deltaTime, bool isMine) { } _faceModel.simulate(deltaTime); + + calculateGeometry(); + + // the blend face may have custom eye meshes + _faceModel.getEyePositions(_leftEyePosition, _rightEyePosition); } void Head::calculateGeometry() { @@ -286,8 +291,6 @@ void Head::render(float alpha, bool isMine) { _renderAlpha = alpha; if (!(_videoFace.render(alpha) || _faceModel.render(alpha))) { - calculateGeometry(); - glEnable(GL_DEPTH_TEST); glEnable(GL_RESCALE_NORMAL); @@ -299,11 +302,6 @@ void Head::render(float alpha, bool isMine) { renderNose(); renderEyeBrows(); } - - if (_faceModel.isActive()) { - // the blend face may have custom eye meshes - _faceModel.getEyePositions(_leftEyePosition, _rightEyePosition); - } if (_renderLookatVectors) { renderLookatVectors(_leftEyePosition, _rightEyePosition, _lookAtPosition); From 5f696bd72e87cc2726e3ff663fe6b515776f53af Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 24 Oct 2013 16:06:44 -0700 Subject: [PATCH 2/7] Need to set lookat position to camera position before simulating in mirror mode. --- interface/src/Application.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 7cf61627d6..f2462a39ec 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1924,10 +1924,15 @@ void Application::update(float deltaTime) { if (_lookatTargetAvatar && !_faceshift.isActive()) { // If the mouse is over another avatar's head... _myAvatar.getHead().setLookAtPosition(lookAtSpot); + } else if (_isHoverVoxel && !_faceshift.isActive()) { // Look at the hovered voxel lookAtSpot = getMouseVoxelWorldCoordinates(_hoverVoxel); _myAvatar.getHead().setLookAtPosition(lookAtSpot); + + } else if (_myCamera.getMode() == CAMERA_MODE_MIRROR && !_faceshift.isActive()) { + _myAvatar.getHead().setLookAtPosition(_myCamera.getPosition()); + } else { // Just look in direction of the mouse ray const float FAR_AWAY_STARE = TREE_SCALE; @@ -2784,9 +2789,6 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { } // Render my own Avatar - if (whichCamera.getMode() == CAMERA_MODE_MIRROR && !_faceshift.isActive()) { - _myAvatar.getHead().setLookAtPosition(whichCamera.getPosition()); - } _myAvatar.render(whichCamera.getMode() == CAMERA_MODE_MIRROR, Menu::getInstance()->isOptionChecked(MenuOption::AvatarAsBalls)); _myAvatar.setDisplayingLookatVectors(Menu::getInstance()->isOptionChecked(MenuOption::LookAtVectors)); From 4f3bacdd4c346a897c5e2b0e460e531228349c04 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 24 Oct 2013 16:16:45 -0700 Subject: [PATCH 3/7] Use calculated eye position here. --- interface/src/Application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index f2462a39ec..c967b8762c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1757,7 +1757,7 @@ Avatar* Application::findLookatTargetAvatar(const glm::vec3& mouseRayOrigin, con float distance; if (rayIntersectsSphere(mouseRayOrigin, mouseRayDirection, headPosition, HEAD_SPHERE_RADIUS * avatar->getHead().getScale(), distance)) { - eyePosition = avatar->getHead().getEyePosition(); + eyePosition = avatar->getHead().calculateAverageEyePosition(); _lookatIndicatorScale = avatar->getHead().getScale(); _lookatOtherPosition = headPosition; nodeUUID = avatar->getOwningNode()->getUUID(); From 08db294a5b641cd74e53d399d7e594c144686f65 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 24 Oct 2013 17:23:21 -0700 Subject: [PATCH 4/7] Smooth gaze direction relative to window. --- interface/src/devices/Faceshift.cpp | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/interface/src/devices/Faceshift.cpp b/interface/src/devices/Faceshift.cpp index 733b1e639d..239acde637 100644 --- a/interface/src/devices/Faceshift.cpp +++ b/interface/src/devices/Faceshift.cpp @@ -12,6 +12,7 @@ #include "Faceshift.h" #include "Menu.h" +#include "Util.h" using namespace fs; using namespace std; @@ -63,11 +64,23 @@ void Faceshift::update() { } float averageEyePitch = (_eyeGazeLeftPitch + _eyeGazeRightPitch) / 2.0f; float averageEyeYaw = (_eyeGazeLeftYaw + _eyeGazeRightYaw) / 2.0f; + + // get the gaze relative to the window + glm::vec3 eyeEulers = safeEulerAngles(_headRotation * glm::quat(glm::radians(glm::vec3( + averageEyePitch, averageEyeYaw, 0.0f)))); + + // smooth relative to the window const float LONG_TERM_AVERAGE_SMOOTHING = 0.999f; - _longTermAverageEyePitch = glm::mix(averageEyePitch, _longTermAverageEyePitch, LONG_TERM_AVERAGE_SMOOTHING); - _longTermAverageEyeYaw = glm::mix(averageEyeYaw, _longTermAverageEyeYaw, LONG_TERM_AVERAGE_SMOOTHING); - _estimatedEyePitch = averageEyePitch - _longTermAverageEyePitch; - _estimatedEyeYaw = averageEyeYaw - _longTermAverageEyeYaw; + _longTermAverageEyePitch = glm::mix(eyeEulers.x, _longTermAverageEyePitch, LONG_TERM_AVERAGE_SMOOTHING); + _longTermAverageEyeYaw = glm::mix(eyeEulers.y, _longTermAverageEyeYaw, LONG_TERM_AVERAGE_SMOOTHING); + + // back to head-relative + float windowEyePitch = eyeEulers.x - _longTermAverageEyePitch; + float windowEyeYaw = eyeEulers.y - _longTermAverageEyeYaw; + glm::vec3 relativeEyeEulers = safeEulerAngles(glm::inverse(_headRotation) * glm::quat(glm::radians(glm::vec3( + windowEyePitch, windowEyeYaw, 0.0f)))); + _estimatedEyePitch = relativeEyeEulers.x; + _estimatedEyeYaw = relativeEyeEulers.y; } void Faceshift::reset() { From 76fb3c18a2b57c723caa1c2ca9ff3fa5d0d4015b Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 24 Oct 2013 17:35:30 -0700 Subject: [PATCH 5/7] add basic rate control, evenly divide packets per second between all connected voxel servers --- interface/src/Application.cpp | 74 +++++++++++++++++++++++++++-------- 1 file changed, 57 insertions(+), 17 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 45c4a2aff4..e4ab1be8ab 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2338,8 +2338,13 @@ void Application::updateAvatar(float deltaTime) { } void Application::queryVoxels() { - // Need to update this to support multiple different servers... + + // if voxels are disabled, then don't send this at all... + if (!Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) { + return; + } + // These will be the same for all servers, so we can set them up once and then reuse for each server we send to. _voxelQuery.setCameraPosition(_viewFrustum.getPosition()); _voxelQuery.setCameraOrientation(_viewFrustum.getOrientation()); _voxelQuery.setCameraFov(_viewFrustum.getFieldOfView()); @@ -2348,24 +2353,59 @@ void Application::queryVoxels() { _voxelQuery.setCameraFarClip(_viewFrustum.getFarClip()); _voxelQuery.setCameraEyeOffsetPosition(_viewFrustum.getEyeOffsetPosition()); - NodeList* nodeList = NodeList::getInstance(); - - // send head/hand data to the avatar mixer and voxel server unsigned char voxelQueryPacket[MAX_PACKET_SIZE]; - unsigned char* endOfVoxelQueryPacket = voxelQueryPacket; - - endOfVoxelQueryPacket += populateTypeAndVersion(endOfVoxelQueryPacket, PACKET_TYPE_VOXEL_QUERY); - - QByteArray ownerUUID = nodeList->getOwnerUUID().toRfc4122(); - memcpy(endOfVoxelQueryPacket, ownerUUID.constData(), ownerUUID.size()); - endOfVoxelQueryPacket += ownerUUID.size(); - - endOfVoxelQueryPacket += _voxelQuery.getBroadcastData(endOfVoxelQueryPacket); - - const char nodeTypesOfInterest[] = { NODE_TYPE_VOXEL_SERVER }; - controlledBroadcastToNodes(voxelQueryPacket, endOfVoxelQueryPacket - voxelQueryPacket, - nodeTypesOfInterest, sizeof(nodeTypesOfInterest)); + NodeList* nodeList = NodeList::getInstance(); + + // Iterate all of the nodes, and get a count of how many voxel servers we have... + int voxelServerCount = 0; + for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { + // only send to the NodeTypes that are NODE_TYPE_VOXEL_SERVER + if (node->getActiveSocket() != NULL && node->getType() == NODE_TYPE_VOXEL_SERVER) { + voxelServerCount++; + } + } + + // make sure there's at least one voxel server + if (voxelServerCount < 1) { + return; // no voxel servers to talk to, we can bail. + } + + // set our preferred PPS to be exactly evenly divided among all of the voxel servers... + int perServerPPS = DEFAULT_MAX_VOXEL_PPS/voxelServerCount; + printf("queryVoxels()... perServerPPS=%d\n",perServerPPS); + + _voxelQuery.setMaxVoxelPacketsPerSecond(perServerPPS); + + UDPSocket* nodeSocket = NodeList::getInstance()->getNodeSocket(); + for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { + // only send to the NodeTypes that are NODE_TYPE_VOXEL_SERVER + if (node->getActiveSocket() != NULL && node->getType() == NODE_TYPE_VOXEL_SERVER) { + + // we can use this to get the voxel server details + //QUuid nodeUUID = node->getUUID(); + //const JurisdictionMap& map = (_voxelServerJurisdictions)[nodeUUID]; + + // set up the packet for sending... + unsigned char* endOfVoxelQueryPacket = voxelQueryPacket; + + // insert packet type/version and node UUID + endOfVoxelQueryPacket += populateTypeAndVersion(endOfVoxelQueryPacket, PACKET_TYPE_VOXEL_QUERY); + QByteArray ownerUUID = nodeList->getOwnerUUID().toRfc4122(); + memcpy(endOfVoxelQueryPacket, ownerUUID.constData(), ownerUUID.size()); + endOfVoxelQueryPacket += ownerUUID.size(); + + // encode the query data... + endOfVoxelQueryPacket += _voxelQuery.getBroadcastData(endOfVoxelQueryPacket); + + int packetLength = endOfVoxelQueryPacket - voxelQueryPacket; + + nodeSocket->send(node->getActiveSocket(), voxelQueryPacket, packetLength); + + // Feed number of bytes to corresponding channel of the bandwidth meter + _bandwidthMeter.outputStream(BandwidthMeter::VOXELS).updateValue(packetLength); + } + } } ///////////////////////////////////////////////////////////////////////////////////// From 37584244e60eb20f83c6a010c2ccf13b49eb9c10 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 24 Oct 2013 18:37:31 -0700 Subject: [PATCH 6/7] only send PACKET_TYPE_VOXEL_QUERY to voxel servers in view --- interface/src/Application.cpp | 97 ++++++++++++++++++++++++++++------- 1 file changed, 78 insertions(+), 19 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e4ab1be8ab..01eb347b87 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2362,18 +2362,56 @@ void Application::queryVoxels() { for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { // only send to the NodeTypes that are NODE_TYPE_VOXEL_SERVER if (node->getActiveSocket() != NULL && node->getType() == NODE_TYPE_VOXEL_SERVER) { - voxelServerCount++; + + // get the server bounds for this server + QUuid nodeUUID = node->getUUID(); + const JurisdictionMap& map = (_voxelServerJurisdictions)[nodeUUID]; + + unsigned char* rootCode = map.getRootOctalCode(); + + if (rootCode) { + VoxelPositionSize rootDetails; + voxelDetailsForCode(rootCode, rootDetails); + AABox serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s); + serverBounds.scale(TREE_SCALE); + + ViewFrustum::location serverFrustumLocation = _viewFrustum.boxInFrustum(serverBounds); + + /** + printf("queryVoxels()... checking to server UUID=%s bounds=[%f, %f, %f, %f] ", + node->getUUID().toString().toLocal8Bit().constData(), + rootDetails.x, rootDetails.y, rootDetails.z, rootDetails.s); + switch (serverFrustumLocation) { + case ViewFrustum::OUTSIDE: { + printf("location=ViewFrustum::OUTSIDE\n"); + } break; + + case ViewFrustum::INSIDE: { + printf("location=ViewFrustum::INSIDE\n"); + } break; + + case ViewFrustum::INTERSECT: { + printf("location=ViewFrustum::INTERSECT\n"); + } break; + } + **/ + + if (serverFrustumLocation != ViewFrustum::OUTSIDE) { + voxelServerCount++; + } + } } } // make sure there's at least one voxel server if (voxelServerCount < 1) { + //printf("queryVoxels()... no servers in view, not sending PACKET_TYPE_VOXEL_QUERY\n"); return; // no voxel servers to talk to, we can bail. } // set our preferred PPS to be exactly evenly divided among all of the voxel servers... int perServerPPS = DEFAULT_MAX_VOXEL_PPS/voxelServerCount; - printf("queryVoxels()... perServerPPS=%d\n",perServerPPS); + //printf("queryVoxels()... perServerPPS=%d\n",perServerPPS); _voxelQuery.setMaxVoxelPacketsPerSecond(perServerPPS); @@ -2382,28 +2420,49 @@ void Application::queryVoxels() { // only send to the NodeTypes that are NODE_TYPE_VOXEL_SERVER if (node->getActiveSocket() != NULL && node->getType() == NODE_TYPE_VOXEL_SERVER) { - // we can use this to get the voxel server details - //QUuid nodeUUID = node->getUUID(); - //const JurisdictionMap& map = (_voxelServerJurisdictions)[nodeUUID]; - // set up the packet for sending... - unsigned char* endOfVoxelQueryPacket = voxelQueryPacket; + // get the server bounds for this server + QUuid nodeUUID = node->getUUID(); + const JurisdictionMap& map = (_voxelServerJurisdictions)[nodeUUID]; - // insert packet type/version and node UUID - endOfVoxelQueryPacket += populateTypeAndVersion(endOfVoxelQueryPacket, PACKET_TYPE_VOXEL_QUERY); - QByteArray ownerUUID = nodeList->getOwnerUUID().toRfc4122(); - memcpy(endOfVoxelQueryPacket, ownerUUID.constData(), ownerUUID.size()); - endOfVoxelQueryPacket += ownerUUID.size(); - - // encode the query data... - endOfVoxelQueryPacket += _voxelQuery.getBroadcastData(endOfVoxelQueryPacket); + unsigned char* rootCode = map.getRootOctalCode(); - int packetLength = endOfVoxelQueryPacket - voxelQueryPacket; + if (rootCode) { + VoxelPositionSize rootDetails; + voxelDetailsForCode(rootCode, rootDetails); + AABox serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s); + serverBounds.scale(TREE_SCALE); - nodeSocket->send(node->getActiveSocket(), voxelQueryPacket, packetLength); + ViewFrustum::location serverFrustumLocation = _viewFrustum.boxInFrustum(serverBounds); + + if (serverFrustumLocation != ViewFrustum::OUTSIDE) { + + /** + printf("queryVoxels()... sending PACKET_TYPE_VOXEL_QUERY to server UUID=%s bounds=[%f, %f, %f, %f] PPS=%d\n", + node->getUUID().toString().toLocal8Bit().constData(), + rootDetails.x, rootDetails.y, rootDetails.z, rootDetails.s, perServerPPS); + **/ + + // set up the packet for sending... + unsigned char* endOfVoxelQueryPacket = voxelQueryPacket; - // Feed number of bytes to corresponding channel of the bandwidth meter - _bandwidthMeter.outputStream(BandwidthMeter::VOXELS).updateValue(packetLength); + // insert packet type/version and node UUID + endOfVoxelQueryPacket += populateTypeAndVersion(endOfVoxelQueryPacket, PACKET_TYPE_VOXEL_QUERY); + QByteArray ownerUUID = nodeList->getOwnerUUID().toRfc4122(); + memcpy(endOfVoxelQueryPacket, ownerUUID.constData(), ownerUUID.size()); + endOfVoxelQueryPacket += ownerUUID.size(); + + // encode the query data... + endOfVoxelQueryPacket += _voxelQuery.getBroadcastData(endOfVoxelQueryPacket); + + int packetLength = endOfVoxelQueryPacket - voxelQueryPacket; + + nodeSocket->send(node->getActiveSocket(), voxelQueryPacket, packetLength); + + // Feed number of bytes to corresponding channel of the bandwidth meter + _bandwidthMeter.outputStream(BandwidthMeter::VOXELS).updateValue(packetLength); + } + } } } } From 660edddf66799087f93651556b6f8e526028992f Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 24 Oct 2013 18:38:33 -0700 Subject: [PATCH 7/7] only send PACKET_TYPE_VOXEL_QUERY to voxel servers in view --- interface/src/Application.cpp | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 01eb347b87..d7debc3528 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2377,25 +2377,6 @@ void Application::queryVoxels() { ViewFrustum::location serverFrustumLocation = _viewFrustum.boxInFrustum(serverBounds); - /** - printf("queryVoxels()... checking to server UUID=%s bounds=[%f, %f, %f, %f] ", - node->getUUID().toString().toLocal8Bit().constData(), - rootDetails.x, rootDetails.y, rootDetails.z, rootDetails.s); - switch (serverFrustumLocation) { - case ViewFrustum::OUTSIDE: { - printf("location=ViewFrustum::OUTSIDE\n"); - } break; - - case ViewFrustum::INSIDE: { - printf("location=ViewFrustum::INSIDE\n"); - } break; - - case ViewFrustum::INTERSECT: { - printf("location=ViewFrustum::INTERSECT\n"); - } break; - } - **/ - if (serverFrustumLocation != ViewFrustum::OUTSIDE) { voxelServerCount++; } @@ -2405,13 +2386,11 @@ void Application::queryVoxels() { // make sure there's at least one voxel server if (voxelServerCount < 1) { - //printf("queryVoxels()... no servers in view, not sending PACKET_TYPE_VOXEL_QUERY\n"); return; // no voxel servers to talk to, we can bail. } // set our preferred PPS to be exactly evenly divided among all of the voxel servers... int perServerPPS = DEFAULT_MAX_VOXEL_PPS/voxelServerCount; - //printf("queryVoxels()... perServerPPS=%d\n",perServerPPS); _voxelQuery.setMaxVoxelPacketsPerSecond(perServerPPS); @@ -2436,13 +2415,6 @@ void Application::queryVoxels() { ViewFrustum::location serverFrustumLocation = _viewFrustum.boxInFrustum(serverBounds); if (serverFrustumLocation != ViewFrustum::OUTSIDE) { - - /** - printf("queryVoxels()... sending PACKET_TYPE_VOXEL_QUERY to server UUID=%s bounds=[%f, %f, %f, %f] PPS=%d\n", - node->getUUID().toString().toLocal8Bit().constData(), - rootDetails.x, rootDetails.y, rootDetails.z, rootDetails.s, perServerPPS); - **/ - // set up the packet for sending... unsigned char* endOfVoxelQueryPacket = voxelQueryPacket;