Use deferred lighting for voxels as well as metavoxels.

This commit is contained in:
Andrzej Kapolka 2014-09-11 18:06:56 -07:00
parent c2b58c9781
commit e6f37544fd
16 changed files with 114 additions and 206 deletions

View file

@ -1,40 +0,0 @@
#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
//
// 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;
// the interpolated position
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 shadowTexCoord = vec3(dot(gl_EyePlaneS[shadowIndex], position), dot(gl_EyePlaneT[shadowIndex], position),
dot(gl_EyePlaneR[shadowIndex], position));
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));
}

View file

@ -1,33 +0,0 @@
#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();
}

View file

@ -26,6 +26,9 @@ const float amplitude = 0.5;
// the position in model space
varying vec3 position;
// the normal in view space
varying vec4 normal;
// gradient based on gradients from cube edge centers rather than random from texture lookup
float randomEdgeGrad(int hash, vec3 position){
int h = int(mod(hash, 16));
@ -114,7 +117,8 @@ void main(void) {
// apply vertex lighting
vec3 color = gl_Color.rgb * vec3(noise, noise, noise);
gl_FragColor = vec4(color, 1);
gl_FragData[0] = vec4(color, 1);
gl_FragData[1] = normalize(normal) * 0.5 + vec4(0.5, 0.5, 0.5, 1.0);
}
@ -156,4 +160,4 @@ float perlin(vec3 location) {
mix(mix(ffcv, cfcv, params.x), mix(fccv, cccv, params.x), params.y),
params.z);
}
*/
*/

View file

@ -14,10 +14,12 @@
// the position in model space
varying vec3 position;
// the interpolated normal
varying vec4 normal;
void main(void) {
position = gl_Vertex.xyz;
vec4 normal = normalize(gl_ModelViewMatrix * vec4(gl_Normal, 0.0));
gl_FrontColor = gl_Color * (gl_LightModel.ambient + gl_LightSource[0].ambient +
gl_LightSource[0].diffuse * max(0.0, dot(normal, gl_LightSource[0].position)));
normal = vec4(gl_NormalMatrix * gl_Normal, 0.0);
gl_FrontColor = gl_Color;
gl_Position = ftransform();
}

View file

@ -1,28 +0,0 @@
#version 120
//
// shadow_map.frag
// fragment shader
//
// Created by Andrzej Kapolka on 11/21/13.
// Copyright 2013 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;
// the inverse of the size of the shadow map
const float shadowScale = 1.0 / 2048.0;
// the color in shadow
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));
}

View file

@ -1,32 +0,0 @@
#version 120
//
// shadow_map.vert
// vertex shader
//
// Created by Andrzej Kapolka on 3/27/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;
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
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();
}

View file

@ -0,0 +1,21 @@
#version 120
//
// voxel.frag
// fragment shader
//
// Created by Andrzej Kapolka on 9/11/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 interpolated normal
varying vec4 normal;
void main(void) {
// store the color and normal directly
gl_FragData[0] = gl_Color;
gl_FragData[1] = normalize(normal) * 0.5 + vec4(0.5, 0.5, 0.5, 1.0);
}

View file

@ -0,0 +1,26 @@
#version 120
//
// voxel.vert
// vertex shader
//
// Created by Andrzej Kapolka on 9/11/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 interpolated normal
varying vec4 normal;
void main(void) {
// store the normal for interpolation
normal = vec4(gl_NormalMatrix * gl_Normal, 0.0);
// use the standard position
gl_Position = ftransform();
// store the color directly
gl_FrontColor = gl_Color;
}

View file

@ -2842,8 +2842,10 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) {
_audioReflector.render();
}
// Draw voxels
_deferredLightingEffect.prepare();
bool deferredLightingRequired = false;
// Draw voxels
if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) {
PerformanceTimer perfTimer("voxels");
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),

View file

