From 1be859ede92f16ff29703d3143febf3996badcd0 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 20 May 2013 17:14:41 -0700 Subject: [PATCH 1/4] 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 597769a8612307875f0f88ea438cb11e0e793f57 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 21 May 2013 12:58:02 -0700 Subject: [PATCH 2/4] 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 3/4] 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 4/4] 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; }