From 1be859ede92f16ff29703d3143febf3996badcd0 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 20 May 2013 17:14:41 -0700 Subject: [PATCH 1/8] Use glDrawRangeElements, which indicates the range of used indices. It may or may not make a difference in performance, but it won't hurt. --- interface/src/VoxelSystem.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index b345f34709..72b23ad1b7 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -663,7 +663,8 @@ void VoxelSystem::render(bool texture) { // draw the number of voxels we have glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesID); glScalef(TREE_SCALE, TREE_SCALE, TREE_SCALE); - glDrawElements(GL_TRIANGLES, 36 * _voxelsInReadArrays, GL_UNSIGNED_INT, 0); + glDrawRangeElementsEXT(GL_TRIANGLES, 0, VERTICES_PER_VOXEL * _voxelsInReadArrays, + 36 * _voxelsInReadArrays, GL_UNSIGNED_INT, 0); glEnable(GL_BLEND); glDisable(GL_CULL_FACE); From 7728a54d269624e9e5f71236dd30ee9269007183 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Mon, 20 May 2013 19:00:49 -0700 Subject: [PATCH 2/8] Converted Transmitter to separate class, removed V1 (Google Glass, Android) support for V2 (iOS) transmitter --- interface/src/Application.cpp | 28 ++--- interface/src/Application.h | 2 + interface/src/Avatar.cpp | 168 --------------------------- interface/src/Avatar.h | 20 +--- libraries/shared/src/PacketHeaders.h | 1 - 5 files changed, 15 insertions(+), 204 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 3c356af930..dbcba2f5c2 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -156,6 +156,7 @@ Application::Application(int& argc, char** argv) : _bytesCount(0) { gettimeofday(&_applicationStartupTime, NULL); + _window->setWindowTitle("Interface"); printLog("Interface Startup:\n"); _voxels.setViewFrustum(&_viewFrustum); @@ -408,14 +409,16 @@ void Application::paintGL() { } } - _frameCount++; + _frameCount++; + // If application has just started, report time from startup to now (first frame display) if (_justStarted) { float startupTime = (usecTimestampNow() - usecTimestamp(&_applicationStartupTime))/1000000.0; _justStarted = false; - char title[30]; - snprintf(title, 30, "Interface: %4.2f seconds", startupTime); + char title[50]; + sprintf(title, "Interface: %4.2f seconds\n", startupTime); + printLog("%s", title); _window->setWindowTitle(title); } } @@ -852,13 +855,10 @@ void Application::idle() { float deltaTime = 1.f/_fps; - // Use Transmitter Hand to move hand if connected, else use mouse - if (_myAvatar.isTransmitterV2Connected()) { + // Use Transmitter Hand to move hand if connected, else use mouse + if (_myTransmitter.isConnected()) { const float HAND_FORCE_SCALING = 0.05f; - const float* handAcceleration = _myAvatar.getTransmitterHandLastAcceleration(); - _myAvatar.setMovedHandOffset(glm::vec3(-handAcceleration[0] * HAND_FORCE_SCALING, - handAcceleration[1] * HAND_FORCE_SCALING, - handAcceleration[2] * HAND_FORCE_SCALING)); + _myAvatar.setMovedHandOffset(_myTransmitter.getLastAcceleration() * HAND_FORCE_SCALING); } else { // update behaviors for avatar hand movement: handControl takes mouse values as input, // and gives back 3D values modulated for smooth transitioning between interaction modes. @@ -1757,8 +1757,8 @@ void Application::displayOverlay() { if (_displayLevels) _serialPort.renderLevels(_glWidget->width(), _glWidget->height()); // Show hand transmitter data if detected - if (_myAvatar.isTransmitterV2Connected()) { - _myAvatar.transmitterV2RenderLevels(_glWidget->width(), _glWidget->height()); + if (_myTransmitter.isConnected()) { + _myTransmitter.renderLevels(_glWidget->width(), _glWidget->height()); } // Display stats and log text onscreen glLineWidth(1.0f); @@ -2111,13 +2111,9 @@ void* Application::networkReceive(void* args) { app->_bytesCount += bytesReceived; switch (app->_incomingPacket[0]) { - case PACKET_HEADER_TRANSMITTER_DATA_V1: - // V1 = android app, or the Google Glass - app->_myAvatar.processTransmitterData(app->_incomingPacket, bytesReceived); - break; case PACKET_HEADER_TRANSMITTER_DATA_V2: // V2 = IOS transmitter app - app->_myAvatar.processTransmitterDataV2(app->_incomingPacket, bytesReceived); + app->_myTransmitter.processIncomingData(app->_incomingPacket, bytesReceived); break; case PACKET_HEADER_MIXED_AUDIO: diff --git a/interface/src/Application.h b/interface/src/Application.h index dae7f8d71b..99c4e530de 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -189,6 +189,8 @@ private: Avatar _myAvatar; // The rendered avatar of oneself + Transmitter _myTransmitter; // Gets UDP data from transmitter app used to animate the avatar + Camera _myCamera; // My view onto the world Camera _viewFrustumOffsetCamera; // The camera we use to sometimes show the view frustum from an offset mode diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index d789f3751a..093e5f26d5 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -76,11 +76,6 @@ Avatar::Avatar(bool isMine) : _speed(0.0f), _maxArmLength(0.0f), _orientation(), - _transmitterIsFirstData(true), - _transmitterHz(0.0f), - _transmitterPackets(0), - _transmitterInitialReading(0.0f, 0.0f, 0.0f), - _isTransmitterV2Connected(false), _pelvisStandingHeight(0.0f), _displayingHead(true), _distanceToNearestAvatar(std::numeric_limits::max()), @@ -1133,169 +1128,6 @@ void Avatar::renderBody(bool lookingInMirror) { } } -// -// Process UDP interface data from Android transmitter or Google Glass -// -void Avatar::processTransmitterData(unsigned char* packetData, int numBytes) { - // Read a packet from a transmitter app, process the data - float - accX, accY, accZ, // Measured acceleration - graX, graY, graZ, // Gravity - gyrX, gyrY, gyrZ, // Gyro velocity in radians/sec as (pitch, roll, yaw) - linX, linY, linZ, // Linear Acceleration (less gravity) - rot1, rot2, rot3, rot4; // Rotation of device: - // rot1 = roll, ranges from -1 to 1, 0 = flat on table - // rot2 = pitch, ranges from -1 to 1, 0 = flat on table - // rot3 = yaw, ranges from -1 to 1 - char device[100]; // Device ID - - enum deviceTypes { DEVICE_GLASS, DEVICE_ANDROID, DEVICE_IPHONE, DEVICE_UNKNOWN }; - - sscanf((char *)packetData, - "tacc %f %f %f gra %f %f %f gyr %f %f %f lin %f %f %f rot %f %f %f %f dna \"%s", - &accX, &accY, &accZ, - &graX, &graY, &graZ, - &gyrX, &gyrY, &gyrZ, - &linX, &linY, &linZ, - &rot1, &rot2, &rot3, &rot4, (char *)&device); - - // decode transmitter device type - deviceTypes deviceType = DEVICE_UNKNOWN; - if (strcmp(device, "ADR")) { - deviceType = DEVICE_ANDROID; - } else { - deviceType = DEVICE_GLASS; - } - - if (_transmitterPackets++ == 0) { - // If first packet received, note time, turn head spring return OFF, get start rotation - gettimeofday(&_transmitterTimer, NULL); - if (deviceType == DEVICE_GLASS) { - _head.setReturnToCenter(true); - _head.setSpringScale(10.f); - printLog("Using Google Glass to drive head, springs ON.\n"); - - } else { - _head.setReturnToCenter(false); - printLog("Using Transmitter %s to drive head, springs OFF.\n", device); - - } - //printLog("Packet: [%s]\n", packetData); - //printLog("Version: %s\n", device); - - _transmitterInitialReading = glm::vec3(rot3, rot2, rot1); - } - - const int TRANSMITTER_COUNT = 100; - if (_transmitterPackets % TRANSMITTER_COUNT == 0) { - // Every 100 packets, record the observed Hz of the transmitter data - timeval now; - gettimeofday(&now, NULL); - double msecsElapsed = diffclock(&_transmitterTimer, &now); - _transmitterHz = static_cast((double)TRANSMITTER_COUNT / (msecsElapsed / 1000.0)); - _transmitterTimer = now; - printLog("Transmitter Hz: %3.1f\n", _transmitterHz); - } - //printLog("Gyr: %3.1f, %3.1f, %3.1f\n", glm::degrees(gyrZ), glm::degrees(-gyrX), glm::degrees(gyrY)); - //printLog("Rot: %3.1f, %3.1f, %3.1f, %3.1f\n", rot1, rot2, rot3, rot4); - - // Update the head with the transmitter data - glm::vec3 eulerAngles((rot3 - _transmitterInitialReading.x) * 180.f, - -(rot2 - _transmitterInitialReading.y) * 180.f, - (rot1 - _transmitterInitialReading.z) * 180.f); - if (eulerAngles.x > 180.f) { eulerAngles.x -= 360.f; } - if (eulerAngles.x < -180.f) { eulerAngles.x += 360.f; } - - glm::vec3 angularVelocity; - if (deviceType != DEVICE_GLASS) { - angularVelocity = glm::vec3(glm::degrees(gyrZ), glm::degrees(-gyrX), glm::degrees(gyrY)); - setHeadFromGyros(&eulerAngles, &angularVelocity, - (_transmitterHz == 0.f) ? 0.f : 1.f / _transmitterHz, 1.0); - - } else { - angularVelocity = glm::vec3(glm::degrees(gyrY), glm::degrees(-gyrX), glm::degrees(-gyrZ)); - setHeadFromGyros(&eulerAngles, &angularVelocity, - (_transmitterHz == 0.f) ? 0.f : 1.f / _transmitterHz, 1000.0); - } -} -// -// Process UDP data from version 2 Transmitter acting as Hand -// -void Avatar::processTransmitterDataV2(unsigned char* packetData, int numBytes) { - if (numBytes == 3 + sizeof(_transmitterHandLastRotationRates) + - sizeof(_transmitterHandLastAcceleration)) { - memcpy(_transmitterHandLastRotationRates, packetData + 2, - sizeof(_transmitterHandLastRotationRates)); - memcpy(_transmitterHandLastAcceleration, packetData + 3 + - sizeof(_transmitterHandLastRotationRates), - sizeof(_transmitterHandLastAcceleration)); - // Convert from transmitter units to internal units - for (int i = 0; i < 3; i++) { - _transmitterHandLastRotationRates[i] *= 180.f / PI; - _transmitterHandLastAcceleration[i] *= GRAVITY_EARTH; - } - if (!_isTransmitterV2Connected) { - printf("Transmitter V2 Connected.\n"); - _isTransmitterV2Connected = true; - } - } else { - printf("Transmitter V2 packet read error.\n"); - } -} - -void Avatar::transmitterV2RenderLevels(int width, int height) { - - char val[50]; - const int LEVEL_CORNER_X = 10; - const int LEVEL_CORNER_Y = 400; - - // Draw the numeric degree/sec values from the gyros - sprintf(val, "Yaw %4.1f", _transmitterHandLastRotationRates[1]); - drawtext(LEVEL_CORNER_X, LEVEL_CORNER_Y, 0.10, 0, 1.0, 1, val, 0, 1, 0); - sprintf(val, "Pitch %4.1f", _transmitterHandLastRotationRates[0]); - drawtext(LEVEL_CORNER_X, LEVEL_CORNER_Y + 15, 0.10, 0, 1.0, 1, val, 0, 1, 0); - sprintf(val, "Roll %4.1f", _transmitterHandLastRotationRates[2]); - drawtext(LEVEL_CORNER_X, LEVEL_CORNER_Y + 30, 0.10, 0, 1.0, 1, val, 0, 1, 0); - sprintf(val, "X %4.3f", _transmitterHandLastAcceleration[0]); - drawtext(LEVEL_CORNER_X, LEVEL_CORNER_Y + 45, 0.10, 0, 1.0, 1, val, 0, 1, 0); - sprintf(val, "Y %4.3f", _transmitterHandLastAcceleration[1]); - drawtext(LEVEL_CORNER_X, LEVEL_CORNER_Y + 60, 0.10, 0, 1.0, 1, val, 0, 1, 0); - sprintf(val, "Z %4.3f", _transmitterHandLastAcceleration[2]); - drawtext(LEVEL_CORNER_X, LEVEL_CORNER_Y + 75, 0.10, 0, 1.0, 1, val, 0, 1, 0); - - // Draw the levels as horizontal lines - const int LEVEL_CENTER = 150; - const float ACCEL_VIEW_SCALING = 50.f; - glLineWidth(2.0); - glColor4f(1, 1, 1, 1); - glBegin(GL_LINES); - // Gyro rates - glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y - 3); - glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + _transmitterHandLastRotationRates[1], LEVEL_CORNER_Y - 3); - glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y + 12); - glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + _transmitterHandLastRotationRates[0], LEVEL_CORNER_Y + 12); - glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y + 27); - glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + _transmitterHandLastRotationRates[2], LEVEL_CORNER_Y + 27); - // Acceleration - glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y + 42); - glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + (int)(_transmitterHandLastAcceleration[0] * ACCEL_VIEW_SCALING), - LEVEL_CORNER_Y + 42); - glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y + 57); - glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + (int)(_transmitterHandLastAcceleration[1] * ACCEL_VIEW_SCALING), - LEVEL_CORNER_Y + 57); - glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y + 72); - glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + (int)(_transmitterHandLastAcceleration[2] * ACCEL_VIEW_SCALING), - LEVEL_CORNER_Y + 72); - - glEnd(); - // Draw green vertical centerline - glColor4f(0, 1, 0, 0.5); - glBegin(GL_LINES); - glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y - 6); - glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y + 30); - glEnd(); -} - void Avatar::setHeadFromGyros(glm::vec3* eulerAngles, glm::vec3* angularVelocity, float deltaTime, float smoothingTime) { // // Given absolute position and angular velocity information, update the avatar's head angles diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h index 3832fa1902..500237930f 100644 --- a/interface/src/Avatar.h +++ b/interface/src/Avatar.h @@ -20,6 +20,7 @@ #include "SerialInterface.h" #include "Balls.h" #include "Head.h" +#include "Transmitter.h" enum DriveKeys { @@ -122,16 +123,6 @@ public: void setThrust(glm::vec3 newThrust) { _thrust = newThrust; }; void addThrust(glm::vec3 newThrust) { _thrust += newThrust; }; glm::vec3 getThrust() { return _thrust; }; - - // Related to getting transmitter UDP data used to animate the avatar hand - void processTransmitterData(unsigned char * packetData, int numBytes); - void processTransmitterDataV2(unsigned char * packetData, int numBytes); - const bool isTransmitterV2Connected() const { return _isTransmitterV2Connected; }; - const float* getTransmitterHandLastAcceleration() const { return _transmitterHandLastAcceleration; }; - const float* getTransmitterHandLastRotationRates() const { return _transmitterHandLastRotationRates; }; - void transmitterV2RenderLevels(int width, int height); - - float getTransmitterHz() { return _transmitterHz; }; void writeAvatarDataToFile(); void readAvatarDataFromFile(); @@ -179,15 +170,6 @@ private: float _maxArmLength; Orientation _orientation; int _driveKeys[MAX_DRIVE_KEYS]; - bool _transmitterIsFirstData; - timeval _transmitterTimeLastReceived; - timeval _transmitterTimer; - float _transmitterHz; - int _transmitterPackets; - glm::vec3 _transmitterInitialReading; - float _transmitterHandLastRotationRates[3]; - float _transmitterHandLastAcceleration[3]; - bool _isTransmitterV2Connected; float _pelvisStandingHeight; float _height; Balls* _balls; diff --git a/libraries/shared/src/PacketHeaders.h b/libraries/shared/src/PacketHeaders.h index 8d9c4ae880..39f81bf651 100644 --- a/libraries/shared/src/PacketHeaders.h +++ b/libraries/shared/src/PacketHeaders.h @@ -28,7 +28,6 @@ const PACKET_HEADER PACKET_HEADER_ERASE_VOXEL = 'E'; const PACKET_HEADER PACKET_HEADER_VOXEL_DATA = 'V'; const PACKET_HEADER PACKET_HEADER_VOXEL_DATA_MONOCHROME = 'v'; const PACKET_HEADER PACKET_HEADER_BULK_AVATAR_DATA = 'X'; -const PACKET_HEADER PACKET_HEADER_TRANSMITTER_DATA_V1 = 't'; const PACKET_HEADER PACKET_HEADER_TRANSMITTER_DATA_V2 = 'T'; const PACKET_HEADER PACKET_HEADER_ENVIRONMENT_DATA = 'e'; const PACKET_HEADER PACKET_HEADER_DOMAIN_LIST_REQUEST = 'L'; From 3539ec858e9b3f2278242c430c61adb6d1ea6ac6 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Mon, 20 May 2013 23:22:28 -0700 Subject: [PATCH 3/8] Added hand movement and body motion to transmitter. Feel much better - like dancing. --- interface/src/Application.cpp | 24 ++++++++++++++++++------ interface/src/Application.h | 1 + interface/src/Avatar.cpp | 23 +++++++++++++++++++++-- interface/src/Avatar.h | 2 +- 4 files changed, 41 insertions(+), 9 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index dbcba2f5c2..d4ab79b09c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -849,7 +849,7 @@ void Application::idle() { timeval check; gettimeofday(&check, NULL); - // Only run simulation code if more than IDLE_SIMULATE_MSECS have passed since last time + // Only run simulation code if more than IDLE_SIMULATE_MSECS have passed since last time we ran if (diffclock(&_lastTimeIdle, &check) > IDLE_SIMULATE_MSECS) { @@ -857,8 +857,10 @@ void Application::idle() { // Use Transmitter Hand to move hand if connected, else use mouse if (_myTransmitter.isConnected()) { - const float HAND_FORCE_SCALING = 0.05f; - _myAvatar.setMovedHandOffset(_myTransmitter.getLastAcceleration() * HAND_FORCE_SCALING); + const float HAND_FORCE_SCALING = 0.01f; + glm::vec3 estimatedRotation = _myTransmitter.getEstimatedRotation(); + glm::vec3 handForce(-estimatedRotation.z, -estimatedRotation.x, estimatedRotation.y); + _myAvatar.setMovedHandOffset(handForce * HAND_FORCE_SCALING); } else { // update behaviors for avatar hand movement: handControl takes mouse values as input, // and gives back 3D values modulated for smooth transitioning between interaction modes. @@ -964,20 +966,26 @@ void Application::idle() { networkReceive(0); } - //loop through all the remote avatars and simulate them... + //loop through all the other avatars and simulate them... AgentList* agentList = AgentList::getInstance(); agentList->lock(); for(AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) { if (agent->getLinkedData() != NULL) { Avatar *avatar = (Avatar *)agent->getLinkedData(); - avatar->simulate(deltaTime); + avatar->simulate(deltaTime, false); avatar->setMouseRay(mouseRayOrigin, mouseRayDirection); } } agentList->unlock(); + // Simulate myself _myAvatar.setGravity(getGravity(_myAvatar.getPosition())); - _myAvatar.simulate(deltaTime); + if (_transmitterDrives->isChecked() && _myTransmitter.isConnected()) { + _myAvatar.simulate(deltaTime, &_myTransmitter); + } else { + _myAvatar.simulate(deltaTime, NULL); + + } // Update audio stats for procedural sounds #ifndef _WIN32 @@ -1204,6 +1212,9 @@ void Application::initMenu() { _gyroLook->setChecked(true); (_mouseLook = optionsMenu->addAction("Mouse Look"))->setCheckable(true); _mouseLook->setChecked(false); + (_transmitterDrives = optionsMenu->addAction("Transmitter Drive"))->setCheckable(true); + _transmitterDrives->setChecked(true); + optionsMenu->addAction("Fullscreen", this, SLOT(setFullscreen(bool)), Qt::Key_F)->setCheckable(true); QMenu* renderMenu = menuBar->addMenu("Render"); @@ -2055,6 +2066,7 @@ void Application::resetSensors() { } QCursor::setPos(_headMouseX, _headMouseY); _myAvatar.reset(); + _myTransmitter.resetLevels(); } static void setShortcutsEnabled(QWidget* widget, bool enabled) { diff --git a/interface/src/Application.h b/interface/src/Application.h index 99c4e530de..092515bb38 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -134,6 +134,7 @@ private: QAction* _lookingInMirror; // Are we currently rendering one's own head as if in mirror? QAction* _gyroLook; // Whether to allow the gyro data from head to move your view QAction* _mouseLook; // Whether the have the mouse near edge of screen move your view + QAction* _transmitterDrives; // Whether to have Transmitter data move/steer the Avatar QAction* _renderVoxels; // Whether to render voxels QAction* _renderVoxelTextures; // Whether to render noise textures on voxels QAction* _renderStarsOn; // Whether to display the stars diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 093e5f26d5..597ca19457 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -209,7 +209,7 @@ void Avatar::updateFromMouse(int mouseX, int mouseY, int screenWidth, int scree return; } -void Avatar::simulate(float deltaTime) { +void Avatar::simulate(float deltaTime, Transmitter* transmitter) { //figure out if the mouse cursor is over any body spheres... if (_isMine) { @@ -258,7 +258,8 @@ void Avatar::simulate(float deltaTime) { if (_isMine) { _thrust = glm::vec3(0.0f, 0.0f, 0.0f); - + + // Add Thrusts from keyboard if (_driveKeys[FWD ]) {_thrust += THRUST_MAG * deltaTime * _orientation.getFront();} if (_driveKeys[BACK ]) {_thrust -= THRUST_MAG * deltaTime * _orientation.getFront();} if (_driveKeys[RIGHT ]) {_thrust += THRUST_MAG * deltaTime * _orientation.getRight();} @@ -267,6 +268,24 @@ void Avatar::simulate(float deltaTime) { if (_driveKeys[DOWN ]) {_thrust -= THRUST_MAG * deltaTime * _orientation.getUp();} if (_driveKeys[ROT_RIGHT]) {_bodyYawDelta -= YAW_MAG * deltaTime;} if (_driveKeys[ROT_LEFT ]) {_bodyYawDelta += YAW_MAG * deltaTime;} + + // Add thrusts from Transmitter + if (transmitter) { + glm::vec3 rotation = transmitter->getEstimatedRotation(); + const float TRANSMITTER_MIN_RATE = 1.f; + const float TRANSMITTER_LATERAL_FORCE_SCALE = 25.f; + const float TRANSMITTER_FWD_FORCE_SCALE = 50.f; + const float TRANSMITTER_YAW_SCALE = 7.0f; + if (fabs(rotation.z) > TRANSMITTER_MIN_RATE) { + _thrust += rotation.z * TRANSMITTER_LATERAL_FORCE_SCALE * deltaTime * _orientation.getRight(); + } + if (fabs(rotation.x) > TRANSMITTER_MIN_RATE) { + _thrust += -rotation.x * TRANSMITTER_FWD_FORCE_SCALE * deltaTime * _orientation.getFront(); + } + if (fabs(rotation.y) > TRANSMITTER_MIN_RATE) { + _bodyYawDelta += rotation.y * TRANSMITTER_YAW_SCALE * deltaTime; + } + } } // update body yaw by body yaw delta diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h index 500237930f..9dc335e031 100644 --- a/interface/src/Avatar.h +++ b/interface/src/Avatar.h @@ -110,7 +110,7 @@ public: void setMousePressed(bool pressed); void render(bool lookingInMirror, glm::vec3 cameraPosition); void renderBody(bool lookingInMirror); - void simulate(float); + void simulate(float deltaTime, Transmitter* transmitter); void setMovedHandOffset(glm::vec3 movedHandOffset) { _movedHandOffset = movedHandOffset; } void updateArmIKAndConstraints( float deltaTime ); void setDisplayingHead( bool displayingHead ); From 340882a3308f2e79d6e1609055ec092f79ab1efc Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 21 May 2013 10:22:05 -0700 Subject: [PATCH 4/8] Changed 1P view to turn off head rendering when close/inside head rather than showing disembodied neck --- interface/src/Application.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d4ab79b09c..3cf26ef2e5 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -316,6 +316,10 @@ void Application::paintGL() { 0.0f, //-_myAvatar.getAbsoluteHeadPitch(), 0.0f); + // Take a look at whether we are inside head, don't render it if so. + const float HEAD_RENDER_DISTANCE = 0.5; + glm::vec3 distanceToHead(_myCamera.getPosition() - _myAvatar.getSpringyHeadPosition()); + if (glm::length(distanceToHead) < HEAD_RENDER_DISTANCE) { _myAvatar.setDisplayingHead(false); } } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { _myCamera.setTargetPosition(_myAvatar.getHeadPosition()); @@ -1052,7 +1056,7 @@ void Application::setRenderFirstPerson(bool firstPerson) { a.distance = 0.0f; a.tightness = 100.0f; _myCamera.setMode(CAMERA_MODE_FIRST_PERSON, a); - _myAvatar.setDisplayingHead(false); + _myAvatar.setDisplayingHead(true); } else { Camera::CameraFollowingAttributes a; From 71a875042a44f80b3769a9f1e45430576f5253ea Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 21 May 2013 11:57:14 -0700 Subject: [PATCH 5/8] Updated transmitter class to handle correct orientation of gyros --- 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 3cf26ef2e5..f09feee0f3 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1366,7 +1366,7 @@ void Application::updateAvatar(float deltaTime) { float measuredYawRate = _serialPort.getLastYawRate(); // Update gyro-based mouse (X,Y on screen) - const float MIN_MOUSE_RATE = 1.0; + const float MIN_MOUSE_RATE = 3.0; const float HORIZONTAL_PIXELS_PER_DEGREE = 2880.f / 45.f; const float VERTICAL_PIXELS_PER_DEGREE = 1800.f / 30.f; if (powf(measuredYawRate * measuredYawRate + From 597769a8612307875f0f88ea438cb11e0e793f57 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 21 May 2013 12:58:02 -0700 Subject: [PATCH 6/8] Added basic capsule/sphere collisions between avatar and voxels. --- interface/src/Application.cpp | 20 +++--- interface/src/Application.h | 3 + interface/src/Audio.cpp | 2 +- interface/src/Avatar.cpp | 18 +++++ interface/src/Avatar.h | 1 + interface/src/VoxelSystem.cpp | 14 ++++ interface/src/VoxelSystem.h | 5 +- libraries/voxels/src/VoxelTree.cpp | 101 +++++++++++++++++++++++++++-- libraries/voxels/src/VoxelTree.h | 3 + 9 files changed, 151 insertions(+), 16 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 3c356af930..75c086b3cb 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -82,39 +82,39 @@ protected: }; void GLCanvas::initializeGL() { - static_cast(QCoreApplication::instance())->initializeGL(); + Application::getInstance()->initializeGL(); } void GLCanvas::paintGL() { - static_cast(QCoreApplication::instance())->paintGL(); + Application::getInstance()->paintGL(); } void GLCanvas::resizeGL(int width, int height) { - static_cast(QCoreApplication::instance())->resizeGL(width, height); + Application::getInstance()->resizeGL(width, height); } void GLCanvas::keyPressEvent(QKeyEvent* event) { - static_cast(QCoreApplication::instance())->keyPressEvent(event); + Application::getInstance()->keyPressEvent(event); } void GLCanvas::keyReleaseEvent(QKeyEvent* event) { - static_cast(QCoreApplication::instance())->keyReleaseEvent(event); + Application::getInstance()->keyReleaseEvent(event); } void GLCanvas::mouseMoveEvent(QMouseEvent* event) { - static_cast(QCoreApplication::instance())->mouseMoveEvent(event); + Application::getInstance()->mouseMoveEvent(event); } void GLCanvas::mousePressEvent(QMouseEvent* event) { - static_cast(QCoreApplication::instance())->mousePressEvent(event); + Application::getInstance()->mousePressEvent(event); } void GLCanvas::mouseReleaseEvent(QMouseEvent* event) { - static_cast(QCoreApplication::instance())->mouseReleaseEvent(event); + Application::getInstance()->mouseReleaseEvent(event); } void GLCanvas::wheelEvent(QWheelEvent* event) { - static_cast(QCoreApplication::instance())->wheelEvent(event); + Application::getInstance()->wheelEvent(event); } Application::Application(int& argc, char** argv) : @@ -2098,7 +2098,7 @@ void* Application::networkReceive(void* args) { sockaddr senderAddress; ssize_t bytesReceived; - Application* app = static_cast(QCoreApplication::instance()); + Application* app = Application::getInstance(); while (!app->_stopNetworkReceiveThread) { // check to see if the UI thread asked us to kill the voxel tree. since we're the only thread allowed to do that if (app->_wantToKillLocalVoxels) { diff --git a/interface/src/Application.h b/interface/src/Application.h index dae7f8d71b..7dc6cb9ca6 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -44,6 +44,8 @@ class Application : public QApplication { Q_OBJECT public: + static Application* getInstance() { return static_cast(QCoreApplication::instance()); } + Application(int& argc, char** argv); void initializeGL(); @@ -60,6 +62,7 @@ public: void wheelEvent(QWheelEvent* event); Avatar* getAvatar() { return &_myAvatar; } + VoxelSystem* getVoxels() { return &_voxels; } private slots: diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index c64701d67e..596751ac27 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -84,7 +84,7 @@ int audioCallback (const void* inputBuffer, Audio* parentAudio = (Audio*) userData; AgentList* agentList = AgentList::getInstance(); - Application* interface = (Application*) QCoreApplication::instance(); + Application* interface = Application::getInstance(); Avatar* interfaceAvatar = interface->getAvatar(); int16_t* inputLeft = ((int16_t**) inputBuffer)[0]; diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index d789f3751a..bc1ba30bb2 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -10,6 +10,7 @@ #include #include #include "world.h" +#include "Application.h" #include "Avatar.h" #include "Head.h" #include "Log.h" @@ -259,6 +260,9 @@ void Avatar::simulate(float deltaTime) { updateCollisionWithSphere(_TEST_bigSpherePosition, _TEST_bigSphereRadius, deltaTime); } + // collision response with voxels + updateCollisionWithVoxels(deltaTime); + // driving the avatar around should only apply if this is my avatar (as opposed to an avatar being driven remotely) if (_isMine) { @@ -569,6 +573,20 @@ void Avatar::updateCollisionWithSphere(glm::vec3 position, float radius, float d } } +void Avatar::updateCollisionWithVoxels(float deltaTime) { + VoxelSystem* voxels = Application::getInstance()->getVoxels(); + float radius = _height * 0.125f; + glm::vec3 halfVector = glm::vec3(0.0f, _height * ONE_HALF - radius, 0.0f); + glm::vec3 penetration; + if (voxels->findCapsulePenetration(_position - halfVector, _position + halfVector, radius, penetration)) { + _position += penetration; + + // reflect the velocity component in the direction of penetration + glm::vec3 direction = glm::normalize(penetration); + _velocity -= 2.0f * glm::dot(_velocity, direction) * direction * BOUNCE; + } +} + void Avatar::updateAvatarCollisions(float deltaTime) { // Reset detector for nearest avatar diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h index 3832fa1902..c826b0bb07 100644 --- a/interface/src/Avatar.h +++ b/interface/src/Avatar.h @@ -212,6 +212,7 @@ private: void updateHandMovementAndTouching(float deltaTime); void updateAvatarCollisions(float deltaTime); void updateCollisionWithSphere( glm::vec3 position, float radius, float deltaTime ); + void updateCollisionWithVoxels(float deltaTime); void applyCollisionWithOtherAvatar( Avatar * other, float deltaTime ); void setHeadFromGyros(glm::vec3 * eulerAngles, glm::vec3 * angularVelocity, float deltaTime, float smoothingTime); void checkForMouseRayTouching(); diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 72b23ad1b7..a6f924dd40 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -930,6 +930,20 @@ bool VoxelSystem::findRayIntersection(const glm::vec3& origin, const glm::vec3& return true; } +bool VoxelSystem::findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) { + pthread_mutex_lock(&_treeLock); + bool result = _tree->findSpherePenetration(center, radius, penetration); + pthread_mutex_unlock(&_treeLock); + return result; +} + +bool VoxelSystem::findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration) { + pthread_mutex_lock(&_treeLock); + bool result = _tree->findCapsulePenetration(start, end, radius, penetration); + pthread_mutex_unlock(&_treeLock); + return result; +} + class falseColorizeRandomEveryOtherArgs { public: falseColorizeRandomEveryOtherArgs() : totalNodes(0), colorableNodes(0), coloredNodes(0), colorThis(true) {}; diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index 6ce5855080..3806a904ab 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -69,7 +69,10 @@ public: bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, VoxelDetail& detail, float& distance, BoxFace& face); - + + bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration); + bool findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration); + void collectStatsForTreesAndVBOs(); void deleteVoxelAt(float x, float y, float z, float s); diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 249a70212e..8e570bca86 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -652,7 +652,7 @@ public: bool found; }; -bool findRayOperation(VoxelNode* node, void* extraData) { +bool findRayIntersectionOp(VoxelNode* node, void* extraData) { RayArgs* args = static_cast(extraData); AABox box = node->getAABox(); float distance; @@ -674,10 +674,103 @@ bool findRayOperation(VoxelNode* node, void* extraData) { } bool VoxelTree::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - VoxelNode*& node, float& distance, BoxFace& face) -{ + VoxelNode*& node, float& distance, BoxFace& face) { RayArgs args = { origin / (float)TREE_SCALE, direction, node, distance, face }; - recurseTreeWithOperation(findRayOperation, &args); + recurseTreeWithOperation(findRayIntersectionOp, &args); + return args.found; +} + +class SphereArgs { +public: + glm::vec3 center; + float radius; + glm::vec3& penetration; + bool found; +}; + +bool findSpherePenetrationOp(VoxelNode* node, void* extraData) { + SphereArgs* args = static_cast(extraData); + + // currently, we treat each node as a sphere enveloping the box + const glm::vec3& nodeCenter = node->getCenter(); + float halfNodeScale = node->getScale() * 0.5f; + float halfNodeScale2 = halfNodeScale * halfNodeScale; + float nodeRadius = sqrtf(halfNodeScale2*3.0f); + glm::vec3 vector = args->center - nodeCenter; + float vectorLength = glm::length(vector); + float distance = vectorLength - nodeRadius - args->radius; + if (distance >= 0.0f) { + return false; + } + if (!node->isLeaf()) { + return true; // recurse on children + } + if (node->isColored()) { + args->penetration += vector * (-distance * TREE_SCALE / vectorLength); + args->found = true; + } + return false; +} + +bool VoxelTree::findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) { + SphereArgs args = { center / (float)TREE_SCALE, radius / TREE_SCALE, penetration }; + penetration = glm::vec3(0.0f, 0.0f, 0.0f); + recurseTreeWithOperation(findSpherePenetrationOp, &args); + return args.found; +} + +class CapsuleArgs { +public: + glm::vec3 start; + glm::vec3 end; + float radius; + glm::vec3& penetration; + bool found; +}; + +glm::vec3 computeVectorFromPointToSegment(const glm::vec3& point, const glm::vec3& start, const glm::vec3& end) { + // compute the projection of the point vector onto the segment vector + glm::vec3 segmentVector = end - start; + float proj = glm::dot(point - start, segmentVector) / glm::dot(segmentVector, segmentVector); + if (proj <= 0.0f) { // closest to the start + return start - point; + + } else if (proj >= 1.0f) { // closest to the end + return end - point; + + } else { // closest to the middle + return start + segmentVector*proj - point; + } +} + +bool findCapsulePenetrationOp(VoxelNode* node, void* extraData) { + CapsuleArgs* args = static_cast(extraData); + + // currently, we treat each node as a sphere enveloping the box + const glm::vec3& nodeCenter = node->getCenter(); + float halfNodeScale = node->getScale() * 0.5f; + float halfNodeScale2 = halfNodeScale * halfNodeScale; + float nodeRadius = sqrtf(halfNodeScale2*3.0f); + glm::vec3 vector = computeVectorFromPointToSegment(nodeCenter, args->start, args->end); + float vectorLength = glm::length(vector); + float distance = vectorLength - nodeRadius - args->radius; + if (distance >= 0.0f) { + return false; + } + if (!node->isLeaf()) { + return true; // recurse on children + } + if (node->isColored()) { + args->penetration += vector * (-distance * TREE_SCALE / vectorLength); + args->found = true; + } + return false; +} + +bool VoxelTree::findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration) { + CapsuleArgs args = { start / (float)TREE_SCALE, end / (float)TREE_SCALE, radius / TREE_SCALE, penetration }; + penetration = glm::vec3(0.0f, 0.0f, 0.0f); + recurseTreeWithOperation(findCapsulePenetrationOp, &args); return args.found; } diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index 6d384f0244..190495c92e 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -71,6 +71,9 @@ public: bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, VoxelNode*& node, float& distance, BoxFace& face); + bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration); + bool findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration); + // Note: this assumes the fileFormat is the HIO individual voxels code files void loadVoxelsFile(const char* fileName, bool wantColorRandomizer); From 1118c06f5d152f37acd56e5ec282f082b659aa74 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 21 May 2013 13:01:01 -0700 Subject: [PATCH 7/8] Only do collision checking for own avatar. --- interface/src/Avatar.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index bc1ba30bb2..29122cb010 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -261,7 +261,9 @@ void Avatar::simulate(float deltaTime) { } // collision response with voxels - updateCollisionWithVoxels(deltaTime); + if (_isMine) { + updateCollisionWithVoxels(deltaTime); + } // driving the avatar around should only apply if this is my avatar (as opposed to an avatar being driven remotely) if (_isMine) { From 0377ca1adb2209b25176335fd045b8b5ecc58aac Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 21 May 2013 13:32:41 -0700 Subject: [PATCH 8/8] Compute nodes' enclosing radius in the same place. --- libraries/voxels/src/VoxelNode.cpp | 4 ++++ libraries/voxels/src/VoxelNode.h | 2 ++ libraries/voxels/src/VoxelTree.cpp | 10 ++-------- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/libraries/voxels/src/VoxelNode.cpp b/libraries/voxels/src/VoxelNode.cpp index 6bab72cf61..e79e06e3a3 100644 --- a/libraries/voxels/src/VoxelNode.cpp +++ b/libraries/voxels/src/VoxelNode.cpp @@ -247,6 +247,10 @@ void VoxelNode::printDebugDetails(const char* label) const { printOctalCode(_octalCode); } +float VoxelNode::getEnclosingRadius() const { + return getScale() * sqrtf(3.0f) / 2.0f; +} + bool VoxelNode::isInView(const ViewFrustum& viewFrustum) const { AABox box = _box; // use temporary box so we can scale it box.scale(TREE_SCALE); diff --git a/libraries/voxels/src/VoxelNode.h b/libraries/voxels/src/VoxelNode.h index cf80bcab46..5ce12199c8 100644 --- a/libraries/voxels/src/VoxelNode.h +++ b/libraries/voxels/src/VoxelNode.h @@ -57,6 +57,8 @@ public: float getScale() const { return _box.getSize().x; /* voxelScale = (1 / powf(2, *node->getOctalCode())); */ }; int getLevel() const { return *_octalCode + 1; /* one based or zero based? */ }; + float getEnclosingRadius() const; + bool isColored() const { return (_trueColor[3]==1); }; bool isInView(const ViewFrustum& viewFrustum) const; ViewFrustum::location inFrustum(const ViewFrustum& viewFrustum) const; diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 8e570bca86..cf8615bd3b 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -693,12 +693,9 @@ bool findSpherePenetrationOp(VoxelNode* node, void* extraData) { // currently, we treat each node as a sphere enveloping the box const glm::vec3& nodeCenter = node->getCenter(); - float halfNodeScale = node->getScale() * 0.5f; - float halfNodeScale2 = halfNodeScale * halfNodeScale; - float nodeRadius = sqrtf(halfNodeScale2*3.0f); glm::vec3 vector = args->center - nodeCenter; float vectorLength = glm::length(vector); - float distance = vectorLength - nodeRadius - args->radius; + float distance = vectorLength - node->getEnclosingRadius() - args->radius; if (distance >= 0.0f) { return false; } @@ -748,12 +745,9 @@ bool findCapsulePenetrationOp(VoxelNode* node, void* extraData) { // currently, we treat each node as a sphere enveloping the box const glm::vec3& nodeCenter = node->getCenter(); - float halfNodeScale = node->getScale() * 0.5f; - float halfNodeScale2 = halfNodeScale * halfNodeScale; - float nodeRadius = sqrtf(halfNodeScale2*3.0f); glm::vec3 vector = computeVectorFromPointToSegment(nodeCenter, args->start, args->end); float vectorLength = glm::length(vector); - float distance = vectorLength - nodeRadius - args->radius; + float distance = vectorLength - node->getEnclosingRadius() - args->radius; if (distance >= 0.0f) { return false; }