From c3f6cab19913921dc2668cf1a40dedff5d177bb9 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 28 May 2014 15:20:09 -0700 Subject: [PATCH 01/27] Working on cascading shadow maps. --- interface/resources/shaders/shadow_map.frag | 12 +- interface/resources/shaders/shadow_map.vert | 10 +- interface/src/Application.cpp | 150 +++++++++++--------- interface/src/Application.h | 6 +- interface/src/renderer/Model.cpp | 9 +- interface/src/voxels/VoxelSystem.cpp | 10 +- 6 files changed, 108 insertions(+), 89 deletions(-) diff --git a/interface/resources/shaders/shadow_map.frag b/interface/resources/shaders/shadow_map.frag index fb3474d9ef..f53c66b095 100644 --- a/interface/resources/shaders/shadow_map.frag +++ b/interface/resources/shaders/shadow_map.frag @@ -13,15 +13,11 @@ uniform sampler2DShadow shadowMap; -// the inverse of the size of the shadow map -const float shadowScale = 1.0 / 2048.0; - varying vec4 shadowColor; void main(void) { - gl_FragColor = mix(shadowColor, gl_Color, 0.25 * - (shadow2D(shadowMap, gl_TexCoord[0].stp + vec3(-shadowScale, -shadowScale, 0.0)).r + - shadow2D(shadowMap, gl_TexCoord[0].stp + vec3(-shadowScale, shadowScale, 0.0)).r + - shadow2D(shadowMap, gl_TexCoord[0].stp + vec3(shadowScale, -shadowScale, 0.0)).r + - shadow2D(shadowMap, gl_TexCoord[0].stp + vec3(shadowScale, shadowScale, 0.0)).r)); + gl_FragColor = mix(shadowColor, gl_Color, shadow2D(shadowMap, gl_TexCoord[0].stp).r * + shadow2D(shadowMap, gl_TexCoord[1].stp).r * + shadow2D(shadowMap, gl_TexCoord[2].stp).r * + shadow2D(shadowMap, gl_TexCoord[3].stp).r); } diff --git a/interface/resources/shaders/shadow_map.vert b/interface/resources/shaders/shadow_map.vert index abe5f99b44..e7efcd7c0f 100644 --- a/interface/resources/shaders/shadow_map.vert +++ b/interface/resources/shaders/shadow_map.vert @@ -21,10 +21,16 @@ void main(void) { vec4 normal = normalize(gl_ModelViewMatrix * vec4(gl_Normal, 0.0)); gl_FrontColor = shadowColor + gl_Color * (gl_LightSource[0].diffuse * max(0.0, dot(normal, gl_LightSource[0].position))); - // generate the shadow texture coordinate using the eye position + // generate the shadow texture coordinates using the eye position vec4 eyePosition = gl_ModelViewMatrix * gl_Vertex; gl_TexCoord[0] = vec4(dot(gl_EyePlaneS[0], eyePosition), dot(gl_EyePlaneT[0], eyePosition), - dot(gl_EyePlaneR[0], eyePosition), 1.0); + dot(gl_EyePlaneR[0], eyePosition), 1.0); + gl_TexCoord[1] = vec4(dot(gl_EyePlaneS[1], eyePosition), dot(gl_EyePlaneT[1], eyePosition), + dot(gl_EyePlaneR[1], eyePosition), 1.0); + gl_TexCoord[2] = vec4(dot(gl_EyePlaneS[2], eyePosition), dot(gl_EyePlaneT[2], eyePosition), + dot(gl_EyePlaneR[2], eyePosition), 1.0); + gl_TexCoord[3] = vec4(dot(gl_EyePlaneS[3], eyePosition), dot(gl_EyePlaneT[3], eyePosition), + dot(gl_EyePlaneR[3], eyePosition), 1.0); // use the fixed function transform gl_Position = ftransform(); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index fac0ef154f..a1c2507822 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2256,94 +2256,104 @@ void Application::updateShadowMap() { glEnable(GL_DEPTH_TEST); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glViewport(0, 0, fbo->width(), fbo->height()); - glm::vec3 lightDirection = -getSunDirection(); glm::quat rotation = rotationBetween(IDENTITY_FRONT, lightDirection); glm::quat inverseRotation = glm::inverse(rotation); - float nearScale = 0.0f; - const float MAX_SHADOW_DISTANCE = 2.0f; - float farScale = (MAX_SHADOW_DISTANCE - _viewFrustum.getNearClip()) / - (_viewFrustum.getFarClip() - _viewFrustum.getNearClip()); - loadViewFrustum(_myCamera, _viewFrustum); - glm::vec3 points[] = { - glm::mix(_viewFrustum.getNearTopLeft(), _viewFrustum.getFarTopLeft(), nearScale), - glm::mix(_viewFrustum.getNearTopRight(), _viewFrustum.getFarTopRight(), nearScale), - glm::mix(_viewFrustum.getNearBottomLeft(), _viewFrustum.getFarBottomLeft(), nearScale), - glm::mix(_viewFrustum.getNearBottomRight(), _viewFrustum.getFarBottomRight(), nearScale), - glm::mix(_viewFrustum.getNearTopLeft(), _viewFrustum.getFarTopLeft(), farScale), - glm::mix(_viewFrustum.getNearTopRight(), _viewFrustum.getFarTopRight(), farScale), - glm::mix(_viewFrustum.getNearBottomLeft(), _viewFrustum.getFarBottomLeft(), farScale), - glm::mix(_viewFrustum.getNearBottomRight(), _viewFrustum.getFarBottomRight(), farScale) }; - glm::vec3 center; - for (size_t i = 0; i < sizeof(points) / sizeof(points[0]); i++) { - center += points[i]; - } - center /= (float)(sizeof(points) / sizeof(points[0])); - float radius = 0.0f; - for (size_t i = 0; i < sizeof(points) / sizeof(points[0]); i++) { - radius = qMax(radius, glm::distance(points[i], center)); - } - center = inverseRotation * center; - // to reduce texture "shimmer," move in texel increments - float texelSize = (2.0f * radius) / fbo->width(); - center = glm::vec3(roundf(center.x / texelSize) * texelSize, roundf(center.y / texelSize) * texelSize, - roundf(center.z / texelSize) * texelSize); + const float MAP_DISTANCES[] = { 0.0f, 2.0f, 6.0f, 14.0f, 30.0f }; + const glm::vec2 MAP_COORDS[] = { glm::vec2(0.0f, 0.0f), glm::vec2(0.5f, 0.0f), + glm::vec2(0.0f, 0.5f), glm::vec2(0.5f, 0.5f) }; - glm::vec3 minima(center.x - radius, center.y - radius, center.z - radius); - glm::vec3 maxima(center.x + radius, center.y + radius, center.z + radius); + int halfSize = fbo->width() / 2; + float frustumScale = 1.0f / (_viewFrustum.getFarClip() - _viewFrustum.getNearClip()); + + for (int i = 0; i < SHADOW_MATRIX_COUNT; i++) { + const glm::vec2& coord = MAP_COORDS[i]; + glViewport(coord.s * halfSize, coord.t * halfSize, halfSize, halfSize); - // stretch out our extents in z so that we get all of the avatars - minima.z -= _viewFrustum.getFarClip() * 0.5f; - maxima.z += _viewFrustum.getFarClip() * 0.5f; + float nearScale = MAP_DISTANCES[i] * frustumScale; + float farScale = MAP_DISTANCES[i + 1] * frustumScale; + loadViewFrustum(_myCamera, _viewFrustum); + glm::vec3 points[] = { + glm::mix(_viewFrustum.getNearTopLeft(), _viewFrustum.getFarTopLeft(), nearScale), + glm::mix(_viewFrustum.getNearTopRight(), _viewFrustum.getFarTopRight(), nearScale), + glm::mix(_viewFrustum.getNearBottomLeft(), _viewFrustum.getFarBottomLeft(), nearScale), + glm::mix(_viewFrustum.getNearBottomRight(), _viewFrustum.getFarBottomRight(), nearScale), + glm::mix(_viewFrustum.getNearTopLeft(), _viewFrustum.getFarTopLeft(), farScale), + glm::mix(_viewFrustum.getNearTopRight(), _viewFrustum.getFarTopRight(), farScale), + glm::mix(_viewFrustum.getNearBottomLeft(), _viewFrustum.getFarBottomLeft(), farScale), + glm::mix(_viewFrustum.getNearBottomRight(), _viewFrustum.getFarBottomRight(), farScale) }; + glm::vec3 center; + for (size_t j = 0; j < sizeof(points) / sizeof(points[0]); j++) { + center += points[j]; + } + center /= (float)(sizeof(points) / sizeof(points[0])); + float radius = 0.0f; + for (size_t j = 0; j < sizeof(points) / sizeof(points[0]); j++) { + radius = qMax(radius, glm::distance(points[j], center)); + } + center = inverseRotation * center; + + // to reduce texture "shimmer," move in texel increments + float texelSize = (2.0f * radius) / halfSize; + center = glm::vec3(roundf(center.x / texelSize) * texelSize, roundf(center.y / texelSize) * texelSize, + roundf(center.z / texelSize) * texelSize); + + glm::vec3 minima(center.x - radius, center.y - radius, center.z - radius); + glm::vec3 maxima(center.x + radius, center.y + radius, center.z + radius); - // save the combined matrix for rendering - _shadowMatrix = glm::transpose(glm::translate(glm::vec3(0.5f, 0.5f, 0.5f)) * glm::scale(glm::vec3(0.5f, 0.5f, 0.5f)) * - glm::ortho(minima.x, maxima.x, minima.y, maxima.y, -maxima.z, -minima.z) * glm::mat4_cast(inverseRotation)); + // stretch out our extents in z so that we get all of the avatars + minima.z -= _viewFrustum.getFarClip() * 0.5f; + maxima.z += _viewFrustum.getFarClip() * 0.5f; - // update the shadow view frustum - _shadowViewFrustum.setPosition(rotation * ((minima + maxima) * 0.5f)); - _shadowViewFrustum.setOrientation(rotation); - _shadowViewFrustum.setOrthographic(true); - _shadowViewFrustum.setWidth(maxima.x - minima.x); - _shadowViewFrustum.setHeight(maxima.y - minima.y); - _shadowViewFrustum.setNearClip(minima.z); - _shadowViewFrustum.setFarClip(maxima.z); - _shadowViewFrustum.setEyeOffsetPosition(glm::vec3()); - _shadowViewFrustum.setEyeOffsetOrientation(glm::quat()); - _shadowViewFrustum.calculate(); + // save the combined matrix for rendering + _shadowMatrices[i] = glm::transpose(glm::translate(glm::vec3(coord, 0.0f)) * glm::scale(glm::vec3(0.5f, 0.5f, 1.0f)) * + glm::translate(glm::vec3(0.5f, 0.5f, 0.5f)) * glm::scale(glm::vec3(0.5f, 0.5f, 0.5f)) * + glm::ortho(minima.x, maxima.x, minima.y, maxima.y, -maxima.z, -minima.z) * glm::mat4_cast(inverseRotation)); - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - glOrtho(minima.x, maxima.x, minima.y, maxima.y, -maxima.z, -minima.z); + // update the shadow view frustum + _shadowViewFrustum.setPosition(rotation * ((minima + maxima) * 0.5f)); + _shadowViewFrustum.setOrientation(rotation); + _shadowViewFrustum.setOrthographic(true); + _shadowViewFrustum.setWidth(maxima.x - minima.x); + _shadowViewFrustum.setHeight(maxima.y - minima.y); + _shadowViewFrustum.setNearClip(minima.z); + _shadowViewFrustum.setFarClip(maxima.z); + _shadowViewFrustum.setEyeOffsetPosition(glm::vec3()); + _shadowViewFrustum.setEyeOffsetOrientation(glm::quat()); + _shadowViewFrustum.calculate(); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - glm::vec3 axis = glm::axis(inverseRotation); - glRotatef(glm::degrees(glm::angle(inverseRotation)), axis.x, axis.y, axis.z); + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glOrtho(minima.x, maxima.x, minima.y, maxima.y, -maxima.z, -minima.z); - // store view matrix without translation, which we'll use for precision-sensitive objects - updateUntranslatedViewMatrix(); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + glm::vec3 axis = glm::axis(inverseRotation); + glRotatef(glm::degrees(glm::angle(inverseRotation)), axis.x, axis.y, axis.z); - glEnable(GL_POLYGON_OFFSET_FILL); - glPolygonOffset(1.1f, 4.0f); // magic numbers courtesy http://www.eecs.berkeley.edu/~ravir/6160/papers/shadowmaps.ppt + // store view matrix without translation, which we'll use for precision-sensitive objects + updateUntranslatedViewMatrix(); - _avatarManager.renderAvatars(Avatar::SHADOW_RENDER_MODE); - _particles.render(OctreeRenderer::SHADOW_RENDER_MODE); - _models.render(OctreeRenderer::SHADOW_RENDER_MODE); + glEnable(GL_POLYGON_OFFSET_FILL); + glPolygonOffset(1.1f, 4.0f); // magic numbers courtesy http://www.eecs.berkeley.edu/~ravir/6160/papers/shadowmaps.ppt - glDisable(GL_POLYGON_OFFSET_FILL); + _avatarManager.renderAvatars(Avatar::SHADOW_RENDER_MODE); + _particles.render(OctreeRenderer::SHADOW_RENDER_MODE); + _models.render(OctreeRenderer::SHADOW_RENDER_MODE); - glPopMatrix(); + glDisable(GL_POLYGON_OFFSET_FILL); - glMatrixMode(GL_PROJECTION); - glPopMatrix(); + glPopMatrix(); - glMatrixMode(GL_MODELVIEW); + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + } + fbo->release(); glViewport(0, 0, _glWidget->width(), _glWidget->height()); diff --git a/interface/src/Application.h b/interface/src/Application.h index 0065944611..5d29a9057a 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -126,6 +126,8 @@ static const float MIRROR_REARVIEW_DISTANCE = 0.65f; static const float MIRROR_REARVIEW_BODY_DISTANCE = 2.3f; static const float MIRROR_FIELD_OF_VIEW = 30.0f; +static const int SHADOW_MATRIX_COUNT = 4; + class Application : public QApplication { Q_OBJECT @@ -261,7 +263,7 @@ public: /// result from matrix multiplication at high translation magnitudes. void loadTranslatedViewMatrix(const glm::vec3& translation); - const glm::mat4& getShadowMatrix() const { return _shadowMatrix; } + const glm::mat4* getShadowMatrices() const { return _shadowMatrices; } void getModelViewMatrix(glm::dmat4* modelViewMatrix); void getProjectionMatrix(glm::dmat4* projectionMatrix); @@ -491,7 +493,7 @@ private: float _rotateMirror; float _raiseMirror; - glm::mat4 _shadowMatrix; + glm::mat4 _shadowMatrices[SHADOW_MATRIX_COUNT]; Environment _environment; diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 678a4b09c0..7c9ba50346 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -1509,9 +1509,12 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent, bool re const QVector& networkMeshes = _geometry->getMeshes(); if (receiveShadows) { - glTexGenfv(GL_S, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrix()[0]); - glTexGenfv(GL_T, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrix()[1]); - glTexGenfv(GL_R, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrix()[2]); + for (int i = SHADOW_MATRIX_COUNT - 1; i >= 0; i--) { + glActiveTexture(GL_TEXTURE0 + i); + glTexGenfv(GL_S, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrices()[i][0]); + glTexGenfv(GL_T, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrices()[i][1]); + glTexGenfv(GL_R, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrices()[i][2]); + } } for (int i = 0; i < networkMeshes.size(); i++) { // exit early if the translucency doesn't match what we're drawing diff --git a/interface/src/voxels/VoxelSystem.cpp b/interface/src/voxels/VoxelSystem.cpp index 8937cef7dd..4f1b322455 100644 --- a/interface/src/voxels/VoxelSystem.cpp +++ b/interface/src/voxels/VoxelSystem.cpp @@ -1490,10 +1490,12 @@ void VoxelSystem::applyScaleAndBindProgram(bool texture) { _shadowMapProgram.bind(); glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getShadowDepthTextureID()); - glTexGenfv(GL_S, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrix()[0]); - glTexGenfv(GL_T, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrix()[1]); - glTexGenfv(GL_R, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrix()[2]); - + for (int i = SHADOW_MATRIX_COUNT - 1; i >= 0; i--) { + glActiveTexture(GL_TEXTURE0 + i); + glTexGenfv(GL_S, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrices()[i][0]); + glTexGenfv(GL_T, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrices()[i][1]); + glTexGenfv(GL_R, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrices()[i][2]); + } } else if (texture) { _perlinModulateProgram.bind(); glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getPermutationNormalTextureID()); From 8cd101ac57a3cdeae4f253477e3a5fde04bdbd11 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 28 May 2014 15:57:38 -0700 Subject: [PATCH 02/27] Added getJointCombinedRotation to Models --- interface/src/renderer/Model.cpp | 12 ++++++++++-- interface/src/renderer/Model.h | 1 + 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 678a4b09c0..91c14d7758 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -641,8 +641,16 @@ bool Model::getJointRotation(int jointIndex, glm::quat& rotation, bool fromBind) return false; } rotation = _jointStates[jointIndex].combinedRotation * - (fromBind ? _geometry->getFBXGeometry().joints[jointIndex].inverseBindRotation : - _geometry->getFBXGeometry().joints[jointIndex].inverseDefaultRotation); + (fromBind ? _geometry->getFBXGeometry().joints[jointIndex].inverseBindRotation : + _geometry->getFBXGeometry().joints[jointIndex].inverseDefaultRotation); + return true; +} + +bool Model::getJointCombinedRotation(int jointIndex, glm::quat& rotation) const { + if (jointIndex == -1 || _jointStates.isEmpty()) { + return false; + } + rotation = _jointStates[jointIndex].combinedRotation; return true; } diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index a4e45287dd..91429a3677 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -123,6 +123,7 @@ public: bool getJointPosition(int jointIndex, glm::vec3& position) const; bool getJointRotation(int jointIndex, glm::quat& rotation, bool fromBind = false) const; + bool getJointCombinedRotation(int jointIndex, glm::quat& rotation) const; QStringList getJointNames() const; From 698ecbf9c5ab7f4c7719ee812159a1a7f9b0e613 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 28 May 2014 15:58:45 -0700 Subject: [PATCH 03/27] Fix for shadow map rendering. --- interface/src/Application.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index a1c2507822..0cae0f3e75 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2266,14 +2266,14 @@ void Application::updateShadowMap() { int halfSize = fbo->width() / 2; float frustumScale = 1.0f / (_viewFrustum.getFarClip() - _viewFrustum.getNearClip()); + loadViewFrustum(_myCamera, _viewFrustum); for (int i = 0; i < SHADOW_MATRIX_COUNT; i++) { const glm::vec2& coord = MAP_COORDS[i]; - glViewport(coord.s * halfSize, coord.t * halfSize, halfSize, halfSize); + glViewport(coord.s * fbo->width(), coord.t * fbo->height(), halfSize, halfSize); float nearScale = MAP_DISTANCES[i] * frustumScale; float farScale = MAP_DISTANCES[i + 1] * frustumScale; - loadViewFrustum(_myCamera, _viewFrustum); glm::vec3 points[] = { glm::mix(_viewFrustum.getNearTopLeft(), _viewFrustum.getFarTopLeft(), nearScale), glm::mix(_viewFrustum.getNearTopRight(), _viewFrustum.getFarTopRight(), nearScale), From b4deed775e224d99e1f8b19d1a59e16ba9d2c392 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 28 May 2014 15:59:42 -0700 Subject: [PATCH 04/27] Added joints position and combined rotation to scripting interface --- interface/src/avatar/Avatar.cpp | 25 +++++++++++++++++++++++++ interface/src/avatar/Avatar.h | 7 ++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 306dc0194e..55c0830dfb 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -705,6 +705,30 @@ QStringList Avatar::getJointNames() const { return _skeletonModel.isActive() ? _skeletonModel.getGeometry()->getFBXGeometry().getJointNames() : QStringList(); } +glm::vec3 Avatar::getJointPosition(int index) const { + glm::vec3 position(0,0,0); + _skeletonModel.getJointPosition(index, position); + return position; +} + +glm::vec3 Avatar::getJointPosition(const QString& name) const { + glm::vec3 position(0,0,0); + _skeletonModel.getJointPosition(getJointIndex(name), position); + return position; +} + +glm::quat Avatar::getJointCombinedRotation(int index) const { + glm::quat rotation; + _skeletonModel.getJointCombinedRotation(index, rotation); + return rotation; +} + +glm::quat Avatar::getJointCombinedRotation(const QString& name) const { + glm::quat rotation; + _skeletonModel.getJointCombinedRotation(getJointIndex(name), rotation); + return rotation; +} + void Avatar::setFaceModelURL(const QUrl& faceModelURL) { AvatarData::setFaceModelURL(faceModelURL); const QUrl DEFAULT_FACE_MODEL_URL = QUrl::fromLocalFile(Application::resourcesPath() + "meshes/defaultAvatar_head.fst"); @@ -725,6 +749,7 @@ void Avatar::setAttachmentData(const QVector& attachmentData) { // make sure we have as many models as attachments while (_attachmentModels.size() < attachmentData.size()) { Model* model = new Model(this); + model->setSnapModelToCenter(true); model->init(); _attachmentModels.append(model); } diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index db13656546..f928881068 100755 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -152,7 +152,12 @@ public: quint32 getCollisionGroups() const { return _collisionGroups; } virtual void setCollisionGroups(quint32 collisionGroups) { _collisionGroups = (collisionGroups & VALID_COLLISION_GROUPS); } - + + Q_INVOKABLE glm::vec3 getJointPosition(int index) const; + Q_INVOKABLE glm::vec3 getJointPosition(const QString& name) const; + Q_INVOKABLE glm::quat getJointCombinedRotation(int index) const; + Q_INVOKABLE glm::quat getJointCombinedRotation(const QString& name) const; + public slots: void updateCollisionGroups(); From 372ddc92fdd27de5c5adb0c634eb97a70a068a5f Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 28 May 2014 16:00:37 -0700 Subject: [PATCH 05/27] Added attaching of model to MyAvatar when close enough --- examples/editModels.js | 109 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 108 insertions(+), 1 deletion(-) diff --git a/examples/editModels.js b/examples/editModels.js index 30d1e4edf4..cf9b9abbdc 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -40,6 +40,17 @@ var modelURLs = [ var toolBar; + +var jointList = MyAvatar.getJointNames(); +//print("\n# Joint list start"); +//for (var i = 0; i < jointList.length; i++) { +// Vec3.print("jointIndex = " + jointList[i] + " = " + i, MyAvatar.getJointPosition(jointList[i])); +//} +//print("# Joint list end"); + + + + function isLocked(properties) { // special case to lock the ground plane model in hq. if (location.hostname == "hq.highfidelity.io" && @@ -81,6 +92,7 @@ function controller(wichSide) { this.grabbing = false; this.modelID = { isKnownID: false }; + this.modelURL = ""; this.oldModelRotation; this.oldModelPosition; this.oldModelRadius; @@ -134,6 +146,7 @@ function controller(wichSide) { this.grabbing = true; this.modelID = modelID; + this.modelURL = properties.modelURL; this.oldModelPosition = properties.position; this.oldModelRotation = properties.modelRotation; @@ -142,6 +155,39 @@ function controller(wichSide) { } this.release = function () { + if (this.grabbing) { + var closestJointIndex = -1; + var closestJointDistance = 10; + for (var i = 0; i < jointList.length; i++) { + var distance = Vec3.distance(MyAvatar.getJointPosition(jointList[i]), this.oldModelPosition); + if (distance < closestJointDistance) { + closestJointDistance = distance; + closestJointIndex = i; + } + } + + print("closestJointIndex: " + closestJointIndex); + print("closestJointDistance: " + closestJointDistance); + + if (closestJointDistance < 0.1) { + print("Attaching to " + jointList[closestJointIndex]); + var jointPosition = MyAvatar.getJointPosition(jointList[closestJointIndex]); + var jointRotation = MyAvatar.getJointCombinedRotation(jointList[closestJointIndex]); + + var attachmentOffset = Vec3.multiply(Vec3.subtract(this.oldModelPosition, jointPosition), 2); + attachmentOffset = Vec3.multiplyQbyV(Quat.inverse(jointRotation), attachmentOffset); + var attachmentRotation = Quat.multiply(Quat.inverse(jointRotation), this.oldModelRotation); + + MyAvatar.attach(this.modelURL, jointList[closestJointIndex], + attachmentOffset, attachmentRotation, 0.75, + true, false); + Vec3.print("offset: ", attachmentOffset); + Vec3.print("joint: ", Quat.safeEulerAngles(jointRotation)); + Vec3.print("model: ", Quat.safeEulerAngles(this.oldModelRotation)); + Vec3.print("delta: ", Quat.safeEulerAngles(attachmentRotation)); + } + } + this.grabbing = false; this.modelID.isKnownID = false; } @@ -259,6 +305,20 @@ function controller(wichSide) { this.oldModelRotation = newRotation; this.oldModelPosition = newPosition; + + + var closestJointIndex = -1; + var closestJointDistance = 10; + for (var i = 0; i < jointList.length; i++) { + var distance = Vec3.distance(MyAvatar.getJointPosition(jointList[i]), newPosition); + if (distance < closestJointDistance) { + closestJointDistance = distance; + closestJointIndex = i; + } + } +// +// print("closestJointIndex: " + closestJointIndex); +// print("closestJointDistance: " + closestJointDistance); } } @@ -408,8 +468,51 @@ function checkController(deltaTime) { } moveOverlays(); + + + + leftController.hideLaser(); + rightController.hideLaser(); + var jointPos = MyAvatar.getJointPosition("RightHand"); + var jointRot = MyAvatar.getJointCombinedRotation("RightHand"); + + Overlays.editOverlay(r, { + position: jointPos, + end: Vec3.sum(jointPos, Vec3.multiplyQbyV(jointRot, { x:1, y:0, z:0 })) + }); + Overlays.editOverlay(g, { + position: jointPos, + end: Vec3.sum(jointPos, Vec3.multiplyQbyV(jointRot, { x:0, y:1, z:0 })) + }); + Overlays.editOverlay(b, { + position: jointPos, + end: Vec3.sum(jointPos, Vec3.multiplyQbyV(jointRot, { x:0, y:0, z:1 })) + }); } - +var r = Overlays.addOverlay("line3d", { + position: { x: 0, y: 0, z: 0 }, + end: { x: 0, y: 0, z: 0 }, + color: { red: 255, green: 0, blue: 0 }, + alpha: 1, + visible: true, + lineWidth: LASER_WIDTH + }); +var g = Overlays.addOverlay("line3d", { + position: { x: 0, y: 0, z: 0 }, + end: { x: 0, y: 0, z: 0 }, + color: { red: 0, green: 255, blue: 0 }, + alpha: 1, + visible: true, + lineWidth: LASER_WIDTH + }); +var b = Overlays.addOverlay("line3d", { + position: { x: 0, y: 0, z: 0 }, + end: { x: 0, y: 0, z: 0 }, + color: { red: 0, green: 0, blue: 255 }, + alpha: 1, + visible: true, + lineWidth: LASER_WIDTH + }); function initToolBar() { @@ -686,6 +789,10 @@ function scriptEnding() { rightController.cleanup(); toolBar.cleanup(); cleanupModelMenus(); + + Overlays.deleteOverlay(r); + Overlays.deleteOverlay(g); + Overlays.deleteOverlay(b); } Script.scriptEnding.connect(scriptEnding); From ff77644caa90fd668c4f9093e2ab7be726edc651 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 28 May 2014 18:35:30 -0700 Subject: [PATCH 06/27] Progress on selecting cascades. --- interface/resources/shaders/shadow_map.frag | 14 ++++++++++---- interface/resources/shaders/shadow_map.vert | 14 +++++--------- interface/src/Application.cpp | 5 ++--- interface/src/Application.h | 1 + interface/src/voxels/VoxelSystem.cpp | 2 ++ 5 files changed, 20 insertions(+), 16 deletions(-) diff --git a/interface/resources/shaders/shadow_map.frag b/interface/resources/shaders/shadow_map.frag index f53c66b095..f2246fff55 100644 --- a/interface/resources/shaders/shadow_map.frag +++ b/interface/resources/shaders/shadow_map.frag @@ -13,11 +13,17 @@ uniform sampler2DShadow shadowMap; +uniform vec3 shadowDistances; + +// the color in shadow varying vec4 shadowColor; +// the interpolated position +varying vec4 position; + void main(void) { - gl_FragColor = mix(shadowColor, gl_Color, shadow2D(shadowMap, gl_TexCoord[0].stp).r * - shadow2D(shadowMap, gl_TexCoord[1].stp).r * - shadow2D(shadowMap, gl_TexCoord[2].stp).r * - shadow2D(shadowMap, gl_TexCoord[3].stp).r); + int shadowIndex = int(dot(step(vec3(position.z), shadowDistances), vec3(1.0, 1.0, 1.0))); + vec3 texCoord = vec3(dot(gl_EyePlaneS[shadowIndex], position), dot(gl_EyePlaneT[shadowIndex], position), + dot(gl_EyePlaneR[shadowIndex], position)); + gl_FragColor = mix(shadowColor, gl_Color, shadow2D(shadowMap, texCoord).r); } diff --git a/interface/resources/shaders/shadow_map.vert b/interface/resources/shaders/shadow_map.vert index e7efcd7c0f..dcc5324927 100644 --- a/interface/resources/shaders/shadow_map.vert +++ b/interface/resources/shaders/shadow_map.vert @@ -11,8 +11,12 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +// the color in shadow varying vec4 shadowColor; +// the interpolated position +varying vec4 position; + void main(void) { // the shadow color includes only the ambient terms shadowColor = gl_Color * (gl_LightModel.ambient + gl_LightSource[0].ambient); @@ -22,15 +26,7 @@ void main(void) { gl_FrontColor = shadowColor + gl_Color * (gl_LightSource[0].diffuse * max(0.0, dot(normal, gl_LightSource[0].position))); // generate the shadow texture coordinates using the eye position - vec4 eyePosition = gl_ModelViewMatrix * gl_Vertex; - gl_TexCoord[0] = vec4(dot(gl_EyePlaneS[0], eyePosition), dot(gl_EyePlaneT[0], eyePosition), - dot(gl_EyePlaneR[0], eyePosition), 1.0); - gl_TexCoord[1] = vec4(dot(gl_EyePlaneS[1], eyePosition), dot(gl_EyePlaneT[1], eyePosition), - dot(gl_EyePlaneR[1], eyePosition), 1.0); - gl_TexCoord[2] = vec4(dot(gl_EyePlaneS[2], eyePosition), dot(gl_EyePlaneT[2], eyePosition), - dot(gl_EyePlaneR[2], eyePosition), 1.0); - gl_TexCoord[3] = vec4(dot(gl_EyePlaneS[3], eyePosition), dot(gl_EyePlaneT[3], eyePosition), - dot(gl_EyePlaneR[3], eyePosition), 1.0); + position = gl_ModelViewMatrix * gl_Vertex; // use the fixed function transform gl_Position = ftransform(); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0cae0f3e75..a2892eb003 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2260,7 +2260,6 @@ void Application::updateShadowMap() { glm::quat rotation = rotationBetween(IDENTITY_FRONT, lightDirection); glm::quat inverseRotation = glm::inverse(rotation); - const float MAP_DISTANCES[] = { 0.0f, 2.0f, 6.0f, 14.0f, 30.0f }; const glm::vec2 MAP_COORDS[] = { glm::vec2(0.0f, 0.0f), glm::vec2(0.5f, 0.0f), glm::vec2(0.0f, 0.5f), glm::vec2(0.5f, 0.5f) }; @@ -2272,8 +2271,8 @@ void Application::updateShadowMap() { const glm::vec2& coord = MAP_COORDS[i]; glViewport(coord.s * fbo->width(), coord.t * fbo->height(), halfSize, halfSize); - float nearScale = MAP_DISTANCES[i] * frustumScale; - float farScale = MAP_DISTANCES[i + 1] * frustumScale; + float nearScale = SHADOW_MATRIX_DISTANCES[i] * frustumScale; + float farScale = SHADOW_MATRIX_DISTANCES[i + 1] * frustumScale; glm::vec3 points[] = { glm::mix(_viewFrustum.getNearTopLeft(), _viewFrustum.getFarTopLeft(), nearScale), glm::mix(_viewFrustum.getNearTopRight(), _viewFrustum.getFarTopRight(), nearScale), diff --git a/interface/src/Application.h b/interface/src/Application.h index 5d29a9057a..59f9ad4e15 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -127,6 +127,7 @@ static const float MIRROR_REARVIEW_BODY_DISTANCE = 2.3f; static const float MIRROR_FIELD_OF_VIEW = 30.0f; static const int SHADOW_MATRIX_COUNT = 4; +static const float SHADOW_MATRIX_DISTANCES[] = { 0.0f, 2.0f, 6.0f, 14.0f, 30.0f }; class Application : public QApplication { Q_OBJECT diff --git a/interface/src/voxels/VoxelSystem.cpp b/interface/src/voxels/VoxelSystem.cpp index 4f1b322455..11bd47b7e4 100644 --- a/interface/src/voxels/VoxelSystem.cpp +++ b/interface/src/voxels/VoxelSystem.cpp @@ -518,6 +518,8 @@ void VoxelSystem::initVoxelMemory() { _shadowMapProgram.bind(); _shadowMapProgram.setUniformValue("shadowMap", 0); + _shadowMapProgram.setUniformValue("shadowDistances", -SHADOW_MATRIX_DISTANCES[1], + -SHADOW_MATRIX_DISTANCES[2], -SHADOW_MATRIX_DISTANCES[3]); _shadowMapProgram.release(); } } From e6966c2155e0561cf34d343047776f98da7ff35a Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 29 May 2014 12:12:23 -0700 Subject: [PATCH 07/27] add improved detailed rendering and FPS debugging stats --- interface/src/Application.cpp | 129 ++++++++++++++++++++------ interface/src/Menu.cpp | 9 +- interface/src/Menu.h | 5 + interface/src/renderer/GlowEffect.cpp | 4 + interface/src/ui/Stats.cpp | 73 ++++++++++++++- interface/src/ui/Stats.h | 1 + libraries/shared/src/PerfStat.cpp | 18 ++++ libraries/shared/src/PerfStat.h | 37 ++++++++ 8 files changed, 245 insertions(+), 31 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4ee15bc949..db6333acee 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -554,6 +554,8 @@ void Application::initializeGL() { } void Application::paintGL() { + PerformanceTimer perfTimer("paintGL"); + PerformanceWarning::setSuppressShortTimings(Menu::getInstance()->isOptionChecked(MenuOption::SuppressShortTimings)); bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::paintGL()"); @@ -648,7 +650,10 @@ void Application::paintGL() { _rearMirrorTools->render(true); } - _applicationOverlay.renderOverlay(); + { + PerformanceTimer perfTimer("paintGL/renderOverlay"); + _applicationOverlay.renderOverlay(); + } } _frameCount++; @@ -1288,11 +1293,13 @@ void Application::timer() { } void Application::idle() { + PerformanceTimer perfTimer("idle"); + // Normally we check PipelineWarnings, but since idle will often take more than 10ms we only show these idle timing // details if we're in ExtraDebugging mode. However, the ::update() and it's subcomponents will show their timing // details normally. bool showWarnings = getLogger()->extraDebugging(); - PerformanceWarning warn(showWarnings, "Application::idle()"); + PerformanceWarning warn(showWarnings, "idle()"); // Only run simulation code if more than IDLE_SIMULATE_MSECS have passed since last time we ran @@ -1300,15 +1307,18 @@ void Application::idle() { if (timeSinceLastUpdate > IDLE_SIMULATE_MSECS) { _lastTimeUpdated.start(); { + PerformanceTimer perfTimer("idle/update"); PerformanceWarning warn(showWarnings, "Application::idle()... update()"); const float BIGGEST_DELTA_TIME_SECS = 0.25f; update(glm::clamp((float)timeSinceLastUpdate / 1000.f, 0.f, BIGGEST_DELTA_TIME_SECS)); } { + PerformanceTimer perfTimer("idle/updateGL"); PerformanceWarning warn(showWarnings, "Application::idle()... updateGL()"); _glWidget->updateGL(); } { + PerformanceTimer perfTimer("idle/rest"); PerformanceWarning warn(showWarnings, "Application::idle()... rest of it"); _idleLoopStdev.addValue(timeSinceLastUpdate); @@ -1320,14 +1330,16 @@ void Application::idle() { } if (Menu::getInstance()->isOptionChecked(MenuOption::BuckyBalls)) { + PerformanceTimer perfTimer("idle/rest/_buckyBalls"); _buckyBalls.simulate(timeSinceLastUpdate / 1000.f, Application::getInstance()->getAvatar()->getHandData()); } // After finishing all of the above work, restart the idle timer, allowing 2ms to process events. idleTimer->start(2); - } - if (_numChangedSettings > 0) { - saveSettings(); + + if (_numChangedSettings > 0) { + saveSettings(); + } } } } @@ -1729,6 +1741,7 @@ bool Application::isLookingAtMyAvatar(Avatar* avatar) { } void Application::updateLOD() { + PerformanceTimer perfTimer("idle/update/updateLOD"); // adjust it unless we were asked to disable this feature, or if we're currently in throttleRendering mode if (!Menu::getInstance()->isOptionChecked(MenuOption::DisableAutoAdjustLOD) && !isThrottleRendering()) { Menu::getInstance()->autoAdjustLOD(_fps); @@ -1738,6 +1751,7 @@ void Application::updateLOD() { } void Application::updateMouseRay() { + PerformanceTimer perfTimer("idle/update/updateMouseRay"); bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::updateMouseRay()"); @@ -1770,6 +1784,7 @@ void Application::updateMouseRay() { } void Application::updateFaceshift() { + PerformanceTimer perfTimer("idle/update/updateFaceshift"); bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::updateFaceshift()"); @@ -1784,6 +1799,7 @@ void Application::updateFaceshift() { } void Application::updateVisage() { + PerformanceTimer perfTimer("idle/update/updateVisage"); bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::updateVisage()"); @@ -1793,6 +1809,7 @@ void Application::updateVisage() { } void Application::updateMyAvatarLookAtPosition() { + PerformanceTimer perfTimer("idle/update/updateMyAvatarLookAtPosition"); bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::updateMyAvatarLookAtPosition()"); @@ -1858,6 +1875,7 @@ void Application::updateMyAvatarLookAtPosition() { } void Application::updateThreads(float deltaTime) { + PerformanceTimer perfTimer("idle/update/updateThreads"); bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::updateThreads()"); @@ -1872,6 +1890,7 @@ void Application::updateThreads(float deltaTime) { } void Application::updateMetavoxels(float deltaTime) { + PerformanceTimer perfTimer("idle/update/updateMetavoxels"); bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::updateMetavoxels()"); @@ -1901,6 +1920,7 @@ void Application::cameraMenuChanged() { } void Application::updateCamera(float deltaTime) { + PerformanceTimer perfTimer("idle/update/updateCamera"); bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::updateCamera()"); @@ -1918,6 +1938,7 @@ void Application::updateCamera(float deltaTime) { } void Application::updateDialogs(float deltaTime) { + PerformanceTimer perfTimer("idle/update/updateDialogs"); bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::updateDialogs()"); @@ -1934,6 +1955,7 @@ void Application::updateDialogs(float deltaTime) { } void Application::updateCursor(float deltaTime) { + PerformanceTimer perfTimer("idle/update/updateCursor"); bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::updateCursor()"); @@ -1958,41 +1980,66 @@ void Application::updateCursor(float deltaTime) { } void Application::update(float deltaTime) { + //PerformanceTimer perfTimer("idle/update"); // NOTE: we track this above in Application::idle() + bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::update()"); updateLOD(); - - // check what's under the mouse and update the mouse voxel - updateMouseRay(); - + updateMouseRay(); // check what's under the mouse and update the mouse voxel updateFaceshift(); updateVisage(); - _myAvatar->updateLookAtTargetAvatar(); + + { + PerformanceTimer perfTimer("idle/update/updateLookAtTargetAvatar"); + _myAvatar->updateLookAtTargetAvatar(); + } updateMyAvatarLookAtPosition(); - _sixenseManager.update(deltaTime); - _joystickManager.update(); - _prioVR.update(deltaTime); + { + PerformanceTimer perfTimer("idle/update/sixense,joystick,prioVR"); + _sixenseManager.update(deltaTime); + _joystickManager.update(); + _prioVR.update(deltaTime); + } updateMyAvatar(deltaTime); // Sample hardware, update view frustum if needed, and send avatar data to mixer/nodes updateThreads(deltaTime); // If running non-threaded, then give the threads some time to process... - _avatarManager.updateOtherAvatars(deltaTime); //loop through all the other avatars and simulate them... + { + PerformanceTimer perfTimer("idle/update/_avatarManager"); + _avatarManager.updateOtherAvatars(deltaTime); //loop through all the other avatars and simulate them... + } updateMetavoxels(deltaTime); // update metavoxels updateCamera(deltaTime); // handle various camera tweaks like off axis projection updateDialogs(deltaTime); // update various stats dialogs if present updateCursor(deltaTime); // Handle cursor updates - _particles.update(); // update the particles... - _particleCollisionSystem.update(); // collide the particles... + { + PerformanceTimer perfTimer("idle/update/_particles"); + _particles.update(); // update the particles... + } + { + PerformanceTimer perfTimer("idle/update/_particleCollisionSystem"); + _particleCollisionSystem.update(); // collide the particles... + } - _models.update(); // update the models... + { + PerformanceTimer perfTimer("idle/update/_models"); + _models.update(); // update the models... + } - _overlays.update(deltaTime); + { + PerformanceTimer perfTimer("idle/update/_overlays"); + _overlays.update(deltaTime); + } - // let external parties know we're updating - emit simulating(deltaTime); + { + PerformanceTimer perfTimer("idle/update/emit simulating"); + // let external parties know we're updating + emit simulating(deltaTime); + } } void Application::updateMyAvatar(float deltaTime) { + PerformanceTimer perfTimer("idle/update/updateMyAvatar"); bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::updateMyAvatar()"); @@ -2253,6 +2300,7 @@ glm::vec3 Application::getSunDirection() { } void Application::updateShadowMap() { + PerformanceTimer perfTimer("pintGL/updateShadowMap"); QOpenGLFramebufferObject* fbo = _textureCache.getShadowFramebufferObject(); fbo->bind(); glEnable(GL_DEPTH_TEST); @@ -2392,6 +2440,7 @@ QImage Application::renderAvatarBillboard() { } void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { + PerformanceTimer perfTimer("paintGL/displaySide"); PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide()"); // transform by eye offset @@ -2424,9 +2473,13 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { glTranslatef(_viewMatrixTranslation.x, _viewMatrixTranslation.y, _viewMatrixTranslation.z); // Setup 3D lights (after the camera transform, so that they are positioned in world space) - setupWorldLight(); + { + PerformanceTimer perfTimer("paintGL/displaySide/setupWorldLight"); + setupWorldLight(); + } if (!selfAvatarOnly && Menu::getInstance()->isOptionChecked(MenuOption::Stars)) { + PerformanceTimer perfTimer("paintGL/displaySide/stars"); PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide() ... stars..."); if (!_stars.isStarsLoaded()) { @@ -2455,6 +2508,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { // draw the sky dome if (!selfAvatarOnly && Menu::getInstance()->isOptionChecked(MenuOption::Atmosphere)) { + PerformanceTimer perfTimer("paintGL/displaySide/atmosphere"); PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide() ... atmosphere..."); _environment.renderAtmospheres(whichCamera); @@ -2474,10 +2528,14 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { glMaterialfv(GL_FRONT, GL_SPECULAR, NO_SPECULAR_COLOR); // draw the audio reflector overlay - _audioReflector.render(); - + { + PerformanceTimer perfTimer("paintGL/displaySide/audioReflector"); + _audioReflector.render(); + } + // Draw voxels if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) { + PerformanceTimer perfTimer("paintGL/displaySide/voxels"); PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide() ... voxels..."); _voxels.render(); @@ -2485,12 +2543,14 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { // also, metavoxels if (Menu::getInstance()->isOptionChecked(MenuOption::Metavoxels)) { + PerformanceTimer perfTimer("paintGL/displaySide/metavoxels"); PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide() ... metavoxels..."); _metavoxels.render(); } if (Menu::getInstance()->isOptionChecked(MenuOption::BuckyBalls)) { + PerformanceTimer perfTimer("paintGL/displaySide/buckyBalls"); PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide() ... bucky balls..."); _buckyBalls.render(); @@ -2498,6 +2558,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { // render particles... if (Menu::getInstance()->isOptionChecked(MenuOption::Particles)) { + PerformanceTimer perfTimer("paintGL/displaySide/particles"); PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide() ... particles..."); _particles.render(); @@ -2505,6 +2566,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { // render models... if (Menu::getInstance()->isOptionChecked(MenuOption::Models)) { + PerformanceTimer perfTimer("paintGL/displaySide/models"); PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide() ... models..."); _models.render(); @@ -2512,6 +2574,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { // render the ambient occlusion effect if enabled if (Menu::getInstance()->isOptionChecked(MenuOption::AmbientOcclusion)) { + PerformanceTimer perfTimer("paintGL/displaySide/AmbientOcclusion"); PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide() ... AmbientOcclusion..."); _ambientOcclusionEffect.render(); @@ -2525,16 +2588,21 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { } bool mirrorMode = (whichCamera.getInterpolatedMode() == CAMERA_MODE_MIRROR); - _avatarManager.renderAvatars(mirrorMode ? Avatar::MIRROR_RENDER_MODE : Avatar::NORMAL_RENDER_MODE, selfAvatarOnly); + { + PerformanceTimer perfTimer("paintGL/displaySide/renderAvatars"); + _avatarManager.renderAvatars(mirrorMode ? Avatar::MIRROR_RENDER_MODE : Avatar::NORMAL_RENDER_MODE, selfAvatarOnly); + } if (!selfAvatarOnly) { // Render the world box if (whichCamera.getMode() != CAMERA_MODE_MIRROR && Menu::getInstance()->isOptionChecked(MenuOption::Stats)) { + PerformanceTimer perfTimer("paintGL/displaySide/renderWorldBox"); renderWorldBox(); } - // brad's frustum for debugging + // view frustum for debugging if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayFrustum) && whichCamera.getMode() != CAMERA_MODE_MIRROR) { + PerformanceTimer perfTimer("paintGL/displaySide/ViewFrustum"); PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide() ... renderViewFrustum..."); renderViewFrustum(_viewFrustum); @@ -2542,6 +2610,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { // render voxel fades if they exist if (_voxelFades.size() > 0) { + PerformanceTimer perfTimer("paintGL/displaySide/voxel fades"); PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide() ... voxel fades..."); _voxelFadesLock.lockForWrite(); @@ -2557,10 +2626,16 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { } // give external parties a change to hook in - emit renderingInWorldInterface(); + { + PerformanceTimer perfTimer("paintGL/displaySide/inWorldInterface"); + emit renderingInWorldInterface(); + } // render JS/scriptable overlays - _overlays.render3D(); + { + PerformanceTimer perfTimer("paintGL/displaySide/3dOverlays"); + _overlays.render3D(); + } } } diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 7fd8f26006..25bf65d18e 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -386,8 +386,15 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::AlternateIK, 0, false); addDisabledActionAndSeparator(developerMenu, "Testing"); - + QMenu* timingMenu = developerMenu->addMenu("Timing and Statistics Tools"); + QMenu* perfTimerMenu = timingMenu->addMenu("Performance Timer"); + addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::DisplayTimingDetails, 0, true); + addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandDisplaySideTiming, 0, false); + addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandIdleTiming, 0, false); + addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandPaintGLTiming, 0, false); + addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandUpdateTiming, 0, false); + addCheckableActionToQMenuAndActionHash(timingMenu, MenuOption::TestPing, 0, true); addCheckableActionToQMenuAndActionHash(timingMenu, MenuOption::FrameTimer); addActionToQMenuAndActionHash(timingMenu, MenuOption::RunTimingTests, 0, this, SLOT(runTests())); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 50e59320b9..c1a9e4274b 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -321,10 +321,15 @@ namespace MenuOption { const QString DisplayModelBounds = "Display Model Bounds"; const QString DisplayModelElementProxy = "Display Model Element Bounds"; const QString DisplayModelElementChildProxies = "Display Model Element Children"; + const QString DisplayTimingDetails = "Display Timing Details"; const QString DontFadeOnVoxelServerChanges = "Don't Fade In/Out on Voxel Server Changes"; const QString EchoLocalAudio = "Echo Local Audio"; const QString EchoServerAudio = "Echo Server Audio"; const QString Enable3DTVMode = "Enable 3DTV Mode"; + const QString ExpandDisplaySideTiming = "Expand Display Side Timing"; + const QString ExpandIdleTiming = "Expand Idle Timing"; + const QString ExpandPaintGLTiming = "Expand PaintGL Timing"; + const QString ExpandUpdateTiming = "Expand Update Timing"; const QString Faceplus = "Faceplus"; const QString Faceshift = "Faceshift"; const QString FilterSixense = "Smooth Sixense Movement"; diff --git a/interface/src/renderer/GlowEffect.cpp b/interface/src/renderer/GlowEffect.cpp index 1eceb71752..262a632df0 100644 --- a/interface/src/renderer/GlowEffect.cpp +++ b/interface/src/renderer/GlowEffect.cpp @@ -14,6 +14,8 @@ #include +#include + #include "Application.h" #include "GlowEffect.h" #include "ProgramObject.h" @@ -119,6 +121,8 @@ static void maybeRelease(QOpenGLFramebufferObject* fbo) { } QOpenGLFramebufferObject* GlowEffect::render(bool toTexture) { + PerformanceTimer perfTimer("paintGL/glowEffect"); + QOpenGLFramebufferObject* primaryFBO = Application::getInstance()->getTextureCache()->getPrimaryFramebufferObject(); primaryFBO->release(); glBindTexture(GL_TEXTURE_2D, primaryFBO->texture()); diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp index a391ed239c..d7ca0152fd 100644 --- a/interface/src/ui/Stats.cpp +++ b/interface/src/ui/Stats.cpp @@ -18,6 +18,8 @@ #include #include +#include + #include "Stats.h" #include "InterfaceConfig.h" #include "Menu.h" @@ -158,6 +160,33 @@ void Stats::drawBackground(unsigned int rgba, int x, int y, int width, int heigh glColor4f(1, 1, 1, 1); } +bool Stats::includeTimingRecord(const QString& name) { + bool included = false; + if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayTimingDetails)) { + + if (name == "idle/update") { + included = Menu::getInstance()->isOptionChecked(MenuOption::ExpandUpdateTiming) || + Menu::getInstance()->isOptionChecked(MenuOption::ExpandIdleTiming); + } else if (name == "idle/updateGL") { + included = Menu::getInstance()->isOptionChecked(MenuOption::ExpandIdleTiming); + } else if (name.startsWith("idle/update")) { + included = Menu::getInstance()->isOptionChecked(MenuOption::ExpandUpdateTiming); + } else if (name.startsWith("idle/")) { + included = Menu::getInstance()->isOptionChecked(MenuOption::ExpandIdleTiming); + } else if (name == "paintGL/displaySide") { + included = Menu::getInstance()->isOptionChecked(MenuOption::ExpandDisplaySideTiming) || + Menu::getInstance()->isOptionChecked(MenuOption::ExpandPaintGLTiming); + } else if (name.startsWith("paintGL/displaySide/")) { + included = Menu::getInstance()->isOptionChecked(MenuOption::ExpandDisplaySideTiming); + } else if (name.startsWith("paintGL/")) { + included = Menu::getInstance()->isOptionChecked(MenuOption::ExpandPaintGLTiming); + } else { + included = true; // include everything else + } + } + return included; +} + // display expanded or contracted stats void Stats::display( const float* color, @@ -190,6 +219,9 @@ void Stats::display( int totalServers = NodeList::getInstance()->size(); lines = _expanded ? 5 : 3; + + + drawBackground(backgroundColor, horizontalOffset, 0, _generalStatsWidth, lines * STATS_PELS_PER_LINE + 10); horizontalOffset += 5; @@ -345,11 +377,25 @@ void Stats::display( VoxelSystem* voxels = Application::getInstance()->getVoxels(); - lines = _expanded ? 12 : 3; + lines = _expanded ? 11 : 3; if (_expanded && Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessing)) { lines += 9; // spatial audio processing adds 1 spacing line and 8 extra lines of info } + if (_expanded && Menu::getInstance()->isOptionChecked(MenuOption::DisplayTimingDetails)) { + // we will also include room for 1 line per timing record and a header + lines += 1; + + const QMap& allRecords = PerformanceTimer::getAllTimerRecords(); + QMapIterator i(allRecords); + while (i.hasNext()) { + i.next(); + if (includeTimingRecord(i.key())) { + lines++; + } + } + } + drawBackground(backgroundColor, horizontalOffset, 0, glWidget->width() - horizontalOffset, lines * STATS_PELS_PER_LINE + 10); horizontalOffset += 5; @@ -454,8 +500,6 @@ void Stats::display( } } - verticalOffset += (_expanded ? STATS_PELS_PER_LINE : 0); - QString serversTotalString = locale.toString((uint)totalNodes); // consider adding: .rightJustified(10, ' '); // Server Voxels @@ -508,6 +552,29 @@ void Stats::display( drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)voxelStats.str().c_str(), color); } + // TODO: the display of these timing details should all be moved to JavaScript + if (_expanded && Menu::getInstance()->isOptionChecked(MenuOption::DisplayTimingDetails)) { + // Timing details... + const int TIMER_OUTPUT_LINE_LENGTH = 300; + char perfLine[TIMER_OUTPUT_LINE_LENGTH]; + verticalOffset += STATS_PELS_PER_LINE; + drawText(horizontalOffset, verticalOffset, scale, rotation, font, + "---------------- Function --------------- --msecs- -calls--", color); + + const QMap& allRecords = PerformanceTimer::getAllTimerRecords(); + QMapIterator i(allRecords); + while (i.hasNext()) { + i.next(); + if (includeTimingRecord(i.key())) { + sprintf(perfLine, "%40s: %8.4f [%6llu]", qPrintable(i.key()), + (float)i.value().getMovingAverage() / (float)USECS_PER_MSEC, + i.value().getCount()); + + verticalOffset += STATS_PELS_PER_LINE; + drawText(horizontalOffset, verticalOffset, scale, rotation, font, perfLine, color); + } + } + } if (_expanded && Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessing)) { verticalOffset += STATS_PELS_PER_LINE; // space one line... diff --git a/interface/src/ui/Stats.h b/interface/src/ui/Stats.h index 1ce0807ee8..66d6ec99f0 100644 --- a/interface/src/ui/Stats.h +++ b/interface/src/ui/Stats.h @@ -30,6 +30,7 @@ public: void checkClick(int mouseX, int mouseY, int mouseDragStartedX, int mouseDragStartedY, int horizontalOffset); void resetWidth(int width, int horizontalOffset); void display(const float* color, int horizontalOffset, float fps, int packetsPerSecond, int bytesPerSecond, int voxelPacketsToProcess); + bool includeTimingRecord(const QString& name); private: static Stats* _sharedInstance; diff --git a/libraries/shared/src/PerfStat.cpp b/libraries/shared/src/PerfStat.cpp index 9235cb3f25..4dca3f3d49 100644 --- a/libraries/shared/src/PerfStat.cpp +++ b/libraries/shared/src/PerfStat.cpp @@ -52,4 +52,22 @@ PerformanceWarning::~PerformanceWarning() { } }; +QMap PerformanceTimer::_records; + +PerformanceTimer::~PerformanceTimer() { + quint64 end = usecTimestampNow(); + quint64 elapsedusec = (end - _start); + PerformanceTimerRecord& namedRecord = _records[_name]; + namedRecord.recordResult(elapsedusec); +} + +void PerformanceTimer::dumpAllTimerRecords() { + QMapIterator i(_records); + while (i.hasNext()) { + i.next(); + qDebug() << i.key() << ": average " << i.value().getAverage() + << " [" << i.value().getMovingAverage() << "]" + << "usecs over" << i.value().getCount() << "calls"; + } +} diff --git a/libraries/shared/src/PerfStat.h b/libraries/shared/src/PerfStat.h index 22cf14f207..f849fb844c 100644 --- a/libraries/shared/src/PerfStat.h +++ b/libraries/shared/src/PerfStat.h @@ -17,6 +17,7 @@ #include #include "SharedUtil.h" +#include "SimpleMovingAverage.h" #include #include @@ -49,5 +50,41 @@ public: static void setSuppressShortTimings(bool suppressShortTimings) { _suppressShortTimings = suppressShortTimings; } }; +class PerformanceTimerRecord { +public: + PerformanceTimerRecord() : _runningTotal(0), _totalCalls(0) {} + + void recordResult(quint64 elapsed) { _runningTotal += elapsed; _totalCalls++; _movingAverage.updateAverage(elapsed); } + quint64 getAverage() const { return (_totalCalls == 0) ? 0 : _runningTotal / _totalCalls; } + quint64 getMovingAverage() const { return (_totalCalls == 0) ? 0 : _movingAverage.getAverage(); } + quint64 getCount() const { return _totalCalls; } + +private: + quint64 _runningTotal; + quint64 _totalCalls; + SimpleMovingAverage _movingAverage; +}; + +class PerformanceTimer { +public: + + PerformanceTimer(const QString& name) : + _start(usecTimestampNow()), + _name(name) { } + + quint64 elapsed() const { return (usecTimestampNow() - _start); }; + + ~PerformanceTimer(); + + static const PerformanceTimerRecord& getTimerRecord(const QString& name) { return _records[name]; }; + static const QMap& getAllTimerRecords() { return _records; }; + static void dumpAllTimerRecords(); + +private: + quint64 _start; + QString _name; + static QMap _records; +}; + #endif // hifi_PerfStat_h From 09231f01f3e96a293ffe6280e200c46b8030a7b8 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 29 May 2014 12:48:41 -0700 Subject: [PATCH 08/27] Retain "simple" shadows, supply cascaded as option. --- .../shaders/cascaded_shadow_map.frag | 29 ++++++++++++++ .../shaders/cascaded_shadow_map.vert | 33 ++++++++++++++++ interface/resources/shaders/shadow_map.frag | 15 ++++---- interface/resources/shaders/shadow_map.vert | 7 ++-- interface/src/Application.cpp | 34 ++++++++++++++--- interface/src/Application.h | 6 +-- interface/src/Menu.cpp | 15 ++++++-- interface/src/Menu.h | 7 +++- interface/src/renderer/Model.cpp | 10 +---- interface/src/voxels/VoxelSystem.cpp | 38 ++++++++++++------- interface/src/voxels/VoxelSystem.h | 1 + 11 files changed, 146 insertions(+), 49 deletions(-) create mode 100644 interface/resources/shaders/cascaded_shadow_map.frag create mode 100644 interface/resources/shaders/cascaded_shadow_map.vert diff --git a/interface/resources/shaders/cascaded_shadow_map.frag b/interface/resources/shaders/cascaded_shadow_map.frag new file mode 100644 index 0000000000..9b3e8f7cc7 --- /dev/null +++ b/interface/resources/shaders/cascaded_shadow_map.frag @@ -0,0 +1,29 @@ +#version 120 + +// +// cascaded_shadow_map.frag +// fragment shader +// +// Created by Andrzej Kapolka on 5/29/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +uniform sampler2DShadow shadowMap; + +uniform vec3 shadowDistances; + +// the color in shadow +varying vec4 shadowColor; + +// the interpolated position +varying vec4 position; + +void main(void) { + int shadowIndex = int(dot(step(vec3(position.z), shadowDistances), vec3(1.0, 1.0, 1.0))); + vec3 texCoord = vec3(dot(gl_EyePlaneS[shadowIndex], position), dot(gl_EyePlaneT[shadowIndex], position), + dot(gl_EyePlaneR[shadowIndex], position)); + gl_FragColor = mix(shadowColor, gl_Color, shadow2D(shadowMap, texCoord).r); +} diff --git a/interface/resources/shaders/cascaded_shadow_map.vert b/interface/resources/shaders/cascaded_shadow_map.vert new file mode 100644 index 0000000000..68ff95b28a --- /dev/null +++ b/interface/resources/shaders/cascaded_shadow_map.vert @@ -0,0 +1,33 @@ +#version 120 + +// +// cascaded_shadow_map.vert +// vertex shader +// +// Created by Andrzej Kapolka on 5/29/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +// the color in shadow +varying vec4 shadowColor; + +// the interpolated position +varying vec4 position; + +void main(void) { + // the shadow color includes only the ambient terms + shadowColor = gl_Color * (gl_LightModel.ambient + gl_LightSource[0].ambient); + + // the normal color includes diffuse + vec4 normal = normalize(gl_ModelViewMatrix * vec4(gl_Normal, 0.0)); + gl_FrontColor = shadowColor + gl_Color * (gl_LightSource[0].diffuse * max(0.0, dot(normal, gl_LightSource[0].position))); + + // generate the shadow texture coordinates using the eye position + position = gl_ModelViewMatrix * gl_Vertex; + + // use the fixed function transform + gl_Position = ftransform(); +} diff --git a/interface/resources/shaders/shadow_map.frag b/interface/resources/shaders/shadow_map.frag index f2246fff55..fa79040ce3 100644 --- a/interface/resources/shaders/shadow_map.frag +++ b/interface/resources/shaders/shadow_map.frag @@ -13,17 +13,16 @@ uniform sampler2DShadow shadowMap; -uniform vec3 shadowDistances; +// the inverse of the size of the shadow map +const float shadowScale = 1.0 / 2048.0; // the color in shadow varying vec4 shadowColor; -// the interpolated position -varying vec4 position; - void main(void) { - int shadowIndex = int(dot(step(vec3(position.z), shadowDistances), vec3(1.0, 1.0, 1.0))); - vec3 texCoord = vec3(dot(gl_EyePlaneS[shadowIndex], position), dot(gl_EyePlaneT[shadowIndex], position), - dot(gl_EyePlaneR[shadowIndex], position)); - gl_FragColor = mix(shadowColor, gl_Color, shadow2D(shadowMap, texCoord).r); + gl_FragColor = mix(shadowColor, gl_Color, 0.25 * + (shadow2D(shadowMap, gl_TexCoord[0].stp + vec3(-shadowScale, -shadowScale, 0.0)).r + + shadow2D(shadowMap, gl_TexCoord[0].stp + vec3(-shadowScale, shadowScale, 0.0)).r + + shadow2D(shadowMap, gl_TexCoord[0].stp + vec3(shadowScale, -shadowScale, 0.0)).r + + shadow2D(shadowMap, gl_TexCoord[0].stp + vec3(shadowScale, shadowScale, 0.0)).r)); } diff --git a/interface/resources/shaders/shadow_map.vert b/interface/resources/shaders/shadow_map.vert index dcc5324927..5d2affba98 100644 --- a/interface/resources/shaders/shadow_map.vert +++ b/interface/resources/shaders/shadow_map.vert @@ -14,9 +14,6 @@ // the color in shadow varying vec4 shadowColor; -// the interpolated position -varying vec4 position; - void main(void) { // the shadow color includes only the ambient terms shadowColor = gl_Color * (gl_LightModel.ambient + gl_LightSource[0].ambient); @@ -26,7 +23,9 @@ void main(void) { gl_FrontColor = shadowColor + gl_Color * (gl_LightSource[0].diffuse * max(0.0, dot(normal, gl_LightSource[0].position))); // generate the shadow texture coordinates using the eye position - position = gl_ModelViewMatrix * gl_Vertex; + vec4 eyePosition = gl_ModelViewMatrix * gl_Vertex; + gl_TexCoord[0] = vec4(dot(gl_EyePlaneS[0], eyePosition), dot(gl_EyePlaneT[0], eyePosition), + dot(gl_EyePlaneR[0], eyePosition), 1.0); // use the fixed function transform gl_Position = ftransform(); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index a2892eb003..af94ddba01 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -616,7 +616,7 @@ void Application::paintGL() { whichCamera = _viewFrustumOffsetCamera; } - if (Menu::getInstance()->isOptionChecked(MenuOption::Shadows)) { + if (Menu::getInstance()->getShadowsEnabled()) { updateShadowMap(); } @@ -2263,13 +2263,20 @@ void Application::updateShadowMap() { const glm::vec2 MAP_COORDS[] = { glm::vec2(0.0f, 0.0f), glm::vec2(0.5f, 0.0f), glm::vec2(0.0f, 0.5f), glm::vec2(0.5f, 0.5f) }; - int halfSize = fbo->width() / 2; float frustumScale = 1.0f / (_viewFrustum.getFarClip() - _viewFrustum.getNearClip()); loadViewFrustum(_myCamera, _viewFrustum); - for (int i = 0; i < SHADOW_MATRIX_COUNT; i++) { + int matrixCount = 1; + int targetSize = fbo->width(); + float targetScale = 1.0f; + if (Menu::getInstance()->isOptionChecked(MenuOption::CascadedShadows)) { + matrixCount = CASCADED_SHADOW_MATRIX_COUNT; + targetSize = fbo->width() / 2; + targetScale = 0.5f; + } + for (int i = 0; i < matrixCount; i++) { const glm::vec2& coord = MAP_COORDS[i]; - glViewport(coord.s * fbo->width(), coord.t * fbo->height(), halfSize, halfSize); + glViewport(coord.s * fbo->width(), coord.t * fbo->height(), targetSize, targetSize); float nearScale = SHADOW_MATRIX_DISTANCES[i] * frustumScale; float farScale = SHADOW_MATRIX_DISTANCES[i + 1] * frustumScale; @@ -2294,7 +2301,7 @@ void Application::updateShadowMap() { center = inverseRotation * center; // to reduce texture "shimmer," move in texel increments - float texelSize = (2.0f * radius) / halfSize; + float texelSize = (2.0f * radius) / targetSize; center = glm::vec3(roundf(center.x / texelSize) * texelSize, roundf(center.y / texelSize) * texelSize, roundf(center.z / texelSize) * texelSize); @@ -2306,7 +2313,8 @@ void Application::updateShadowMap() { maxima.z += _viewFrustum.getFarClip() * 0.5f; // save the combined matrix for rendering - _shadowMatrices[i] = glm::transpose(glm::translate(glm::vec3(coord, 0.0f)) * glm::scale(glm::vec3(0.5f, 0.5f, 1.0f)) * + _shadowMatrices[i] = glm::transpose(glm::translate(glm::vec3(coord, 0.0f)) * + glm::scale(glm::vec3(targetScale, targetScale, 1.0f)) * glm::translate(glm::vec3(0.5f, 0.5f, 0.5f)) * glm::scale(glm::vec3(0.5f, 0.5f, 0.5f)) * glm::ortho(minima.x, maxima.x, minima.y, maxima.y, -maxima.z, -minima.z) * glm::mat4_cast(inverseRotation)); @@ -2433,6 +2441,20 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { // Setup 3D lights (after the camera transform, so that they are positioned in world space) setupWorldLight(); + // setup shadow matrices (again, after the camera transform) + int shadowMatrixCount = 0; + if (Menu::getInstance()->isOptionChecked(MenuOption::SimpleShadows)) { + shadowMatrixCount = 1; + } else if (Menu::getInstance()->isOptionChecked(MenuOption::CascadedShadows)) { + shadowMatrixCount = CASCADED_SHADOW_MATRIX_COUNT; + } + for (int i = shadowMatrixCount - 1; i >= 0; i--) { + glActiveTexture(GL_TEXTURE0 + i); + glTexGenfv(GL_S, GL_EYE_PLANE, (const GLfloat*)&_shadowMatrices[i][0]); + glTexGenfv(GL_T, GL_EYE_PLANE, (const GLfloat*)&_shadowMatrices[i][1]); + glTexGenfv(GL_R, GL_EYE_PLANE, (const GLfloat*)&_shadowMatrices[i][2]); + } + if (!selfAvatarOnly && Menu::getInstance()->isOptionChecked(MenuOption::Stars)) { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide() ... stars..."); diff --git a/interface/src/Application.h b/interface/src/Application.h index 59f9ad4e15..68d437815b 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -126,7 +126,6 @@ static const float MIRROR_REARVIEW_DISTANCE = 0.65f; static const float MIRROR_REARVIEW_BODY_DISTANCE = 2.3f; static const float MIRROR_FIELD_OF_VIEW = 30.0f; -static const int SHADOW_MATRIX_COUNT = 4; static const float SHADOW_MATRIX_DISTANCES[] = { 0.0f, 2.0f, 6.0f, 14.0f, 30.0f }; class Application : public QApplication { @@ -264,8 +263,6 @@ public: /// result from matrix multiplication at high translation magnitudes. void loadTranslatedViewMatrix(const glm::vec3& translation); - const glm::mat4* getShadowMatrices() const { return _shadowMatrices; } - void getModelViewMatrix(glm::dmat4* modelViewMatrix); void getProjectionMatrix(glm::dmat4* projectionMatrix); @@ -494,7 +491,8 @@ private: float _rotateMirror; float _raiseMirror; - glm::mat4 _shadowMatrices[SHADOW_MATRIX_COUNT]; + static const int CASCADED_SHADOW_MATRIX_COUNT = 4; + glm::mat4 _shadowMatrices[CASCADED_SHADOW_MATRIX_COUNT]; Environment _environment; diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 45b4089a11..ef5ffeaaf1 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -303,7 +303,12 @@ Menu::Menu() : appInstance->getGlowEffect(), SLOT(cycleRenderMode())); - addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Shadows, 0, false); + QMenu* shadowMenu = renderOptionsMenu->addMenu("Shadows"); + QActionGroup* shadowGroup = new QActionGroup(shadowMenu); + shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, "None", 0, true)); + shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, MenuOption::SimpleShadows, 0, false)); + shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, MenuOption::CascadedShadows, 0, false)); + addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Metavoxels, 0, true); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::BuckyBalls, 0, false); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Particles, 0, true); @@ -666,6 +671,10 @@ void Menu::scanMenu(QMenu* menu, settingsAction modifySetting, QSettings* set) { set->endGroup(); } +bool Menu::getShadowsEnabled() const { + return isOptionChecked(MenuOption::SimpleShadows) || isOptionChecked(MenuOption::CascadedShadows); +} + void Menu::handleViewFrustumOffsetKeyModifier(int key) { const float VIEW_FRUSTUM_OFFSET_DELTA = 0.5f; const float VIEW_FRUSTUM_OFFSET_UP_DELTA = 0.05f; @@ -836,8 +845,8 @@ void Menu::setIsOptionChecked(const QString& menuOption, bool isChecked) { } } -bool Menu::isOptionChecked(const QString& menuOption) { - QAction* menu = _actionHash.value(menuOption); +bool Menu::isOptionChecked(const QString& menuOption) const { + const QAction* menu = _actionHash.value(menuOption); if (menu) { return menu->isChecked(); } diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 012dc1662c..e973ae88b3 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -102,6 +102,8 @@ public: int getMaxVoxels() const { return _maxVoxels; } QAction* getUseVoxelShader() const { return _useVoxelShader; } + bool getShadowsEnabled() const; + void handleViewFrustumOffsetKeyModifier(int key); // User Tweakable LOD Items @@ -170,7 +172,7 @@ public slots: void removeSeparator(const QString& menuName, const QString& separatorName); void addMenuItem(const MenuItemProperties& properties); void removeMenuItem(const QString& menuName, const QString& menuitem); - bool isOptionChecked(const QString& menuOption); + bool isOptionChecked(const QString& menuOption) const; void setIsOptionChecked(const QString& menuOption, bool isChecked); private slots: @@ -301,6 +303,7 @@ namespace MenuOption { const QString Bandwidth = "Bandwidth Display"; const QString BandwidthDetails = "Bandwidth Details"; const QString BuckyBalls = "Bucky Balls"; + const QString CascadedShadows = "Cascaded"; const QString Chat = "Chat..."; const QString ChatCircling = "Chat Circling"; const QString CollideWithAvatars = "Collide With Avatars"; @@ -376,7 +379,7 @@ namespace MenuOption { const QString ScriptEditor = "Script Editor..."; const QString SettingsExport = "Export Settings"; const QString SettingsImport = "Import Settings"; - const QString Shadows = "Shadows"; + const QString SimpleShadows = "Simple"; const QString ShowBordersVoxelNodes = "Show Voxel Nodes"; const QString ShowBordersModelNodes = "Show Model Nodes"; const QString ShowBordersParticleNodes = "Show Particle Nodes"; diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 7c9ba50346..1839e20ef7 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -508,7 +508,7 @@ bool Model::render(float alpha, RenderMode mode, bool receiveShadows) { glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GREATER, 0.5f * alpha); - receiveShadows &= Menu::getInstance()->isOptionChecked(MenuOption::Shadows); + receiveShadows &= Menu::getInstance()->getShadowsEnabled(); renderMeshes(alpha, mode, false, receiveShadows); glDisable(GL_ALPHA_TEST); @@ -1508,14 +1508,6 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent, bool re const FBXGeometry& geometry = _geometry->getFBXGeometry(); const QVector& networkMeshes = _geometry->getMeshes(); - if (receiveShadows) { - for (int i = SHADOW_MATRIX_COUNT - 1; i >= 0; i--) { - glActiveTexture(GL_TEXTURE0 + i); - glTexGenfv(GL_S, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrices()[i][0]); - glTexGenfv(GL_T, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrices()[i][1]); - glTexGenfv(GL_R, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrices()[i][2]); - } - } for (int i = 0; i < networkMeshes.size(); i++) { // exit early if the translucency doesn't match what we're drawing const NetworkMesh& networkMesh = networkMeshes.at(i); diff --git a/interface/src/voxels/VoxelSystem.cpp b/interface/src/voxels/VoxelSystem.cpp index 11bd47b7e4..3525a086b4 100644 --- a/interface/src/voxels/VoxelSystem.cpp +++ b/interface/src/voxels/VoxelSystem.cpp @@ -518,9 +518,19 @@ void VoxelSystem::initVoxelMemory() { _shadowMapProgram.bind(); _shadowMapProgram.setUniformValue("shadowMap", 0); - _shadowMapProgram.setUniformValue("shadowDistances", -SHADOW_MATRIX_DISTANCES[1], - -SHADOW_MATRIX_DISTANCES[2], -SHADOW_MATRIX_DISTANCES[3]); _shadowMapProgram.release(); + + _cascadedShadowMapProgram.addShaderFromSourceFile(QGLShader::Vertex, + Application::resourcesPath() + "shaders/cascaded_shadow_map.vert"); + _cascadedShadowMapProgram.addShaderFromSourceFile(QGLShader::Fragment, + Application::resourcesPath() + "shaders/cascaded_shadow_map.frag"); + _cascadedShadowMapProgram.link(); + + _cascadedShadowMapProgram.bind(); + _cascadedShadowMapProgram.setUniformValue("shadowMap", 0); + _cascadedShadowMapProgram.setUniformValue("shadowDistances", -SHADOW_MATRIX_DISTANCES[1], + -SHADOW_MATRIX_DISTANCES[2], -SHADOW_MATRIX_DISTANCES[3]); + _cascadedShadowMapProgram.release(); } } _renderer = new PrimitiveRenderer(_maxVoxels); @@ -1168,6 +1178,7 @@ glm::vec3 VoxelSystem::computeVoxelVertex(const glm::vec3& startVertex, float vo ProgramObject VoxelSystem::_perlinModulateProgram; ProgramObject VoxelSystem::_shadowMapProgram; +ProgramObject VoxelSystem::_cascadedShadowMapProgram; void VoxelSystem::init() { if (_initialized) { @@ -1488,16 +1499,14 @@ void VoxelSystem::render() { void VoxelSystem::applyScaleAndBindProgram(bool texture) { - if (Menu::getInstance()->isOptionChecked(MenuOption::Shadows)) { - _shadowMapProgram.bind(); + if (Menu::getInstance()->getShadowsEnabled()) { + if (Menu::getInstance()->isOptionChecked(MenuOption::CascadedShadows)) { + _cascadedShadowMapProgram.bind(); + } else { + _shadowMapProgram.bind(); + } glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getShadowDepthTextureID()); - for (int i = SHADOW_MATRIX_COUNT - 1; i >= 0; i--) { - glActiveTexture(GL_TEXTURE0 + i); - glTexGenfv(GL_S, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrices()[i][0]); - glTexGenfv(GL_T, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrices()[i][1]); - glTexGenfv(GL_R, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrices()[i][2]); - } } else if (texture) { _perlinModulateProgram.bind(); glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getPermutationNormalTextureID()); @@ -1511,11 +1520,14 @@ void VoxelSystem::removeScaleAndReleaseProgram(bool texture) { // scale back down to 1 so heads aren't massive glPopMatrix(); - if (Menu::getInstance()->isOptionChecked(MenuOption::Shadows)) { - _shadowMapProgram.release(); + if (Menu::getInstance()->getShadowsEnabled()) { + if (Menu::getInstance()->isOptionChecked(MenuOption::CascadedShadows)) { + _cascadedShadowMapProgram.release(); + } else { + _shadowMapProgram.release(); + } glBindTexture(GL_TEXTURE_2D, 0); - } else if (texture) { _perlinModulateProgram.release(); glBindTexture(GL_TEXTURE_2D, 0); diff --git a/interface/src/voxels/VoxelSystem.h b/interface/src/voxels/VoxelSystem.h index 15e2b20a75..acd0cd170a 100644 --- a/interface/src/voxels/VoxelSystem.h +++ b/interface/src/voxels/VoxelSystem.h @@ -233,6 +233,7 @@ private: static ProgramObject _perlinModulateProgram; static ProgramObject _shadowMapProgram; + static ProgramObject _cascadedShadowMapProgram; int _hookID; std::vector _freeIndexes; From bd4d16768440b2c636f48bfca9344078dd6c15af Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 29 May 2014 14:13:02 -0700 Subject: [PATCH 09/27] Make JavaScript audio samples able to be looped Add a "loop" property to AudioInjectorOptions and provide an example JavaScript file. --- examples/playSoundLoop.js | 43 ++++++++++++++++++++ libraries/audio/src/AudioInjector.cpp | 5 +++ libraries/audio/src/AudioInjectorOptions.cpp | 2 + libraries/audio/src/AudioInjectorOptions.h | 5 +++ 4 files changed, 55 insertions(+) create mode 100644 examples/playSoundLoop.js diff --git a/examples/playSoundLoop.js b/examples/playSoundLoop.js new file mode 100644 index 0000000000..86226468bc --- /dev/null +++ b/examples/playSoundLoop.js @@ -0,0 +1,43 @@ +// +// playSoundLoop.js +// examples +// +// Created by David Rowe on 5/29/14. +// Copyright 2014 High Fidelity, Inc. +// +// This example script plays a sound in a continuous loop. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +var sound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Guitars/Guitar+-+Nylon+A.raw"); + +var soundPlaying = false; + +function keyPressEvent(event) { + if (event.text === "1") { + if (!Audio.isInjectorPlaying(soundPlaying)) { + var options = new AudioInjectionOptions(); + options.position = MyAvatar.position; + options.volume = 0.5; + options.loop = true; + soundPlaying = Audio.playSound(sound, options); + print("Started sound loop"); + } else { + Audio.stopInjector(soundPlaying); + print("Stopped sound loop"); + } + } +} + +function scriptEnding() { + if (Audio.isInjectorPlaying(soundPlaying)) { + Audio.stopInjector(soundPlaying); + print("Stopped sound loop"); + } +} + +// Connect a call back that happens every frame +Script.scriptEnding.connect(scriptEnding); +Controller.keyPressEvent.connect(keyPressEvent); diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index 1fe9f1336f..129dc47bd0 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -88,6 +88,7 @@ void AudioInjector::injectAudio() { int currentSendPosition = 0; int numPreAudioDataBytes = injectAudioPacket.size(); + bool shouldLoop = _options.getLoop(); // loop to send off our audio in NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL byte chunks while (currentSendPosition < soundByteArray.size() && !_shouldStop) { @@ -120,6 +121,10 @@ void AudioInjector::injectAudio() { usleep(usecToSleep); } } + + if (shouldLoop && currentSendPosition == soundByteArray.size()) { + currentSendPosition = 0; + } } } diff --git a/libraries/audio/src/AudioInjectorOptions.cpp b/libraries/audio/src/AudioInjectorOptions.cpp index cd6b08f6c7..49f1571c98 100644 --- a/libraries/audio/src/AudioInjectorOptions.cpp +++ b/libraries/audio/src/AudioInjectorOptions.cpp @@ -15,6 +15,7 @@ AudioInjectorOptions::AudioInjectorOptions(QObject* parent) : QObject(parent), _position(0.0f, 0.0f, 0.0f), _volume(1.0f), + _loop(false), _orientation(glm::vec3(0.0f, 0.0f, 0.0f)), _loopbackAudioInterface(NULL) { @@ -24,6 +25,7 @@ AudioInjectorOptions::AudioInjectorOptions(QObject* parent) : AudioInjectorOptions::AudioInjectorOptions(const AudioInjectorOptions& other) { _position = other._position; _volume = other._volume; + _loop = other._loop; _orientation = other._orientation; _loopbackAudioInterface = other._loopbackAudioInterface; } diff --git a/libraries/audio/src/AudioInjectorOptions.h b/libraries/audio/src/AudioInjectorOptions.h index bbe3d57b08..b90deb93f1 100644 --- a/libraries/audio/src/AudioInjectorOptions.h +++ b/libraries/audio/src/AudioInjectorOptions.h @@ -26,6 +26,7 @@ class AudioInjectorOptions : public QObject { Q_PROPERTY(glm::vec3 position READ getPosition WRITE setPosition) Q_PROPERTY(float volume READ getVolume WRITE setVolume) + Q_PROPERTY(bool loop READ getLoop WRITE setLoop) public: AudioInjectorOptions(QObject* parent = 0); AudioInjectorOptions(const AudioInjectorOptions& other); @@ -36,6 +37,9 @@ public: float getVolume() const { return _volume; } void setVolume(float volume) { _volume = volume; } + float getLoop() const { return _loop; } + void setLoop(float loop) { _loop = loop; } + const glm::quat& getOrientation() const { return _orientation; } void setOrientation(const glm::quat& orientation) { _orientation = orientation; } @@ -45,6 +49,7 @@ public: private: glm::vec3 _position; float _volume; + bool _loop; glm::quat _orientation; AbstractAudioInterface* _loopbackAudioInterface; }; From b91fd19f39a270761dd1e21520a04fa59e4323c0 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 29 May 2014 14:30:28 -0700 Subject: [PATCH 10/27] snapped attachment to center and scale them to fit --- interface/src/avatar/Avatar.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 55c0830dfb..ac6718dcc8 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -378,10 +378,10 @@ void Avatar::simulateAttachments(float deltaTime) { model->setLODDistance(getLODDistance()); } if (_skeletonModel.getJointPosition(jointIndex, jointPosition) && - _skeletonModel.getJointRotation(jointIndex, jointRotation)) { + _skeletonModel.getJointCombinedRotation(jointIndex, jointRotation)) { model->setTranslation(jointPosition + jointRotation * attachment.translation * _scale); model->setRotation(jointRotation * attachment.rotation); - model->setScale(_skeletonModel.getScale() * attachment.scale); + model->setScaleToFit(true, _scale * attachment.scale); model->simulate(deltaTime); } } @@ -749,7 +749,6 @@ void Avatar::setAttachmentData(const QVector& attachmentData) { // make sure we have as many models as attachments while (_attachmentModels.size() < attachmentData.size()) { Model* model = new Model(this); - model->setSnapModelToCenter(true); model->init(); _attachmentModels.append(model); } @@ -759,6 +758,8 @@ void Avatar::setAttachmentData(const QVector& attachmentData) { // update the urls for (int i = 0; i < attachmentData.size(); i++) { + _attachmentModels[i]->setSnapModelToCenter(true); + _attachmentModels[i]->setScaleToFit(true, _scale * _attachmentData.at(i).scale); _attachmentModels[i]->setURL(attachmentData.at(i).modelURL); } } From b34453647b37cee3b0e8ceaf43df716684e23a64 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 29 May 2014 14:34:10 -0700 Subject: [PATCH 11/27] editModels click/drag/attach tweaks --- examples/editModels.js | 69 +++++------------------------------------- 1 file changed, 8 insertions(+), 61 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index cf9b9abbdc..7cf78d592e 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -40,16 +40,7 @@ var modelURLs = [ var toolBar; - var jointList = MyAvatar.getJointNames(); -//print("\n# Joint list start"); -//for (var i = 0; i < jointList.length; i++) { -// Vec3.print("jointIndex = " + jointList[i] + " = " + i, MyAvatar.getJointPosition(jointList[i])); -//} -//print("# Joint list end"); - - - function isLocked(properties) { // special case to lock the ground plane model in hq. @@ -156,6 +147,10 @@ function controller(wichSide) { this.release = function () { if (this.grabbing) { + if (jointList.length <= 0) { + jointList = MyAvatar.getJointNames(); + } + var closestJointIndex = -1; var closestJointDistance = 10; for (var i = 0; i < jointList.length; i++) { @@ -169,22 +164,19 @@ function controller(wichSide) { print("closestJointIndex: " + closestJointIndex); print("closestJointDistance: " + closestJointDistance); - if (closestJointDistance < 0.1) { + if (closestJointDistance < this.oldModelRadius) { print("Attaching to " + jointList[closestJointIndex]); var jointPosition = MyAvatar.getJointPosition(jointList[closestJointIndex]); var jointRotation = MyAvatar.getJointCombinedRotation(jointList[closestJointIndex]); - var attachmentOffset = Vec3.multiply(Vec3.subtract(this.oldModelPosition, jointPosition), 2); + var attachmentOffset = Vec3.subtract(this.oldModelPosition, jointPosition); attachmentOffset = Vec3.multiplyQbyV(Quat.inverse(jointRotation), attachmentOffset); var attachmentRotation = Quat.multiply(Quat.inverse(jointRotation), this.oldModelRotation); MyAvatar.attach(this.modelURL, jointList[closestJointIndex], - attachmentOffset, attachmentRotation, 0.75, + attachmentOffset, attachmentRotation, 2.0 * this.oldModelRadius, true, false); - Vec3.print("offset: ", attachmentOffset); - Vec3.print("joint: ", Quat.safeEulerAngles(jointRotation)); - Vec3.print("model: ", Quat.safeEulerAngles(this.oldModelRotation)); - Vec3.print("delta: ", Quat.safeEulerAngles(attachmentRotation)); + Models.deleteModel(this.modelID); } } @@ -468,52 +460,7 @@ function checkController(deltaTime) { } moveOverlays(); - - - - leftController.hideLaser(); - rightController.hideLaser(); - var jointPos = MyAvatar.getJointPosition("RightHand"); - var jointRot = MyAvatar.getJointCombinedRotation("RightHand"); - - Overlays.editOverlay(r, { - position: jointPos, - end: Vec3.sum(jointPos, Vec3.multiplyQbyV(jointRot, { x:1, y:0, z:0 })) - }); - Overlays.editOverlay(g, { - position: jointPos, - end: Vec3.sum(jointPos, Vec3.multiplyQbyV(jointRot, { x:0, y:1, z:0 })) - }); - Overlays.editOverlay(b, { - position: jointPos, - end: Vec3.sum(jointPos, Vec3.multiplyQbyV(jointRot, { x:0, y:0, z:1 })) - }); } -var r = Overlays.addOverlay("line3d", { - position: { x: 0, y: 0, z: 0 }, - end: { x: 0, y: 0, z: 0 }, - color: { red: 255, green: 0, blue: 0 }, - alpha: 1, - visible: true, - lineWidth: LASER_WIDTH - }); -var g = Overlays.addOverlay("line3d", { - position: { x: 0, y: 0, z: 0 }, - end: { x: 0, y: 0, z: 0 }, - color: { red: 0, green: 255, blue: 0 }, - alpha: 1, - visible: true, - lineWidth: LASER_WIDTH - }); -var b = Overlays.addOverlay("line3d", { - position: { x: 0, y: 0, z: 0 }, - end: { x: 0, y: 0, z: 0 }, - color: { red: 0, green: 0, blue: 255 }, - alpha: 1, - visible: true, - lineWidth: LASER_WIDTH - }); - function initToolBar() { toolBar = new ToolBar(0, 0, ToolBar.VERTICAL); From 980e873a1350bd8dac5bc36713ff4f59442eab6d Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 29 May 2014 15:02:09 -0700 Subject: [PATCH 12/27] Better prints in editModels --- examples/editModels.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 7cf78d592e..89be4089a0 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -161,8 +161,8 @@ function controller(wichSide) { } } - print("closestJointIndex: " + closestJointIndex); - print("closestJointDistance: " + closestJointDistance); + print("closestJoint: " + jojntList[closestJointIndex]); + print("closestJointDistance (attach max distance): " + closestJointDistance + " (" + this.oldModelRadius + ")"); if (closestJointDistance < this.oldModelRadius) { print("Attaching to " + jointList[closestJointIndex]); From 3e207f9452ade9ac88408a73ba1fc7739d0faa30 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 29 May 2014 15:09:42 -0700 Subject: [PATCH 13/27] fixed display error in editVoxels with new boundaries --- examples/editVoxels.js | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/examples/editVoxels.js b/examples/editVoxels.js index 14bea50bb0..22df8604e1 100644 --- a/examples/editVoxels.js +++ b/examples/editVoxels.js @@ -28,8 +28,10 @@ var NEW_VOXEL_SIZE = 1.0; var NEW_VOXEL_DISTANCE_FROM_CAMERA = 3.0; var PIXELS_PER_EXTRUDE_VOXEL = 16; var WHEEL_PIXELS_PER_SCALE_CHANGE = 100; -var MAX_VOXEL_SCALE = 16.0; -var MIN_VOXEL_SCALE = 1.0 / Math.pow(2.0, 8.0); +var MAX_VOXEL_SCALE_POWER = 4; +var MIN_VOXEL_SCALE_POWER = -8; +var MAX_VOXEL_SCALE = Math.pow(2.0, MAX_VOXEL_SCALE_POWER); +var MIN_VOXEL_SCALE = Math.pow(2.0, MIN_VOXEL_SCALE_POWER); var WHITE_COLOR = { red: 255, green: 255, blue: 255 }; var MAX_PASTE_VOXEL_SCALE = 256; @@ -330,6 +332,13 @@ function ScaleSelector() { visible: false }); this.setScale = function(scale) { + if (scale > MAX_VOXEL_SCALE) { + scale = MAX_VOXEL_SCALE; + } + if (scale < MIN_VOXEL_SCALE) { + scale = MIN_VOXEL_SCALE; + } + this.scale = scale; this.power = Math.floor(Math.log(scale) / Math.log(2)); rescaleImport(); @@ -391,12 +400,9 @@ function ScaleSelector() { this.incrementScale = function() { copyScale = false; - if (this.power < 13) { + if (this.power < MAX_VOXEL_SCALE_POWER) { ++this.power; this.scale *= 2.0; - if (this.scale > MAX_VOXEL_SCALE) { - this.scale = MAX_VOXEL_SCALE; - } this.update(); rescaleImport(); resizeVoxelSound.play(voxelSizePlus); @@ -405,7 +411,7 @@ function ScaleSelector() { this.decrementScale = function() { copyScale = false; - if (-4 < this.power) { + if (MIN_VOXEL_SCALE_POWER < this.power) { --this.power; this.scale /= 2.0; this.update(); From 391902f79bfdd5ffea0956d1fc525537cbfbf4fa Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 29 May 2014 15:30:40 -0700 Subject: [PATCH 14/27] Cascaded shadow maps for models. --- .../shaders/cascaded_shadow_map.frag | 15 +- .../shaders/model_cascaded_shadow_map.frag | 56 ++++++ .../model_cascaded_shadow_normal_map.frag | 69 +++++++ ...l_cascaded_shadow_normal_specular_map.frag | 72 ++++++++ .../model_cascaded_shadow_specular_map.frag | 59 ++++++ interface/src/renderer/Model.cpp | 170 ++++++++++++++++-- interface/src/renderer/Model.h | 16 ++ 7 files changed, 440 insertions(+), 17 deletions(-) create mode 100644 interface/resources/shaders/model_cascaded_shadow_map.frag create mode 100644 interface/resources/shaders/model_cascaded_shadow_normal_map.frag create mode 100644 interface/resources/shaders/model_cascaded_shadow_normal_specular_map.frag create mode 100644 interface/resources/shaders/model_cascaded_shadow_specular_map.frag diff --git a/interface/resources/shaders/cascaded_shadow_map.frag b/interface/resources/shaders/cascaded_shadow_map.frag index 9b3e8f7cc7..337f98a228 100644 --- a/interface/resources/shaders/cascaded_shadow_map.frag +++ b/interface/resources/shaders/cascaded_shadow_map.frag @@ -11,10 +11,15 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +// the shadow texture uniform sampler2DShadow shadowMap; +// the distances to the cascade sections uniform vec3 shadowDistances; +// the inverse of the size of the shadow map +const float shadowScale = 1.0 / 2048.0; + // the color in shadow varying vec4 shadowColor; @@ -22,8 +27,14 @@ varying vec4 shadowColor; varying vec4 position; void main(void) { + // compute the index of the cascade to use and the corresponding texture coordinates int shadowIndex = int(dot(step(vec3(position.z), shadowDistances), vec3(1.0, 1.0, 1.0))); - vec3 texCoord = vec3(dot(gl_EyePlaneS[shadowIndex], position), dot(gl_EyePlaneT[shadowIndex], position), + vec3 shadowTexCoord = vec3(dot(gl_EyePlaneS[shadowIndex], position), dot(gl_EyePlaneT[shadowIndex], position), dot(gl_EyePlaneR[shadowIndex], position)); - gl_FragColor = mix(shadowColor, gl_Color, shadow2D(shadowMap, texCoord).r); + + gl_FragColor = mix(shadowColor, gl_Color, 0.25 * + (shadow2D(shadowMap, shadowTexCoord + vec3(-shadowScale, -shadowScale, 0.0)).r + + shadow2D(shadowMap, shadowTexCoord + vec3(-shadowScale, shadowScale, 0.0)).r + + shadow2D(shadowMap, shadowTexCoord + vec3(shadowScale, -shadowScale, 0.0)).r + + shadow2D(shadowMap, shadowTexCoord + vec3(shadowScale, shadowScale, 0.0)).r)); } diff --git a/interface/resources/shaders/model_cascaded_shadow_map.frag b/interface/resources/shaders/model_cascaded_shadow_map.frag new file mode 100644 index 0000000000..720c43b656 --- /dev/null +++ b/interface/resources/shaders/model_cascaded_shadow_map.frag @@ -0,0 +1,56 @@ +#version 120 + +// +// model_cascaded_shadow_map.frag +// fragment shader +// +// Created by Andrzej Kapolka on 5/29/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +// the diffuse texture +uniform sampler2D diffuseMap; + +// the shadow texture +uniform sampler2DShadow shadowMap; + +// the distances to the cascade sections +uniform vec3 shadowDistances; + +// the inverse of the size of the shadow map +const float shadowScale = 1.0 / 2048.0; + +// the interpolated position +varying vec4 position; + +// the interpolated normal +varying vec4 normal; + +void main(void) { + // compute the index of the cascade to use and the corresponding texture coordinates + int shadowIndex = int(dot(step(vec3(position.z), shadowDistances), vec3(1.0, 1.0, 1.0))); + vec3 shadowTexCoord = vec3(dot(gl_EyePlaneS[shadowIndex], position), dot(gl_EyePlaneT[shadowIndex], position), + dot(gl_EyePlaneR[shadowIndex], position)); + + // compute the base color based on OpenGL lighting model + vec4 normalizedNormal = normalize(normal); + float diffuse = dot(normalizedNormal, gl_LightSource[0].position); + float facingLight = step(0.0, diffuse) * 0.25 * + (shadow2D(shadowMap, shadowTexCoord + vec3(-shadowScale, -shadowScale, 0.0)).r + + shadow2D(shadowMap, shadowTexCoord + vec3(-shadowScale, shadowScale, 0.0)).r + + shadow2D(shadowMap, shadowTexCoord + vec3(shadowScale, -shadowScale, 0.0)).r + + shadow2D(shadowMap, shadowTexCoord + vec3(shadowScale, shadowScale, 0.0)).r); + vec4 base = gl_Color * (gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient + + gl_FrontLightProduct[0].diffuse * (diffuse * facingLight)); + + // compute the specular component (sans exponent) + float specular = facingLight * max(0.0, dot(normalize(gl_LightSource[0].position - normalize(vec4(position.xyz, 0.0))), + normalizedNormal)); + + // modulate texture by base color and add specular contribution + gl_FragColor = base * texture2D(diffuseMap, gl_TexCoord[0].st) + + vec4(pow(specular, gl_FrontMaterial.shininess) * gl_FrontLightProduct[0].specular.rgb, 0.0); +} diff --git a/interface/resources/shaders/model_cascaded_shadow_normal_map.frag b/interface/resources/shaders/model_cascaded_shadow_normal_map.frag new file mode 100644 index 0000000000..5758333392 --- /dev/null +++ b/interface/resources/shaders/model_cascaded_shadow_normal_map.frag @@ -0,0 +1,69 @@ +#version 120 + +// +// model_cascaded_shadow_normal_map.frag +// fragment shader +// +// Created by Andrzej Kapolka on 5/29/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +// the diffuse texture +uniform sampler2D diffuseMap; + +// the normal map texture +uniform sampler2D normalMap; + +// the shadow texture +uniform sampler2DShadow shadowMap; + +// the distances to the cascade sections +uniform vec3 shadowDistances; + +// the inverse of the size of the shadow map +const float shadowScale = 1.0 / 2048.0; + +// the interpolated position +varying vec4 interpolatedPosition; + +// the interpolated normal +varying vec4 interpolatedNormal; + +// the interpolated tangent +varying vec4 interpolatedTangent; + +void main(void) { + vec3 normalizedNormal = normalize(vec3(interpolatedNormal)); + vec3 normalizedTangent = normalize(vec3(interpolatedTangent)); + vec3 normalizedBitangent = normalize(cross(normalizedNormal, normalizedTangent)); + vec3 localNormal = vec3(texture2D(normalMap, gl_TexCoord[0].st)) * 2.0 - vec3(1.0, 1.0, 1.0); + + // compute the index of the cascade to use and the corresponding texture coordinates + int shadowIndex = int(dot(step(vec3(interpolatedPosition.z), shadowDistances), vec3(1.0, 1.0, 1.0))); + vec3 shadowTexCoord = vec3(dot(gl_EyePlaneS[shadowIndex], interpolatedPosition), + dot(gl_EyePlaneT[shadowIndex], interpolatedPosition), + dot(gl_EyePlaneR[shadowIndex], interpolatedPosition)); + + // compute the base color based on OpenGL lighting model + vec4 viewNormal = vec4(normalizedTangent * localNormal.x + + normalizedBitangent * localNormal.y + normalizedNormal * localNormal.z, 0.0); + float diffuse = dot(viewNormal, gl_LightSource[0].position); + float facingLight = step(0.0, diffuse) * 0.25 * + (shadow2D(shadowMap, shadowTexCoord + vec3(-shadowScale, -shadowScale, 0.0)).r + + shadow2D(shadowMap, shadowTexCoord + vec3(-shadowScale, shadowScale, 0.0)).r + + shadow2D(shadowMap, shadowTexCoord + vec3(shadowScale, -shadowScale, 0.0)).r + + shadow2D(shadowMap, shadowTexCoord + vec3(shadowScale, shadowScale, 0.0)).r); + vec4 base = gl_Color * (gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient + + gl_FrontLightProduct[0].diffuse * (diffuse * facingLight)); + + // compute the specular component (sans exponent) + float specular = facingLight * max(0.0, dot(normalize(gl_LightSource[0].position - + normalize(vec4(vec3(interpolatedPosition), 0.0))), viewNormal)); + + // modulate texture by base color and add specular contribution + gl_FragColor = base * texture2D(diffuseMap, gl_TexCoord[0].st) + + vec4(pow(specular, gl_FrontMaterial.shininess) * gl_FrontLightProduct[0].specular.rgb, 0.0); +} diff --git a/interface/resources/shaders/model_cascaded_shadow_normal_specular_map.frag b/interface/resources/shaders/model_cascaded_shadow_normal_specular_map.frag new file mode 100644 index 0000000000..2b949710f3 --- /dev/null +++ b/interface/resources/shaders/model_cascaded_shadow_normal_specular_map.frag @@ -0,0 +1,72 @@ +#version 120 + +// +// model_cascaded_shadow_normal_specular_map.frag +// fragment shader +// +// Created by Andrzej Kapolka on 5/29/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +// the diffuse texture +uniform sampler2D diffuseMap; + +// the normal map texture +uniform sampler2D normalMap; + +// the specular map texture +uniform sampler2D specularMap; + +// the shadow texture +uniform sampler2DShadow shadowMap; + +// the distances to the cascade sections +uniform vec3 shadowDistances; + +// the inverse of the size of the shadow map +const float shadowScale = 1.0 / 2048.0; + +// the interpolated position +varying vec4 interpolatedPosition; + +// the interpolated normal +varying vec4 interpolatedNormal; + +// the interpolated tangent +varying vec4 interpolatedTangent; + +void main(void) { + vec3 normalizedNormal = normalize(vec3(interpolatedNormal)); + vec3 normalizedTangent = normalize(vec3(interpolatedTangent)); + vec3 normalizedBitangent = normalize(cross(normalizedNormal, normalizedTangent)); + vec3 localNormal = vec3(texture2D(normalMap, gl_TexCoord[0].st)) * 2.0 - vec3(1.0, 1.0, 1.0); + + // compute the index of the cascade to use and the corresponding texture coordinates + int shadowIndex = int(dot(step(vec3(interpolatedPosition.z), shadowDistances), vec3(1.0, 1.0, 1.0))); + vec3 shadowTexCoord = vec3(dot(gl_EyePlaneS[shadowIndex], interpolatedPosition), + dot(gl_EyePlaneT[shadowIndex], interpolatedPosition), + dot(gl_EyePlaneR[shadowIndex], interpolatedPosition)); + + // compute the base color based on OpenGL lighting model + vec4 viewNormal = vec4(normalizedTangent * localNormal.x + + normalizedBitangent * localNormal.y + normalizedNormal * localNormal.z, 0.0); + float diffuse = dot(viewNormal, gl_LightSource[0].position); + float facingLight = step(0.0, diffuse) * 0.25 * + (shadow2D(shadowMap, shadowTexCoord + vec3(-shadowScale, -shadowScale, 0.0)).r + + shadow2D(shadowMap, shadowTexCoord + vec3(-shadowScale, shadowScale, 0.0)).r + + shadow2D(shadowMap, shadowTexCoord + vec3(shadowScale, -shadowScale, 0.0)).r + + shadow2D(shadowMap, shadowTexCoord + vec3(shadowScale, shadowScale, 0.0)).r); + vec4 base = gl_Color * (gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient + + gl_FrontLightProduct[0].diffuse * (diffuse * facingLight)); + + // compute the specular component (sans exponent) + float specular = facingLight * max(0.0, dot(normalize(gl_LightSource[0].position - + normalize(vec4(interpolatedPosition.xyz, 0.0))), viewNormal)); + + // modulate texture by base color and add specular contribution + gl_FragColor = base * texture2D(diffuseMap, gl_TexCoord[0].st) + vec4(pow(specular, gl_FrontMaterial.shininess) * + gl_FrontLightProduct[0].specular.rgb * texture2D(specularMap, gl_TexCoord[0].st).rgb, 0.0); +} diff --git a/interface/resources/shaders/model_cascaded_shadow_specular_map.frag b/interface/resources/shaders/model_cascaded_shadow_specular_map.frag new file mode 100644 index 0000000000..ba8ba6b85b --- /dev/null +++ b/interface/resources/shaders/model_cascaded_shadow_specular_map.frag @@ -0,0 +1,59 @@ +#version 120 + +// +// model_cascaded_shadow_specular_map.frag +// fragment shader +// +// Created by Andrzej Kapolka on 5/29/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +// the diffuse texture +uniform sampler2D diffuseMap; + +// the specular texture +uniform sampler2D specularMap; + +// the shadow texture +uniform sampler2DShadow shadowMap; + +// the distances to the cascade sections +uniform vec3 shadowDistances; + +// the inverse of the size of the shadow map +const float shadowScale = 1.0 / 2048.0; + +// the interpolated position in view space +varying vec4 position; + +// the interpolated normal +varying vec4 normal; + +void main(void) { + // compute the index of the cascade to use and the corresponding texture coordinates + int shadowIndex = int(dot(step(vec3(position.z), shadowDistances), vec3(1.0, 1.0, 1.0))); + vec3 shadowTexCoord = vec3(dot(gl_EyePlaneS[shadowIndex], position), dot(gl_EyePlaneT[shadowIndex], position), + dot(gl_EyePlaneR[shadowIndex], position)); + + // compute the base color based on OpenGL lighting model + vec4 normalizedNormal = normalize(normal); + float diffuse = dot(normalizedNormal, gl_LightSource[0].position); + float facingLight = step(0.0, diffuse) * 0.25 * + (shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(-shadowScale, -shadowScale, 0.0)).r + + shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(-shadowScale, shadowScale, 0.0)).r + + shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(shadowScale, -shadowScale, 0.0)).r + + shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(shadowScale, shadowScale, 0.0)).r); + vec4 base = gl_Color * (gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient + + gl_FrontLightProduct[0].diffuse * (diffuse * facingLight)); + + // compute the specular component (sans exponent) + float specular = facingLight * max(0.0, dot(normalize(gl_LightSource[0].position - normalize(vec4(position.xyz, 0.0))), + normalizedNormal)); + + // modulate texture by base color and add specular contribution + gl_FragColor = base * texture2D(diffuseMap, gl_TexCoord[0].st) + vec4(pow(specular, gl_FrontMaterial.shininess) * + gl_FrontLightProduct[0].specular.rgb * texture2D(specularMap, gl_TexCoord[0].st).rgb, 0.0); +} diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 1839e20ef7..a550064ef1 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -65,6 +65,11 @@ ProgramObject Model::_shadowNormalMapProgram; ProgramObject Model::_shadowSpecularMapProgram; ProgramObject Model::_shadowNormalSpecularMapProgram; +ProgramObject Model::_cascadedShadowMapProgram; +ProgramObject Model::_cascadedShadowNormalMapProgram; +ProgramObject Model::_cascadedShadowSpecularMapProgram; +ProgramObject Model::_cascadedShadowNormalSpecularMapProgram; + ProgramObject Model::_shadowProgram; ProgramObject Model::_skinProgram; @@ -77,12 +82,19 @@ ProgramObject Model::_skinShadowNormalMapProgram; ProgramObject Model::_skinShadowSpecularMapProgram; ProgramObject Model::_skinShadowNormalSpecularMapProgram; +ProgramObject Model::_skinCascadedShadowMapProgram; +ProgramObject Model::_skinCascadedShadowNormalMapProgram; +ProgramObject Model::_skinCascadedShadowSpecularMapProgram; +ProgramObject Model::_skinCascadedShadowNormalSpecularMapProgram; + ProgramObject Model::_skinShadowProgram; int Model::_normalMapTangentLocation; int Model::_normalSpecularMapTangentLocation; int Model::_shadowNormalMapTangentLocation; int Model::_shadowNormalSpecularMapTangentLocation; +int Model::_cascadedShadowNormalMapTangentLocation; +int Model::_cascadedShadowNormalSpecularMapTangentLocation; Model::SkinLocations Model::_skinLocations; Model::SkinLocations Model::_skinNormalMapLocations; @@ -92,6 +104,10 @@ Model::SkinLocations Model::_skinShadowMapLocations; Model::SkinLocations Model::_skinShadowNormalMapLocations; Model::SkinLocations Model::_skinShadowSpecularMapLocations; Model::SkinLocations Model::_skinShadowNormalSpecularMapLocations; +Model::SkinLocations Model::_skinCascadedShadowMapLocations; +Model::SkinLocations Model::_skinCascadedShadowNormalMapLocations; +Model::SkinLocations Model::_skinCascadedShadowSpecularMapLocations; +Model::SkinLocations Model::_skinCascadedShadowNormalSpecularMapLocations; Model::SkinLocations Model::_skinShadowLocations; void Model::setScale(const glm::vec3& scale) { @@ -132,6 +148,8 @@ void Model::initSkinProgram(ProgramObject& program, Model::SkinLocations& locati program.setUniformValue("normalMap", 1); program.setUniformValue("specularMap", specularTextureUnit); program.setUniformValue("shadowMap", shadowTextureUnit); + program.setUniformValue("shadowDistances", -SHADOW_MATRIX_DISTANCES[1], + -SHADOW_MATRIX_DISTANCES[2], -SHADOW_MATRIX_DISTANCES[3]); program.release(); } @@ -229,7 +247,7 @@ void Model::init() { _normalSpecularMapProgram.setUniformValue("diffuseMap", 0); _normalSpecularMapProgram.setUniformValue("normalMap", 1); _normalSpecularMapProgram.setUniformValue("specularMap", 2); - _normalSpecularMapTangentLocation = _normalMapProgram.attributeLocation("tangent"); + _normalSpecularMapTangentLocation = _normalSpecularMapProgram.attributeLocation("tangent"); _normalSpecularMapProgram.release(); @@ -279,10 +297,69 @@ void Model::init() { _shadowNormalSpecularMapProgram.setUniformValue("normalMap", 1); _shadowNormalSpecularMapProgram.setUniformValue("specularMap", 2); _shadowNormalSpecularMapProgram.setUniformValue("shadowMap", 3); - _shadowNormalSpecularMapTangentLocation = _normalMapProgram.attributeLocation("tangent"); + _shadowNormalSpecularMapTangentLocation = _shadowNormalSpecularMapProgram.attributeLocation("tangent"); _shadowNormalSpecularMapProgram.release(); + _cascadedShadowMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + + "shaders/model.vert"); + _cascadedShadowMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + + "shaders/model_cascaded_shadow_map.frag"); + _cascadedShadowMapProgram.link(); + + _cascadedShadowMapProgram.bind(); + _cascadedShadowMapProgram.setUniformValue("diffuseMap", 0); + _cascadedShadowMapProgram.setUniformValue("shadowMap", 1); + _cascadedShadowMapProgram.setUniformValue("shadowDistances", -SHADOW_MATRIX_DISTANCES[1], + -SHADOW_MATRIX_DISTANCES[2], -SHADOW_MATRIX_DISTANCES[3]); + _cascadedShadowMapProgram.release(); + + _cascadedShadowNormalMapProgram.addShaderFromSourceFile(QGLShader::Vertex, + Application::resourcesPath() + "shaders/model_normal_map.vert"); + _cascadedShadowNormalMapProgram.addShaderFromSourceFile(QGLShader::Fragment, + Application::resourcesPath() + "shaders/model_cascaded_shadow_normal_map.frag"); + _cascadedShadowNormalMapProgram.link(); + + _cascadedShadowNormalMapProgram.bind(); + _cascadedShadowNormalMapProgram.setUniformValue("diffuseMap", 0); + _cascadedShadowNormalMapProgram.setUniformValue("normalMap", 1); + _cascadedShadowNormalMapProgram.setUniformValue("shadowMap", 2); + _cascadedShadowNormalMapProgram.setUniformValue("shadowDistances", -SHADOW_MATRIX_DISTANCES[1], + -SHADOW_MATRIX_DISTANCES[2], -SHADOW_MATRIX_DISTANCES[3]); + _cascadedShadowNormalMapTangentLocation = _cascadedShadowNormalMapProgram.attributeLocation("tangent"); + _cascadedShadowNormalMapProgram.release(); + + _cascadedShadowSpecularMapProgram.addShaderFromSourceFile(QGLShader::Vertex, + Application::resourcesPath() + "shaders/model.vert"); + _cascadedShadowSpecularMapProgram.addShaderFromSourceFile(QGLShader::Fragment, + Application::resourcesPath() + "shaders/model_cascaded_shadow_specular_map.frag"); + _cascadedShadowSpecularMapProgram.link(); + + _cascadedShadowSpecularMapProgram.bind(); + _cascadedShadowSpecularMapProgram.setUniformValue("diffuseMap", 0); + _cascadedShadowSpecularMapProgram.setUniformValue("specularMap", 1); + _cascadedShadowSpecularMapProgram.setUniformValue("shadowMap", 2); + _cascadedShadowSpecularMapProgram.setUniformValue("shadowDistances", -SHADOW_MATRIX_DISTANCES[1], + -SHADOW_MATRIX_DISTANCES[2], -SHADOW_MATRIX_DISTANCES[3]); + _cascadedShadowSpecularMapProgram.release(); + + _cascadedShadowNormalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Vertex, + Application::resourcesPath() + "shaders/model_normal_map.vert"); + _cascadedShadowNormalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Fragment, + Application::resourcesPath() + "shaders/model_cascaded_shadow_normal_specular_map.frag"); + _cascadedShadowNormalSpecularMapProgram.link(); + + _cascadedShadowNormalSpecularMapProgram.bind(); + _cascadedShadowNormalSpecularMapProgram.setUniformValue("diffuseMap", 0); + _cascadedShadowNormalSpecularMapProgram.setUniformValue("normalMap", 1); + _cascadedShadowNormalSpecularMapProgram.setUniformValue("specularMap", 2); + _cascadedShadowNormalSpecularMapProgram.setUniformValue("shadowMap", 3); + _cascadedShadowNormalSpecularMapProgram.setUniformValue("shadowDistances", -SHADOW_MATRIX_DISTANCES[1], + -SHADOW_MATRIX_DISTANCES[2], -SHADOW_MATRIX_DISTANCES[3]); + _cascadedShadowNormalSpecularMapTangentLocation = _cascadedShadowNormalSpecularMapProgram.attributeLocation("tangent"); + _cascadedShadowNormalSpecularMapProgram.release(); + + _shadowProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/model_shadow.vert"); _shadowProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_shadow.frag"); @@ -353,6 +430,39 @@ void Model::init() { initSkinProgram(_skinShadowNormalSpecularMapProgram, _skinShadowNormalSpecularMapLocations, 2, 3); + _skinCascadedShadowMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + + "shaders/skin_model.vert"); + _skinCascadedShadowMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + + "shaders/model_cascaded_shadow_map.frag"); + _skinCascadedShadowMapProgram.link(); + + initSkinProgram(_skinCascadedShadowMapProgram, _skinCascadedShadowMapLocations); + + _skinCascadedShadowNormalMapProgram.addShaderFromSourceFile(QGLShader::Vertex, + Application::resourcesPath() + "shaders/skin_model_normal_map.vert"); + _skinCascadedShadowNormalMapProgram.addShaderFromSourceFile(QGLShader::Fragment, + Application::resourcesPath() + "shaders/model_cascaded_shadow_normal_map.frag"); + _skinCascadedShadowNormalMapProgram.link(); + + initSkinProgram(_skinCascadedShadowNormalMapProgram, _skinCascadedShadowNormalMapLocations, 1, 2); + + _skinCascadedShadowSpecularMapProgram.addShaderFromSourceFile(QGLShader::Vertex, + Application::resourcesPath() + "shaders/skin_model.vert"); + _skinCascadedShadowSpecularMapProgram.addShaderFromSourceFile(QGLShader::Fragment, + Application::resourcesPath() + "shaders/model_cascaded_shadow_specular_map.frag"); + _skinCascadedShadowSpecularMapProgram.link(); + + initSkinProgram(_skinCascadedShadowSpecularMapProgram, _skinCascadedShadowSpecularMapLocations, 1, 2); + + _skinCascadedShadowNormalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Vertex, + Application::resourcesPath() + "shaders/skin_model_normal_map.vert"); + _skinCascadedShadowNormalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Fragment, + Application::resourcesPath() + "shaders/model_cascaded_shadow_normal_specular_map.frag"); + _skinCascadedShadowNormalSpecularMapProgram.link(); + + initSkinProgram(_skinCascadedShadowNormalSpecularMapProgram, _skinCascadedShadowNormalSpecularMapLocations, 2, 3); + + _skinShadowProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/skin_model_shadow.vert"); _skinShadowProgram.addShaderFromSourceFile(QGLShader::Fragment, @@ -1508,6 +1618,7 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent, bool re const FBXGeometry& geometry = _geometry->getFBXGeometry(); const QVector& networkMeshes = _geometry->getMeshes(); + bool cascadedShadows = Menu::getInstance()->isOptionChecked(MenuOption::CascadedShadows); for (int i = 0; i < networkMeshes.size(); i++) { // exit early if the translucency doesn't match what we're drawing const NetworkMesh& networkMesh = networkMeshes.at(i); @@ -1529,6 +1640,7 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent, bool re ProgramObject* program = &_program; ProgramObject* skinProgram = &_skinProgram; SkinLocations* skinLocations = &_skinLocations; + int tangentLocation = _normalMapTangentLocation; GLenum specularTextureUnit = 0; GLenum shadowTextureUnit = 0; if (mode == SHADOW_RENDER_MODE) { @@ -1539,21 +1651,38 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent, bool re } else if (!mesh.tangents.isEmpty()) { if (mesh.hasSpecularTexture()) { if (receiveShadows) { - program = &_shadowNormalSpecularMapProgram; - skinProgram = &_skinShadowNormalSpecularMapProgram; - skinLocations = &_skinShadowNormalSpecularMapLocations; + if (cascadedShadows) { + program = &_cascadedShadowNormalSpecularMapProgram; + skinProgram = &_skinCascadedShadowNormalSpecularMapProgram; + skinLocations = &_skinCascadedShadowNormalSpecularMapLocations; + tangentLocation = _cascadedShadowNormalSpecularMapTangentLocation; + } else { + program = &_shadowNormalSpecularMapProgram; + skinProgram = &_skinShadowNormalSpecularMapProgram; + skinLocations = &_skinShadowNormalSpecularMapLocations; + tangentLocation = _shadowNormalSpecularMapTangentLocation; + } shadowTextureUnit = GL_TEXTURE3; } else { program = &_normalSpecularMapProgram; skinProgram = &_skinNormalSpecularMapProgram; skinLocations = &_skinNormalSpecularMapLocations; + tangentLocation = _normalSpecularMapTangentLocation; } specularTextureUnit = GL_TEXTURE2; } else if (receiveShadows) { - program = &_shadowNormalMapProgram; - skinProgram = &_skinShadowNormalMapProgram; - skinLocations = &_skinShadowNormalMapLocations; + if (cascadedShadows) { + program = &_cascadedShadowNormalMapProgram; + skinProgram = &_skinCascadedShadowNormalMapProgram; + skinLocations = &_skinCascadedShadowNormalMapLocations; + tangentLocation = _cascadedShadowNormalMapTangentLocation; + } else { + program = &_shadowNormalMapProgram; + skinProgram = &_skinShadowNormalMapProgram; + skinLocations = &_skinShadowNormalMapLocations; + tangentLocation = _shadowNormalMapTangentLocation; + } shadowTextureUnit = GL_TEXTURE2; } else { program = &_normalMapProgram; @@ -1562,9 +1691,15 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent, bool re } } else if (mesh.hasSpecularTexture()) { if (receiveShadows) { - program = &_shadowSpecularMapProgram; - skinProgram = &_skinShadowSpecularMapProgram; - skinLocations = &_skinShadowSpecularMapLocations; + if (cascadedShadows) { + program = &_cascadedShadowSpecularMapProgram; + skinProgram = &_skinCascadedShadowSpecularMapProgram; + skinLocations = &_skinCascadedShadowSpecularMapLocations; + } else { + program = &_shadowSpecularMapProgram; + skinProgram = &_skinShadowSpecularMapProgram; + skinLocations = &_skinShadowSpecularMapLocations; + } shadowTextureUnit = GL_TEXTURE2; } else { program = &_specularMapProgram; @@ -1574,15 +1709,20 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent, bool re specularTextureUnit = GL_TEXTURE1; } else if (receiveShadows) { - program = &_shadowMapProgram; - skinProgram = &_skinShadowMapProgram; - skinLocations = &_skinShadowMapLocations; + if (cascadedShadows) { + program = &_cascadedShadowMapProgram; + skinProgram = &_skinCascadedShadowMapProgram; + skinLocations = &_skinCascadedShadowMapLocations; + } else { + program = &_shadowMapProgram; + skinProgram = &_skinShadowMapProgram; + skinLocations = &_skinShadowMapLocations; + } shadowTextureUnit = GL_TEXTURE1; } const MeshState& state = _meshStates.at(i); ProgramObject* activeProgram = program; - int tangentLocation = _normalMapTangentLocation; glPushMatrix(); Application::getInstance()->loadTranslatedViewMatrix(_translation); diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index a4e45287dd..5561855afb 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -280,6 +280,11 @@ private: static ProgramObject _shadowSpecularMapProgram; static ProgramObject _shadowNormalSpecularMapProgram; + static ProgramObject _cascadedShadowMapProgram; + static ProgramObject _cascadedShadowNormalMapProgram; + static ProgramObject _cascadedShadowSpecularMapProgram; + static ProgramObject _cascadedShadowNormalSpecularMapProgram; + static ProgramObject _shadowProgram; static ProgramObject _skinProgram; @@ -292,12 +297,19 @@ private: static ProgramObject _skinShadowSpecularMapProgram; static ProgramObject _skinShadowNormalSpecularMapProgram; + static ProgramObject _skinCascadedShadowMapProgram; + static ProgramObject _skinCascadedShadowNormalMapProgram; + static ProgramObject _skinCascadedShadowSpecularMapProgram; + static ProgramObject _skinCascadedShadowNormalSpecularMapProgram; + static ProgramObject _skinShadowProgram; static int _normalMapTangentLocation; static int _normalSpecularMapTangentLocation; static int _shadowNormalMapTangentLocation; static int _shadowNormalSpecularMapTangentLocation; + static int _cascadedShadowNormalMapTangentLocation; + static int _cascadedShadowNormalSpecularMapTangentLocation; class SkinLocations { public: @@ -315,6 +327,10 @@ private: static SkinLocations _skinShadowNormalMapLocations; static SkinLocations _skinShadowSpecularMapLocations; static SkinLocations _skinShadowNormalSpecularMapLocations; + static SkinLocations _skinCascadedShadowMapLocations; + static SkinLocations _skinCascadedShadowNormalMapLocations; + static SkinLocations _skinCascadedShadowSpecularMapLocations; + static SkinLocations _skinCascadedShadowNormalSpecularMapLocations; static SkinLocations _skinShadowLocations; static void initSkinProgram(ProgramObject& program, SkinLocations& locations, From 7e3ef34e6c2ddb053843bc98e8fed8d902c28437 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 29 May 2014 15:34:20 -0700 Subject: [PATCH 15/27] CR feedback --- interface/src/ui/Stats.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp index d7ca0152fd..42eae260c7 100644 --- a/interface/src/ui/Stats.cpp +++ b/interface/src/ui/Stats.cpp @@ -219,9 +219,6 @@ void Stats::display( int totalServers = NodeList::getInstance()->size(); lines = _expanded ? 5 : 3; - - - drawBackground(backgroundColor, horizontalOffset, 0, _generalStatsWidth, lines * STATS_PELS_PER_LINE + 10); horizontalOffset += 5; From c7b636365c1ef352d74cc3573b9304a3f6f71f5d Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 29 May 2014 15:50:23 -0700 Subject: [PATCH 16/27] Don't attach to joints in range when I grab --- examples/editModels.js | 40 ++++++++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 89be4089a0..6857ed18cf 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -88,6 +88,8 @@ function controller(wichSide) { this.oldModelPosition; this.oldModelRadius; + this.jointsIntersectingFronStart = []; + this.laser = Overlays.addOverlay("line3d", { position: { x: 0, y: 0, z: 0 }, end: { x: 0, y: 0, z: 0 }, @@ -142,6 +144,14 @@ function controller(wichSide) { this.oldModelPosition = properties.position; this.oldModelRotation = properties.modelRotation; this.oldModelRadius = properties.radius; + + this.jointsIntersectingFronStart = []; + for (var i = 0; i < jointList.length; i++) { + var distance = Vec3.distance(MyAvatar.getJointPosition(jointList[i]), this.oldModelPosition); + if (distance < this.oldModelRadius) { + this.jointsIntersectingFronStart.push(i); + } + } } } @@ -161,27 +171,33 @@ function controller(wichSide) { } } - print("closestJoint: " + jojntList[closestJointIndex]); + print("closestJoint: " + jointList[closestJointIndex]); print("closestJointDistance (attach max distance): " + closestJointDistance + " (" + this.oldModelRadius + ")"); if (closestJointDistance < this.oldModelRadius) { - print("Attaching to " + jointList[closestJointIndex]); - var jointPosition = MyAvatar.getJointPosition(jointList[closestJointIndex]); - var jointRotation = MyAvatar.getJointCombinedRotation(jointList[closestJointIndex]); - var attachmentOffset = Vec3.subtract(this.oldModelPosition, jointPosition); - attachmentOffset = Vec3.multiplyQbyV(Quat.inverse(jointRotation), attachmentOffset); - var attachmentRotation = Quat.multiply(Quat.inverse(jointRotation), this.oldModelRotation); - - MyAvatar.attach(this.modelURL, jointList[closestJointIndex], - attachmentOffset, attachmentRotation, 2.0 * this.oldModelRadius, - true, false); - Models.deleteModel(this.modelID); + if (this.jointsIntersectingFronStart.indexOf(closestJointIndex) != -1) { + // Do nothing + } else { + print("Attaching to " + jointList[closestJointIndex]); + var jointPosition = MyAvatar.getJointPosition(jointList[closestJointIndex]); + var jointRotation = MyAvatar.getJointCombinedRotation(jointList[closestJointIndex]); + + var attachmentOffset = Vec3.subtract(this.oldModelPosition, jointPosition); + attachmentOffset = Vec3.multiplyQbyV(Quat.inverse(jointRotation), attachmentOffset); + var attachmentRotation = Quat.multiply(Quat.inverse(jointRotation), this.oldModelRotation); + + MyAvatar.attach(this.modelURL, jointList[closestJointIndex], + attachmentOffset, attachmentRotation, 2.0 * this.oldModelRadius, + true, false); + Models.deleteModel(this.modelID); + } } } this.grabbing = false; this.modelID.isKnownID = false; + this.jointsIntersectingFronStart = []; } this.checkTrigger = function () { From fd0c19513209d2ec40a509d2df68e30d2586c6bb Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 29 May 2014 15:55:17 -0700 Subject: [PATCH 17/27] Code cleanup --- examples/editModels.js | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 6857ed18cf..deada7e1aa 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -305,28 +305,9 @@ function controller(wichSide) { position: newPosition, modelRotation: newRotation }); -// print("Moving " + this.modelID.id); -// Vec3.print("Old Position: ", this.oldModelPosition); -// Vec3.print("Sav Position: ", newPosition); -// Quat.print("Old Rotation: ", this.oldModelRotation); -// Quat.print("New Rotation: ", newRotation); this.oldModelRotation = newRotation; this.oldModelPosition = newPosition; - - - var closestJointIndex = -1; - var closestJointDistance = 10; - for (var i = 0; i < jointList.length; i++) { - var distance = Vec3.distance(MyAvatar.getJointPosition(jointList[i]), newPosition); - if (distance < closestJointDistance) { - closestJointDistance = distance; - closestJointIndex = i; - } - } -// -// print("closestJointIndex: " + closestJointIndex); -// print("closestJointDistance: " + closestJointDistance); } } From b89d0a292cc7a25ae9b0ea4151055ebd7d7a9262 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 29 May 2014 15:56:46 -0700 Subject: [PATCH 18/27] code cleanup --- examples/editModels.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index deada7e1aa..d07ca4c282 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -733,10 +733,6 @@ function scriptEnding() { rightController.cleanup(); toolBar.cleanup(); cleanupModelMenus(); - - Overlays.deleteOverlay(r); - Overlays.deleteOverlay(g); - Overlays.deleteOverlay(b); } Script.scriptEnding.connect(scriptEnding); From 0b4484a153ec22e58f7a244d9e0e2bc6fdb14d10 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 29 May 2014 16:49:51 -0700 Subject: [PATCH 19/27] Trying a different way of determining the cascade threshold distances. --- interface/src/Application.cpp | 3 +++ interface/src/Application.h | 3 +++ interface/src/voxels/VoxelSystem.cpp | 5 +++-- interface/src/voxels/VoxelSystem.h | 1 + 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index af94ddba01..bcb52cfabc 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2298,6 +2298,9 @@ void Application::updateShadowMap() { for (size_t j = 0; j < sizeof(points) / sizeof(points[0]); j++) { radius = qMax(radius, glm::distance(points[j], center)); } + if (i < 3) { + _shadowDistances[i] = -glm::distance(_viewFrustum.getPosition(), center) - radius; + } center = inverseRotation * center; // to reduce texture "shimmer," move in texel increments diff --git a/interface/src/Application.h b/interface/src/Application.h index 68d437815b..3fcf40b95b 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -266,6 +266,8 @@ public: void getModelViewMatrix(glm::dmat4* modelViewMatrix); void getProjectionMatrix(glm::dmat4* projectionMatrix); + const glm::vec3& getShadowDistances() const { return _shadowDistances; } + /// Computes the off-axis frustum parameters for the view frustum, taking mirroring into account. void computeOffAxisFrustum(float& left, float& right, float& bottom, float& top, float& nearVal, float& farVal, glm::vec4& nearClipPlane, glm::vec4& farClipPlane) const; @@ -493,6 +495,7 @@ private: static const int CASCADED_SHADOW_MATRIX_COUNT = 4; glm::mat4 _shadowMatrices[CASCADED_SHADOW_MATRIX_COUNT]; + glm::vec3 _shadowDistances; Environment _environment; diff --git a/interface/src/voxels/VoxelSystem.cpp b/interface/src/voxels/VoxelSystem.cpp index 3525a086b4..2b86a58d9b 100644 --- a/interface/src/voxels/VoxelSystem.cpp +++ b/interface/src/voxels/VoxelSystem.cpp @@ -528,8 +528,7 @@ void VoxelSystem::initVoxelMemory() { _cascadedShadowMapProgram.bind(); _cascadedShadowMapProgram.setUniformValue("shadowMap", 0); - _cascadedShadowMapProgram.setUniformValue("shadowDistances", -SHADOW_MATRIX_DISTANCES[1], - -SHADOW_MATRIX_DISTANCES[2], -SHADOW_MATRIX_DISTANCES[3]); + _shadowDistancesLocation = _cascadedShadowMapProgram.uniformLocation("shadowDistances"); _cascadedShadowMapProgram.release(); } } @@ -1179,6 +1178,7 @@ glm::vec3 VoxelSystem::computeVoxelVertex(const glm::vec3& startVertex, float vo ProgramObject VoxelSystem::_perlinModulateProgram; ProgramObject VoxelSystem::_shadowMapProgram; ProgramObject VoxelSystem::_cascadedShadowMapProgram; +int VoxelSystem::_shadowDistancesLocation; void VoxelSystem::init() { if (_initialized) { @@ -1502,6 +1502,7 @@ void VoxelSystem::applyScaleAndBindProgram(bool texture) { if (Menu::getInstance()->getShadowsEnabled()) { if (Menu::getInstance()->isOptionChecked(MenuOption::CascadedShadows)) { _cascadedShadowMapProgram.bind(); + _cascadedShadowMapProgram.setUniform(_shadowDistancesLocation, Application::getInstance()->getShadowDistances()); } else { _shadowMapProgram.bind(); } diff --git a/interface/src/voxels/VoxelSystem.h b/interface/src/voxels/VoxelSystem.h index acd0cd170a..71abc9ca93 100644 --- a/interface/src/voxels/VoxelSystem.h +++ b/interface/src/voxels/VoxelSystem.h @@ -234,6 +234,7 @@ private: static ProgramObject _perlinModulateProgram; static ProgramObject _shadowMapProgram; static ProgramObject _cascadedShadowMapProgram; + static int _shadowDistancesLocation; int _hookID; std::vector _freeIndexes; From d17eeaf35be7c8a4c98b0bd2722de6e31a16d817 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Thu, 29 May 2014 16:50:13 -0700 Subject: [PATCH 20/27] remove old oculus yaw offset, expand limit on head yaw --- interface/src/avatar/MyAvatar.cpp | 43 +++---------------------------- libraries/avatars/src/HeadData.h | 4 +-- 2 files changed, 5 insertions(+), 42 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 582a3934d4..569dce044e 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -76,8 +76,7 @@ MyAvatar::MyAvatar() : _lastFloorContactPoint(0.0f), _lookAtTargetAvatar(), _shouldRender(true), - _billboardValid(false), - _oculusYawOffset(0.0f) + _billboardValid(false) { for (int i = 0; i < MAX_DRIVE_KEYS; i++) { _driveKeys[i] = 0.0f; @@ -90,8 +89,7 @@ MyAvatar::~MyAvatar() { void MyAvatar::reset() { _skeletonModel.reset(); - getHead()->reset(); - _oculusYawOffset = 0.0f; + getHead()->reset(); setVelocity(glm::vec3(0.0f)); setThrust(glm::vec3(0.0f)); @@ -828,43 +826,8 @@ void MyAvatar::updateOrientation(float deltaTime) { OculusManager::getEulerAngles(yaw, pitch, roll); // ... so they need to be converted to degrees before we do math... - // The neck is limited in how much it can yaw, so we check its relative - // yaw from the body and yaw the body if necessary. - yaw *= DEGREES_PER_RADIAN; - float bodyToHeadYaw = yaw - _oculusYawOffset; - const float MAX_NECK_YAW = 85.0f; // degrees - if ((fabs(bodyToHeadYaw) > 2.0f * MAX_NECK_YAW) && (yaw * _oculusYawOffset < 0.0f)) { - // We've wrapped around the range for yaw so adjust - // the measured yaw to be relative to _oculusYawOffset. - if (yaw > 0.0f) { - yaw -= 360.0f; - } else { - yaw += 360.0f; - } - bodyToHeadYaw = yaw - _oculusYawOffset; - } - - float delta = fabs(bodyToHeadYaw) - MAX_NECK_YAW; - if (delta > 0.0f) { - yaw = MAX_NECK_YAW; - if (bodyToHeadYaw < 0.0f) { - delta *= -1.0f; - bodyToHeadYaw = -MAX_NECK_YAW; - } else { - bodyToHeadYaw = MAX_NECK_YAW; - } - // constrain _oculusYawOffset to be within range [-180,180] - _oculusYawOffset = fmod((_oculusYawOffset + delta) + 180.0f, 360.0f) - 180.0f; - - // We must adjust the body orientation using a delta rotation (rather than - // doing yaw math) because the body's yaw ranges are not the same - // as what the Oculus API provides. - glm::quat bodyCorrection = glm::angleAxis(glm::radians(delta), _worldUpDirection); - orientation = orientation * bodyCorrection; - } Head* head = getHead(); - head->setBaseYaw(bodyToHeadYaw); - + head->setBaseYaw(yaw * DEGREES_PER_RADIAN); head->setBasePitch(pitch * DEGREES_PER_RADIAN); head->setBaseRoll(roll * DEGREES_PER_RADIAN); } diff --git a/libraries/avatars/src/HeadData.h b/libraries/avatars/src/HeadData.h index b76bd189bf..9e2920ae85 100644 --- a/libraries/avatars/src/HeadData.h +++ b/libraries/avatars/src/HeadData.h @@ -20,8 +20,8 @@ #include // degrees -const float MIN_HEAD_YAW = -110.f; -const float MAX_HEAD_YAW = 110.f; +const float MIN_HEAD_YAW = -180.f; +const float MAX_HEAD_YAW = 180.f; const float MIN_HEAD_PITCH = -60.f; const float MAX_HEAD_PITCH = 60.f; const float MIN_HEAD_ROLL = -50.f; From 12beef7fec0a8e958c77a82a11b5322696917be4 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 29 May 2014 17:08:36 -0700 Subject: [PATCH 21/27] Apply the new shadow distances to the models, too. --- interface/src/renderer/Model.cpp | 32 +++++++++++++++++++++----------- interface/src/renderer/Model.h | 6 ++++++ 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index a550064ef1..85392bd353 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -96,6 +96,11 @@ int Model::_shadowNormalSpecularMapTangentLocation; int Model::_cascadedShadowNormalMapTangentLocation; int Model::_cascadedShadowNormalSpecularMapTangentLocation; +int Model::_cascadedShadowMapDistancesLocation; +int Model::_cascadedShadowNormalMapDistancesLocation; +int Model::_cascadedShadowSpecularMapDistancesLocation; +int Model::_cascadedShadowNormalSpecularMapDistancesLocation; + Model::SkinLocations Model::_skinLocations; Model::SkinLocations Model::_skinNormalMapLocations; Model::SkinLocations Model::_skinSpecularMapLocations; @@ -144,12 +149,11 @@ void Model::initSkinProgram(ProgramObject& program, Model::SkinLocations& locati locations.clusterIndices = program.attributeLocation("clusterIndices"); locations.clusterWeights = program.attributeLocation("clusterWeights"); locations.tangent = program.attributeLocation("tangent"); + locations.shadowDistances = program.uniformLocation("shadowDistances"); program.setUniformValue("diffuseMap", 0); program.setUniformValue("normalMap", 1); program.setUniformValue("specularMap", specularTextureUnit); program.setUniformValue("shadowMap", shadowTextureUnit); - program.setUniformValue("shadowDistances", -SHADOW_MATRIX_DISTANCES[1], - -SHADOW_MATRIX_DISTANCES[2], -SHADOW_MATRIX_DISTANCES[3]); program.release(); } @@ -310,8 +314,7 @@ void Model::init() { _cascadedShadowMapProgram.bind(); _cascadedShadowMapProgram.setUniformValue("diffuseMap", 0); _cascadedShadowMapProgram.setUniformValue("shadowMap", 1); - _cascadedShadowMapProgram.setUniformValue("shadowDistances", -SHADOW_MATRIX_DISTANCES[1], - -SHADOW_MATRIX_DISTANCES[2], -SHADOW_MATRIX_DISTANCES[3]); + _cascadedShadowMapDistancesLocation = _cascadedShadowMapProgram.uniformLocation("shadowDistances"); _cascadedShadowMapProgram.release(); _cascadedShadowNormalMapProgram.addShaderFromSourceFile(QGLShader::Vertex, @@ -324,8 +327,7 @@ void Model::init() { _cascadedShadowNormalMapProgram.setUniformValue("diffuseMap", 0); _cascadedShadowNormalMapProgram.setUniformValue("normalMap", 1); _cascadedShadowNormalMapProgram.setUniformValue("shadowMap", 2); - _cascadedShadowNormalMapProgram.setUniformValue("shadowDistances", -SHADOW_MATRIX_DISTANCES[1], - -SHADOW_MATRIX_DISTANCES[2], -SHADOW_MATRIX_DISTANCES[3]); + _cascadedShadowNormalMapDistancesLocation = _cascadedShadowNormalMapProgram.uniformLocation("shadowDistances"); _cascadedShadowNormalMapTangentLocation = _cascadedShadowNormalMapProgram.attributeLocation("tangent"); _cascadedShadowNormalMapProgram.release(); @@ -339,8 +341,7 @@ void Model::init() { _cascadedShadowSpecularMapProgram.setUniformValue("diffuseMap", 0); _cascadedShadowSpecularMapProgram.setUniformValue("specularMap", 1); _cascadedShadowSpecularMapProgram.setUniformValue("shadowMap", 2); - _cascadedShadowSpecularMapProgram.setUniformValue("shadowDistances", -SHADOW_MATRIX_DISTANCES[1], - -SHADOW_MATRIX_DISTANCES[2], -SHADOW_MATRIX_DISTANCES[3]); + _cascadedShadowSpecularMapDistancesLocation = _cascadedShadowSpecularMapProgram.uniformLocation("shadowDistances"); _cascadedShadowSpecularMapProgram.release(); _cascadedShadowNormalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Vertex, @@ -354,8 +355,8 @@ void Model::init() { _cascadedShadowNormalSpecularMapProgram.setUniformValue("normalMap", 1); _cascadedShadowNormalSpecularMapProgram.setUniformValue("specularMap", 2); _cascadedShadowNormalSpecularMapProgram.setUniformValue("shadowMap", 3); - _cascadedShadowNormalSpecularMapProgram.setUniformValue("shadowDistances", -SHADOW_MATRIX_DISTANCES[1], - -SHADOW_MATRIX_DISTANCES[2], -SHADOW_MATRIX_DISTANCES[3]); + _cascadedShadowNormalSpecularMapDistancesLocation = + _cascadedShadowNormalSpecularMapProgram.uniformLocation("shadowDistances"); _cascadedShadowNormalSpecularMapTangentLocation = _cascadedShadowNormalSpecularMapProgram.attributeLocation("tangent"); _cascadedShadowNormalSpecularMapProgram.release(); @@ -1641,6 +1642,7 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent, bool re ProgramObject* skinProgram = &_skinProgram; SkinLocations* skinLocations = &_skinLocations; int tangentLocation = _normalMapTangentLocation; + int shadowDistancesLocation = _cascadedShadowMapDistancesLocation; GLenum specularTextureUnit = 0; GLenum shadowTextureUnit = 0; if (mode == SHADOW_RENDER_MODE) { @@ -1656,6 +1658,7 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent, bool re skinProgram = &_skinCascadedShadowNormalSpecularMapProgram; skinLocations = &_skinCascadedShadowNormalSpecularMapLocations; tangentLocation = _cascadedShadowNormalSpecularMapTangentLocation; + shadowDistancesLocation = _cascadedShadowNormalSpecularMapDistancesLocation; } else { program = &_shadowNormalSpecularMapProgram; skinProgram = &_skinShadowNormalSpecularMapProgram; @@ -1677,6 +1680,7 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent, bool re skinProgram = &_skinCascadedShadowNormalMapProgram; skinLocations = &_skinCascadedShadowNormalMapLocations; tangentLocation = _cascadedShadowNormalMapTangentLocation; + shadowDistancesLocation = _cascadedShadowNormalMapDistancesLocation; } else { program = &_shadowNormalMapProgram; skinProgram = &_skinShadowNormalMapProgram; @@ -1695,6 +1699,7 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent, bool re program = &_cascadedShadowSpecularMapProgram; skinProgram = &_skinCascadedShadowSpecularMapProgram; skinLocations = &_skinCascadedShadowSpecularMapLocations; + shadowDistancesLocation = _cascadedShadowSpecularMapDistancesLocation; } else { program = &_shadowSpecularMapProgram; skinProgram = &_skinShadowSpecularMapProgram; @@ -1740,10 +1745,15 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent, bool re skinProgram->enableAttributeArray(skinLocations->clusterWeights); activeProgram = skinProgram; tangentLocation = skinLocations->tangent; - + if (cascadedShadows) { + program->setUniform(skinLocations->shadowDistances, Application::getInstance()->getShadowDistances()); + } } else { glMultMatrixf((const GLfloat*)&state.clusterMatrices[0]); program->bind(); + if (cascadedShadows) { + program->setUniform(shadowDistancesLocation, Application::getInstance()->getShadowDistances()); + } } if (mesh.blendshapes.isEmpty()) { diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 5561855afb..5aa2c2160b 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -311,12 +311,18 @@ private: static int _cascadedShadowNormalMapTangentLocation; static int _cascadedShadowNormalSpecularMapTangentLocation; + static int _cascadedShadowMapDistancesLocation; + static int _cascadedShadowNormalMapDistancesLocation; + static int _cascadedShadowSpecularMapDistancesLocation; + static int _cascadedShadowNormalSpecularMapDistancesLocation; + class SkinLocations { public: int clusterMatrices; int clusterIndices; int clusterWeights; int tangent; + int shadowDistances; }; static SkinLocations _skinLocations; From 34091128d8ce1d27a8a0d08ae924f50afc559a71 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 29 May 2014 17:22:59 -0700 Subject: [PATCH 22/27] Distance tweak. --- interface/src/Application.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ba3904d44e..152b780363 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2349,7 +2349,8 @@ void Application::updateShadowMap() { radius = qMax(radius, glm::distance(points[j], center)); } if (i < 3) { - _shadowDistances[i] = -glm::distance(_viewFrustum.getPosition(), center) - radius; + const float RADIUS_SCALE = 0.5f; + _shadowDistances[i] = -glm::distance(_viewFrustum.getPosition(), center) - radius * RADIUS_SCALE; } center = inverseRotation * center; From ac22cebde1922be01e12b7d95b794afd565d0493 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 29 May 2014 17:41:40 -0700 Subject: [PATCH 23/27] more performance stats debugging --- interface/src/Application.cpp | 61 +++++++++++++-------- interface/src/Menu.cpp | 3 ++ interface/src/Menu.h | 3 ++ interface/src/avatar/MyAvatar.cpp | 89 ++++++++++++++++++++++--------- interface/src/ui/Stats.cpp | 10 +++- 5 files changed, 116 insertions(+), 50 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index db6333acee..1cb215ff3d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2001,8 +2001,14 @@ void Application::update(float deltaTime) { _joystickManager.update(); _prioVR.update(deltaTime); } - updateMyAvatar(deltaTime); // Sample hardware, update view frustum if needed, and send avatar data to mixer/nodes + + { + PerformanceTimer perfTimer("idle/update/updateMyAvatar"); + updateMyAvatar(deltaTime); // Sample hardware, update view frustum if needed, and send avatar data to mixer/nodes + } + updateThreads(deltaTime); // If running non-threaded, then give the threads some time to process... + { PerformanceTimer perfTimer("idle/update/_avatarManager"); _avatarManager.updateOtherAvatars(deltaTime); //loop through all the other avatars and simulate them... @@ -2039,17 +2045,22 @@ void Application::update(float deltaTime) { } void Application::updateMyAvatar(float deltaTime) { - PerformanceTimer perfTimer("idle/update/updateMyAvatar"); + PerformanceTimer perfTimer("updateMyAvatar"); bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::updateMyAvatar()"); - _myAvatar->update(deltaTime); + { + PerformanceTimer perfTimer("updateMyAvatar/_myAvatar->update()"); + _myAvatar->update(deltaTime); + } - // send head/hand data to the avatar mixer and voxel server - QByteArray packet = byteArrayWithPopulatedHeader(PacketTypeAvatarData); - packet.append(_myAvatar->toByteArray()); - - controlledBroadcastToNodes(packet, NodeSet() << NodeType::AvatarMixer); + { + // send head/hand data to the avatar mixer and voxel server + PerformanceTimer perfTimer("updateMyAvatar/sendToAvatarMixer"); + QByteArray packet = byteArrayWithPopulatedHeader(PacketTypeAvatarData); + packet.append(_myAvatar->toByteArray()); + controlledBroadcastToNodes(packet, NodeSet() << NodeType::AvatarMixer); + } // Update _viewFrustum with latest camera and view frustum data... // NOTE: we get this from the view frustum, to make it simpler, since the @@ -2057,22 +2068,28 @@ void Application::updateMyAvatar(float deltaTime) { // We could optimize this to not actually load the viewFrustum, since we don't // actually need to calculate the view frustum planes to send these details // to the server. - loadViewFrustum(_myCamera, _viewFrustum); + { + PerformanceTimer perfTimer("updateMyAvatar/loadViewFrustum"); + loadViewFrustum(_myCamera, _viewFrustum); + } // Update my voxel servers with my current voxel query... - quint64 now = usecTimestampNow(); - quint64 sinceLastQuery = now - _lastQueriedTime; - const quint64 TOO_LONG_SINCE_LAST_QUERY = 3 * USECS_PER_SECOND; - bool queryIsDue = sinceLastQuery > TOO_LONG_SINCE_LAST_QUERY; - bool viewIsDifferentEnough = !_lastQueriedViewFrustum.isVerySimilar(_viewFrustum); + { + PerformanceTimer perfTimer("updateMyAvatar/queryOctree"); + quint64 now = usecTimestampNow(); + quint64 sinceLastQuery = now - _lastQueriedTime; + const quint64 TOO_LONG_SINCE_LAST_QUERY = 3 * USECS_PER_SECOND; + bool queryIsDue = sinceLastQuery > TOO_LONG_SINCE_LAST_QUERY; + bool viewIsDifferentEnough = !_lastQueriedViewFrustum.isVerySimilar(_viewFrustum); - // if it's been a while since our last query or the view has significantly changed then send a query, otherwise suppress it - if (queryIsDue || viewIsDifferentEnough) { - _lastQueriedTime = now; - queryOctree(NodeType::VoxelServer, PacketTypeVoxelQuery, _voxelServerJurisdictions); - queryOctree(NodeType::ParticleServer, PacketTypeParticleQuery, _particleServerJurisdictions); - queryOctree(NodeType::ModelServer, PacketTypeModelQuery, _modelServerJurisdictions); - _lastQueriedViewFrustum = _viewFrustum; + // if it's been a while since our last query or the view has significantly changed then send a query, otherwise suppress it + if (queryIsDue || viewIsDifferentEnough) { + _lastQueriedTime = now; + queryOctree(NodeType::VoxelServer, PacketTypeVoxelQuery, _voxelServerJurisdictions); + queryOctree(NodeType::ParticleServer, PacketTypeParticleQuery, _particleServerJurisdictions); + queryOctree(NodeType::ModelServer, PacketTypeModelQuery, _modelServerJurisdictions); + _lastQueriedViewFrustum = _viewFrustum; + } } } @@ -2300,7 +2317,7 @@ glm::vec3 Application::getSunDirection() { } void Application::updateShadowMap() { - PerformanceTimer perfTimer("pintGL/updateShadowMap"); + PerformanceTimer perfTimer("paintGL/updateShadowMap"); QOpenGLFramebufferObject* fbo = _textureCache.getShadowFramebufferObject(); fbo->bind(); glEnable(GL_DEPTH_TEST); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 25bf65d18e..72029df2cd 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -391,6 +391,9 @@ Menu::Menu() : QMenu* perfTimerMenu = timingMenu->addMenu("Performance Timer"); addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::DisplayTimingDetails, 0, true); addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandDisplaySideTiming, 0, false); + addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandAvatarSimulateTiming, 0, false); + addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandAvatarUpdateTiming, 0, false); + addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandMiscAvatarTiming, 0, false); addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandIdleTiming, 0, false); addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandPaintGLTiming, 0, false); addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandUpdateTiming, 0, false); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index c1a9e4274b..9b05df910b 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -326,6 +326,9 @@ namespace MenuOption { const QString EchoLocalAudio = "Echo Local Audio"; const QString EchoServerAudio = "Echo Server Audio"; const QString Enable3DTVMode = "Enable 3DTV Mode"; + const QString ExpandMiscAvatarTiming = "Expand Misc MyAvatar Timing"; + const QString ExpandAvatarUpdateTiming = "Expand MyAvatar update Timing"; + const QString ExpandAvatarSimulateTiming = "Expand MyAvatar simulate Timing"; const QString ExpandDisplaySideTiming = "Expand Display Side Timing"; const QString ExpandIdleTiming = "Expand Idle Timing"; const QString ExpandPaintGLTiming = "Expand PaintGL Timing"; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 582a3934d4..ff8b2b5e91 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -24,9 +24,9 @@ #include #include #include -#include - +#include #include +#include #include "Application.h" #include "Audio.h" @@ -103,10 +103,15 @@ void MyAvatar::reset() { } void MyAvatar::update(float deltaTime) { + PerformanceTimer perfTimer("MyAvatar::update/"); Head* head = getHead(); head->relaxLean(deltaTime); - updateFromTrackers(deltaTime); + { + PerformanceTimer perfTimer("MyAvatar::update/updateFromTrackers"); + updateFromTrackers(deltaTime); + } if (Menu::getInstance()->isOptionChecked(MenuOption::MoveWithLean)) { + PerformanceTimer perfTimer("MyAvatar::update/moveWithLean"); // Faceshift drive is enabled, set the avatar drive based on the head position moveWithLean(); } @@ -117,13 +122,18 @@ void MyAvatar::update(float deltaTime) { head->setAudioAverageLoudness(audio->getAudioAverageInputLoudness()); if (_motionBehaviors & AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY) { + PerformanceTimer perfTimer("MyAvatar::update/gravityWork"); setGravity(Application::getInstance()->getEnvironment()->getGravity(getPosition())); } - simulate(deltaTime); + { + PerformanceTimer perfTimer("MyAvatar::update/simulate"); + simulate(deltaTime); + } } void MyAvatar::simulate(float deltaTime) { + PerformanceTimer perfTimer("MyAvatar::simulate"); if (_scale != _targetScale) { float scale = (1.0f - SMOOTHING_RATIO) * _scale + SMOOTHING_RATIO * _targetScale; @@ -134,34 +144,56 @@ void MyAvatar::simulate(float deltaTime) { // no extra movement of the hand here any more ... _handState = HAND_STATE_NULL; - updateOrientation(deltaTime); - updatePosition(deltaTime); - - // update avatar skeleton and simulate hand and head - getHand()->collideAgainstOurself(); - getHand()->simulate(deltaTime, true); - - _skeletonModel.simulate(deltaTime); - simulateAttachments(deltaTime); - - // copy out the skeleton joints from the model - _jointData.resize(_skeletonModel.getJointStateCount()); - for (int i = 0; i < _jointData.size(); i++) { - JointData& data = _jointData[i]; - data.valid = _skeletonModel.getJointState(i, data.rotation); + { + PerformanceTimer perfTimer("MyAvatar::simulate/updateOrientation"); + updateOrientation(deltaTime); + } + { + PerformanceTimer perfTimer("MyAvatar::simulate/updatePosition"); + updatePosition(deltaTime); } - Head* head = getHead(); - glm::vec3 headPosition; - if (!_skeletonModel.getHeadPosition(headPosition)) { - headPosition = _position; + { + PerformanceTimer perfTimer("MyAvatar::simulate/hand Collision,simulate"); + // update avatar skeleton and simulate hand and head + getHand()->collideAgainstOurself(); + getHand()->simulate(deltaTime, true); + } + + { + PerformanceTimer perfTimer("MyAvatar::simulate/_skeletonModel.simulate()"); + _skeletonModel.simulate(deltaTime); + } + { + PerformanceTimer perfTimer("MyAvatar::simulate/simulateAttachments"); + simulateAttachments(deltaTime); + } + + { + PerformanceTimer perfTimer("MyAvatar::simulate/copy joints"); + // copy out the skeleton joints from the model + _jointData.resize(_skeletonModel.getJointStateCount()); + for (int i = 0; i < _jointData.size(); i++) { + JointData& data = _jointData[i]; + data.valid = _skeletonModel.getJointState(i, data.rotation); + } + } + + { + PerformanceTimer perfTimer("MyAvatar::simulate/head Simulate"); + Head* head = getHead(); + glm::vec3 headPosition; + if (!_skeletonModel.getHeadPosition(headPosition)) { + headPosition = _position; + } + head->setPosition(headPosition); + head->setScale(_scale); + head->simulate(deltaTime, true); } - head->setPosition(headPosition); - head->setScale(_scale); - head->simulate(deltaTime, true); // now that we're done stepping the avatar forward in time, compute new collisions if (_collisionGroups != 0) { + PerformanceTimer perfTimer("MyAvatar::simulate/_collisionGroups"); Camera* myCamera = Application::getInstance()->getCamera(); float radius = getSkeletonHeight() * COLLISION_RADIUS_SCALE; @@ -171,14 +203,17 @@ void MyAvatar::simulate(float deltaTime) { } updateShapePositions(); if (_collisionGroups & COLLISION_GROUP_ENVIRONMENT) { + PerformanceTimer perfTimer("MyAvatar::simulate/updateCollisionWithEnvironment"); updateCollisionWithEnvironment(deltaTime, radius); } if (_collisionGroups & COLLISION_GROUP_VOXELS) { + PerformanceTimer perfTimer("MyAvatar::simulate/updateCollisionWithVoxels"); updateCollisionWithVoxels(deltaTime, radius); } else { _trapDuration = 0.0f; } if (_collisionGroups & COLLISION_GROUP_AVATARS) { + PerformanceTimer perfTimer("MyAvatar::simulate/updateCollisionWithAvatars"); updateCollisionWithAvatars(deltaTime); } } @@ -791,6 +826,7 @@ bool MyAvatar::shouldRenderHead(const glm::vec3& cameraPosition, RenderMode rend } float MyAvatar::computeDistanceToFloor(const glm::vec3& startPoint) { + PerformanceTimer perfTimer("MyAvatar::computeDistanceToFloor()"); glm::vec3 direction = -_worldUpDirection; OctreeElement* elementHit; // output from findRayIntersection float distance = FLT_MAX; // output from findRayIntersection @@ -876,6 +912,7 @@ void MyAvatar::updateOrientation(float deltaTime) { const float NEARBY_FLOOR_THRESHOLD = 5.0f; void MyAvatar::updatePosition(float deltaTime) { + PerformanceTimer perfTimer("MyAvatar::updatePosition"); float keyboardInput = fabsf(_driveKeys[FWD] - _driveKeys[BACK]) + fabsf(_driveKeys[RIGHT] - _driveKeys[LEFT]) + fabsf(_driveKeys[UP] - _driveKeys[DOWN]); diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp index 42eae260c7..fa62ecdb9b 100644 --- a/interface/src/ui/Stats.cpp +++ b/interface/src/ui/Stats.cpp @@ -173,6 +173,12 @@ bool Stats::includeTimingRecord(const QString& name) { included = Menu::getInstance()->isOptionChecked(MenuOption::ExpandUpdateTiming); } else if (name.startsWith("idle/")) { included = Menu::getInstance()->isOptionChecked(MenuOption::ExpandIdleTiming); + } else if (name.startsWith("MyAvatar::simulate")) { + included = Menu::getInstance()->isOptionChecked(MenuOption::ExpandAvatarSimulateTiming); + } else if (name.startsWith("MyAvatar::update/") || name.startsWith("updateMyAvatar")) { + included = Menu::getInstance()->isOptionChecked(MenuOption::ExpandAvatarUpdateTiming); + } else if (name.startsWith("MyAvatar::")) { + included = Menu::getInstance()->isOptionChecked(MenuOption::ExpandMiscAvatarTiming); } else if (name == "paintGL/displaySide") { included = Menu::getInstance()->isOptionChecked(MenuOption::ExpandDisplaySideTiming) || Menu::getInstance()->isOptionChecked(MenuOption::ExpandPaintGLTiming); @@ -556,14 +562,14 @@ void Stats::display( char perfLine[TIMER_OUTPUT_LINE_LENGTH]; verticalOffset += STATS_PELS_PER_LINE; drawText(horizontalOffset, verticalOffset, scale, rotation, font, - "---------------- Function --------------- --msecs- -calls--", color); + "--------------------- Function -------------------- --msecs- -calls--", color); const QMap& allRecords = PerformanceTimer::getAllTimerRecords(); QMapIterator i(allRecords); while (i.hasNext()) { i.next(); if (includeTimingRecord(i.key())) { - sprintf(perfLine, "%40s: %8.4f [%6llu]", qPrintable(i.key()), + sprintf(perfLine, "%50s: %8.4f [%6llu]", qPrintable(i.key()), (float)i.value().getMovingAverage() / (float)USECS_PER_MSEC, i.value().getCount()); From 1eace78e4740db99652def5dd70db11f68b5b2ed Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 29 May 2014 17:46:25 -0700 Subject: [PATCH 24/27] Hide distances; they no longer need to be publicly visible. --- interface/src/Application.cpp | 1 + interface/src/Application.h | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 152b780363..b4659cb828 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2310,6 +2310,7 @@ void Application::updateShadowMap() { glm::quat rotation = rotationBetween(IDENTITY_FRONT, lightDirection); glm::quat inverseRotation = glm::inverse(rotation); + const float SHADOW_MATRIX_DISTANCES[] = { 0.0f, 2.0f, 6.0f, 14.0f, 30.0f }; const glm::vec2 MAP_COORDS[] = { glm::vec2(0.0f, 0.0f), glm::vec2(0.5f, 0.0f), glm::vec2(0.0f, 0.5f), glm::vec2(0.5f, 0.5f) }; diff --git a/interface/src/Application.h b/interface/src/Application.h index c89c324ab1..f3d9c0fd27 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -126,8 +126,6 @@ static const float MIRROR_REARVIEW_DISTANCE = 0.65f; static const float MIRROR_REARVIEW_BODY_DISTANCE = 2.3f; static const float MIRROR_FIELD_OF_VIEW = 30.0f; -static const float SHADOW_MATRIX_DISTANCES[] = { 0.0f, 2.0f, 6.0f, 14.0f, 30.0f }; - class Application : public QApplication { Q_OBJECT From 17e3bd6110ff95c8f4f77c2733074b2c34fcc9bb Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 29 May 2014 18:24:21 -0700 Subject: [PATCH 25/27] CR comments --- examples/editModels.js | 10 +++++----- interface/src/avatar/Avatar.cpp | 28 ++++++++++++++++++++++++++-- interface/src/renderer/Model.cpp | 4 ++-- 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index d07ca4c282..1db6901e23 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -88,7 +88,7 @@ function controller(wichSide) { this.oldModelPosition; this.oldModelRadius; - this.jointsIntersectingFronStart = []; + this.jointsIntersectingFromStart = []; this.laser = Overlays.addOverlay("line3d", { position: { x: 0, y: 0, z: 0 }, @@ -145,11 +145,11 @@ function controller(wichSide) { this.oldModelRotation = properties.modelRotation; this.oldModelRadius = properties.radius; - this.jointsIntersectingFronStart = []; + this.jointsIntersectingFromStart = []; for (var i = 0; i < jointList.length; i++) { var distance = Vec3.distance(MyAvatar.getJointPosition(jointList[i]), this.oldModelPosition); if (distance < this.oldModelRadius) { - this.jointsIntersectingFronStart.push(i); + this.jointsIntersectingFromStart.push(i); } } } @@ -176,7 +176,7 @@ function controller(wichSide) { if (closestJointDistance < this.oldModelRadius) { - if (this.jointsIntersectingFronStart.indexOf(closestJointIndex) != -1) { + if (this.jointsIntersectingFromStart.indexOf(closestJointIndex) != -1) { // Do nothing } else { print("Attaching to " + jointList[closestJointIndex]); @@ -197,7 +197,7 @@ function controller(wichSide) { this.grabbing = false; this.modelID.isKnownID = false; - this.jointsIntersectingFronStart = []; + this.jointsIntersectingFromStart = []; } this.checkTrigger = function () { diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index ac6718dcc8..870d5b1a53 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -706,24 +706,48 @@ QStringList Avatar::getJointNames() const { } glm::vec3 Avatar::getJointPosition(int index) const { - glm::vec3 position(0,0,0); + if (QThread::currentThread() != thread()) { + glm::vec3 position; + QMetaObject::invokeMethod(const_cast(this), "getJointPosition", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(glm::vec3, position), Q_ARG(const int, index)); + return position; + } + glm::vec3 position; _skeletonModel.getJointPosition(index, position); return position; } glm::vec3 Avatar::getJointPosition(const QString& name) const { - glm::vec3 position(0,0,0); + if (QThread::currentThread() != thread()) { + glm::vec3 position; + QMetaObject::invokeMethod(const_cast(this), "getJointPosition", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(glm::vec3, position), Q_ARG(const QString&, name)); + return position; + } + glm::vec3 position; _skeletonModel.getJointPosition(getJointIndex(name), position); return position; } glm::quat Avatar::getJointCombinedRotation(int index) const { + if (QThread::currentThread() != thread()) { + glm::quat rotation; + QMetaObject::invokeMethod(const_cast(this), "getJointCombinedRotation", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(glm::quat, rotation), Q_ARG(const int, index)); + return rotation; + } glm::quat rotation; _skeletonModel.getJointCombinedRotation(index, rotation); return rotation; } glm::quat Avatar::getJointCombinedRotation(const QString& name) const { + if (QThread::currentThread() != thread()) { + glm::quat rotation; + QMetaObject::invokeMethod(const_cast(this), "getJointCombinedRotation", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(glm::quat, rotation), Q_ARG(const QString&, name)); + return rotation; + } glm::quat rotation; _skeletonModel.getJointCombinedRotation(getJointIndex(name), rotation); return rotation; diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index b41d440e16..ee774c183a 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -634,8 +634,8 @@ bool Model::getJointRotation(int jointIndex, glm::quat& rotation, bool fromBind) return false; } rotation = _jointStates[jointIndex]._combinedRotation * - (fromBind ? _geometry->getFBXGeometry().joints[jointIndex].inverseBindRotation : - _geometry->getFBXGeometry().joints[jointIndex].inverseDefaultRotation); + (fromBind ? _geometry->getFBXGeometry().joints[jointIndex].inverseBindRotation : + _geometry->getFBXGeometry().joints[jointIndex].inverseDefaultRotation); return true; } From e59e25372786fb87a05789dceeb23ae8bd4f4dfe Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 29 May 2014 18:32:11 -0700 Subject: [PATCH 26/27] fix ray intersection performance --- libraries/octree/src/Octree.cpp | 1 + libraries/octree/src/OctreeElement.cpp | 11 ++++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 3ec1871023..6cbce20dbc 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -600,6 +600,7 @@ public: bool found; }; + bool findRayIntersectionOp(OctreeElement* element, void* extraData) { RayArgs* args = static_cast(extraData); diff --git a/libraries/octree/src/OctreeElement.cpp b/libraries/octree/src/OctreeElement.cpp index 22320b5969..4e14f603e8 100644 --- a/libraries/octree/src/OctreeElement.cpp +++ b/libraries/octree/src/OctreeElement.cpp @@ -1308,11 +1308,6 @@ bool OctreeElement::findRayIntersection(const glm::vec3& origin, const glm::vec3 keepSearching = true; // assume that we will continue searching after this. - // by default, we only allow intersections with leaves with content - if (!canRayIntersect()) { - return false; // we don't intersect with non-leaves, and we keep searching - } - AACube cube = getAACube(); float localDistance; BoxFace localFace; @@ -1323,6 +1318,11 @@ bool OctreeElement::findRayIntersection(const glm::vec3& origin, const glm::vec3 return false; // we did not intersect } + // by default, we only allow intersections with leaves with content + if (!canRayIntersect()) { + return false; // we don't intersect with non-leaves, and we keep searching + } + // we did hit this element, so calculate appropriate distances localDistance *= TREE_SCALE; if (localDistance < distance) { @@ -1346,6 +1346,7 @@ bool OctreeElement::findDetailedRayIntersection(const glm::vec3& origin, const g if (intersectedObject) { *intersectedObject = this; } + keepSearching = false; return true; // we did intersect } return false; // we did not intersect From 6a57e662ac8655342c7278c43dc8b1f0acdf8394 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 29 May 2014 18:34:11 -0700 Subject: [PATCH 27/27] removed extra line --- libraries/octree/src/Octree.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 6cbce20dbc..3ec1871023 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -600,7 +600,6 @@ public: bool found; }; - bool findRayIntersectionOp(OctreeElement* element, void* extraData) { RayArgs* args = static_cast(extraData);