diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 9d7d2ae249..06974743f0 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -917,15 +917,10 @@ void Application::pair() { PairingHandler::sendPairRequest(); } -void Application::setHead(bool head) { +void Application::setRenderMirrored(bool head) { if (head) { - _myCamera.setMode(CAMERA_MODE_MIRROR); - _myCamera.setModeShiftRate(100.0f); _manualFirstPerson->setChecked(false); - - } else { - _myCamera.setMode(CAMERA_MODE_THIRD_PERSON); - _myCamera.setModeShiftRate(1.0f); + _manualThirdPerson->setChecked(false); } } @@ -940,8 +935,16 @@ void Application::setFullscreen(bool fullscreen) { } void Application::setRenderFirstPerson(bool firstPerson) { - if (firstPerson && _lookingInMirror->isChecked()) { - _lookingInMirror->trigger(); + if (firstPerson) { + _lookingInMirror->setChecked(false); + _manualThirdPerson->setChecked(false); + } +} + +void Application::setRenderThirdPerson(bool thirdPerson) { + if (thirdPerson) { + _lookingInMirror->setChecked(false); + _manualFirstPerson->setChecked(false); } } @@ -1242,7 +1245,7 @@ void Application::initMenu() { pairMenu->addAction("Pair", this, SLOT(pair())); QMenu* optionsMenu = menuBar->addMenu("Options"); - (_lookingInMirror = optionsMenu->addAction("Mirror", this, SLOT(setHead(bool)), Qt::Key_H))->setCheckable(true); + (_lookingInMirror = optionsMenu->addAction("Mirror", this, SLOT(setRenderMirrored(bool)), Qt::Key_H))->setCheckable(true); (_echoAudioMode = optionsMenu->addAction("Echo Audio"))->setCheckable(true); optionsMenu->addAction("Noise", this, SLOT(setNoise(bool)), Qt::Key_N)->setCheckable(true); @@ -1277,12 +1280,15 @@ void Application::initMenu() { _renderAvatarsOn->setChecked(true); (_renderAvatarBalls = renderMenu->addAction("Avatar as Balls"))->setCheckable(true); _renderAvatarBalls->setChecked(false); + renderMenu->addAction("Cycle Voxeltar Mode", _myAvatar.getVoxels(), SLOT(cycleMode())); (_renderFrameTimerOn = renderMenu->addAction("Show Timer"))->setCheckable(true); _renderFrameTimerOn->setChecked(false); (_renderLookatOn = renderMenu->addAction("Lookat Vectors"))->setCheckable(true); _renderLookatOn->setChecked(false); (_manualFirstPerson = renderMenu->addAction( "First Person", this, SLOT(setRenderFirstPerson(bool)), Qt::Key_P))->setCheckable(true); + (_manualThirdPerson = renderMenu->addAction( + "Third Person", this, SLOT(setRenderThirdPerson(bool))))->setCheckable(true); QMenu* toolsMenu = menuBar->addMenu("Tools"); (_renderStatsOn = toolsMenu->addAction("Stats"))->setCheckable(true); @@ -1420,7 +1426,7 @@ void Application::init() { _myAvatar.init(); _myAvatar.setPosition(START_LOCATION); - _myCamera.setMode(CAMERA_MODE_THIRD_PERSON ); + _myCamera.setMode(CAMERA_MODE_THIRD_PERSON); _myCamera.setModeShiftRate(1.0f); _myAvatar.setDisplayingLookatVectors(false); @@ -1619,25 +1625,35 @@ void Application::update(float deltaTime) { _myAvatar.simulate(deltaTime, NULL); } - if (_myCamera.getMode() != CAMERA_MODE_MIRROR && !OculusManager::isConnected()) { - if (_manualFirstPerson->isChecked()) { - if (_myCamera.getMode() != CAMERA_MODE_FIRST_PERSON ) { - _myCamera.setMode(CAMERA_MODE_FIRST_PERSON); - _myCamera.setModeShiftRate(1.0f); - } + if (!OculusManager::isConnected()) { + if (_lookingInMirror->isChecked()) { + if (_myCamera.getMode() != CAMERA_MODE_MIRROR) { + _myCamera.setMode(CAMERA_MODE_MIRROR); + _myCamera.setModeShiftRate(100.0f); + } + } else if (_manualFirstPerson->isChecked()) { + if (_myCamera.getMode() != CAMERA_MODE_FIRST_PERSON) { + _myCamera.setMode(CAMERA_MODE_FIRST_PERSON); + _myCamera.setModeShiftRate(1.0f); + } + } else if (_manualThirdPerson->isChecked()) { + if (_myCamera.getMode() != CAMERA_MODE_THIRD_PERSON) { + _myCamera.setMode(CAMERA_MODE_THIRD_PERSON); + _myCamera.setModeShiftRate(1.0f); + } } else { const float THIRD_PERSON_SHIFT_VELOCITY = 2.0f; const float TIME_BEFORE_SHIFT_INTO_FIRST_PERSON = 0.75f; const float TIME_BEFORE_SHIFT_INTO_THIRD_PERSON = 0.1f; if ((_myAvatar.getElapsedTimeStopped() > TIME_BEFORE_SHIFT_INTO_FIRST_PERSON) - && (_myCamera.getMode() != CAMERA_MODE_FIRST_PERSON)) { - _myCamera.setMode(CAMERA_MODE_FIRST_PERSON); - _myCamera.setModeShiftRate(1.0f); - } + && (_myCamera.getMode() != CAMERA_MODE_FIRST_PERSON)) { + _myCamera.setMode(CAMERA_MODE_FIRST_PERSON); + _myCamera.setModeShiftRate(1.0f); + } if ((_myAvatar.getSpeed() > THIRD_PERSON_SHIFT_VELOCITY) - && (_myAvatar.getElapsedTimeMoving() > TIME_BEFORE_SHIFT_INTO_THIRD_PERSON) - && (_myCamera.getMode() != CAMERA_MODE_THIRD_PERSON)) { + && (_myAvatar.getElapsedTimeMoving() > TIME_BEFORE_SHIFT_INTO_THIRD_PERSON) + && (_myCamera.getMode() != CAMERA_MODE_THIRD_PERSON)) { _myCamera.setMode(CAMERA_MODE_THIRD_PERSON); _myCamera.setModeShiftRate(1000.0f); } diff --git a/interface/src/Application.h b/interface/src/Application.h index b7211187de..705979c5e4 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -92,11 +92,12 @@ private slots: void pair(); - void setHead(bool head); + void setRenderMirrored(bool mirrored); void setNoise(bool noise); void setFullscreen(bool fullscreen); void setRenderFirstPerson(bool firstPerson); + void setRenderThirdPerson(bool thirdPerson); void renderThrustAtVoxel(const glm::vec3& thrust); void renderLineToTouchedVoxel(); @@ -196,6 +197,7 @@ private: QAction* _renderFrameTimerOn; // Whether to show onscreen text overlay with stats QAction* _renderLookatOn; // Whether to show lookat vectors from avatar eyes if looking at something QAction* _manualFirstPerson; // Whether to force first-person mode + QAction* _manualThirdPerson; // Whether to force third-person mode QAction* _logOn; // Whether to show on-screen log QActionGroup* _voxelModeActions; // The group of voxel edit mode actions QAction* _addVoxelMode; // Whether add voxel mode is enabled diff --git a/interface/src/AvatarVoxelSystem.cpp b/interface/src/AvatarVoxelSystem.cpp index dc3b937da9..4e21f2f140 100644 --- a/interface/src/AvatarVoxelSystem.cpp +++ b/interface/src/AvatarVoxelSystem.cpp @@ -22,7 +22,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), _voxelReply(0) { + _mode(0), _avatar(avatar), _voxelReply(0) { // we may have been created in the network thread, but we live in the main thread moveToThread(Application::getInstance()->thread()); @@ -77,6 +77,35 @@ void AvatarVoxelSystem::removeOutOfView() { // no-op for now } +class Mode { +public: + + bool bindVoxelsTogether; + int maxBonesPerBind; + bool includeBonesOutsideBindRadius; + bool ignoreOrientations; +}; + +const Mode MODES[] = { + { false, BONE_ELEMENTS_PER_VERTEX, false, false }, // original + { false, 1, true, false }, // one bone per vertex + { true, 1, true, false }, // one bone per voxel + { true, BONE_ELEMENTS_PER_VERTEX, false, false }, // four bones per voxel + { false, BONE_ELEMENTS_PER_VERTEX, false, true }, // no orientations + { false, 1, true, true }, // no orientations, one bone per vertex + { true, 1, true, true }, // no orientations, one bone per voxel + { true, BONE_ELEMENTS_PER_VERTEX, false, true } }; // no orientations, four bones per voxel + +void AvatarVoxelSystem::cycleMode() { + _mode = (_mode + 1) % (sizeof(MODES) / sizeof(MODES[0])); + printLog("Voxeltar bind mode %d.\n", _mode); + + // rebind + QUrl url = _voxelURL; + setVoxelURL(QUrl()); + setVoxelURL(url); +} + void AvatarVoxelSystem::setVoxelURL(const QUrl& url) { // don't restart the download if it's the same URL if (_voxelURL == url) { @@ -117,14 +146,28 @@ void AvatarVoxelSystem::updateNodeInArrays(glBufferIndex nodeIndex, const glm::v VoxelSystem::updateNodeInArrays(nodeIndex, startVertex, voxelScale, color); 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++) { + GLfloat* writeBoneWeightsAt = _writeBoneWeightsArray + (nodeIndex * BONE_ELEMENTS_PER_VOXEL); + + if (MODES[_mode].bindVoxelsTogether) { 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]; + computeBoneIndicesAndWeights(startVertex + glm::vec3(voxelScale, voxelScale, voxelScale) * 0.5f, + boneIndices, boneWeights); + for (int i = 0; i < VERTICES_PER_VOXEL; i++) { + 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]; + } + } + } else { + for (int i = 0; i < VERTICES_PER_VOXEL; i++) { + 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]; + } } } } @@ -177,8 +220,12 @@ 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); - orientation = orientation * glm::inverse(_avatar->getSkeleton().joint[i].absoluteBindPoseRotation); + boneMatrices[i].translate(position.x, position.y, position.z); + if (MODES[_mode].ignoreOrientations) { + orientation = _avatar->getOrientation(); + } else { + orientation = orientation * glm::inverse(_avatar->getSkeleton().joint[i].absoluteBindPoseRotation); + } boneMatrices[i].rotate(QQuaternion(orientation.w, orientation.x, orientation.y, orientation.z)); const glm::vec3& bindPosition = _avatar->getSkeleton().joint[i].absoluteBindPosePosition; boneMatrices[i].translate(-bindPosition.x, -bindPosition.y, -bindPosition.z); @@ -244,7 +291,7 @@ void AvatarVoxelSystem::computeBoneIndicesAndWeights(const glm::vec3& vertex, Bo float distance = glm::length(computeVectorFromPointToSegment(jointVertex, skeleton.joint[parent == AVATAR_JOINT_NULL ? i : parent].absoluteBindPosePosition, skeleton.joint[i].absoluteBindPosePosition)); - if (distance > skeleton.joint[i].bindRadius) { + if (!MODES[_mode].includeBonesOutsideBindRadius && distance > skeleton.joint[i].bindRadius) { continue; } for (int j = 0; j < BONE_ELEMENTS_PER_VERTEX; j++) { @@ -261,7 +308,7 @@ void AvatarVoxelSystem::computeBoneIndicesAndWeights(const glm::vec3& vertex, Bo // compute the weights based on inverse distance float totalWeight = 0.0f; - for (int i = 0; i < BONE_ELEMENTS_PER_VERTEX; i++) { + for (int i = 0; i < MODES[_mode].maxBonesPerBind; i++) { indices[i] = nearest[i].index; if (nearest[i].distance != FLT_MAX) { weights[i] = 1.0f / glm::max(nearest[i].distance, EPSILON); diff --git a/interface/src/AvatarVoxelSystem.h b/interface/src/AvatarVoxelSystem.h index cf297c25f4..51144e3954 100644 --- a/interface/src/AvatarVoxelSystem.h +++ b/interface/src/AvatarVoxelSystem.h @@ -25,7 +25,7 @@ class AvatarVoxelSystem : public QObject, public VoxelSystem { Q_OBJECT public: - + AvatarVoxelSystem(Avatar* avatar); virtual ~AvatarVoxelSystem(); @@ -35,6 +35,10 @@ public: Q_INVOKABLE void setVoxelURL(const QUrl& url); const QUrl& getVoxelURL() const { return _voxelURL; } + +public slots: + + void cycleMode(); protected: @@ -54,6 +58,8 @@ private: void computeBoneIndicesAndWeights(const glm::vec3& vertex, BoneIndices& indices, glm::vec4& weights) const; + int _mode; + Avatar* _avatar; QUrl _voxelURL;