diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 2c510c4980..02ee60a012 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2795,13 +2795,14 @@ void Application::updateShadowMap() { QOpenGLFramebufferObject* fbo = DependencyManager::get()->getShadowFramebufferObject(); fbo->bind(); glEnable(GL_DEPTH_TEST); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glClear(/*GL_COLOR_BUFFER_BIT | */GL_DEPTH_BUFFER_BIT); glm::vec3 lightDirection = -getSunDirection(); 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 float SHADOW_MATRIX_DISTANCES[] = { 0.0f, 2.0f, 6.0f, 14.0f, 30.0f }; + const float SHADOW_MATRIX_DISTANCES[] = { 1.0f, 2.5f, 5.0f, 10.0f, 20.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) }; @@ -2855,8 +2856,8 @@ void Application::updateShadowMap() { glm::vec3 maxima(center.x + radius, center.y + radius, center.z + radius); // 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; + // minima.z -= _viewFrustum.getFarClip() * 0.5f; + // maxima.z += _viewFrustum.getFarClip() * 0.5f; // save the combined matrix for rendering _shadowMatrices[i] = glm::transpose(glm::translate(glm::vec3(coord, 0.0f)) * @@ -2897,8 +2898,9 @@ void Application::updateShadowMap() { viewTransform.setRotation(rotation); setViewTransform(viewTransform); - 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); + //glEnable(GL_POLYGON_OFFSET_FILL); + //glPolygonOffset(1.1f, 4.0f); // magic numbers courtesy http://www.eecs.berkeley.edu/~ravir/6160/papers/shadowmaps.ppt { PerformanceTimer perfTimer("avatarManager"); @@ -2907,7 +2909,7 @@ void Application::updateShadowMap() { { PerformanceTimer perfTimer("entities"); - // _entities.render(RenderArgs::SHADOW_RENDER_MODE); + _entities.render(RenderArgs::SHADOW_RENDER_MODE); } // render JS/scriptable overlays @@ -2921,7 +2923,7 @@ void Application::updateShadowMap() { _overlays.renderWorld(true, RenderArgs::SHADOW_RENDER_MODE); } - glDisable(GL_POLYGON_OFFSET_FILL); + //glDisable(GL_POLYGON_OFFSET_FILL); glPopMatrix(); diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 92e925d73e..699603cb21 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -166,7 +166,14 @@ void RenderableModelEntityItem::render(RenderArgs* args) { // TODO: this is the majority of model render time. And rendering of a cube model vs the basic Box render // is significantly more expensive. Is there a way to call this that doesn't cost us as much? PerformanceTimer perfTimer("model->render"); - _model->renderInScene(alpha, args); + // filter out if not needed to render + if (args && (args->_renderMode == RenderArgs::SHADOW_RENDER_MODE)) { + if (isMoving() || isAnimatingSomething()) { + _model->renderInScene(alpha, args); + } + } else { + _model->renderInScene(alpha, args); + } } else { // if we couldn't get a model, then just draw a cube glColor3ub(getColor()[RED_INDEX],getColor()[GREEN_INDEX],getColor()[BLUE_INDEX]); diff --git a/libraries/render-utils/src/Shadow.slh b/libraries/render-utils/src/Shadow.slh new file mode 100755 index 0000000000..ff3cc68658 --- /dev/null +++ b/libraries/render-utils/src/Shadow.slh @@ -0,0 +1,98 @@ + +<@if not SHADOW_SLH@> +<@def SHADOW_SLH@> + +// the shadow texture +uniform sampler2DShadow shadowMap; + +// the distances to the cascade sections +uniform vec3 shadowDistances; + +// the inverse of the size of the shadow map +uniform float shadowScale; + +vec2 samples[8] = vec2[8]( + vec2(-2.0, -2.0), + vec2(2.0, -2.0), + vec2(2.0, 2.0), + vec2(-2.0, 2.0), + vec2(1.0, 0.0), + vec2(0.0, 1.0), + vec2(-1.0, 0.0), + vec2(0.0, -1.0) +); + +vec4 evalShadowTexcoord(vec4 position) { + // 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)); + + return vec4(shadowTexcoord, shadowIndex); +} + +float evalShadowAttenuationPCF(vec4 shadowTexcoord) { + float radiusScale = (shadowTexcoord.w + 1.0); + float shadowAttenuation = (0.25 * ( + texture(shadowMap, shadowTexcoord.xyz + radiusScale * shadowScale * vec3(samples[0], 0.0)) + + texture(shadowMap, shadowTexcoord.xyz + radiusScale * shadowScale * vec3(samples[1], 0.0)) + + texture(shadowMap, shadowTexcoord.xyz + radiusScale * shadowScale * vec3(samples[2], 0.0)) + + texture(shadowMap, shadowTexcoord.xyz + radiusScale * shadowScale * vec3(samples[3], 0.0)) + )); + + if ((shadowAttenuation > 0) && (shadowAttenuation < 1.0)) { + radiusScale *= 0.5; + shadowAttenuation = 0.5 * shadowAttenuation + (0.125 * ( + texture(shadowMap, shadowTexcoord.xyz + radiusScale * shadowScale * vec3(samples[4], 0.0)) + + texture(shadowMap, shadowTexcoord.xyz + radiusScale * shadowScale * vec3(samples[5], 0.0)) + + texture(shadowMap, shadowTexcoord.xyz + radiusScale * shadowScale * vec3(samples[6], 0.0)) + + texture(shadowMap, shadowTexcoord.xyz + radiusScale * shadowScale * vec3(samples[7], 0.0)) + )); + } + + return shadowAttenuation; +} + +float evalShadowAttenuationBasic(vec4 shadowTexcoord) { + float radiusScale = 0.5; + float shadowAttenuation = (0.25 * ( + texture(shadowMap, shadowTexcoord.xyz + radiusScale * shadowScale * vec3(samples[0], 0.0)) + + texture(shadowMap, shadowTexcoord.xyz + radiusScale * shadowScale * vec3(samples[1], 0.0)) + + texture(shadowMap, shadowTexcoord.xyz + radiusScale * shadowScale * vec3(samples[2], 0.0)) + + texture(shadowMap, shadowTexcoord.xyz + radiusScale * shadowScale * vec3(samples[3], 0.0)) + )); + return shadowAttenuation; +} + +float evalShadowAttenuation(vec4 shadowTexcoord) { + return evalShadowAttenuationBasic(shadowTexcoord); +} + + +vec3 debugShadowMap(float shadowAttenuation, vec4 shadowTexcoord) { + vec3 colorArray[4]; + colorArray[0].xyz = vec3(1.0, 1.0, 1.0); + colorArray[1].xyz = vec3(1.0, 0.0, 0.0); + colorArray[2].xyz = vec3(0.0, 1.0, 0.0); + colorArray[3].xyz = vec3(0.0, 0.0, 1.0); + + vec2 offsetArray[4]; + offsetArray[0] = vec2(0.0, 0.0); + offsetArray[1] = vec2(0.5, 0.0); + offsetArray[2] = vec2(0.0, 0.5); + offsetArray[3] = vec2(0.5, 0.5); + + return shadowAttenuation * colorArray[int(shadowTexcoord.w)]; + // return shadowAttenuation * vec3(2.0*(shadowTexcoord.xy - offsetArray[int(shadowTexcoord.w)]), 0); + } + +<@endif@> \ No newline at end of file diff --git a/libraries/render-utils/src/TextureCache.cpp b/libraries/render-utils/src/TextureCache.cpp index 1591f5cb26..086a878b2d 100644 --- a/libraries/render-utils/src/TextureCache.cpp +++ b/libraries/render-utils/src/TextureCache.cpp @@ -299,8 +299,9 @@ QOpenGLFramebufferObject* TextureCache::getShadowFramebufferObject() { glGenTextures(1, &_shadowDepthTextureID); glBindTexture(GL_TEXTURE_2D, _shadowDepthTextureID); - glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, SHADOW_MAP_SIZE, SHADOW_MAP_SIZE, - 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, SHADOW_MAP_SIZE, SHADOW_MAP_SIZE, + 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0); + //0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); @@ -308,6 +309,8 @@ QOpenGLFramebufferObject* TextureCache::getShadowFramebufferObject() { const float DISTANT_BORDER[] = { 1.0f, 1.0f, 1.0f, 1.0f }; glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, DISTANT_BORDER); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); glBindTexture(GL_TEXTURE_2D, 0); _shadowFramebufferObject->bind(); diff --git a/libraries/render-utils/src/directional_light_cascaded_shadow_map.slf b/libraries/render-utils/src/directional_light_cascaded_shadow_map.slf index b314beb6dc..fde4b4db0e 100644 --- a/libraries/render-utils/src/directional_light_cascaded_shadow_map.slf +++ b/libraries/render-utils/src/directional_light_cascaded_shadow_map.slf @@ -24,14 +24,7 @@ uniform sampler2D specularMap; // the depth texture uniform sampler2D depthMap; -// the shadow texture -uniform sampler2DShadow shadowMap; - -// the distances to the cascade sections -uniform vec3 shadowDistances; - -// the inverse of the size of the shadow map -uniform float shadowScale; +<@include Shadow.slh@> // the distance to the near clip plane uniform float near; @@ -55,17 +48,9 @@ void main(void) { float z = near / (depthVal * depthScale - 1.0); vec4 position = vec4((depthTexCoordOffset + gl_TexCoord[0].st * depthTexCoordScale) * z, z, 1.0); - // 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)); - - // evaluate the shadow test but only relevant for light facing fragments - float shadowAttenuation = (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)); + // Eval shadow Texcoord and then Attenuation + vec4 shadowTexcoord = evalShadowTexcoord(position); + float shadowAttenuation = evalShadowAttenuation(shadowTexcoord); // get the normal from the map vec3 normalizedNormal = normalize(normalVal.xyz * 2.0 - vec3(1.0)); @@ -75,7 +60,7 @@ void main(void) { // Light mapped or not ? if ((normalVal.a >= 0.45) && (normalVal.a <= 0.55)) { - normalVal.a = 0.0; + normalVal.a = 1.0; // need to catch normals perpendicular to the projection plane hence the magic number for the threshold // it should be just 0, but we have innacurracy so we need to overshoot @@ -108,4 +93,8 @@ void main(void) { vec4 specularColor = specularVal; gl_FragColor = vec4(baseColor.rgb + pow(specular, specularColor.a * 128.0) * specularColor.rgb, normalVal.a); } + + if (gl_FragCoord.x > 1024) { + gl_FragColor = vec4(debugShadowMap(shadowAttenuation, shadowTexcoord) * diffuse, normalVal.a); + } }