mirror of
https://github.com/lubosz/overte.git
synced 2025-04-17 07:32:10 +02:00
Retain "simple" shadows, supply cascaded as option.
This commit is contained in:
parent
ff77644caa
commit
09231f01f3
11 changed files with 146 additions and 49 deletions
29
interface/resources/shaders/cascaded_shadow_map.frag
Normal file
29
interface/resources/shaders/cascaded_shadow_map.frag
Normal file
|
@ -0,0 +1,29 @@
|
|||
#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
|
||||
//
|
||||
|
||||
uniform sampler2DShadow shadowMap;
|
||||
|
||||
uniform vec3 shadowDistances;
|
||||
|
||||
// the color in shadow
|
||||
varying vec4 shadowColor;
|
||||
|
||||
// the interpolated position
|
||||
varying vec4 position;
|
||||
|
||||
void main(void) {
|
||||
int shadowIndex = int(dot(step(vec3(position.z), shadowDistances), vec3(1.0, 1.0, 1.0)));
|
||||
vec3 texCoord = vec3(dot(gl_EyePlaneS[shadowIndex], position), dot(gl_EyePlaneT[shadowIndex], position),
|
||||
dot(gl_EyePlaneR[shadowIndex], position));
|
||||
gl_FragColor = mix(shadowColor, gl_Color, shadow2D(shadowMap, texCoord).r);
|
||||
}
|
33
interface/resources/shaders/cascaded_shadow_map.vert
Normal file
33
interface/resources/shaders/cascaded_shadow_map.vert
Normal file
|
@ -0,0 +1,33 @@
|
|||
#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();
|
||||
}
|
|
@ -13,17 +13,16 @@
|
|||
|
||||
uniform sampler2DShadow shadowMap;
|
||||
|
||||
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) {
|
||||
int shadowIndex = int(dot(step(vec3(position.z), shadowDistances), vec3(1.0, 1.0, 1.0)));
|
||||
vec3 texCoord = vec3(dot(gl_EyePlaneS[shadowIndex], position), dot(gl_EyePlaneT[shadowIndex], position),
|
||||
dot(gl_EyePlaneR[shadowIndex], position));
|
||||
gl_FragColor = mix(shadowColor, gl_Color, shadow2D(shadowMap, texCoord).r);
|
||||
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));
|
||||
}
|
||||
|
|
|
@ -14,9 +14,6 @@
|
|||
// 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);
|
||||
|
@ -26,7 +23,9 @@ void main(void) {
|
|||
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;
|
||||
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();
|
||||
|
|
|
@ -616,7 +616,7 @@ void Application::paintGL() {
|
|||
whichCamera = _viewFrustumOffsetCamera;
|
||||
}
|
||||
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Shadows)) {
|
||||
if (Menu::getInstance()->getShadowsEnabled()) {
|
||||
updateShadowMap();
|
||||
}
|
||||
|
||||
|
@ -2263,13 +2263,20 @@ void Application::updateShadowMap() {
|
|||
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) };
|
||||
|
||||
int halfSize = fbo->width() / 2;
|
||||
float frustumScale = 1.0f / (_viewFrustum.getFarClip() - _viewFrustum.getNearClip());
|
||||
loadViewFrustum(_myCamera, _viewFrustum);
|
||||
|
||||
for (int i = 0; i < SHADOW_MATRIX_COUNT; i++) {
|
||||
int matrixCount = 1;
|
||||
int targetSize = fbo->width();
|
||||
float targetScale = 1.0f;
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::CascadedShadows)) {
|
||||
matrixCount = CASCADED_SHADOW_MATRIX_COUNT;
|
||||
targetSize = fbo->width() / 2;
|
||||
targetScale = 0.5f;
|
||||
}
|
||||
for (int i = 0; i < matrixCount; i++) {
|
||||
const glm::vec2& coord = MAP_COORDS[i];
|
||||
glViewport(coord.s * fbo->width(), coord.t * fbo->height(), halfSize, halfSize);
|
||||
glViewport(coord.s * fbo->width(), coord.t * fbo->height(), targetSize, targetSize);
|
||||
|
||||
float nearScale = SHADOW_MATRIX_DISTANCES[i] * frustumScale;
|
||||
float farScale = SHADOW_MATRIX_DISTANCES[i + 1] * frustumScale;
|
||||
|
@ -2294,7 +2301,7 @@ void Application::updateShadowMap() {
|
|||
center = inverseRotation * center;
|
||||
|
||||
// to reduce texture "shimmer," move in texel increments
|
||||
float texelSize = (2.0f * radius) / halfSize;
|
||||
float texelSize = (2.0f * radius) / targetSize;
|
||||
center = glm::vec3(roundf(center.x / texelSize) * texelSize, roundf(center.y / texelSize) * texelSize,
|
||||
roundf(center.z / texelSize) * texelSize);
|
||||
|
||||
|
@ -2306,7 +2313,8 @@ void Application::updateShadowMap() {
|
|||
maxima.z += _viewFrustum.getFarClip() * 0.5f;
|
||||
|
||||
// save the combined matrix for rendering
|
||||
_shadowMatrices[i] = glm::transpose(glm::translate(glm::vec3(coord, 0.0f)) * glm::scale(glm::vec3(0.5f, 0.5f, 1.0f)) *
|
||||
_shadowMatrices[i] = glm::transpose(glm::translate(glm::vec3(coord, 0.0f)) *
|
||||
glm::scale(glm::vec3(targetScale, targetScale, 1.0f)) *
|
||||
glm::translate(glm::vec3(0.5f, 0.5f, 0.5f)) * glm::scale(glm::vec3(0.5f, 0.5f, 0.5f)) *
|
||||
glm::ortho(minima.x, maxima.x, minima.y, maxima.y, -maxima.z, -minima.z) * glm::mat4_cast(inverseRotation));
|
||||
|
||||
|
@ -2433,6 +2441,20 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) {
|
|||
// Setup 3D lights (after the camera transform, so that they are positioned in world space)
|
||||
setupWorldLight();
|
||||
|
||||
// setup shadow matrices (again, after the camera transform)
|
||||
int shadowMatrixCount = 0;
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::SimpleShadows)) {
|
||||
shadowMatrixCount = 1;
|
||||
} else if (Menu::getInstance()->isOptionChecked(MenuOption::CascadedShadows)) {
|
||||
shadowMatrixCount = CASCADED_SHADOW_MATRIX_COUNT;
|
||||
}
|
||||
for (int i = shadowMatrixCount - 1; i >= 0; i--) {
|
||||
glActiveTexture(GL_TEXTURE0 + i);
|
||||
glTexGenfv(GL_S, GL_EYE_PLANE, (const GLfloat*)&_shadowMatrices[i][0]);
|
||||
glTexGenfv(GL_T, GL_EYE_PLANE, (const GLfloat*)&_shadowMatrices[i][1]);
|
||||
glTexGenfv(GL_R, GL_EYE_PLANE, (const GLfloat*)&_shadowMatrices[i][2]);
|
||||
}
|
||||
|
||||
if (!selfAvatarOnly && Menu::getInstance()->isOptionChecked(MenuOption::Stars)) {
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||
"Application::displaySide() ... stars...");
|
||||
|
|
|
@ -126,7 +126,6 @@ static const float MIRROR_REARVIEW_DISTANCE = 0.65f;
|
|||
static const float MIRROR_REARVIEW_BODY_DISTANCE = 2.3f;
|
||||
static const float MIRROR_FIELD_OF_VIEW = 30.0f;
|
||||
|
||||
static const int SHADOW_MATRIX_COUNT = 4;
|
||||
static const float SHADOW_MATRIX_DISTANCES[] = { 0.0f, 2.0f, 6.0f, 14.0f, 30.0f };
|
||||
|
||||
class Application : public QApplication {
|
||||
|
@ -264,8 +263,6 @@ public:
|
|||
/// result from matrix multiplication at high translation magnitudes.
|
||||
void loadTranslatedViewMatrix(const glm::vec3& translation);
|
||||
|
||||
const glm::mat4* getShadowMatrices() const { return _shadowMatrices; }
|
||||
|
||||
void getModelViewMatrix(glm::dmat4* modelViewMatrix);
|
||||
void getProjectionMatrix(glm::dmat4* projectionMatrix);
|
||||
|
||||
|
@ -494,7 +491,8 @@ private:
|
|||
float _rotateMirror;
|
||||
float _raiseMirror;
|
||||
|
||||
glm::mat4 _shadowMatrices[SHADOW_MATRIX_COUNT];
|
||||
static const int CASCADED_SHADOW_MATRIX_COUNT = 4;
|
||||
glm::mat4 _shadowMatrices[CASCADED_SHADOW_MATRIX_COUNT];
|
||||
|
||||
Environment _environment;
|
||||
|
||||
|
|
|
@ -303,7 +303,12 @@ Menu::Menu() :
|
|||
appInstance->getGlowEffect(),
|
||||
SLOT(cycleRenderMode()));
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Shadows, 0, false);
|
||||
QMenu* shadowMenu = renderOptionsMenu->addMenu("Shadows");
|
||||
QActionGroup* shadowGroup = new QActionGroup(shadowMenu);
|
||||
shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, "None", 0, true));
|
||||
shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, MenuOption::SimpleShadows, 0, false));
|
||||
shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, MenuOption::CascadedShadows, 0, false));
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Metavoxels, 0, true);
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::BuckyBalls, 0, false);
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Particles, 0, true);
|
||||
|
@ -666,6 +671,10 @@ void Menu::scanMenu(QMenu* menu, settingsAction modifySetting, QSettings* set) {
|
|||
set->endGroup();
|
||||
}
|
||||
|
||||
bool Menu::getShadowsEnabled() const {
|
||||
return isOptionChecked(MenuOption::SimpleShadows) || isOptionChecked(MenuOption::CascadedShadows);
|
||||
}
|
||||
|
||||
void Menu::handleViewFrustumOffsetKeyModifier(int key) {
|
||||
const float VIEW_FRUSTUM_OFFSET_DELTA = 0.5f;
|
||||
const float VIEW_FRUSTUM_OFFSET_UP_DELTA = 0.05f;
|
||||
|
@ -836,8 +845,8 @@ void Menu::setIsOptionChecked(const QString& menuOption, bool isChecked) {
|
|||
}
|
||||
}
|
||||
|
||||
bool Menu::isOptionChecked(const QString& menuOption) {
|
||||
QAction* menu = _actionHash.value(menuOption);
|
||||
bool Menu::isOptionChecked(const QString& menuOption) const {
|
||||
const QAction* menu = _actionHash.value(menuOption);
|
||||
if (menu) {
|
||||
return menu->isChecked();
|
||||
}
|
||||
|
|
|
@ -102,6 +102,8 @@ public:
|
|||
int getMaxVoxels() const { return _maxVoxels; }
|
||||
QAction* getUseVoxelShader() const { return _useVoxelShader; }
|
||||
|
||||
bool getShadowsEnabled() const;
|
||||
|
||||
void handleViewFrustumOffsetKeyModifier(int key);
|
||||
|
||||
// User Tweakable LOD Items
|
||||
|
@ -170,7 +172,7 @@ public slots:
|
|||
void removeSeparator(const QString& menuName, const QString& separatorName);
|
||||
void addMenuItem(const MenuItemProperties& properties);
|
||||
void removeMenuItem(const QString& menuName, const QString& menuitem);
|
||||
bool isOptionChecked(const QString& menuOption);
|
||||
bool isOptionChecked(const QString& menuOption) const;
|
||||
void setIsOptionChecked(const QString& menuOption, bool isChecked);
|
||||
|
||||
private slots:
|
||||
|
@ -301,6 +303,7 @@ namespace MenuOption {
|
|||
const QString Bandwidth = "Bandwidth Display";
|
||||
const QString BandwidthDetails = "Bandwidth Details";
|
||||
const QString BuckyBalls = "Bucky Balls";
|
||||
const QString CascadedShadows = "Cascaded";
|
||||
const QString Chat = "Chat...";
|
||||
const QString ChatCircling = "Chat Circling";
|
||||
const QString CollideWithAvatars = "Collide With Avatars";
|
||||
|
@ -376,7 +379,7 @@ namespace MenuOption {
|
|||
const QString ScriptEditor = "Script Editor...";
|
||||
const QString SettingsExport = "Export Settings";
|
||||
const QString SettingsImport = "Import Settings";
|
||||
const QString Shadows = "Shadows";
|
||||
const QString SimpleShadows = "Simple";
|
||||
const QString ShowBordersVoxelNodes = "Show Voxel Nodes";
|
||||
const QString ShowBordersModelNodes = "Show Model Nodes";
|
||||
const QString ShowBordersParticleNodes = "Show Particle Nodes";
|
||||
|
|
|
@ -508,7 +508,7 @@ bool Model::render(float alpha, RenderMode mode, bool receiveShadows) {
|
|||
glEnable(GL_ALPHA_TEST);
|
||||
glAlphaFunc(GL_GREATER, 0.5f * alpha);
|
||||
|
||||
receiveShadows &= Menu::getInstance()->isOptionChecked(MenuOption::Shadows);
|
||||
receiveShadows &= Menu::getInstance()->getShadowsEnabled();
|
||||
renderMeshes(alpha, mode, false, receiveShadows);
|
||||
|
||||
glDisable(GL_ALPHA_TEST);
|
||||
|
@ -1508,14 +1508,6 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent, bool re
|
|||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||
const QVector<NetworkMesh>& networkMeshes = _geometry->getMeshes();
|
||||
|
||||
if (receiveShadows) {
|
||||
for (int i = SHADOW_MATRIX_COUNT - 1; i >= 0; i--) {
|
||||
glActiveTexture(GL_TEXTURE0 + i);
|
||||
glTexGenfv(GL_S, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrices()[i][0]);
|
||||
glTexGenfv(GL_T, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrices()[i][1]);
|
||||
glTexGenfv(GL_R, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrices()[i][2]);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < networkMeshes.size(); i++) {
|
||||
// exit early if the translucency doesn't match what we're drawing
|
||||
const NetworkMesh& networkMesh = networkMeshes.at(i);
|
||||
|
|
|
@ -518,9 +518,19 @@ void VoxelSystem::initVoxelMemory() {
|
|||
|
||||
_shadowMapProgram.bind();
|
||||
_shadowMapProgram.setUniformValue("shadowMap", 0);
|
||||
_shadowMapProgram.setUniformValue("shadowDistances", -SHADOW_MATRIX_DISTANCES[1],
|
||||
-SHADOW_MATRIX_DISTANCES[2], -SHADOW_MATRIX_DISTANCES[3]);
|
||||
_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);
|
||||
_cascadedShadowMapProgram.setUniformValue("shadowDistances", -SHADOW_MATRIX_DISTANCES[1],
|
||||
-SHADOW_MATRIX_DISTANCES[2], -SHADOW_MATRIX_DISTANCES[3]);
|
||||
_cascadedShadowMapProgram.release();
|
||||
}
|
||||
}
|
||||
_renderer = new PrimitiveRenderer(_maxVoxels);
|
||||
|
@ -1168,6 +1178,7 @@ glm::vec3 VoxelSystem::computeVoxelVertex(const glm::vec3& startVertex, float vo
|
|||
|
||||
ProgramObject VoxelSystem::_perlinModulateProgram;
|
||||
ProgramObject VoxelSystem::_shadowMapProgram;
|
||||
ProgramObject VoxelSystem::_cascadedShadowMapProgram;
|
||||
|
||||
void VoxelSystem::init() {
|
||||
if (_initialized) {
|
||||
|
@ -1488,16 +1499,14 @@ void VoxelSystem::render() {
|
|||
|
||||
void VoxelSystem::applyScaleAndBindProgram(bool texture) {
|
||||
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Shadows)) {
|
||||
_shadowMapProgram.bind();
|
||||
if (Menu::getInstance()->getShadowsEnabled()) {
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::CascadedShadows)) {
|
||||
_cascadedShadowMapProgram.bind();
|
||||
} else {
|
||||
_shadowMapProgram.bind();
|
||||
}
|
||||
glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getShadowDepthTextureID());
|
||||
|
||||
for (int i = SHADOW_MATRIX_COUNT - 1; i >= 0; i--) {
|
||||
glActiveTexture(GL_TEXTURE0 + i);
|
||||
glTexGenfv(GL_S, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrices()[i][0]);
|
||||
glTexGenfv(GL_T, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrices()[i][1]);
|
||||
glTexGenfv(GL_R, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrices()[i][2]);
|
||||
}
|
||||
} else if (texture) {
|
||||
_perlinModulateProgram.bind();
|
||||
glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getPermutationNormalTextureID());
|
||||
|
@ -1511,11 +1520,14 @@ void VoxelSystem::removeScaleAndReleaseProgram(bool texture) {
|
|||
// scale back down to 1 so heads aren't massive
|
||||
glPopMatrix();
|
||||
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Shadows)) {
|
||||
_shadowMapProgram.release();
|
||||
if (Menu::getInstance()->getShadowsEnabled()) {
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::CascadedShadows)) {
|
||||
_cascadedShadowMapProgram.release();
|
||||
} else {
|
||||
_shadowMapProgram.release();
|
||||
}
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
|
||||
} else if (texture) {
|
||||
_perlinModulateProgram.release();
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
|
|
@ -233,6 +233,7 @@ private:
|
|||
|
||||
static ProgramObject _perlinModulateProgram;
|
||||
static ProgramObject _shadowMapProgram;
|
||||
static ProgramObject _cascadedShadowMapProgram;
|
||||
|
||||
int _hookID;
|
||||
std::vector<glBufferIndex> _freeIndexes;
|
||||
|
|
Loading…
Reference in a new issue