From 70ab33b65b95f3cc93fd880ac6033dfdf8cecfc1 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 27 May 2014 10:54:18 -0700 Subject: [PATCH 1/3] Some tricks to avoid shadow artifacts: render back faces to shadow buffer, use polygon offset. --- interface/src/Application.cpp | 5 +++++ interface/src/renderer/Model.cpp | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b5d9d8939c..cad6c26a00 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2325,10 +2325,15 @@ void Application::updateShadowMap() { // store view matrix without translation, which we'll use for precision-sensitive objects updateUntranslatedViewMatrix(); + glEnable(GL_POLYGON_OFFSET_FILL); + glPolygonOffset(1.1f, 4.0f); + _avatarManager.renderAvatars(Avatar::SHADOW_RENDER_MODE); _particles.render(OctreeRenderer::SHADOW_RENDER_MODE); _models.render(OctreeRenderer::SHADOW_RENDER_MODE); + glDisable(GL_POLYGON_OFFSET_FILL); + glPopMatrix(); glMatrixMode(GL_PROJECTION); diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 5337e845a1..c4cc312091 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -498,6 +498,9 @@ bool Model::render(float alpha, RenderMode mode) { glDisable(GL_CULL_FACE); } else { glEnable(GL_CULL_FACE); + if (mode == SHADOW_RENDER_MODE) { + glCullFace(GL_FRONT); + } } // render opaque meshes with alpha testing @@ -515,6 +518,10 @@ bool Model::render(float alpha, RenderMode mode) { glDisable(GL_CULL_FACE); + if (mode == SHADOW_RENDER_MODE) { + glCullFace(GL_BACK); + } + // deactivate vertex arrays after drawing glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); From edaa251e5f4b274b31bca21daa437adaa8ad6ec4 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 27 May 2014 11:43:34 -0700 Subject: [PATCH 2/3] Provide option to disable avatar shadowing. --- interface/src/Application.cpp | 2 +- interface/src/Menu.cpp | 1 + interface/src/Menu.h | 1 + interface/src/avatar/Avatar.cpp | 7 ++++--- interface/src/avatar/Head.cpp | 3 ++- interface/src/avatar/MyAvatar.cpp | 5 +++-- interface/src/renderer/Model.cpp | 10 +++++----- interface/src/renderer/Model.h | 4 ++-- 8 files changed, 19 insertions(+), 14 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index cad6c26a00..1addb7bafd 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2326,7 +2326,7 @@ void Application::updateShadowMap() { updateUntranslatedViewMatrix(); glEnable(GL_POLYGON_OFFSET_FILL); - glPolygonOffset(1.1f, 4.0f); + glPolygonOffset(1.1f, 4.0f); // magic numbers courtesy http://www.eecs.berkeley.edu/~ravir/6160/papers/shadowmaps.ppt _avatarManager.renderAvatars(Avatar::SHADOW_RENDER_MODE); _particles.render(OctreeRenderer::SHADOW_RENDER_MODE); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 856e1efae7..68e3b484d3 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -332,6 +332,7 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::AllowOculusCameraModeChange, 0, false); addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::Avatars, 0, true); + addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::AvatarsReceiveShadows, 0, true); addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::RenderSkeletonCollisionShapes); addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::RenderHeadCollisionShapes); addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::RenderBoundingCollisionShapes); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 279d2151c9..70f4f62ce4 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -293,6 +293,7 @@ namespace MenuOption { const QString AudioSpatialProcessingDontDistanceAttenuate = "Don't calculate distance attenuation"; const QString AudioSpatialProcessingAlternateDistanceAttenuate = "Alternate distance attenuation"; const QString Avatars = "Avatars"; + const QString AvatarsReceiveShadows = "Avatars Receive Shadows"; const QString Bandwidth = "Bandwidth Display"; const QString BandwidthDetails = "Bandwidth Details"; const QString BuckyBalls = "Bucky Balls"; diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index aff15f4e0b..306dc0194e 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -347,7 +347,6 @@ glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const { void Avatar::renderBody(RenderMode renderMode, float glowLevel) { Model::RenderMode modelRenderMode = (renderMode == SHADOW_RENDER_MODE) ? Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE; - { Glower glower(glowLevel); @@ -356,7 +355,8 @@ void Avatar::renderBody(RenderMode renderMode, float glowLevel) { renderBillboard(); return; } - _skeletonModel.render(1.0f, modelRenderMode); + + _skeletonModel.render(1.0f, modelRenderMode, Menu::getInstance()->isOptionChecked(MenuOption::AvatarsReceiveShadows)); renderAttachments(renderMode); getHand()->render(false, modelRenderMode); } @@ -390,8 +390,9 @@ void Avatar::simulateAttachments(float deltaTime) { void Avatar::renderAttachments(RenderMode renderMode) { Model::RenderMode modelRenderMode = (renderMode == SHADOW_RENDER_MODE) ? Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE; + bool receiveShadows = Menu::getInstance()->isOptionChecked(MenuOption::AvatarsReceiveShadows); foreach (Model* model, _attachmentModels) { - model->render(1.0f, modelRenderMode); + model->render(1.0f, modelRenderMode, receiveShadows); } } diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index 2d0599b31f..8382843c1e 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -176,7 +176,8 @@ void Head::relaxLean(float deltaTime) { } void Head::render(float alpha, Model::RenderMode mode) { - if (_faceModel.render(alpha, mode) && _renderLookatVectors && mode != Model::SHADOW_RENDER_MODE) { + if (_faceModel.render(alpha, mode, Menu::getInstance()->isOptionChecked(MenuOption::AvatarsReceiveShadows)) && + _renderLookatVectors && mode != Model::SHADOW_RENDER_MODE) { renderLookatVectors(_leftEyePosition, _rightEyePosition, _lookAtPosition); } } diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index a598c55aaa..f47880056c 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -773,7 +773,7 @@ void MyAvatar::renderBody(RenderMode renderMode, float glowLevel) { // Render the body's voxels and head Model::RenderMode modelRenderMode = (renderMode == SHADOW_RENDER_MODE) ? Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE; - _skeletonModel.render(1.0f, modelRenderMode); + _skeletonModel.render(1.0f, modelRenderMode, Menu::getInstance()->isOptionChecked(MenuOption::AvatarsReceiveShadows)); renderAttachments(renderMode); // Render head so long as the camera isn't inside it @@ -1695,10 +1695,11 @@ void MyAvatar::renderAttachments(RenderMode renderMode) { QString headJointName = (geometry.headJointIndex == -1) ? QString() : geometry.joints.at(geometry.headJointIndex).name; Model::RenderMode modelRenderMode = (renderMode == SHADOW_RENDER_MODE) ? Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE; + bool receiveShadows = Menu::getInstance()->isOptionChecked(MenuOption::AvatarsReceiveShadows); for (int i = 0; i < _attachmentData.size(); i++) { const QString& jointName = _attachmentData.at(i).jointName; if (jointName != headJointName && jointName != "Head") { - _attachmentModels.at(i)->render(1.0f, modelRenderMode); + _attachmentModels.at(i)->render(1.0f, modelRenderMode, receiveShadows); } } } diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index c4cc312091..db2f6e0664 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -470,7 +470,7 @@ bool Model::updateGeometry() { return needFullUpdate; } -bool Model::render(float alpha, RenderMode mode) { +bool Model::render(float alpha, RenderMode mode, bool receiveShadows) { // render the attachments foreach (Model* attachment, _attachments) { attachment->render(alpha, mode); @@ -508,13 +508,14 @@ bool Model::render(float alpha, RenderMode mode) { glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GREATER, 0.5f * alpha); - renderMeshes(alpha, mode, false); + receiveShadows &= Menu::getInstance()->isOptionChecked(MenuOption::Shadows); + renderMeshes(alpha, mode, false, receiveShadows); glDisable(GL_ALPHA_TEST); // render translucent meshes afterwards - renderMeshes(alpha, mode, true); + renderMeshes(alpha, mode, true, receiveShadows); glDisable(GL_CULL_FACE); @@ -1596,11 +1597,10 @@ void Model::deleteGeometry() { } } -void Model::renderMeshes(float alpha, RenderMode mode, bool translucent) { +void Model::renderMeshes(float alpha, RenderMode mode, bool translucent, bool receiveShadows) { const FBXGeometry& geometry = _geometry->getFBXGeometry(); const QVector& networkMeshes = _geometry->getMeshes(); - bool receiveShadows = Menu::getInstance()->isOptionChecked(MenuOption::Shadows); 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]); diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 5b1f6402d3..69ea700b49 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -79,7 +79,7 @@ public: enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, DIFFUSE_RENDER_MODE, NORMAL_RENDER_MODE }; - bool render(float alpha = 1.0f, RenderMode mode = DEFAULT_RENDER_MODE); + bool render(float alpha = 1.0f, RenderMode mode = DEFAULT_RENDER_MODE, bool receiveShadows = true); /// Sets the URL of the model to render. /// \param fallback the URL of a fallback model to render if the requested model fails to load @@ -315,7 +315,7 @@ private: void applyNextGeometry(); void deleteGeometry(); - void renderMeshes(float alpha, RenderMode mode, bool translucent); + void renderMeshes(float alpha, RenderMode mode, bool translucent, bool receiveShadows); QVector createJointStates(const FBXGeometry& geometry); QSharedPointer _baseGeometry; ///< reference required to prevent collection of base From e22d239d4d4041b32f05f323c5b991e809736d40 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 27 May 2014 12:30:45 -0700 Subject: [PATCH 3/3] What the heck; let's try using some multisampling on the shadow maps. --- interface/resources/shaders/model_shadow_map.frag | 9 ++++++++- interface/resources/shaders/model_shadow_normal_map.frag | 9 ++++++++- .../shaders/model_shadow_normal_specular_map.frag | 9 ++++++++- .../resources/shaders/model_shadow_specular_map.frag | 9 ++++++++- 4 files changed, 32 insertions(+), 4 deletions(-) diff --git a/interface/resources/shaders/model_shadow_map.frag b/interface/resources/shaders/model_shadow_map.frag index 4a2bb312dc..aa1df03b95 100644 --- a/interface/resources/shaders/model_shadow_map.frag +++ b/interface/resources/shaders/model_shadow_map.frag @@ -17,6 +17,9 @@ uniform sampler2D diffuseMap; // the shadow texture uniform sampler2DShadow shadowMap; +// the inverse of the size of the shadow map +const float shadowScale = 1.0 / 2048.0; + // the interpolated position varying vec4 position; @@ -27,7 +30,11 @@ void main(void) { // 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) * shadow2D(shadowMap, gl_TexCoord[1].stp).r; + 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)); diff --git a/interface/resources/shaders/model_shadow_normal_map.frag b/interface/resources/shaders/model_shadow_normal_map.frag index d61b123fba..3461c1b5f3 100644 --- a/interface/resources/shaders/model_shadow_normal_map.frag +++ b/interface/resources/shaders/model_shadow_normal_map.frag @@ -20,6 +20,9 @@ uniform sampler2D normalMap; // the shadow texture uniform sampler2DShadow shadowMap; +// the inverse of the size of the shadow map +const float shadowScale = 1.0 / 2048.0; + // the interpolated position varying vec4 interpolatedPosition; @@ -39,7 +42,11 @@ void main(void) { 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) * shadow2D(shadowMap, gl_TexCoord[1].stp).r; + 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)); diff --git a/interface/resources/shaders/model_shadow_normal_specular_map.frag b/interface/resources/shaders/model_shadow_normal_specular_map.frag index 9865056479..273d197fca 100644 --- a/interface/resources/shaders/model_shadow_normal_specular_map.frag +++ b/interface/resources/shaders/model_shadow_normal_specular_map.frag @@ -23,6 +23,9 @@ uniform sampler2D specularMap; // the shadow texture uniform sampler2DShadow shadowMap; +// the inverse of the size of the shadow map +const float shadowScale = 1.0 / 2048.0; + // the interpolated position varying vec4 interpolatedPosition; @@ -42,7 +45,11 @@ void main(void) { 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) * shadow2D(shadowMap, gl_TexCoord[1].stp).r; + 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)); diff --git a/interface/resources/shaders/model_shadow_specular_map.frag b/interface/resources/shaders/model_shadow_specular_map.frag index 4be0f1636d..77cff1e04e 100644 --- a/interface/resources/shaders/model_shadow_specular_map.frag +++ b/interface/resources/shaders/model_shadow_specular_map.frag @@ -20,6 +20,9 @@ uniform sampler2D specularMap; // the shadow texture uniform sampler2DShadow shadowMap; +// 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; @@ -30,7 +33,11 @@ void main(void) { // 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) * shadow2D(shadowMap, gl_TexCoord[1].stp).r; + 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));