@ -121,23 +121,13 @@ int RenderVisitor::visit(MetavoxelInfo& info) {
return STOP_RECURSION;
}
const GLenum COLOR_DRAW_BUFFERS[] = { GL_COLOR_ATTACHMENT0 };
const GLenum NORMAL_DRAW_BUFFERS[] = { GL_COLOR_ATTACHMENT1 };
const GLenum COLOR_NORMAL_DRAW_BUFFERS[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 };
void MetavoxelSystem::render() {
// update the frustum
ViewFrustum* viewFrustum = Application::getInstance()->getDisplayViewFrustum();
_frustum.set(viewFrustum->getFarTopLeft(), viewFrustum->getFarTopRight(), viewFrustum->getFarBottomLeft(),
viewFrustum->getFarBottomRight(), viewFrustum->getNearTopLeft(), viewFrustum->getNearTopRight(),
viewFrustum->getNearBottomLeft(), viewFrustum->getNearBottomRight());
// clear the normal buffer
glDrawBuffers(sizeof(NORMAL_DRAW_BUFFERS) / sizeof(NORMAL_DRAW_BUFFERS[0]), NORMAL_DRAW_BUFFERS);
glClear(GL_COLOR_BUFFER_BIT);
glDrawBuffers(sizeof(COLOR_DRAW_BUFFERS) / sizeof(COLOR_DRAW_BUFFERS[0]), COLOR_DRAW_BUFFERS);
RenderVisitor renderVisitor(getLOD());
guideToAugmented(renderVisitor, true);
@ -834,7 +824,7 @@ void HeightfieldBuffer::render(bool cursor) {
glDrawRangeElements(GL_TRIANGLES, 0, vertexCount - 1, indexCount, GL_UNSIGNED_INT, 0);
glDrawBuffers(sizeof(COLOR_DRAW_BUFFERS) / sizeof(COLOR_DRAW_BUFFERS[0]), COLOR_DRAW_BUFFERS);
Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true, false);
glDepthFunc(GL_LEQUAL);
glDepthMask(false);
@ -907,7 +897,7 @@ void HeightfieldBuffer::render(bool cursor) {
glDepthMask(true);
glDepthFunc(GL_LESS);
glDrawBuffers(sizeof(COLOR_NORMAL_DRAW_BUFFERS) / sizeof(COLOR_NORMAL_DRAW_BUFFERS[0]), COLOR_NORMAL_DRAW_BUFFERS);
Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true, true);
DefaultMetavoxelRendererImplementation::getBaseHeightfieldProgram().bind();
@ -936,7 +926,7 @@ void HeightfieldBuffer::render(bool cursor) {
QHash<int, HeightfieldBuffer::BufferPair> HeightfieldBuffer::_bufferPairs;
void HeightfieldPreview::render(const glm::vec3& translation, float scale) const {
glDrawBuffers(sizeof(COLOR_NORMAL_DRAW_BUFFERS) / sizeof(COLOR_NORMAL_DRAW_BUFFERS[0]), COLOR_NORMAL_DRAW_BUFFERS);
Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true, true);
glDisable(GL_BLEND);
glEnable(GL_CULL_FACE);
@ -969,7 +959,7 @@ void HeightfieldPreview::render(const glm::vec3& translation, float scale) const
glDisable(GL_CULL_FACE);
glEnable(GL_BLEND);
glDrawBuffers(sizeof(COLOR_DRAW_BUFFERS) / sizeof(COLOR_DRAW_BUFFERS[0]), COLOR_DRAW_BUFFERS);
Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true, false);
}
VoxelBuffer::VoxelBuffer(const QVector<VoxelPoint>& vertices, const QVector<int>& indices,
@ -1017,7 +1007,7 @@ void VoxelBuffer::render(bool cursor) {
glDrawRangeElements(GL_QUADS, 0, _vertexCount - 1, _indexCount, GL_UNSIGNED_INT, 0);
if (!_materials.isEmpty()) {
glDrawBuffers(sizeof(COLOR_DRAW_BUFFERS) / sizeof(COLOR_DRAW_BUFFERS[0]), COLOR_DRAW_BUFFERS);
Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true, false);
glDepthFunc(GL_LEQUAL);
glDepthMask(false);
@ -1087,7 +1077,7 @@ void VoxelBuffer::render(bool cursor) {
glDepthMask(true);
glDepthFunc(GL_LESS);
glDrawBuffers(sizeof(COLOR_NORMAL_DRAW_BUFFERS) / sizeof(COLOR_NORMAL_DRAW_BUFFERS[0]), COLOR_NORMAL_DRAW_BUFFERS);
Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true, true);
DefaultMetavoxelRendererImplementation::getSplatVoxelProgram().disableAttributeArray(locations.materials);
DefaultMetavoxelRendererImplementation::getSplatVoxelProgram().disableAttributeArray(locations.materialWeights);
@ -2132,7 +2122,7 @@ void DefaultMetavoxelRendererImplementation::render(MetavoxelData& data, Metavox
_pointProgram.release();
glDrawBuffers(sizeof(COLOR_NORMAL_DRAW_BUFFERS) / sizeof(COLOR_NORMAL_DRAW_BUFFERS[0]), COLOR_NORMAL_DRAW_BUFFERS);
Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true, true);
glEnable(GL_CULL_FACE);
glEnable(GL_ALPHA_TEST);
@ -2175,7 +2165,7 @@ void DefaultMetavoxelRendererImplementation::render(MetavoxelData& data, Metavox
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDrawBuffers(sizeof(COLOR_DRAW_BUFFERS) / sizeof(COLOR_DRAW_BUFFERS[0]), COLOR_DRAW_BUFFERS);
Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true, false);
}
void DefaultMetavoxelRendererImplementation::loadSplatProgram(const char* type,

View file

@ -26,6 +26,13 @@ void DeferredLightingEffect::init() {
_directionalLightCascadedShadowMapLocations);
}
void DeferredLightingEffect::prepare() {
// clear the normal buffer
Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(false, true);
glClear(GL_COLOR_BUFFER_BIT);
Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true, false);
}
void DeferredLightingEffect::render() {
// perform deferred lighting, rendering to free fbo
glPushMatrix();
@ -38,6 +45,7 @@ void DeferredLightingEffect::render() {
glDisable(GL_BLEND);
glDisable(GL_LIGHTING);
glDisable(GL_DEPTH_TEST);
glDisable(GL_COLOR_MATERIAL);
glDepthMask(false);
QOpenGLFramebufferObject* primaryFBO = Application::getInstance()->getTextureCache()->getPrimaryFramebufferObject();
@ -133,6 +141,7 @@ void DeferredLightingEffect::render() {
glDisable(GL_TEXTURE_2D);
glEnable(GL_LIGHTING);
glEnable(GL_COLOR_MATERIAL);
glEnable(GL_DEPTH_TEST);
glDepthMask(true);

View file

@ -19,6 +19,8 @@ class DeferredLightingEffect {
public:
void init();
void prepare();
void render();
private:

View file

@ -242,6 +242,18 @@ GLuint TextureCache::getPrimaryNormalTextureID() {
return _primaryNormalTextureID;
}
void TextureCache::setPrimaryDrawBuffers(bool color, bool normal) {
GLenum buffers[2];
int bufferCount = 0;
if (color) {
buffers[bufferCount++] = GL_COLOR_ATTACHMENT0;
}
if (normal) {
buffers[bufferCount++] = GL_COLOR_ATTACHMENT1;
}
glDrawBuffers(bufferCount, buffers);
}
QOpenGLFramebufferObject* TextureCache::getSecondaryFramebufferObject() {
if (!_secondaryFramebufferObject) {
_secondaryFramebufferObject = createFramebufferObject();

View file

@ -64,6 +64,9 @@ public:
/// Returns the ID of the primary framebuffer object's normal texture.
GLuint getPrimaryNormalTextureID();
/// Enables or disables draw buffers on the primary framebuffer. Note: the primary framebuffer must be bound.
void setPrimaryDrawBuffers(bool color, bool normal);
/// Returns a pointer to the secondary framebuffer object, used as an additional render target when performing full
/// screen effects.
QOpenGLFramebufferObject* getSecondaryFramebufferObject();

View file

@ -506,29 +506,13 @@ void VoxelSystem::initVoxelMemory() {
_memoryUsageRAM += (sizeof(GLubyte) * vertexPointsPerVoxel * _maxVoxels);
// create our simple fragment shader if we're the first system to init
if (!_shadowMapProgram.isLinked()) {
_shadowMapProgram.addShaderFromSourceFile(QGLShader::Vertex,
Application::resourcesPath() + "shaders/shadow_map.vert");
_shadowMapProgram.addShaderFromSourceFile(QGLShader::Fragment,
Application::resourcesPath() + "shaders/shadow_map.frag");
_shadowMapProgram.link();
_shadowMapProgram.bind();
_shadowMapProgram.setUniformValue("shadowMap", 0);
_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);
_shadowDistancesLocation = _cascadedShadowMapProgram.uniformLocation("shadowDistances");
_cascadedShadowMapProgram.release();
if (!_program.isLinked()) {
_program.addShaderFromSourceFile(QGLShader::Vertex,
Application::resourcesPath() + "shaders/voxel.vert");
_program.addShaderFromSourceFile(QGLShader::Fragment,
Application::resourcesPath() + "shaders/voxel.frag");
_program.link();
}
}
_renderer = new PrimitiveRenderer(_maxVoxels);
@ -1150,10 +1134,8 @@ glm::vec3 VoxelSystem::computeVoxelVertex(const glm::vec3& startVertex, float vo
return startVertex + glm::vec3(identityVertex[0], identityVertex[1], identityVertex[2]) * voxelScale;
}
ProgramObject VoxelSystem::_program;
ProgramObject VoxelSystem::_perlinModulateProgram;
ProgramObject VoxelSystem::_shadowMapProgram;
ProgramObject VoxelSystem::_cascadedShadowMapProgram;
int VoxelSystem::_shadowDistancesLocation;
void VoxelSystem::init() {
if (_initialized) {
@ -1478,41 +1460,31 @@ void VoxelSystem::render() {
}
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();
}
glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getShadowDepthTextureID());
} else if (texture) {
if (texture) {
bindPerlinModulateProgram();
glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getPermutationNormalTextureID());
} else {
_program.bind();
}
glPushMatrix();
glScalef(_treeScale, _treeScale, _treeScale);
Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true, true);
}
void VoxelSystem::removeScaleAndReleaseProgram(bool texture) {
// scale back down to 1 so heads aren't massive
glPopMatrix();
if (Menu::getInstance()->getShadowsEnabled()) {
if (Menu::getInstance()->isOptionChecked(MenuOption::CascadedShadows)) {
_cascadedShadowMapProgram.release();
} else {
_shadowMapProgram.release();
}
glBindTexture(GL_TEXTURE_2D, 0);
} else if (texture) {
if (texture) {
_perlinModulateProgram.release();
glBindTexture(GL_TEXTURE_2D, 0);
} else {
_program.release();
}
Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true, false);
}
int VoxelSystem::_nodeCount = 0;

View file

@ -228,10 +228,8 @@ private:
bool _voxelsDirty;
static ProgramObject _program;
static ProgramObject _perlinModulateProgram;
static ProgramObject _shadowMapProgram;
static ProgramObject _cascadedShadowMapProgram;
static int _shadowDistancesLocation;
static void bindPerlinModulateProgram();