From 668f6d3cfdc0b2c250bdb4bf0c6a47e9b8a05599 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 15 Aug 2014 16:13:47 -0700 Subject: [PATCH] Support for shadows on heightmaps. --- .../shaders/metavoxel_heightfield.vert | 15 +++- ...voxel_heightfield_cascaded_shadow_map.frag | 48 ++++++++++++ .../metavoxel_heightfield_shadow_map.frag | 37 +++++++++ interface/src/MetavoxelSystem.cpp | 78 +++++++++++++++++-- interface/src/MetavoxelSystem.h | 17 ++++ interface/src/renderer/Model.cpp | 8 +- 6 files changed, 190 insertions(+), 13 deletions(-) create mode 100644 interface/resources/shaders/metavoxel_heightfield_cascaded_shadow_map.frag create mode 100644 interface/resources/shaders/metavoxel_heightfield_shadow_map.frag diff --git a/interface/resources/shaders/metavoxel_heightfield.vert b/interface/resources/shaders/metavoxel_heightfield.vert index 4932ad1b2b..70cf3f9419 100644 --- a/interface/resources/shaders/metavoxel_heightfield.vert +++ b/interface/resources/shaders/metavoxel_heightfield.vert @@ -20,6 +20,9 @@ uniform float heightScale; // the scale between height and color textures uniform float colorScale; +// the interpolated position +varying vec4 position; + // the interpolated normal varying vec4 normal; @@ -32,13 +35,17 @@ void main(void) { texture2D(heightMap, heightCoord + vec2(0.0, heightScale)).r; normal = normalize(gl_ModelViewMatrix * vec4(deltaX, heightScale, deltaZ, 0.0)); - // pass along the scaled/offset texture coordinates - gl_TexCoord[0] = (gl_MultiTexCoord0 - vec4(heightScale, heightScale, 0.0, 0.0)) * colorScale; - // add the height to the position float height = texture2D(heightMap, heightCoord).r; - gl_Position = gl_ModelViewProjectionMatrix * (gl_Vertex + vec4(0.0, height, 0.0, 0.0)); + position = gl_ModelViewMatrix * (gl_Vertex + vec4(0.0, height, 0.0, 0.0)); + gl_Position = gl_ProjectionMatrix * position; // the zero height should be invisible gl_FrontColor = vec4(1.0, 1.0, 1.0, step(height, 0.0)); + + // pass along the scaled/offset texture coordinates + gl_TexCoord[0] = (gl_MultiTexCoord0 - vec4(heightScale, heightScale, 0.0, 0.0)) * colorScale; + + // and the shadow texture coordinates + gl_TexCoord[1] = vec4(dot(gl_EyePlaneS[0], position), dot(gl_EyePlaneT[0], position), dot(gl_EyePlaneR[0], position), 1.0); } diff --git a/interface/resources/shaders/metavoxel_heightfield_cascaded_shadow_map.frag b/interface/resources/shaders/metavoxel_heightfield_cascaded_shadow_map.frag new file mode 100644 index 0000000000..059a4e0296 --- /dev/null +++ b/interface/resources/shaders/metavoxel_heightfield_cascaded_shadow_map.frag @@ -0,0 +1,48 @@ +#version 120 + +// +// metavoxel_heightfield.frag +// fragment shader +// +// Created by Andrzej Kapolka on 7/28/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 + float diffuse = dot(normalize(normal), 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)); + gl_FragColor = base * texture2D(diffuseMap, gl_TexCoord[0].st); +} diff --git a/interface/resources/shaders/metavoxel_heightfield_shadow_map.frag b/interface/resources/shaders/metavoxel_heightfield_shadow_map.frag new file mode 100644 index 0000000000..bf319462d3 --- /dev/null +++ b/interface/resources/shaders/metavoxel_heightfield_shadow_map.frag @@ -0,0 +1,37 @@ +#version 120 + +// +// metavoxel_heightfield.frag +// fragment shader +// +// Created by Andrzej Kapolka on 7/28/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 inverse of the size of the shadow map +const float shadowScale = 1.0 / 2048.0; + +// the interpolated normal +varying vec4 normal; + +void main(void) { + // compute the base color based on OpenGL lighting model + float diffuse = dot(normalize(normal), 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)); + gl_FragColor = base * texture2D(diffuseMap, gl_TexCoord[0].st); +} diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 40a2ff0097..433c8af23e 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -760,10 +760,21 @@ void HeightfieldBuffer::render(bool cursor) { glBindTexture(GL_TEXTURE_2D, _heightTextureID); if (!cursor) { - DefaultMetavoxelRendererImplementation::getHeightfieldProgram().setUniformValue( - DefaultMetavoxelRendererImplementation::getHeightScaleLocation(), 1.0f / _heightSize); - DefaultMetavoxelRendererImplementation::getHeightfieldProgram().setUniformValue( - DefaultMetavoxelRendererImplementation::getColorScaleLocation(), (float)_heightSize / innerSize); + int heightScaleLocation = DefaultMetavoxelRendererImplementation::getHeightScaleLocation(); + int colorScaleLocation = DefaultMetavoxelRendererImplementation::getColorScaleLocation(); + ProgramObject* program = &DefaultMetavoxelRendererImplementation::getHeightfieldProgram(); + if (Menu::getInstance()->isOptionChecked(MenuOption::SimpleShadows)) { + heightScaleLocation = DefaultMetavoxelRendererImplementation::getShadowMapHeightScaleLocation(); + colorScaleLocation = DefaultMetavoxelRendererImplementation::getShadowMapColorScaleLocation(); + program = &DefaultMetavoxelRendererImplementation::getShadowMapHeightfieldProgram(); + + } else if (Menu::getInstance()->isOptionChecked(MenuOption::CascadedShadows)) { + heightScaleLocation = DefaultMetavoxelRendererImplementation::getCascadedShadowMapHeightScaleLocation(); + colorScaleLocation = DefaultMetavoxelRendererImplementation::getCascadedShadowMapColorScaleLocation(); + program = &DefaultMetavoxelRendererImplementation::getCascadedShadowMapHeightfieldProgram(); + } + program->setUniformValue(heightScaleLocation, 1.0f / _heightSize); + program->setUniformValue(colorScaleLocation, (float)_heightSize / innerSize); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, _colorTextureID); } @@ -858,6 +869,35 @@ void DefaultMetavoxelRendererImplementation::init() { _colorScaleLocation = _heightfieldProgram.uniformLocation("colorScale"); _heightfieldProgram.release(); + _shadowMapHeightfieldProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + + "shaders/metavoxel_heightfield.vert"); + _shadowMapHeightfieldProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + + "shaders/metavoxel_heightfield_shadow_map.frag"); + _shadowMapHeightfieldProgram.link(); + + _shadowMapHeightfieldProgram.bind(); + _shadowMapHeightfieldProgram.setUniformValue("heightMap", 0); + _shadowMapHeightfieldProgram.setUniformValue("diffuseMap", 1); + _shadowMapHeightfieldProgram.setUniformValue("shadowMap", 2); + _shadowMapHeightScaleLocation = _shadowMapHeightfieldProgram.uniformLocation("heightScale"); + _shadowMapColorScaleLocation = _shadowMapHeightfieldProgram.uniformLocation("colorScale"); + _shadowMapHeightfieldProgram.release(); + + _cascadedShadowMapHeightfieldProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + + "shaders/metavoxel_heightfield.vert"); + _cascadedShadowMapHeightfieldProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + + "shaders/metavoxel_heightfield_cascaded_shadow_map.frag"); + _cascadedShadowMapHeightfieldProgram.link(); + + _cascadedShadowMapHeightfieldProgram.bind(); + _cascadedShadowMapHeightfieldProgram.setUniformValue("heightMap", 0); + _cascadedShadowMapHeightfieldProgram.setUniformValue("diffuseMap", 1); + _cascadedShadowMapHeightfieldProgram.setUniformValue("shadowMap", 2); + _cascadedShadowMapHeightScaleLocation = _cascadedShadowMapHeightfieldProgram.uniformLocation("heightScale"); + _cascadedShadowMapColorScaleLocation = _cascadedShadowMapHeightfieldProgram.uniformLocation("colorScale"); + _shadowDistancesLocation = _cascadedShadowMapHeightfieldProgram.uniformLocation("shadowDistances"); + _cascadedShadowMapHeightfieldProgram.release(); + _heightfieldCursorProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/metavoxel_heightfield_cursor.vert"); _heightfieldCursorProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + @@ -1394,15 +1434,34 @@ void DefaultMetavoxelRendererImplementation::render(MetavoxelData& data, Metavox glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - _heightfieldProgram.bind(); + ProgramObject* program = &_heightfieldProgram; + if (Menu::getInstance()->getShadowsEnabled()) { + if (Menu::getInstance()->isOptionChecked(MenuOption::CascadedShadows)) { + program = &_cascadedShadowMapHeightfieldProgram; + program->bind(); + program->setUniform(_shadowDistancesLocation, Application::getInstance()->getShadowDistances()); + + } else { + program = &_shadowMapHeightfieldProgram; + } + glActiveTexture(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getShadowDepthTextureID()); + glActiveTexture(GL_TEXTURE0); + } + + program->bind(); glEnableClientState(GL_TEXTURE_COORD_ARRAY); BufferRenderVisitor heightfieldRenderVisitor(Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute()); data.guide(heightfieldRenderVisitor); - _heightfieldProgram.release(); + program->release(); + glActiveTexture(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_2D, 0); + glActiveTexture(GL_TEXTURE0); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); @@ -1416,6 +1475,13 @@ int DefaultMetavoxelRendererImplementation::_pointScaleLocation; ProgramObject DefaultMetavoxelRendererImplementation::_heightfieldProgram; int DefaultMetavoxelRendererImplementation::_heightScaleLocation; int DefaultMetavoxelRendererImplementation::_colorScaleLocation; +ProgramObject DefaultMetavoxelRendererImplementation::_shadowMapHeightfieldProgram; +int DefaultMetavoxelRendererImplementation::_shadowMapHeightScaleLocation; +int DefaultMetavoxelRendererImplementation::_shadowMapColorScaleLocation; +ProgramObject DefaultMetavoxelRendererImplementation::_cascadedShadowMapHeightfieldProgram; +int DefaultMetavoxelRendererImplementation::_cascadedShadowMapHeightScaleLocation; +int DefaultMetavoxelRendererImplementation::_cascadedShadowMapColorScaleLocation; +int DefaultMetavoxelRendererImplementation::_shadowDistancesLocation; ProgramObject DefaultMetavoxelRendererImplementation::_heightfieldCursorProgram; static void enableClipPlane(GLenum plane, float x, float y, float z, float w) { diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h index 051c5da711..38d67bcaed 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -223,6 +223,14 @@ public: static int getHeightScaleLocation() { return _heightScaleLocation; } static int getColorScaleLocation() { return _colorScaleLocation; } + static ProgramObject& getShadowMapHeightfieldProgram() { return _shadowMapHeightfieldProgram; } + static int getShadowMapHeightScaleLocation() { return _shadowMapHeightScaleLocation; } + static int getShadowMapColorScaleLocation() { return _shadowMapColorScaleLocation; } + + static ProgramObject& getCascadedShadowMapHeightfieldProgram() { return _cascadedShadowMapHeightfieldProgram; } + static int getCascadedShadowMapHeightScaleLocation() { return _cascadedShadowMapHeightScaleLocation; } + static int getCascadedShadowMapColorScaleLocation() { return _cascadedShadowMapColorScaleLocation; } + static ProgramObject& getHeightfieldCursorProgram() { return _heightfieldCursorProgram; } Q_INVOKABLE DefaultMetavoxelRendererImplementation(); @@ -240,6 +248,15 @@ private: static int _heightScaleLocation; static int _colorScaleLocation; + static ProgramObject _shadowMapHeightfieldProgram; + static int _shadowMapHeightScaleLocation; + static int _shadowMapColorScaleLocation; + + static ProgramObject _cascadedShadowMapHeightfieldProgram; + static int _cascadedShadowMapHeightScaleLocation; + static int _cascadedShadowMapColorScaleLocation; + static int _shadowDistancesLocation; + static ProgramObject _heightfieldCursorProgram; }; diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index a915406f8e..2ec676de53 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -1449,9 +1449,11 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent, bool re if (cascadedShadows) { activeProgram->setUniform(activeLocations->shadowDistances, Application::getInstance()->getShadowDistances()); } - activeProgram->setUniformValueArray(activeLocations->localLightDirections, - (const GLfloat*)_localLightDirections, MAX_LOCAL_LIGHTS, 4); - + if (mode != SHADOW_RENDER_MODE) { + activeProgram->setUniformValueArray(activeLocations->localLightDirections, + (const GLfloat*)_localLightDirections, MAX_LOCAL_LIGHTS, 4); + } + if (mesh.blendshapes.isEmpty()) { if (!(mesh.tangents.isEmpty() || mode == SHADOW_RENDER_MODE)) { activeProgram->setAttributeBuffer(activeLocations->tangent, GL_FLOAT, vertexCount * 2 * sizeof(glm::vec3), 3);