From a43844447c26a1ce3359225a2fdadc44902fbd26 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 28 Dec 2013 10:07:33 -0800 Subject: [PATCH 01/10] first cut at 3D TV support --- interface/src/Application.cpp | 46 +++++++--- interface/src/Application.h | 6 +- interface/src/Menu.cpp | 2 + interface/src/Menu.h | 1 + interface/src/devices/TV3DManager.cpp | 124 ++++++++++++++++++++++++++ interface/src/devices/TV3DManager.h | 41 +++++++++ 6 files changed, 208 insertions(+), 12 deletions(-) create mode 100644 interface/src/devices/TV3DManager.cpp create mode 100644 interface/src/devices/TV3DManager.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 08ffa436dc..21e6575931 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -57,6 +57,7 @@ #include "Util.h" #include "devices/LeapManager.h" #include "devices/OculusManager.h" +#include "devices/TV3DManager.h" #include "renderer/ProgramObject.h" #include "ui/TextRenderer.h" #include "InfoView.h" @@ -439,7 +440,10 @@ void Application::paintGL() { if (OculusManager::isConnected()) { OculusManager::display(whichCamera); - + } else if (TV3DManager::isConnected()) { + _glowEffect.prepare(); + TV3DManager::display(whichCamera); + _glowEffect.render(); } else { _glowEffect.prepare(); @@ -474,8 +478,13 @@ void Application::paintGL() { _mirrorCamera.update(1.0f/_fps); // set the bounds of rear mirror view - glViewport(_mirrorViewRect.x(), _glWidget->height() - _mirrorViewRect.y() - _mirrorViewRect.height(), _mirrorViewRect.width(), _mirrorViewRect.height()); - glScissor(_mirrorViewRect.x(), _glWidget->height() - _mirrorViewRect.y() - _mirrorViewRect.height(), _mirrorViewRect.width(), _mirrorViewRect.height()); + float mirrorX = _mirrorViewRect.x(); + float mirrorY = _glWidget->height() - _mirrorViewRect.y() - _mirrorViewRect.height(); + float mirrorW = _mirrorViewRect.width(); + float mirrorH = _mirrorViewRect.height(); + + glViewport(mirrorX, mirrorY, mirrorW, mirrorH); + glScissor(mirrorX, mirrorY, mirrorW, mirrorH); bool updateViewFrustum = false; updateProjectionMatrix(_mirrorCamera, updateViewFrustum); glEnable(GL_SCISSOR_TEST); @@ -501,14 +510,18 @@ void Application::paintGL() { _myAvatar.getSkeletonModel().setTranslation(_myAvatar.getHead().getFaceModel().getTranslation() - neckPosition); - displaySide(_mirrorCamera, true); + //displaySide(_mirrorCamera, true); + displaySide(whichCamera); + // restore absolute translations _myAvatar.getSkeletonModel().setTranslation(absoluteSkeletonTranslation); _myAvatar.getHead().getFaceModel().setTranslation(absoluteFaceTranslation); } else { - displaySide(_mirrorCamera, true); + //displaySide(_mirrorCamera, true); + displaySide(whichCamera); + } glPopMatrix(); @@ -531,7 +544,8 @@ void Application::paintGL() { void Application::resetCamerasOnResizeGL(Camera& camera, int width, int height) { if (OculusManager::isConnected()) { OculusManager::configureCamera(camera, width, height); - + } else if (TV3DManager::isConnected()) { + TV3DManager::configureCamera(camera, width, height); } else { camera.setAspectRatio((float)width / height); camera.setFieldOfView(Menu::getInstance()->getFieldOfView()); @@ -910,7 +924,9 @@ void Application::keyPressEvent(QKeyEvent* event) { case Qt::Key_J: if (isShifted) { _viewFrustum.setFocalLength(_viewFrustum.getFocalLength() - 0.1f); - + if (TV3DManager::isConnected()) { + TV3DManager::configureCamera(_myCamera, _glWidget->width(),_glWidget->height()); + } } else { _myCamera.setEyeOffsetPosition(_myCamera.getEyeOffsetPosition() + glm::vec3(-0.001, 0, 0)); } @@ -920,6 +936,9 @@ void Application::keyPressEvent(QKeyEvent* event) { case Qt::Key_M: if (isShifted) { _viewFrustum.setFocalLength(_viewFrustum.getFocalLength() + 0.1f); + if (TV3DManager::isConnected()) { + TV3DManager::configureCamera(_myCamera, _glWidget->width(),_glWidget->height()); + } } else { _myCamera.setEyeOffsetPosition(_myCamera.getEyeOffsetPosition() + glm::vec3(0.001, 0, 0)); @@ -1828,6 +1847,13 @@ void Application::init() { "trigger", Qt::QueuedConnection); } + + TV3DManager::connect(); + if (TV3DManager::isConnected()) { + QMetaObject::invokeMethod(Menu::getInstance()->getActionForOption(MenuOption::Fullscreen), + "trigger", + Qt::QueuedConnection); + } LeapManager::initialize(); @@ -2415,7 +2441,7 @@ void Application::updateCamera(float deltaTime) { bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::updateCamera()"); - if (!OculusManager::isConnected()) { + if (!OculusManager::isConnected() && !TV3DManager::isConnected()) { if (Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror)) { if (_myCamera.getMode() != CAMERA_MODE_MIRROR) { _myCamera.setMode(CAMERA_MODE_MIRROR); @@ -3800,7 +3826,7 @@ void Application::renderAvatars(bool forceRenderHead, bool selfAvatarOnly) { return; } PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), - "Application::displaySide() ... Avatars..."); + "Application::renderAvatars()"); if (!selfAvatarOnly) { // Render avatars of other nodes @@ -4089,7 +4115,7 @@ void Application::resetSensors() { if (OculusManager::isConnected()) { OculusManager::reset(); } - + QCursor::setPos(_headMouseX, _headMouseY); _myAvatar.reset(); _myTransmitter.resetLevels(); diff --git a/interface/src/Application.h b/interface/src/Application.h index e917f6d63d..2c813d1068 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -255,11 +255,13 @@ private slots: void resetSensors(); -private: - void resetCamerasOnResizeGL(Camera& camera, int width, int height); +public: void updateProjectionMatrix(); void updateProjectionMatrix(Camera& camera, bool updateViewFrustum = true); +private: + void resetCamerasOnResizeGL(Camera& camera, int width, int height); + static bool sendVoxelsOperation(OctreeElement* node, void* extraData); static void processAvatarURLsMessage(unsigned char* packetData, size_t dataBytes); static void processAvatarFaceVideoMessage(unsigned char* packetData, size_t dataBytes); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 98b807fea2..286959d413 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -232,6 +232,8 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FirstPerson, Qt::Key_P, true); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Mirror, Qt::SHIFT | Qt::Key_H); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FullscreenMirror, Qt::Key_H); + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Enable3DTVMode, 0, false); + QMenu* avatarSizeMenu = viewMenu->addMenu("Avatar Size"); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 73bb0472b4..f5b41d904e 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -178,6 +178,7 @@ namespace MenuOption { const QString FilterSixense = "Smooth Sixense Movement"; const QString DontRenderVoxels = "Don't call _voxels.render()"; const QString DontCallOpenGLForVoxels = "Don't call glDrawRangeElementsEXT() for Voxels"; + const QString Enable3DTVMode = "Enable 3DTV Mode"; const QString EnableOcclusionCulling = "Enable Occlusion Culling"; const QString EnableVoxelPacketCompression = "Enable Voxel Packet Compression"; const QString EchoServerAudio = "Echo Server Audio"; diff --git a/interface/src/devices/TV3DManager.cpp b/interface/src/devices/TV3DManager.cpp new file mode 100644 index 0000000000..eb4e8ad4c0 --- /dev/null +++ b/interface/src/devices/TV3DManager.cpp @@ -0,0 +1,124 @@ +// +// TV3DManager.cpp +// hifi +// +// Created by Stephen Birarda on 5/9/13. +// Copyright (c) 2012 High Fidelity, Inc. All rights reserved. +// + +#include + +#include + +#include "Application.h" +#include "InterfaceConfig.h" +#include "TV3DManager.h" +#include "Menu.h" + +int TV3DManager::_screenWidth = 1; +int TV3DManager::_screenHeight = 1; +double TV3DManager::_aspect = 1.0; +eyeFrustum TV3DManager::_leftEye; +eyeFrustum TV3DManager::_rightEye; + + +bool TV3DManager::isConnected() { + return Menu::getInstance()->isOptionChecked(MenuOption::Enable3DTVMode); +} + +void TV3DManager::connect() { +} + + +void TV3DManager::setFrustum(Camera& whichCamera) { + const double DTR = 0.0174532925; // degree to radians + const double IOD = 0.05; //intraocular distance + double fovy = whichCamera.getFieldOfView(); // field of view in y-axis + double nearZ = whichCamera.getNearClip(); // near clipping plane + double screenZ = Application::getInstance()->getViewFrustum()->getFocalLength(); // screen projection plane + + double top = nearZ * tan(DTR * fovy / 2); //sets top of frustum based on fovy and near clipping plane + double right = _aspect * top; // sets right of frustum based on aspect ratio + double frustumshift = (IOD / 2) * nearZ / screenZ; + + _leftEye.top = top; + _leftEye.bottom = -top; + _leftEye.left = -right + frustumshift; + _leftEye.right = right + frustumshift; + _leftEye.modelTranslation = IOD / 2; + + _rightEye.top = top; + _rightEye.bottom = -top; + _rightEye.left = -right - frustumshift; + _rightEye.right = right - frustumshift; + _rightEye.modelTranslation = -IOD / 2; +} + +void TV3DManager::configureCamera(Camera& whichCamera, int screenWidth, int screenHeight) { + if (screenHeight == 0) { + screenHeight = 1; // prevent divide by 0 + } + _screenWidth = screenWidth; + _screenHeight = screenHeight; + _aspect= (double)_screenWidth / (double)_screenHeight; + setFrustum(whichCamera); + + glViewport (0, 0, _screenWidth, _screenHeight); // sets drawing viewport + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); +} + +void TV3DManager::display(Camera& whichCamera) { + double nearZ = whichCamera.getNearClip(); // near clipping plane + double farZ = whichCamera.getFarClip(); // far clipping plane + + // left eye portal + int portalX = 0; + int portalY = 0; + int portalW = Application::getInstance()->getGLWidget()->width() / 2; + int portalH = Application::getInstance()->getGLWidget()->height(); + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glEnable(GL_SCISSOR_TEST); + // render left side view + glViewport(portalX, portalY, portalW, portalH); + glScissor(portalX, portalY, portalW, portalH); + + glPushMatrix(); + { + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); // reset projection matrix + glFrustum(_leftEye.left, _leftEye.right, _leftEye.bottom, _leftEye.top, nearZ, farZ); // set left view frustum + glTranslatef(_leftEye.modelTranslation, 0.0, 0.0); // translate to cancel parallax + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + Application::getInstance()->displaySide(whichCamera); + } + glPopMatrix(); + glDisable(GL_SCISSOR_TEST); + + // render right side view + portalX = Application::getInstance()->getGLWidget()->width() / 2; + glEnable(GL_SCISSOR_TEST); + // render left side view + glViewport(portalX, portalY, portalW, portalH); + glScissor(portalX, portalY, portalW, portalH); + glPushMatrix(); + { + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); // reset projection matrix + glFrustum(_rightEye.left, _rightEye.right, _rightEye.bottom, _rightEye.top, nearZ, farZ); // set left view frustum + glTranslatef(_rightEye.modelTranslation, 0.0, 0.0); // translate to cancel parallax + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + Application::getInstance()->displaySide(whichCamera); + } + glPopMatrix(); + glDisable(GL_SCISSOR_TEST); + + // reset the viewport to how we started + glViewport(0, 0, Application::getInstance()->getGLWidget()->width(), Application::getInstance()->getGLWidget()->height()); +} \ No newline at end of file diff --git a/interface/src/devices/TV3DManager.h b/interface/src/devices/TV3DManager.h new file mode 100644 index 0000000000..edea489745 --- /dev/null +++ b/interface/src/devices/TV3DManager.h @@ -0,0 +1,41 @@ +// +// TV3DManager.h +// hifi +// +// Created by Brad Hefta-Gaub on 12/24/2013 +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#ifndef __hifi__TV3DManager__ +#define __hifi__TV3DManager__ + +#include + +class Camera; + +struct eyeFrustum { + double left; + double right; + double bottom; + double top; + float modelTranslation; +}; + + +/// Handles interaction with 3D TVs +class TV3DManager { +public: + static void connect(); + static bool isConnected(); + static void configureCamera(Camera& camera, int screenWidth, int screenHeight); + static void display(Camera& whichCamera); +private: + static void setFrustum(Camera& whichCamera); + static int _screenWidth; + static int _screenHeight; + static double _aspect; + static eyeFrustum _leftEye; + static eyeFrustum _rightEye; +}; + +#endif /* defined(__hifi__TV3DManager__) */ From 32b2fb8f219d6a3b894ed1e5995394c4f97f9186 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 28 Dec 2013 12:08:24 -0800 Subject: [PATCH 02/10] cleanup --- interface/src/Application.cpp | 9 ++------- interface/src/Application.h | 7 ++----- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 21e6575931..5becba1e12 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -510,18 +510,13 @@ void Application::paintGL() { _myAvatar.getSkeletonModel().setTranslation(_myAvatar.getHead().getFaceModel().getTranslation() - neckPosition); - //displaySide(_mirrorCamera, true); - displaySide(whichCamera); - + displaySide(_mirrorCamera, true); // restore absolute translations _myAvatar.getSkeletonModel().setTranslation(absoluteSkeletonTranslation); _myAvatar.getHead().getFaceModel().setTranslation(absoluteFaceTranslation); - } else { - //displaySide(_mirrorCamera, true); - displaySide(whichCamera); - + displaySide(_mirrorCamera, true); } glPopMatrix(); diff --git a/interface/src/Application.h b/interface/src/Application.h index 2c813d1068..fac4d03fb2 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -254,13 +254,10 @@ private slots: void shrinkMirrorView(); void resetSensors(); - -public: - void updateProjectionMatrix(); - void updateProjectionMatrix(Camera& camera, bool updateViewFrustum = true); - private: void resetCamerasOnResizeGL(Camera& camera, int width, int height); + void updateProjectionMatrix(); + void updateProjectionMatrix(Camera& camera, bool updateViewFrustum = true); static bool sendVoxelsOperation(OctreeElement* node, void* extraData); static void processAvatarURLsMessage(unsigned char* packetData, size_t dataBytes); From 6f2a1b98025b27b64a3e0d2c27a6d82925998a68 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 28 Dec 2013 12:51:50 -0800 Subject: [PATCH 03/10] cleanup --- interface/src/Application.cpp | 11 ++++------- interface/src/devices/TV3DManager.cpp | 4 ++-- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 5becba1e12..fcd02375a6 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -478,13 +478,10 @@ void Application::paintGL() { _mirrorCamera.update(1.0f/_fps); // set the bounds of rear mirror view - float mirrorX = _mirrorViewRect.x(); - float mirrorY = _glWidget->height() - _mirrorViewRect.y() - _mirrorViewRect.height(); - float mirrorW = _mirrorViewRect.width(); - float mirrorH = _mirrorViewRect.height(); - - glViewport(mirrorX, mirrorY, mirrorW, mirrorH); - glScissor(mirrorX, mirrorY, mirrorW, mirrorH); + glViewport(_mirrorViewRect.x(), _glWidget->height() - _mirrorViewRect.y() - _mirrorViewRect.height(), + _mirrorViewRect.width(), _mirrorViewRect.height()); + glScissor(_mirrorViewRect.x(), _glWidget->height() - _mirrorViewRect.y() - _mirrorViewRect.height(), + _mirrorViewRect.width(), _mirrorViewRect.height()); bool updateViewFrustum = false; updateProjectionMatrix(_mirrorCamera, updateViewFrustum); glEnable(GL_SCISSOR_TEST); diff --git a/interface/src/devices/TV3DManager.cpp b/interface/src/devices/TV3DManager.cpp index eb4e8ad4c0..d309c33ed3 100644 --- a/interface/src/devices/TV3DManager.cpp +++ b/interface/src/devices/TV3DManager.cpp @@ -2,8 +2,8 @@ // TV3DManager.cpp // hifi // -// Created by Stephen Birarda on 5/9/13. -// Copyright (c) 2012 High Fidelity, Inc. All rights reserved. +// Created by Brad Hefta-Gaub on 12/24/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. // #include From 47f45c3af1fbbe0e30fa3fd0b90a2afb6750f43c Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 28 Dec 2013 13:00:25 -0800 Subject: [PATCH 04/10] make sure camera is configured on connect --- interface/src/devices/TV3DManager.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/interface/src/devices/TV3DManager.cpp b/interface/src/devices/TV3DManager.cpp index d309c33ed3..c00168931f 100644 --- a/interface/src/devices/TV3DManager.cpp +++ b/interface/src/devices/TV3DManager.cpp @@ -27,6 +27,12 @@ bool TV3DManager::isConnected() { } void TV3DManager::connect() { + Application* app = Application::getInstance(); + int width = app->getGLWidget()->width(); + int height = app->getGLWidget()->height(); + Camera& camera = *app->getCamera(); + + configureCamera(camera, width, height); } From 788bb530f86aec5811a09759bdba2cf54eb50828 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 28 Dec 2013 13:02:27 -0800 Subject: [PATCH 05/10] added comment --- interface/src/devices/TV3DManager.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/interface/src/devices/TV3DManager.cpp b/interface/src/devices/TV3DManager.cpp index c00168931f..283b9f3e37 100644 --- a/interface/src/devices/TV3DManager.cpp +++ b/interface/src/devices/TV3DManager.cpp @@ -36,6 +36,8 @@ void TV3DManager::connect() { } +// The basic strategy of this stereoscopic rendering is explained here: +// http://www.orthostereo.com/geometryopengl.html void TV3DManager::setFrustum(Camera& whichCamera) { const double DTR = 0.0174532925; // degree to radians const double IOD = 0.05; //intraocular distance From 6e661e05e59c7ad50cc015b0a5d3ebbe1b3ddfc3 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 31 Dec 2013 09:30:01 -0800 Subject: [PATCH 06/10] minor cleanup and enforcement of coding standards --- libraries/octree/src/Octree.cpp | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 56bbc79bda..3f50776443 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -572,7 +572,7 @@ bool findRayIntersectionOp(OctreeElement* node, void* extraData) { bool Octree::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, OctreeElement*& node, float& distance, BoxFace& face) { - RayArgs args = { origin / (float)TREE_SCALE, direction, node, distance, face }; + RayArgs args = { origin / static_cast(TREE_SCALE), direction, node, distance, face }; recurseTreeWithOperation(findRayIntersectionOp, &args); return args.found; } @@ -600,7 +600,7 @@ bool findSpherePenetrationOp(OctreeElement* element, void* extraData) { if (element->hasContent()) { glm::vec3 elementPenetration; if (element->findSpherePenetration(args->center, args->radius, elementPenetration, &args->penetratedObject)) { - args->penetration = addPenetrations(args->penetration, elementPenetration * (float)TREE_SCALE); + args->penetration = addPenetrations(args->penetration, elementPenetration * static_cast(TREE_SCALE)); args->found = true; } } @@ -610,7 +610,12 @@ bool findSpherePenetrationOp(OctreeElement* element, void* extraData) { bool Octree::findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration, void** penetratedObject) { - SphereArgs args = { center / (float)TREE_SCALE, radius / TREE_SCALE, penetration, false, NULL }; + SphereArgs args = { + center / static_cast(TREE_SCALE), + radius / static_cast(TREE_SCALE), + penetration, + false, + NULL }; penetration = glm::vec3(0.0f, 0.0f, 0.0f); recurseTreeWithOperation(findSpherePenetrationOp, &args); if (penetratedObject) { @@ -642,7 +647,7 @@ bool findCapsulePenetrationOp(OctreeElement* node, void* extraData) { if (node->hasContent()) { glm::vec3 nodePenetration; if (box.findCapsulePenetration(args->start, args->end, args->radius, nodePenetration)) { - args->penetration = addPenetrations(args->penetration, nodePenetration * (float)TREE_SCALE); + args->penetration = addPenetrations(args->penetration, nodePenetration * static_cast(TREE_SCALE)); args->found = true; } } @@ -650,7 +655,11 @@ bool findCapsulePenetrationOp(OctreeElement* node, void* extraData) { } bool Octree::findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration) { - CapsuleArgs args = { start / (float)TREE_SCALE, end / (float)TREE_SCALE, radius / TREE_SCALE, penetration }; + CapsuleArgs args = { + start / static_cast(TREE_SCALE), + end / static_cast(TREE_SCALE), + radius / static_cast(TREE_SCALE), + penetration }; penetration = glm::vec3(0.0f, 0.0f, 0.0f); recurseTreeWithOperation(findCapsulePenetrationOp, &args); return args.found; @@ -719,8 +728,8 @@ int Octree::encodeTreeBitstream(OctreeElement* node, // if childBytesWritten == 1 then something went wrong... that's not possible assert(childBytesWritten != 1); - // if includeColor and childBytesWritten == 2, then it can only mean that the lower level trees don't exist or for some reason - // couldn't be written... so reset them here... This isn't true for the non-color included case + // if includeColor and childBytesWritten == 2, then it can only mean that the lower level trees don't exist or for some + // reason couldn't be written... so reset them here... This isn't true for the non-color included case if (params.includeColor && childBytesWritten == 2) { childBytesWritten = 0; //params.stopReason = EncodeBitstreamParams::UNKNOWN; // possibly should be DIDNT_FIT... @@ -887,9 +896,10 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* node, bool keepDiggingDeeper = true; // Assuming we're in view we have a great work ethic, we're always ready for more! // At any given point in writing the bitstream, the largest minimum we might need to flesh out the current level - // is 1 byte for child colors + 3*NUMBER_OF_CHILDREN bytes for the actual colors + 1 byte for child trees. There could be sub trees - // below this point, which might take many more bytes, but that's ok, because we can always mark our subtrees as - // not existing and stop the packet at this point, then start up with a new packet for the remaining sub trees. + // is 1 byte for child colors + 3*NUMBER_OF_CHILDREN bytes for the actual colors + 1 byte for child trees. + // There could be sub trees below this point, which might take many more bytes, but that's ok, because we can + // always mark our subtrees as not existing and stop the packet at this point, then start up with a new packet + // for the remaining sub trees. unsigned char childrenExistInTreeBits = 0; unsigned char childrenExistInPacketBits = 0; unsigned char childrenColoredBits = 0; @@ -943,7 +953,6 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* node, if (params.stats && childNode) { params.stats->traversed(childNode); } - } // for each child node in Distance sorted order..., check to see if they exist, are colored, and in view, and if so @@ -1066,7 +1075,6 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* node, params.stats->skippedNoChange(childNode); } } - } } } From 14b88fd1415b63c270716319cc3dfd76b7613843 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 31 Dec 2013 09:49:46 -0800 Subject: [PATCH 07/10] Changing meaning of "elasticy" in applyHardCollision() to range in [0,1] instead of [1,2] Also enforcing C++ style casts as per coding standard. --- .../particles/src/ParticleCollisionSystem.cpp | 54 ++++++++++--------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/libraries/particles/src/ParticleCollisionSystem.cpp b/libraries/particles/src/ParticleCollisionSystem.cpp index b3ad9a9740..0c36022c75 100644 --- a/libraries/particles/src/ParticleCollisionSystem.cpp +++ b/libraries/particles/src/ParticleCollisionSystem.cpp @@ -67,10 +67,10 @@ void ParticleCollisionSystem::checkParticle(Particle* particle) { } void ParticleCollisionSystem::updateCollisionWithVoxels(Particle* particle) { - glm::vec3 center = particle->getPosition() * (float)TREE_SCALE; - float radius = particle->getRadius() * (float)TREE_SCALE; - const float VOXEL_ELASTICITY = 1.4f; - const float VOXEL_DAMPING = 0.0; + glm::vec3 center = particle->getPosition() * static_cast(TREE_SCALE); + float radius = particle->getRadius() * static_cast(TREE_SCALE); + const float VOXEL_ELASTICITY = 0.4f; // fraction of momentum conserved at collision + const float VOXEL_DAMPING = 0.0f; const float VOXEL_COLLISION_FREQUENCY = 0.5f; glm::vec3 penetration; if (_voxels->findSpherePenetration(center, radius, penetration)) { @@ -82,10 +82,10 @@ void ParticleCollisionSystem::updateCollisionWithVoxels(Particle* particle) { } void ParticleCollisionSystem::updateCollisionWithParticles(Particle* particle) { - glm::vec3 center = particle->getPosition() * (float)TREE_SCALE; - float radius = particle->getRadius() * (float)TREE_SCALE; + glm::vec3 center = particle->getPosition() * static_cast(TREE_SCALE); + float radius = particle->getRadius() * static_cast(TREE_SCALE); const float VOXEL_ELASTICITY = 1.4f; - const float VOXEL_DAMPING = 0.0; + const float VOXEL_DAMPING = 0.0f; const float VOXEL_COLLISION_FREQUENCY = 0.5f; glm::vec3 penetration; Particle* penetratedParticle; @@ -121,10 +121,10 @@ void ParticleCollisionSystem::updateCollisionWithAvatars(Particle* particle) { } //printf("updateCollisionWithAvatars()...\n"); - glm::vec3 center = particle->getPosition() * (float)TREE_SCALE; - float radius = particle->getRadius() * (float)TREE_SCALE; + glm::vec3 center = particle->getPosition() * static_cast(TREE_SCALE); + float radius = particle->getRadius() * static_cast(TREE_SCALE); const float VOXEL_ELASTICITY = 1.4f; - const float VOXEL_DAMPING = 0.0; + const float VOXEL_DAMPING = 0.0f; const float VOXEL_COLLISION_FREQUENCY = 0.5f; glm::vec3 penetration; const PalmData* collidingPalm = NULL; @@ -145,7 +145,7 @@ void ParticleCollisionSystem::updateCollisionWithAvatars(Particle* particle) { // determine if the palm that collided was moving, if so, then we add that palm velocity as well... glm::vec3 addedVelocity = NO_ADDED_VELOCITY; if (collidingPalm) { - glm::vec3 palmVelocity = collidingPalm->getVelocity() / (float)TREE_SCALE; + glm::vec3 palmVelocity = collidingPalm->getVelocity() / static_cast(TREE_SCALE); //printf("collidingPalm Velocity=%f,%f,%f\n", palmVelocity.x, palmVelocity.y, palmVelocity.z); addedVelocity = palmVelocity; } @@ -159,7 +159,7 @@ void ParticleCollisionSystem::updateCollisionWithAvatars(Particle* particle) { for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { //qDebug() << "updateCollisionWithAvatars()... node:" << *node << "\n"; if (node->getLinkedData() && node->getType() == NODE_TYPE_AGENT) { - AvatarData* avatar = (AvatarData*)node->getLinkedData(); + AvatarData* avatar = static_cast(node->getLinkedData()); //printf("updateCollisionWithAvatars()...avatar=%p\n", avatar); // check hands... @@ -173,7 +173,7 @@ void ParticleCollisionSystem::updateCollisionWithAvatars(Particle* particle) { // determine if the palm that collided was moving, if so, then we add that palm velocity as well... glm::vec3 addedVelocity = NO_ADDED_VELOCITY; if (collidingPalm) { - glm::vec3 palmVelocity = collidingPalm->getVelocity() / (float)TREE_SCALE; + glm::vec3 palmVelocity = collidingPalm->getVelocity() / static_cast(TREE_SCALE); //printf("collidingPalm Velocity=%f,%f,%f\n", palmVelocity.x, palmVelocity.y, palmVelocity.z); addedVelocity = palmVelocity; } @@ -192,21 +192,22 @@ void ParticleCollisionSystem::applyHardCollision(Particle* particle, const glm:: // Update the particle in response to a hard collision. Position will be reset exactly // to outside the colliding surface. Velocity will be modified according to elasticity. // - // if elasticity = 1.0, collision is inelastic. - // if elasticity > 1.0, collision is elastic. + // if elasticity = 0.0, collision is inelastic (vel normal to collision is lost) + // if elasticity = 1.0, collision is 100% elastic. // glm::vec3 position = particle->getPosition(); glm::vec3 velocity = particle->getVelocity(); - position -= penetration; - static float HALTING_VELOCITY = 0.2f / (float) TREE_SCALE; - // cancel out the velocity component in the direction of penetration - float penetrationLength = glm::length(penetration); const float EPSILON = 0.0f; + float velocityDotPenetration = glm::dot(velocity, penetration); + if (velocityDotPenetration > EPSILON) { + position -= penetration; + static float HALTING_VELOCITY = 0.2f / static_cast(TREE_SCALE); + // cancel out the velocity component in the direction of penetration - if (penetrationLength > EPSILON) { + float penetrationLength = glm::length(penetration); glm::vec3 direction = penetration / penetrationLength; - velocity -= glm::dot(velocity, direction) * direction * elasticity; + velocity -= (glm::dot(velocity, direction) * (1.0f + elasticity)) * direction; velocity += addedVelocity; velocity *= glm::clamp(1.f - damping, 0.0f, 1.0f); if (glm::length(velocity) < HALTING_VELOCITY) { @@ -222,9 +223,10 @@ void ParticleCollisionSystem::applyHardCollision(Particle* particle, const glm:: ParticleEditHandle particleEditHandle(_packetSender, _particles, particle->getID()); particleEditHandle.updateParticle(position, particle->getRadius(), particle->getXColor(), velocity, - particle->getGravity(), particle->getDamping(), particle->getInHand(), particle->getUpdateScript()); + particle->getGravity(), particle->getDamping(), particle->getInHand(), + particle->getUpdateScript()); } - + void ParticleCollisionSystem::updateCollisionSound(Particle* particle, const glm::vec3 &penetration, float frequency) { @@ -233,12 +235,12 @@ void ParticleCollisionSystem::updateCollisionSound(Particle* particle, const glm const float COLLISION_LOUDNESS = 1.f; const float DURATION_SCALING = 0.004f; const float NOISE_SCALING = 0.1f; - glm::vec3 velocity = particle->getVelocity() * (float)TREE_SCALE; + glm::vec3 velocity = particle->getVelocity() * static_cast(TREE_SCALE); /* // how do we want to handle this?? // - glm::vec3 gravity = particle->getGravity() * (float)TREE_SCALE; + glm::vec3 gravity = particle->getGravity() * static_cast(TREE_SCALE); if (glm::length(gravity) > EPSILON) { // If gravity is on, remove the effect of gravity on velocity for this @@ -260,4 +262,4 @@ void ParticleCollisionSystem::updateCollisionSound(Particle* particle, const glm fmin(velocityTangentToCollision / velocityTowardCollision * NOISE_SCALING, 1.f), 1.f - DURATION_SCALING * powf(frequency, 0.5f) / velocityTowardCollision, false); } -} \ No newline at end of file +} From 5843c745cbbc7cdec986a9b02408735585d86083 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 2 Jan 2014 09:30:14 -0800 Subject: [PATCH 08/10] minor formatting and code standard enforcement to Particle.* --- libraries/particles/src/Particle.cpp | 11 ++++------- libraries/particles/src/Particle.h | 4 ++-- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/libraries/particles/src/Particle.cpp b/libraries/particles/src/Particle.cpp index f2ee1c1fb4..fdd156450d 100644 --- a/libraries/particles/src/Particle.cpp +++ b/libraries/particles/src/Particle.cpp @@ -459,15 +459,14 @@ void Particle::adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, ssiz void Particle::update() { - uint64_t now = usecTimestampNow(); - int elapsed = now - _lastUpdated; // making this signed slightly improves clock skew behavior - float timeElapsed = (float)((float)elapsed/(float)USECS_PER_SECOND); - + float elapsed = static_cast(now - _lastUpdated); + _lastUpdated = now; + float timeElapsed = elapsed / static_cast(USECS_PER_SECOND); // calculate our default shouldDie state... then allow script to change it if it wants... float velocityScalar = glm::length(getVelocity()); - const float STILL_MOVING = 0.05 / TREE_SCALE; + const float STILL_MOVING = 0.05f / static_cast(TREE_SCALE); bool isStillMoving = (velocityScalar > STILL_MOVING); const float REALLY_OLD = 30.0f; // 30 seconds bool isReallyOld = (getLifetime() > REALLY_OLD); @@ -503,8 +502,6 @@ void Particle::update() { _velocity -= dampingResistance * timeElapsed; //printf("applying damping to Particle timeElapsed=%f\n",timeElapsed); } - - _lastUpdated = now; } void Particle::runScript() { diff --git a/libraries/particles/src/Particle.h b/libraries/particles/src/Particle.h index 0d50413b4f..22622482e6 100644 --- a/libraries/particles/src/Particle.h +++ b/libraries/particles/src/Particle.h @@ -75,8 +75,8 @@ public: uint64_t getLastEdited() const { return _lastEdited; } /// lifetime of the particle in seconds - float getLifetime() const { return (float)(usecTimestampNow() - _created) / (float)USECS_PER_SECOND; } - float getEditedAgo() const { return (float)(usecTimestampNow() - _lastEdited) / (float)USECS_PER_SECOND; } + float getLifetime() const { return static_cast(usecTimestampNow() - _created) / static_cast(USECS_PER_SECOND); } + float getEditedAgo() const { return static_cast(usecTimestampNow() - _lastEdited) / static_cast(USECS_PER_SECOND); } uint32_t getID() const { return _id; } bool getShouldDie() const { return _shouldDie; } QString getUpdateScript() const { return _updateScript; } From d520adba98b819db8deb5cfef82b66b716471057 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 2 Jan 2014 09:31:24 -0800 Subject: [PATCH 09/10] exposed getVelocity() and findSpherePenetration() in Avatar base class --- libraries/avatars/src/AvatarData.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 7ebf12616d..1dd5dacafe 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -41,6 +41,8 @@ enum KeyState DELETE_KEY_DOWN }; +const glm::vec3 vec3Zero(0.0f); + class JointData; class AvatarData : public NodeData { @@ -103,6 +105,17 @@ public: void setHeadData(HeadData* headData) { _headData = headData; } void setHandData(HandData* handData) { _handData = handData; } + + virtual const glm::vec3& getVelocity() const { return vec3Zero; } + + /// Checks for penetration between the described sphere and the avatar. + /// \param penetratorCenter the center of the penetration test sphere + /// \param penetratorRadius the radius of the penetration test sphere + /// \param penetration[out] the vector in which to store the penetration + /// \param skeletonSkipIndex if not -1, the index of a joint to skip (along with its descendents) in the skeleton model + /// \return whether or not the sphere penetrated + virtual bool findSpherePenetration(const glm::vec3& penetratorCenter, float penetratorRadius, + glm::vec3& penetration, int skeletonSkipIndex = -1) { return false; } protected: QUuid _uuid; From 934b0f619bc065550fa73ee1ec991aad9233eced Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 2 Jan 2014 09:36:21 -0800 Subject: [PATCH 10/10] Particles now collide with avatars, but avatars don't react yet. --- .../particles/src/ParticleCollisionSystem.cpp | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/libraries/particles/src/ParticleCollisionSystem.cpp b/libraries/particles/src/ParticleCollisionSystem.cpp index 0c36022c75..68898087d7 100644 --- a/libraries/particles/src/ParticleCollisionSystem.cpp +++ b/libraries/particles/src/ParticleCollisionSystem.cpp @@ -133,12 +133,17 @@ void ParticleCollisionSystem::updateCollisionWithAvatars(Particle* particle) { if (_selfAvatar) { AvatarData* avatar = (AvatarData*)_selfAvatar; //printf("updateCollisionWithAvatars()..._selfAvatar=%p\n", avatar); - + // check hands... const HandData* handData = avatar->getHandData(); - // if the particle penetrates the hand, then apply a hard collision + // TODO: combine hand and collision check into one. Note: would need to supply + // CollisionInfo class rather than just vec3 (penetration) so we can get back + // added velocity. + if (handData->findSpherePenetration(center, radius, penetration, collidingPalm)) { + // TODO: dot collidingPalm and hand velocities and skip collision when they are moving apart. + // apply a hard collision when ball collides with hand penetration /= (float)TREE_SCALE; updateCollisionSound(particle, penetration, VOXEL_COLLISION_FREQUENCY); @@ -150,6 +155,12 @@ void ParticleCollisionSystem::updateCollisionWithAvatars(Particle* particle) { addedVelocity = palmVelocity; } + applyHardCollision(particle, penetration, VOXEL_ELASTICITY, VOXEL_DAMPING, addedVelocity); + } else if (avatar->findSpherePenetration(center, radius, penetration)) { + // apply hard collision when particle collides with avatar + penetration /= (float)TREE_SCALE; + updateCollisionSound(particle, penetration, VOXEL_COLLISION_FREQUENCY); + glm::vec3 addedVelocity = avatar->getVelocity(); applyHardCollision(particle, penetration, VOXEL_ELASTICITY, VOXEL_DAMPING, addedVelocity); } } @@ -159,14 +170,15 @@ void ParticleCollisionSystem::updateCollisionWithAvatars(Particle* particle) { for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { //qDebug() << "updateCollisionWithAvatars()... node:" << *node << "\n"; if (node->getLinkedData() && node->getType() == NODE_TYPE_AGENT) { + // TODO: dot collidingPalm and hand velocities and skip collision when they are moving apart. AvatarData* avatar = static_cast(node->getLinkedData()); //printf("updateCollisionWithAvatars()...avatar=%p\n", avatar); // check hands... const HandData* handData = avatar->getHandData(); - // if the particle penetrates the hand, then apply a hard collision if (handData->findSpherePenetration(center, radius, penetration, collidingPalm)) { + // apply a hard collision when ball collides with hand penetration /= (float)TREE_SCALE; updateCollisionSound(particle, penetration, VOXEL_COLLISION_FREQUENCY); @@ -180,6 +192,11 @@ void ParticleCollisionSystem::updateCollisionWithAvatars(Particle* particle) { applyHardCollision(particle, penetration, VOXEL_ELASTICITY, VOXEL_DAMPING, addedVelocity); + } else if (avatar->findSpherePenetration(center, radius, penetration)) { + penetration /= (float)TREE_SCALE; + updateCollisionSound(particle, penetration, VOXEL_COLLISION_FREQUENCY); + glm::vec3 addedVelocity = avatar->getVelocity(); + applyHardCollision(particle, penetration, VOXEL_ELASTICITY, VOXEL_DAMPING, addedVelocity); } } }