From e4bc7af6b4a95a52dde268a2f09a5ef40eca7a38 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 31 May 2013 14:52:29 -0700 Subject: [PATCH 01/10] Working on avatar voxels. --- interface/src/Application.cpp | 9 +++-- interface/src/Application.h | 1 + interface/src/Avatar.cpp | 20 ++++++++++- interface/src/Avatar.h | 3 ++ interface/src/VoxelSystem.cpp | 63 +++++++++++++++++++---------------- interface/src/VoxelSystem.h | 15 ++++----- 6 files changed, 68 insertions(+), 43 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4dd3dba178..12af31234b 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -156,8 +156,6 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _window->setWindowTitle("Interface"); printLog("Interface Startup:\n"); - _voxels.setViewFrustum(&_viewFrustum); - unsigned int listenPort = AGENT_SOCKET_LISTEN_PORT; const char** constArgv = const_cast(argv); const char* portStr = getCmdOption(argc, constArgv, "--listenPort"); @@ -1417,8 +1415,6 @@ void Application::initDisplay() { void Application::init() { _voxels.init(); - _voxels.setViewerAvatar(&_myAvatar); - _voxels.setCamera(&_myCamera); _environment.init(); @@ -1429,6 +1425,7 @@ void Application::init() { _stars.readInput(STAR_FILE, STAR_CACHE_FILE, 0); + _myAvatar.init(); _myAvatar.setPosition(START_LOCATION); _myCamera.setMode(CAMERA_MODE_THIRD_PERSON ); _myCamera.setModeShiftRate(1.0f); @@ -2298,7 +2295,9 @@ QAction* Application::checkedVoxelModeAction() const { void Application::attachNewHeadToAgent(Agent* newAgent) { if (newAgent->getLinkedData() == NULL) { - newAgent->setLinkedData(new Avatar(newAgent)); + Avatar* newAvatar = new Avatar(newAgent); + newAvatar->init(); + newAgent->setLinkedData(newAvatar); } } diff --git a/interface/src/Application.h b/interface/src/Application.h index 22694aaae5..c2918f1add 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -65,6 +65,7 @@ public: Avatar* getAvatar() { return &_myAvatar; } Camera* getCamera() { return &_myCamera; } + ViewFrustum* getViewFrustum() { return &_viewFrustum; } VoxelSystem* getVoxels() { return &_voxels; } Environment* getEnvironment() { return &_environment; } bool shouldEchoAudio() { return _echoAudioMode->isChecked(); } diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 3a4162d296..886fb78d97 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -61,6 +61,8 @@ const float SKIN_COLOR[] = {1.0, 0.84, 0.66}; const float DARK_SKIN_COLOR[] = {0.9, 0.78, 0.63}; const int NUM_BODY_CONE_SIDES = 9; +const float AVATAR_TREE_SCALE = 1.0f; +const int MAX_VOXELS_PER_AVATAR = 2000; bool usingBigSphereCollisionTest = true; @@ -93,7 +95,8 @@ Avatar::Avatar(Agent* owningAgent) : _mouseRayDirection(0.0f, 0.0f, 0.0f), _interactingOther(NULL), _cumulativeMouseYaw(0.0f), - _isMouseTurningRight(false) + _isMouseTurningRight(false), + _voxels(AVATAR_TREE_SCALE, MAX_VOXELS_PER_AVATAR) { // give the pointer to our head to inherited _headData variable from AvatarData @@ -119,6 +122,12 @@ Avatar::~Avatar() { delete _balls; } +void Avatar::init() { + _voxels.init(); + + _voxels.createVoxel(0.0f, 0.0f, 0.0f, 1.0f, 255, 0, 255); +} + void Avatar::reset() { _head.reset(); } @@ -1132,6 +1141,15 @@ void Avatar::renderBody(bool lookingInMirror) { const float RENDER_OPAQUE_BEYOND = 1.0f; // Meters beyond which body is shown opaque const float RENDER_TRANSLUCENT_BEYOND = 0.5f; + // Render the body's voxels + glPushMatrix(); + glTranslatef(_position.x, _position.y, _position.z); + glm::quat rotation = getOrientation(); + glm::vec3 axis = glm::axis(rotation); + glRotatef(glm::angle(rotation), axis.x, axis.y, axis.z); + _voxels.render(false); + glPopMatrix(); + // Render the body as balls and cones for (int b = 0; b < NUM_AVATAR_JOINTS; b++) { float distanceToCamera = glm::length(_cameraPosition - _joint[b].position); diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h index d272514ed1..d1bc651eff 100644 --- a/interface/src/Avatar.h +++ b/interface/src/Avatar.h @@ -19,6 +19,7 @@ #include "Head.h" #include "Skeleton.h" #include "Transmitter.h" +#include "VoxelSystem.h" enum DriveKeys { @@ -46,6 +47,7 @@ public: Avatar(Agent* owningAgent = NULL); ~Avatar(); + void init(); void reset(); void simulate(float deltaTime, Transmitter* transmitter); void updateHeadFromGyros(float frametime, SerialInterface * serialInterface); @@ -147,6 +149,7 @@ private: Avatar* _interactingOther; float _cumulativeMouseYaw; bool _isMouseTurningRight; + VoxelSystem _voxels; // private methods... glm::vec3 caclulateAverageEyePosition() { return _head.caclulateAverageEyePosition(); } // get the position smack-dab between the eyes (for lookat) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 5e1b72e5c4..b4202511e6 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -19,6 +19,7 @@ #include #include #include +#include "Application.h" #include "Log.h" #include "VoxelConstants.h" #include "InterfaceConfig.h" @@ -37,14 +38,15 @@ GLfloat identityNormals[] = { 0,0,-1, 0,0,-1, 0,0,-1, 0,0,-1, -1,0,0, +1,0,0, +1,0,0, -1,0,0, -1,0,0, +1,0,0, +1,0,0, -1,0,0 }; -GLubyte identityIndices[] = { 0,2,1, 0,3,2, // Z- . +GLubyte identityIndices[] = { 0,2,1, 0,3,2, // Z- 8,9,13, 8,13,12, // Y- 16,23,19, 16,20,23, // X- 17,18,22, 17,22,21, // X+ 10,11,15, 10,15,14, // Y+ - 4,5,6, 4,6,7 }; // Z+ . + 4,5,6, 4,6,7 }; // Z+ -VoxelSystem::VoxelSystem() : AgentData(NULL) { +VoxelSystem::VoxelSystem(float treeScale, int maxVoxels) : + AgentData(NULL), _treeScale(treeScale), _maxVoxels(maxVoxels) { _voxelsInReadArrays = _voxelsInWriteArrays = _voxelsUpdated = 0; _writeRenderFullVBO = true; _readRenderFullVBO = true; @@ -312,12 +314,11 @@ void VoxelSystem::copyWrittenDataToReadArrays(bool fullVBOs) { } int VoxelSystem::newTreeToArrays(VoxelNode* node) { - assert(_viewFrustum); // you must set up _viewFrustum before calling this int voxelsUpdated = 0; bool shouldRender = false; // assume we don't need to render it // if it's colored, we might need to render it! if (node->isColored()) { - float distanceToNode = node->distanceToCamera(*_viewFrustum); + float distanceToNode = node->distanceToCamera(*Application::getInstance()->getViewFrustum()); float boundary = boundaryDistanceForRenderLevel(node->getLevel()); float childBoundary = boundaryDistanceForRenderLevel(node->getLevel() + 1); bool inBoundary = (distanceToNode <= boundary); @@ -352,7 +353,7 @@ int VoxelSystem::newTreeToArrays(VoxelNode* node) { int VoxelSystem::updateNodeInArraysAsFullVBO(VoxelNode* node) { // If we've run out of room, then just bail... - if (_voxelsInWriteArrays >= MAX_VOXELS_PER_SYSTEM) { + if (_voxelsInWriteArrays >= _maxVoxels) { return 0; } @@ -382,7 +383,7 @@ int VoxelSystem::updateNodeInArraysAsFullVBO(VoxelNode* node) { int VoxelSystem::updateNodeInArraysAsPartialVBO(VoxelNode* node) { // If we've run out of room, then just bail... - if (_voxelsInWriteArrays >= MAX_VOXELS_PER_SYSTEM) { + if (_voxelsInWriteArrays >= _maxVoxels) { return 0; } @@ -425,6 +426,9 @@ int VoxelSystem::updateNodeInArraysAsPartialVBO(VoxelNode* node) { return 0; // not-updated } +ProgramObject* VoxelSystem::_perlinModulateProgram = 0; +GLuint VoxelSystem::_permutationNormalTextureID = 0; + void VoxelSystem::init() { _renderWarningsOn = false; @@ -440,23 +444,23 @@ void VoxelSystem::init() { _unusedArraySpace = 0; // we will track individual dirty sections with these arrays of bools - _writeVoxelDirtyArray = new bool[MAX_VOXELS_PER_SYSTEM]; - memset(_writeVoxelDirtyArray, false, MAX_VOXELS_PER_SYSTEM * sizeof(bool)); - _readVoxelDirtyArray = new bool[MAX_VOXELS_PER_SYSTEM]; - memset(_readVoxelDirtyArray, false, MAX_VOXELS_PER_SYSTEM * sizeof(bool)); + _writeVoxelDirtyArray = new bool[_maxVoxels]; + memset(_writeVoxelDirtyArray, false, _maxVoxels * sizeof(bool)); + _readVoxelDirtyArray = new bool[_maxVoxels]; + memset(_readVoxelDirtyArray, false, _maxVoxels * sizeof(bool)); // prep the data structures for incoming voxel data - _writeVerticesArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM]; - _readVerticesArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM]; + _writeVerticesArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * _maxVoxels]; + _readVerticesArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * _maxVoxels]; - _writeColorsArray = new GLubyte[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM]; - _readColorsArray = new GLubyte[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM]; + _writeColorsArray = new GLubyte[VERTEX_POINTS_PER_VOXEL * _maxVoxels]; + _readColorsArray = new GLubyte[VERTEX_POINTS_PER_VOXEL * _maxVoxels]; - GLuint* indicesArray = new GLuint[INDICES_PER_VOXEL * MAX_VOXELS_PER_SYSTEM]; + GLuint* indicesArray = new GLuint[INDICES_PER_VOXEL * _maxVoxels]; // populate the indicesArray // this will not change given new voxels, so we can set it all up now - for (int n = 0; n < MAX_VOXELS_PER_SYSTEM; n++) { + for (int n = 0; n < _maxVoxels; n++) { // fill the indices array int voxelIndexOffset = n * INDICES_PER_VOXEL; GLuint* currentIndicesPos = indicesArray + voxelIndexOffset; @@ -468,11 +472,11 @@ void VoxelSystem::init() { } } - GLfloat* normalsArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM]; + GLfloat* normalsArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * _maxVoxels]; GLfloat* normalsArrayEndPointer = normalsArray; // populate the normalsArray - for (int n = 0; n < MAX_VOXELS_PER_SYSTEM; n++) { + for (int n = 0; n < _maxVoxels; n++) { for (int i = 0; i < VERTEX_POINTS_PER_VOXEL; i++) { *(normalsArrayEndPointer++) = identityNormals[i]; } @@ -481,32 +485,35 @@ void VoxelSystem::init() { // VBO for the verticesArray glGenBuffers(1, &_vboVerticesID); glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID); - glBufferData(GL_ARRAY_BUFFER, VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat) * MAX_VOXELS_PER_SYSTEM, NULL, GL_DYNAMIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat) * _maxVoxels, NULL, GL_DYNAMIC_DRAW); // VBO for the normalsArray glGenBuffers(1, &_vboNormalsID); glBindBuffer(GL_ARRAY_BUFFER, _vboNormalsID); glBufferData(GL_ARRAY_BUFFER, - VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat) * MAX_VOXELS_PER_SYSTEM, + VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat) * _maxVoxels, normalsArray, GL_STATIC_DRAW); // VBO for colorsArray glGenBuffers(1, &_vboColorsID); glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); - glBufferData(GL_ARRAY_BUFFER, VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte) * MAX_VOXELS_PER_SYSTEM, NULL, GL_DYNAMIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte) * _maxVoxels, NULL, GL_DYNAMIC_DRAW); // VBO for the indicesArray glGenBuffers(1, &_vboIndicesID); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesID); glBufferData(GL_ELEMENT_ARRAY_BUFFER, - INDICES_PER_VOXEL * sizeof(GLuint) * MAX_VOXELS_PER_SYSTEM, + INDICES_PER_VOXEL * sizeof(GLuint) * _maxVoxels, indicesArray, GL_STATIC_DRAW); // delete the indices and normals arrays that are no longer needed delete[] indicesArray; delete[] normalsArray; - // create our simple fragment shader + // create our simple fragment shader if we're the first system to init + if (_perlinModulateProgram != 0) { + return; + } switchToResourcesParentIfRequired(); _perlinModulateProgram = new ProgramObject(); _perlinModulateProgram->addShaderFromSourceFile(QGLShader::Vertex, "resources/shaders/perlin_modulate.vert"); @@ -661,7 +668,7 @@ 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); + glScalef(_treeScale, _treeScale, _treeScale); glDrawRangeElementsEXT(GL_TRIANGLES, 0, VERTICES_PER_VOXEL * _voxelsInReadArrays - 1, 36 * _voxelsInReadArrays, GL_UNSIGNED_INT, 0); @@ -855,7 +862,7 @@ bool VoxelSystem::removeOutOfViewOperation(VoxelNode* node, void* extraData) { for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { VoxelNode* childNode = node->getChildAtIndex(i); if (childNode) { - ViewFrustum::location inFrustum = childNode->inFrustum(*thisVoxelSystem->_viewFrustum); + ViewFrustum::location inFrustum = childNode->inFrustum(*Application::getInstance()->getViewFrustum()); switch (inFrustum) { case ViewFrustum::OUTSIDE: { args->nodesOutside++; @@ -907,9 +914,9 @@ bool VoxelSystem::hasViewChanged() { } // If our viewFrustum has changed since our _lastKnowViewFrustum - if (_viewFrustum && !_lastStableViewFrustum.matches(_viewFrustum)) { + if (!_lastStableViewFrustum.matches(Application::getInstance()->getViewFrustum())) { result = true; - _lastStableViewFrustum = *_viewFrustum; // save last stable + _lastStableViewFrustum = *Application::getInstance()->getViewFrustum(); // save last stable } return result; } diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index 7bffb1d33c..de904bb64f 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -16,7 +16,6 @@ #include #include #include -#include "Avatar.h" #include "Camera.h" #include "Util.h" #include "world.h" @@ -27,7 +26,7 @@ const int NUM_CHILDREN = 8; class VoxelSystem : public AgentData { public: - VoxelSystem(); + VoxelSystem(float treeScale = TREE_SCALE, int maxVoxels = MAX_VOXELS_PER_SYSTEM); ~VoxelSystem(); int parseData(unsigned char* sourceBuffer, int numBytes); @@ -41,8 +40,6 @@ public: unsigned long getVoxelsUpdated() const {return _voxelsUpdated;}; unsigned long getVoxelsRendered() const {return _voxelsInReadArrays;}; - void setViewerAvatar(Avatar *newViewerAvatar) { _viewerAvatar = newViewerAvatar; }; - void setCamera(Camera* newCamera) { _camera = newCamera; }; void loadVoxelsFile(const char* fileName,bool wantColorRandomizer); long int getVoxelsCreated(); @@ -114,8 +111,8 @@ private: static float _maxDistance; static float _minDistance; - Avatar* _viewerAvatar; - Camera* _camera; + float _treeScale; + int _maxVoxels; VoxelTree* _tree; GLfloat* _readVerticesArray; GLubyte* _readColorsArray; @@ -143,9 +140,6 @@ private: pthread_mutex_t _bufferWriteLock; pthread_mutex_t _treeLock; - ProgramObject* _perlinModulateProgram; - GLuint _permutationNormalTextureID; - ViewFrustum* _viewFrustum; ViewFrustum _lastKnowViewFrustum; ViewFrustum _lastStableViewFrustum; @@ -158,6 +152,9 @@ private: bool _voxelsDirty; + static ProgramObject* _perlinModulateProgram; + static GLuint _permutationNormalTextureID; + public: void updateVBOs(); void updateFullVBOs(); // all voxels in the VBO From 7425b392376223376c552c748b14aab906c91e07 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 31 May 2013 17:55:30 -0700 Subject: [PATCH 02/10] Working on avatar voxel system. --- interface/src/Avatar.cpp | 9 +- interface/src/Avatar.h | 5 +- interface/src/AvatarVoxelSystem.cpp | 97 ++++++++++++++++++++ interface/src/AvatarVoxelSystem.h | 43 +++++++++ interface/src/VoxelSystem.cpp | 134 +++++++++++----------------- interface/src/VoxelSystem.h | 33 ++++--- 6 files changed, 216 insertions(+), 105 deletions(-) create mode 100644 interface/src/AvatarVoxelSystem.cpp create mode 100644 interface/src/AvatarVoxelSystem.h diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index cc30a011af..7198c0030c 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -57,9 +57,6 @@ const float SKIN_COLOR[] = {1.0, 0.84, 0.66}; const float DARK_SKIN_COLOR[] = {0.9, 0.78, 0.63}; const int NUM_BODY_CONE_SIDES = 9; -const float AVATAR_TREE_SCALE = 1.0f; -const int MAX_VOXELS_PER_AVATAR = 2000; - bool usingBigSphereCollisionTest = true; float chatMessageScale = 0.0015; @@ -91,8 +88,7 @@ Avatar::Avatar(Agent* owningAgent) : _mouseRayDirection(0.0f, 0.0f, 0.0f), _interactingOther(NULL), _cumulativeMouseYaw(0.0f), - _isMouseTurningRight(false), - _voxels(AVATAR_TREE_SCALE, MAX_VOXELS_PER_AVATAR) + _isMouseTurningRight(false) { // give the pointer to our head to inherited _headData variable from AvatarData @@ -1153,7 +1149,8 @@ void Avatar::renderBody(bool lookingInMirror) { // Render the body's voxels glPushMatrix(); - glTranslatef(_position.x, _position.y, _position.z); + const glm::vec3& voxelPosition = _joint[AVATAR_JOINT_PELVIS].springyPosition; + glTranslatef(voxelPosition.x, voxelPosition.y, voxelPosition.z); glm::quat rotation = getOrientation(); glm::vec3 axis = glm::axis(rotation); glRotatef(glm::angle(rotation), axis.x, axis.y, axis.z); diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h index d1bc651eff..726ae972c2 100644 --- a/interface/src/Avatar.h +++ b/interface/src/Avatar.h @@ -13,13 +13,13 @@ #include #include "world.h" #include "AvatarTouch.h" +#include "AvatarVoxelSystem.h" #include "InterfaceConfig.h" #include "SerialInterface.h" #include "Balls.h" #include "Head.h" #include "Skeleton.h" #include "Transmitter.h" -#include "VoxelSystem.h" enum DriveKeys { @@ -149,7 +149,8 @@ private: Avatar* _interactingOther; float _cumulativeMouseYaw; bool _isMouseTurningRight; - VoxelSystem _voxels; + + AvatarVoxelSystem _voxels; // private methods... glm::vec3 caclulateAverageEyePosition() { return _head.caclulateAverageEyePosition(); } // get the position smack-dab between the eyes (for lookat) diff --git a/interface/src/AvatarVoxelSystem.cpp b/interface/src/AvatarVoxelSystem.cpp new file mode 100644 index 0000000000..79f3f113b9 --- /dev/null +++ b/interface/src/AvatarVoxelSystem.cpp @@ -0,0 +1,97 @@ +// +// AvatarVoxelSystem.cpp +// interface +// +// Created by Andrzej Kapolka on 5/31/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. + +#include + +#include "AvatarVoxelSystem.h" + +const float AVATAR_TREE_SCALE = 1.0f; +const int MAX_VOXELS_PER_AVATAR = 2000; +const int BONE_INDEX_ELEMENTS_PER_VOXEL = 4 * VERTICES_PER_VOXEL; +const int BONE_WEIGHT_ELEMENTS_PER_VOXEL = 4 * VERTICES_PER_VOXEL; + +AvatarVoxelSystem::AvatarVoxelSystem() : VoxelSystem(AVATAR_TREE_SCALE, MAX_VOXELS_PER_AVATAR) { +} + +AvatarVoxelSystem::~AvatarVoxelSystem() { + delete[] _readBoneIndicesArray; + delete[] _readBoneWeightsArray; + delete[] _writeBoneIndicesArray; + delete[] _writeBoneWeightsArray; +} + +void AvatarVoxelSystem::init() { + VoxelSystem::init(); + + // prep the data structures for incoming voxel data + _writeBoneIndicesArray = new GLubyte[BONE_INDEX_ELEMENTS_PER_VOXEL * _maxVoxels]; + _readBoneIndicesArray = new GLubyte[BONE_INDEX_ELEMENTS_PER_VOXEL * _maxVoxels]; + + _writeBoneWeightsArray = new GLfloat[BONE_WEIGHT_ELEMENTS_PER_VOXEL * _maxVoxels]; + _readBoneWeightsArray = new GLfloat[BONE_WEIGHT_ELEMENTS_PER_VOXEL * _maxVoxels]; + + // VBO for the boneIndicesArray + glGenBuffers(1, &_vboBoneIndicesID); + glBindBuffer(GL_ARRAY_BUFFER, _vboBoneIndicesID); + glBufferData(GL_ARRAY_BUFFER, BONE_INDEX_ELEMENTS_PER_VOXEL * sizeof(GLubyte) * _maxVoxels, NULL, GL_DYNAMIC_DRAW); + + // VBO for the boneWeightsArray + glGenBuffers(1, &_vboBoneWeightsID); + glBindBuffer(GL_ARRAY_BUFFER, _vboBoneWeightsID); + glBufferData(GL_ARRAY_BUFFER, BONE_WEIGHT_ELEMENTS_PER_VOXEL * sizeof(GLfloat) * _maxVoxels, NULL, GL_DYNAMIC_DRAW); +} + +void AvatarVoxelSystem::render(bool texture) { + VoxelSystem::render(texture); +} + +void AvatarVoxelSystem::updateNodeInArrays(glBufferIndex nodeIndex, const glm::vec3& startVertex, + float voxelScale, const nodeColor& color) { + VoxelSystem::updateNodeInArrays(nodeIndex, startVertex, voxelScale, color); + + for (int j = 0; j < BONE_INDEX_ELEMENTS_PER_VOXEL; j++) { + GLubyte* writeBoneIndicesAt = _writeBoneIndicesArray + (nodeIndex * BONE_INDEX_ELEMENTS_PER_VOXEL); + GLfloat* writeBoneWeightsAt = _writeBoneWeightsArray + (nodeIndex * BONE_WEIGHT_ELEMENTS_PER_VOXEL); + *(writeBoneIndicesAt + j) = 0; + *(writeBoneWeightsAt + j) = 0.0f; + } +} + +void AvatarVoxelSystem::copyWrittenDataSegmentToReadArrays(glBufferIndex segmentStart, glBufferIndex segmentEnd) { + VoxelSystem::copyWrittenDataSegmentToReadArrays(segmentStart, segmentEnd); + + int segmentLength = (segmentEnd - segmentStart) + 1; + GLintptr segmentStartAt = segmentStart * BONE_INDEX_ELEMENTS_PER_VOXEL * sizeof(GLubyte); + GLsizeiptr segmentSizeBytes = segmentLength * BONE_INDEX_ELEMENTS_PER_VOXEL * sizeof(GLubyte); + GLubyte* readBoneIndicesAt = _readBoneIndicesArray + (segmentStart * BONE_INDEX_ELEMENTS_PER_VOXEL); + GLubyte* writeBoneIndicesAt = _writeBoneIndicesArray + (segmentStart * BONE_INDEX_ELEMENTS_PER_VOXEL); + memcpy(readBoneIndicesAt, writeBoneIndicesAt, segmentSizeBytes); + + segmentStartAt = segmentStart * BONE_WEIGHT_ELEMENTS_PER_VOXEL * sizeof(GLfloat); + segmentSizeBytes = segmentLength * BONE_WEIGHT_ELEMENTS_PER_VOXEL * sizeof(GLfloat); + GLfloat* readBoneWeightsAt = _readBoneWeightsArray + (segmentStart * BONE_WEIGHT_ELEMENTS_PER_VOXEL); + GLfloat* writeBoneWeightsAt = _writeBoneWeightsArray + (segmentStart * BONE_WEIGHT_ELEMENTS_PER_VOXEL); + memcpy(readBoneWeightsAt, writeBoneWeightsAt, segmentSizeBytes); +} + +void AvatarVoxelSystem::updateVBOSegment(glBufferIndex segmentStart, glBufferIndex segmentEnd) { + VoxelSystem::updateVBOSegment(segmentStart, segmentEnd); + + int segmentLength = (segmentEnd - segmentStart) + 1; + GLintptr segmentStartAt = segmentStart * BONE_INDEX_ELEMENTS_PER_VOXEL * sizeof(GLubyte); + GLsizeiptr segmentSizeBytes = segmentLength * BONE_INDEX_ELEMENTS_PER_VOXEL * sizeof(GLubyte); + GLubyte* readBoneIndicesFrom = _readBoneIndicesArray + (segmentStart * BONE_INDEX_ELEMENTS_PER_VOXEL); + glBindBuffer(GL_ARRAY_BUFFER, _vboBoneIndicesID); + glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readBoneIndicesFrom); + + segmentStartAt = segmentStart * BONE_WEIGHT_ELEMENTS_PER_VOXEL * sizeof(GLfloat); + segmentSizeBytes = segmentLength * BONE_WEIGHT_ELEMENTS_PER_VOXEL * sizeof(GLfloat); + GLfloat* readBoneWeightsFrom = _readBoneWeightsArray + (segmentStart * BONE_WEIGHT_ELEMENTS_PER_VOXEL); + glBindBuffer(GL_ARRAY_BUFFER, _vboBoneWeightsID); + glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readBoneWeightsFrom); +} + diff --git a/interface/src/AvatarVoxelSystem.h b/interface/src/AvatarVoxelSystem.h new file mode 100644 index 0000000000..d129e046b9 --- /dev/null +++ b/interface/src/AvatarVoxelSystem.h @@ -0,0 +1,43 @@ +// +// AvatarVoxelSystem.h +// interface +// +// Created by Andrzej Kapolka on 5/31/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#ifndef __interface__AvatarVoxelSystem__ +#define __interface__AvatarVoxelSystem__ + +#include "VoxelSystem.h" + +class AvatarVoxelSystem : public VoxelSystem { +public: + + AvatarVoxelSystem(); + virtual ~AvatarVoxelSystem(); + + virtual void init(); + virtual void render(bool texture); + +protected: + + virtual void updateNodeInArrays(glBufferIndex nodeIndex, const glm::vec3& startVertex, + float voxelScale, const nodeColor& color); + virtual void copyWrittenDataSegmentToReadArrays(glBufferIndex segmentStart, glBufferIndex segmentEnd); + virtual void updateVBOSegment(glBufferIndex segmentStart, glBufferIndex segmentEnd); + +private: + + GLubyte* _readBoneIndicesArray; + GLfloat* _readBoneWeightsArray; + GLubyte* _writeBoneIndicesArray; + GLfloat* _writeBoneWeightsArray; + + GLuint _vboBoneIndicesID; + GLuint _vboBoneWeightsID; + + ProgramObject* _skinProgram; +}; + +#endif /* defined(__interface__AvatarVoxelSystem__) */ diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index b4202511e6..7f5a926d28 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -231,10 +231,8 @@ void VoxelSystem::cleanupRemovedVoxels() { } void VoxelSystem::copyWrittenDataToReadArraysFullVBOs() { - int bytesOfVertices = (_voxelsInWriteArrays * VERTEX_POINTS_PER_VOXEL) * sizeof(GLfloat); - int bytesOfColors = (_voxelsInWriteArrays * VERTEX_POINTS_PER_VOXEL) * sizeof(GLubyte); - memcpy(_readVerticesArray, _writeVerticesArray, bytesOfVertices); - memcpy(_readColorsArray, _writeColorsArray, bytesOfColors ); + copyWrittenDataSegmentToReadArrays(0, _voxelsInWriteArrays - 1); + _voxelsInReadArrays = _voxelsInWriteArrays; // clear our dirty flags @@ -261,47 +259,37 @@ void VoxelSystem::copyWrittenDataToReadArraysPartialVBOs() { if (!thisVoxelDirty) { // If we got here because because this voxel is NOT dirty, so the last dirty voxel was the one before // this one and so that's where the "segment" ends - segmentEnd = i - 1; + copyWrittenDataSegmentToReadArrays(segmentStart, i - 1); inSegment = false; - int segmentLength = (segmentEnd - segmentStart) + 1; - - GLintptr segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); - GLsizeiptr segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); - GLfloat* readVerticesAt = _readVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); - GLfloat* writeVerticesAt = _writeVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); - memcpy(readVerticesAt, writeVerticesAt, segmentSizeBytes); - - segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); - segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); - GLubyte* readColorsAt = _readColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); - GLubyte* writeColorsAt = _writeColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); - memcpy(readColorsAt, writeColorsAt, segmentSizeBytes); } } } // if we got to the end of the array, and we're in an active dirty segment... if (inSegment) { - segmentEnd = _voxelsInWriteArrays - 1; - int segmentLength = (segmentEnd - segmentStart) + 1; - - GLintptr segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); - GLsizeiptr segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); - GLfloat* readVerticesAt = _readVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); - GLfloat* writeVerticesAt = _writeVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); - memcpy(readVerticesAt, writeVerticesAt, segmentSizeBytes); - - segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); - segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); - GLubyte* readColorsAt = _readColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); - GLubyte* writeColorsAt = _writeColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); - memcpy(readColorsAt, writeColorsAt, segmentSizeBytes); + copyWrittenDataSegmentToReadArrays(segmentStart, _voxelsInWriteArrays - 1); } // update our length _voxelsInReadArrays = _voxelsInWriteArrays; } +void VoxelSystem::copyWrittenDataSegmentToReadArrays(glBufferIndex segmentStart, glBufferIndex segmentEnd) { + int segmentLength = (segmentEnd - segmentStart) + 1; + + GLintptr segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); + GLsizeiptr segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); + GLfloat* readVerticesAt = _readVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); + GLfloat* writeVerticesAt = _writeVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); + memcpy(readVerticesAt, writeVerticesAt, segmentSizeBytes); + + segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); + segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); + GLubyte* readColorsAt = _readColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); + GLubyte* writeColorsAt = _writeColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); + memcpy(readColorsAt, writeColorsAt, segmentSizeBytes); +} + void VoxelSystem::copyWrittenDataToReadArrays(bool fullVBOs) { PerformanceWarning warn(_renderWarningsOn, "copyWrittenDataToReadArrays()"); if (_voxelsDirty && _voxelsUpdated) { @@ -364,12 +352,7 @@ int VoxelSystem::updateNodeInArraysAsFullVBO(VoxelNode* node) { // populate the array with points for the 8 vertices // and RGB color for each added vertex - for (int j = 0; j < VERTEX_POINTS_PER_VOXEL; j++ ) { - GLfloat* writeVerticesAt = _writeVerticesArray + (nodeIndex * VERTEX_POINTS_PER_VOXEL); - GLubyte* writeColorsAt = _writeColorsArray + (nodeIndex * VERTEX_POINTS_PER_VOXEL); - *(writeVerticesAt+j) = startVertex[j % 3] + (identityVertices[j] * voxelScale); - *(writeColorsAt +j) = node->getColor()[j % 3]; - } + updateNodeInArrays(nodeIndex, startVertex, voxelScale, node->getColor()); node->setBufferIndex(nodeIndex); _writeVoxelDirtyArray[nodeIndex] = true; // just in case we switch to Partial mode _voxelsInWriteArrays++; // our know vertices in the arrays @@ -415,17 +398,23 @@ int VoxelSystem::updateNodeInArraysAsPartialVBO(VoxelNode* node) { // populate the array with points for the 8 vertices // and RGB color for each added vertex - for (int j = 0; j < VERTEX_POINTS_PER_VOXEL; j++ ) { - GLfloat* writeVerticesAt = _writeVerticesArray + (nodeIndex * VERTEX_POINTS_PER_VOXEL); - GLubyte* writeColorsAt = _writeColorsArray + (nodeIndex * VERTEX_POINTS_PER_VOXEL); - *(writeVerticesAt+j) = startVertex[j % 3] + (identityVertices[j] * voxelScale); - *(writeColorsAt +j) = node->getColor()[j % 3]; - } + updateNodeInArrays(nodeIndex, startVertex, voxelScale, node->getColor()); + return 1; // updated! } return 0; // not-updated } +void VoxelSystem::updateNodeInArrays(glBufferIndex nodeIndex, const glm::vec3& startVertex, + float voxelScale, const nodeColor& color) { + for (int j = 0; j < VERTEX_POINTS_PER_VOXEL; j++ ) { + GLfloat* writeVerticesAt = _writeVerticesArray + (nodeIndex * VERTEX_POINTS_PER_VOXEL); + GLubyte* writeColorsAt = _writeColorsArray + (nodeIndex * VERTEX_POINTS_PER_VOXEL); + *(writeVerticesAt+j) = startVertex[j % 3] + (identityVertices[j] * voxelScale); + *(writeColorsAt +j) = color[j % 3]; + } +} + ProgramObject* VoxelSystem::_perlinModulateProgram = 0; GLuint VoxelSystem::_permutationNormalTextureID = 0; @@ -546,20 +535,7 @@ void VoxelSystem::init() { } void VoxelSystem::updateFullVBOs() { - glBufferIndex segmentStart = 0; - glBufferIndex segmentEnd = _voxelsInReadArrays; - - int segmentLength = (segmentEnd - segmentStart) + 1; - GLintptr segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); - GLsizeiptr segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); - GLfloat* readVerticesFrom = _readVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); - glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID); - glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readVerticesFrom); - segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); - segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); - GLubyte* readColorsFrom = _readColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); - glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); - glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readColorsFrom); + updateVBOSegment(0, _voxelsInReadArrays); // consider the _readVoxelDirtyArray[] clean! memset(_readVoxelDirtyArray, false, _voxelsInReadArrays * sizeof(bool)); @@ -581,39 +557,17 @@ void VoxelSystem::updatePartialVBOs() { if (!thisVoxelDirty) { // If we got here because because this voxel is NOT dirty, so the last dirty voxel was the one before // this one and so that's where the "segment" ends - segmentEnd = i - 1; + updateVBOSegment(segmentStart, i - 1); inSegment = false; - int segmentLength = (segmentEnd - segmentStart) + 1; - GLintptr segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); - GLsizeiptr segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); - GLfloat* readVerticesFrom = _readVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); - glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID); - glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readVerticesFrom); - segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); - segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); - GLubyte* readColorsFrom = _readColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); - glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); - glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readColorsFrom); } _readVoxelDirtyArray[i] = false; // consider us clean! } } // if we got to the end of the array, and we're in an active dirty segment... - if (inSegment) { - segmentEnd = _voxelsInReadArrays - 1; + if (inSegment) { + updateVBOSegment(segmentStart, _voxelsInReadArrays - 1); inSegment = false; - int segmentLength = (segmentEnd - segmentStart) + 1; - GLintptr segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); - GLsizeiptr segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); - GLfloat* readVerticesFrom = _readVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); - glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID); - glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readVerticesFrom); - segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); - segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); - GLubyte* readColorsFrom = _readColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); - glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); - glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readColorsFrom); } } @@ -635,6 +589,20 @@ void VoxelSystem::updateVBOs() { _callsToTreesToArrays = 0; // clear it } +void VoxelSystem::updateVBOSegment(glBufferIndex segmentStart, glBufferIndex segmentEnd) { + int segmentLength = (segmentEnd - segmentStart) + 1; + GLintptr segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); + GLsizeiptr segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); + GLfloat* readVerticesFrom = _readVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); + glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID); + glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readVerticesFrom); + segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); + segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); + GLubyte* readColorsFrom = _readColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); + glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); + glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readColorsFrom); +} + void VoxelSystem::render(bool texture) { PerformanceWarning warn(_renderWarningsOn, "render()"); diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index de904bb64f..a7824d8326 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -31,11 +31,9 @@ public: int parseData(unsigned char* sourceBuffer, int numBytes); - void setViewFrustum(ViewFrustum* viewFrustum) { _viewFrustum = viewFrustum; }; - - void init(); + virtual void init(); void simulate(float deltaTime) { }; - void render(bool texture); + virtual void render(bool texture); unsigned long getVoxelsUpdated() const {return _voxelsUpdated;}; unsigned long getVoxelsRendered() const {return _voxelsInReadArrays;}; @@ -80,6 +78,16 @@ public: void createLine(glm::vec3 point1, glm::vec3 point2, float unitSize, rgbColor color, bool destructive = false); void createSphere(float r,float xc, float yc, float zc, float s, bool solid, creationMode mode, bool destructive = false, bool debug = false); + +protected: + + int _maxVoxels; + + virtual void updateNodeInArrays(glBufferIndex nodeIndex, const glm::vec3& startVertex, + float voxelScale, const nodeColor& color); + virtual void copyWrittenDataSegmentToReadArrays(glBufferIndex segmentStart, glBufferIndex segmentEnd); + virtual void updateVBOSegment(glBufferIndex segmentStart, glBufferIndex segmentEnd); + private: // disallow copying of VoxelSystem objects VoxelSystem(const VoxelSystem&); @@ -107,12 +115,13 @@ private: void copyWrittenDataToReadArraysFullVBOs(); void copyWrittenDataToReadArraysPartialVBOs(); + void updateVBOs(); + // these are kinda hacks, used by getDistanceFromViewRangeOperation() probably shouldn't be here static float _maxDistance; static float _minDistance; - float _treeScale; - int _maxVoxels; + float _treeScale; VoxelTree* _tree; GLfloat* _readVerticesArray; GLubyte* _readColorsArray; @@ -121,8 +130,8 @@ private: bool* _writeVoxelDirtyArray; bool* _readVoxelDirtyArray; unsigned long _voxelsUpdated; - unsigned long _voxelsInWriteArrays; unsigned long _voxelsInReadArrays; + unsigned long _voxelsInWriteArrays; unsigned long _unusedArraySpace; bool _writeRenderFullVBO; @@ -140,7 +149,6 @@ private: pthread_mutex_t _bufferWriteLock; pthread_mutex_t _treeLock; - ViewFrustum* _viewFrustum; ViewFrustum _lastKnowViewFrustum; ViewFrustum _lastStableViewFrustum; @@ -149,17 +157,14 @@ private: void setupNewVoxelsForDrawing(); void copyWrittenDataToReadArrays(bool fullVBOs); + + void updateFullVBOs(); // all voxels in the VBO + void updatePartialVBOs(); // multiple segments, only dirty voxels bool _voxelsDirty; static ProgramObject* _perlinModulateProgram; static GLuint _permutationNormalTextureID; - -public: - void updateVBOs(); - void updateFullVBOs(); // all voxels in the VBO - void updatePartialVBOs(); // multiple segments, only dirty voxels - }; #endif From 6c975f9c6fe2a95a9225909de722721290637f2e Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Sat, 1 Jun 2013 15:06:29 -0700 Subject: [PATCH 03/10] More work on avatar voxels. --- interface/resources/shaders/skin_voxels.vert | 34 +++++++++++ interface/src/Avatar.cpp | 3 +- interface/src/AvatarVoxelSystem.cpp | 64 +++++++++++++++++--- interface/src/AvatarVoxelSystem.h | 13 +++- interface/src/VoxelSystem.cpp | 24 +++++--- interface/src/VoxelSystem.h | 2 + 6 files changed, 121 insertions(+), 19 deletions(-) create mode 100644 interface/resources/shaders/skin_voxels.vert diff --git a/interface/resources/shaders/skin_voxels.vert b/interface/resources/shaders/skin_voxels.vert new file mode 100644 index 0000000000..c63b2e1b31 --- /dev/null +++ b/interface/resources/shaders/skin_voxels.vert @@ -0,0 +1,34 @@ +#version 120 + +// +// skin_voxels.vert +// vertex shader +// +// Created by Andrzej Kapolka on 5/31/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +const int MAX_BONES = 32; +const int INDICES_PER_VERTEX = 4; + +uniform mat4 boneMatrices[MAX_BONES]; + +attribute vec4 boneIndices; +attribute vec4 boneWeights; + +void main(void) { + vec4 position = vec4(0.0, 0.0, 0.0, 0.0); + vec4 normal = vec4(0.0, 0.0, 0.0, 0.0); + for (int i = 0; i < INDICES_PER_VERTEX; i++) { + mat4 boneMatrix = boneMatrices[int(boneIndices[i])]; + float boneWeight = boneWeights[i]; + position += boneMatrix * gl_Vertex * boneWeight; + normal += boneMatrix * vec4(gl_Normal, 0.0) * boneWeight; + } + position = gl_ModelViewProjectionMatrix * position; + normal = normalize(gl_ModelViewMatrix * normal); + + gl_FrontColor = gl_Color * (gl_LightModel.ambient + gl_LightSource[0].ambient + + gl_LightSource[0].diffuse * max(0.0, dot(normal, gl_LightSource[0].position))); + gl_Position = position; +} diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 7198c0030c..6ee8cefb55 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -88,7 +88,8 @@ Avatar::Avatar(Agent* owningAgent) : _mouseRayDirection(0.0f, 0.0f, 0.0f), _interactingOther(NULL), _cumulativeMouseYaw(0.0f), - _isMouseTurningRight(false) + _isMouseTurningRight(false), + _voxels(this) { // give the pointer to our head to inherited _headData variable from AvatarData diff --git a/interface/src/AvatarVoxelSystem.cpp b/interface/src/AvatarVoxelSystem.cpp index 79f3f113b9..dcea2816ec 100644 --- a/interface/src/AvatarVoxelSystem.cpp +++ b/interface/src/AvatarVoxelSystem.cpp @@ -8,13 +8,18 @@ #include #include "AvatarVoxelSystem.h" +#include "renderer/ProgramObject.h" const float AVATAR_TREE_SCALE = 1.0f; const int MAX_VOXELS_PER_AVATAR = 2000; -const int BONE_INDEX_ELEMENTS_PER_VOXEL = 4 * VERTICES_PER_VOXEL; -const int BONE_WEIGHT_ELEMENTS_PER_VOXEL = 4 * VERTICES_PER_VOXEL; +const int BONE_INDEX_ELEMENTS_PER_VERTEX = 4; +const int BONE_INDEX_ELEMENTS_PER_VOXEL = BONE_INDEX_ELEMENTS_PER_VERTEX * VERTICES_PER_VOXEL; +const int BONE_WEIGHT_ELEMENTS_PER_VERTEX = 4; +const int BONE_WEIGHT_ELEMENTS_PER_VOXEL = BONE_WEIGHT_ELEMENTS_PER_VERTEX * VERTICES_PER_VOXEL; -AvatarVoxelSystem::AvatarVoxelSystem() : VoxelSystem(AVATAR_TREE_SCALE, MAX_VOXELS_PER_AVATAR) { +AvatarVoxelSystem::AvatarVoxelSystem(Avatar* avatar) : + VoxelSystem(AVATAR_TREE_SCALE, MAX_VOXELS_PER_AVATAR), + _avatar(avatar) { } AvatarVoxelSystem::~AvatarVoxelSystem() { @@ -24,6 +29,11 @@ AvatarVoxelSystem::~AvatarVoxelSystem() { delete[] _writeBoneWeightsArray; } +ProgramObject* AvatarVoxelSystem::_skinProgram = 0; +int AvatarVoxelSystem::_boneMatricesLocation; +int AvatarVoxelSystem::_boneIndicesLocation; +int AvatarVoxelSystem::_boneWeightsLocation; + void AvatarVoxelSystem::init() { VoxelSystem::init(); @@ -43,6 +53,18 @@ void AvatarVoxelSystem::init() { glGenBuffers(1, &_vboBoneWeightsID); glBindBuffer(GL_ARRAY_BUFFER, _vboBoneWeightsID); glBufferData(GL_ARRAY_BUFFER, BONE_WEIGHT_ELEMENTS_PER_VOXEL * sizeof(GLfloat) * _maxVoxels, NULL, GL_DYNAMIC_DRAW); + + // load our skin program if this is the first avatar system to initialize + if (_skinProgram != 0) { + return; + } + _skinProgram = new ProgramObject(); + _skinProgram->addShaderFromSourceFile(QGLShader::Vertex, "resources/shaders/skin_voxels.vert"); + _skinProgram->link(); + + _boneMatricesLocation = _skinProgram->uniformLocation("boneMatrices"); + _boneIndicesLocation = _skinProgram->attributeLocation("boneIndices"); + _boneWeightsLocation = _skinProgram->attributeLocation("boneWeights"); } void AvatarVoxelSystem::render(bool texture) { @@ -53,11 +75,15 @@ void AvatarVoxelSystem::updateNodeInArrays(glBufferIndex nodeIndex, const glm::v float voxelScale, const nodeColor& color) { VoxelSystem::updateNodeInArrays(nodeIndex, startVertex, voxelScale, color); - for (int j = 0; j < BONE_INDEX_ELEMENTS_PER_VOXEL; j++) { - GLubyte* writeBoneIndicesAt = _writeBoneIndicesArray + (nodeIndex * BONE_INDEX_ELEMENTS_PER_VOXEL); - GLfloat* writeBoneWeightsAt = _writeBoneWeightsArray + (nodeIndex * BONE_WEIGHT_ELEMENTS_PER_VOXEL); - *(writeBoneIndicesAt + j) = 0; - *(writeBoneWeightsAt + j) = 0.0f; + GLubyte* writeBoneIndicesAt = _writeBoneIndicesArray + (nodeIndex * BONE_INDEX_ELEMENTS_PER_VOXEL); + GLfloat* writeBoneWeightsAt = _writeBoneWeightsArray + (nodeIndex * BONE_WEIGHT_ELEMENTS_PER_VOXEL); + for (int i = 0; i < VERTICES_PER_VOXEL; i++) { + GLubyte boneIndices[] = { 0, 0, 0, 0}; + glm::vec4 boneWeights = glm::vec4(1.0f, 0.0f, 0.0f, 0.0f); + for (int j = 0; j < BONE_INDEX_ELEMENTS_PER_VERTEX; j++) { + *(writeBoneIndicesAt + i * BONE_INDEX_ELEMENTS_PER_VERTEX + j) = boneIndices[j]; + *(writeBoneWeightsAt + i * BONE_WEIGHT_ELEMENTS_PER_VERTEX + j) = boneWeights[j]; + } } } @@ -95,3 +121,25 @@ void AvatarVoxelSystem::updateVBOSegment(glBufferIndex segmentStart, glBufferInd glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readBoneWeightsFrom); } +void AvatarVoxelSystem::bindProgram(bool texture) { + _skinProgram->bind(); + + QMatrix4x4 boneMatrices[1]; + + _skinProgram->setUniformValueArray(_boneMatricesLocation, boneMatrices, sizeof(boneMatrices) / sizeof(boneMatrices[0])); + + glBindBuffer(GL_ARRAY_BUFFER, _vboBoneIndicesID); + _skinProgram->setAttributeBuffer(_boneIndicesLocation, GL_UNSIGNED_BYTE, 0, BONE_INDEX_ELEMENTS_PER_VERTEX); + _skinProgram->enableAttributeArray(_boneIndicesLocation); + + glBindBuffer(GL_ARRAY_BUFFER, _vboBoneWeightsID); + _skinProgram->setAttributeBuffer(_boneWeightsLocation, GL_FLOAT, 0, BONE_WEIGHT_ELEMENTS_PER_VERTEX); + _skinProgram->enableAttributeArray(_boneWeightsLocation); +} + +void AvatarVoxelSystem::releaseProgram(bool texture) { + _skinProgram->release(); + _skinProgram->disableAttributeArray(_boneIndicesLocation); + _skinProgram->disableAttributeArray(_boneWeightsLocation); +} + diff --git a/interface/src/AvatarVoxelSystem.h b/interface/src/AvatarVoxelSystem.h index d129e046b9..1b28a1a60d 100644 --- a/interface/src/AvatarVoxelSystem.h +++ b/interface/src/AvatarVoxelSystem.h @@ -11,10 +11,12 @@ #include "VoxelSystem.h" +class Avatar; + class AvatarVoxelSystem : public VoxelSystem { public: - AvatarVoxelSystem(); + AvatarVoxelSystem(Avatar* avatar); virtual ~AvatarVoxelSystem(); virtual void init(); @@ -26,9 +28,13 @@ protected: float voxelScale, const nodeColor& color); virtual void copyWrittenDataSegmentToReadArrays(glBufferIndex segmentStart, glBufferIndex segmentEnd); virtual void updateVBOSegment(glBufferIndex segmentStart, glBufferIndex segmentEnd); + virtual void bindProgram(bool texture); + virtual void releaseProgram(bool texture); private: + Avatar* _avatar; + GLubyte* _readBoneIndicesArray; GLfloat* _readBoneWeightsArray; GLubyte* _writeBoneIndicesArray; @@ -37,7 +43,10 @@ private: GLuint _vboBoneIndicesID; GLuint _vboBoneWeightsID; - ProgramObject* _skinProgram; + static ProgramObject* _skinProgram; + static int _boneMatricesLocation; + static int _boneIndicesLocation; + static int _boneWeightsLocation; }; #endif /* defined(__interface__AvatarVoxelSystem__) */ diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 7f5a926d28..c2d3de8da1 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -625,10 +625,7 @@ void VoxelSystem::render(bool texture) { glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); glColorPointer(3, GL_UNSIGNED_BYTE, 0, 0); - if (texture) { - _perlinModulateProgram->bind(); - glBindTexture(GL_TEXTURE_2D, _permutationNormalTextureID); - } + bindProgram(texture); // for performance, disable blending and enable backface culling glDisable(GL_BLEND); @@ -643,10 +640,7 @@ void VoxelSystem::render(bool texture) { glEnable(GL_BLEND); glDisable(GL_CULL_FACE); - if (texture) { - _perlinModulateProgram->release(); - glBindTexture(GL_TEXTURE_2D, 0); - } + releaseProgram(texture); // deactivate vertex and color arrays after drawing glDisableClientState(GL_VERTEX_ARRAY); @@ -663,6 +657,20 @@ void VoxelSystem::render(bool texture) { pthread_mutex_unlock(&_bufferWriteLock); } +void VoxelSystem::bindProgram(bool texture) { + if (texture) { + _perlinModulateProgram->bind(); + glBindTexture(GL_TEXTURE_2D, _permutationNormalTextureID); + } +} + +void VoxelSystem::releaseProgram(bool texture) { + if (texture) { + _perlinModulateProgram->release(); + glBindTexture(GL_TEXTURE_2D, 0); + } +} + int VoxelSystem::_nodeCount = 0; void VoxelSystem::killLocalVoxels() { diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index a7824d8326..8c9337bbe5 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -87,6 +87,8 @@ protected: float voxelScale, const nodeColor& color); virtual void copyWrittenDataSegmentToReadArrays(glBufferIndex segmentStart, glBufferIndex segmentEnd); virtual void updateVBOSegment(glBufferIndex segmentStart, glBufferIndex segmentEnd); + virtual void bindProgram(bool texture); + virtual void releaseProgram(bool texture); private: // disallow copying of VoxelSystem objects From 8d757e148fb5007b0f12a50c7e794fe78262ae52 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Sun, 2 Jun 2013 19:55:51 -0700 Subject: [PATCH 04/10] More work on voxeltars; basic skinning works. --- interface/src/Avatar.cpp | 19 ++-- interface/src/Avatar.h | 8 +- interface/src/AvatarVoxelSystem.cpp | 141 ++++++++++++++++++++-------- interface/src/AvatarVoxelSystem.h | 9 +- interface/src/Skeleton.cpp | 13 ++- interface/src/Skeleton.h | 11 ++- interface/src/VoxelSystem.cpp | 25 +++-- interface/src/VoxelSystem.h | 15 +-- 8 files changed, 168 insertions(+), 73 deletions(-) diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 62de224e99..2250bda751 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -172,8 +172,6 @@ Avatar::~Avatar() { void Avatar::init() { _voxels.init(); - - _voxels.createVoxel(0.0f, 0.0f, 0.0f, 1.0f, 255, 0, 255); } void Avatar::reset() { @@ -953,8 +951,11 @@ void Avatar::updateBodyBalls(float deltaTime) { } */ - //update position by velocity... + // update position by velocity... _bodyBall[b].position += _bodyBall[b].velocity * deltaTime; + + // update rotation + _bodyBall[b].rotation = _skeleton.joint[b].rotation; } } @@ -1016,14 +1017,7 @@ void Avatar::renderBody(bool lookingInMirror) { const float RENDER_TRANSLUCENT_BEYOND = 0.5f; // Render the body's voxels - glPushMatrix(); - const glm::vec3& voxelPosition = _joint[AVATAR_JOINT_PELVIS].springyPosition; - glTranslatef(voxelPosition.x, voxelPosition.y, voxelPosition.z); - glm::quat rotation = getOrientation(); - glm::vec3 axis = glm::axis(rotation); - glRotatef(glm::angle(rotation), axis.x, axis.y, axis.z); _voxels.render(false); - glPopMatrix(); // Render the body as balls and cones for (int b = 0; b < NUM_AVATAR_JOINTS; b++) { @@ -1130,6 +1124,11 @@ void Avatar::setHeadFromGyros(glm::vec3* eulerAngles, glm::vec3* angularVelocity } } +void Avatar::getBodyBallTransform(AvatarJointID jointID, glm::vec3& position, glm::quat& rotation) const { + position = _bodyBall[jointID].position; + rotation = _bodyBall[jointID].rotation; +} + void Avatar::writeAvatarDataToFile() { Application::getInstance()->setSetting("avatarPos", _position); Application::getInstance()->setSetting("avatarRotation", glm::vec3(_bodyYaw, _bodyPitch, _bodyRoll)); diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h index 4fff0bdc40..c7561d3986 100644 --- a/interface/src/Avatar.h +++ b/interface/src/Avatar.h @@ -66,7 +66,7 @@ public: void setOrientation (const glm::quat& orientation); //getters - + const Skeleton& getSkeleton () const { return _skeleton;} float getHeadYawRate () const { return _head.yawRate;} float getBodyYaw () const { return _bodyYaw;} bool getIsNearInteractingOther() const { return _avatarTouch.getAbleToReachOtherAvatar();} @@ -97,6 +97,9 @@ public: void addThrust(glm::vec3 newThrust) { _thrust += newThrust; }; glm::vec3 getThrust() { return _thrust; }; + // Get the position/rotation of a single body ball + void getBodyBallTransform(AvatarJointID jointID, glm::vec3& position, glm::quat& rotation) const; + //read/write avatar data void writeAvatarDataToFile(); void readAvatarDataFromFile(); @@ -108,7 +111,8 @@ private: struct AvatarBall { - glm::vec3 position; + glm::vec3 position; + glm::quat rotation; glm::vec3 velocity; float jointTightness; float radius; diff --git a/interface/src/AvatarVoxelSystem.cpp b/interface/src/AvatarVoxelSystem.cpp index dcea2816ec..50c8ca8a71 100644 --- a/interface/src/AvatarVoxelSystem.cpp +++ b/interface/src/AvatarVoxelSystem.cpp @@ -7,15 +7,15 @@ #include +#include + +#include "Avatar.h" #include "AvatarVoxelSystem.h" #include "renderer/ProgramObject.h" const float AVATAR_TREE_SCALE = 1.0f; const int MAX_VOXELS_PER_AVATAR = 2000; -const int BONE_INDEX_ELEMENTS_PER_VERTEX = 4; -const int BONE_INDEX_ELEMENTS_PER_VOXEL = BONE_INDEX_ELEMENTS_PER_VERTEX * VERTICES_PER_VOXEL; -const int BONE_WEIGHT_ELEMENTS_PER_VERTEX = 4; -const int BONE_WEIGHT_ELEMENTS_PER_VOXEL = BONE_WEIGHT_ELEMENTS_PER_VERTEX * VERTICES_PER_VOXEL; +const int BONE_ELEMENTS_PER_VOXEL = BONE_ELEMENTS_PER_VERTEX * VERTICES_PER_VOXEL; AvatarVoxelSystem::AvatarVoxelSystem(Avatar* avatar) : VoxelSystem(AVATAR_TREE_SCALE, MAX_VOXELS_PER_AVATAR), @@ -38,21 +38,31 @@ void AvatarVoxelSystem::init() { VoxelSystem::init(); // prep the data structures for incoming voxel data - _writeBoneIndicesArray = new GLubyte[BONE_INDEX_ELEMENTS_PER_VOXEL * _maxVoxels]; - _readBoneIndicesArray = new GLubyte[BONE_INDEX_ELEMENTS_PER_VOXEL * _maxVoxels]; + _writeBoneIndicesArray = new GLubyte[BONE_ELEMENTS_PER_VOXEL * _maxVoxels]; + _readBoneIndicesArray = new GLubyte[BONE_ELEMENTS_PER_VOXEL * _maxVoxels]; - _writeBoneWeightsArray = new GLfloat[BONE_WEIGHT_ELEMENTS_PER_VOXEL * _maxVoxels]; - _readBoneWeightsArray = new GLfloat[BONE_WEIGHT_ELEMENTS_PER_VOXEL * _maxVoxels]; + _writeBoneWeightsArray = new GLfloat[BONE_ELEMENTS_PER_VOXEL * _maxVoxels]; + _readBoneWeightsArray = new GLfloat[BONE_ELEMENTS_PER_VOXEL * _maxVoxels]; // VBO for the boneIndicesArray glGenBuffers(1, &_vboBoneIndicesID); glBindBuffer(GL_ARRAY_BUFFER, _vboBoneIndicesID); - glBufferData(GL_ARRAY_BUFFER, BONE_INDEX_ELEMENTS_PER_VOXEL * sizeof(GLubyte) * _maxVoxels, NULL, GL_DYNAMIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, BONE_ELEMENTS_PER_VOXEL * sizeof(GLubyte) * _maxVoxels, NULL, GL_DYNAMIC_DRAW); // VBO for the boneWeightsArray glGenBuffers(1, &_vboBoneWeightsID); glBindBuffer(GL_ARRAY_BUFFER, _vboBoneWeightsID); - glBufferData(GL_ARRAY_BUFFER, BONE_WEIGHT_ELEMENTS_PER_VOXEL * sizeof(GLfloat) * _maxVoxels, NULL, GL_DYNAMIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, BONE_ELEMENTS_PER_VOXEL * sizeof(GLfloat) * _maxVoxels, NULL, GL_DYNAMIC_DRAW); + + for (int i = 0; i < 150; i++) { + int power = pow(2, randIntInRange(6, 8)); + float size = 1.0f / power; + _tree->createVoxel( + randIntInRange(0, power - 1) * size, + randIntInRange(0, power - 1) * size, + randIntInRange(0, power - 1) * size, size, 255, 0, 255, true); + } + setupNewVoxelsForDrawing(); // load our skin program if this is the first avatar system to initialize if (_skinProgram != 0) { @@ -75,14 +85,15 @@ void AvatarVoxelSystem::updateNodeInArrays(glBufferIndex nodeIndex, const glm::v float voxelScale, const nodeColor& color) { VoxelSystem::updateNodeInArrays(nodeIndex, startVertex, voxelScale, color); - GLubyte* writeBoneIndicesAt = _writeBoneIndicesArray + (nodeIndex * BONE_INDEX_ELEMENTS_PER_VOXEL); - GLfloat* writeBoneWeightsAt = _writeBoneWeightsArray + (nodeIndex * BONE_WEIGHT_ELEMENTS_PER_VOXEL); + GLubyte* writeBoneIndicesAt = _writeBoneIndicesArray + (nodeIndex * BONE_ELEMENTS_PER_VOXEL); + GLfloat* writeBoneWeightsAt = _writeBoneWeightsArray + (nodeIndex * BONE_ELEMENTS_PER_VOXEL); for (int i = 0; i < VERTICES_PER_VOXEL; i++) { - GLubyte boneIndices[] = { 0, 0, 0, 0}; - glm::vec4 boneWeights = glm::vec4(1.0f, 0.0f, 0.0f, 0.0f); - for (int j = 0; j < BONE_INDEX_ELEMENTS_PER_VERTEX; j++) { - *(writeBoneIndicesAt + i * BONE_INDEX_ELEMENTS_PER_VERTEX + j) = boneIndices[j]; - *(writeBoneWeightsAt + i * BONE_WEIGHT_ELEMENTS_PER_VERTEX + j) = boneWeights[j]; + BoneIndices boneIndices; + glm::vec4 boneWeights; + computeBoneIndicesAndWeights(computeVoxelVertex(startVertex, voxelScale, i), boneIndices, boneWeights); + for (int j = 0; j < BONE_ELEMENTS_PER_VERTEX; j++) { + *(writeBoneIndicesAt + i * BONE_ELEMENTS_PER_VERTEX + j) = boneIndices[j]; + *(writeBoneWeightsAt + i * BONE_ELEMENTS_PER_VERTEX + j) = boneWeights[j]; } } } @@ -91,16 +102,16 @@ void AvatarVoxelSystem::copyWrittenDataSegmentToReadArrays(glBufferIndex segment VoxelSystem::copyWrittenDataSegmentToReadArrays(segmentStart, segmentEnd); int segmentLength = (segmentEnd - segmentStart) + 1; - GLintptr segmentStartAt = segmentStart * BONE_INDEX_ELEMENTS_PER_VOXEL * sizeof(GLubyte); - GLsizeiptr segmentSizeBytes = segmentLength * BONE_INDEX_ELEMENTS_PER_VOXEL * sizeof(GLubyte); - GLubyte* readBoneIndicesAt = _readBoneIndicesArray + (segmentStart * BONE_INDEX_ELEMENTS_PER_VOXEL); - GLubyte* writeBoneIndicesAt = _writeBoneIndicesArray + (segmentStart * BONE_INDEX_ELEMENTS_PER_VOXEL); + GLintptr segmentStartAt = segmentStart * BONE_ELEMENTS_PER_VOXEL * sizeof(GLubyte); + GLsizeiptr segmentSizeBytes = segmentLength * BONE_ELEMENTS_PER_VOXEL * sizeof(GLubyte); + GLubyte* readBoneIndicesAt = _readBoneIndicesArray + (segmentStart * BONE_ELEMENTS_PER_VOXEL); + GLubyte* writeBoneIndicesAt = _writeBoneIndicesArray + (segmentStart * BONE_ELEMENTS_PER_VOXEL); memcpy(readBoneIndicesAt, writeBoneIndicesAt, segmentSizeBytes); - segmentStartAt = segmentStart * BONE_WEIGHT_ELEMENTS_PER_VOXEL * sizeof(GLfloat); - segmentSizeBytes = segmentLength * BONE_WEIGHT_ELEMENTS_PER_VOXEL * sizeof(GLfloat); - GLfloat* readBoneWeightsAt = _readBoneWeightsArray + (segmentStart * BONE_WEIGHT_ELEMENTS_PER_VOXEL); - GLfloat* writeBoneWeightsAt = _writeBoneWeightsArray + (segmentStart * BONE_WEIGHT_ELEMENTS_PER_VOXEL); + segmentStartAt = segmentStart * BONE_ELEMENTS_PER_VOXEL * sizeof(GLfloat); + segmentSizeBytes = segmentLength * BONE_ELEMENTS_PER_VOXEL * sizeof(GLfloat); + GLfloat* readBoneWeightsAt = _readBoneWeightsArray + (segmentStart * BONE_ELEMENTS_PER_VOXEL); + GLfloat* writeBoneWeightsAt = _writeBoneWeightsArray + (segmentStart * BONE_ELEMENTS_PER_VOXEL); memcpy(readBoneWeightsAt, writeBoneWeightsAt, segmentSizeBytes); } @@ -108,38 +119,94 @@ void AvatarVoxelSystem::updateVBOSegment(glBufferIndex segmentStart, glBufferInd VoxelSystem::updateVBOSegment(segmentStart, segmentEnd); int segmentLength = (segmentEnd - segmentStart) + 1; - GLintptr segmentStartAt = segmentStart * BONE_INDEX_ELEMENTS_PER_VOXEL * sizeof(GLubyte); - GLsizeiptr segmentSizeBytes = segmentLength * BONE_INDEX_ELEMENTS_PER_VOXEL * sizeof(GLubyte); - GLubyte* readBoneIndicesFrom = _readBoneIndicesArray + (segmentStart * BONE_INDEX_ELEMENTS_PER_VOXEL); + GLintptr segmentStartAt = segmentStart * BONE_ELEMENTS_PER_VOXEL * sizeof(GLubyte); + GLsizeiptr segmentSizeBytes = segmentLength * BONE_ELEMENTS_PER_VOXEL * sizeof(GLubyte); + GLubyte* readBoneIndicesFrom = _readBoneIndicesArray + (segmentStart * BONE_ELEMENTS_PER_VOXEL); glBindBuffer(GL_ARRAY_BUFFER, _vboBoneIndicesID); glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readBoneIndicesFrom); - segmentStartAt = segmentStart * BONE_WEIGHT_ELEMENTS_PER_VOXEL * sizeof(GLfloat); - segmentSizeBytes = segmentLength * BONE_WEIGHT_ELEMENTS_PER_VOXEL * sizeof(GLfloat); - GLfloat* readBoneWeightsFrom = _readBoneWeightsArray + (segmentStart * BONE_WEIGHT_ELEMENTS_PER_VOXEL); + segmentStartAt = segmentStart * BONE_ELEMENTS_PER_VOXEL * sizeof(GLfloat); + segmentSizeBytes = segmentLength * BONE_ELEMENTS_PER_VOXEL * sizeof(GLfloat); + GLfloat* readBoneWeightsFrom = _readBoneWeightsArray + (segmentStart * BONE_ELEMENTS_PER_VOXEL); glBindBuffer(GL_ARRAY_BUFFER, _vboBoneWeightsID); glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readBoneWeightsFrom); } -void AvatarVoxelSystem::bindProgram(bool texture) { +void AvatarVoxelSystem::applyScaleAndBindProgram(bool texture) { _skinProgram->bind(); - QMatrix4x4 boneMatrices[1]; + // the base matrix includes centering and scale + QMatrix4x4 baseMatrix; + baseMatrix.scale(_treeScale); + baseMatrix.translate(-0.5f, -0.5f, -0.5f); - _skinProgram->setUniformValueArray(_boneMatricesLocation, boneMatrices, sizeof(boneMatrices) / sizeof(boneMatrices[0])); + // bone matrices include joint transforms + QMatrix4x4 boneMatrices[NUM_AVATAR_JOINTS]; + for (int i = 0; i < NUM_AVATAR_JOINTS; i++) { + glm::vec3 position; + glm::quat orientation; + _avatar->getBodyBallTransform((AvatarJointID)i, position, orientation); + boneMatrices[i].translate(position.x, position.y, position.z); + boneMatrices[i].rotate(QQuaternion(orientation.w, orientation.x, orientation.y, orientation.z)); + const glm::vec3& defaultPosition = _avatar->getSkeleton().joint[i].absoluteDefaultPosePosition; + boneMatrices[i].translate(-defaultPosition.x, -defaultPosition.y, -defaultPosition.z); + boneMatrices[i] *= baseMatrix; + } + _skinProgram->setUniformValueArray(_boneMatricesLocation, boneMatrices, NUM_AVATAR_JOINTS); glBindBuffer(GL_ARRAY_BUFFER, _vboBoneIndicesID); - _skinProgram->setAttributeBuffer(_boneIndicesLocation, GL_UNSIGNED_BYTE, 0, BONE_INDEX_ELEMENTS_PER_VERTEX); + glVertexAttribPointer(_boneIndicesLocation, BONE_ELEMENTS_PER_VERTEX, GL_UNSIGNED_BYTE, false, 0, 0); _skinProgram->enableAttributeArray(_boneIndicesLocation); glBindBuffer(GL_ARRAY_BUFFER, _vboBoneWeightsID); - _skinProgram->setAttributeBuffer(_boneWeightsLocation, GL_FLOAT, 0, BONE_WEIGHT_ELEMENTS_PER_VERTEX); + _skinProgram->setAttributeBuffer(_boneWeightsLocation, GL_FLOAT, 0, BONE_ELEMENTS_PER_VERTEX); _skinProgram->enableAttributeArray(_boneWeightsLocation); } -void AvatarVoxelSystem::releaseProgram(bool texture) { +void AvatarVoxelSystem::removeScaleAndReleaseProgram(bool texture) { _skinProgram->release(); _skinProgram->disableAttributeArray(_boneIndicesLocation); _skinProgram->disableAttributeArray(_boneWeightsLocation); } +class IndexDistance { +public: + IndexDistance(GLubyte index = 0, float distance = FLT_MAX) : index(index), distance(distance) { } + + GLubyte index; + float distance; +}; + +void AvatarVoxelSystem::computeBoneIndicesAndWeights(const glm::vec3& vertex, BoneIndices& indices, glm::vec4& weights) const { + // transform into joint space + glm::vec3 jointVertex = (vertex - glm::vec3(0.5f, 0.5f, 0.5f)) * AVATAR_TREE_SCALE; + + // find the nearest four joints (TODO: use a better data structure for the pose positions to speed this up) + IndexDistance nearest[BONE_ELEMENTS_PER_VERTEX]; + for (int i = 0; i < NUM_AVATAR_JOINTS; i++) { + float distance = glm::distance(jointVertex, _avatar->getSkeleton().joint[i].absoluteDefaultPosePosition); + for (int j = 0; j < BONE_ELEMENTS_PER_VERTEX; j++) { + if (distance < nearest[j].distance) { + // move the rest of the indices down + for (int k = BONE_ELEMENTS_PER_VERTEX - 1; k > j; k--) { + nearest[k] = nearest[k - 1]; + } + nearest[j] = IndexDistance(i, distance); + break; + } + } + } + + // compute the weights based on inverse distance + float totalWeight = 0.0f; + for (int i = 0; i < BONE_ELEMENTS_PER_VERTEX; i++) { + indices[i] = nearest[i].index; + weights[i] = (i == 0) ? 1.0f : 0.0f; // 1.0f / glm::max(nearest[i].distance, EPSILON); + totalWeight += weights[i]; + } + + // normalize the weights + for (int i = 0; i < BONE_ELEMENTS_PER_VERTEX; i++) { + weights[i] /= totalWeight; + } +} diff --git a/interface/src/AvatarVoxelSystem.h b/interface/src/AvatarVoxelSystem.h index 1b28a1a60d..e3a80c3817 100644 --- a/interface/src/AvatarVoxelSystem.h +++ b/interface/src/AvatarVoxelSystem.h @@ -11,6 +11,9 @@ #include "VoxelSystem.h" +const int BONE_ELEMENTS_PER_VERTEX = 4; +typedef GLubyte BoneIndices[BONE_ELEMENTS_PER_VERTEX]; + class Avatar; class AvatarVoxelSystem : public VoxelSystem { @@ -28,11 +31,13 @@ protected: float voxelScale, const nodeColor& color); virtual void copyWrittenDataSegmentToReadArrays(glBufferIndex segmentStart, glBufferIndex segmentEnd); virtual void updateVBOSegment(glBufferIndex segmentStart, glBufferIndex segmentEnd); - virtual void bindProgram(bool texture); - virtual void releaseProgram(bool texture); + virtual void applyScaleAndBindProgram(bool texture); + virtual void removeScaleAndReleaseProgram(bool texture); private: + void computeBoneIndicesAndWeights(const glm::vec3& vertex, BoneIndices& indices, glm::vec4& weights) const; + Avatar* _avatar; GLubyte* _readBoneIndicesArray; diff --git a/interface/src/Skeleton.cpp b/interface/src/Skeleton.cpp index 64a8645247..ae31810d8e 100644 --- a/interface/src/Skeleton.cpp +++ b/interface/src/Skeleton.cpp @@ -18,7 +18,7 @@ void Skeleton::initialize() { joint[b].parent = AVATAR_JOINT_NULL; joint[b].position = glm::vec3(0.0, 0.0, 0.0); joint[b].defaultPosePosition = glm::vec3(0.0, 0.0, 0.0); - joint[b].rotation = glm::quat(0.0f, 0.0f, 0.0f, 0.0f); + joint[b].rotation = glm::quat(1.0f, 0.0f, 0.0f, 0.0f); joint[b].length = 0.0; } @@ -77,9 +77,18 @@ void Skeleton::initialize() { joint[ AVATAR_JOINT_RIGHT_HEEL ].defaultPosePosition = glm::vec3( -0.01, -0.22, 0.08 ); joint[ AVATAR_JOINT_RIGHT_TOES ].defaultPosePosition = glm::vec3( 0.00, -0.03, -0.05 ); - // calculate bone length + // calculate bone length, absolute positions for (int b = 0; b < NUM_AVATAR_JOINTS; b++) { joint[b].length = glm::length(joint[b].defaultPosePosition); + + if (joint[b].parent == AVATAR_JOINT_NULL) { + joint[b].absoluteDefaultPosePosition = glm::vec3(0.0f, 0.0f, 0.0f); + } else { + joint[b].absoluteDefaultPosePosition = joint[ joint[b].parent ].absoluteDefaultPosePosition; + } + + glm::vec3 rotatedJointVector = joint[b].defaultPosePosition; + joint[b].absoluteDefaultPosePosition += rotatedJointVector; } } diff --git a/interface/src/Skeleton.h b/interface/src/Skeleton.h index 4c1152728d..5602dfc136 100644 --- a/interface/src/Skeleton.h +++ b/interface/src/Skeleton.h @@ -58,11 +58,12 @@ public: struct AvatarJoint { - AvatarJointID parent; // which joint is this joint connected to? - glm::vec3 position; // the position at the "end" of the joint - in global space - glm::vec3 defaultPosePosition; // the parent relative position when the avatar is in the "T-pose" - glm::quat rotation; // the parent-relative rotation (orientation) of the joint as a quaternion - float length; // the length of vector connecting the joint and its parent + AvatarJointID parent; // which joint is this joint connected to? + glm::vec3 position; // the position at the "end" of the joint - in global space + glm::vec3 defaultPosePosition; // the parent relative position when the avatar is in the "T-pose" + glm::vec3 absoluteDefaultPosePosition; // the absolute position when the avatar is in the "T-pose" + glm::quat rotation; // the parent-relative rotation (orientation) of the joint as a quaternion + float length; // the length of vector connecting the joint and its parent }; AvatarJoint joint[ NUM_AVATAR_JOINTS ]; diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index c2d3de8da1..dc2e06506f 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -415,6 +415,11 @@ void VoxelSystem::updateNodeInArrays(glBufferIndex nodeIndex, const glm::vec3& s } } +glm::vec3 VoxelSystem::computeVoxelVertex(const glm::vec3& startVertex, float voxelScale, int index) const { + const float* identityVertex = identityVertices + index * 3; + return startVertex + glm::vec3(identityVertex[0], identityVertex[1], identityVertex[2]) * voxelScale; +} + ProgramObject* VoxelSystem::_perlinModulateProgram = 0; GLuint VoxelSystem::_permutationNormalTextureID = 0; @@ -609,8 +614,8 @@ void VoxelSystem::render(bool texture) { // get the lock so that the update thread won't change anything pthread_mutex_lock(&_bufferWriteLock); - glPushMatrix(); updateVBOs(); + // tell OpenGL where to find vertex and color information glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); @@ -625,7 +630,7 @@ void VoxelSystem::render(bool texture) { glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); glColorPointer(3, GL_UNSIGNED_BYTE, 0, 0); - bindProgram(texture); + applyScaleAndBindProgram(texture); // for performance, disable blending and enable backface culling glDisable(GL_BLEND); @@ -633,14 +638,13 @@ void VoxelSystem::render(bool texture) { // draw the number of voxels we have glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesID); - glScalef(_treeScale, _treeScale, _treeScale); glDrawRangeElementsEXT(GL_TRIANGLES, 0, VERTICES_PER_VOXEL * _voxelsInReadArrays - 1, 36 * _voxelsInReadArrays, GL_UNSIGNED_INT, 0); glEnable(GL_BLEND); glDisable(GL_CULL_FACE); - releaseProgram(texture); + removeScaleAndReleaseProgram(texture); // deactivate vertex and color arrays after drawing glDisableClientState(GL_VERTEX_ARRAY); @@ -650,21 +654,24 @@ void VoxelSystem::render(bool texture) { // bind with 0 to switch back to normal operation glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - - // scale back down to 1 so heads aren't massive - glPopMatrix(); pthread_mutex_unlock(&_bufferWriteLock); } -void VoxelSystem::bindProgram(bool texture) { +void VoxelSystem::applyScaleAndBindProgram(bool texture) { + glPushMatrix(); + glScalef(_treeScale, _treeScale, _treeScale); + if (texture) { _perlinModulateProgram->bind(); glBindTexture(GL_TEXTURE_2D, _permutationNormalTextureID); } } -void VoxelSystem::releaseProgram(bool texture) { +void VoxelSystem::removeScaleAndReleaseProgram(bool texture) { + // scale back down to 1 so heads aren't massive + glPopMatrix(); + if (texture) { _perlinModulateProgram->release(); glBindTexture(GL_TEXTURE_2D, 0); diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index 8c9337bbe5..3a46e19517 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -81,14 +81,20 @@ public: protected: - int _maxVoxels; + float _treeScale; + int _maxVoxels; + VoxelTree* _tree; + + glm::vec3 computeVoxelVertex(const glm::vec3& startVertex, float voxelScale, int index) const; + + void setupNewVoxelsForDrawing(); virtual void updateNodeInArrays(glBufferIndex nodeIndex, const glm::vec3& startVertex, float voxelScale, const nodeColor& color); virtual void copyWrittenDataSegmentToReadArrays(glBufferIndex segmentStart, glBufferIndex segmentEnd); virtual void updateVBOSegment(glBufferIndex segmentStart, glBufferIndex segmentEnd); - virtual void bindProgram(bool texture); - virtual void releaseProgram(bool texture); + virtual void applyScaleAndBindProgram(bool texture); + virtual void removeScaleAndReleaseProgram(bool texture); private: // disallow copying of VoxelSystem objects @@ -123,8 +129,6 @@ private: static float _maxDistance; static float _minDistance; - float _treeScale; - VoxelTree* _tree; GLfloat* _readVerticesArray; GLubyte* _readColorsArray; GLfloat* _writeVerticesArray; @@ -157,7 +161,6 @@ private: int newTreeToArrays(VoxelNode *currentNode); void cleanupRemovedVoxels(); - void setupNewVoxelsForDrawing(); void copyWrittenDataToReadArrays(bool fullVBOs); void updateFullVBOs(); // all voxels in the VBO From a6daa296ffc47ea80a68e0b35e3fd3b20f008cb9 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 3 Jun 2013 10:08:42 -0700 Subject: [PATCH 05/10] Slight fix to capsule/box penetration test: we should use the smaller distance to the diagonal, not the first one we find. --- interface/src/AvatarVoxelSystem.cpp | 4 +--- libraries/voxels/src/AABox.cpp | 7 +++++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/interface/src/AvatarVoxelSystem.cpp b/interface/src/AvatarVoxelSystem.cpp index 50c8ca8a71..d6b51bec82 100644 --- a/interface/src/AvatarVoxelSystem.cpp +++ b/interface/src/AvatarVoxelSystem.cpp @@ -7,8 +7,6 @@ #include -#include - #include "Avatar.h" #include "AvatarVoxelSystem.h" #include "renderer/ProgramObject.h" @@ -201,7 +199,7 @@ void AvatarVoxelSystem::computeBoneIndicesAndWeights(const glm::vec3& vertex, Bo float totalWeight = 0.0f; for (int i = 0; i < BONE_ELEMENTS_PER_VERTEX; i++) { indices[i] = nearest[i].index; - weights[i] = (i == 0) ? 1.0f : 0.0f; // 1.0f / glm::max(nearest[i].distance, EPSILON); + weights[i] = 1.0f / glm::max(nearest[i].distance, EPSILON); totalWeight += weights[i]; } diff --git a/libraries/voxels/src/AABox.cpp b/libraries/voxels/src/AABox.cpp index b7580b243e..1b29c70b59 100644 --- a/libraries/voxels/src/AABox.cpp +++ b/libraries/voxels/src/AABox.cpp @@ -292,13 +292,16 @@ glm::vec3 AABox::getClosestPointOnFace(const glm::vec4& origin, const glm::vec4& glm::vec4 diagonals[] = { secondAxisMinPlane + thirdAxisMaxPlane + offset, secondAxisMaxPlane + thirdAxisMaxPlane + offset }; + float minDistance = FLT_MAX; for (int i = 0; i < sizeof(diagonals) / sizeof(diagonals[0]); i++) { float divisor = glm::dot(direction, diagonals[i]); if (fabs(divisor) < EPSILON) { continue; // segment is parallel to diagonal plane } - float directionalDistance = -glm::dot(origin, diagonals[i]) / divisor; - return getClosestPointOnFace(glm::vec3(origin + direction * directionalDistance), face); + minDistance = glm::min(-glm::dot(origin, diagonals[i]) / divisor, minDistance); + } + if (minDistance != FLT_MAX) { + return getClosestPointOnFace(glm::vec3(origin + direction * minDistance), face); } } From 73f8fca2afaa182d93d9a11e9510d6d8141e5891 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 3 Jun 2013 13:00:54 -0700 Subject: [PATCH 06/10] More work on voxeltars; added rotations. --- interface/src/Avatar.cpp | 8 +++- interface/src/AvatarVoxelSystem.cpp | 9 ++-- interface/src/Skeleton.cpp | 65 +++++++++++++-------------- interface/src/Skeleton.h | 68 +++++++++++++++-------------- interface/src/Util.cpp | 21 +++++++++ interface/src/Util.h | 2 + 6 files changed, 103 insertions(+), 70 deletions(-) diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 2250bda751..fa193d3a70 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -909,6 +909,8 @@ void Avatar::updateBodyBalls(float deltaTime) { if (glm::length(_position - _bodyBall[AVATAR_JOINT_PELVIS].position) > BEYOND_BODY_SPRING_RANGE) { resetBodyBalls(); } + glm::quat orientation = getOrientation(); + glm::vec3 jointDirection = orientation * JOINT_DIRECTION; for (int b = 0; b < NUM_AVATAR_JOINTS; b++) { glm::vec3 springVector(_bodyBall[b].position); @@ -955,7 +957,11 @@ void Avatar::updateBodyBalls(float deltaTime) { _bodyBall[b].position += _bodyBall[b].velocity * deltaTime; // update rotation - _bodyBall[b].rotation = _skeleton.joint[b].rotation; + if (_skeleton.joint[b].parent == AVATAR_JOINT_NULL || length < 0.1f) { + _bodyBall[b].rotation = orientation * _skeleton.joint[b].absoluteBindPoseRotation; + } else { + _bodyBall[b].rotation = rotationBetween(jointDirection, springVector) * orientation; + } } } diff --git a/interface/src/AvatarVoxelSystem.cpp b/interface/src/AvatarVoxelSystem.cpp index d6b51bec82..9e441c148c 100644 --- a/interface/src/AvatarVoxelSystem.cpp +++ b/interface/src/AvatarVoxelSystem.cpp @@ -144,10 +144,11 @@ void AvatarVoxelSystem::applyScaleAndBindProgram(bool texture) { glm::vec3 position; glm::quat orientation; _avatar->getBodyBallTransform((AvatarJointID)i, position, orientation); - boneMatrices[i].translate(position.x, position.y, position.z); + boneMatrices[i].translate(position.x, position.y, position.z); + orientation = orientation * glm::inverse(_avatar->getSkeleton().joint[i].absoluteBindPoseRotation); boneMatrices[i].rotate(QQuaternion(orientation.w, orientation.x, orientation.y, orientation.z)); - const glm::vec3& defaultPosition = _avatar->getSkeleton().joint[i].absoluteDefaultPosePosition; - boneMatrices[i].translate(-defaultPosition.x, -defaultPosition.y, -defaultPosition.z); + const glm::vec3& bindPosition = _avatar->getSkeleton().joint[i].absoluteBindPosePosition; + boneMatrices[i].translate(-bindPosition.x, -bindPosition.y, -bindPosition.z); boneMatrices[i] *= baseMatrix; } _skinProgram->setUniformValueArray(_boneMatricesLocation, boneMatrices, NUM_AVATAR_JOINTS); @@ -182,7 +183,7 @@ void AvatarVoxelSystem::computeBoneIndicesAndWeights(const glm::vec3& vertex, Bo // find the nearest four joints (TODO: use a better data structure for the pose positions to speed this up) IndexDistance nearest[BONE_ELEMENTS_PER_VERTEX]; for (int i = 0; i < NUM_AVATAR_JOINTS; i++) { - float distance = glm::distance(jointVertex, _avatar->getSkeleton().joint[i].absoluteDefaultPosePosition); + float distance = glm::distance(jointVertex, _avatar->getSkeleton().joint[i].absoluteBindPosePosition); for (int j = 0; j < BONE_ELEMENTS_PER_VERTEX; j++) { if (distance < nearest[j].distance) { // move the rest of the indices down diff --git a/interface/src/Skeleton.cpp b/interface/src/Skeleton.cpp index ae31810d8e..136cb6f619 100644 --- a/interface/src/Skeleton.cpp +++ b/interface/src/Skeleton.cpp @@ -5,6 +5,7 @@ // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. #include "Skeleton.h" +#include "Util.h" const float BODY_SPRING_DEFAULT_TIGHTNESS = 1000.0f; const float FLOATING_HEIGHT = 0.13f; @@ -17,7 +18,7 @@ void Skeleton::initialize() { for (int b=0; b 179.99f) { // 180 degree rotation; must use another axis + axis = glm::cross(v1, glm::vec3(1.0f, 0.0f, 0.0f)); + float axisLength = glm::length(axis); + if (axisLength < EPSILON) { // parallel to x; y will work + axis = glm::normalize(glm::cross(v1, glm::vec3(0.0f, 1.0f, 0.0f))); + } else { + axis /= axisLength; + } + } else { + axis = glm::normalize(glm::cross(v1, v2)); + } + return glm::angleAxis(angle, axis); +} + // Safe version of glm::eulerAngles; uses the factorization method described in David Eberly's // http://www.geometrictools.com/Documentation/EulerAngles.pdf (via Clyde, // https://github.com/threerings/clyde/blob/master/src/main/java/com/threerings/math/Quaternion.java) diff --git a/interface/src/Util.h b/interface/src/Util.h index 0823ac405b..0187d93da5 100644 --- a/interface/src/Util.h +++ b/interface/src/Util.h @@ -45,6 +45,8 @@ void drawVector(glm::vec3* vector); float angleBetween(const glm::vec3& v1, const glm::vec3& v2); +glm::quat rotationBetween(const glm::vec3& v1, const glm::vec3& v2); + glm::vec3 safeEulerAngles(const glm::quat& q); glm::quat safeMix(const glm::quat& q1, const glm::quat& q2, float alpha); From bc8eadd526b70b4e0ca624b8d541e9ae21efd140 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 4 Jun 2013 10:22:58 -0700 Subject: [PATCH 07/10] More work on voxeltars; separated default pose from bind pose. --- interface/CMakeLists.txt | 4 +- interface/src/Application.cpp | 44 ++++++++++++++++++-- interface/src/Application.h | 9 +++++ interface/src/Avatar.h | 2 + interface/src/AvatarVoxelSystem.cpp | 63 ++++++++++++++++++++++------- interface/src/AvatarVoxelSystem.h | 23 +++++++++-- interface/src/Skeleton.cpp | 61 ++++++++++++++++++++-------- interface/src/Skeleton.h | 1 + interface/src/VoxelSystem.h | 4 +- 9 files changed, 171 insertions(+), 40 deletions(-) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index d5da2073fb..b2984b35bb 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -63,12 +63,12 @@ if (APPLE) endif (APPLE) -find_package(Qt4 REQUIRED QtCore QtGui QtOpenGL) +find_package(Qt4 REQUIRED QtCore QtGui QtNetwork QtOpenGL) include(${QT_USE_FILE}) SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${QT_QTGUI_INCLUDE_DIR}") # run qt moc on qt-enabled headers -qt4_wrap_cpp(INTERFACE_SRCS src/Application.h) +qt4_wrap_cpp(INTERFACE_SRCS src/Application.h src/AvatarVoxelSystem.h) # create the executable, make it a bundle on OS X add_executable(${TARGET_NAME} MACOSX_BUNDLE ${INTERFACE_SRCS}) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e8aaaf9856..57f1b89969 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -21,16 +21,23 @@ #include #include +#include #include +#include #include +#include #include #include +#include #include #include #include +#include #include +#include #include #include +#include #include #include @@ -1122,6 +1129,31 @@ void Application::terminate() { } } +void Application::editPreferences() { + QDialog dialog(_glWidget); + dialog.setWindowTitle("Interface Preferences"); + QBoxLayout* layout = new QBoxLayout(QBoxLayout::TopToBottom); + dialog.setLayout(layout); + + QFormLayout* form = new QFormLayout(); + layout->addLayout(form, 1); + + QLineEdit* avatarURL = new QLineEdit(_settings->value("avatarURL").toString()); + form->addRow("Avatar URL:", avatarURL); + + QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + dialog.connect(buttons, SIGNAL(accepted()), SLOT(accept())); + dialog.connect(buttons, SIGNAL(rejected()), SLOT(reject())); + layout->addWidget(buttons); + + if (dialog.exec() != QDialog::Accepted) { + return; + } + QUrl url(avatarURL->text()); + _settings->setValue("avatarURL", url); + _myAvatar.getVoxels()->loadVoxelsFromURL(url); +} + void Application::pair() { PairingHandler::sendPairRequest(); } @@ -1285,6 +1317,9 @@ void Application::initMenu() { QMenu* fileMenu = menuBar->addMenu("File"); fileMenu->addAction("Quit", this, SLOT(quit()), Qt::CTRL | Qt::Key_Q); + QMenu* editMenu = menuBar->addMenu("Edit"); + editMenu->addAction("Preferences...", this, SLOT(editPreferences())); + QMenu* pairMenu = menuBar->addMenu("Pair"); pairMenu->addAction("Pair", this, SLOT(pair())); @@ -1325,9 +1360,7 @@ void Application::initMenu() { renderMenu->addAction("First Person", this, SLOT(setRenderFirstPerson(bool)), Qt::Key_P)->setCheckable(true); QMenu* toolsMenu = menuBar->addMenu("Tools"); - (_renderStatsOn = toolsMenu->addAction("Stats"))->setCheckable(true); - _renderStatsOn->setShortcut(Qt::Key_Slash); (_logOn = toolsMenu->addAction("Log"))->setCheckable(true); _logOn->setChecked(false); @@ -1381,6 +1414,9 @@ void Application::initMenu() { debugMenu->addAction("Wants Res-In", this, SLOT(setWantsResIn(bool)))->setCheckable(true); debugMenu->addAction("Wants Monochrome", this, SLOT(setWantsMonochrome(bool)))->setCheckable(true); debugMenu->addAction("Wants View Delta Sending", this, SLOT(setWantsDelta(bool)))->setCheckable(true); + + _networkAccessManager = new QNetworkAccessManager(this); + _settings = new QSettings("High Fidelity", "Interface", this); } void Application::updateFrustumRenderModeAction() { @@ -1431,6 +1467,8 @@ void Application::init() { _myCamera.setModeShiftRate(1.0f); _myAvatar.setDisplayingLookatVectors(false); + _myAvatar.getVoxels()->loadVoxelsFromURL(_settings->value("avatarURL").toUrl()); + QCursor::setPos(_headMouseX, _headMouseY); OculusManager::connect(); @@ -1727,7 +1765,7 @@ void Application::displayOculus(Camera& whichCamera) { glPopMatrix(); } - + void Application::displaySide(Camera& whichCamera) { // transform by eye offset diff --git a/interface/src/Application.h b/interface/src/Application.h index c2918f1add..1ed24683ae 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -37,6 +37,8 @@ class QGLWidget; class QKeyEvent; class QMainWindow; class QMouseEvent; +class QNetworkAccessManager; +class QSettings; class QWheelEvent; class Agent; @@ -70,6 +72,8 @@ public: Environment* getEnvironment() { return &_environment; } bool shouldEchoAudio() { return _echoAudioMode->isChecked(); } + QNetworkAccessManager* getNetworkAccessManager() { return _networkAccessManager; } + /*! @fn getSettingBool @brief A function for getting boolean settings from the settings file. @@ -127,6 +131,8 @@ private slots: void idle(); void terminate(); + void editPreferences(); + void pair(); void setHead(bool head); @@ -227,6 +233,9 @@ private: QAction* _fullScreenMode; // whether we are in full screen mode QAction* _frustumRenderModeAction; + QNetworkAccessManager* _networkAccessManager; + QSettings* _settings; + SerialInterface _serialPort; bool _displayLevels; diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h index c7561d3986..475fc0bc59 100644 --- a/interface/src/Avatar.h +++ b/interface/src/Avatar.h @@ -89,6 +89,8 @@ public: glm::quat getOrientation () const; glm::quat getWorldAlignedOrientation() const; + AvatarVoxelSystem* getVoxels() { return &_voxels; } + // Set what driving keys are being pressed to control thrust levels void setDriveKeys(int key, bool val) { _driveKeys[key] = val; }; bool getDriveKeys(int key) { return _driveKeys[key]; }; diff --git a/interface/src/AvatarVoxelSystem.cpp b/interface/src/AvatarVoxelSystem.cpp index 9e441c148c..5fdf974f71 100644 --- a/interface/src/AvatarVoxelSystem.cpp +++ b/interface/src/AvatarVoxelSystem.cpp @@ -7,6 +7,12 @@ #include +#include +#include + +#include + +#include "Application.h" #include "Avatar.h" #include "AvatarVoxelSystem.h" #include "renderer/ProgramObject.h" @@ -17,7 +23,7 @@ const int BONE_ELEMENTS_PER_VOXEL = BONE_ELEMENTS_PER_VERTEX * VERTICES_PER_VOXE AvatarVoxelSystem::AvatarVoxelSystem(Avatar* avatar) : VoxelSystem(AVATAR_TREE_SCALE, MAX_VOXELS_PER_AVATAR), - _avatar(avatar) { + _avatar(avatar), _voxelReply(0) { } AvatarVoxelSystem::~AvatarVoxelSystem() { @@ -52,16 +58,6 @@ void AvatarVoxelSystem::init() { glBindBuffer(GL_ARRAY_BUFFER, _vboBoneWeightsID); glBufferData(GL_ARRAY_BUFFER, BONE_ELEMENTS_PER_VOXEL * sizeof(GLfloat) * _maxVoxels, NULL, GL_DYNAMIC_DRAW); - for (int i = 0; i < 150; i++) { - int power = pow(2, randIntInRange(6, 8)); - float size = 1.0f / power; - _tree->createVoxel( - randIntInRange(0, power - 1) * size, - randIntInRange(0, power - 1) * size, - randIntInRange(0, power - 1) * size, size, 255, 0, 255, true); - } - setupNewVoxelsForDrawing(); - // load our skin program if this is the first avatar system to initialize if (_skinProgram != 0) { return; @@ -75,8 +71,25 @@ void AvatarVoxelSystem::init() { _boneWeightsLocation = _skinProgram->attributeLocation("boneWeights"); } -void AvatarVoxelSystem::render(bool texture) { - VoxelSystem::render(texture); +void AvatarVoxelSystem::removeOutOfView() { + // no-op for now +} + +void AvatarVoxelSystem::loadVoxelsFromURL(const QUrl& url) { + // cancel any current download + if (_voxelReply != 0) { + delete _voxelReply; + } + + killLocalVoxels(); + + // load the URL data asynchronously + if (!url.isValid()) { + return; + } + _voxelReply = Application::getInstance()->getNetworkAccessManager()->get(QNetworkRequest(url)); + connect(_voxelReply, SIGNAL(readyRead()), SLOT(readVoxelDataFromReply())); + connect(_voxelReply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(handleVoxelReplyError())); } void AvatarVoxelSystem::updateNodeInArrays(glBufferIndex nodeIndex, const glm::vec3& startVertex, @@ -168,6 +181,25 @@ void AvatarVoxelSystem::removeScaleAndReleaseProgram(bool texture) { _skinProgram->disableAttributeArray(_boneWeightsLocation); } +void AvatarVoxelSystem::readVoxelDataFromReply() { + // for now, just wait until we have the full business + if (!_voxelReply->isFinished()) { + return; + } + QByteArray entirety = _voxelReply->readAll(); + _voxelReply->deleteLater(); + _voxelReply = 0; + _tree->readBitstreamToTree((unsigned char*)entirety.data(), entirety.size(), WANT_COLOR, NO_EXISTS_BITS); + setupNewVoxelsForDrawing(); +} + +void AvatarVoxelSystem::handleVoxelReplyError() { + printLog("%s\n", _voxelReply->errorString().toAscii().constData()); + + _voxelReply->deleteLater(); + _voxelReply = 0; +} + class IndexDistance { public: IndexDistance(GLubyte index = 0, float distance = FLT_MAX) : index(index), distance(distance) { } @@ -183,7 +215,10 @@ void AvatarVoxelSystem::computeBoneIndicesAndWeights(const glm::vec3& vertex, Bo // find the nearest four joints (TODO: use a better data structure for the pose positions to speed this up) IndexDistance nearest[BONE_ELEMENTS_PER_VERTEX]; for (int i = 0; i < NUM_AVATAR_JOINTS; i++) { - float distance = glm::distance(jointVertex, _avatar->getSkeleton().joint[i].absoluteBindPosePosition); + AvatarJointID parent = _avatar->getSkeleton().joint[i].parent; + float distance = glm::length(computeVectorFromPointToSegment(jointVertex, + _avatar->getSkeleton().joint[parent == AVATAR_JOINT_NULL ? i : parent].absoluteBindPosePosition, + _avatar->getSkeleton().joint[i].absoluteBindPosePosition)); for (int j = 0; j < BONE_ELEMENTS_PER_VERTEX; j++) { if (distance < nearest[j].distance) { // move the rest of the indices down diff --git a/interface/src/AvatarVoxelSystem.h b/interface/src/AvatarVoxelSystem.h index e3a80c3817..edeeadb17c 100644 --- a/interface/src/AvatarVoxelSystem.h +++ b/interface/src/AvatarVoxelSystem.h @@ -9,22 +9,32 @@ #ifndef __interface__AvatarVoxelSystem__ #define __interface__AvatarVoxelSystem__ +#include + #include "VoxelSystem.h" const int BONE_ELEMENTS_PER_VERTEX = 4; typedef GLubyte BoneIndices[BONE_ELEMENTS_PER_VERTEX]; +class QNetworkReply; +class QUrl; + class Avatar; -class AvatarVoxelSystem : public VoxelSystem { +class AvatarVoxelSystem : public QObject, public VoxelSystem { + Q_OBJECT + public: - + AvatarVoxelSystem(Avatar* avatar); virtual ~AvatarVoxelSystem(); virtual void init(); - virtual void render(bool texture); + virtual void removeOutOfView(); + + void loadVoxelsFromURL(const QUrl& url); + protected: virtual void updateNodeInArrays(glBufferIndex nodeIndex, const glm::vec3& startVertex, @@ -33,6 +43,11 @@ protected: virtual void updateVBOSegment(glBufferIndex segmentStart, glBufferIndex segmentEnd); virtual void applyScaleAndBindProgram(bool texture); virtual void removeScaleAndReleaseProgram(bool texture); + +private slots: + + void readVoxelDataFromReply(); + void handleVoxelReplyError(); private: @@ -48,6 +63,8 @@ private: GLuint _vboBoneIndicesID; GLuint _vboBoneWeightsID; + QNetworkReply* _voxelReply; + static ProgramObject* _skinProgram; static int _boneMatricesLocation; static int _boneIndicesLocation; diff --git a/interface/src/Skeleton.cpp b/interface/src/Skeleton.cpp index 136cb6f619..a694b4032d 100644 --- a/interface/src/Skeleton.cpp +++ b/interface/src/Skeleton.cpp @@ -49,7 +49,7 @@ void Skeleton::initialize() { joint[ AVATAR_JOINT_RIGHT_HEEL ].parent = AVATAR_JOINT_RIGHT_KNEE; joint[ AVATAR_JOINT_RIGHT_TOES ].parent = AVATAR_JOINT_RIGHT_HEEL; - // specify the default pose position + // specify the bind pose position joint[ AVATAR_JOINT_PELVIS ].bindPosePosition = glm::vec3( 0.0, 0.0, 0.0 ); joint[ AVATAR_JOINT_TORSO ].bindPosePosition = glm::vec3( 0.0, 0.09, -0.01 ); joint[ AVATAR_JOINT_CHEST ].bindPosePosition = glm::vec3( 0.0, 0.09, -0.01 ); @@ -58,29 +58,58 @@ void Skeleton::initialize() { joint[ AVATAR_JOINT_LEFT_COLLAR ].bindPosePosition = glm::vec3( -0.06, 0.04, 0.01 ); joint[ AVATAR_JOINT_LEFT_SHOULDER ].bindPosePosition = glm::vec3( -0.05, 0.0, 0.01 ); - joint[ AVATAR_JOINT_LEFT_ELBOW ].bindPosePosition = glm::vec3( 0.0, -0.16, 0.0 ); - joint[ AVATAR_JOINT_LEFT_WRIST ].bindPosePosition = glm::vec3( 0.0, -0.117, 0.0 ); - joint[ AVATAR_JOINT_LEFT_FINGERTIPS ].bindPosePosition = glm::vec3( 0.0, -0.1, 0.0 ); + joint[ AVATAR_JOINT_LEFT_ELBOW ].bindPosePosition = glm::vec3( -0.16, 0.0, 0.0 ); + joint[ AVATAR_JOINT_LEFT_WRIST ].bindPosePosition = glm::vec3( -0.12, 0.0, 0.0 ); + joint[ AVATAR_JOINT_LEFT_FINGERTIPS ].bindPosePosition = glm::vec3( -0.1, 0.0, 0.0 ); joint[ AVATAR_JOINT_RIGHT_COLLAR ].bindPosePosition = glm::vec3( 0.06, 0.04, 0.01 ); joint[ AVATAR_JOINT_RIGHT_SHOULDER ].bindPosePosition = glm::vec3( 0.05, 0.0, 0.01 ); - joint[ AVATAR_JOINT_RIGHT_ELBOW ].bindPosePosition = glm::vec3( 0.0, -0.16, 0.0 ); - joint[ AVATAR_JOINT_RIGHT_WRIST ].bindPosePosition = glm::vec3( 0.0, -0.117, 0.0 ); - joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].bindPosePosition = glm::vec3( 0.0, -0.1, 0.0 ); + joint[ AVATAR_JOINT_RIGHT_ELBOW ].bindPosePosition = glm::vec3( 0.16, 0.0, 0.0 ); + joint[ AVATAR_JOINT_RIGHT_WRIST ].bindPosePosition = glm::vec3( 0.12, 0.0, 0.0 ); + joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].bindPosePosition = glm::vec3( 0.1, 0.0, 0.0 ); joint[ AVATAR_JOINT_LEFT_HIP ].bindPosePosition = glm::vec3( -0.05, 0.0, 0.02 ); - joint[ AVATAR_JOINT_LEFT_KNEE ].bindPosePosition = glm::vec3( 0.01, -0.25, -0.03 ); - joint[ AVATAR_JOINT_LEFT_HEEL ].bindPosePosition = glm::vec3( 0.01, -0.22, 0.08 ); - joint[ AVATAR_JOINT_LEFT_TOES ].bindPosePosition = glm::vec3( 0.00, -0.03, -0.05 ); + joint[ AVATAR_JOINT_LEFT_KNEE ].bindPosePosition = glm::vec3( 0.00, -0.25, 0.00 ); + joint[ AVATAR_JOINT_LEFT_HEEL ].bindPosePosition = glm::vec3( 0.00, -0.23, 0.00 ); + joint[ AVATAR_JOINT_LEFT_TOES ].bindPosePosition = glm::vec3( 0.00, 0.00, -0.06 ); joint[ AVATAR_JOINT_RIGHT_HIP ].bindPosePosition = glm::vec3( 0.05, 0.0, 0.02 ); - joint[ AVATAR_JOINT_RIGHT_KNEE ].bindPosePosition = glm::vec3( -0.01, -0.25, -0.03 ); - joint[ AVATAR_JOINT_RIGHT_HEEL ].bindPosePosition = glm::vec3( -0.01, -0.22, 0.08 ); - joint[ AVATAR_JOINT_RIGHT_TOES ].bindPosePosition = glm::vec3( 0.00, -0.03, -0.05 ); + joint[ AVATAR_JOINT_RIGHT_KNEE ].bindPosePosition = glm::vec3( 0.00, -0.25, 0.00 ); + joint[ AVATAR_JOINT_RIGHT_HEEL ].bindPosePosition = glm::vec3( 0.00, -0.23, 0.00 ); + joint[ AVATAR_JOINT_RIGHT_TOES ].bindPosePosition = glm::vec3( 0.00, 0.00, -0.06 ); + + // specify the default pose position + joint[ AVATAR_JOINT_PELVIS ].defaultPosePosition = glm::vec3( 0.0, 0.0, 0.0 ); + joint[ AVATAR_JOINT_TORSO ].defaultPosePosition = glm::vec3( 0.0, 0.09, -0.01 ); + joint[ AVATAR_JOINT_CHEST ].defaultPosePosition = glm::vec3( 0.0, 0.09, -0.01 ); + joint[ AVATAR_JOINT_NECK_BASE ].defaultPosePosition = glm::vec3( 0.0, 0.14, 0.01 ); + joint[ AVATAR_JOINT_HEAD_BASE ].defaultPosePosition = glm::vec3( 0.0, 0.04, 0.00 ); + + joint[ AVATAR_JOINT_LEFT_COLLAR ].defaultPosePosition = glm::vec3( -0.06, 0.04, 0.01 ); + joint[ AVATAR_JOINT_LEFT_SHOULDER ].defaultPosePosition = glm::vec3( -0.05, 0.0, 0.01 ); + joint[ AVATAR_JOINT_LEFT_ELBOW ].defaultPosePosition = glm::vec3( 0.0, -0.16, 0.0 ); + joint[ AVATAR_JOINT_LEFT_WRIST ].defaultPosePosition = glm::vec3( 0.0, -0.117, 0.0 ); + joint[ AVATAR_JOINT_LEFT_FINGERTIPS ].defaultPosePosition = glm::vec3( 0.0, -0.1, 0.0 ); + + joint[ AVATAR_JOINT_RIGHT_COLLAR ].defaultPosePosition = glm::vec3( 0.06, 0.04, 0.01 ); + joint[ AVATAR_JOINT_RIGHT_SHOULDER ].defaultPosePosition = glm::vec3( 0.05, 0.0, 0.01 ); + joint[ AVATAR_JOINT_RIGHT_ELBOW ].defaultPosePosition = glm::vec3( 0.0, -0.16, 0.0 ); + joint[ AVATAR_JOINT_RIGHT_WRIST ].defaultPosePosition = glm::vec3( 0.0, -0.117, 0.0 ); + joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].defaultPosePosition = glm::vec3( 0.0, -0.1, 0.0 ); + + joint[ AVATAR_JOINT_LEFT_HIP ].defaultPosePosition = glm::vec3( -0.05, 0.0, 0.02 ); + joint[ AVATAR_JOINT_LEFT_KNEE ].defaultPosePosition = glm::vec3( 0.01, -0.25, -0.03 ); + joint[ AVATAR_JOINT_LEFT_HEEL ].defaultPosePosition = glm::vec3( 0.01, -0.22, 0.08 ); + joint[ AVATAR_JOINT_LEFT_TOES ].defaultPosePosition = glm::vec3( 0.00, -0.03, -0.05 ); + + joint[ AVATAR_JOINT_RIGHT_HIP ].defaultPosePosition = glm::vec3( 0.05, 0.0, 0.02 ); + joint[ AVATAR_JOINT_RIGHT_KNEE ].defaultPosePosition = glm::vec3( -0.01, -0.25, -0.03 ); + joint[ AVATAR_JOINT_RIGHT_HEEL ].defaultPosePosition = glm::vec3( -0.01, -0.22, 0.08 ); + joint[ AVATAR_JOINT_RIGHT_TOES ].defaultPosePosition = glm::vec3( 0.00, -0.03, -0.05 ); - // calculate bone length, absolute positions/rotations + // calculate bone length, absolute bind positions/rotations for (int b = 0; b < NUM_AVATAR_JOINTS; b++) { - joint[b].length = glm::length(joint[b].bindPosePosition); + joint[b].length = glm::length(joint[b].defaultPosePosition); if (joint[b].parent == AVATAR_JOINT_NULL) { joint[b].absoluteBindPosePosition = joint[b].bindPosePosition; @@ -106,7 +135,7 @@ void Skeleton::update(float deltaTime, const glm::quat& orientation, glm::vec3 p joint[b].position = joint[ joint[b].parent ].position; } - glm::vec3 rotatedJointVector = joint[b].rotation * joint[b].bindPosePosition; + glm::vec3 rotatedJointVector = joint[b].rotation * joint[b].defaultPosePosition; joint[b].position += rotatedJointVector; } } diff --git a/interface/src/Skeleton.h b/interface/src/Skeleton.h index 78405b39ac..dd55c5fa68 100644 --- a/interface/src/Skeleton.h +++ b/interface/src/Skeleton.h @@ -61,6 +61,7 @@ public: { AvatarJointID parent; // which joint is this joint connected to? glm::vec3 position; // the position at the "end" of the joint - in global space + glm::vec3 defaultPosePosition; // the parent relative position when the avatar is in the default pose glm::vec3 bindPosePosition; // the parent relative position when the avatar is in the "T-pose" glm::vec3 absoluteBindPosePosition; // the absolute position when the avatar is in the "T-pose" glm::quat absoluteBindPoseRotation; // the absolute rotation when the avatar is in the "T-pose" diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index 3a46e19517..e310fdaf7c 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -33,7 +33,7 @@ public: virtual void init(); void simulate(float deltaTime) { }; - virtual void render(bool texture); + void render(bool texture); unsigned long getVoxelsUpdated() const {return _voxelsUpdated;}; unsigned long getVoxelsRendered() const {return _voxelsInReadArrays;}; @@ -59,7 +59,7 @@ public: void setRenderPipelineWarnings(bool on) { _renderWarningsOn = on; }; bool getRenderPipelineWarnings() const { return _renderWarningsOn; }; - void removeOutOfView(); + virtual void removeOutOfView(); bool hasViewChanged(); bool isViewChanging(); From 90a53bc5181ad246035fd812fc1d8cb95ca43a04 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 4 Jun 2013 10:40:08 -0700 Subject: [PATCH 08/10] Only bind vertices within an adjustable radius. --- interface/src/Avatar.cpp | 2 +- interface/src/AvatarVoxelSystem.cpp | 29 ++++++++++++++++++++++------- interface/src/Skeleton.cpp | 3 ++- interface/src/Skeleton.h | 1 + 4 files changed, 26 insertions(+), 9 deletions(-) diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index fa193d3a70..a563ff6fff 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -957,7 +957,7 @@ void Avatar::updateBodyBalls(float deltaTime) { _bodyBall[b].position += _bodyBall[b].velocity * deltaTime; // update rotation - if (_skeleton.joint[b].parent == AVATAR_JOINT_NULL || length < 0.1f) { + if (_skeleton.joint[b].parent == AVATAR_JOINT_NULL || length < EPSILON) { _bodyBall[b].rotation = orientation * _skeleton.joint[b].absoluteBindPoseRotation; } else { _bodyBall[b].rotation = rotationBetween(jointDirection, springVector) * orientation; diff --git a/interface/src/AvatarVoxelSystem.cpp b/interface/src/AvatarVoxelSystem.cpp index 5fdf974f71..2500c9b2d4 100644 --- a/interface/src/AvatarVoxelSystem.cpp +++ b/interface/src/AvatarVoxelSystem.cpp @@ -202,7 +202,7 @@ void AvatarVoxelSystem::handleVoxelReplyError() { class IndexDistance { public: - IndexDistance(GLubyte index = 0, float distance = FLT_MAX) : index(index), distance(distance) { } + IndexDistance(GLubyte index = AVATAR_JOINT_PELVIS, float distance = FLT_MAX) : index(index), distance(distance) { } GLubyte index; float distance; @@ -214,11 +214,15 @@ void AvatarVoxelSystem::computeBoneIndicesAndWeights(const glm::vec3& vertex, Bo // find the nearest four joints (TODO: use a better data structure for the pose positions to speed this up) IndexDistance nearest[BONE_ELEMENTS_PER_VERTEX]; + const Skeleton& skeleton = _avatar->getSkeleton(); for (int i = 0; i < NUM_AVATAR_JOINTS; i++) { - AvatarJointID parent = _avatar->getSkeleton().joint[i].parent; + AvatarJointID parent = skeleton.joint[i].parent; float distance = glm::length(computeVectorFromPointToSegment(jointVertex, - _avatar->getSkeleton().joint[parent == AVATAR_JOINT_NULL ? i : parent].absoluteBindPosePosition, - _avatar->getSkeleton().joint[i].absoluteBindPosePosition)); + skeleton.joint[parent == AVATAR_JOINT_NULL ? i : parent].absoluteBindPosePosition, + skeleton.joint[i].absoluteBindPosePosition)); + if (distance > skeleton.joint[i].bindRadius) { + continue; + } for (int j = 0; j < BONE_ELEMENTS_PER_VERTEX; j++) { if (distance < nearest[j].distance) { // move the rest of the indices down @@ -235,11 +239,22 @@ void AvatarVoxelSystem::computeBoneIndicesAndWeights(const glm::vec3& vertex, Bo float totalWeight = 0.0f; for (int i = 0; i < BONE_ELEMENTS_PER_VERTEX; i++) { indices[i] = nearest[i].index; - weights[i] = 1.0f / glm::max(nearest[i].distance, EPSILON); - totalWeight += weights[i]; + if (nearest[i].distance != FLT_MAX) { + weights[i] = 1.0f / glm::max(nearest[i].distance, EPSILON); + totalWeight += weights[i]; + + } else { + weights[i] = 0.0f; + } } - // normalize the weights + // if it's not attached to anything, consider it attached to the hip + if (totalWeight == 0.0f) { + weights[0] = 1.0f; + return; + } + + // ortherwise, normalize the weights for (int i = 0; i < BONE_ELEMENTS_PER_VERTEX; i++) { weights[i] /= totalWeight; } diff --git a/interface/src/Skeleton.cpp b/interface/src/Skeleton.cpp index a694b4032d..f22953a6c1 100644 --- a/interface/src/Skeleton.cpp +++ b/interface/src/Skeleton.cpp @@ -18,9 +18,10 @@ void Skeleton::initialize() { for (int b=0; b Date: Tue, 4 Jun 2013 15:52:39 -0700 Subject: [PATCH 09/10] Adjusted default bind radius, spring vector threshold. --- interface/src/Avatar.cpp | 3 ++- interface/src/Skeleton.cpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 61112c3403..4a3e8db2bc 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -1076,7 +1076,8 @@ void Avatar::updateBodyBalls(float deltaTime) { _bodyBall[b].position += _bodyBall[b].velocity * deltaTime; // update rotation - if (_skeleton.joint[b].parent == AVATAR_JOINT_NULL || length < EPSILON) { + const float SMALL_SPRING_LENGTH = 0.001f; // too-small springs can change direction rapidly + if (_skeleton.joint[b].parent == AVATAR_JOINT_NULL || length < SMALL_SPRING_LENGTH) { _bodyBall[b].rotation = orientation * _skeleton.joint[_bodyBall[b].parentJoint].absoluteBindPoseRotation; } else { _bodyBall[b].rotation = rotationBetween(jointDirection, springVector) * orientation; diff --git a/interface/src/Skeleton.cpp b/interface/src/Skeleton.cpp index 13092648a3..b3720c8869 100644 --- a/interface/src/Skeleton.cpp +++ b/interface/src/Skeleton.cpp @@ -21,7 +21,7 @@ void Skeleton::initialize() { joint[b].defaultPosePosition = glm::vec3(0.0, 0.0, 0.0); joint[b].rotation = glm::quat(1.0f, 0.0f, 0.0f, 0.0f); joint[b].length = 0.0; - joint[b].bindRadius = 1.0f / 16; + joint[b].bindRadius = 1.0f / 8; } // specify the parental hierarchy From 93b50f44f5a8ee791bebbba87a0f19aa1bd6a0c4 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 4 Jun 2013 15:59:07 -0700 Subject: [PATCH 10/10] Add a reasonable minimum size for the URL field. --- interface/src/Application.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 8aba8a613a..6f898ecae7 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1158,6 +1158,7 @@ void Application::editPreferences() { layout->addLayout(form, 1); QLineEdit* avatarURL = new QLineEdit(_settings->value("avatarURL").toString()); + avatarURL->setMinimumWidth(400); form->addRow("Avatar URL:", avatarURL); QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);