diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 2bc42ff104..c2ce4c9077 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2514,7 +2514,7 @@ 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_DEPTH_BUFFER_BIT); glm::vec3 lightDirection = -getSunDirection(); glm::quat rotation = rotationBetween(IDENTITY_FRONT, lightDirection); @@ -2539,8 +2539,10 @@ void Application::updateShadowMap() { const glm::vec2& coord = MAP_COORDS[i]; glViewport(coord.s * fbo->width(), coord.t * fbo->height(), targetSize, targetSize); + // if simple shadow then since the resolution is twice as much as with cascaded, cover 2 regions with the map, not just one + int regionIncrement = (matrixCount == 1 ? 2 : 1); float nearScale = SHADOW_MATRIX_DISTANCES[i] * frustumScale; - float farScale = SHADOW_MATRIX_DISTANCES[i + 1] * frustumScale; + float farScale = SHADOW_MATRIX_DISTANCES[i + regionIncrement] * frustumScale; glm::vec3 points[] = { glm::mix(_viewFrustum.getNearTopLeft(), _viewFrustum.getFarTopLeft(), nearScale), glm::mix(_viewFrustum.getNearTopRight(), _viewFrustum.getFarTopRight(), nearScale), @@ -2626,7 +2628,7 @@ void Application::updateShadowMap() { { PerformanceTimer perfTimer("entities"); - // _entities.render(RenderArgs::SHADOW_RENDER_MODE); + _entities.render(RenderArgs::SHADOW_RENDER_MODE); } // render JS/scriptable overlays 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..a8d0ce457a --- /dev/null +++ b/libraries/render-utils/src/Shadow.slh @@ -0,0 +1,115 @@ + +<@if not SHADOW_SLH@> +<@def SHADOW_SLH@> + +// the shadow texture +uniform sampler2DShadow shadowMap; + +// Fetching it +float fetchShadow(vec3 texcoord) { +<@if GLPROFILE == PC_GL @> + return texture(shadowMap, texcoord); +<@elif GLPROFILE == MAC_GL@> + return shadow2D(shadowMap, texcoord).r; +<@else@> + return shadow2D(shadowMap, texcoord).r; +<@endif@> +} + +// 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 corresponding texture coordinates + vec3 shadowTexcoord = vec3(dot(gl_EyePlaneS[0], position), dot(gl_EyePlaneT[0], position), dot(gl_EyePlaneR[0], position)); + return vec4(shadowTexcoord, 0.0); +} + +vec4 evalCascadedShadowTexcoord(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 * ( + fetchShadow(shadowTexcoord.xyz + radiusScale * shadowScale * vec3(samples[0], 0.0)) + + fetchShadow(shadowTexcoord.xyz + radiusScale * shadowScale * vec3(samples[1], 0.0)) + + fetchShadow(shadowTexcoord.xyz + radiusScale * shadowScale * vec3(samples[2], 0.0)) + + fetchShadow(shadowTexcoord.xyz + radiusScale * shadowScale * vec3(samples[3], 0.0)) + )); + + if ((shadowAttenuation > 0) && (shadowAttenuation < 1.0)) { + radiusScale *= 0.5; + shadowAttenuation = 0.5 * shadowAttenuation + (0.125 * ( + fetchShadow(shadowTexcoord.xyz + radiusScale * shadowScale * vec3(samples[4], 0.0)) + + fetchShadow(shadowTexcoord.xyz + radiusScale * shadowScale * vec3(samples[5], 0.0)) + + fetchShadow(shadowTexcoord.xyz + radiusScale * shadowScale * vec3(samples[6], 0.0)) + + fetchShadow(shadowTexcoord.xyz + radiusScale * shadowScale * vec3(samples[7], 0.0)) + )); + } + + return shadowAttenuation; +} + +float evalShadowAttenuationBasic(vec4 shadowTexcoord) { + float radiusScale = 0.5; + float shadowAttenuation = (0.25 * ( + fetchShadow(shadowTexcoord.xyz + radiusScale * shadowScale * vec3(samples[0], 0.0)) + + fetchShadow(shadowTexcoord.xyz + radiusScale * shadowScale * vec3(samples[1], 0.0)) + + fetchShadow(shadowTexcoord.xyz + radiusScale * shadowScale * vec3(samples[2], 0.0)) + + fetchShadow(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@> diff --git a/libraries/render-utils/src/TextureCache.cpp b/libraries/render-utils/src/TextureCache.cpp index 1591f5cb26..df860338ab 100644 --- a/libraries/render-utils/src/TextureCache.cpp +++ b/libraries/render-utils/src/TextureCache.cpp @@ -299,15 +299,16 @@ 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); 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); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); 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..e2a58de14b 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,8 @@ 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; +// Everything about shadow +<@include Shadow.slh@> // the distance to the near clip plane uniform float near; @@ -55,17 +49,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 = evalCascadedShadowTexcoord(position); + float shadowAttenuation = evalShadowAttenuation(shadowTexcoord); // get the normal from the map vec3 normalizedNormal = normalize(normalVal.xyz * 2.0 - vec3(1.0)); @@ -75,7 +61,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 diff --git a/libraries/render-utils/src/directional_light_shadow_map.slf b/libraries/render-utils/src/directional_light_shadow_map.slf index 056e866699..7a34f56f93 100644 --- a/libraries/render-utils/src/directional_light_shadow_map.slf +++ b/libraries/render-utils/src/directional_light_shadow_map.slf @@ -24,11 +24,8 @@ uniform sampler2D specularMap; // the depth texture uniform sampler2D depthMap; -// the shadow texture -uniform sampler2DShadow shadowMap; - -// the inverse of the size of the shadow map -uniform float shadowScale; +// Everything about shadow +<@include Shadow.slh@> // the distance to the near clip plane uniform float near; @@ -52,15 +49,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 corresponding texture coordinates - vec3 shadowTexCoord = vec3(dot(gl_EyePlaneS[0], position), dot(gl_EyePlaneT[0], position), dot(gl_EyePlaneR[0], 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));