From 7b790d20156d05e90a6c5e0150680c89e65d92ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Lemaire?= Date: Sat, 21 Dec 2013 23:48:54 +0100 Subject: [PATCH 01/17] Switched opengl skybox to shaders --- src/basics/basics_global.h | 3 + src/definition/definition_global.h | 1 + src/render/opengl/ExplorerChunkSky.cpp | 148 ---------- src/render/opengl/ExplorerChunkSky.h | 42 --- src/render/opengl/OpenGLPart.cpp | 109 +++++++ src/render/opengl/OpenGLPart.h | 46 +++ src/render/opengl/OpenGLRenderer.cpp | 17 ++ src/render/opengl/OpenGLRenderer.h | 11 + src/render/opengl/OpenGLShaderProgram.cpp | 277 ++++++++++++++++++ src/render/opengl/OpenGLShaderProgram.h | 61 ++++ src/render/opengl/OpenGLSkybox.cpp | 96 ++++++ src/render/opengl/OpenGLSkybox.h | 35 +++ src/render/opengl/WidgetExplorer.cpp | 17 +- src/render/opengl/opengl.pro | 19 +- src/render/opengl/opengl_global.h | 2 + src/render/opengl/shaders/resources.qrc | 6 + src/render/opengl/shaders/skybox.frag | 233 +++++++++++++++ src/render/opengl/shaders/skybox.vert | 10 + .../software/AtmosphereModelBruneton.cpp | 15 + src/render/software/AtmosphereModelBruneton.h | 5 + src/render/software/AtmosphereRenderer.h | 2 + 21 files changed, 948 insertions(+), 207 deletions(-) delete mode 100644 src/render/opengl/ExplorerChunkSky.cpp delete mode 100644 src/render/opengl/ExplorerChunkSky.h create mode 100644 src/render/opengl/OpenGLPart.cpp create mode 100644 src/render/opengl/OpenGLPart.h create mode 100644 src/render/opengl/OpenGLShaderProgram.cpp create mode 100644 src/render/opengl/OpenGLShaderProgram.h create mode 100644 src/render/opengl/OpenGLSkybox.cpp create mode 100644 src/render/opengl/OpenGLSkybox.h create mode 100644 src/render/opengl/shaders/resources.qrc create mode 100644 src/render/opengl/shaders/skybox.frag create mode 100644 src/render/opengl/shaders/skybox.vert diff --git a/src/basics/basics_global.h b/src/basics/basics_global.h index e6830b6..853908d 100644 --- a/src/basics/basics_global.h +++ b/src/basics/basics_global.h @@ -20,6 +20,9 @@ namespace basics { class NoiseGenerator; class Curve; class ColorProfile; + class Texture2D; + class Texture3D; + class Texture4D; } } using namespace paysages::basics; diff --git a/src/definition/definition_global.h b/src/definition/definition_global.h index 7279f08..78585e3 100644 --- a/src/definition/definition_global.h +++ b/src/definition/definition_global.h @@ -2,6 +2,7 @@ #define DEFINITION_GLOBAL_H #include + #if defined(DEFINITION_LIBRARY) # define DEFINITIONSHARED_EXPORT Q_DECL_EXPORT #else diff --git a/src/render/opengl/ExplorerChunkSky.cpp b/src/render/opengl/ExplorerChunkSky.cpp deleted file mode 100644 index 3ebd5a9..0000000 --- a/src/render/opengl/ExplorerChunkSky.cpp +++ /dev/null @@ -1,148 +0,0 @@ -#include "ExplorerChunkSky.h" - -#include -#include -#include "CameraDefinition.h" -#include "SoftwareRenderer.h" -#include "AtmosphereRenderer.h" -#include "AtmosphereResult.h" - -ExplorerChunkSky::ExplorerChunkSky(SoftwareRenderer* renderer, double size, SkyboxOrientation orientation) : BaseExplorerChunk(renderer) -{ - _box_size = size; - _orientation = orientation; - _center = VECTOR_ZERO; - - setMaxTextureSize(256); - maintain(); -} - -void ExplorerChunkSky::onCameraEvent(CameraDefinition* camera) -{ - _center = camera->getLocation(); -} - -void ExplorerChunkSky::onRenderEvent(QGLWidget*) -{ - double size = _box_size; - Vector3 camera = _center; - - glBegin(GL_QUADS); - switch (_orientation) - { - case SKYBOX_NORTH: - glTexCoord2d(0.0, 0.0); - glVertex3d(camera.x - size, camera.y + size, camera.z - size); - glTexCoord2d(0.0, 1.0); - glVertex3d(camera.x - size, camera.y - size, camera.z - size); - glTexCoord2d(1.0, 1.0); - glVertex3d(camera.x + size, camera.y - size, camera.z - size); - glTexCoord2d(1.0, 0.0); - glVertex3d(camera.x + size, camera.y + size, camera.z - size); - break; - case SKYBOX_SOUTH: - glTexCoord2d(0.0, 0.0); - glVertex3d(camera.x + size, camera.y + size, camera.z + size); - glTexCoord2d(0.0, 1.0); - glVertex3d(camera.x + size, camera.y - size, camera.z + size); - glTexCoord2d(1.0, 1.0); - glVertex3d(camera.x - size, camera.y - size, camera.z + size); - glTexCoord2d(1.0, 0.0); - glVertex3d(camera.x - size, camera.y + size, camera.z + size); - break; - case SKYBOX_EAST: - glTexCoord2d(0.0, 0.0); - glVertex3d(camera.x + size, camera.y + size, camera.z - size); - glTexCoord2d(0.0, 1.0); - glVertex3d(camera.x + size, camera.y - size, camera.z - size); - glTexCoord2d(1.0, 1.0); - glVertex3d(camera.x + size, camera.y - size, camera.z + size); - glTexCoord2d(1.0, 0.0); - glVertex3d(camera.x + size, camera.y + size, camera.z + size); - break; - case SKYBOX_WEST: - glTexCoord2d(0.0, 0.0); - glVertex3d(camera.x - size, camera.y + size, camera.z + size); - glTexCoord2d(0.0, 1.0); - glVertex3d(camera.x - size, camera.y - size, camera.z + size); - glTexCoord2d(1.0, 1.0); - glVertex3d(camera.x - size, camera.y - size, camera.z - size); - glTexCoord2d(1.0, 0.0); - glVertex3d(camera.x - size, camera.y + size, camera.z - size); - break; - case SKYBOX_TOP: - glTexCoord2d(0.0, 0.0); - glVertex3d(camera.x - size, camera.y + size, camera.z + size); - glTexCoord2d(0.0, 1.0); - glVertex3d(camera.x - size, camera.y + size, camera.z - size); - glTexCoord2d(1.0, 1.0); - glVertex3d(camera.x + size, camera.y + size, camera.z - size); - glTexCoord2d(1.0, 0.0); - glVertex3d(camera.x + size, camera.y + size, camera.z + size); - break; - case SKYBOX_BOTTOM: - /*glTexCoord2d(0.0, 0.0); - glVertex3d(camera.x - size, camera.y - size, camera.z - size); - glTexCoord2d(0.0, 1.0); - glVertex3d(camera.x - size, camera.y - size, camera.z + size); - glTexCoord2d(1.0, 1.0); - glVertex3d(camera.x + size, camera.y - size, camera.z + size); - glTexCoord2d(1.0, 0.0); - glVertex3d(camera.x + size, camera.y - size, camera.z - size);*/ - break; - } - glEnd(); -} - -double ExplorerChunkSky::getDisplayedSizeHint(CameraDefinition*) -{ - return 1000.0; -} - -Color ExplorerChunkSky::getTextureColor(double x, double y) -{ - Vector3 location; - - x -= 0.5; - y -= 0.5; - - switch (_orientation) - { - case SKYBOX_NORTH: - location.x = x; - location.y = -y; - location.z = -0.5; - break; - case SKYBOX_SOUTH: - location.x = -x; - location.y = -y; - location.z = 0.5; - break; - case SKYBOX_EAST: - location.x = 0.5; - location.y = -y; - location.z = x; - break; - case SKYBOX_WEST: - location.x = -0.5; - location.y = -y; - location.z = -x; - break; - case SKYBOX_TOP: - location.x = x; - location.y = 0.5; - location.z = -y; - break; - case SKYBOX_BOTTOM: - location.x = x; - location.y = -0.5; - location.z = y; - break; - } - location = location.normalize(); - if (location.y < 0.0) - { - location.y = 0.0; - } - return renderer()->getAtmosphereRenderer()->getSkyColor(location).final; -} diff --git a/src/render/opengl/ExplorerChunkSky.h b/src/render/opengl/ExplorerChunkSky.h deleted file mode 100644 index 7948d79..0000000 --- a/src/render/opengl/ExplorerChunkSky.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef EXPLORERCHUNKSKY_H -#define EXPLORERCHUNKSKY_H - -#include "opengl_global.h" - -#include "BaseExplorerChunk.h" - -#include "Vector3.h" - -namespace paysages { -namespace opengl { - -enum SkyboxOrientation -{ - SKYBOX_NORTH, - SKYBOX_SOUTH, - SKYBOX_WEST, - SKYBOX_EAST, - SKYBOX_TOP, - SKYBOX_BOTTOM -}; - -class OPENGLSHARED_EXPORT ExplorerChunkSky:public BaseExplorerChunk -{ -public: - ExplorerChunkSky(SoftwareRenderer* renderer, double size, SkyboxOrientation orientation); - - void onCameraEvent(CameraDefinition* camera); - void onRenderEvent(QGLWidget* widget); - double getDisplayedSizeHint(CameraDefinition* camera); - Color getTextureColor(double x, double y); - -private: - SkyboxOrientation _orientation; - double _box_size; - Vector3 _center; -}; - -} -} - -#endif // EXPLORERCHUNKSKY_H diff --git a/src/render/opengl/OpenGLPart.cpp b/src/render/opengl/OpenGLPart.cpp new file mode 100644 index 0000000..c2d6d98 --- /dev/null +++ b/src/render/opengl/OpenGLPart.cpp @@ -0,0 +1,109 @@ +#include "OpenGLPart.h" + +#include +#include +#include "OpenGLRenderer.h" +#include "OpenGLShaderProgram.h" +#include "CameraDefinition.h" +#include "AtmosphereDefinition.h" +#include "AtmosphereRenderer.h" +#include "WaterRenderer.h" +#include "Scenery.h" + +OpenGLPart::OpenGLPart(OpenGLRenderer* renderer): + renderer(renderer) +{ +} + +OpenGLPart::~OpenGLPart() +{ + QMapIterator i(shaders); + while (i.hasNext()) + { + i.next(); + delete i.value(); + } +} + +OpenGLShaderProgram* OpenGLPart::createShader(QString name) +{ + OpenGLShaderProgram* program = new OpenGLShaderProgram(name, renderer->getOpenGlFunctions()); + + if (!shaders.contains(name)) + { + shaders[name] = program; + return program; + } + else + { + return 0; + } +} + +void OpenGLPart::postInitialize() +{ + QMapIterator i(shaders); + while (i.hasNext()) + { + i.next(); + i.value()->compile(); + } +} + +void OpenGLPart::updateCamera(CameraDefinition* camera) +{ + // Get camera info + Vector3 location = camera->getLocation(); + Vector3 target = camera->getTarget(); + Vector3 up = camera->getUpVector(); + CameraPerspective perspective = camera->getPerspective(); + + QVector3D vlocation(location.x, location.y, location.z); + + // Compute matrix + QMatrix4x4 transform; + transform.setToIdentity(); + transform.lookAt(vlocation, + QVector3D(target.x, target.y, target.z), + QVector3D(up.x, up.y, up.z)); + + QMatrix4x4 projection; + projection.setToIdentity(); + projection.perspective(perspective.yfov * 180.0 / M_PI, perspective.xratio, perspective.znear, perspective.zfar); + + // Set in shaders + QMapIterator i(shaders); + while (i.hasNext()) + { + i.next(); + i.value()->updateCamera(vlocation, projection * transform); + } +} + +void OpenGLPart::updateScenery(bool onlyCommon) +{ + Scenery* scenery = renderer->getScenery(); + + // Collect common info + double water_height = renderer->getWaterRenderer()->getHeightInfo().max_height; + Vector3 orig_sun_direction = renderer->getAtmosphereRenderer()->getSunDirection(); + QVector3D sun_direction = QVector3D(orig_sun_direction.x, orig_sun_direction.y, orig_sun_direction.z); + Color orig_sun_color = scenery->getAtmosphere()->sun_color; + QColor sun_color = QColor(orig_sun_color.r, orig_sun_color.g, orig_sun_color.b); + + // Update shaders + QMapIterator i(shaders); + while (i.hasNext()) + { + i.next(); + + i.value()->updateWaterHeight(water_height); + i.value()->updateSun(sun_direction, sun_color); + } + + // Let subclass do its own collecting + if (not onlyCommon) + { + update(); + } +} diff --git a/src/render/opengl/OpenGLPart.h b/src/render/opengl/OpenGLPart.h new file mode 100644 index 0000000..b7ae211 --- /dev/null +++ b/src/render/opengl/OpenGLPart.h @@ -0,0 +1,46 @@ +#ifndef OPENGLPART_H +#define OPENGLPART_H + +#include "opengl_global.h" + +#include +#include + +namespace paysages { +namespace opengl { + +// Class that can be inherited by scenery parts, to use OpenGL features + +class OPENGLSHARED_EXPORT OpenGLPart +{ +public: + OpenGLPart(OpenGLRenderer* renderer); + virtual ~OpenGLPart(); + + // Initialize the part rendering (create shaders, prepare static textures...) + virtual void initialize() = 0; + + // Update parameters from scenery + virtual void update() = 0; + + // Do the rendering + virtual void render() = 0; + + void postInitialize(); + void updateCamera(CameraDefinition* camera); + void updateScenery(bool onlyCommon=false); + +protected: + // Create a shader program + OpenGLShaderProgram* createShader(QString name); + + // Access to the main scenery renderer + OpenGLRenderer* renderer; + +private: + QMap shaders; +}; +} +} + +#endif // OPENGLPART_H diff --git a/src/render/opengl/OpenGLRenderer.cpp b/src/render/opengl/OpenGLRenderer.cpp index 31bbfc6..0106179 100644 --- a/src/render/opengl/OpenGLRenderer.cpp +++ b/src/render/opengl/OpenGLRenderer.cpp @@ -1,18 +1,22 @@ #include "OpenGLRenderer.h" +#include #include #include #include #include "Scenery.h" #include "CameraDefinition.h" +#include "OpenGLSkybox.h" OpenGLRenderer::OpenGLRenderer(Scenery* scenery): SoftwareRenderer(scenery) { + skybox = new OpenGLSkybox(this); } OpenGLRenderer::~OpenGLRenderer() { + delete skybox; } void OpenGLRenderer::initialize() @@ -38,6 +42,11 @@ void OpenGLRenderer::initialize() glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); prepare(); + + functions = new QOpenGLFunctions(); + + skybox->initialize(); + skybox->updateScenery(); } void OpenGLRenderer::resize(int width, int height) @@ -56,7 +65,15 @@ void OpenGLRenderer::resize(int width, int height) void OpenGLRenderer::paint() { + glClearColor(0.0, 0.0, 0.0, 0.0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + skybox->render(); +} + +void OpenGLRenderer::cameraChangeEvent(CameraDefinition *camera) +{ + skybox->updateCamera(camera); } double OpenGLRenderer::getPrecision(const Vector3 &) diff --git a/src/render/opengl/OpenGLRenderer.h b/src/render/opengl/OpenGLRenderer.h index 075b3ac..fc5786c 100644 --- a/src/render/opengl/OpenGLRenderer.h +++ b/src/render/opengl/OpenGLRenderer.h @@ -5,6 +5,8 @@ #include "SoftwareRenderer.h" +class QOpenGLFunctions; + namespace paysages { namespace opengl { @@ -21,8 +23,17 @@ public: void resize(int width, int height); void paint(); + void cameraChangeEvent(CameraDefinition* camera); + + inline QOpenGLFunctions* getOpenGlFunctions() {return functions;} + virtual double getPrecision(const Vector3 &location) override; virtual Color applyMediumTraversal(Vector3 location, Color color) override; + +private: + QOpenGLFunctions* functions; + + OpenGLSkybox* skybox; }; } diff --git a/src/render/opengl/OpenGLShaderProgram.cpp b/src/render/opengl/OpenGLShaderProgram.cpp new file mode 100644 index 0000000..f9e11bb --- /dev/null +++ b/src/render/opengl/OpenGLShaderProgram.cpp @@ -0,0 +1,277 @@ +#include "OpenGLShaderProgram.h" + +#include +#include +#include +#include "Texture2D.h" +#include "Texture3D.h" +#include "Texture4D.h" +#include "Color.h" + +OpenGLShaderProgram::OpenGLShaderProgram(QString name, QOpenGLFunctions* functions): + name(name), functions(functions) +{ + program = new QOpenGLShaderProgram(); +} + +OpenGLShaderProgram::~OpenGLShaderProgram() +{ + delete program; +} + +void OpenGLShaderProgram::addVertexSource(QString path) +{ + program->addShaderFromSourceFile(QOpenGLShader::Vertex, QString(":/shaders/%1.vert").arg(path)); +} + +void OpenGLShaderProgram::addFragmentSource(QString path) +{ + program->addShaderFromSourceFile(QOpenGLShader::Fragment, QString(":/shaders/%1.frag").arg(path)); +} + +void OpenGLShaderProgram::compile() +{ + if (not program->link()) + { + qWarning() << "Error while compiling shader " << name << "\n" << program->log() << "\n"; + } + else + { + qDebug() << "Shader " << name << " compilation output:\n" << program->log() << "\n"; + } +} + +void OpenGLShaderProgram::updateCamera(const QVector3D& location, const QMatrix4x4& view) +{ + this->camera_location = location; + this->view = view; +} + +void OpenGLShaderProgram::updateWaterHeight(double height) +{ + this->water_height = height; +} + +void OpenGLShaderProgram::updateSun(const QVector3D& direction, const QColor& color) +{ + this->sun_direction = direction; + this->sun_color = color; +} + +void OpenGLShaderProgram::addTexture(QString sampler_name, Texture2D* texture) +{ + GLuint texid; + + if (textures.contains(sampler_name)) + { + texid = textures[sampler_name].second; + } + else + { + glGenTextures(1, &texid); + textures[sampler_name] = QPair(GL_TEXTURE_2D, texid); + } + + glBindTexture(GL_TEXTURE_2D, texid); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + int sx, sy; + texture->getSize(&sx, &sy); + float* pixels = new float[sx * sy * 4]; + for (int x = 0; x < sx; x++) + { + for (int y = 0; y < sy; y++) + { + float* pixel = pixels + (y * sx + x) * 4; + Color col = texture->getPixel(x, y); + pixel[0] = (float)col.r; + pixel[1] = (float)col.g; + pixel[2] = (float)col.b; + pixel[3] = (float)col.a; + } + } + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, sx, sy, 0, GL_RGBA, GL_FLOAT, pixels); + delete[] pixels; +} + +void OpenGLShaderProgram::addTexture(QString sampler_name, Texture3D* texture) +{ + GLuint texid; + + if (textures.contains(sampler_name)) + { + texid = textures[sampler_name].second; + } + else + { + glGenTextures(1, &texid); + textures[sampler_name] = QPair(GL_TEXTURE_3D, texid); + } + + glBindTexture(GL_TEXTURE_3D, texid); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + + int sx, sy, sz; + texture->getSize(&sx, &sy, &sz); + float* pixels = new float[sx * sy * sz * 4]; + for (int x = 0; x < sx; x++) + { + for (int y = 0; y < sy; y++) + { + for (int z = 0; z < sz; z++) + { + float* pixel = pixels + (z * (sx * sy) + y * sx + x) * 4; + Color col = texture->getPixel(x, y, z); + pixel[0] = (float)col.r; + pixel[1] = (float)col.g; + pixel[2] = (float)col.b; + pixel[3] = (float)col.a; + } + } + } + + glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, sx, sy, sz, 0, GL_RGBA, GL_FLOAT, pixels); + delete[] pixels; +} + +void OpenGLShaderProgram::addTexture(QString sampler_name, Texture4D* texture) +{ + GLuint texid; + + if (textures.contains(sampler_name)) + { + texid = textures[sampler_name].second; + } + else + { + glGenTextures(1, &texid); + textures[sampler_name] = QPair(GL_TEXTURE_3D, texid); + } + + glBindTexture(GL_TEXTURE_3D, texid); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + + int sx, sy, sz, sw; + texture->getSize(&sx, &sy, &sz, &sw); + float* pixels = new float[sx * sy * sz * sw * 4]; + for (int x = 0; x < sx; x++) + { + for (int y = 0; y < sy; y++) + { + for (int z = 0; z < sz; z++) + { + for (int w = 0; w < sw; w++) + { + float* pixel = pixels + (w * (sx * sy * sz) + z * (sx * sy) + y * sx + x) * 4; + Color col = texture->getPixel(x, y, z, w); + pixel[0] = (float)col.r; + pixel[1] = (float)col.g; + pixel[2] = (float)col.b; + pixel[3] = (float)col.a; + } + } + } + } + + glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, sx, sy, sz * sw, 0, GL_RGBA, GL_FLOAT, pixels); + delete[] pixels; +} + +void OpenGLShaderProgram::bind() +{ + program->bind(); + + // TODO Keep locations in cache + + int viewMatrix = program->uniformLocation("viewMatrix"); + if (viewMatrix >= 0) + { + program->setUniformValue(viewMatrix, view); + } + + int cameraLocation = program->uniformLocation("cameraLocation"); + if (cameraLocation >= 0) + { + program->setUniformValue(cameraLocation, camera_location); + } + + int waterHeight = program->uniformLocation("waterHeight"); + if (waterHeight >= 0) + { + program->setUniformValue(waterHeight, water_height); + } + + int sunDirection = program->uniformLocation("sunDirection"); + if (sunDirection >= 0) + { + program->setUniformValue(sunDirection, sun_direction); + } + + int sunColor = program->uniformLocation("sunColor"); + if (sunColor >= 0) + { + program->setUniformValue(sunColor, sun_color); + } + + QMapIterator > iter(textures); + int i = 0; + while (iter.hasNext()) + { + iter.next(); + int textureSampler = program->uniformLocation(iter.key()); + if (textureSampler >= 0) + { + glActiveTexture(GL_TEXTURE0 + i); + glBindTexture(iter.value().first, iter.value().second); + program->setUniformValue(textureSampler, i); + i++; + } + } +} + +void OpenGLShaderProgram::release() +{ + program->release(); +} + +void OpenGLShaderProgram::drawTriangles(float* vertices, int triangle_count) +{ + bind(); + + GLuint vertex = program->attributeLocation("vertex"); + program->setAttributeArray(vertex, GL_FLOAT, vertices, 3); + program->enableAttributeArray(vertex); + + glDrawArrays(GL_TRIANGLES, 0, triangle_count * 3); + + program->disableAttributeArray(vertex); + + release(); +} + +void OpenGLShaderProgram::drawTriangleStrip(float* vertices, int vertex_count) +{ + bind(); + + GLuint vertex = program->attributeLocation("vertex"); + program->setAttributeArray(vertex, GL_FLOAT, vertices, 3); + program->enableAttributeArray(vertex); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, vertex_count); + + program->disableAttributeArray(vertex); + + release(); +} diff --git a/src/render/opengl/OpenGLShaderProgram.h b/src/render/opengl/OpenGLShaderProgram.h new file mode 100644 index 0000000..aa8e30a --- /dev/null +++ b/src/render/opengl/OpenGLShaderProgram.h @@ -0,0 +1,61 @@ +#ifndef OPENGLSHADERPROGRAM_H +#define OPENGLSHADERPROGRAM_H + +#include "opengl_global.h" + +#include +#include +#include +#include +#include + +class QOpenGLShaderProgram; +class QOpenGLFunctions; + +namespace paysages { +namespace opengl { + +class OPENGLSHARED_EXPORT OpenGLShaderProgram +{ +public: + OpenGLShaderProgram(QString name, QOpenGLFunctions* functions); + ~OpenGLShaderProgram(); + + void addVertexSource(QString path); + void addFragmentSource(QString path); + void compile(); + + void updateCamera(const QVector3D& location, const QMatrix4x4& view); + void updateWaterHeight(double height); + void updateSun(const QVector3D& direction, const QColor& color); + + void addTexture(QString sampler_name, Texture2D* texture); + void addTexture(QString sampler_name, Texture3D* texture); + void addTexture(QString sampler_name, Texture4D* texture); + + void drawTriangles(float* vertices, int triangle_count); + void drawTriangleStrip(float* vertices, int vertex_count); + +private: + void bind(); + void release(); + + QMatrix4x4 view; + QVector3D camera_location; + + float water_height; + + QVector3D sun_direction; + QColor sun_color; + + QString name; + QOpenGLShaderProgram* program; + QOpenGLFunctions* functions; + + QMap > textures; +}; + +} +} + +#endif // OPENGLSHADERPROGRAM_H diff --git a/src/render/opengl/OpenGLSkybox.cpp b/src/render/opengl/OpenGLSkybox.cpp new file mode 100644 index 0000000..8cfa29a --- /dev/null +++ b/src/render/opengl/OpenGLSkybox.cpp @@ -0,0 +1,96 @@ +#include "OpenGLSkybox.h" + +#include +#include "OpenGLRenderer.h" +#include "OpenGLShaderProgram.h" +#include "Scenery.h" +#include "AtmosphereDefinition.h" +#include "AtmosphereRenderer.h" +#include "AtmosphereModelBruneton.h" + +OpenGLSkybox::OpenGLSkybox(OpenGLRenderer* renderer): + OpenGLPart(renderer) +{ + vertices = new float[14 * 3]; + daytime = renderer->getScenery()->getAtmosphere()->_daytime; +} + +OpenGLSkybox::~OpenGLSkybox() +{ + delete[] vertices; +} + +void OpenGLSkybox::initialize() +{ + program = createShader("skybox"); + program->addVertexSource("skybox"); + program->addFragmentSource("skybox"); + + setVertex(0, 1.0f, 1.0f, 1.0f); + setVertex(12, 1.0f, 1.0f, 1.0f); + + setVertex(1, 1.0f, -1.0f, 1.0f); + setVertex(5, 1.0f, -1.0f, 1.0f); + setVertex(13, 1.0f, -1.0f, 1.0f); + + setVertex(2, -1.0f, 1.0f, 1.0f); + setVertex(10, -1.0f, 1.0f, 1.0f); + + setVertex(3, -1.0f, -1.0f, 1.0f); + + setVertex(4, -1.0f, -1.0f, -1.0f); + setVertex(8, -1.0f, -1.0f, -1.0f); + + setVertex(6, 1.0f, -1.0f, -1.0f); + + setVertex(7, 1.0f, 1.0f, -1.0f); + setVertex(11, 1.0f, 1.0f, -1.0f); + + setVertex(9, -1.0f, 1.0f, -1.0f); +} + +void OpenGLSkybox::update() +{ + SoftwareBrunetonAtmosphereRenderer* bruneton = (SoftwareBrunetonAtmosphereRenderer*)renderer->getAtmosphereRenderer(); + + program->addTexture("transmittanceTexture", bruneton->getModel()->getTextureTransmittance()); + program->addTexture("inscatterTexture", bruneton->getModel()->getTextureInscatter()); +} + +void OpenGLSkybox::render() +{ + program->drawTriangleStrip(vertices, 14); +} + +void OpenGLSkybox::alterDayTime(double delta) +{ +#if 0 + Scenery* scenery = renderer->getScenery(); + AtmosphereDefinition* definition = scenery->getAtmosphere()->definition; + daytime = fmod(daytime + delta * 0.001, 1.0); + // TEMP + if (daytime > 0.8) + { + daytime -= 0.6; + } + if (daytime < 0.2) + { + daytime += 0.6; + } + + definition->hour = (int)(daytime * 24.0); + definition->minute = (int)((daytime - (((double)definition->hour) / 24.0)) * 1440.0); + + AtmosphereDefinitionClass.validate(definition); + + // TODO Update only the sun + updateScenery(scenery, true); +#endif +} + +void OpenGLSkybox::setVertex(int i, float x, float y, float z) +{ + vertices[i * 3] = x; + vertices[i * 3 + 1] = y; + vertices[i * 3 + 2] = z; +} diff --git a/src/render/opengl/OpenGLSkybox.h b/src/render/opengl/OpenGLSkybox.h new file mode 100644 index 0000000..e2a72cb --- /dev/null +++ b/src/render/opengl/OpenGLSkybox.h @@ -0,0 +1,35 @@ +#ifndef OPENGLSKYBOX_H +#define OPENGLSKYBOX_H + +#include "opengl_global.h" + +#include "OpenGLPart.h" + +namespace paysages { +namespace opengl { + +class OPENGLSHARED_EXPORT OpenGLSkybox: public OpenGLPart +{ +public: + OpenGLSkybox(OpenGLRenderer* renderer); + virtual ~OpenGLSkybox(); + + virtual void initialize() override; + virtual void update() override; + virtual void render() override; + + void alterDayTime(double delta); + +private: + void setVertex(int i, float x, float y, float z); + + OpenGLShaderProgram* program; + float* vertices; + + double daytime; +}; + +} +} + +#endif // OPENGLSKYBOX_H diff --git a/src/render/opengl/WidgetExplorer.cpp b/src/render/opengl/WidgetExplorer.cpp index 2337813..b31d0ce 100644 --- a/src/render/opengl/WidgetExplorer.cpp +++ b/src/render/opengl/WidgetExplorer.cpp @@ -11,7 +11,6 @@ #include "WaterDefinition.h" #include "SurfaceMaterial.h" #include "CameraDefinition.h" -#include "ExplorerChunkSky.h" #include "ExplorerChunkTerrain.h" #include "TerrainRenderer.h" #include "WaterRenderer.h" @@ -113,14 +112,6 @@ void WidgetExplorer::startRendering() } } - // Add skybox - for (int orientation = 0; orientation < 5; orientation++) - { - ExplorerChunkSky* chunk = new ExplorerChunkSky(_renderer, 500.0, (SkyboxOrientation) orientation); - _chunks.append(chunk); - _updateQueue.append(chunk); - } - // Start rendering workers int nbcore; _alive = true; @@ -374,9 +365,13 @@ void WidgetExplorer::paintGL() // Don't do this at each frame, only on camera change _renderer->getScenery()->setCamera(_current_camera); _renderer->getScenery()->getCamera(_current_camera); + _renderer->cameraChangeEvent(_current_camera); start_time = QTime::currentTime(); + // Background + _renderer->paint(); + glMatrixMode(GL_MODELVIEW); glLoadIdentity(); Vector3 camera_location = _current_camera->getLocation(); @@ -384,10 +379,6 @@ void WidgetExplorer::paintGL() Vector3 camera_up = _current_camera->getUpVector(); gluLookAt(camera_location.x, camera_location.y, camera_location.z, camera_target.x, camera_target.y, camera_target.z, camera_up.x, camera_up.y, camera_up.z); - // Background - glClearColor(0.0, 0.0, 0.0, 0.0); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - // Render water double water_height = _renderer->getTerrainRenderer()->getWaterHeight(); glDisable(GL_TEXTURE_2D); diff --git a/src/render/opengl/opengl.pro b/src/render/opengl/opengl.pro index cd7042e..5e47964 100644 --- a/src/render/opengl/opengl.pro +++ b/src/render/opengl/opengl.pro @@ -16,17 +16,21 @@ include(../../common.pri) SOURCES += \ OpenGLRenderer.cpp \ BaseExplorerChunk.cpp \ - ExplorerChunkSky.cpp \ ExplorerChunkTerrain.cpp \ - WidgetExplorer.cpp + WidgetExplorer.cpp \ + OpenGLShaderProgram.cpp \ + OpenGLPart.cpp \ + OpenGLSkybox.cpp HEADERS +=\ opengl_global.h \ OpenGLRenderer.h \ BaseExplorerChunk.h \ - ExplorerChunkSky.h \ ExplorerChunkTerrain.h \ - WidgetExplorer.h + WidgetExplorer.h \ + OpenGLShaderProgram.h \ + OpenGLPart.h \ + OpenGLSkybox.h unix:!symbian { maemo5 { @@ -60,3 +64,10 @@ else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../software/debug/ else:unix: LIBS += -L$$OUT_PWD/../software/ -lpaysages_render_software INCLUDEPATH += $$PWD/../software DEPENDPATH += $$PWD/../software + +RESOURCES += \ + shaders/resources.qrc + +OTHER_FILES += \ + shaders/skybox.frag \ + shaders/skybox.vert diff --git a/src/render/opengl/opengl_global.h b/src/render/opengl/opengl_global.h index 19fa590..63b65f6 100644 --- a/src/render/opengl/opengl_global.h +++ b/src/render/opengl/opengl_global.h @@ -16,6 +16,8 @@ namespace opengl { class WidgetExplorer; class OpenGLRenderer; class BaseExplorerChunk; + class OpenGLShaderProgram; + class OpenGLSkybox; } } using namespace paysages::opengl; diff --git a/src/render/opengl/shaders/resources.qrc b/src/render/opengl/shaders/resources.qrc new file mode 100644 index 0000000..a922c12 --- /dev/null +++ b/src/render/opengl/shaders/resources.qrc @@ -0,0 +1,6 @@ + + + skybox.frag + skybox.vert + + diff --git a/src/render/opengl/shaders/skybox.frag b/src/render/opengl/shaders/skybox.frag new file mode 100644 index 0000000..3ffa70e --- /dev/null +++ b/src/render/opengl/shaders/skybox.frag @@ -0,0 +1,233 @@ +const float GROUND_OFFSET = 0.5; +const float Rg = 6360.0; +const float Rt = 6420.0; +const float RL = 6421.0; +const float exposure = 0.4; +const float ISun = 100.0; +const float AVERAGE_GROUND_REFLECTANCE = 0.1; +const float HR = 8.0; +const vec3 betaR = vec3(5.8e-3, 1.35e-2, 3.31e-2); +const float HM = 1.2; +const vec3 betaMSca = vec3(4e-3); +const vec3 betaMEx = vec3(4e-3 / 0.9); +const float mieG = 0.8; +const float SPHERE_SIZE = 20000.0; +const float WORLD_SCALING = 0.05; +const float SUN_DISTANCE = 149597870.0; +const float SUN_DISTANCE_SCALED = (SUN_DISTANCE / WORLD_SCALING); +const float SUN_RADIUS = 6.955e5; +const float SUN_RADIUS_SCALED = (SUN_RADIUS / WORLD_SCALING); +const float M_PI = 3.141592657; + +const int RES_MU = 128; +const int RES_MU_S = 32; +const int RES_R = 32; +const int RES_NU = 8; + +uniform float waterHeight; +uniform vec3 cameraLocation; +uniform vec3 sunDirection; +uniform vec4 sunColor; +const float sunRadius = 1.0; // TODO -> uniform + +varying vec3 unprojected; + +uniform sampler2D transmittanceTexture; +uniform sampler3D inscatterTexture; + +vec4 texture4D(sampler3D tex, float r, float mu, float muS, float nu) +{ + if (r < Rg + 0.00000001) r = Rg + 0.00000001; + float H = sqrt(Rt * Rt - Rg * Rg); + float rho = sqrt(r * r - Rg * Rg); + float rmu = r * mu; + float delta = rmu * rmu - r * r + Rg * Rg; + vec4 cst = (rmu < 0.0 && delta > 0.0) ? vec4(1.0, 0.0, 0.0, 0.5 - 0.5 / float(RES_MU)) : vec4(-1.0, H * H, H, 0.5 + 0.5 / float(RES_MU)); + float uR = 0.5 / float(RES_R) + rho / H * (1.0 - 1.0 / float(RES_R)); + float uMu = cst.a + (rmu * cst.r + sqrt(delta + cst.g)) / (rho + cst.b) * (0.5 - 1.0 / float(RES_MU)); + float uMuS = 0.5 / float(RES_MU_S) + (atan(max(muS, -0.1975) * tan(1.26 * 1.1)) / 1.1 + (1.0 - 0.26)) * 0.5 * (1.0 - 1.0 / float(RES_MU_S)); + + float sr = 1.0 / float(RES_R); + int br = int(floor(uR / sr)); + vec4 r1 = texture3D(tex, vec3(uMu, uMuS, float(br) * sr + nu * sr)); + vec4 r2 = texture3D(tex, vec3(uMu, uMuS, float(br + 1) * sr + nu * sr)); + return mix(r1, r2, (uR - float(br) * sr) / sr); +} + +float _limit(float r, float mu) +{ + float dout = -r * mu + sqrt(r * r * (mu * mu - 1.0) + RL * RL); + float delta2 = r * r * (mu * mu - 1.0) + Rg * Rg; + if (delta2 >= 0.0) + { + float din = -r * mu - sqrt(delta2); + if (din >= 0.0) { + dout = min(dout, din); + } + } + return dout; +} + +vec2 _getTransmittanceUV(float r, float mu) +{ + if (r < Rg + 0.00000001) r = Rg + 0.00000001; + float dr = (r - Rg) / (Rt - Rg); + return vec2(atan((mu + 0.15) / (1.0 + 0.15) * tan(1.5)) / 1.5, sqrt(dr)); +} + +vec4 _transmittance(float r, float mu) +{ + vec2 uv = _getTransmittanceUV(r, mu); + return texture2D(transmittanceTexture, uv); +} + +vec4 _transmittanceWithShadow(float r, float mu) +{ + return mu < -sqrt(1.0 - (Rg / r) * (Rg / r)) ? vec4(0.0) : _transmittance(r, mu); +} + +vec4 _sunTransmittance(vec3 v, vec3 s, float r, float mu, float radius) +{ + vec4 transmittance = r <= Rt ? _transmittanceWithShadow(r, mu) : vec4(1.0); /* T(x,xo) */ + float d = _limit(r, mu); + radius *= (1.0 + 10.0 * d / Rt); /* Inflating due to lens effect near horizon */ + float isun = step(cos(radius * M_PI / 180.0), dot(v, s)) * ISun; /* Lsun */ + transmittance.r *= isun; + transmittance.g *= isun; + transmittance.b *= isun; + transmittance.a = 1.0; + return transmittance; /* Eq (9) */ +} + +float phaseFunctionR(float mu) { + return (3.0 / (16.0 * M_PI)) * (1.0 + mu * mu); +} + +float phaseFunctionM(float mu) { + return 1.5 * 1.0 / (4.0 * M_PI) * (1.0 - mieG*mieG) * pow(1.0 + (mieG*mieG) - 2.0*mieG*mu, -3.0/2.0) * (1.0 + mu * mu) / (2.0 + mieG*mieG); +} + +float opticalDepth(float H, float r, float mu, float d) { + float a = sqrt((0.5/H)*r); + vec2 a01 = a*vec2(mu, mu + d / r); + vec2 a01s = sign(a01); + vec2 a01sq = a01*a01; + float x = a01s.y > a01s.x ? exp(a01sq.x) : 0.0; + vec2 y = a01s / (2.3193*abs(a01) + sqrt(1.52*a01sq + 4.0)) * vec2(1.0, exp(-d/H*(d/(2.0*r)+mu))); + return sqrt((6.2831*H)*r) * exp((Rg-r)/H) * (x + dot(y, vec2(1.0, -1.0))); +} + +vec3 analyticTransmittance(float r, float mu, float d) { + return exp(- betaR * opticalDepth(HR, r, mu, d) - betaMEx * opticalDepth(HM, r, mu, d)); +} + +vec3 getMie(vec4 rayMie) { // rayMie.rgb=C*, rayMie.w=Cm,r + return rayMie.rgb * rayMie.w / max(rayMie.r, 1e-4) * (betaR.r / betaR); +} + +vec3 _getInscatterColor(inout vec3 x, inout float t, vec3 v, vec3 s, out float r, out float mu, out vec3 attenuation) { + vec3 result; + r = length(x); + mu = dot(x, v) / r; + float d = -r * mu - sqrt(r * r * (mu * mu - 1.0) + Rt * Rt); + if (d > 0.0) { // if x in space and ray intersects atmosphere + // move x to nearest intersection of ray with top atmosphere boundary + x += d * v; + t -= d; + mu = (r * mu + d) / Rt; + r = Rt; + } + if (r <= Rt) { // if ray intersects atmosphere + float nu = dot(v, s); + float muS = dot(x, s) / r; + float phaseR = phaseFunctionR(nu); + float phaseM = phaseFunctionM(nu); + vec4 inscatter = max(texture4D(inscatterTexture, r, mu, muS, nu), 0.0); + if (t > 0.0) { + vec3 x0 = x + t * v; + float r0 = length(x0); + float rMu0 = dot(x0, v); + float mu0 = rMu0 / r0; + float muS0 = dot(x0, s) / r0; + // avoids imprecision problems in transmittance computations based on textures + attenuation = analyticTransmittance(r, mu, t); + if (r0 > Rg + 0.001) { + // computes S[L]-T(x,x0)S[L]|x0 + inscatter = max(inscatter - attenuation.rgbr * texture4D(inscatterTexture, r0, mu0, muS0, nu), 0.0); + // avoids imprecision problems near horizon by interpolating between two points above and below horizon + const float EPS = 0.02; + float muHoriz = -sqrt(1.0 - (Rg / r) * (Rg / r)); + if (abs(mu - muHoriz) < EPS) { + float a = ((mu - muHoriz) + EPS) / (2.0 * EPS); + + mu = muHoriz - EPS; + r0 = sqrt(r * r + t * t + 2.0 * r * t * mu); + mu0 = (r * mu + t) / r0; + vec4 inScatter0 = texture4D(inscatterTexture, r, mu, muS, nu); + vec4 inScatter1 = texture4D(inscatterTexture, r0, mu0, muS0, nu); + vec4 inScatterA = max(inScatter0 - attenuation.rgbr * inScatter1, 0.0); + + mu = muHoriz + EPS; + r0 = sqrt(r * r + t * t + 2.0 * r * t * mu); + mu0 = (r * mu + t) / r0; + inScatter0 = texture4D(inscatterTexture, r, mu, muS, nu); + inScatter1 = texture4D(inscatterTexture, r0, mu0, muS0, nu); + vec4 inScatterB = max(inScatter0 - attenuation.rgbr * inScatter1, 0.0); + + inscatter = mix(inScatterA, inScatterB, a); + } + } + } + // avoids imprecision problems in Mie scattering when sun is below horizon + inscatter.w *= smoothstep(0.00, 0.02, muS); + result = max(inscatter.rgb * phaseR + getMie(inscatter) * phaseM, 0.0); + } else { // x in space and ray looking in space + result = vec3(0.0); + } + return result * ISun; +} + +float _uncharted2Tonemap(float x) +{ + float A = 0.15; + float B = 0.50; + float C = 0.10; + float D = 0.20; + float E = 0.02; + float F = 0.30; + + return ((x * (A * x + C * B) + D * E) / (x * (A * x + B) + D * F)) - E / F; +} + +vec4 _toneMappingUncharted(vec4 color, float exposure) +{ + float W = 11.2; + float white_scale = 1.0 / _uncharted2Tonemap(W); + vec4 result; + + result.r = pow(_uncharted2Tonemap(color.r * exposure) * white_scale, 1.0 / 2.2); + result.g = pow(_uncharted2Tonemap(color.g * exposure) * white_scale, 1.0 / 2.2); + result.b = pow(_uncharted2Tonemap(color.b * exposure) * white_scale, 1.0 / 2.2); + result.a = 1.0; + + return result; +} + +void main(void) +{ + float yoffset = GROUND_OFFSET - waterHeight; + float cameray = max(cameraLocation[1] + yoffset, 0.0); + vec3 x = vec3(0.0, Rg + cameray * WORLD_SCALING, 0.0); + vec3 v = normalize(unprojected - cameraLocation); + vec3 s = normalize(sunDirection * SUN_DISTANCE_SCALED - x); + + float r = length(x); + float mu = dot(x, v) / r; + float t = -r * mu - sqrt(r * r * (mu * mu - 1.0) + Rg * Rg); + + vec4 sunTransmittance = _sunTransmittance(v, s, r, mu, sunRadius); + vec3 attenuation; + vec3 inscattering = _getInscatterColor(x, t, v, s, r, mu, attenuation); + + gl_FragColor = _toneMappingUncharted(sunTransmittance + vec4(inscattering, 0.0), 2.0); +} diff --git a/src/render/opengl/shaders/skybox.vert b/src/render/opengl/shaders/skybox.vert new file mode 100644 index 0000000..ff142a5 --- /dev/null +++ b/src/render/opengl/shaders/skybox.vert @@ -0,0 +1,10 @@ +attribute highp vec4 vertex; +uniform highp mat4 viewMatrix; +uniform vec3 cameraLocation; +varying vec3 unprojected; + +void main(void) +{ + unprojected = cameraLocation + vertex.xyz * 500.0; + gl_Position = viewMatrix * vec4(unprojected, 1.0); +} diff --git a/src/render/software/AtmosphereModelBruneton.cpp b/src/render/software/AtmosphereModelBruneton.cpp index 9eb28c9..a723a4d 100644 --- a/src/render/software/AtmosphereModelBruneton.cpp +++ b/src/render/software/AtmosphereModelBruneton.cpp @@ -1268,3 +1268,18 @@ void AtmosphereModelBruneton::fillLightingStatus(LightStatus *status, const Vect status->pushComponent(irradiance); } + +Texture2D *AtmosphereModelBruneton::getTextureTransmittance() const +{ + return _transmittanceTexture; +} + +Texture2D *AtmosphereModelBruneton::getTextureIrradiance() const +{ + return _irradianceTexture; +} + +Texture4D *AtmosphereModelBruneton::getTextureInscatter() const +{ + return _inscatterTexture; +} diff --git a/src/render/software/AtmosphereModelBruneton.h b/src/render/software/AtmosphereModelBruneton.h index 71d768c..7d0aa8b 100644 --- a/src/render/software/AtmosphereModelBruneton.h +++ b/src/render/software/AtmosphereModelBruneton.h @@ -17,6 +17,11 @@ public: AtmosphereResult applyAerialPerspective(Vector3 location, const Color &base); void fillLightingStatus(LightStatus *status, const Vector3 &normal, int opaque); + /* Functions to get access to internal textures (for opengl shaders) */ + Texture2D* getTextureTransmittance() const; + Texture2D* getTextureIrradiance() const; + Texture4D* getTextureInscatter() const; + private: SoftwareRenderer* parent; }; diff --git a/src/render/software/AtmosphereRenderer.h b/src/render/software/AtmosphereRenderer.h index fe05468..bdda48f 100644 --- a/src/render/software/AtmosphereRenderer.h +++ b/src/render/software/AtmosphereRenderer.h @@ -39,6 +39,8 @@ public: virtual AtmosphereResult applyAerialPerspective(Vector3 location, Color base) override; virtual AtmosphereResult getSkyColor(Vector3 direction) override; + inline const AtmosphereModelBruneton* getModel() const {return model;} + private: AtmosphereModelBruneton* model; }; From 65e5a194bae2a5dbbf08e69a9d19b4e9a61113db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Lemaire?= Date: Sun, 22 Dec 2013 00:10:18 +0100 Subject: [PATCH 02/17] Use QOpenGLFunctions for gl* calls (except legacy code) --- src/render/opengl/OpenGLRenderer.cpp | 50 +++++++++---------- src/render/opengl/OpenGLRenderer.h | 6 +-- src/render/opengl/OpenGLShaderProgram.cpp | 58 +++++++++++------------ src/render/opengl/OpenGLShaderProgram.h | 6 +-- src/render/opengl/WidgetExplorer.cpp | 5 ++ 5 files changed, 62 insertions(+), 63 deletions(-) diff --git a/src/render/opengl/OpenGLRenderer.cpp b/src/render/opengl/OpenGLRenderer.cpp index 0106179..8bb5254 100644 --- a/src/render/opengl/OpenGLRenderer.cpp +++ b/src/render/opengl/OpenGLRenderer.cpp @@ -1,6 +1,6 @@ #include "OpenGLRenderer.h" -#include +#include #include #include #include @@ -11,62 +11,56 @@ OpenGLRenderer::OpenGLRenderer(Scenery* scenery): SoftwareRenderer(scenery) { + functions = new QOpenGLFunctions_3_2_Core(); skybox = new OpenGLSkybox(this); } OpenGLRenderer::~OpenGLRenderer() { delete skybox; + delete functions; } void OpenGLRenderer::initialize() { - glClearColor(0.0, 0.0, 0.0, 0.0); + // TODO Check return value + functions->initializeOpenGLFunctions(); - glDisable(GL_LIGHTING); + functions->glClearColor(0.0, 0.0, 0.0, 0.0); - glFrontFace(GL_CCW); - glCullFace(GL_BACK); - glEnable(GL_CULL_FACE); + functions->glDisable(GL_LIGHTING); - glDepthFunc(GL_LESS); - glDepthMask(1); - glEnable(GL_DEPTH_TEST); + functions->glFrontFace(GL_CCW); + functions->glCullFace(GL_BACK); + functions->glEnable(GL_CULL_FACE); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glEnable(GL_LINE_SMOOTH); - glLineWidth(1.0); + functions->glDepthFunc(GL_LESS); + functions->glDepthMask(1); + functions->glEnable(GL_DEPTH_TEST); - glDisable(GL_FOG); + functions->glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + functions->glEnable(GL_LINE_SMOOTH); + functions->glLineWidth(1.0); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + functions->glDisable(GL_FOG); + + functions->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); prepare(); - functions = new QOpenGLFunctions(); - skybox->initialize(); skybox->updateScenery(); } void OpenGLRenderer::resize(int width, int height) { - CameraPerspective perspective; - - glViewport(0, 0, width, height); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - perspective = render_camera->getPerspective(); - gluPerspective(perspective.yfov * 180.0 / M_PI, perspective.xratio, perspective.znear, perspective.zfar); - - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + functions->glViewport(0, 0, width, height); } void OpenGLRenderer::paint() { - glClearColor(0.0, 0.0, 0.0, 0.0); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + functions->glClearColor(0.0, 0.0, 0.0, 0.0); + functions->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); skybox->render(); } diff --git a/src/render/opengl/OpenGLRenderer.h b/src/render/opengl/OpenGLRenderer.h index fc5786c..664dc9f 100644 --- a/src/render/opengl/OpenGLRenderer.h +++ b/src/render/opengl/OpenGLRenderer.h @@ -5,7 +5,7 @@ #include "SoftwareRenderer.h" -class QOpenGLFunctions; +class QOpenGLFunctions_3_2_Core; namespace paysages { namespace opengl { @@ -25,13 +25,13 @@ public: void cameraChangeEvent(CameraDefinition* camera); - inline QOpenGLFunctions* getOpenGlFunctions() {return functions;} + inline QOpenGLFunctions_3_2_Core* getOpenGlFunctions() {return functions;} virtual double getPrecision(const Vector3 &location) override; virtual Color applyMediumTraversal(Vector3 location, Color color) override; private: - QOpenGLFunctions* functions; + QOpenGLFunctions_3_2_Core* functions; OpenGLSkybox* skybox; }; diff --git a/src/render/opengl/OpenGLShaderProgram.cpp b/src/render/opengl/OpenGLShaderProgram.cpp index f9e11bb..3caece4 100644 --- a/src/render/opengl/OpenGLShaderProgram.cpp +++ b/src/render/opengl/OpenGLShaderProgram.cpp @@ -1,14 +1,14 @@ #include "OpenGLShaderProgram.h" #include -#include +#include #include #include "Texture2D.h" #include "Texture3D.h" #include "Texture4D.h" #include "Color.h" -OpenGLShaderProgram::OpenGLShaderProgram(QString name, QOpenGLFunctions* functions): +OpenGLShaderProgram::OpenGLShaderProgram(QString name, QOpenGLFunctions_3_2_Core* functions): name(name), functions(functions) { program = new QOpenGLShaderProgram(); @@ -68,15 +68,15 @@ void OpenGLShaderProgram::addTexture(QString sampler_name, Texture2D* texture) } else { - glGenTextures(1, &texid); + functions->glGenTextures(1, &texid); textures[sampler_name] = QPair(GL_TEXTURE_2D, texid); } - glBindTexture(GL_TEXTURE_2D, texid); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + functions->glBindTexture(GL_TEXTURE_2D, texid); + functions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + functions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + functions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + functions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); int sx, sy; texture->getSize(&sx, &sy); @@ -94,7 +94,7 @@ void OpenGLShaderProgram::addTexture(QString sampler_name, Texture2D* texture) } } - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, sx, sy, 0, GL_RGBA, GL_FLOAT, pixels); + functions->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, sx, sy, 0, GL_RGBA, GL_FLOAT, pixels); delete[] pixels; } @@ -108,16 +108,16 @@ void OpenGLShaderProgram::addTexture(QString sampler_name, Texture3D* texture) } else { - glGenTextures(1, &texid); + functions->glGenTextures(1, &texid); textures[sampler_name] = QPair(GL_TEXTURE_3D, texid); } - glBindTexture(GL_TEXTURE_3D, texid); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + functions->glBindTexture(GL_TEXTURE_3D, texid); + functions->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + functions->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + functions->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + functions->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + functions->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); int sx, sy, sz; texture->getSize(&sx, &sy, &sz); @@ -138,7 +138,7 @@ void OpenGLShaderProgram::addTexture(QString sampler_name, Texture3D* texture) } } - glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, sx, sy, sz, 0, GL_RGBA, GL_FLOAT, pixels); + functions->glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, sx, sy, sz, 0, GL_RGBA, GL_FLOAT, pixels); delete[] pixels; } @@ -152,16 +152,16 @@ void OpenGLShaderProgram::addTexture(QString sampler_name, Texture4D* texture) } else { - glGenTextures(1, &texid); + functions->glGenTextures(1, &texid); textures[sampler_name] = QPair(GL_TEXTURE_3D, texid); } - glBindTexture(GL_TEXTURE_3D, texid); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + functions->glBindTexture(GL_TEXTURE_3D, texid); + functions->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + functions->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + functions->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + functions->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + functions->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); int sx, sy, sz, sw; texture->getSize(&sx, &sy, &sz, &sw); @@ -185,7 +185,7 @@ void OpenGLShaderProgram::addTexture(QString sampler_name, Texture4D* texture) } } - glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, sx, sy, sz * sw, 0, GL_RGBA, GL_FLOAT, pixels); + functions->glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, sx, sy, sz * sw, 0, GL_RGBA, GL_FLOAT, pixels); delete[] pixels; } @@ -233,8 +233,8 @@ void OpenGLShaderProgram::bind() int textureSampler = program->uniformLocation(iter.key()); if (textureSampler >= 0) { - glActiveTexture(GL_TEXTURE0 + i); - glBindTexture(iter.value().first, iter.value().second); + functions->glActiveTexture(GL_TEXTURE0 + i); + functions->glBindTexture(iter.value().first, iter.value().second); program->setUniformValue(textureSampler, i); i++; } @@ -254,7 +254,7 @@ void OpenGLShaderProgram::drawTriangles(float* vertices, int triangle_count) program->setAttributeArray(vertex, GL_FLOAT, vertices, 3); program->enableAttributeArray(vertex); - glDrawArrays(GL_TRIANGLES, 0, triangle_count * 3); + functions->glDrawArrays(GL_TRIANGLES, 0, triangle_count * 3); program->disableAttributeArray(vertex); @@ -269,7 +269,7 @@ void OpenGLShaderProgram::drawTriangleStrip(float* vertices, int vertex_count) program->setAttributeArray(vertex, GL_FLOAT, vertices, 3); program->enableAttributeArray(vertex); - glDrawArrays(GL_TRIANGLE_STRIP, 0, vertex_count); + functions->glDrawArrays(GL_TRIANGLE_STRIP, 0, vertex_count); program->disableAttributeArray(vertex); diff --git a/src/render/opengl/OpenGLShaderProgram.h b/src/render/opengl/OpenGLShaderProgram.h index aa8e30a..773a1e4 100644 --- a/src/render/opengl/OpenGLShaderProgram.h +++ b/src/render/opengl/OpenGLShaderProgram.h @@ -10,7 +10,7 @@ #include class QOpenGLShaderProgram; -class QOpenGLFunctions; +class QOpenGLFunctions_3_2_Core; namespace paysages { namespace opengl { @@ -18,7 +18,7 @@ namespace opengl { class OPENGLSHARED_EXPORT OpenGLShaderProgram { public: - OpenGLShaderProgram(QString name, QOpenGLFunctions* functions); + OpenGLShaderProgram(QString name, QOpenGLFunctions_3_2_Core* functions); ~OpenGLShaderProgram(); void addVertexSource(QString path); @@ -50,7 +50,7 @@ private: QString name; QOpenGLShaderProgram* program; - QOpenGLFunctions* functions; + QOpenGLFunctions_3_2_Core* functions; QMap > textures; }; diff --git a/src/render/opengl/WidgetExplorer.cpp b/src/render/opengl/WidgetExplorer.cpp index b31d0ce..f0f8890 100644 --- a/src/render/opengl/WidgetExplorer.cpp +++ b/src/render/opengl/WidgetExplorer.cpp @@ -353,6 +353,11 @@ void WidgetExplorer::resizeGL(int w, int h) { _current_camera->setRenderSize(w, h); _renderer->resize(w, h); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + CameraPerspective perspective = _current_camera->getPerspective(); + gluPerspective(perspective.yfov * 180.0 / M_PI, perspective.xratio, perspective.znear, perspective.zfar); } void WidgetExplorer::paintGL() From 3696adc90b92f2cbf3ac526cdf799f78d4d4042a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Lemaire?= Date: Sun, 22 Dec 2013 00:41:19 +0100 Subject: [PATCH 03/17] Use opengl shaders for water rendering --- src/render/opengl/OpenGLRenderer.cpp | 12 ++++--- src/render/opengl/OpenGLRenderer.h | 1 + src/render/opengl/OpenGLWater.cpp | 42 +++++++++++++++++++++++++ src/render/opengl/OpenGLWater.h | 31 ++++++++++++++++++ src/render/opengl/WidgetExplorer.cpp | 12 ------- src/render/opengl/opengl.pro | 11 +++++-- src/render/opengl/opengl_global.h | 1 + src/render/opengl/shaders/resources.qrc | 2 ++ src/render/opengl/shaders/water.frag | 6 ++++ src/render/opengl/shaders/water.vert | 11 +++++++ 10 files changed, 110 insertions(+), 19 deletions(-) create mode 100644 src/render/opengl/OpenGLWater.cpp create mode 100644 src/render/opengl/OpenGLWater.h create mode 100644 src/render/opengl/shaders/water.frag create mode 100644 src/render/opengl/shaders/water.vert diff --git a/src/render/opengl/OpenGLRenderer.cpp b/src/render/opengl/OpenGLRenderer.cpp index 8bb5254..65a6b5b 100644 --- a/src/render/opengl/OpenGLRenderer.cpp +++ b/src/render/opengl/OpenGLRenderer.cpp @@ -1,23 +1,22 @@ #include "OpenGLRenderer.h" #include -#include -#include -#include -#include "Scenery.h" #include "CameraDefinition.h" #include "OpenGLSkybox.h" +#include "OpenGLWater.h" OpenGLRenderer::OpenGLRenderer(Scenery* scenery): SoftwareRenderer(scenery) { functions = new QOpenGLFunctions_3_2_Core(); skybox = new OpenGLSkybox(this); + water = new OpenGLWater(this); } OpenGLRenderer::~OpenGLRenderer() { delete skybox; + delete water; delete functions; } @@ -50,6 +49,9 @@ void OpenGLRenderer::initialize() skybox->initialize(); skybox->updateScenery(); + + water->initialize(); + water->updateScenery(); } void OpenGLRenderer::resize(int width, int height) @@ -63,11 +65,13 @@ void OpenGLRenderer::paint() functions->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); skybox->render(); + water->render(); } void OpenGLRenderer::cameraChangeEvent(CameraDefinition *camera) { skybox->updateCamera(camera); + water->updateCamera(camera); } double OpenGLRenderer::getPrecision(const Vector3 &) diff --git a/src/render/opengl/OpenGLRenderer.h b/src/render/opengl/OpenGLRenderer.h index 664dc9f..1021f4c 100644 --- a/src/render/opengl/OpenGLRenderer.h +++ b/src/render/opengl/OpenGLRenderer.h @@ -34,6 +34,7 @@ private: QOpenGLFunctions_3_2_Core* functions; OpenGLSkybox* skybox; + OpenGLWater* water; }; } diff --git a/src/render/opengl/OpenGLWater.cpp b/src/render/opengl/OpenGLWater.cpp new file mode 100644 index 0000000..bebef71 --- /dev/null +++ b/src/render/opengl/OpenGLWater.cpp @@ -0,0 +1,42 @@ +#include "OpenGLWater.h" + +#include "OpenGLShaderProgram.h" + +OpenGLWater::OpenGLWater(OpenGLRenderer *renderer): + OpenGLPart(renderer) +{ + vertices = new float[4 * 3]; +} + +OpenGLWater::~OpenGLWater() +{ + delete[] vertices; +} + +void OpenGLWater::initialize() +{ + program = createShader("water"); + program->addVertexSource("water"); + program->addFragmentSource("water"); + + setVertex(0, -1.0f, 0.0f, -1.0f); + setVertex(1, -1.0f, 0.0f, 1.0f); + setVertex(2, 1.0f, 0.0f, -1.0f); + setVertex(3, 1.0f, 0.0f, 1.0f); +} + +void OpenGLWater::update() +{ +} + +void OpenGLWater::render() +{ + program->drawTriangleStrip(vertices, 4); +} + +void OpenGLWater::setVertex(int i, float x, float y, float z) +{ + vertices[i * 3] = x; + vertices[i * 3 + 1] = y; + vertices[i * 3 + 2] = z; +} diff --git a/src/render/opengl/OpenGLWater.h b/src/render/opengl/OpenGLWater.h new file mode 100644 index 0000000..a30d4bc --- /dev/null +++ b/src/render/opengl/OpenGLWater.h @@ -0,0 +1,31 @@ +#ifndef OPENGLWATER_H +#define OPENGLWATER_H + +#include "opengl_global.h" + +#include "OpenGLPart.h" + +namespace paysages { +namespace opengl { + +class OPENGLSHARED_EXPORT OpenGLWater: public OpenGLPart +{ +public: + OpenGLWater(OpenGLRenderer* renderer); + virtual ~OpenGLWater(); + + virtual void initialize() override; + virtual void update() override; + virtual void render() override; + +private: + void setVertex(int i, float x, float y, float z); + + OpenGLShaderProgram* program; + float* vertices; +}; + +} +} + +#endif // OPENGLWATER_H diff --git a/src/render/opengl/WidgetExplorer.cpp b/src/render/opengl/WidgetExplorer.cpp index f0f8890..b1e00b0 100644 --- a/src/render/opengl/WidgetExplorer.cpp +++ b/src/render/opengl/WidgetExplorer.cpp @@ -365,7 +365,6 @@ void WidgetExplorer::paintGL() GLenum error_code; QTime start_time; double frame_time; - WaterDefinition* water = _renderer->getScenery()->getWater(); // Don't do this at each frame, only on camera change _renderer->getScenery()->setCamera(_current_camera); @@ -384,17 +383,6 @@ void WidgetExplorer::paintGL() Vector3 camera_up = _current_camera->getUpVector(); gluLookAt(camera_location.x, camera_location.y, camera_location.z, camera_target.x, camera_target.y, camera_target.z, camera_up.x, camera_up.y, camera_up.z); - // Render water - double water_height = _renderer->getTerrainRenderer()->getWaterHeight(); - glDisable(GL_TEXTURE_2D); - glColor3f(water->material->_rgb.r, water->material->_rgb.g, water->material->_rgb.b); - glBegin(GL_QUADS); - glVertex3f(camera_location.x - 500.0, water_height, camera_location.z - 500.0); - glVertex3f(camera_location.x - 500.0, water_height, camera_location.z + 500.0); - glVertex3f(camera_location.x + 500.0, water_height, camera_location.z + 500.0); - glVertex3f(camera_location.x + 500.0, water_height, camera_location.z - 500.0); - glEnd(); - // Render chunks glEnable(GL_TEXTURE_2D); for (int i = 0; i < _chunks.count(); i++) diff --git a/src/render/opengl/opengl.pro b/src/render/opengl/opengl.pro index 5e47964..fe2ea41 100644 --- a/src/render/opengl/opengl.pro +++ b/src/render/opengl/opengl.pro @@ -20,7 +20,8 @@ SOURCES += \ WidgetExplorer.cpp \ OpenGLShaderProgram.cpp \ OpenGLPart.cpp \ - OpenGLSkybox.cpp + OpenGLSkybox.cpp \ + OpenGLWater.cpp HEADERS +=\ opengl_global.h \ @@ -30,7 +31,8 @@ HEADERS +=\ WidgetExplorer.h \ OpenGLShaderProgram.h \ OpenGLPart.h \ - OpenGLSkybox.h + OpenGLSkybox.h \ + OpenGLWater.h unix:!symbian { maemo5 { @@ -70,4 +72,7 @@ RESOURCES += \ OTHER_FILES += \ shaders/skybox.frag \ - shaders/skybox.vert + shaders/skybox.vert \ + shaders/water.vert \ + shaders/water.frag \ + shaders/bruneton.frag diff --git a/src/render/opengl/opengl_global.h b/src/render/opengl/opengl_global.h index 63b65f6..b949e60 100644 --- a/src/render/opengl/opengl_global.h +++ b/src/render/opengl/opengl_global.h @@ -18,6 +18,7 @@ namespace opengl { class BaseExplorerChunk; class OpenGLShaderProgram; class OpenGLSkybox; + class OpenGLWater; } } using namespace paysages::opengl; diff --git a/src/render/opengl/shaders/resources.qrc b/src/render/opengl/shaders/resources.qrc index a922c12..5d1b756 100644 --- a/src/render/opengl/shaders/resources.qrc +++ b/src/render/opengl/shaders/resources.qrc @@ -2,5 +2,7 @@ skybox.frag skybox.vert + water.frag + water.vert diff --git a/src/render/opengl/shaders/water.frag b/src/render/opengl/shaders/water.frag new file mode 100644 index 0000000..e6c4b07 --- /dev/null +++ b/src/render/opengl/shaders/water.frag @@ -0,0 +1,6 @@ +varying vec3 unprojected; + +void main(void) +{ + gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0); +} diff --git a/src/render/opengl/shaders/water.vert b/src/render/opengl/shaders/water.vert new file mode 100644 index 0000000..485fe10 --- /dev/null +++ b/src/render/opengl/shaders/water.vert @@ -0,0 +1,11 @@ +attribute highp vec4 vertex; +uniform highp mat4 viewMatrix; +uniform float waterHeight; +uniform vec3 cameraLocation; +varying vec3 unprojected; + +void main(void) +{ + unprojected = vec3(cameraLocation.x + vertex.x * 500.0, vertex.y + waterHeight, cameraLocation.z + vertex.z * 500.0); + gl_Position = viewMatrix * vec4(unprojected, 1.0); +} From 994dcb5f44018cd52fdabce09d2383dc2d5a8b57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Lemaire?= Date: Sun, 22 Dec 2013 01:17:57 +0100 Subject: [PATCH 04/17] Add aerial perspective to water shader --- src/render/opengl/shaders/skybox.frag | 7 +- src/render/opengl/shaders/water.frag | 236 ++++++++++++++++++++++++++ 2 files changed, 240 insertions(+), 3 deletions(-) diff --git a/src/render/opengl/shaders/skybox.frag b/src/render/opengl/shaders/skybox.frag index 3ffa70e..6ab26cc 100644 --- a/src/render/opengl/shaders/skybox.frag +++ b/src/render/opengl/shaders/skybox.frag @@ -216,9 +216,10 @@ vec4 _toneMappingUncharted(vec4 color, float exposure) void main(void) { float yoffset = GROUND_OFFSET - waterHeight; - float cameray = max(cameraLocation[1] + yoffset, 0.0); - vec3 x = vec3(0.0, Rg + cameray * WORLD_SCALING, 0.0); - vec3 v = normalize(unprojected - cameraLocation); + vec3 camera = vec3(cameraLocation.x, max(cameraLocation.y + yoffset, 0.0), cameraLocation.z); + vec3 location = vec3(unprojected.x, max(unprojected.y + yoffset, 0.0), unprojected.z); + vec3 x = vec3(0.0, Rg + camera.y * WORLD_SCALING, 0.0); + vec3 v = normalize(location - camera); vec3 s = normalize(sunDirection * SUN_DISTANCE_SCALED - x); float r = length(x); diff --git a/src/render/opengl/shaders/water.frag b/src/render/opengl/shaders/water.frag index e6c4b07..61982e4 100644 --- a/src/render/opengl/shaders/water.frag +++ b/src/render/opengl/shaders/water.frag @@ -1,6 +1,242 @@ +const float GROUND_OFFSET = 0.5; +const float Rg = 6360.0; +const float Rt = 6420.0; +const float RL = 6421.0; +const float exposure = 0.4; +const float ISun = 100.0; +const float AVERAGE_GROUND_REFLECTANCE = 0.1; +const float HR = 8.0; +const vec3 betaR = vec3(5.8e-3, 1.35e-2, 3.31e-2); +const float HM = 1.2; +const vec3 betaMSca = vec3(4e-3); +const vec3 betaMEx = vec3(4e-3 / 0.9); +const float mieG = 0.8; +const float SPHERE_SIZE = 20000.0; +const float WORLD_SCALING = 0.05; +const float SUN_DISTANCE = 149597870.0; +const float SUN_DISTANCE_SCALED = (SUN_DISTANCE / WORLD_SCALING); +const float SUN_RADIUS = 6.955e5; +const float SUN_RADIUS_SCALED = (SUN_RADIUS / WORLD_SCALING); +const float M_PI = 3.141592657; + +const int RES_MU = 128; +const int RES_MU_S = 32; +const int RES_R = 32; +const int RES_NU = 8; + +uniform float waterHeight; +uniform vec3 cameraLocation; +uniform vec3 sunDirection; +uniform vec4 sunColor; +const float sunRadius = 1.0; // TODO -> uniform + varying vec3 unprojected; +uniform sampler2D transmittanceTexture; +uniform sampler3D inscatterTexture; + +vec4 texture4D(sampler3D tex, float r, float mu, float muS, float nu) +{ + if (r < Rg + 0.00000001) r = Rg + 0.00000001; + float H = sqrt(Rt * Rt - Rg * Rg); + float rho = sqrt(r * r - Rg * Rg); + float rmu = r * mu; + float delta = rmu * rmu - r * r + Rg * Rg; + vec4 cst = (rmu < 0.0 && delta > 0.0) ? vec4(1.0, 0.0, 0.0, 0.5 - 0.5 / float(RES_MU)) : vec4(-1.0, H * H, H, 0.5 + 0.5 / float(RES_MU)); + float uR = 0.5 / float(RES_R) + rho / H * (1.0 - 1.0 / float(RES_R)); + float uMu = cst.a + (rmu * cst.r + sqrt(delta + cst.g)) / (rho + cst.b) * (0.5 - 1.0 / float(RES_MU)); + float uMuS = 0.5 / float(RES_MU_S) + (atan(max(muS, -0.1975) * tan(1.26 * 1.1)) / 1.1 + (1.0 - 0.26)) * 0.5 * (1.0 - 1.0 / float(RES_MU_S)); + + float sr = 1.0 / float(RES_R); + int br = int(floor(uR / sr)); + vec4 r1 = texture3D(tex, vec3(uMu, uMuS, float(br) * sr + nu * sr)); + vec4 r2 = texture3D(tex, vec3(uMu, uMuS, float(br + 1) * sr + nu * sr)); + return mix(r1, r2, (uR - float(br) * sr) / sr); +} + +float _limit(float r, float mu) +{ + float dout = -r * mu + sqrt(r * r * (mu * mu - 1.0) + RL * RL); + float delta2 = r * r * (mu * mu - 1.0) + Rg * Rg; + if (delta2 >= 0.0) + { + float din = -r * mu - sqrt(delta2); + if (din >= 0.0) { + dout = min(dout, din); + } + } + return dout; +} + +vec2 _getTransmittanceUV(float r, float mu) +{ + if (r < Rg + 0.00000001) r = Rg + 0.00000001; + float dr = (r - Rg) / (Rt - Rg); + return vec2(atan((mu + 0.15) / (1.0 + 0.15) * tan(1.5)) / 1.5, sqrt(dr)); +} + +vec4 _transmittance(float r, float mu) +{ + vec2 uv = _getTransmittanceUV(r, mu); + return texture2D(transmittanceTexture, uv); +} + +vec4 _transmittanceWithShadow(float r, float mu) +{ + return mu < -sqrt(1.0 - (Rg / r) * (Rg / r)) ? vec4(0.0) : _transmittance(r, mu); +} + +vec4 _sunTransmittance(vec3 v, vec3 s, float r, float mu, float radius) +{ + vec4 transmittance = r <= Rt ? _transmittanceWithShadow(r, mu) : vec4(1.0); /* T(x,xo) */ + float d = _limit(r, mu); + radius *= (1.0 + 10.0 * d / Rt); /* Inflating due to lens effect near horizon */ + float isun = step(cos(radius * M_PI / 180.0), dot(v, s)) * ISun; /* Lsun */ + transmittance.r *= isun; + transmittance.g *= isun; + transmittance.b *= isun; + transmittance.a = 1.0; + return transmittance; /* Eq (9) */ +} + +float phaseFunctionR(float mu) { + return (3.0 / (16.0 * M_PI)) * (1.0 + mu * mu); +} + +float phaseFunctionM(float mu) { + return 1.5 * 1.0 / (4.0 * M_PI) * (1.0 - mieG*mieG) * pow(1.0 + (mieG*mieG) - 2.0*mieG*mu, -3.0/2.0) * (1.0 + mu * mu) / (2.0 + mieG*mieG); +} + +float opticalDepth(float H, float r, float mu, float d) { + float a = sqrt((0.5/H)*r); + vec2 a01 = a*vec2(mu, mu + d / r); + vec2 a01s = sign(a01); + vec2 a01sq = a01*a01; + float x = a01s.y > a01s.x ? exp(a01sq.x) : 0.0; + vec2 y = a01s / (2.3193*abs(a01) + sqrt(1.52*a01sq + 4.0)) * vec2(1.0, exp(-d/H*(d/(2.0*r)+mu))); + return sqrt((6.2831*H)*r) * exp((Rg-r)/H) * (x + dot(y, vec2(1.0, -1.0))); +} + +vec3 analyticTransmittance(float r, float mu, float d) { + return exp(- betaR * opticalDepth(HR, r, mu, d) - betaMEx * opticalDepth(HM, r, mu, d)); +} + +vec3 getMie(vec4 rayMie) { // rayMie.rgb=C*, rayMie.w=Cm,r + return rayMie.rgb * rayMie.w / max(rayMie.r, 1e-4) * (betaR.r / betaR); +} + +vec3 _getInscatterColor(inout vec3 x, inout float t, vec3 v, vec3 s, out float r, out float mu, out vec3 attenuation) { + vec3 result; + r = length(x); + mu = dot(x, v) / r; + float d = -r * mu - sqrt(r * r * (mu * mu - 1.0) + Rt * Rt); + if (d > 0.0) { // if x in space and ray intersects atmosphere + // move x to nearest intersection of ray with top atmosphere boundary + x += d * v; + t -= d; + mu = (r * mu + d) / Rt; + r = Rt; + } + if (r <= Rt) { // if ray intersects atmosphere + float nu = dot(v, s); + float muS = dot(x, s) / r; + float phaseR = phaseFunctionR(nu); + float phaseM = phaseFunctionM(nu); + vec4 inscatter = max(texture4D(inscatterTexture, r, mu, muS, nu), 0.0); + if (t > 0.0) { + vec3 x0 = x + t * v; + float r0 = length(x0); + float rMu0 = dot(x0, v); + float mu0 = rMu0 / r0; + float muS0 = dot(x0, s) / r0; + // avoids imprecision problems in transmittance computations based on textures + attenuation = analyticTransmittance(r, mu, t); + if (r0 > Rg + 0.001) { + // computes S[L]-T(x,x0)S[L]|x0 + inscatter = max(inscatter - attenuation.rgbr * texture4D(inscatterTexture, r0, mu0, muS0, nu), 0.0); + // avoids imprecision problems near horizon by interpolating between two points above and below horizon + const float EPS = 0.02; + float muHoriz = -sqrt(1.0 - (Rg / r) * (Rg / r)); + if (abs(mu - muHoriz) < EPS) { + float a = ((mu - muHoriz) + EPS) / (2.0 * EPS); + + mu = muHoriz - EPS; + r0 = sqrt(r * r + t * t + 2.0 * r * t * mu); + mu0 = (r * mu + t) / r0; + vec4 inScatter0 = texture4D(inscatterTexture, r, mu, muS, nu); + vec4 inScatter1 = texture4D(inscatterTexture, r0, mu0, muS0, nu); + vec4 inScatterA = max(inScatter0 - attenuation.rgbr * inScatter1, 0.0); + + mu = muHoriz + EPS; + r0 = sqrt(r * r + t * t + 2.0 * r * t * mu); + mu0 = (r * mu + t) / r0; + inScatter0 = texture4D(inscatterTexture, r, mu, muS, nu); + inScatter1 = texture4D(inscatterTexture, r0, mu0, muS0, nu); + vec4 inScatterB = max(inScatter0 - attenuation.rgbr * inScatter1, 0.0); + + inscatter = mix(inScatterA, inScatterB, a); + } + } + } + // avoids imprecision problems in Mie scattering when sun is below horizon + inscatter.w *= smoothstep(0.00, 0.02, muS); + result = max(inscatter.rgb * phaseR + getMie(inscatter) * phaseM, 0.0); + } else { // x in space and ray looking in space + result = vec3(0.0); + } + return result * ISun; +} + +float _uncharted2Tonemap(float x) +{ + float A = 0.15; + float B = 0.50; + float C = 0.10; + float D = 0.20; + float E = 0.02; + float F = 0.30; + + return ((x * (A * x + C * B) + D * E) / (x * (A * x + B) + D * F)) - E / F; +} + +vec4 _toneMappingUncharted(vec4 color, float exposure) +{ + float W = 11.2; + float white_scale = 1.0 / _uncharted2Tonemap(W); + vec4 result; + + result.r = pow(_uncharted2Tonemap(color.r * exposure) * white_scale, 1.0 / 2.2); + result.g = pow(_uncharted2Tonemap(color.g * exposure) * white_scale, 1.0 / 2.2); + result.b = pow(_uncharted2Tonemap(color.b * exposure) * white_scale, 1.0 / 2.2); + result.a = 1.0; + + return result; +} + void main(void) { gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0); + + float yoffset = GROUND_OFFSET - waterHeight; + vec3 camera = vec3(cameraLocation.x, max(cameraLocation.y + yoffset, 0.0), cameraLocation.z); + vec3 location = vec3(unprojected.x, max(unprojected.y + yoffset, 0.0), unprojected.z); + vec3 x = vec3(0.0, Rg + camera.y * WORLD_SCALING, 0.0); + vec3 v = normalize(location - camera); + vec3 s = normalize(sunDirection * SUN_DISTANCE_SCALED - x); + + if (v.y == 0.0) + { + v.y = -0.000001; + } + + float r = length(x); + float mu = dot(x, v) / r; + float t = length(location - camera) * WORLD_SCALING; + + vec3 attenuation; + vec3 inscattering = _getInscatterColor(x, t, v, s, r, mu, attenuation); + + gl_FragColor = gl_FragColor * vec4(attenuation, 0.0) + vec4(inscattering, 0.0); + + gl_FragColor = _toneMappingUncharted(gl_FragColor, 2.0); } From 666420bbb2f74b4d1625e63ae58deaf78b9d8ffb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Lemaire?= Date: Sun, 22 Dec 2013 15:04:33 +0100 Subject: [PATCH 05/17] New OpenGLSharedState class to manage shader variables --- src/render/opengl/OpenGLPart.cpp | 22 +-------- src/render/opengl/OpenGLRenderer.cpp | 5 ++ src/render/opengl/OpenGLRenderer.h | 4 +- src/render/opengl/OpenGLShaderProgram.cpp | 38 +++------------ src/render/opengl/OpenGLShaderProgram.h | 15 +++--- src/render/opengl/OpenGLSharedState.cpp | 23 +++++++++ src/render/opengl/OpenGLSharedState.h | 46 ++++++++++++++++++ src/render/opengl/OpenGLSkybox.cpp | 8 +++- src/render/opengl/OpenGLVariable.cpp | 57 +++++++++++++++++++++++ src/render/opengl/OpenGLVariable.h | 54 +++++++++++++++++++++ src/render/opengl/OpenGLWater.cpp | 5 ++ src/render/opengl/opengl.pro | 8 +++- src/render/opengl/opengl_global.h | 2 + src/system/Logs.cpp | 1 + src/system/Logs.h | 9 ++++ src/system/system.pro | 6 ++- 16 files changed, 237 insertions(+), 66 deletions(-) create mode 100644 src/render/opengl/OpenGLSharedState.cpp create mode 100644 src/render/opengl/OpenGLSharedState.h create mode 100644 src/render/opengl/OpenGLVariable.cpp create mode 100644 src/render/opengl/OpenGLVariable.h create mode 100644 src/system/Logs.cpp create mode 100644 src/system/Logs.h diff --git a/src/render/opengl/OpenGLPart.cpp b/src/render/opengl/OpenGLPart.cpp index c2d6d98..4c184d6 100644 --- a/src/render/opengl/OpenGLPart.cpp +++ b/src/render/opengl/OpenGLPart.cpp @@ -7,7 +7,6 @@ #include "CameraDefinition.h" #include "AtmosphereDefinition.h" #include "AtmosphereRenderer.h" -#include "WaterRenderer.h" #include "Scenery.h" OpenGLPart::OpenGLPart(OpenGLRenderer* renderer): @@ -27,7 +26,7 @@ OpenGLPart::~OpenGLPart() OpenGLShaderProgram* OpenGLPart::createShader(QString name) { - OpenGLShaderProgram* program = new OpenGLShaderProgram(name, renderer->getOpenGlFunctions()); + OpenGLShaderProgram* program = new OpenGLShaderProgram(name, renderer); if (!shaders.contains(name)) { @@ -82,25 +81,6 @@ void OpenGLPart::updateCamera(CameraDefinition* camera) void OpenGLPart::updateScenery(bool onlyCommon) { - Scenery* scenery = renderer->getScenery(); - - // Collect common info - double water_height = renderer->getWaterRenderer()->getHeightInfo().max_height; - Vector3 orig_sun_direction = renderer->getAtmosphereRenderer()->getSunDirection(); - QVector3D sun_direction = QVector3D(orig_sun_direction.x, orig_sun_direction.y, orig_sun_direction.z); - Color orig_sun_color = scenery->getAtmosphere()->sun_color; - QColor sun_color = QColor(orig_sun_color.r, orig_sun_color.g, orig_sun_color.b); - - // Update shaders - QMapIterator i(shaders); - while (i.hasNext()) - { - i.next(); - - i.value()->updateWaterHeight(water_height); - i.value()->updateSun(sun_direction, sun_color); - } - // Let subclass do its own collecting if (not onlyCommon) { diff --git a/src/render/opengl/OpenGLRenderer.cpp b/src/render/opengl/OpenGLRenderer.cpp index 65a6b5b..1b326bf 100644 --- a/src/render/opengl/OpenGLRenderer.cpp +++ b/src/render/opengl/OpenGLRenderer.cpp @@ -2,6 +2,7 @@ #include #include "CameraDefinition.h" +#include "OpenGLSharedState.h" #include "OpenGLSkybox.h" #include "OpenGLWater.h" @@ -9,6 +10,8 @@ OpenGLRenderer::OpenGLRenderer(Scenery* scenery): SoftwareRenderer(scenery) { functions = new QOpenGLFunctions_3_2_Core(); + shared_state = new OpenGLSharedState(); + skybox = new OpenGLSkybox(this); water = new OpenGLWater(this); } @@ -17,7 +20,9 @@ OpenGLRenderer::~OpenGLRenderer() { delete skybox; delete water; + delete functions; + delete shared_state; } void OpenGLRenderer::initialize() diff --git a/src/render/opengl/OpenGLRenderer.h b/src/render/opengl/OpenGLRenderer.h index 1021f4c..2069ed1 100644 --- a/src/render/opengl/OpenGLRenderer.h +++ b/src/render/opengl/OpenGLRenderer.h @@ -25,13 +25,15 @@ public: void cameraChangeEvent(CameraDefinition* camera); - inline QOpenGLFunctions_3_2_Core* getOpenGlFunctions() {return functions;} + inline QOpenGLFunctions_3_2_Core* getOpenGlFunctions() const {return functions;} + inline OpenGLSharedState* getSharedState() const {return shared_state;} virtual double getPrecision(const Vector3 &location) override; virtual Color applyMediumTraversal(Vector3 location, Color color) override; private: QOpenGLFunctions_3_2_Core* functions; + OpenGLSharedState* shared_state; OpenGLSkybox* skybox; OpenGLWater* water; diff --git a/src/render/opengl/OpenGLShaderProgram.cpp b/src/render/opengl/OpenGLShaderProgram.cpp index 3caece4..cf34e66 100644 --- a/src/render/opengl/OpenGLShaderProgram.cpp +++ b/src/render/opengl/OpenGLShaderProgram.cpp @@ -3,15 +3,18 @@ #include #include #include +#include "OpenGLRenderer.h" +#include "OpenGLSharedState.h" #include "Texture2D.h" #include "Texture3D.h" #include "Texture4D.h" #include "Color.h" -OpenGLShaderProgram::OpenGLShaderProgram(QString name, QOpenGLFunctions_3_2_Core* functions): - name(name), functions(functions) +OpenGLShaderProgram::OpenGLShaderProgram(QString name, OpenGLRenderer* renderer): + renderer(renderer), name(name) { program = new QOpenGLShaderProgram(); + functions = renderer->getOpenGlFunctions(); } OpenGLShaderProgram::~OpenGLShaderProgram() @@ -47,17 +50,6 @@ void OpenGLShaderProgram::updateCamera(const QVector3D& location, const QMatrix4 this->view = view; } -void OpenGLShaderProgram::updateWaterHeight(double height) -{ - this->water_height = height; -} - -void OpenGLShaderProgram::updateSun(const QVector3D& direction, const QColor& color) -{ - this->sun_direction = direction; - this->sun_color = color; -} - void OpenGLShaderProgram::addTexture(QString sampler_name, Texture2D* texture) { GLuint texid; @@ -193,6 +185,8 @@ void OpenGLShaderProgram::bind() { program->bind(); + renderer->getSharedState()->apply(this); + // TODO Keep locations in cache int viewMatrix = program->uniformLocation("viewMatrix"); @@ -207,24 +201,6 @@ void OpenGLShaderProgram::bind() program->setUniformValue(cameraLocation, camera_location); } - int waterHeight = program->uniformLocation("waterHeight"); - if (waterHeight >= 0) - { - program->setUniformValue(waterHeight, water_height); - } - - int sunDirection = program->uniformLocation("sunDirection"); - if (sunDirection >= 0) - { - program->setUniformValue(sunDirection, sun_direction); - } - - int sunColor = program->uniformLocation("sunColor"); - if (sunColor >= 0) - { - program->setUniformValue(sunColor, sun_color); - } - QMapIterator > iter(textures); int i = 0; while (iter.hasNext()) diff --git a/src/render/opengl/OpenGLShaderProgram.h b/src/render/opengl/OpenGLShaderProgram.h index 773a1e4..7cf9e6b 100644 --- a/src/render/opengl/OpenGLShaderProgram.h +++ b/src/render/opengl/OpenGLShaderProgram.h @@ -18,7 +18,7 @@ namespace opengl { class OPENGLSHARED_EXPORT OpenGLShaderProgram { public: - OpenGLShaderProgram(QString name, QOpenGLFunctions_3_2_Core* functions); + OpenGLShaderProgram(QString name, OpenGLRenderer* renderer); ~OpenGLShaderProgram(); void addVertexSource(QString path); @@ -26,8 +26,6 @@ public: void compile(); void updateCamera(const QVector3D& location, const QMatrix4x4& view); - void updateWaterHeight(double height); - void updateSun(const QVector3D& direction, const QColor& color); void addTexture(QString sampler_name, Texture2D* texture); void addTexture(QString sampler_name, Texture3D* texture); @@ -36,18 +34,19 @@ public: void drawTriangles(float* vertices, int triangle_count); void drawTriangleStrip(float* vertices, int vertex_count); +protected: + inline QOpenGLShaderProgram* getProgram() const {return program;} + friend class OpenGLVariable; + private: void bind(); void release(); + OpenGLRenderer* renderer; + QMatrix4x4 view; QVector3D camera_location; - float water_height; - - QVector3D sun_direction; - QColor sun_color; - QString name; QOpenGLShaderProgram* program; QOpenGLFunctions_3_2_Core* functions; diff --git a/src/render/opengl/OpenGLSharedState.cpp b/src/render/opengl/OpenGLSharedState.cpp new file mode 100644 index 0000000..a504fd8 --- /dev/null +++ b/src/render/opengl/OpenGLSharedState.cpp @@ -0,0 +1,23 @@ +#include "OpenGLSharedState.h" + +OpenGLSharedState::OpenGLSharedState() +{ +} + +void OpenGLSharedState::apply(OpenGLShaderProgram *program) +{ + for (const auto &pair : variables) + { + pair.second->apply(program); + } +} + +OpenGLVariable *OpenGLSharedState::get(const std::string &name) +{ + OpenGLVariable*& var = variables[name]; + if (var == 0) + { + var = new OpenGLVariable(name); + } + return var; +} diff --git a/src/render/opengl/OpenGLSharedState.h b/src/render/opengl/OpenGLSharedState.h new file mode 100644 index 0000000..050f68d --- /dev/null +++ b/src/render/opengl/OpenGLSharedState.h @@ -0,0 +1,46 @@ +#ifndef OPENGLSHAREDSTATE_H +#define OPENGLSHAREDSTATE_H + +#include "opengl_global.h" + +#include +#include "OpenGLVariable.h" + +namespace paysages { +namespace opengl { + +/*! + * \brief OpenGL variables that can be shared between shaders. + */ +class OPENGLSHARED_EXPORT OpenGLSharedState +{ +public: + OpenGLSharedState(); + + /*! + * \brief Apply the stored variables to the bound program. + */ + void apply(OpenGLShaderProgram* program); + + /*! + * \brief Get or create a variable in the state. + */ + OpenGLVariable *get(const std::string &name); + + // Shortcuts + inline void set(const std::string &name, const Texture2D *texture) {get(name)->set(texture);} + inline void set(const std::string &name, const Texture3D *texture) {get(name)->set(texture);} + inline void set(const std::string &name, const Texture4D *texture) {get(name)->set(texture);} + inline void set(const std::string &name, float value) {get(name)->set(value);} + inline void set(const std::string &name, const Vector3 &vector) {get(name)->set(vector);} + inline void set(const std::string &name, const Matrix4 &matrix) {get(name)->set(matrix);} + inline void set(const std::string &name, const Color &color) {get(name)->set(color);} + +private: + std::map variables; +}; + +} +} + +#endif // OPENGLSHAREDSTATE_H diff --git a/src/render/opengl/OpenGLSkybox.cpp b/src/render/opengl/OpenGLSkybox.cpp index 8cfa29a..11773b0 100644 --- a/src/render/opengl/OpenGLSkybox.cpp +++ b/src/render/opengl/OpenGLSkybox.cpp @@ -3,6 +3,7 @@ #include #include "OpenGLRenderer.h" #include "OpenGLShaderProgram.h" +#include "OpenGLSharedState.h" #include "Scenery.h" #include "AtmosphereDefinition.h" #include "AtmosphereRenderer.h" @@ -51,8 +52,13 @@ void OpenGLSkybox::initialize() void OpenGLSkybox::update() { - SoftwareBrunetonAtmosphereRenderer* bruneton = (SoftwareBrunetonAtmosphereRenderer*)renderer->getAtmosphereRenderer(); + Vector3 sun_direction = renderer->getAtmosphereRenderer()->getSunDirection(); + renderer->getSharedState()->set("sunDirection", sun_direction); + Color sun_color = renderer->getScenery()->getAtmosphere()->sun_color; + renderer->getSharedState()->set("sunColor", sun_color); + + SoftwareBrunetonAtmosphereRenderer* bruneton = (SoftwareBrunetonAtmosphereRenderer*)renderer->getAtmosphereRenderer(); program->addTexture("transmittanceTexture", bruneton->getModel()->getTextureTransmittance()); program->addTexture("inscatterTexture", bruneton->getModel()->getTextureInscatter()); } diff --git a/src/render/opengl/OpenGLVariable.cpp b/src/render/opengl/OpenGLVariable.cpp new file mode 100644 index 0000000..5724399 --- /dev/null +++ b/src/render/opengl/OpenGLVariable.cpp @@ -0,0 +1,57 @@ +#include "OpenGLVariable.h" + +#include +#include +#include "OpenGLShaderProgram.h" +#include "Vector3.h" +#include "Color.h" + +OpenGLVariable::OpenGLVariable(const std::string &name): + name(name) +{ + type = TYPE_NONE; +} + +void OpenGLVariable::apply(OpenGLShaderProgram *program) +{ + QOpenGLShaderProgram* pr = program->getProgram(); + + switch (type) + { + case TYPE_FLOAT: + pr->setUniformValue(name.c_str(), value_float); + break; + case TYPE_COLOR: + pr->setUniformValue(name.c_str(), value_color); + break; + case TYPE_VECTOR3: + pr->setUniformValue(name.c_str(), value_vector3); + break; + case TYPE_NONE: + break; + } +} + +void OpenGLVariable::set(float value) +{ + assert(type == TYPE_NONE or type == TYPE_FLOAT); + + type = TYPE_FLOAT; + value_float = value; +} + +void OpenGLVariable::set(const Vector3 &vector) +{ + assert(type == TYPE_NONE or type == TYPE_COLOR); + + type = TYPE_VECTOR3; + value_vector3 = QVector3D(vector.x, vector.y, vector.z); +} + +void OpenGLVariable::set(const Color &color) +{ + assert(type == TYPE_NONE or type == TYPE_COLOR); + + type = TYPE_COLOR; + value_color = QColor(color.r, color.g, color.b); +} diff --git a/src/render/opengl/OpenGLVariable.h b/src/render/opengl/OpenGLVariable.h new file mode 100644 index 0000000..102c1ea --- /dev/null +++ b/src/render/opengl/OpenGLVariable.h @@ -0,0 +1,54 @@ +#ifndef OPENGLVARIABLE_H +#define OPENGLVARIABLE_H + +#include "opengl_global.h" + +#include +#include + +namespace paysages { +namespace opengl { + +/*! + * \brief OpenGL variable that can be bound to a uniform for shaders. + */ +class OpenGLVariable +{ +public: + typedef enum { + TYPE_NONE, + TYPE_TEXTURE_2D, + TYPE_TEXTURE_3D, + TYPE_TEXTURE_4D, + TYPE_FLOAT, + TYPE_VECTOR3, + TYPE_MATRIX4, + TYPE_COLOR + } OpenGLVariableType; + +public: + OpenGLVariable(const std::string &name); + + void apply(OpenGLShaderProgram *program); + + void set(const Texture2D *texture); + void set(const Texture3D *texture); + void set(const Texture4D *texture); + void set(float value); + void set(const Vector3 &vector); + void set(const Matrix4 &matrix); + void set(const Color &color); + +private: + std::string name; + OpenGLVariableType type; + + float value_float; + QColor value_color; + QVector3D value_vector3; +}; + +} +} + +#endif // OPENGLVARIABLE_H diff --git a/src/render/opengl/OpenGLWater.cpp b/src/render/opengl/OpenGLWater.cpp index bebef71..3c88c23 100644 --- a/src/render/opengl/OpenGLWater.cpp +++ b/src/render/opengl/OpenGLWater.cpp @@ -1,6 +1,9 @@ #include "OpenGLWater.h" +#include "OpenGLRenderer.h" #include "OpenGLShaderProgram.h" +#include "OpenGLSharedState.h" +#include "WaterRenderer.h" OpenGLWater::OpenGLWater(OpenGLRenderer *renderer): OpenGLPart(renderer) @@ -27,6 +30,8 @@ void OpenGLWater::initialize() void OpenGLWater::update() { + double water_height = renderer->getWaterRenderer()->getHeightInfo().max_height; + renderer->getSharedState()->set("waterHeight", water_height); } void OpenGLWater::render() diff --git a/src/render/opengl/opengl.pro b/src/render/opengl/opengl.pro index fe2ea41..b341939 100644 --- a/src/render/opengl/opengl.pro +++ b/src/render/opengl/opengl.pro @@ -21,7 +21,9 @@ SOURCES += \ OpenGLShaderProgram.cpp \ OpenGLPart.cpp \ OpenGLSkybox.cpp \ - OpenGLWater.cpp + OpenGLWater.cpp \ + OpenGLSharedState.cpp \ + OpenGLVariable.cpp HEADERS +=\ opengl_global.h \ @@ -32,7 +34,9 @@ HEADERS +=\ OpenGLShaderProgram.h \ OpenGLPart.h \ OpenGLSkybox.h \ - OpenGLWater.h + OpenGLWater.h \ + OpenGLSharedState.h \ + OpenGLVariable.h unix:!symbian { maemo5 { diff --git a/src/render/opengl/opengl_global.h b/src/render/opengl/opengl_global.h index b949e60..d8f0cef 100644 --- a/src/render/opengl/opengl_global.h +++ b/src/render/opengl/opengl_global.h @@ -17,6 +17,8 @@ namespace opengl { class OpenGLRenderer; class BaseExplorerChunk; class OpenGLShaderProgram; + class OpenGLSharedState; + class OpenGLVariable; class OpenGLSkybox; class OpenGLWater; } diff --git a/src/system/Logs.cpp b/src/system/Logs.cpp new file mode 100644 index 0000000..eca5c5c --- /dev/null +++ b/src/system/Logs.cpp @@ -0,0 +1 @@ +#include "Logs.h" diff --git a/src/system/Logs.h b/src/system/Logs.h new file mode 100644 index 0000000..a044089 --- /dev/null +++ b/src/system/Logs.h @@ -0,0 +1,9 @@ +#ifndef LOGS_H +#define LOGS_H + +#include "system_global.h" + +#define logWarning qWarning +#define logError qError + +#endif // LOGS_H diff --git a/src/system/system.pro b/src/system/system.pro index 2c6bd99..2aa7ac0 100644 --- a/src/system/system.pro +++ b/src/system/system.pro @@ -23,7 +23,8 @@ SOURCES += \ ParallelWork.cpp \ ParallelQueue.cpp \ CacheFile.cpp \ - PictureWriter.cpp + PictureWriter.cpp \ + Logs.cpp HEADERS += \ system_global.h \ @@ -36,7 +37,8 @@ HEADERS += \ ParallelWork.h \ ParallelQueue.h \ CacheFile.h \ - PictureWriter.h + PictureWriter.h \ + Logs.h unix:!symbian { maemo5 { From 645bada91b2b85b72037b3a1815ca910895c9180 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Lemaire?= Date: Sun, 22 Dec 2013 17:30:48 +0100 Subject: [PATCH 06/17] Added camera to OpenGLSharedState --- src/basics/Matrix4.h | 12 +++++++++ src/definition/CameraDefinition.h | 1 + src/render/opengl/OpenGLPart.cpp | 30 ----------------------- src/render/opengl/OpenGLPart.h | 1 - src/render/opengl/OpenGLRenderer.cpp | 22 +++++++++++++++-- src/render/opengl/OpenGLShaderProgram.cpp | 20 --------------- src/render/opengl/OpenGLShaderProgram.h | 5 ---- src/render/opengl/OpenGLSharedState.h | 2 ++ src/render/opengl/OpenGLVariable.cpp | 26 ++++++++++++++++++-- src/render/opengl/OpenGLVariable.h | 4 +++ 10 files changed, 63 insertions(+), 60 deletions(-) diff --git a/src/basics/Matrix4.h b/src/basics/Matrix4.h index a53d3f3..42954c7 100644 --- a/src/basics/Matrix4.h +++ b/src/basics/Matrix4.h @@ -4,6 +4,9 @@ #include "basics_global.h" #include "Vector3.h" +#ifdef QT_GUI_LIB +#include +#endif namespace paysages { namespace basics { @@ -35,6 +38,15 @@ public: double getDeterminant() const; +#ifdef QT_GUI_LIB + inline QMatrix4x4 toQMatrix() const { + return QMatrix4x4(a, b, c, d, + e, f, g, h, + i, j, k, l, + m, n, o, p); + } +#endif + private: double a; double b; diff --git a/src/definition/CameraDefinition.h b/src/definition/CameraDefinition.h index e5dc512..162e38a 100644 --- a/src/definition/CameraDefinition.h +++ b/src/definition/CameraDefinition.h @@ -36,6 +36,7 @@ public: inline double getRoll() const {return roll;} inline Vector3 getDirection() const {return Vector3(direction);} inline Vector3 getDirectionNormalized() const {return forward;} + inline const Matrix4 &getTransformationMatrix() const {return projector;} inline VectorSpherical getDirectionSpherical() const {return direction;} inline CameraPerspective getPerspective() const {return perspective;} diff --git a/src/render/opengl/OpenGLPart.cpp b/src/render/opengl/OpenGLPart.cpp index 4c184d6..2e313d5 100644 --- a/src/render/opengl/OpenGLPart.cpp +++ b/src/render/opengl/OpenGLPart.cpp @@ -49,36 +49,6 @@ void OpenGLPart::postInitialize() } } -void OpenGLPart::updateCamera(CameraDefinition* camera) -{ - // Get camera info - Vector3 location = camera->getLocation(); - Vector3 target = camera->getTarget(); - Vector3 up = camera->getUpVector(); - CameraPerspective perspective = camera->getPerspective(); - - QVector3D vlocation(location.x, location.y, location.z); - - // Compute matrix - QMatrix4x4 transform; - transform.setToIdentity(); - transform.lookAt(vlocation, - QVector3D(target.x, target.y, target.z), - QVector3D(up.x, up.y, up.z)); - - QMatrix4x4 projection; - projection.setToIdentity(); - projection.perspective(perspective.yfov * 180.0 / M_PI, perspective.xratio, perspective.znear, perspective.zfar); - - // Set in shaders - QMapIterator i(shaders); - while (i.hasNext()) - { - i.next(); - i.value()->updateCamera(vlocation, projection * transform); - } -} - void OpenGLPart::updateScenery(bool onlyCommon) { // Let subclass do its own collecting diff --git a/src/render/opengl/OpenGLPart.h b/src/render/opengl/OpenGLPart.h index b7ae211..84ef432 100644 --- a/src/render/opengl/OpenGLPart.h +++ b/src/render/opengl/OpenGLPart.h @@ -27,7 +27,6 @@ public: virtual void render() = 0; void postInitialize(); - void updateCamera(CameraDefinition* camera); void updateScenery(bool onlyCommon=false); protected: diff --git a/src/render/opengl/OpenGLRenderer.cpp b/src/render/opengl/OpenGLRenderer.cpp index 1b326bf..0600be9 100644 --- a/src/render/opengl/OpenGLRenderer.cpp +++ b/src/render/opengl/OpenGLRenderer.cpp @@ -75,8 +75,26 @@ void OpenGLRenderer::paint() void OpenGLRenderer::cameraChangeEvent(CameraDefinition *camera) { - skybox->updateCamera(camera); - water->updateCamera(camera); + // Get camera info + Vector3 location = camera->getLocation(); + Vector3 target = camera->getTarget(); + Vector3 up = camera->getUpVector(); + CameraPerspective perspective = camera->getPerspective(); + + // Compute matrix + QMatrix4x4 transform; + transform.setToIdentity(); + transform.lookAt(QVector3D(location.x, location.y, location.z), + QVector3D(target.x, target.y, target.z), + QVector3D(up.x, up.y, up.z)); + + QMatrix4x4 projection; + projection.setToIdentity(); + projection.perspective(perspective.yfov * 180.0 / M_PI, perspective.xratio, perspective.znear, perspective.zfar); + + // Set in shaders + shared_state->set("cameraLocation", location); + shared_state->set("viewMatrix", projection * transform); } double OpenGLRenderer::getPrecision(const Vector3 &) diff --git a/src/render/opengl/OpenGLShaderProgram.cpp b/src/render/opengl/OpenGLShaderProgram.cpp index cf34e66..9023b4d 100644 --- a/src/render/opengl/OpenGLShaderProgram.cpp +++ b/src/render/opengl/OpenGLShaderProgram.cpp @@ -44,12 +44,6 @@ void OpenGLShaderProgram::compile() } } -void OpenGLShaderProgram::updateCamera(const QVector3D& location, const QMatrix4x4& view) -{ - this->camera_location = location; - this->view = view; -} - void OpenGLShaderProgram::addTexture(QString sampler_name, Texture2D* texture) { GLuint texid; @@ -187,20 +181,6 @@ void OpenGLShaderProgram::bind() renderer->getSharedState()->apply(this); - // TODO Keep locations in cache - - int viewMatrix = program->uniformLocation("viewMatrix"); - if (viewMatrix >= 0) - { - program->setUniformValue(viewMatrix, view); - } - - int cameraLocation = program->uniformLocation("cameraLocation"); - if (cameraLocation >= 0) - { - program->setUniformValue(cameraLocation, camera_location); - } - QMapIterator > iter(textures); int i = 0; while (iter.hasNext()) diff --git a/src/render/opengl/OpenGLShaderProgram.h b/src/render/opengl/OpenGLShaderProgram.h index 7cf9e6b..0f23c2a 100644 --- a/src/render/opengl/OpenGLShaderProgram.h +++ b/src/render/opengl/OpenGLShaderProgram.h @@ -25,8 +25,6 @@ public: void addFragmentSource(QString path); void compile(); - void updateCamera(const QVector3D& location, const QMatrix4x4& view); - void addTexture(QString sampler_name, Texture2D* texture); void addTexture(QString sampler_name, Texture3D* texture); void addTexture(QString sampler_name, Texture4D* texture); @@ -44,9 +42,6 @@ private: OpenGLRenderer* renderer; - QMatrix4x4 view; - QVector3D camera_location; - QString name; QOpenGLShaderProgram* program; QOpenGLFunctions_3_2_Core* functions; diff --git a/src/render/opengl/OpenGLSharedState.h b/src/render/opengl/OpenGLSharedState.h index 050f68d..8ce3d00 100644 --- a/src/render/opengl/OpenGLSharedState.h +++ b/src/render/opengl/OpenGLSharedState.h @@ -33,7 +33,9 @@ public: inline void set(const std::string &name, const Texture4D *texture) {get(name)->set(texture);} inline void set(const std::string &name, float value) {get(name)->set(value);} inline void set(const std::string &name, const Vector3 &vector) {get(name)->set(vector);} + inline void set(const std::string &name, const QVector3D &vector) {get(name)->set(vector);} inline void set(const std::string &name, const Matrix4 &matrix) {get(name)->set(matrix);} + inline void set(const std::string &name, const QMatrix4x4 &matrix) {get(name)->set(matrix);} inline void set(const std::string &name, const Color &color) {get(name)->set(color);} private: diff --git a/src/render/opengl/OpenGLVariable.cpp b/src/render/opengl/OpenGLVariable.cpp index 5724399..b7d864e 100644 --- a/src/render/opengl/OpenGLVariable.cpp +++ b/src/render/opengl/OpenGLVariable.cpp @@ -4,6 +4,7 @@ #include #include "OpenGLShaderProgram.h" #include "Vector3.h" +#include "Matrix4.h" #include "Color.h" OpenGLVariable::OpenGLVariable(const std::string &name): @@ -27,6 +28,9 @@ void OpenGLVariable::apply(OpenGLShaderProgram *program) case TYPE_VECTOR3: pr->setUniformValue(name.c_str(), value_vector3); break; + case TYPE_MATRIX4: + pr->setUniformValue(name.c_str(), value_matrix4); + break; case TYPE_NONE: break; } @@ -42,10 +46,28 @@ void OpenGLVariable::set(float value) void OpenGLVariable::set(const Vector3 &vector) { - assert(type == TYPE_NONE or type == TYPE_COLOR); + set(QVector3D(vector.x, vector.y, vector.z)); +} + +void OpenGLVariable::set(const QVector3D &vector) +{ + assert(type == TYPE_NONE or type == TYPE_VECTOR3); type = TYPE_VECTOR3; - value_vector3 = QVector3D(vector.x, vector.y, vector.z); + value_vector3 = vector; +} + +void OpenGLVariable::set(const Matrix4 &matrix) +{ + set(matrix.toQMatrix()); +} + +void OpenGLVariable::set(const QMatrix4x4 &matrix) +{ + assert(type == TYPE_NONE or type == TYPE_MATRIX4); + + type = TYPE_MATRIX4; + value_matrix4 = matrix; } void OpenGLVariable::set(const Color &color) diff --git a/src/render/opengl/OpenGLVariable.h b/src/render/opengl/OpenGLVariable.h index 102c1ea..0fc633c 100644 --- a/src/render/opengl/OpenGLVariable.h +++ b/src/render/opengl/OpenGLVariable.h @@ -5,6 +5,7 @@ #include #include +#include namespace paysages { namespace opengl { @@ -36,7 +37,9 @@ public: void set(const Texture4D *texture); void set(float value); void set(const Vector3 &vector); + void set(const QVector3D &vector); void set(const Matrix4 &matrix); + void set(const QMatrix4x4 &matrix); void set(const Color &color); private: @@ -46,6 +49,7 @@ private: float value_float; QColor value_color; QVector3D value_vector3; + QMatrix4x4 value_matrix4; }; } From 992089f0ef4efa84958b451cc20ad2a0f8c72579 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Lemaire?= Date: Sun, 22 Dec 2013 18:05:11 +0100 Subject: [PATCH 07/17] Added textures to OpenGLSharedState --- src/basics/Texture2D.cpp | 18 +-- src/basics/Texture2D.h | 14 +- src/basics/Texture3D.cpp | 18 +-- src/basics/Texture3D.h | 14 +- src/basics/Texture4D.cpp | 18 +-- src/basics/Texture4D.h | 14 +- src/render/opengl/OpenGLShaderProgram.cpp | 149 +-------------------- src/render/opengl/OpenGLShaderProgram.h | 11 +- src/render/opengl/OpenGLSharedState.cpp | 4 +- src/render/opengl/OpenGLSharedState.h | 2 +- src/render/opengl/OpenGLSkybox.cpp | 4 +- src/render/opengl/OpenGLVariable.cpp | 154 +++++++++++++++++++++- src/render/opengl/OpenGLVariable.h | 11 +- 13 files changed, 219 insertions(+), 212 deletions(-) diff --git a/src/basics/Texture2D.cpp b/src/basics/Texture2D.cpp index 5950490..13e71e7 100644 --- a/src/basics/Texture2D.cpp +++ b/src/basics/Texture2D.cpp @@ -19,7 +19,7 @@ Texture2D::~Texture2D() delete[] data; } -void Texture2D::getSize(int* xsize, int* ysize) +void Texture2D::getSize(int* xsize, int* ysize) const { *xsize = this->xsize; *ysize = this->ysize; @@ -33,7 +33,7 @@ void Texture2D::setPixel(int x, int y, Color col) data[y * xsize + x] = col; } -Color Texture2D::getPixel(int x, int y) +Color Texture2D::getPixel(int x, int y) const { assert(x >= 0 && x < xsize); assert(y >= 0 && y < ysize); @@ -41,7 +41,7 @@ Color Texture2D::getPixel(int x, int y) return data[y * xsize + x]; } -Color Texture2D::getNearest(double dx, double dy) +Color Texture2D::getNearest(double dx, double dy) const { if (dx < 0.0) dx = 0.0; if (dx > 1.0) dx = 1.0; @@ -57,7 +57,7 @@ Color Texture2D::getNearest(double dx, double dy) return this->data[iy * this->xsize + ix]; } -Color Texture2D::getLinear(double dx, double dy) +Color Texture2D::getLinear(double dx, double dy) const { if (dx < 0.0) dx = 0.0; if (dx > 1.0) dx = 1.0; @@ -89,7 +89,7 @@ Color Texture2D::getLinear(double dx, double dy) return c1.lerp(c2, dy); } -Color Texture2D::getCubic(double dx, double dy) +Color Texture2D::getCubic(double dx, double dy) const { /* TODO */ return getLinear(dx, dy); @@ -122,7 +122,7 @@ void Texture2D::add(Texture2D* source) } } -void Texture2D::save(PackStream* stream) +void Texture2D::save(PackStream* stream) const { int i, n; stream->write(&this->xsize); @@ -151,17 +151,17 @@ void Texture2D::load(PackStream* stream) class Texture2DWriter:public PictureWriter { public: - Texture2DWriter(Texture2D *tex): tex(tex) {} + Texture2DWriter(const Texture2D *tex): tex(tex) {} virtual unsigned int getPixel(int x, int y) override { return tex->getPixel(x, y).to32BitBGRA(); } private: - Texture2D *tex; + const Texture2D *tex; }; -void Texture2D::saveToFile(const std::string &filepath) +void Texture2D::saveToFile(const std::string &filepath) const { Texture2DWriter writer(this); writer.save(filepath, xsize, ysize); diff --git a/src/basics/Texture2D.h b/src/basics/Texture2D.h index 94bc39f..67d1649 100644 --- a/src/basics/Texture2D.h +++ b/src/basics/Texture2D.h @@ -12,17 +12,17 @@ public: Texture2D(int xsize, int ysize); ~Texture2D(); - void getSize(int* xsize, int* ysize); + void getSize(int* xsize, int* ysize) const; void setPixel(int x, int y, Color col); - Color getPixel(int x, int y); - Color getNearest(double dx, double dy); - Color getLinear(double dx, double dy); - Color getCubic(double dx, double dy); + Color getPixel(int x, int y) const; + Color getNearest(double dx, double dy) const; + Color getLinear(double dx, double dy) const; + Color getCubic(double dx, double dy) const; void fill(Color col); void add(Texture2D* other); - void save(PackStream* stream); + void save(PackStream* stream) const; void load(PackStream* stream); - void saveToFile(const std::string &filepath); + void saveToFile(const std::string &filepath) const; private: int xsize; diff --git a/src/basics/Texture3D.cpp b/src/basics/Texture3D.cpp index bca20a7..55400e2 100644 --- a/src/basics/Texture3D.cpp +++ b/src/basics/Texture3D.cpp @@ -20,7 +20,7 @@ Texture3D::~Texture3D() delete[] data; } -void Texture3D::getSize(int* xsize, int* ysize, int* zsize) +void Texture3D::getSize(int* xsize, int* ysize, int* zsize) const { *xsize = this->xsize; *ysize = this->ysize; @@ -36,7 +36,7 @@ void Texture3D::setPixel(int x, int y, int z, Color col) this->data[z * this->xsize * this->ysize + y * this->xsize + x] = col; } -Color Texture3D::getPixel(int x, int y, int z) +Color Texture3D::getPixel(int x, int y, int z) const { assert(x >= 0 && x < this->xsize); assert(y >= 0 && y < this->ysize); @@ -45,7 +45,7 @@ Color Texture3D::getPixel(int x, int y, int z) return this->data[z * this->xsize * this->ysize + y * this->xsize + x]; } -Color Texture3D::getNearest(double dx, double dy, double dz) +Color Texture3D::getNearest(double dx, double dy, double dz) const { if (dx < 0.0) dx = 0.0; if (dx > 1.0) dx = 1.0; @@ -65,7 +65,7 @@ Color Texture3D::getNearest(double dx, double dy, double dz) return this->data[iz * this->xsize * this->ysize + iy * this->xsize + ix]; } -Color Texture3D::getLinear(double dx, double dy, double dz) +Color Texture3D::getLinear(double dx, double dy, double dz) const { if (dx < 0.0) dx = 0.0; if (dx > 1.0) dx = 1.0; @@ -112,7 +112,7 @@ Color Texture3D::getLinear(double dx, double dy, double dz) return cy1.lerp(cy2, dz); } -Color Texture3D::getCubic(double dx, double dy, double dz) +Color Texture3D::getCubic(double dx, double dy, double dz) const { /* TODO */ return getLinear(dx, dy, dz); @@ -146,7 +146,7 @@ void Texture3D::add(Texture3D* source) } } -void Texture3D::save(PackStream* stream) +void Texture3D::save(PackStream* stream) const { int i, n; stream->write(&this->xsize); @@ -177,7 +177,7 @@ void Texture3D::load(PackStream* stream) class Texture3DWriter:public PictureWriter { public: - Texture3DWriter(Texture3D *tex): tex(tex) {} + Texture3DWriter(const Texture3D *tex): tex(tex) {} virtual unsigned int getPixel(int x, int y) override { @@ -190,10 +190,10 @@ public: return tex->getPixel(x, y, z).to32BitBGRA(); } private: - Texture3D *tex; + const Texture3D *tex; }; -void Texture3D::saveToFile(const std::string &filepath) +void Texture3D::saveToFile(const std::string &filepath) const { Texture3DWriter writer(this); writer.save(filepath, xsize, ysize * zsize); diff --git a/src/basics/Texture3D.h b/src/basics/Texture3D.h index 3c40f16..8a68208 100644 --- a/src/basics/Texture3D.h +++ b/src/basics/Texture3D.h @@ -12,17 +12,17 @@ public: Texture3D(int xsize, int ysize, int zsize); ~Texture3D(); - void getSize(int* xsize, int* ysize, int* zsize); + void getSize(int* xsize, int* ysize, int* zsize) const; void setPixel(int x, int y, int z, Color col); - Color getPixel(int x, int y, int z); - Color getNearest(double dx, double dy, double dz); - Color getLinear(double dx, double dy, double dz); - Color getCubic(double dx, double dy, double dz); + Color getPixel(int x, int y, int z) const; + Color getNearest(double dx, double dy, double dz) const; + Color getLinear(double dx, double dy, double dz) const; + Color getCubic(double dx, double dy, double dz) const; void fill(Color col); void add(Texture3D* other); - void save(PackStream* stream); + void save(PackStream* stream) const; void load(PackStream* stream); - void saveToFile(const std::string &filepath); + void saveToFile(const std::string &filepath) const; private: int xsize; diff --git a/src/basics/Texture4D.cpp b/src/basics/Texture4D.cpp index 8700ecd..877ea4b 100644 --- a/src/basics/Texture4D.cpp +++ b/src/basics/Texture4D.cpp @@ -21,7 +21,7 @@ Texture4D::~Texture4D() delete[] data; } -void Texture4D::getSize(int* xsize, int* ysize, int* zsize, int* wsize) +void Texture4D::getSize(int* xsize, int* ysize, int* zsize, int* wsize) const { *xsize = this->xsize; *ysize = this->ysize; @@ -39,7 +39,7 @@ void Texture4D::setPixel(int x, int y, int z, int w, Color col) this->data[w * this->xsize * this->ysize * this->zsize + z * this->xsize * this->ysize + y * this->xsize + x] = col; } -Color Texture4D::getPixel(int x, int y, int z, int w) +Color Texture4D::getPixel(int x, int y, int z, int w) const { assert(x >= 0 && x < this->xsize); assert(y >= 0 && y < this->ysize); @@ -49,7 +49,7 @@ Color Texture4D::getPixel(int x, int y, int z, int w) return this->data[w * this->xsize * this->ysize * this->zsize + z * this->xsize * this->ysize + y * this->xsize + x]; } -Color Texture4D::getNearest(double dx, double dy, double dz, double dw) +Color Texture4D::getNearest(double dx, double dy, double dz, double dw) const { if (dx < 0.0) dx = 0.0; if (dx > 1.0) dx = 1.0; @@ -73,7 +73,7 @@ Color Texture4D::getNearest(double dx, double dy, double dz, double dw) return this->data[iw * this->xsize * this->ysize * this->zsize + iz * this->xsize * this->ysize + iy * this->xsize + ix]; } -Color Texture4D::getLinear(double dx, double dy, double dz, double dw) +Color Texture4D::getLinear(double dx, double dy, double dz, double dw) const { if (dx < 0.0) dx = 0.0; if (dx > 1.0) dx = 1.0; @@ -143,7 +143,7 @@ Color Texture4D::getLinear(double dx, double dy, double dz, double dw) return cz1.lerp(cz2, dw); } -Color Texture4D::getCubic(double dx, double dy, double dz, double dw) +Color Texture4D::getCubic(double dx, double dy, double dz, double dw) const { /* TODO */ return getLinear(dx, dy, dz, dw); @@ -178,7 +178,7 @@ void Texture4D::add(Texture4D* source) } } -void Texture4D::save(PackStream* stream) +void Texture4D::save(PackStream* stream) const { int i, n; stream->write(&this->xsize); @@ -212,7 +212,7 @@ void Texture4D::load(PackStream* stream) class Texture4DWriter:public PictureWriter { public: - Texture4DWriter(Texture4D *tex): tex(tex) {} + Texture4DWriter(const Texture4D *tex): tex(tex) {} virtual unsigned int getPixel(int x, int y) override { @@ -228,10 +228,10 @@ public: return tex->getPixel(x, y, z, w).to32BitBGRA(); } private: - Texture4D *tex; + const Texture4D *tex; }; -void Texture4D::saveToFile(const std::string &filepath) +void Texture4D::saveToFile(const std::string &filepath) const { Texture4DWriter writer(this); writer.save(filepath, xsize * wsize, ysize * zsize); diff --git a/src/basics/Texture4D.h b/src/basics/Texture4D.h index 3657951..6b53580 100644 --- a/src/basics/Texture4D.h +++ b/src/basics/Texture4D.h @@ -12,17 +12,17 @@ public: Texture4D(int xsize, int ysize, int zsize, int wsize); ~Texture4D(); - void getSize(int* xsize, int* ysize, int* zsize, int* wsize); + void getSize(int* xsize, int* ysize, int* zsize, int* wsize) const; void setPixel(int x, int y, int z, int w, Color col); - Color getPixel(int x, int y, int z, int w); - Color getNearest(double dx, double dy, double dz, double dw); - Color getLinear(double dx, double dy, double dz, double dw); - Color getCubic(double dx, double dy, double dz, double dw); + Color getPixel(int x, int y, int z, int w) const; + Color getNearest(double dx, double dy, double dz, double dw) const; + Color getLinear(double dx, double dy, double dz, double dw) const; + Color getCubic(double dx, double dy, double dz, double dw) const; void fill(Color col); void add(Texture4D* other); - void save(PackStream* stream); + void save(PackStream* stream) const; void load(PackStream* stream); - void saveToFile(const std::string &filepath); + void saveToFile(const std::string &filepath) const; private: int xsize; diff --git a/src/render/opengl/OpenGLShaderProgram.cpp b/src/render/opengl/OpenGLShaderProgram.cpp index 9023b4d..03289a3 100644 --- a/src/render/opengl/OpenGLShaderProgram.cpp +++ b/src/render/opengl/OpenGLShaderProgram.cpp @@ -44,157 +44,12 @@ void OpenGLShaderProgram::compile() } } -void OpenGLShaderProgram::addTexture(QString sampler_name, Texture2D* texture) -{ - GLuint texid; - - if (textures.contains(sampler_name)) - { - texid = textures[sampler_name].second; - } - else - { - functions->glGenTextures(1, &texid); - textures[sampler_name] = QPair(GL_TEXTURE_2D, texid); - } - - functions->glBindTexture(GL_TEXTURE_2D, texid); - functions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - functions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - functions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - functions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - int sx, sy; - texture->getSize(&sx, &sy); - float* pixels = new float[sx * sy * 4]; - for (int x = 0; x < sx; x++) - { - for (int y = 0; y < sy; y++) - { - float* pixel = pixels + (y * sx + x) * 4; - Color col = texture->getPixel(x, y); - pixel[0] = (float)col.r; - pixel[1] = (float)col.g; - pixel[2] = (float)col.b; - pixel[3] = (float)col.a; - } - } - - functions->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, sx, sy, 0, GL_RGBA, GL_FLOAT, pixels); - delete[] pixels; -} - -void OpenGLShaderProgram::addTexture(QString sampler_name, Texture3D* texture) -{ - GLuint texid; - - if (textures.contains(sampler_name)) - { - texid = textures[sampler_name].second; - } - else - { - functions->glGenTextures(1, &texid); - textures[sampler_name] = QPair(GL_TEXTURE_3D, texid); - } - - functions->glBindTexture(GL_TEXTURE_3D, texid); - functions->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - functions->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - functions->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - functions->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - functions->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); - - int sx, sy, sz; - texture->getSize(&sx, &sy, &sz); - float* pixels = new float[sx * sy * sz * 4]; - for (int x = 0; x < sx; x++) - { - for (int y = 0; y < sy; y++) - { - for (int z = 0; z < sz; z++) - { - float* pixel = pixels + (z * (sx * sy) + y * sx + x) * 4; - Color col = texture->getPixel(x, y, z); - pixel[0] = (float)col.r; - pixel[1] = (float)col.g; - pixel[2] = (float)col.b; - pixel[3] = (float)col.a; - } - } - } - - functions->glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, sx, sy, sz, 0, GL_RGBA, GL_FLOAT, pixels); - delete[] pixels; -} - -void OpenGLShaderProgram::addTexture(QString sampler_name, Texture4D* texture) -{ - GLuint texid; - - if (textures.contains(sampler_name)) - { - texid = textures[sampler_name].second; - } - else - { - functions->glGenTextures(1, &texid); - textures[sampler_name] = QPair(GL_TEXTURE_3D, texid); - } - - functions->glBindTexture(GL_TEXTURE_3D, texid); - functions->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - functions->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - functions->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - functions->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - functions->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); - - int sx, sy, sz, sw; - texture->getSize(&sx, &sy, &sz, &sw); - float* pixels = new float[sx * sy * sz * sw * 4]; - for (int x = 0; x < sx; x++) - { - for (int y = 0; y < sy; y++) - { - for (int z = 0; z < sz; z++) - { - for (int w = 0; w < sw; w++) - { - float* pixel = pixels + (w * (sx * sy * sz) + z * (sx * sy) + y * sx + x) * 4; - Color col = texture->getPixel(x, y, z, w); - pixel[0] = (float)col.r; - pixel[1] = (float)col.g; - pixel[2] = (float)col.b; - pixel[3] = (float)col.a; - } - } - } - } - - functions->glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, sx, sy, sz * sw, 0, GL_RGBA, GL_FLOAT, pixels); - delete[] pixels; -} - void OpenGLShaderProgram::bind() { program->bind(); - renderer->getSharedState()->apply(this); - - QMapIterator > iter(textures); - int i = 0; - while (iter.hasNext()) - { - iter.next(); - int textureSampler = program->uniformLocation(iter.key()); - if (textureSampler >= 0) - { - functions->glActiveTexture(GL_TEXTURE0 + i); - functions->glBindTexture(iter.value().first, iter.value().second); - program->setUniformValue(textureSampler, i); - i++; - } - } + int texture_unit = 0; + renderer->getSharedState()->apply(this, texture_unit); } void OpenGLShaderProgram::release() diff --git a/src/render/opengl/OpenGLShaderProgram.h b/src/render/opengl/OpenGLShaderProgram.h index 0f23c2a..fa4d5c1 100644 --- a/src/render/opengl/OpenGLShaderProgram.h +++ b/src/render/opengl/OpenGLShaderProgram.h @@ -4,10 +4,6 @@ #include "opengl_global.h" #include -#include -#include -#include -#include class QOpenGLShaderProgram; class QOpenGLFunctions_3_2_Core; @@ -25,15 +21,12 @@ public: void addFragmentSource(QString path); void compile(); - void addTexture(QString sampler_name, Texture2D* texture); - void addTexture(QString sampler_name, Texture3D* texture); - void addTexture(QString sampler_name, Texture4D* texture); - void drawTriangles(float* vertices, int triangle_count); void drawTriangleStrip(float* vertices, int vertex_count); protected: inline QOpenGLShaderProgram* getProgram() const {return program;} + inline OpenGLRenderer* getRenderer() const {return renderer;} friend class OpenGLVariable; private: @@ -45,8 +38,6 @@ private: QString name; QOpenGLShaderProgram* program; QOpenGLFunctions_3_2_Core* functions; - - QMap > textures; }; } diff --git a/src/render/opengl/OpenGLSharedState.cpp b/src/render/opengl/OpenGLSharedState.cpp index a504fd8..b59951d 100644 --- a/src/render/opengl/OpenGLSharedState.cpp +++ b/src/render/opengl/OpenGLSharedState.cpp @@ -4,11 +4,11 @@ OpenGLSharedState::OpenGLSharedState() { } -void OpenGLSharedState::apply(OpenGLShaderProgram *program) +void OpenGLSharedState::apply(OpenGLShaderProgram *program, int &texture_unit) { for (const auto &pair : variables) { - pair.second->apply(program); + pair.second->apply(program, texture_unit); } } diff --git a/src/render/opengl/OpenGLSharedState.h b/src/render/opengl/OpenGLSharedState.h index 8ce3d00..afe8817 100644 --- a/src/render/opengl/OpenGLSharedState.h +++ b/src/render/opengl/OpenGLSharedState.h @@ -20,7 +20,7 @@ public: /*! * \brief Apply the stored variables to the bound program. */ - void apply(OpenGLShaderProgram* program); + void apply(OpenGLShaderProgram* program, int &texture_unit); /*! * \brief Get or create a variable in the state. diff --git a/src/render/opengl/OpenGLSkybox.cpp b/src/render/opengl/OpenGLSkybox.cpp index 11773b0..bc6376a 100644 --- a/src/render/opengl/OpenGLSkybox.cpp +++ b/src/render/opengl/OpenGLSkybox.cpp @@ -59,8 +59,8 @@ void OpenGLSkybox::update() renderer->getSharedState()->set("sunColor", sun_color); SoftwareBrunetonAtmosphereRenderer* bruneton = (SoftwareBrunetonAtmosphereRenderer*)renderer->getAtmosphereRenderer(); - program->addTexture("transmittanceTexture", bruneton->getModel()->getTextureTransmittance()); - program->addTexture("inscatterTexture", bruneton->getModel()->getTextureInscatter()); + renderer->getSharedState()->set("transmittanceTexture", bruneton->getModel()->getTextureTransmittance()); + renderer->getSharedState()->set("inscatterTexture", bruneton->getModel()->getTextureInscatter()); } void OpenGLSkybox::render() diff --git a/src/render/opengl/OpenGLVariable.cpp b/src/render/opengl/OpenGLVariable.cpp index b7d864e..11e97a5 100644 --- a/src/render/opengl/OpenGLVariable.cpp +++ b/src/render/opengl/OpenGLVariable.cpp @@ -2,20 +2,33 @@ #include #include +#include +#include "OpenGLRenderer.h" #include "OpenGLShaderProgram.h" #include "Vector3.h" #include "Matrix4.h" #include "Color.h" +#include "Texture2D.h" +#include "Texture3D.h" +#include "Texture4D.h" OpenGLVariable::OpenGLVariable(const std::string &name): name(name) { type = TYPE_NONE; + texture_toupload = false; } -void OpenGLVariable::apply(OpenGLShaderProgram *program) +void OpenGLVariable::apply(OpenGLShaderProgram *program, int &texture_unit) { QOpenGLShaderProgram* pr = program->getProgram(); + QOpenGLFunctions_3_2_Core* functions = program->getRenderer()->getOpenGlFunctions(); + + if (texture_toupload) + { + uploadTexture(program->getRenderer()); + texture_toupload = false; + } switch (type) { @@ -31,11 +44,51 @@ void OpenGLVariable::apply(OpenGLShaderProgram *program) case TYPE_MATRIX4: pr->setUniformValue(name.c_str(), value_matrix4); break; + case TYPE_TEXTURE_2D: + functions->glActiveTexture(GL_TEXTURE0 + texture_unit); + functions->glBindTexture(GL_TEXTURE_2D, texture_id); + pr->setUniformValue(name.c_str(), texture_unit); + texture_unit++; + break; + case TYPE_TEXTURE_3D: + case TYPE_TEXTURE_4D: + functions->glActiveTexture(GL_TEXTURE0 + texture_unit); + functions->glBindTexture(GL_TEXTURE_3D, texture_id); + pr->setUniformValue(name.c_str(), texture_unit); + texture_unit++; + break; case TYPE_NONE: break; } } +void OpenGLVariable::set(const Texture2D *texture) +{ + assert(type == TYPE_NONE or type == TYPE_TEXTURE_2D); + + type = TYPE_TEXTURE_2D; + value_tex2d = texture; + texture_toupload = true; +} + +void OpenGLVariable::set(const Texture3D *texture) +{ + assert(type == TYPE_NONE or type == TYPE_TEXTURE_3D); + + type = TYPE_TEXTURE_3D; + value_tex3d = texture; + texture_toupload = true; +} + +void OpenGLVariable::set(const Texture4D *texture) +{ + assert(type == TYPE_NONE or type == TYPE_TEXTURE_4D); + + type = TYPE_TEXTURE_4D; + value_tex4d = texture; + texture_toupload = true; +} + void OpenGLVariable::set(float value) { assert(type == TYPE_NONE or type == TYPE_FLOAT); @@ -77,3 +130,102 @@ void OpenGLVariable::set(const Color &color) type = TYPE_COLOR; value_color = QColor(color.r, color.g, color.b); } + +void OpenGLVariable::uploadTexture(OpenGLRenderer* renderer) +{ + QOpenGLFunctions_3_2_Core* functions = renderer->getOpenGlFunctions(); + + assert(type == TYPE_TEXTURE_2D or type == TYPE_TEXTURE_3D or type == TYPE_TEXTURE_4D); + + if (texture_id == 0) + { + GLuint texid; + functions->glGenTextures(1, &texid); + texture_id = texid; + } + + GLenum textype = (type == TYPE_TEXTURE_2D) ? GL_TEXTURE_2D : GL_TEXTURE_3D; + + functions->glBindTexture(textype, texture_id); + functions->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + functions->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + functions->glTexParameteri(textype, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + functions->glTexParameteri(textype, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + if (textype == GL_TEXTURE_3D) + { + functions->glTexParameteri(textype, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + } + + if (type == TYPE_TEXTURE_2D) + { + int sx, sy; + value_tex2d->getSize(&sx, &sy); + float* pixels = new float[sx * sy * 4]; + for (int x = 0; x < sx; x++) + { + for (int y = 0; y < sy; y++) + { + float* pixel = pixels + (y * sx + x) * 4; + Color col = value_tex2d->getPixel(x, y); + pixel[0] = (float)col.r; + pixel[1] = (float)col.g; + pixel[2] = (float)col.b; + pixel[3] = (float)col.a; + } + } + + functions->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, sx, sy, 0, GL_RGBA, GL_FLOAT, pixels); + delete[] pixels; + } + else if (type == TYPE_TEXTURE_3D) + { + int sx, sy, sz; + value_tex3d->getSize(&sx, &sy, &sz); + float* pixels = new float[sx * sy * sz * 4]; + for (int x = 0; x < sx; x++) + { + for (int y = 0; y < sy; y++) + { + for (int z = 0; z < sz; z++) + { + float* pixel = pixels + (z * (sx * sy) + y * sx + x) * 4; + Color col = value_tex3d->getPixel(x, y, z); + pixel[0] = (float)col.r; + pixel[1] = (float)col.g; + pixel[2] = (float)col.b; + pixel[3] = (float)col.a; + } + } + } + + functions->glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, sx, sy, sz, 0, GL_RGBA, GL_FLOAT, pixels); + delete[] pixels; + } + else + { + int sx, sy, sz, sw; + value_tex4d->getSize(&sx, &sy, &sz, &sw); + float* pixels = new float[sx * sy * sz * sw * 4]; + for (int x = 0; x < sx; x++) + { + for (int y = 0; y < sy; y++) + { + for (int z = 0; z < sz; z++) + { + for (int w = 0; w < sw; w++) + { + float* pixel = pixels + (w * (sx * sy * sz) + z * (sx * sy) + y * sx + x) * 4; + Color col = value_tex4d->getPixel(x, y, z, w); + pixel[0] = (float)col.r; + pixel[1] = (float)col.g; + pixel[2] = (float)col.b; + pixel[3] = (float)col.a; + } + } + } + } + + functions->glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, sx, sy, sz * sw, 0, GL_RGBA, GL_FLOAT, pixels); + delete[] pixels; + } +} diff --git a/src/render/opengl/OpenGLVariable.h b/src/render/opengl/OpenGLVariable.h index 0fc633c..07a7f29 100644 --- a/src/render/opengl/OpenGLVariable.h +++ b/src/render/opengl/OpenGLVariable.h @@ -30,7 +30,7 @@ public: public: OpenGLVariable(const std::string &name); - void apply(OpenGLShaderProgram *program); + void apply(OpenGLShaderProgram *program, int &texture_unit); void set(const Texture2D *texture); void set(const Texture3D *texture); @@ -42,6 +42,9 @@ public: void set(const QMatrix4x4 &matrix); void set(const Color &color); +protected: + void uploadTexture(OpenGLRenderer* renderer); + private: std::string name; OpenGLVariableType type; @@ -50,6 +53,12 @@ private: QColor value_color; QVector3D value_vector3; QMatrix4x4 value_matrix4; + const Texture2D* value_tex2d; + const Texture3D* value_tex3d; + const Texture4D* value_tex4d; + + bool texture_toupload; + unsigned int texture_id; }; } From 39789aea3f2314f26859524fed897fa86201fe92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Lemaire?= Date: Sun, 22 Dec 2013 18:47:24 +0100 Subject: [PATCH 08/17] Allow shaders source code to be split in several files (and thus included) --- src/render/opengl/OpenGLPart.cpp | 10 - src/render/opengl/OpenGLPart.h | 1 - src/render/opengl/OpenGLShaderProgram.cpp | 33 +++- src/render/opengl/OpenGLShaderProgram.h | 7 +- src/render/opengl/OpenGLSkybox.cpp | 2 + src/render/opengl/OpenGLWater.cpp | 2 + src/render/opengl/opengl.pro | 4 +- src/render/opengl/shaders/bruneton.frag | 188 ++++++++++++++++++ src/render/opengl/shaders/resources.qrc | 2 + src/render/opengl/shaders/skybox.frag | 215 --------------------- src/render/opengl/shaders/tonemapping.frag | 25 +++ src/render/opengl/shaders/water.frag | 215 --------------------- src/system/Logs.h | 2 +- 13 files changed, 259 insertions(+), 447 deletions(-) create mode 100644 src/render/opengl/shaders/bruneton.frag create mode 100644 src/render/opengl/shaders/tonemapping.frag diff --git a/src/render/opengl/OpenGLPart.cpp b/src/render/opengl/OpenGLPart.cpp index 2e313d5..807f8cf 100644 --- a/src/render/opengl/OpenGLPart.cpp +++ b/src/render/opengl/OpenGLPart.cpp @@ -39,16 +39,6 @@ OpenGLShaderProgram* OpenGLPart::createShader(QString name) } } -void OpenGLPart::postInitialize() -{ - QMapIterator i(shaders); - while (i.hasNext()) - { - i.next(); - i.value()->compile(); - } -} - void OpenGLPart::updateScenery(bool onlyCommon) { // Let subclass do its own collecting diff --git a/src/render/opengl/OpenGLPart.h b/src/render/opengl/OpenGLPart.h index 84ef432..906ad7c 100644 --- a/src/render/opengl/OpenGLPart.h +++ b/src/render/opengl/OpenGLPart.h @@ -26,7 +26,6 @@ public: // Do the rendering virtual void render() = 0; - void postInitialize(); void updateScenery(bool onlyCommon=false); protected: diff --git a/src/render/opengl/OpenGLShaderProgram.cpp b/src/render/opengl/OpenGLShaderProgram.cpp index 03289a3..dc326a1 100644 --- a/src/render/opengl/OpenGLShaderProgram.cpp +++ b/src/render/opengl/OpenGLShaderProgram.cpp @@ -9,12 +9,14 @@ #include "Texture3D.h" #include "Texture4D.h" #include "Color.h" +#include "Logs.h" OpenGLShaderProgram::OpenGLShaderProgram(QString name, OpenGLRenderer* renderer): renderer(renderer), name(name) { program = new QOpenGLShaderProgram(); functions = renderer->getOpenGlFunctions(); + compiled = false; } OpenGLShaderProgram::~OpenGLShaderProgram() @@ -24,21 +26,40 @@ OpenGLShaderProgram::~OpenGLShaderProgram() void OpenGLShaderProgram::addVertexSource(QString path) { - program->addShaderFromSourceFile(QOpenGLShader::Vertex, QString(":/shaders/%1.vert").arg(path)); + QFile file(QString(":/shaders/%1.vert").arg(path)); + if (file.open(QIODevice::ReadOnly | QIODevice::Text)) + { + source_vertex += QString(file.readAll()).toStdString(); + } + else + { + logError() << "Can't open vertex file " << file.fileName(); + } } void OpenGLShaderProgram::addFragmentSource(QString path) { - program->addShaderFromSourceFile(QOpenGLShader::Fragment, QString(":/shaders/%1.frag").arg(path)); + QFile file(QString(":/shaders/%1.frag").arg(path)); + if (file.open(QIODevice::ReadOnly | QIODevice::Text)) + { + source_fragment += QString(file.readAll()).toStdString(); + } + else + { + logError("Can't open fragment file %s", file.fileName().toStdString().c_str()); + } } void OpenGLShaderProgram::compile() { + program->addShaderFromSourceCode(QOpenGLShader::Vertex, QString::fromStdString(source_vertex)); + program->addShaderFromSourceCode(QOpenGLShader::Fragment, QString::fromStdString(source_fragment)); + if (not program->link()) { qWarning() << "Error while compiling shader " << name << "\n" << program->log() << "\n"; } - else + else if (program->log().length() > 0) { qDebug() << "Shader " << name << " compilation output:\n" << program->log() << "\n"; } @@ -46,6 +67,12 @@ void OpenGLShaderProgram::compile() void OpenGLShaderProgram::bind() { + if (not compiled) + { + compile(); + compiled = true; + } + program->bind(); int texture_unit = 0; diff --git a/src/render/opengl/OpenGLShaderProgram.h b/src/render/opengl/OpenGLShaderProgram.h index fa4d5c1..2b4bfd1 100644 --- a/src/render/opengl/OpenGLShaderProgram.h +++ b/src/render/opengl/OpenGLShaderProgram.h @@ -19,7 +19,6 @@ public: void addVertexSource(QString path); void addFragmentSource(QString path); - void compile(); void drawTriangles(float* vertices, int triangle_count); void drawTriangleStrip(float* vertices, int vertex_count); @@ -30,14 +29,20 @@ protected: friend class OpenGLVariable; private: + void compile(); void bind(); void release(); + bool compiled; + OpenGLRenderer* renderer; QString name; QOpenGLShaderProgram* program; QOpenGLFunctions_3_2_Core* functions; + + std::string source_vertex; + std::string source_fragment; }; } diff --git a/src/render/opengl/OpenGLSkybox.cpp b/src/render/opengl/OpenGLSkybox.cpp index bc6376a..3f0b2dd 100644 --- a/src/render/opengl/OpenGLSkybox.cpp +++ b/src/render/opengl/OpenGLSkybox.cpp @@ -25,6 +25,8 @@ void OpenGLSkybox::initialize() { program = createShader("skybox"); program->addVertexSource("skybox"); + program->addFragmentSource("bruneton"); + program->addFragmentSource("tonemapping"); program->addFragmentSource("skybox"); setVertex(0, 1.0f, 1.0f, 1.0f); diff --git a/src/render/opengl/OpenGLWater.cpp b/src/render/opengl/OpenGLWater.cpp index 3c88c23..dddf6ec 100644 --- a/src/render/opengl/OpenGLWater.cpp +++ b/src/render/opengl/OpenGLWater.cpp @@ -20,6 +20,8 @@ void OpenGLWater::initialize() { program = createShader("water"); program->addVertexSource("water"); + program->addFragmentSource("bruneton"); + program->addFragmentSource("tonemapping"); program->addFragmentSource("water"); setVertex(0, -1.0f, 0.0f, -1.0f); diff --git a/src/render/opengl/opengl.pro b/src/render/opengl/opengl.pro index b341939..17807eb 100644 --- a/src/render/opengl/opengl.pro +++ b/src/render/opengl/opengl.pro @@ -79,4 +79,6 @@ OTHER_FILES += \ shaders/skybox.vert \ shaders/water.vert \ shaders/water.frag \ - shaders/bruneton.frag + shaders/bruneton.frag \ + shaders/bruneton.frag \ + shaders/tonemapping.frag diff --git a/src/render/opengl/shaders/bruneton.frag b/src/render/opengl/shaders/bruneton.frag new file mode 100644 index 0000000..ec61346 --- /dev/null +++ b/src/render/opengl/shaders/bruneton.frag @@ -0,0 +1,188 @@ +const float GROUND_OFFSET = 0.5; +const float Rg = 6360.0; +const float Rt = 6420.0; +const float RL = 6421.0; +const float exposure = 0.4; +const float ISun = 100.0; +const float AVERAGE_GROUND_REFLECTANCE = 0.1; +const float HR = 8.0; +const vec3 betaR = vec3(5.8e-3, 1.35e-2, 3.31e-2); +const float HM = 1.2; +const vec3 betaMSca = vec3(4e-3); +const vec3 betaMEx = vec3(4e-3 / 0.9); +const float mieG = 0.8; +const float SPHERE_SIZE = 20000.0; +const float WORLD_SCALING = 0.05; +const float SUN_DISTANCE = 149597870.0; +const float SUN_DISTANCE_SCALED = (SUN_DISTANCE / WORLD_SCALING); +const float SUN_RADIUS = 6.955e5; +const float SUN_RADIUS_SCALED = (SUN_RADIUS / WORLD_SCALING); +const float M_PI = 3.141592657; + +const int RES_MU = 128; +const int RES_MU_S = 32; +const int RES_R = 32; +const int RES_NU = 8; + +uniform float waterHeight; +uniform vec3 cameraLocation; +uniform vec3 sunDirection; +uniform vec4 sunColor; +const float sunRadius = 1.0; // TODO -> uniform + +varying vec3 unprojected; + +uniform sampler2D transmittanceTexture; +uniform sampler3D inscatterTexture; + +vec4 texture4D(sampler3D tex, float r, float mu, float muS, float nu) +{ + if (r < Rg + 0.00000001) r = Rg + 0.00000001; + float H = sqrt(Rt * Rt - Rg * Rg); + float rho = sqrt(r * r - Rg * Rg); + float rmu = r * mu; + float delta = rmu * rmu - r * r + Rg * Rg; + vec4 cst = (rmu < 0.0 && delta > 0.0) ? vec4(1.0, 0.0, 0.0, 0.5 - 0.5 / float(RES_MU)) : vec4(-1.0, H * H, H, 0.5 + 0.5 / float(RES_MU)); + float uR = 0.5 / float(RES_R) + rho / H * (1.0 - 1.0 / float(RES_R)); + float uMu = cst.a + (rmu * cst.r + sqrt(delta + cst.g)) / (rho + cst.b) * (0.5 - 1.0 / float(RES_MU)); + float uMuS = 0.5 / float(RES_MU_S) + (atan(max(muS, -0.1975) * tan(1.26 * 1.1)) / 1.1 + (1.0 - 0.26)) * 0.5 * (1.0 - 1.0 / float(RES_MU_S)); + + float sr = 1.0 / float(RES_R); + int br = int(floor(uR / sr)); + vec4 r1 = texture3D(tex, vec3(uMu, uMuS, float(br) * sr + nu * sr)); + vec4 r2 = texture3D(tex, vec3(uMu, uMuS, float(br + 1) * sr + nu * sr)); + return mix(r1, r2, (uR - float(br) * sr) / sr); +} + +float _limit(float r, float mu) +{ + float dout = -r * mu + sqrt(r * r * (mu * mu - 1.0) + RL * RL); + float delta2 = r * r * (mu * mu - 1.0) + Rg * Rg; + if (delta2 >= 0.0) + { + float din = -r * mu - sqrt(delta2); + if (din >= 0.0) { + dout = min(dout, din); + } + } + return dout; +} + +vec2 _getTransmittanceUV(float r, float mu) +{ + if (r < Rg + 0.00000001) r = Rg + 0.00000001; + float dr = (r - Rg) / (Rt - Rg); + return vec2(atan((mu + 0.15) / (1.0 + 0.15) * tan(1.5)) / 1.5, sqrt(dr)); +} + +vec4 _transmittance(float r, float mu) +{ + vec2 uv = _getTransmittanceUV(r, mu); + return texture2D(transmittanceTexture, uv); +} + +vec4 _transmittanceWithShadow(float r, float mu) +{ + return mu < -sqrt(1.0 - (Rg / r) * (Rg / r)) ? vec4(0.0) : _transmittance(r, mu); +} + +vec4 _sunTransmittance(vec3 v, vec3 s, float r, float mu, float radius) +{ + vec4 transmittance = r <= Rt ? _transmittanceWithShadow(r, mu) : vec4(1.0); /* T(x,xo) */ + float d = _limit(r, mu); + radius *= (1.0 + 10.0 * d / Rt); /* Inflating due to lens effect near horizon */ + float isun = step(cos(radius * M_PI / 180.0), dot(v, s)) * ISun; /* Lsun */ + transmittance.r *= isun; + transmittance.g *= isun; + transmittance.b *= isun; + transmittance.a = 1.0; + return transmittance; /* Eq (9) */ +} + +float phaseFunctionR(float mu) { + return (3.0 / (16.0 * M_PI)) * (1.0 + mu * mu); +} + +float phaseFunctionM(float mu) { + return 1.5 * 1.0 / (4.0 * M_PI) * (1.0 - mieG*mieG) * pow(1.0 + (mieG*mieG) - 2.0*mieG*mu, -3.0/2.0) * (1.0 + mu * mu) / (2.0 + mieG*mieG); +} + +float opticalDepth(float H, float r, float mu, float d) { + float a = sqrt((0.5/H)*r); + vec2 a01 = a*vec2(mu, mu + d / r); + vec2 a01s = sign(a01); + vec2 a01sq = a01*a01; + float x = a01s.y > a01s.x ? exp(a01sq.x) : 0.0; + vec2 y = a01s / (2.3193*abs(a01) + sqrt(1.52*a01sq + 4.0)) * vec2(1.0, exp(-d/H*(d/(2.0*r)+mu))); + return sqrt((6.2831*H)*r) * exp((Rg-r)/H) * (x + dot(y, vec2(1.0, -1.0))); +} + +vec3 analyticTransmittance(float r, float mu, float d) { + return exp(- betaR * opticalDepth(HR, r, mu, d) - betaMEx * opticalDepth(HM, r, mu, d)); +} + +vec3 getMie(vec4 rayMie) { // rayMie.rgb=C*, rayMie.w=Cm,r + return rayMie.rgb * rayMie.w / max(rayMie.r, 1e-4) * (betaR.r / betaR); +} + +vec3 _getInscatterColor(inout vec3 x, inout float t, vec3 v, vec3 s, out float r, out float mu, out vec3 attenuation) { + vec3 result; + r = length(x); + mu = dot(x, v) / r; + float d = -r * mu - sqrt(r * r * (mu * mu - 1.0) + Rt * Rt); + if (d > 0.0) { // if x in space and ray intersects atmosphere + // move x to nearest intersection of ray with top atmosphere boundary + x += d * v; + t -= d; + mu = (r * mu + d) / Rt; + r = Rt; + } + if (r <= Rt) { // if ray intersects atmosphere + float nu = dot(v, s); + float muS = dot(x, s) / r; + float phaseR = phaseFunctionR(nu); + float phaseM = phaseFunctionM(nu); + vec4 inscatter = max(texture4D(inscatterTexture, r, mu, muS, nu), 0.0); + if (t > 0.0) { + vec3 x0 = x + t * v; + float r0 = length(x0); + float rMu0 = dot(x0, v); + float mu0 = rMu0 / r0; + float muS0 = dot(x0, s) / r0; + // avoids imprecision problems in transmittance computations based on textures + attenuation = analyticTransmittance(r, mu, t); + if (r0 > Rg + 0.001) { + // computes S[L]-T(x,x0)S[L]|x0 + inscatter = max(inscatter - attenuation.rgbr * texture4D(inscatterTexture, r0, mu0, muS0, nu), 0.0); + // avoids imprecision problems near horizon by interpolating between two points above and below horizon + const float EPS = 0.02; + float muHoriz = -sqrt(1.0 - (Rg / r) * (Rg / r)); + if (abs(mu - muHoriz) < EPS) { + float a = ((mu - muHoriz) + EPS) / (2.0 * EPS); + + mu = muHoriz - EPS; + r0 = sqrt(r * r + t * t + 2.0 * r * t * mu); + mu0 = (r * mu + t) / r0; + vec4 inScatter0 = texture4D(inscatterTexture, r, mu, muS, nu); + vec4 inScatter1 = texture4D(inscatterTexture, r0, mu0, muS0, nu); + vec4 inScatterA = max(inScatter0 - attenuation.rgbr * inScatter1, 0.0); + + mu = muHoriz + EPS; + r0 = sqrt(r * r + t * t + 2.0 * r * t * mu); + mu0 = (r * mu + t) / r0; + inScatter0 = texture4D(inscatterTexture, r, mu, muS, nu); + inScatter1 = texture4D(inscatterTexture, r0, mu0, muS0, nu); + vec4 inScatterB = max(inScatter0 - attenuation.rgbr * inScatter1, 0.0); + + inscatter = mix(inScatterA, inScatterB, a); + } + } + } + // avoids imprecision problems in Mie scattering when sun is below horizon + inscatter.w *= smoothstep(0.00, 0.02, muS); + result = max(inscatter.rgb * phaseR + getMie(inscatter) * phaseM, 0.0); + } else { // x in space and ray looking in space + result = vec3(0.0); + } + return result * ISun; +} diff --git a/src/render/opengl/shaders/resources.qrc b/src/render/opengl/shaders/resources.qrc index 5d1b756..761c28b 100644 --- a/src/render/opengl/shaders/resources.qrc +++ b/src/render/opengl/shaders/resources.qrc @@ -4,5 +4,7 @@ skybox.vert water.frag water.vert + bruneton.frag + tonemapping.frag diff --git a/src/render/opengl/shaders/skybox.frag b/src/render/opengl/shaders/skybox.frag index 6ab26cc..cbb700b 100644 --- a/src/render/opengl/shaders/skybox.frag +++ b/src/render/opengl/shaders/skybox.frag @@ -1,218 +1,3 @@ -const float GROUND_OFFSET = 0.5; -const float Rg = 6360.0; -const float Rt = 6420.0; -const float RL = 6421.0; -const float exposure = 0.4; -const float ISun = 100.0; -const float AVERAGE_GROUND_REFLECTANCE = 0.1; -const float HR = 8.0; -const vec3 betaR = vec3(5.8e-3, 1.35e-2, 3.31e-2); -const float HM = 1.2; -const vec3 betaMSca = vec3(4e-3); -const vec3 betaMEx = vec3(4e-3 / 0.9); -const float mieG = 0.8; -const float SPHERE_SIZE = 20000.0; -const float WORLD_SCALING = 0.05; -const float SUN_DISTANCE = 149597870.0; -const float SUN_DISTANCE_SCALED = (SUN_DISTANCE / WORLD_SCALING); -const float SUN_RADIUS = 6.955e5; -const float SUN_RADIUS_SCALED = (SUN_RADIUS / WORLD_SCALING); -const float M_PI = 3.141592657; - -const int RES_MU = 128; -const int RES_MU_S = 32; -const int RES_R = 32; -const int RES_NU = 8; - -uniform float waterHeight; -uniform vec3 cameraLocation; -uniform vec3 sunDirection; -uniform vec4 sunColor; -const float sunRadius = 1.0; // TODO -> uniform - -varying vec3 unprojected; - -uniform sampler2D transmittanceTexture; -uniform sampler3D inscatterTexture; - -vec4 texture4D(sampler3D tex, float r, float mu, float muS, float nu) -{ - if (r < Rg + 0.00000001) r = Rg + 0.00000001; - float H = sqrt(Rt * Rt - Rg * Rg); - float rho = sqrt(r * r - Rg * Rg); - float rmu = r * mu; - float delta = rmu * rmu - r * r + Rg * Rg; - vec4 cst = (rmu < 0.0 && delta > 0.0) ? vec4(1.0, 0.0, 0.0, 0.5 - 0.5 / float(RES_MU)) : vec4(-1.0, H * H, H, 0.5 + 0.5 / float(RES_MU)); - float uR = 0.5 / float(RES_R) + rho / H * (1.0 - 1.0 / float(RES_R)); - float uMu = cst.a + (rmu * cst.r + sqrt(delta + cst.g)) / (rho + cst.b) * (0.5 - 1.0 / float(RES_MU)); - float uMuS = 0.5 / float(RES_MU_S) + (atan(max(muS, -0.1975) * tan(1.26 * 1.1)) / 1.1 + (1.0 - 0.26)) * 0.5 * (1.0 - 1.0 / float(RES_MU_S)); - - float sr = 1.0 / float(RES_R); - int br = int(floor(uR / sr)); - vec4 r1 = texture3D(tex, vec3(uMu, uMuS, float(br) * sr + nu * sr)); - vec4 r2 = texture3D(tex, vec3(uMu, uMuS, float(br + 1) * sr + nu * sr)); - return mix(r1, r2, (uR - float(br) * sr) / sr); -} - -float _limit(float r, float mu) -{ - float dout = -r * mu + sqrt(r * r * (mu * mu - 1.0) + RL * RL); - float delta2 = r * r * (mu * mu - 1.0) + Rg * Rg; - if (delta2 >= 0.0) - { - float din = -r * mu - sqrt(delta2); - if (din >= 0.0) { - dout = min(dout, din); - } - } - return dout; -} - -vec2 _getTransmittanceUV(float r, float mu) -{ - if (r < Rg + 0.00000001) r = Rg + 0.00000001; - float dr = (r - Rg) / (Rt - Rg); - return vec2(atan((mu + 0.15) / (1.0 + 0.15) * tan(1.5)) / 1.5, sqrt(dr)); -} - -vec4 _transmittance(float r, float mu) -{ - vec2 uv = _getTransmittanceUV(r, mu); - return texture2D(transmittanceTexture, uv); -} - -vec4 _transmittanceWithShadow(float r, float mu) -{ - return mu < -sqrt(1.0 - (Rg / r) * (Rg / r)) ? vec4(0.0) : _transmittance(r, mu); -} - -vec4 _sunTransmittance(vec3 v, vec3 s, float r, float mu, float radius) -{ - vec4 transmittance = r <= Rt ? _transmittanceWithShadow(r, mu) : vec4(1.0); /* T(x,xo) */ - float d = _limit(r, mu); - radius *= (1.0 + 10.0 * d / Rt); /* Inflating due to lens effect near horizon */ - float isun = step(cos(radius * M_PI / 180.0), dot(v, s)) * ISun; /* Lsun */ - transmittance.r *= isun; - transmittance.g *= isun; - transmittance.b *= isun; - transmittance.a = 1.0; - return transmittance; /* Eq (9) */ -} - -float phaseFunctionR(float mu) { - return (3.0 / (16.0 * M_PI)) * (1.0 + mu * mu); -} - -float phaseFunctionM(float mu) { - return 1.5 * 1.0 / (4.0 * M_PI) * (1.0 - mieG*mieG) * pow(1.0 + (mieG*mieG) - 2.0*mieG*mu, -3.0/2.0) * (1.0 + mu * mu) / (2.0 + mieG*mieG); -} - -float opticalDepth(float H, float r, float mu, float d) { - float a = sqrt((0.5/H)*r); - vec2 a01 = a*vec2(mu, mu + d / r); - vec2 a01s = sign(a01); - vec2 a01sq = a01*a01; - float x = a01s.y > a01s.x ? exp(a01sq.x) : 0.0; - vec2 y = a01s / (2.3193*abs(a01) + sqrt(1.52*a01sq + 4.0)) * vec2(1.0, exp(-d/H*(d/(2.0*r)+mu))); - return sqrt((6.2831*H)*r) * exp((Rg-r)/H) * (x + dot(y, vec2(1.0, -1.0))); -} - -vec3 analyticTransmittance(float r, float mu, float d) { - return exp(- betaR * opticalDepth(HR, r, mu, d) - betaMEx * opticalDepth(HM, r, mu, d)); -} - -vec3 getMie(vec4 rayMie) { // rayMie.rgb=C*, rayMie.w=Cm,r - return rayMie.rgb * rayMie.w / max(rayMie.r, 1e-4) * (betaR.r / betaR); -} - -vec3 _getInscatterColor(inout vec3 x, inout float t, vec3 v, vec3 s, out float r, out float mu, out vec3 attenuation) { - vec3 result; - r = length(x); - mu = dot(x, v) / r; - float d = -r * mu - sqrt(r * r * (mu * mu - 1.0) + Rt * Rt); - if (d > 0.0) { // if x in space and ray intersects atmosphere - // move x to nearest intersection of ray with top atmosphere boundary - x += d * v; - t -= d; - mu = (r * mu + d) / Rt; - r = Rt; - } - if (r <= Rt) { // if ray intersects atmosphere - float nu = dot(v, s); - float muS = dot(x, s) / r; - float phaseR = phaseFunctionR(nu); - float phaseM = phaseFunctionM(nu); - vec4 inscatter = max(texture4D(inscatterTexture, r, mu, muS, nu), 0.0); - if (t > 0.0) { - vec3 x0 = x + t * v; - float r0 = length(x0); - float rMu0 = dot(x0, v); - float mu0 = rMu0 / r0; - float muS0 = dot(x0, s) / r0; - // avoids imprecision problems in transmittance computations based on textures - attenuation = analyticTransmittance(r, mu, t); - if (r0 > Rg + 0.001) { - // computes S[L]-T(x,x0)S[L]|x0 - inscatter = max(inscatter - attenuation.rgbr * texture4D(inscatterTexture, r0, mu0, muS0, nu), 0.0); - // avoids imprecision problems near horizon by interpolating between two points above and below horizon - const float EPS = 0.02; - float muHoriz = -sqrt(1.0 - (Rg / r) * (Rg / r)); - if (abs(mu - muHoriz) < EPS) { - float a = ((mu - muHoriz) + EPS) / (2.0 * EPS); - - mu = muHoriz - EPS; - r0 = sqrt(r * r + t * t + 2.0 * r * t * mu); - mu0 = (r * mu + t) / r0; - vec4 inScatter0 = texture4D(inscatterTexture, r, mu, muS, nu); - vec4 inScatter1 = texture4D(inscatterTexture, r0, mu0, muS0, nu); - vec4 inScatterA = max(inScatter0 - attenuation.rgbr * inScatter1, 0.0); - - mu = muHoriz + EPS; - r0 = sqrt(r * r + t * t + 2.0 * r * t * mu); - mu0 = (r * mu + t) / r0; - inScatter0 = texture4D(inscatterTexture, r, mu, muS, nu); - inScatter1 = texture4D(inscatterTexture, r0, mu0, muS0, nu); - vec4 inScatterB = max(inScatter0 - attenuation.rgbr * inScatter1, 0.0); - - inscatter = mix(inScatterA, inScatterB, a); - } - } - } - // avoids imprecision problems in Mie scattering when sun is below horizon - inscatter.w *= smoothstep(0.00, 0.02, muS); - result = max(inscatter.rgb * phaseR + getMie(inscatter) * phaseM, 0.0); - } else { // x in space and ray looking in space - result = vec3(0.0); - } - return result * ISun; -} - -float _uncharted2Tonemap(float x) -{ - float A = 0.15; - float B = 0.50; - float C = 0.10; - float D = 0.20; - float E = 0.02; - float F = 0.30; - - return ((x * (A * x + C * B) + D * E) / (x * (A * x + B) + D * F)) - E / F; -} - -vec4 _toneMappingUncharted(vec4 color, float exposure) -{ - float W = 11.2; - float white_scale = 1.0 / _uncharted2Tonemap(W); - vec4 result; - - result.r = pow(_uncharted2Tonemap(color.r * exposure) * white_scale, 1.0 / 2.2); - result.g = pow(_uncharted2Tonemap(color.g * exposure) * white_scale, 1.0 / 2.2); - result.b = pow(_uncharted2Tonemap(color.b * exposure) * white_scale, 1.0 / 2.2); - result.a = 1.0; - - return result; -} - void main(void) { float yoffset = GROUND_OFFSET - waterHeight; diff --git a/src/render/opengl/shaders/tonemapping.frag b/src/render/opengl/shaders/tonemapping.frag new file mode 100644 index 0000000..89f9f19 --- /dev/null +++ b/src/render/opengl/shaders/tonemapping.frag @@ -0,0 +1,25 @@ +float _uncharted2Tonemap(float x) +{ + float A = 0.15; + float B = 0.50; + float C = 0.10; + float D = 0.20; + float E = 0.02; + float F = 0.30; + + return ((x * (A * x + C * B) + D * E) / (x * (A * x + B) + D * F)) - E / F; +} + +vec4 _toneMappingUncharted(vec4 color, float exposure) +{ + float W = 11.2; + float white_scale = 1.0 / _uncharted2Tonemap(W); + vec4 result; + + result.r = pow(_uncharted2Tonemap(color.r * exposure) * white_scale, 1.0 / 2.2); + result.g = pow(_uncharted2Tonemap(color.g * exposure) * white_scale, 1.0 / 2.2); + result.b = pow(_uncharted2Tonemap(color.b * exposure) * white_scale, 1.0 / 2.2); + result.a = 1.0; + + return result; +} diff --git a/src/render/opengl/shaders/water.frag b/src/render/opengl/shaders/water.frag index 61982e4..9ef198a 100644 --- a/src/render/opengl/shaders/water.frag +++ b/src/render/opengl/shaders/water.frag @@ -1,218 +1,3 @@ -const float GROUND_OFFSET = 0.5; -const float Rg = 6360.0; -const float Rt = 6420.0; -const float RL = 6421.0; -const float exposure = 0.4; -const float ISun = 100.0; -const float AVERAGE_GROUND_REFLECTANCE = 0.1; -const float HR = 8.0; -const vec3 betaR = vec3(5.8e-3, 1.35e-2, 3.31e-2); -const float HM = 1.2; -const vec3 betaMSca = vec3(4e-3); -const vec3 betaMEx = vec3(4e-3 / 0.9); -const float mieG = 0.8; -const float SPHERE_SIZE = 20000.0; -const float WORLD_SCALING = 0.05; -const float SUN_DISTANCE = 149597870.0; -const float SUN_DISTANCE_SCALED = (SUN_DISTANCE / WORLD_SCALING); -const float SUN_RADIUS = 6.955e5; -const float SUN_RADIUS_SCALED = (SUN_RADIUS / WORLD_SCALING); -const float M_PI = 3.141592657; - -const int RES_MU = 128; -const int RES_MU_S = 32; -const int RES_R = 32; -const int RES_NU = 8; - -uniform float waterHeight; -uniform vec3 cameraLocation; -uniform vec3 sunDirection; -uniform vec4 sunColor; -const float sunRadius = 1.0; // TODO -> uniform - -varying vec3 unprojected; - -uniform sampler2D transmittanceTexture; -uniform sampler3D inscatterTexture; - -vec4 texture4D(sampler3D tex, float r, float mu, float muS, float nu) -{ - if (r < Rg + 0.00000001) r = Rg + 0.00000001; - float H = sqrt(Rt * Rt - Rg * Rg); - float rho = sqrt(r * r - Rg * Rg); - float rmu = r * mu; - float delta = rmu * rmu - r * r + Rg * Rg; - vec4 cst = (rmu < 0.0 && delta > 0.0) ? vec4(1.0, 0.0, 0.0, 0.5 - 0.5 / float(RES_MU)) : vec4(-1.0, H * H, H, 0.5 + 0.5 / float(RES_MU)); - float uR = 0.5 / float(RES_R) + rho / H * (1.0 - 1.0 / float(RES_R)); - float uMu = cst.a + (rmu * cst.r + sqrt(delta + cst.g)) / (rho + cst.b) * (0.5 - 1.0 / float(RES_MU)); - float uMuS = 0.5 / float(RES_MU_S) + (atan(max(muS, -0.1975) * tan(1.26 * 1.1)) / 1.1 + (1.0 - 0.26)) * 0.5 * (1.0 - 1.0 / float(RES_MU_S)); - - float sr = 1.0 / float(RES_R); - int br = int(floor(uR / sr)); - vec4 r1 = texture3D(tex, vec3(uMu, uMuS, float(br) * sr + nu * sr)); - vec4 r2 = texture3D(tex, vec3(uMu, uMuS, float(br + 1) * sr + nu * sr)); - return mix(r1, r2, (uR - float(br) * sr) / sr); -} - -float _limit(float r, float mu) -{ - float dout = -r * mu + sqrt(r * r * (mu * mu - 1.0) + RL * RL); - float delta2 = r * r * (mu * mu - 1.0) + Rg * Rg; - if (delta2 >= 0.0) - { - float din = -r * mu - sqrt(delta2); - if (din >= 0.0) { - dout = min(dout, din); - } - } - return dout; -} - -vec2 _getTransmittanceUV(float r, float mu) -{ - if (r < Rg + 0.00000001) r = Rg + 0.00000001; - float dr = (r - Rg) / (Rt - Rg); - return vec2(atan((mu + 0.15) / (1.0 + 0.15) * tan(1.5)) / 1.5, sqrt(dr)); -} - -vec4 _transmittance(float r, float mu) -{ - vec2 uv = _getTransmittanceUV(r, mu); - return texture2D(transmittanceTexture, uv); -} - -vec4 _transmittanceWithShadow(float r, float mu) -{ - return mu < -sqrt(1.0 - (Rg / r) * (Rg / r)) ? vec4(0.0) : _transmittance(r, mu); -} - -vec4 _sunTransmittance(vec3 v, vec3 s, float r, float mu, float radius) -{ - vec4 transmittance = r <= Rt ? _transmittanceWithShadow(r, mu) : vec4(1.0); /* T(x,xo) */ - float d = _limit(r, mu); - radius *= (1.0 + 10.0 * d / Rt); /* Inflating due to lens effect near horizon */ - float isun = step(cos(radius * M_PI / 180.0), dot(v, s)) * ISun; /* Lsun */ - transmittance.r *= isun; - transmittance.g *= isun; - transmittance.b *= isun; - transmittance.a = 1.0; - return transmittance; /* Eq (9) */ -} - -float phaseFunctionR(float mu) { - return (3.0 / (16.0 * M_PI)) * (1.0 + mu * mu); -} - -float phaseFunctionM(float mu) { - return 1.5 * 1.0 / (4.0 * M_PI) * (1.0 - mieG*mieG) * pow(1.0 + (mieG*mieG) - 2.0*mieG*mu, -3.0/2.0) * (1.0 + mu * mu) / (2.0 + mieG*mieG); -} - -float opticalDepth(float H, float r, float mu, float d) { - float a = sqrt((0.5/H)*r); - vec2 a01 = a*vec2(mu, mu + d / r); - vec2 a01s = sign(a01); - vec2 a01sq = a01*a01; - float x = a01s.y > a01s.x ? exp(a01sq.x) : 0.0; - vec2 y = a01s / (2.3193*abs(a01) + sqrt(1.52*a01sq + 4.0)) * vec2(1.0, exp(-d/H*(d/(2.0*r)+mu))); - return sqrt((6.2831*H)*r) * exp((Rg-r)/H) * (x + dot(y, vec2(1.0, -1.0))); -} - -vec3 analyticTransmittance(float r, float mu, float d) { - return exp(- betaR * opticalDepth(HR, r, mu, d) - betaMEx * opticalDepth(HM, r, mu, d)); -} - -vec3 getMie(vec4 rayMie) { // rayMie.rgb=C*, rayMie.w=Cm,r - return rayMie.rgb * rayMie.w / max(rayMie.r, 1e-4) * (betaR.r / betaR); -} - -vec3 _getInscatterColor(inout vec3 x, inout float t, vec3 v, vec3 s, out float r, out float mu, out vec3 attenuation) { - vec3 result; - r = length(x); - mu = dot(x, v) / r; - float d = -r * mu - sqrt(r * r * (mu * mu - 1.0) + Rt * Rt); - if (d > 0.0) { // if x in space and ray intersects atmosphere - // move x to nearest intersection of ray with top atmosphere boundary - x += d * v; - t -= d; - mu = (r * mu + d) / Rt; - r = Rt; - } - if (r <= Rt) { // if ray intersects atmosphere - float nu = dot(v, s); - float muS = dot(x, s) / r; - float phaseR = phaseFunctionR(nu); - float phaseM = phaseFunctionM(nu); - vec4 inscatter = max(texture4D(inscatterTexture, r, mu, muS, nu), 0.0); - if (t > 0.0) { - vec3 x0 = x + t * v; - float r0 = length(x0); - float rMu0 = dot(x0, v); - float mu0 = rMu0 / r0; - float muS0 = dot(x0, s) / r0; - // avoids imprecision problems in transmittance computations based on textures - attenuation = analyticTransmittance(r, mu, t); - if (r0 > Rg + 0.001) { - // computes S[L]-T(x,x0)S[L]|x0 - inscatter = max(inscatter - attenuation.rgbr * texture4D(inscatterTexture, r0, mu0, muS0, nu), 0.0); - // avoids imprecision problems near horizon by interpolating between two points above and below horizon - const float EPS = 0.02; - float muHoriz = -sqrt(1.0 - (Rg / r) * (Rg / r)); - if (abs(mu - muHoriz) < EPS) { - float a = ((mu - muHoriz) + EPS) / (2.0 * EPS); - - mu = muHoriz - EPS; - r0 = sqrt(r * r + t * t + 2.0 * r * t * mu); - mu0 = (r * mu + t) / r0; - vec4 inScatter0 = texture4D(inscatterTexture, r, mu, muS, nu); - vec4 inScatter1 = texture4D(inscatterTexture, r0, mu0, muS0, nu); - vec4 inScatterA = max(inScatter0 - attenuation.rgbr * inScatter1, 0.0); - - mu = muHoriz + EPS; - r0 = sqrt(r * r + t * t + 2.0 * r * t * mu); - mu0 = (r * mu + t) / r0; - inScatter0 = texture4D(inscatterTexture, r, mu, muS, nu); - inScatter1 = texture4D(inscatterTexture, r0, mu0, muS0, nu); - vec4 inScatterB = max(inScatter0 - attenuation.rgbr * inScatter1, 0.0); - - inscatter = mix(inScatterA, inScatterB, a); - } - } - } - // avoids imprecision problems in Mie scattering when sun is below horizon - inscatter.w *= smoothstep(0.00, 0.02, muS); - result = max(inscatter.rgb * phaseR + getMie(inscatter) * phaseM, 0.0); - } else { // x in space and ray looking in space - result = vec3(0.0); - } - return result * ISun; -} - -float _uncharted2Tonemap(float x) -{ - float A = 0.15; - float B = 0.50; - float C = 0.10; - float D = 0.20; - float E = 0.02; - float F = 0.30; - - return ((x * (A * x + C * B) + D * E) / (x * (A * x + B) + D * F)) - E / F; -} - -vec4 _toneMappingUncharted(vec4 color, float exposure) -{ - float W = 11.2; - float white_scale = 1.0 / _uncharted2Tonemap(W); - vec4 result; - - result.r = pow(_uncharted2Tonemap(color.r * exposure) * white_scale, 1.0 / 2.2); - result.g = pow(_uncharted2Tonemap(color.g * exposure) * white_scale, 1.0 / 2.2); - result.b = pow(_uncharted2Tonemap(color.b * exposure) * white_scale, 1.0 / 2.2); - result.a = 1.0; - - return result; -} - void main(void) { gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0); diff --git a/src/system/Logs.h b/src/system/Logs.h index a044089..17d084c 100644 --- a/src/system/Logs.h +++ b/src/system/Logs.h @@ -4,6 +4,6 @@ #include "system_global.h" #define logWarning qWarning -#define logError qError +#define logError qCritical #endif // LOGS_H From 8098482d5047ca5a5e608f24c91f3eb90eb3976f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Lemaire?= Date: Mon, 23 Dec 2013 10:26:29 +0100 Subject: [PATCH 09/17] Retrograded to OpenGL 3.0 functions --- src/render/opengl/OpenGLRenderer.cpp | 64 +++++++++++++---------- src/render/opengl/OpenGLRenderer.h | 8 +-- src/render/opengl/OpenGLShaderProgram.cpp | 2 +- src/render/opengl/OpenGLShaderProgram.h | 3 +- src/render/opengl/OpenGLVariable.cpp | 8 +-- src/render/opengl/opengl_global.h | 5 ++ 6 files changed, 52 insertions(+), 38 deletions(-) diff --git a/src/render/opengl/OpenGLRenderer.cpp b/src/render/opengl/OpenGLRenderer.cpp index 0600be9..d3e943d 100644 --- a/src/render/opengl/OpenGLRenderer.cpp +++ b/src/render/opengl/OpenGLRenderer.cpp @@ -1,6 +1,6 @@ #include "OpenGLRenderer.h" -#include +#include OPENGL_FUNCTIONS_INCLUDE #include "CameraDefinition.h" #include "OpenGLSharedState.h" #include "OpenGLSkybox.h" @@ -9,7 +9,9 @@ OpenGLRenderer::OpenGLRenderer(Scenery* scenery): SoftwareRenderer(scenery) { - functions = new QOpenGLFunctions_3_2_Core(); + ready = false; + + functions = new OpenGLFunctions(); shared_state = new OpenGLSharedState(); skybox = new OpenGLSkybox(this); @@ -27,50 +29,58 @@ OpenGLRenderer::~OpenGLRenderer() void OpenGLRenderer::initialize() { - // TODO Check return value - functions->initializeOpenGLFunctions(); + ready = functions->initializeOpenGLFunctions(); - functions->glClearColor(0.0, 0.0, 0.0, 0.0); + if (ready) + { + functions->glClearColor(0.0, 0.0, 0.0, 0.0); - functions->glDisable(GL_LIGHTING); + functions->glDisable(GL_LIGHTING); - functions->glFrontFace(GL_CCW); - functions->glCullFace(GL_BACK); - functions->glEnable(GL_CULL_FACE); + functions->glFrontFace(GL_CCW); + functions->glCullFace(GL_BACK); + functions->glEnable(GL_CULL_FACE); - functions->glDepthFunc(GL_LESS); - functions->glDepthMask(1); - functions->glEnable(GL_DEPTH_TEST); + functions->glDepthFunc(GL_LESS); + functions->glDepthMask(1); + functions->glEnable(GL_DEPTH_TEST); - functions->glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - functions->glEnable(GL_LINE_SMOOTH); - functions->glLineWidth(1.0); + functions->glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + functions->glEnable(GL_LINE_SMOOTH); + functions->glLineWidth(1.0); - functions->glDisable(GL_FOG); + functions->glDisable(GL_FOG); - functions->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + functions->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - prepare(); + prepare(); - skybox->initialize(); - skybox->updateScenery(); + skybox->initialize(); + skybox->updateScenery(); - water->initialize(); - water->updateScenery(); + water->initialize(); + water->updateScenery(); + } } void OpenGLRenderer::resize(int width, int height) { - functions->glViewport(0, 0, width, height); + if (ready) + { + functions->glViewport(0, 0, width, height); + } } void OpenGLRenderer::paint() { - functions->glClearColor(0.0, 0.0, 0.0, 0.0); - functions->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + if (ready) + { + functions->glClearColor(0.0, 0.0, 0.0, 0.0); + functions->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - skybox->render(); - water->render(); + skybox->render(); + water->render(); + } } void OpenGLRenderer::cameraChangeEvent(CameraDefinition *camera) diff --git a/src/render/opengl/OpenGLRenderer.h b/src/render/opengl/OpenGLRenderer.h index 2069ed1..fc4f7de 100644 --- a/src/render/opengl/OpenGLRenderer.h +++ b/src/render/opengl/OpenGLRenderer.h @@ -5,8 +5,6 @@ #include "SoftwareRenderer.h" -class QOpenGLFunctions_3_2_Core; - namespace paysages { namespace opengl { @@ -25,14 +23,16 @@ public: void cameraChangeEvent(CameraDefinition* camera); - inline QOpenGLFunctions_3_2_Core* getOpenGlFunctions() const {return functions;} + inline OpenGLFunctions* getOpenGlFunctions() const {return functions;} inline OpenGLSharedState* getSharedState() const {return shared_state;} virtual double getPrecision(const Vector3 &location) override; virtual Color applyMediumTraversal(Vector3 location, Color color) override; private: - QOpenGLFunctions_3_2_Core* functions; + bool ready; + + OpenGLFunctions* functions; OpenGLSharedState* shared_state; OpenGLSkybox* skybox; diff --git a/src/render/opengl/OpenGLShaderProgram.cpp b/src/render/opengl/OpenGLShaderProgram.cpp index dc326a1..6df6534 100644 --- a/src/render/opengl/OpenGLShaderProgram.cpp +++ b/src/render/opengl/OpenGLShaderProgram.cpp @@ -1,7 +1,7 @@ #include "OpenGLShaderProgram.h" +#include OPENGL_FUNCTIONS_INCLUDE #include -#include #include #include "OpenGLRenderer.h" #include "OpenGLSharedState.h" diff --git a/src/render/opengl/OpenGLShaderProgram.h b/src/render/opengl/OpenGLShaderProgram.h index 2b4bfd1..9a00bef 100644 --- a/src/render/opengl/OpenGLShaderProgram.h +++ b/src/render/opengl/OpenGLShaderProgram.h @@ -6,7 +6,6 @@ #include class QOpenGLShaderProgram; -class QOpenGLFunctions_3_2_Core; namespace paysages { namespace opengl { @@ -39,7 +38,7 @@ private: QString name; QOpenGLShaderProgram* program; - QOpenGLFunctions_3_2_Core* functions; + OpenGLFunctions* functions; std::string source_vertex; std::string source_fragment; diff --git a/src/render/opengl/OpenGLVariable.cpp b/src/render/opengl/OpenGLVariable.cpp index 11e97a5..be33aff 100644 --- a/src/render/opengl/OpenGLVariable.cpp +++ b/src/render/opengl/OpenGLVariable.cpp @@ -1,8 +1,8 @@ #include "OpenGLVariable.h" -#include +#include OPENGL_FUNCTIONS_INCLUDE #include -#include +#include #include "OpenGLRenderer.h" #include "OpenGLShaderProgram.h" #include "Vector3.h" @@ -22,7 +22,7 @@ OpenGLVariable::OpenGLVariable(const std::string &name): void OpenGLVariable::apply(OpenGLShaderProgram *program, int &texture_unit) { QOpenGLShaderProgram* pr = program->getProgram(); - QOpenGLFunctions_3_2_Core* functions = program->getRenderer()->getOpenGlFunctions(); + OpenGLFunctions* functions = program->getRenderer()->getOpenGlFunctions(); if (texture_toupload) { @@ -133,7 +133,7 @@ void OpenGLVariable::set(const Color &color) void OpenGLVariable::uploadTexture(OpenGLRenderer* renderer) { - QOpenGLFunctions_3_2_Core* functions = renderer->getOpenGlFunctions(); + OpenGLFunctions* functions = renderer->getOpenGlFunctions(); assert(type == TYPE_TEXTURE_2D or type == TYPE_TEXTURE_3D or type == TYPE_TEXTURE_4D); diff --git a/src/render/opengl/opengl_global.h b/src/render/opengl/opengl_global.h index d8f0cef..d74c89d 100644 --- a/src/render/opengl/opengl_global.h +++ b/src/render/opengl/opengl_global.h @@ -25,4 +25,9 @@ namespace opengl { } using namespace paysages::opengl; +//#define OpenGLFunctions QOpenGLFunctions_3_2_Core +#define OpenGLFunctions QOpenGLFunctions_3_0 +#define OPENGL_FUNCTIONS_INCLUDE +class OpenGLFunctions; + #endif // OPENGL_GLOBAL_H From ac5c0fd584e2359bf10038bd627b416aa06f6e02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Lemaire?= Date: Mon, 23 Dec 2013 14:09:52 +0100 Subject: [PATCH 10/17] Refactored opengl terrain rendering for future use of shaders --- src/render/opengl/BaseExplorerChunk.cpp | 170 -------------------- src/render/opengl/BaseExplorerChunk.h | 58 ------- src/render/opengl/ExplorerChunkTerrain.cpp | 161 +++++++++++++++---- src/render/opengl/ExplorerChunkTerrain.h | 34 +++- src/render/opengl/OpenGLRenderer.cpp | 7 + src/render/opengl/OpenGLRenderer.h | 1 + src/render/opengl/OpenGLTerrain.cpp | 144 +++++++++++++++++ src/render/opengl/OpenGLTerrain.h | 40 +++++ src/render/opengl/WidgetExplorer.cpp | 178 +-------------------- src/render/opengl/WidgetExplorer.h | 14 -- src/render/opengl/opengl.pro | 8 +- src/render/opengl/opengl_global.h | 3 +- src/system/ParallelPool.cpp | 55 +++++++ src/system/ParallelPool.h | 43 +++++ src/system/system.pro | 6 +- src/system/system_global.h | 1 + 16 files changed, 465 insertions(+), 458 deletions(-) delete mode 100644 src/render/opengl/BaseExplorerChunk.cpp delete mode 100644 src/render/opengl/BaseExplorerChunk.h create mode 100644 src/render/opengl/OpenGLTerrain.cpp create mode 100644 src/render/opengl/OpenGLTerrain.h create mode 100644 src/system/ParallelPool.cpp create mode 100644 src/system/ParallelPool.h diff --git a/src/render/opengl/BaseExplorerChunk.cpp b/src/render/opengl/BaseExplorerChunk.cpp deleted file mode 100644 index 82f7322..0000000 --- a/src/render/opengl/BaseExplorerChunk.cpp +++ /dev/null @@ -1,170 +0,0 @@ -#include "BaseExplorerChunk.h" - -#include -#include -#include "ColorProfile.h" - -#ifndef GL_CLAMP_TO_EDGE -#define GL_CLAMP_TO_EDGE 0x812F -#endif - -BaseExplorerChunk::BaseExplorerChunk(SoftwareRenderer* renderer) -{ - _renderer = renderer; - _color_profile = new ColorProfile; - - priority = 0.0; - _reset_needed = false; - - _texture = new QImage(1, 1, QImage::Format_ARGB32); - _texture_id = 0; - _texture_changed = false; - _texture_current_size = 0; - _texture_max_size = 0; -} - -BaseExplorerChunk::~BaseExplorerChunk() -{ - _lock_data.lock(); - delete _color_profile; - delete _texture; - _lock_data.unlock(); -} - -bool BaseExplorerChunk::maintain() -{ - bool subchanged; - - _lock_data.lock(); - if (_reset_needed) - { - _reset_needed = false; - _texture_current_size = 0; - onResetEvent(); - } - _lock_data.unlock(); - - subchanged = onMaintainEvent(); - - // Improve texture resolution - if (_texture_current_size < _texture_max_size) - { - int new_texture_size = _texture_current_size ? _texture_current_size * 2 : 1; - QImage* new_image = new QImage(_texture->scaled(new_texture_size + 1, new_texture_size + 1, Qt::IgnoreAspectRatio, Qt::FastTransformation)); - for (int j = 0; j <= new_texture_size; j++) - { - for (int i = 0; i <= new_texture_size; i++) - { - if (_texture_current_size <= 1 || i % 2 != 0 || j % 2 != 0) - { - Color color = getTextureColor((double)i / (double)new_texture_size, 1.0 - (double)j / (double)new_texture_size); - color = _color_profile->apply(color); - color.normalize(); - new_image->setPixel(i, j, color.to32BitBGRA()); - } - } - } - - _lock_data.lock(); - delete _texture; - _texture = new_image; - _texture_current_size = new_texture_size; - _texture_changed = true; - _lock_data.unlock(); - - /*if (_texture_current_size < 4 && _texture_current_size < _texture_max_size) - { - maintain(); - }*/ - - return true; - } - else - { - return subchanged; - } -} - -void BaseExplorerChunk::updatePriority(CameraDefinition* camera) -{ - if (_reset_needed || (_texture_max_size > 1 && _texture_current_size <= 1)) - { - priority = 1000.0; - } - else if (_texture_current_size == _texture_max_size) - { - priority = -1000.0; - } - else - { - priority = getDisplayedSizeHint(camera) - _texture_current_size; - } - onCameraEvent(camera); -} - -void BaseExplorerChunk::render(QGLWidget* widget) -{ - // Put texture in place - _lock_data.lock(); - if (_texture_changed) - { - _texture_changed = false; - if (_texture_id) - { - widget->deleteTexture(_texture_id); - } - // TODO Only do the scale if not power-of-two textures are unsupported by GPU - _texture_id = widget->bindTexture(_texture->scaled(_texture_current_size, _texture_current_size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); - //_texture_id = widget->bindTexture(*_texture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } - else - { - glBindTexture(GL_TEXTURE_2D, _texture_id); - } - _lock_data.unlock(); - - // Delegate poly rendering to subclass - if (!_reset_needed) - { - onRenderEvent(widget); - } -} - -void BaseExplorerChunk::askReset() -{ - _reset_needed = true; -} - -void BaseExplorerChunk::setMaxTextureSize(int size) -{ - _texture_max_size = size; -} - -void BaseExplorerChunk::onCameraEvent(CameraDefinition*) -{ -} - -void BaseExplorerChunk::onResetEvent() -{ -} - -bool BaseExplorerChunk::onMaintainEvent() -{ - return false; -} - -void BaseExplorerChunk::onRenderEvent(QGLWidget*) -{ -} - -double BaseExplorerChunk::getDisplayedSizeHint(CameraDefinition*) -{ - return 0.0; -} - -Color BaseExplorerChunk::getTextureColor(double, double) -{ - return COLOR_TRANSPARENT; -} diff --git a/src/render/opengl/BaseExplorerChunk.h b/src/render/opengl/BaseExplorerChunk.h deleted file mode 100644 index 08c9780..0000000 --- a/src/render/opengl/BaseExplorerChunk.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef BASEEXPLORERCHUNK_H -#define BASEEXPLORERCHUNK_H - -#include "opengl_global.h" - -#include -#include "Color.h" - -class QImage; -class QGLWidget; - -namespace paysages { -namespace opengl { - -class BaseExplorerChunk -{ -public: - virtual ~BaseExplorerChunk(); - - bool maintain(); - void updatePriority(CameraDefinition* camera); - void render(QGLWidget* widget); - - double priority; -protected: - BaseExplorerChunk(SoftwareRenderer* renderer); - - inline SoftwareRenderer* renderer() {return _renderer;} - - void askReset(); - void setMaxTextureSize(int size); - - virtual void onCameraEvent(CameraDefinition* camera); - virtual void onResetEvent(); - virtual bool onMaintainEvent(); - virtual void onRenderEvent(QGLWidget* widget); - virtual double getDisplayedSizeHint(CameraDefinition* camera); - virtual Color getTextureColor(double x, double y); - - QMutex _lock_data; - -private: - SoftwareRenderer* _renderer; - ColorProfile* _color_profile; - - bool _reset_needed; - - QImage* _texture; - unsigned int _texture_id; - bool _texture_changed; - int _texture_current_size; - int _texture_max_size; -}; - -} -} - -#endif // BASEEXPLORERCHUNK_H diff --git a/src/render/opengl/ExplorerChunkTerrain.cpp b/src/render/opengl/ExplorerChunkTerrain.cpp index ed0d595..4fd3acb 100644 --- a/src/render/opengl/ExplorerChunkTerrain.cpp +++ b/src/render/opengl/ExplorerChunkTerrain.cpp @@ -1,13 +1,28 @@ #include "ExplorerChunkTerrain.h" +#include OPENGL_FUNCTIONS_INCLUDE #include -#include +#include +#include +#include "ColorProfile.h" #include "CameraDefinition.h" -#include "SoftwareRenderer.h" +#include "OpenGLRenderer.h" #include "TerrainRenderer.h" -ExplorerChunkTerrain::ExplorerChunkTerrain(SoftwareRenderer* renderer, double x, double z, double size, int nbchunks, double water_height) : BaseExplorerChunk(renderer) +ExplorerChunkTerrain::ExplorerChunkTerrain(OpenGLRenderer* renderer, double x, double z, double size, int nbchunks, double water_height): + _renderer(renderer) { + _color_profile = new ColorProfile; + + priority = 0.0; + _reset_needed = false; + + _texture = new QImage(1, 1, QImage::Format_ARGB32); + texture = new QOpenGLTexture(*_texture); + _texture_changed = false; + _texture_current_size = 0; + _texture_max_size = 0; + _startx = x; _startz = z; _size = size; @@ -31,20 +46,70 @@ ExplorerChunkTerrain::ExplorerChunkTerrain(SoftwareRenderer* renderer, double x, ExplorerChunkTerrain::~ExplorerChunkTerrain() { _lock_data.lock(); + delete _color_profile; + delete _texture; + delete texture; delete [] _tessellation; _lock_data.unlock(); } -void ExplorerChunkTerrain::onResetEvent() +bool ExplorerChunkTerrain::maintain() { - _tessellation_current_size = 0; - _overwater = false; + bool subchanged; + + _lock_data.lock(); + if (_reset_needed) + { + _reset_needed = false; + _texture_current_size = 0; + _tessellation_current_size = 0; + _overwater = false; + } + _lock_data.unlock(); + + subchanged = onMaintainEvent(); + + // Improve texture resolution + if (_texture_current_size < _texture_max_size) + { + int new_texture_size = _texture_current_size ? _texture_current_size * 2 : 1; + QImage* new_image = new QImage(_texture->scaled(new_texture_size + 1, new_texture_size + 1, Qt::IgnoreAspectRatio, Qt::FastTransformation)); + for (int j = 0; j <= new_texture_size; j++) + { + for (int i = 0; i <= new_texture_size; i++) + { + if (_texture_current_size <= 1 || i % 2 != 0 || j % 2 != 0) + { + Color color = getTextureColor((double)i / (double)new_texture_size, (double)j / (double)new_texture_size); + color = _color_profile->apply(color); + color.normalize(); + new_image->setPixel(i, j, color.to32BitBGRA()); + } + } + } + + _lock_data.lock(); + delete _texture; + _texture = new_image; + _texture_current_size = new_texture_size; + _texture_changed = true; + _lock_data.unlock(); + + /*if (_texture_current_size < 4 && _texture_current_size < _texture_max_size) + { + maintain(); + }*/ + + return true; + } + else + { + return subchanged; + } } bool ExplorerChunkTerrain::onMaintainEvent() { - SoftwareRenderer* renderer = this->renderer(); - // Improve heightmap resolution if (_tessellation_current_size < _tessellation_max_size) { @@ -57,7 +122,7 @@ bool ExplorerChunkTerrain::onMaintainEvent() { if (_tessellation_current_size == 0 || i % old_tessellation_inc != 0 || j % old_tessellation_inc != 0) { - double height = renderer->getTerrainRenderer()->getHeight(_startx + _tessellation_step * (double) i, _startz + _tessellation_step * (double) j, 1); + double height = _renderer->getTerrainRenderer()->getHeight(_startx + _tessellation_step * (double) i, _startz + _tessellation_step * (double) j, 1); if (height >= _water_height) { _overwater = true; @@ -84,8 +149,21 @@ bool ExplorerChunkTerrain::onMaintainEvent() } } -void ExplorerChunkTerrain::onCameraEvent(CameraDefinition* camera) +void ExplorerChunkTerrain::updatePriority(CameraDefinition* camera) { + if (_reset_needed || (_texture_max_size > 1 && _texture_current_size <= 1)) + { + priority = 1000.0; + } + else if (_texture_current_size == _texture_max_size) + { + priority = -1000.0; + } + else + { + priority = getDisplayedSizeHint(camera) - _texture_current_size; + } + Vector3 camera_location = camera->getLocation(); // Handle position @@ -116,33 +194,62 @@ void ExplorerChunkTerrain::onCameraEvent(CameraDefinition* camera) _lock_data.unlock(); } -void ExplorerChunkTerrain::onRenderEvent(QGLWidget*) +void ExplorerChunkTerrain::render(OpenGLFunctions* functions) { + // Put texture in place _lock_data.lock(); - int tessellation_size = _tessellation_current_size; - double tsize = 1.0 / (double) _tessellation_max_size; + if (_texture_changed) + { + _texture_changed = false; + texture->destroy(); + // TODO Only do the scale if not power-of-two textures are unsupported by GPU + texture->setData(_texture->scaled(_texture_current_size, _texture_current_size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); + //texture->setData(*_texture); + texture->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::ClampToEdge); + texture->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::ClampToEdge); + } + texture->bind(); _lock_data.unlock(); - if (tessellation_size <= 1 or not _overwater) + // Delegate poly rendering to subclass + if (!_reset_needed) { - return; - } + _lock_data.lock(); + int tessellation_size = _tessellation_current_size; + double tsize = 1.0 / (double) _tessellation_max_size; + _lock_data.unlock(); - int tessellation_inc = _tessellation_max_size / (double) tessellation_size; - for (int j = 0; j < _tessellation_max_size; j += tessellation_inc) - { - glBegin(GL_QUAD_STRIP); - for (int i = 0; i <= _tessellation_max_size; i += tessellation_inc) + if (tessellation_size <= 1 or not _overwater) { - glTexCoord2d(tsize * (double) i, tsize * (double) j); - glVertex3d(_startx + _tessellation_step * (double) i, _tessellation[j * (_tessellation_max_size + 1) + i], _startz + _tessellation_step * (double) j); - glTexCoord2d(tsize * (double) i, tsize * (double) (j + tessellation_inc)); - glVertex3d(_startx + _tessellation_step * (double) i, _tessellation[(j + tessellation_inc) * (_tessellation_max_size + 1) + i], _startz + _tessellation_step * (double) (j + tessellation_inc)); + return; + } + + int tessellation_inc = _tessellation_max_size / (double) tessellation_size; + for (int j = 0; j < _tessellation_max_size; j += tessellation_inc) + { + functions->glBegin(GL_QUAD_STRIP); + for (int i = 0; i <= _tessellation_max_size; i += tessellation_inc) + { + functions->glTexCoord2d(tsize * (double) i, tsize * (double) j); + functions->glVertex3d(_startx + _tessellation_step * (double) i, _tessellation[j * (_tessellation_max_size + 1) + i], _startz + _tessellation_step * (double) j); + functions->glTexCoord2d(tsize * (double) i, tsize * (double) (j + tessellation_inc)); + functions->glVertex3d(_startx + _tessellation_step * (double) i, _tessellation[(j + tessellation_inc) * (_tessellation_max_size + 1) + i], _startz + _tessellation_step * (double) (j + tessellation_inc)); + } + functions->glEnd(); } - glEnd(); } } +void ExplorerChunkTerrain::askReset() +{ + _reset_needed = true; +} + +void ExplorerChunkTerrain::setMaxTextureSize(int size) +{ + _texture_max_size = size; +} + double ExplorerChunkTerrain::getDisplayedSizeHint(CameraDefinition* camera) { double distance; @@ -170,7 +277,7 @@ double ExplorerChunkTerrain::getDisplayedSizeHint(CameraDefinition* camera) Color ExplorerChunkTerrain::getTextureColor(double x, double y) { Vector3 location = {_startx + x * _size, 0.0, _startz + y * _size}; - return renderer()->getTerrainRenderer()->getFinalColor(location, 0.01); + return _renderer->getTerrainRenderer()->getFinalColor(location, 0.01); } Vector3 ExplorerChunkTerrain::getCenter() diff --git a/src/render/opengl/ExplorerChunkTerrain.h b/src/render/opengl/ExplorerChunkTerrain.h index ce21462..2c7c911 100644 --- a/src/render/opengl/ExplorerChunkTerrain.h +++ b/src/render/opengl/ExplorerChunkTerrain.h @@ -1,26 +1,34 @@ #ifndef EXPLORERCHUNKTERRAIN_H #define EXPLORERCHUNKTERRAIN_H -#include "BaseExplorerChunk.h" +#include "opengl_global.h" -#include "Vector3.h" +#include +class QImage; +class QOpenGLTexture; namespace paysages { namespace opengl { -class OPENGLSHARED_EXPORT ExplorerChunkTerrain:public BaseExplorerChunk +class OPENGLSHARED_EXPORT ExplorerChunkTerrain { public: - ExplorerChunkTerrain(SoftwareRenderer* renderer, double x, double z, double size, int nbchunks, double water_height); + ExplorerChunkTerrain(OpenGLRenderer* renderer, double x, double z, double size, int nbchunks, double water_height); ~ExplorerChunkTerrain(); - void onCameraEvent(CameraDefinition* camera); - void onResetEvent(); + bool maintain(); + void updatePriority(CameraDefinition* camera); + void render(OpenGLFunctions* functions); + + void askReset(); + void setMaxTextureSize(int size); + bool onMaintainEvent(); - void onRenderEvent(QGLWidget* widget); double getDisplayedSizeHint(CameraDefinition* camera); Color getTextureColor(double x, double y); + double priority; + private: Vector3 getCenter(); @@ -38,6 +46,18 @@ private: int _tessellation_current_size; double _tessellation_step; + QMutex _lock_data; + + OpenGLRenderer* _renderer; + ColorProfile* _color_profile; + + bool _reset_needed; + + QImage* _texture; + QOpenGLTexture* texture; + bool _texture_changed; + int _texture_current_size; + int _texture_max_size; }; } diff --git a/src/render/opengl/OpenGLRenderer.cpp b/src/render/opengl/OpenGLRenderer.cpp index d3e943d..311de4d 100644 --- a/src/render/opengl/OpenGLRenderer.cpp +++ b/src/render/opengl/OpenGLRenderer.cpp @@ -5,6 +5,7 @@ #include "OpenGLSharedState.h" #include "OpenGLSkybox.h" #include "OpenGLWater.h" +#include "OpenGLTerrain.h" OpenGLRenderer::OpenGLRenderer(Scenery* scenery): SoftwareRenderer(scenery) @@ -16,12 +17,14 @@ OpenGLRenderer::OpenGLRenderer(Scenery* scenery): skybox = new OpenGLSkybox(this); water = new OpenGLWater(this); + terrain = new OpenGLTerrain(this); } OpenGLRenderer::~OpenGLRenderer() { delete skybox; delete water; + delete terrain; delete functions; delete shared_state; @@ -60,6 +63,9 @@ void OpenGLRenderer::initialize() water->initialize(); water->updateScenery(); + + terrain->initialize(); + terrain->updateScenery(); } } @@ -79,6 +85,7 @@ void OpenGLRenderer::paint() functions->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); skybox->render(); + terrain->render(); water->render(); } } diff --git a/src/render/opengl/OpenGLRenderer.h b/src/render/opengl/OpenGLRenderer.h index fc4f7de..d4daeab 100644 --- a/src/render/opengl/OpenGLRenderer.h +++ b/src/render/opengl/OpenGLRenderer.h @@ -37,6 +37,7 @@ private: OpenGLSkybox* skybox; OpenGLWater* water; + OpenGLTerrain* terrain; }; } diff --git a/src/render/opengl/OpenGLTerrain.cpp b/src/render/opengl/OpenGLTerrain.cpp new file mode 100644 index 0000000..5d083f0 --- /dev/null +++ b/src/render/opengl/OpenGLTerrain.cpp @@ -0,0 +1,144 @@ +#include "OpenGLTerrain.h" + +#include OPENGL_FUNCTIONS_INCLUDE +#include "OpenGLRenderer.h" +#include "OpenGLShaderProgram.h" +#include "ParallelPool.h" +#include "Thread.h" +#include "ExplorerChunkTerrain.h" +#include "WaterRenderer.h" +#include "CameraDefinition.h" +#include "Scenery.h" + +class ChunkMaintenanceThreads:public ParallelPool +{ +public: + ChunkMaintenanceThreads(OpenGLTerrain* terrain): + terrain(terrain) + { + } + + virtual void work() override + { + while (running) + { + terrain->performChunksMaintenance(); + Thread::timeSleepMs(10); + } + } + +private: + OpenGLTerrain* terrain; +}; + +OpenGLTerrain::OpenGLTerrain(OpenGLRenderer *renderer): + OpenGLPart(renderer) +{ + work = new ChunkMaintenanceThreads(this); +} + +OpenGLTerrain::~OpenGLTerrain() +{ + delete work; + + for (int i = 0; i < _chunks.count(); i++) + { + delete _chunks[i]; + } +} + +void OpenGLTerrain::initialize() +{ + // Prepare shader programs + program = createShader("terrain"); + program->addVertexSource("terrain"); + program->addFragmentSource("bruneton"); + program->addFragmentSource("tonemapping"); + program->addFragmentSource("terrain"); + + // Add terrain chunks + int chunks = 20; + double size = 400.0; + double chunksize = size / (double) chunks; + double start = -size / 2.0; + double water_height = renderer->getWaterRenderer()->getHeightInfo().base_height; + for (int i = 0; i < chunks; i++) + { + for (int j = 0; j < chunks; j++) + { + ExplorerChunkTerrain* chunk = new ExplorerChunkTerrain(renderer, start + chunksize * (double) i, start + chunksize * (double) j, chunksize, chunks, water_height); + _chunks.append(chunk); + _updateQueue.append(chunk); + } + } + + // Start chunks maintenance + work->start(); +} + +void OpenGLTerrain::update() +{ +} + +// TEMP +#include "GL/gl.h" +#include "GL/glu.h" + +void OpenGLTerrain::render() +{ + CameraDefinition* camera = renderer->getScenery()->getCamera(); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + CameraPerspective perspective = camera->getPerspective(); + gluPerspective(perspective.yfov * 180.0 / M_PI, perspective.xratio, perspective.znear, perspective.zfar); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + Vector3 camera_location = camera->getLocation(); + Vector3 camera_target = camera->getTarget(); + Vector3 camera_up = camera->getUpVector(); + gluLookAt(camera_location.x, camera_location.y, camera_location.z, camera_target.x, camera_target.y, camera_target.z, camera_up.x, camera_up.y, camera_up.z); + + // Render chunks + glEnable(GL_TEXTURE_2D); + for (int i = 0; i < _chunks.count(); i++) + { + glColor3f(1.0, 1.0, 1.0); + _chunks[i]->render(renderer->getOpenGlFunctions()); + } +} + +static bool _cmpChunks(const ExplorerChunkTerrain* c1, const ExplorerChunkTerrain* c2) +{ + return c1->priority > c2->priority; +} + +void OpenGLTerrain::performChunksMaintenance() +{ + CameraDefinition* camera = renderer->getScenery()->getCamera(); + ExplorerChunkTerrain* chunk; + + _lock_chunks.lock(); + if (_updateQueue.count() > 0) + { + chunk = _updateQueue.takeFirst(); + _lock_chunks.unlock(); + } + else + { + _lock_chunks.unlock(); + return; + } + + chunk->maintain(); + + _lock_chunks.lock(); + _updateQueue.append(chunk); + for (int i = 0; i < _chunks.count(); i++) + { + _chunks[i]->updatePriority(camera); + } + qSort(_updateQueue.begin(), _updateQueue.end(), _cmpChunks); + _lock_chunks.unlock(); +} diff --git a/src/render/opengl/OpenGLTerrain.h b/src/render/opengl/OpenGLTerrain.h new file mode 100644 index 0000000..d61c657 --- /dev/null +++ b/src/render/opengl/OpenGLTerrain.h @@ -0,0 +1,40 @@ +#ifndef OPENGLTERRAIN_H +#define OPENGLTERRAIN_H + +#include "opengl_global.h" + +#include "OpenGLPart.h" + +#include +#include +#include + +namespace paysages { +namespace opengl { + +class OPENGLSHARED_EXPORT OpenGLTerrain:public OpenGLPart +{ +public: + OpenGLTerrain(OpenGLRenderer* renderer); + virtual ~OpenGLTerrain(); + + virtual void initialize() override; + virtual void update() override; + virtual void render() override; + + void performChunksMaintenance(); + +private: + OpenGLShaderProgram* program; + + ParallelPool* work; + + QVector _chunks; + QList _updateQueue; + QMutex _lock_chunks; +}; + +} +} + +#endif // OPENGLTERRAIN_H diff --git a/src/render/opengl/WidgetExplorer.cpp b/src/render/opengl/WidgetExplorer.cpp index b1e00b0..00e191d 100644 --- a/src/render/opengl/WidgetExplorer.cpp +++ b/src/render/opengl/WidgetExplorer.cpp @@ -17,44 +17,6 @@ #include "Scenery.h" #include "LightingManager.h" -class ChunkMaintenanceThread : public QThread -{ -public: - - ChunkMaintenanceThread(WidgetExplorer* wanderer) - { - _wanderer = wanderer; - _running = true; - } - - void askStop() - { - _running = false; - } - - static inline void usleep(unsigned long us) - { - QThread::usleep(us); - } - -protected: - - void run() - { - while (_running) - { - _wanderer->performChunksMaintenance(); - QThread::usleep(10000); - } - } - -private: - bool _running; - WidgetExplorer* _wanderer; -}; - -static QVector _threads; - WidgetExplorer::WidgetExplorer(QWidget *parent, CameraDefinition* camera, Scenery* scenery) : QGLWidget(parent) { @@ -71,9 +33,6 @@ QGLWidget(parent) _renderer->getLightingManager()->setSpecularity(false); _renderer->disableClouds(); - _inited = false; - _updated = false; - _average_frame_time = 0.05; _quality = 3; _last_mouse_x = 0; @@ -84,103 +43,10 @@ QGLWidget(parent) WidgetExplorer::~WidgetExplorer() { - stopRendering(); - - for (int i = 0; i < _chunks.count(); i++) - { - delete _chunks[i]; - } delete _current_camera; delete _renderer; } -void WidgetExplorer::startRendering() -{ - // Add terrain - int chunks = 20; - double size = 400.0; - double chunksize = size / (double) chunks; - double start = -size / 2.0; - double water_height = _renderer->getWaterRenderer()->getHeightInfo().base_height; - for (int i = 0; i < chunks; i++) - { - for (int j = 0; j < chunks; j++) - { - ExplorerChunkTerrain* chunk = new ExplorerChunkTerrain(_renderer, start + chunksize * (double) i, start + chunksize * (double) j, chunksize, chunks, water_height); - _chunks.append(chunk); - _updateQueue.append(chunk); - } - } - - // Start rendering workers - int nbcore; - _alive = true; - - nbcore = QThread::idealThreadCount(); - if (nbcore < 1) - { - nbcore = 1; - } - - for (int i = 0; i < nbcore; i++) - { - _threads.append(new ChunkMaintenanceThread(this)); - } - for (int i = 0; i < _threads.count(); i++) - { - _threads[i]->start(); - } -} - -void WidgetExplorer::stopRendering() -{ - for (int i = 0; i < _threads.count(); i++) - { - _threads[i]->askStop(); - } - _alive = false; - for (int i = 0; i < _threads.count(); i++) - { - _threads[i]->wait(); - } -} - -bool _cmpChunks(const BaseExplorerChunk* c1, const BaseExplorerChunk* c2) -{ - return c1->priority > c2->priority; -} - -void WidgetExplorer::performChunksMaintenance() -{ - BaseExplorerChunk* chunk; - - _lock_chunks.lock(); - if (_updateQueue.count() > 0) - { - chunk = _updateQueue.takeFirst(); - _lock_chunks.unlock(); - } - else - { - _lock_chunks.unlock(); - return; - } - - if (chunk->maintain()) - { - if (!_alive) - { - return; - } - - _updated = true; - } - - _lock_chunks.lock(); - _updateQueue.append(chunk); - _lock_chunks.unlock(); -} - void WidgetExplorer::resetCamera() { _base_camera->copy(_current_camera); @@ -323,25 +189,7 @@ void WidgetExplorer::wheelEvent(QWheelEvent* event) void WidgetExplorer::timerEvent(QTimerEvent*) { - if (!_inited) - { - _inited = true; - startRendering(); - } - - if (_updated) - { - _updated = false; - updateGL(); - } - - for (int i = 0; i < _chunks.count(); i++) - { - _chunks[i]->updatePriority(_current_camera); - } - _lock_chunks.lock(); - qSort(_updateQueue.begin(), _updateQueue.end(), _cmpChunks); - _lock_chunks.unlock(); + updateGL(); } void WidgetExplorer::initializeGL() @@ -353,11 +201,6 @@ void WidgetExplorer::resizeGL(int w, int h) { _current_camera->setRenderSize(w, h); _renderer->resize(w, h); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - CameraPerspective perspective = _current_camera->getPerspective(); - gluPerspective(perspective.yfov * 180.0 / M_PI, perspective.xratio, perspective.znear, perspective.zfar); } void WidgetExplorer::paintGL() @@ -376,21 +219,6 @@ void WidgetExplorer::paintGL() // Background _renderer->paint(); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - Vector3 camera_location = _current_camera->getLocation(); - Vector3 camera_target = _current_camera->getTarget(); - Vector3 camera_up = _current_camera->getUpVector(); - gluLookAt(camera_location.x, camera_location.y, camera_location.z, camera_target.x, camera_target.y, camera_target.z, camera_up.x, camera_up.y, camera_up.z); - - // Render chunks - glEnable(GL_TEXTURE_2D); - for (int i = 0; i < _chunks.count(); i++) - { - glColor3f(1.0, 1.0, 1.0); - _chunks[i]->render(this); - } - frame_time = 0.001 * (double) start_time.msecsTo(QTime::currentTime()); _average_frame_time = _average_frame_time * 0.8 + frame_time * 0.2; @@ -406,13 +234,13 @@ void WidgetExplorer::paintGL() } // Messages - if (!_inited) + /*if (!_inited) { glColor3f(0.0, 0.0, 0.0); renderText(6, height() - 10, tr("Please wait while loading scene...")); glColor3f(1.0, 1.0, 1.0); renderText(5, height() - 9, tr("Please wait while loading scene...")); - } + }*/ while ((error_code = glGetError()) != GL_NO_ERROR) { diff --git a/src/render/opengl/WidgetExplorer.h b/src/render/opengl/WidgetExplorer.h index fb7994f..6da061f 100644 --- a/src/render/opengl/WidgetExplorer.h +++ b/src/render/opengl/WidgetExplorer.h @@ -5,8 +5,6 @@ #include -#include - namespace paysages { namespace opengl { @@ -17,8 +15,6 @@ public: WidgetExplorer(QWidget* parent, CameraDefinition* camera, Scenery* scenery); ~WidgetExplorer(); - void performChunksMaintenance(); - public slots: void resetCamera(); void validateCamera(); @@ -35,20 +31,10 @@ protected: void paintGL(); private: - void startRendering(); - void stopRendering(); - CameraDefinition* _current_camera; CameraDefinition* _base_camera; OpenGLRenderer* _renderer; - bool _inited; - bool _updated; - - QVector _chunks; - QList _updateQueue; - bool _alive; - QMutex _lock_chunks; double _average_frame_time; int _quality; diff --git a/src/render/opengl/opengl.pro b/src/render/opengl/opengl.pro index 17807eb..fce63a4 100644 --- a/src/render/opengl/opengl.pro +++ b/src/render/opengl/opengl.pro @@ -15,7 +15,6 @@ include(../../common.pri) SOURCES += \ OpenGLRenderer.cpp \ - BaseExplorerChunk.cpp \ ExplorerChunkTerrain.cpp \ WidgetExplorer.cpp \ OpenGLShaderProgram.cpp \ @@ -23,12 +22,12 @@ SOURCES += \ OpenGLSkybox.cpp \ OpenGLWater.cpp \ OpenGLSharedState.cpp \ - OpenGLVariable.cpp + OpenGLVariable.cpp \ + OpenGLTerrain.cpp HEADERS +=\ opengl_global.h \ OpenGLRenderer.h \ - BaseExplorerChunk.h \ ExplorerChunkTerrain.h \ WidgetExplorer.h \ OpenGLShaderProgram.h \ @@ -36,7 +35,8 @@ HEADERS +=\ OpenGLSkybox.h \ OpenGLWater.h \ OpenGLSharedState.h \ - OpenGLVariable.h + OpenGLVariable.h \ + OpenGLTerrain.h unix:!symbian { maemo5 { diff --git a/src/render/opengl/opengl_global.h b/src/render/opengl/opengl_global.h index d74c89d..9496f54 100644 --- a/src/render/opengl/opengl_global.h +++ b/src/render/opengl/opengl_global.h @@ -15,12 +15,13 @@ namespace paysages { namespace opengl { class WidgetExplorer; class OpenGLRenderer; - class BaseExplorerChunk; class OpenGLShaderProgram; class OpenGLSharedState; class OpenGLVariable; class OpenGLSkybox; class OpenGLWater; + class OpenGLTerrain; + class ExplorerChunkTerrain; } } using namespace paysages::opengl; diff --git a/src/system/ParallelPool.cpp b/src/system/ParallelPool.cpp new file mode 100644 index 0000000..941868e --- /dev/null +++ b/src/system/ParallelPool.cpp @@ -0,0 +1,55 @@ +#include "ParallelPool.h" + +#include "System.h" +#include "Thread.h" + +static void* _threadFunction(void* data) +{ + ParallelPool* pool = (ParallelPool*)data; + pool->work(); + return NULL; +} + +ParallelPool::ParallelPool() +{ + running = false; +} + +ParallelPool::~ParallelPool() +{ + if (running) + { + interrupt(); + } + for (auto thread : threads) + { + thread->join(); + delete thread; + } + threads.clear(); +} + +void ParallelPool::start(int thread_count) +{ + if (running) + { + qCritical("Starting an already started parallel pool !"); + return; + } + running = true; + if (thread_count < 0) + { + thread_count = System::getCoreCount(); + } + for (int i = 0; i < thread_count; i++) + { + Thread* thread = new Thread(_threadFunction); + thread->start(this); + threads.push_back(thread); + } +} + +void ParallelPool::interrupt() +{ + running = false; +} diff --git a/src/system/ParallelPool.h b/src/system/ParallelPool.h new file mode 100644 index 0000000..350d41e --- /dev/null +++ b/src/system/ParallelPool.h @@ -0,0 +1,43 @@ +#ifndef PARALLELPOOL_H +#define PARALLELPOOL_H + +#include "system_global.h" + +namespace paysages { +namespace system { + +/*! + * Pool to handle a group of threads doing the same task. + */ +class ParallelPool +{ +public: + ParallelPool(); + virtual ~ParallelPool(); + + /*! + * Start the effective work. + */ + void start(int thread_count=-1); + + /*! + * Method called from each thread to do actual work. + */ + virtual void work() = 0; + + /*! + * Method called once to interrupt all threads. + */ + virtual void interrupt(); + +protected: + bool running; + +private: + std::vector threads; +}; + +} +} + +#endif // PARALLELPOOL_H diff --git a/src/system/system.pro b/src/system/system.pro index 2aa7ac0..5de52fa 100644 --- a/src/system/system.pro +++ b/src/system/system.pro @@ -24,7 +24,8 @@ SOURCES += \ ParallelQueue.cpp \ CacheFile.cpp \ PictureWriter.cpp \ - Logs.cpp + Logs.cpp \ + ParallelPool.cpp HEADERS += \ system_global.h \ @@ -38,7 +39,8 @@ HEADERS += \ ParallelQueue.h \ CacheFile.h \ PictureWriter.h \ - Logs.h + Logs.h \ + ParallelPool.h unix:!symbian { maemo5 { diff --git a/src/system/system_global.h b/src/system/system_global.h index 5b5dfb2..b557937 100644 --- a/src/system/system_global.h +++ b/src/system/system_global.h @@ -15,6 +15,7 @@ namespace system { class PackStream; class ParallelQueue; class ParallelWork; + class ParallelPool; class Thread; class Mutex; } From f97823604e959370d9908547c1ab371a424b0cd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Lemaire?= Date: Mon, 23 Dec 2013 17:24:05 +0100 Subject: [PATCH 11/17] Introduced VertexArray object to handle terrain vertex data This will be used later with opengl vertex arrays --- src/render/opengl/ExplorerChunkTerrain.cpp | 50 +++++--- src/render/opengl/ExplorerChunkTerrain.h | 10 +- src/render/opengl/VertexArray.cpp | 1 + src/render/opengl/VertexArray.h | 135 +++++++++++++++++++++ src/render/opengl/opengl.pro | 6 +- src/render/opengl/opengl_global.h | 1 + src/tests/VertexArray_Test.cpp | 100 +++++++++++++++ src/tests/tests.pro | 9 +- 8 files changed, 291 insertions(+), 21 deletions(-) create mode 100644 src/render/opengl/VertexArray.cpp create mode 100644 src/render/opengl/VertexArray.h create mode 100644 src/tests/VertexArray_Test.cpp diff --git a/src/render/opengl/ExplorerChunkTerrain.cpp b/src/render/opengl/ExplorerChunkTerrain.cpp index 4fd3acb..5d5fd90 100644 --- a/src/render/opengl/ExplorerChunkTerrain.cpp +++ b/src/render/opengl/ExplorerChunkTerrain.cpp @@ -8,6 +8,7 @@ #include "CameraDefinition.h" #include "OpenGLRenderer.h" #include "TerrainRenderer.h" +#include "VertexArray.h" ExplorerChunkTerrain::ExplorerChunkTerrain(OpenGLRenderer* renderer, double x, double z, double size, int nbchunks, double water_height): _renderer(renderer) @@ -33,8 +34,11 @@ ExplorerChunkTerrain::ExplorerChunkTerrain(OpenGLRenderer* renderer, double x, d _water_height = water_height; _overwater = false; - _tessellation_max_size = 32; - _tessellation = new double[(_tessellation_max_size + 1) * (_tessellation_max_size + 1)]; + tessellation_count = 33; + tessellated = new VertexArray(); + tessellated->setGridSize(tessellation_count); + tessellated->setAutoGridIndices(tessellation_count); + _tessellation_max_size = tessellation_count - 1; _tessellation_current_size = 0; _tessellation_step = _size / (double) _tessellation_max_size; @@ -49,7 +53,7 @@ ExplorerChunkTerrain::~ExplorerChunkTerrain() delete _color_profile; delete _texture; delete texture; - delete [] _tessellation; + delete tessellated; _lock_data.unlock(); } @@ -116,24 +120,39 @@ bool ExplorerChunkTerrain::onMaintainEvent() int new_tessellation_size = _tessellation_current_size ? _tessellation_current_size * 4 : 2; int old_tessellation_inc = _tessellation_current_size ? _tessellation_max_size / _tessellation_current_size : 1; int new_tessellation_inc = _tessellation_max_size / new_tessellation_size; + float internal_step = 1.0f / (float)_tessellation_max_size; for (int j = 0; j <= _tessellation_max_size; j += new_tessellation_inc) { for (int i = 0; i <= _tessellation_max_size; i += new_tessellation_inc) { if (_tessellation_current_size == 0 || i % old_tessellation_inc != 0 || j % old_tessellation_inc != 0) { - double height = _renderer->getTerrainRenderer()->getHeight(_startx + _tessellation_step * (double) i, _startz + _tessellation_step * (double) j, 1); + double x = _startx + _tessellation_step * (float)i; + double z = _startz + _tessellation_step * (float)j; + + double height = _renderer->getTerrainRenderer()->getHeight(x, z, 1); if (height >= _water_height) { _overwater = true; } - _tessellation[j * (_tessellation_max_size + 1) + i] = height; + + TerrainVertex v; + + v.uv[0] = internal_step * (float)i; + v.uv[1] = internal_step * (float)j; + + v.location[0] = x; + v.location[1] = height; + v.location[2] = z; + + tessellated->setGridVertex(tessellation_count, i, j, v); } } } _lock_data.lock(); _tessellation_current_size = new_tessellation_size; + tessellated->setAutoGridIndices(tessellation_count, new_tessellation_inc); _lock_data.unlock(); if (_tessellation_current_size < 4 && _tessellation_current_size < _tessellation_max_size) @@ -216,7 +235,6 @@ void ExplorerChunkTerrain::render(OpenGLFunctions* functions) { _lock_data.lock(); int tessellation_size = _tessellation_current_size; - double tsize = 1.0 / (double) _tessellation_max_size; _lock_data.unlock(); if (tessellation_size <= 1 or not _overwater) @@ -224,19 +242,17 @@ void ExplorerChunkTerrain::render(OpenGLFunctions* functions) return; } - int tessellation_inc = _tessellation_max_size / (double) tessellation_size; - for (int j = 0; j < _tessellation_max_size; j += tessellation_inc) + _lock_data.lock(); // TEMP + int n = tessellated->getIndexCount(); + functions->glBegin(GL_TRIANGLES); + for (int i = 0; i < n; i++) { - functions->glBegin(GL_QUAD_STRIP); - for (int i = 0; i <= _tessellation_max_size; i += tessellation_inc) - { - functions->glTexCoord2d(tsize * (double) i, tsize * (double) j); - functions->glVertex3d(_startx + _tessellation_step * (double) i, _tessellation[j * (_tessellation_max_size + 1) + i], _startz + _tessellation_step * (double) j); - functions->glTexCoord2d(tsize * (double) i, tsize * (double) (j + tessellation_inc)); - functions->glVertex3d(_startx + _tessellation_step * (double) i, _tessellation[(j + tessellation_inc) * (_tessellation_max_size + 1) + i], _startz + _tessellation_step * (double) (j + tessellation_inc)); - } - functions->glEnd(); + TerrainVertex v = tessellated->getVertexByIndex(i); + functions->glTexCoord2d(v.uv[0], v.uv[1]); + functions->glVertex3d(v.location[0], v.location[1], v.location[2]); } + functions->glEnd(); + _lock_data.unlock(); // TEMP } } diff --git a/src/render/opengl/ExplorerChunkTerrain.h b/src/render/opengl/ExplorerChunkTerrain.h index 2c7c911..1de8355 100644 --- a/src/render/opengl/ExplorerChunkTerrain.h +++ b/src/render/opengl/ExplorerChunkTerrain.h @@ -12,6 +12,13 @@ namespace opengl { class OPENGLSHARED_EXPORT ExplorerChunkTerrain { +public: + typedef struct + { + float location[3]; + float uv[2]; + } TerrainVertex; + public: ExplorerChunkTerrain(OpenGLRenderer* renderer, double x, double z, double size, int nbchunks, double water_height); ~ExplorerChunkTerrain(); @@ -41,7 +48,8 @@ private: double _water_height; bool _overwater; - double* _tessellation; + int tessellation_count; + VertexArray *tessellated; int _tessellation_max_size; int _tessellation_current_size; double _tessellation_step; diff --git a/src/render/opengl/VertexArray.cpp b/src/render/opengl/VertexArray.cpp new file mode 100644 index 0000000..96d7d79 --- /dev/null +++ b/src/render/opengl/VertexArray.cpp @@ -0,0 +1 @@ +#include "VertexArray.h" diff --git a/src/render/opengl/VertexArray.h b/src/render/opengl/VertexArray.h new file mode 100644 index 0000000..ffc289f --- /dev/null +++ b/src/render/opengl/VertexArray.h @@ -0,0 +1,135 @@ +#ifndef VERTEXARRAY_H +#define VERTEXARRAY_H + +#include "opengl_global.h" + +#include + +namespace paysages { +namespace opengl { + +/*! + * Wrapper for OpenGL vertex arrays. + */ +template class VertexArray +{ +public: + VertexArray() + { + ready = false; + changed = false; + vertex_count = 1; + vertices = new Vertex[1]; + index_count = 1; + indices = new int[1]; + } + + ~VertexArray() + { + delete[] vertices; + delete[] indices; + } + + inline int getVertexCount() {return vertex_count;} + inline int getIndexCount() {return index_count;} + inline bool isReady() {return ready;} + inline bool isChanged() {return changed;} + + void setVertexCount(int count) + { + assert(count > 0 and count <= 16384); + + delete[] vertices; + vertices = new Vertex[count]; + + vertex_count = count; + } + + void setGridSize(int edge_vertex_count) + { + assert(edge_vertex_count >= 2); + + setVertexCount(edge_vertex_count * edge_vertex_count); + } + + void setVertex(int position, const Vertex &vertex) + { + assert(position >= 0 and position < vertex_count); + + vertices[position] = vertex; + + changed = true; + } + + void setGridVertex(int edge_vertex_count, int x, int y, const Vertex &vertex) + { + setVertex(y * edge_vertex_count + x, vertex); + } + + void setAutoGridIndices(int edge_vertex_count, int stride=1) + { + assert(stride >= 1); + + delete[] indices; + int cell_count = edge_vertex_count - 1; + + index_count = (cell_count / stride) * (cell_count / stride) * 6; + indices = new int[index_count]; + + int idx = 0; + for (int y = 0; y < cell_count; y += stride) + { + for (int x = 0; x < cell_count; x += stride) + { + int base = y * edge_vertex_count + x; + indices[idx++] = base; + indices[idx++] = base + edge_vertex_count * stride; + indices[idx++] = base + stride; + indices[idx++] = base + stride; + indices[idx++] = base + edge_vertex_count * stride; + indices[idx++] = base + edge_vertex_count * stride + stride; + } + } + } + + Vertex getVertex(int position) + { + assert(position >= 0 and position < vertex_count); + + return vertices[position]; + } + + Vertex getVertexByIndex(int index) + { + assert(index >= 0 and index < index_count); + + return getVertex(indices[index]); + } + + Vertex getGridVertex(int edge_vertex_count, int x, int y) + { + return getVertex(y * edge_vertex_count + x); + } + + int getIndex(int position) + { + assert(position >= 0 and position < index_count); + + return indices[position]; + } + +private: + bool ready; + bool changed; + + int vertex_count; + Vertex* vertices; + + int index_count; + int* indices; +}; + +} +} + +#endif // VERTEXARRAY_H diff --git a/src/render/opengl/opengl.pro b/src/render/opengl/opengl.pro index fce63a4..47594ae 100644 --- a/src/render/opengl/opengl.pro +++ b/src/render/opengl/opengl.pro @@ -23,7 +23,8 @@ SOURCES += \ OpenGLWater.cpp \ OpenGLSharedState.cpp \ OpenGLVariable.cpp \ - OpenGLTerrain.cpp + OpenGLTerrain.cpp \ + VertexArray.cpp HEADERS +=\ opengl_global.h \ @@ -36,7 +37,8 @@ HEADERS +=\ OpenGLWater.h \ OpenGLSharedState.h \ OpenGLVariable.h \ - OpenGLTerrain.h + OpenGLTerrain.h \ + VertexArray.h unix:!symbian { maemo5 { diff --git a/src/render/opengl/opengl_global.h b/src/render/opengl/opengl_global.h index 9496f54..1150545 100644 --- a/src/render/opengl/opengl_global.h +++ b/src/render/opengl/opengl_global.h @@ -22,6 +22,7 @@ namespace opengl { class OpenGLWater; class OpenGLTerrain; class ExplorerChunkTerrain; + template class VertexArray; } } using namespace paysages::opengl; diff --git a/src/tests/VertexArray_Test.cpp b/src/tests/VertexArray_Test.cpp new file mode 100644 index 0000000..1b29e6d --- /dev/null +++ b/src/tests/VertexArray_Test.cpp @@ -0,0 +1,100 @@ +#include "BaseTestCase.h" + +#include "VertexArray.h" + +class TestVertex +{ +public: + float uv[2]; + int loc[3]; + + bool operator==(const TestVertex &other) const + { + return other.uv[0] == uv[0] + and other.uv[1] == uv[1] + and other.loc[0] == loc[0] + and other.loc[1] == loc[1] + and other.loc[2] == loc[2]; + } +}; + +TEST(VertexArray, grid) +{ + VertexArray array; + + array.setGridSize(3); + + ASSERT_EQ(9, array.getVertexCount()); + + TestVertex v1 = {{0.1, 0.2}, {1, 2, 3}}; + TestVertex vgot; + + array.setGridVertex(3, 1, 2, v1); + vgot = array.getGridVertex(3, 1, 2); + EXPECT_EQ(v1, vgot); + vgot = array.getVertex(7); + EXPECT_EQ(v1, vgot); +} + +TEST(VertexArray, gridIndices) +{ + VertexArray array; + + array.setGridSize(3); + + array.setAutoGridIndices(3); + ASSERT_EQ(24, array.getIndexCount()); + + EXPECT_EQ(0, array.getIndex(0)); + EXPECT_EQ(3, array.getIndex(1)); + EXPECT_EQ(1, array.getIndex(2)); + + EXPECT_EQ(1, array.getIndex(3)); + EXPECT_EQ(3, array.getIndex(4)); + EXPECT_EQ(4, array.getIndex(5)); + + EXPECT_EQ(1, array.getIndex(6)); + EXPECT_EQ(4, array.getIndex(7)); + EXPECT_EQ(2, array.getIndex(8)); + + EXPECT_EQ(2, array.getIndex(9)); + EXPECT_EQ(4, array.getIndex(10)); + EXPECT_EQ(5, array.getIndex(11)); + + EXPECT_EQ(3, array.getIndex(12)); + EXPECT_EQ(6, array.getIndex(13)); + EXPECT_EQ(4, array.getIndex(14)); +} + +TEST(VertexArray, gridIndicesStride) +{ + VertexArray array; + + array.setGridSize(5); + + array.setAutoGridIndices(5, 1); + ASSERT_EQ(96, array.getIndexCount()); + + array.setAutoGridIndices(5, 2); + ASSERT_EQ(24, array.getIndexCount()); + + EXPECT_EQ(0, array.getIndex(0)); + EXPECT_EQ(10, array.getIndex(1)); + EXPECT_EQ(2, array.getIndex(2)); + + EXPECT_EQ(2, array.getIndex(3)); + EXPECT_EQ(10, array.getIndex(4)); + EXPECT_EQ(12, array.getIndex(5)); + + EXPECT_EQ(2, array.getIndex(6)); + EXPECT_EQ(12, array.getIndex(7)); + EXPECT_EQ(4, array.getIndex(8)); + + EXPECT_EQ(4, array.getIndex(9)); + EXPECT_EQ(12, array.getIndex(10)); + EXPECT_EQ(14, array.getIndex(11)); + + EXPECT_EQ(10, array.getIndex(12)); + EXPECT_EQ(20, array.getIndex(13)); + EXPECT_EQ(12, array.getIndex(14)); +} diff --git a/src/tests/tests.pro b/src/tests/tests.pro index 3fc8679..2e638f3 100644 --- a/src/tests/tests.pro +++ b/src/tests/tests.pro @@ -17,7 +17,8 @@ SOURCES += main.cpp \ Bruneton_Test.cpp \ Camera_Test.cpp \ Clouds_Test.cpp \ - FluidMediumManager_Test.cpp + FluidMediumManager_Test.cpp \ + VertexArray_Test.cpp HEADERS += \ BaseTestCase.h @@ -51,3 +52,9 @@ else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../render/software/ else:unix: LIBS += -L$$OUT_PWD/../render/software/ -lpaysages_render_software INCLUDEPATH += $$PWD/../render/software DEPENDPATH += $$PWD/../render/software + +win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../render/opengl/release/ -lpaysages_render_opengl +else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../render/opengl/debug/ -lpaysages_render_opengl +else:unix: LIBS += -L$$OUT_PWD/../render/opengl/ -lpaysages_render_opengl +INCLUDEPATH += $$PWD/../render/opengl +DEPENDPATH += $$PWD/../render/opengl From bf47e058ee071862ba218a7c080675554bafbef2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Lemaire?= Date: Tue, 24 Dec 2013 11:44:39 +0100 Subject: [PATCH 12/17] Rendering terrain chunks with new shader system --- src/render/opengl/ExplorerChunkTerrain.cpp | 53 ++++++++++++---------- src/render/opengl/ExplorerChunkTerrain.h | 6 +-- src/render/opengl/OpenGLShaderProgram.cpp | 2 +- src/render/opengl/OpenGLShaderProgram.h | 8 ++-- src/render/opengl/OpenGLTerrain.cpp | 25 ++-------- src/render/opengl/VertexArray.cpp | 1 - src/render/opengl/VertexArray.h | 30 ++++++++++-- src/render/opengl/opengl.pro | 7 +-- src/render/opengl/shaders/resources.qrc | 2 + src/render/opengl/shaders/terrain.frag | 30 ++++++++++++ src/render/opengl/shaders/terrain.vert | 12 +++++ 11 files changed, 115 insertions(+), 61 deletions(-) delete mode 100644 src/render/opengl/VertexArray.cpp create mode 100644 src/render/opengl/shaders/terrain.frag create mode 100644 src/render/opengl/shaders/terrain.vert diff --git a/src/render/opengl/ExplorerChunkTerrain.cpp b/src/render/opengl/ExplorerChunkTerrain.cpp index 5d5fd90..05edbba 100644 --- a/src/render/opengl/ExplorerChunkTerrain.cpp +++ b/src/render/opengl/ExplorerChunkTerrain.cpp @@ -3,7 +3,6 @@ #include OPENGL_FUNCTIONS_INCLUDE #include #include -#include #include "ColorProfile.h" #include "CameraDefinition.h" #include "OpenGLRenderer.h" @@ -13,13 +12,13 @@ ExplorerChunkTerrain::ExplorerChunkTerrain(OpenGLRenderer* renderer, double x, double z, double size, int nbchunks, double water_height): _renderer(renderer) { - _color_profile = new ColorProfile; + _color_profile = new ColorProfile(ColorProfile::TONE_MAPPING_REIHNARD, 2.0); priority = 0.0; _reset_needed = false; - _texture = new QImage(1, 1, QImage::Format_ARGB32); - texture = new QOpenGLTexture(*_texture); + _texture = new QImage(1, 1, QImage::Format_RGBA8888); + texture_id = 0; _texture_changed = false; _texture_current_size = 0; _texture_max_size = 0; @@ -52,7 +51,6 @@ ExplorerChunkTerrain::~ExplorerChunkTerrain() _lock_data.lock(); delete _color_profile; delete _texture; - delete texture; delete tessellated; _lock_data.unlock(); } @@ -85,9 +83,9 @@ bool ExplorerChunkTerrain::maintain() if (_texture_current_size <= 1 || i % 2 != 0 || j % 2 != 0) { Color color = getTextureColor((double)i / (double)new_texture_size, (double)j / (double)new_texture_size); - color = _color_profile->apply(color); + //color = _color_profile->apply(color); color.normalize(); - new_image->setPixel(i, j, color.to32BitBGRA()); + new_image->setPixel(i, j, color.to32BitRGBA()); } } } @@ -213,24 +211,34 @@ void ExplorerChunkTerrain::updatePriority(CameraDefinition* camera) _lock_data.unlock(); } -void ExplorerChunkTerrain::render(OpenGLFunctions* functions) +void ExplorerChunkTerrain::render(QOpenGLShaderProgram* program, OpenGLFunctions* functions) { // Put texture in place _lock_data.lock(); if (_texture_changed) { _texture_changed = false; - texture->destroy(); + // TODO Only do the scale if not power-of-two textures are unsupported by GPU - texture->setData(_texture->scaled(_texture_current_size, _texture_current_size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); - //texture->setData(*_texture); - texture->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::ClampToEdge); - texture->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::ClampToEdge); + QImage tex = _texture->scaled(_texture_current_size, _texture_current_size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + + if (texture_id == 0) + { + GLuint texid; + functions->glGenTextures(1, &texid); + texture_id = texid; + } + + functions->glBindTexture(GL_TEXTURE_2D, texture_id); + functions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + functions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + functions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + functions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + functions->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, tex.bits()); } - texture->bind(); _lock_data.unlock(); - // Delegate poly rendering to subclass + // Render tessellated mesh if (!_reset_needed) { _lock_data.lock(); @@ -243,15 +251,12 @@ void ExplorerChunkTerrain::render(OpenGLFunctions* functions) } _lock_data.lock(); // TEMP - int n = tessellated->getIndexCount(); - functions->glBegin(GL_TRIANGLES); - for (int i = 0; i < n; i++) - { - TerrainVertex v = tessellated->getVertexByIndex(i); - functions->glTexCoord2d(v.uv[0], v.uv[1]); - functions->glVertex3d(v.location[0], v.location[1], v.location[2]); - } - functions->glEnd(); + // TEMP + functions->glActiveTexture(GL_TEXTURE0 + 3); + functions->glBindTexture(GL_TEXTURE_2D, texture_id); + program->setUniformValue("groundTexture", 3); + + tessellated->render(program, functions); _lock_data.unlock(); // TEMP } } diff --git a/src/render/opengl/ExplorerChunkTerrain.h b/src/render/opengl/ExplorerChunkTerrain.h index 1de8355..c1ae2ca 100644 --- a/src/render/opengl/ExplorerChunkTerrain.h +++ b/src/render/opengl/ExplorerChunkTerrain.h @@ -5,7 +5,7 @@ #include class QImage; -class QOpenGLTexture; +class QOpenGLShaderProgram; namespace paysages { namespace opengl { @@ -25,7 +25,7 @@ public: bool maintain(); void updatePriority(CameraDefinition* camera); - void render(OpenGLFunctions* functions); + void render(QOpenGLShaderProgram* program, OpenGLFunctions* functions); void askReset(); void setMaxTextureSize(int size); @@ -62,7 +62,7 @@ private: bool _reset_needed; QImage* _texture; - QOpenGLTexture* texture; + unsigned int texture_id; bool _texture_changed; int _texture_current_size; int _texture_max_size; diff --git a/src/render/opengl/OpenGLShaderProgram.cpp b/src/render/opengl/OpenGLShaderProgram.cpp index 6df6534..1b07d7d 100644 --- a/src/render/opengl/OpenGLShaderProgram.cpp +++ b/src/render/opengl/OpenGLShaderProgram.cpp @@ -46,7 +46,7 @@ void OpenGLShaderProgram::addFragmentSource(QString path) } else { - logError("Can't open fragment file %s", file.fileName().toStdString().c_str()); + logError() << "Can't open fragment file " << file.fileName(); } } diff --git a/src/render/opengl/OpenGLShaderProgram.h b/src/render/opengl/OpenGLShaderProgram.h index 9a00bef..5caabf5 100644 --- a/src/render/opengl/OpenGLShaderProgram.h +++ b/src/render/opengl/OpenGLShaderProgram.h @@ -22,15 +22,17 @@ public: void drawTriangles(float* vertices, int triangle_count); void drawTriangleStrip(float* vertices, int vertex_count); -protected: + void bind(); + void release(); + inline QOpenGLShaderProgram* getProgram() const {return program;} inline OpenGLRenderer* getRenderer() const {return renderer;} + +protected: friend class OpenGLVariable; private: void compile(); - void bind(); - void release(); bool compiled; diff --git a/src/render/opengl/OpenGLTerrain.cpp b/src/render/opengl/OpenGLTerrain.cpp index 5d083f0..73b29c5 100644 --- a/src/render/opengl/OpenGLTerrain.cpp +++ b/src/render/opengl/OpenGLTerrain.cpp @@ -80,33 +80,16 @@ void OpenGLTerrain::update() { } -// TEMP -#include "GL/gl.h" -#include "GL/glu.h" - void OpenGLTerrain::render() { - CameraDefinition* camera = renderer->getScenery()->getCamera(); + program->bind(); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - CameraPerspective perspective = camera->getPerspective(); - gluPerspective(perspective.yfov * 180.0 / M_PI, perspective.xratio, perspective.znear, perspective.zfar); - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - Vector3 camera_location = camera->getLocation(); - Vector3 camera_target = camera->getTarget(); - Vector3 camera_up = camera->getUpVector(); - gluLookAt(camera_location.x, camera_location.y, camera_location.z, camera_target.x, camera_target.y, camera_target.z, camera_up.x, camera_up.y, camera_up.z); - - // Render chunks - glEnable(GL_TEXTURE_2D); for (int i = 0; i < _chunks.count(); i++) { - glColor3f(1.0, 1.0, 1.0); - _chunks[i]->render(renderer->getOpenGlFunctions()); + _chunks[i]->render(program->getProgram(), renderer->getOpenGlFunctions()); } + + program->release(); } static bool _cmpChunks(const ExplorerChunkTerrain* c1, const ExplorerChunkTerrain* c2) diff --git a/src/render/opengl/VertexArray.cpp b/src/render/opengl/VertexArray.cpp deleted file mode 100644 index 96d7d79..0000000 --- a/src/render/opengl/VertexArray.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "VertexArray.h" diff --git a/src/render/opengl/VertexArray.h b/src/render/opengl/VertexArray.h index ffc289f..66300d6 100644 --- a/src/render/opengl/VertexArray.h +++ b/src/render/opengl/VertexArray.h @@ -3,7 +3,9 @@ #include "opengl_global.h" +#include OPENGL_FUNCTIONS_INCLUDE #include +#include namespace paysages { namespace opengl { @@ -21,7 +23,7 @@ public: vertex_count = 1; vertices = new Vertex[1]; index_count = 1; - indices = new int[1]; + indices = new unsigned short[1]; } ~VertexArray() @@ -74,7 +76,7 @@ public: int cell_count = edge_vertex_count - 1; index_count = (cell_count / stride) * (cell_count / stride) * 6; - indices = new int[index_count]; + indices = new unsigned short[index_count]; int idx = 0; for (int y = 0; y < cell_count; y += stride) @@ -99,7 +101,7 @@ public: return vertices[position]; } - Vertex getVertexByIndex(int index) + Vertex getVertexByIndex(unsigned short index) { assert(index >= 0 and index < index_count); @@ -111,13 +113,31 @@ public: return getVertex(y * edge_vertex_count + x); } - int getIndex(int position) + unsigned short getIndex(int position) { assert(position >= 0 and position < index_count); return indices[position]; } + void render(QOpenGLShaderProgram* program, OpenGLFunctions* functions) + { + size_t ptr = (size_t)vertices; + + GLuint vertex = program->attributeLocation("vertex"); + program->setAttributeArray(vertex, GL_FLOAT, (void*)(ptr + offsetof(Vertex, location)), 3, sizeof(Vertex)); + program->enableAttributeArray(vertex); + + GLuint uv = program->attributeLocation("uv"); + program->setAttributeArray(uv, GL_FLOAT, (void*)(ptr + offsetof(Vertex, uv)), 2, sizeof(Vertex)); + program->enableAttributeArray(uv); + + functions->glDrawElements(GL_TRIANGLES, index_count, GL_UNSIGNED_SHORT, indices); + + program->disableAttributeArray(vertex); + program->disableAttributeArray(uv); + } + private: bool ready; bool changed; @@ -126,7 +146,7 @@ private: Vertex* vertices; int index_count; - int* indices; + unsigned short* indices; }; } diff --git a/src/render/opengl/opengl.pro b/src/render/opengl/opengl.pro index 47594ae..30e51d5 100644 --- a/src/render/opengl/opengl.pro +++ b/src/render/opengl/opengl.pro @@ -23,8 +23,7 @@ SOURCES += \ OpenGLWater.cpp \ OpenGLSharedState.cpp \ OpenGLVariable.cpp \ - OpenGLTerrain.cpp \ - VertexArray.cpp + OpenGLTerrain.cpp HEADERS +=\ opengl_global.h \ @@ -83,4 +82,6 @@ OTHER_FILES += \ shaders/water.frag \ shaders/bruneton.frag \ shaders/bruneton.frag \ - shaders/tonemapping.frag + shaders/tonemapping.frag \ + shaders/terrain.frag \ + shaders/terrain.vert diff --git a/src/render/opengl/shaders/resources.qrc b/src/render/opengl/shaders/resources.qrc index 761c28b..d73512f 100644 --- a/src/render/opengl/shaders/resources.qrc +++ b/src/render/opengl/shaders/resources.qrc @@ -6,5 +6,7 @@ water.vert bruneton.frag tonemapping.frag + terrain.frag + terrain.vert diff --git a/src/render/opengl/shaders/terrain.frag b/src/render/opengl/shaders/terrain.frag new file mode 100644 index 0000000..77054be --- /dev/null +++ b/src/render/opengl/shaders/terrain.frag @@ -0,0 +1,30 @@ +uniform sampler2D groundTexture; +varying vec2 texcoord; + +void main(void) +{ + gl_FragColor = texture2D(groundTexture, texcoord); + + float yoffset = GROUND_OFFSET - waterHeight; + vec3 camera = vec3(cameraLocation.x, max(cameraLocation.y + yoffset, 0.0), cameraLocation.z); + vec3 location = vec3(unprojected.x, max(unprojected.y + yoffset, 0.0), unprojected.z); + vec3 x = vec3(0.0, Rg + camera.y * WORLD_SCALING, 0.0); + vec3 v = normalize(location - camera); + vec3 s = normalize(sunDirection * SUN_DISTANCE_SCALED - x); + + if (v.y == 0.0) + { + v.y = -0.000001; + } + + float r = length(x); + float mu = dot(x, v) / r; + float t = length(location - camera) * WORLD_SCALING; + + vec3 attenuation; + vec3 inscattering = _getInscatterColor(x, t, v, s, r, mu, attenuation); + + gl_FragColor = gl_FragColor * vec4(attenuation, 0.0) + vec4(inscattering, 0.0); + + gl_FragColor = _toneMappingUncharted(gl_FragColor, 2.0); +} diff --git a/src/render/opengl/shaders/terrain.vert b/src/render/opengl/shaders/terrain.vert new file mode 100644 index 0000000..c4fd270 --- /dev/null +++ b/src/render/opengl/shaders/terrain.vert @@ -0,0 +1,12 @@ +attribute highp vec4 vertex; +attribute highp vec2 uv; +uniform highp mat4 viewMatrix; +varying vec3 unprojected; +varying vec2 texcoord; + +void main(void) +{ + unprojected = vertex.xyz; + texcoord = uv; + gl_Position = viewMatrix * vertex; +} From 74e707a989d688a1e384ed68f73d7b85905e5d75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Lemaire?= Date: Tue, 24 Dec 2013 11:48:06 +0100 Subject: [PATCH 13/17] Fixed water color in opengl rendering --- src/render/opengl/OpenGLWater.cpp | 6 ++++++ src/render/opengl/shaders/water.frag | 4 +++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/render/opengl/OpenGLWater.cpp b/src/render/opengl/OpenGLWater.cpp index dddf6ec..6ef79b5 100644 --- a/src/render/opengl/OpenGLWater.cpp +++ b/src/render/opengl/OpenGLWater.cpp @@ -4,6 +4,9 @@ #include "OpenGLShaderProgram.h" #include "OpenGLSharedState.h" #include "WaterRenderer.h" +#include "Scenery.h" +#include "WaterDefinition.h" +#include "SurfaceMaterial.h" OpenGLWater::OpenGLWater(OpenGLRenderer *renderer): OpenGLPart(renderer) @@ -34,6 +37,9 @@ void OpenGLWater::update() { double water_height = renderer->getWaterRenderer()->getHeightInfo().max_height; renderer->getSharedState()->set("waterHeight", water_height); + + Color water_color = renderer->getScenery()->getWater()->material->_rgb; + renderer->getSharedState()->set("waterColor", water_color); } void OpenGLWater::render() diff --git a/src/render/opengl/shaders/water.frag b/src/render/opengl/shaders/water.frag index 9ef198a..a4318fc 100644 --- a/src/render/opengl/shaders/water.frag +++ b/src/render/opengl/shaders/water.frag @@ -1,6 +1,8 @@ +uniform vec4 waterColor; + void main(void) { - gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0); + gl_FragColor = waterColor; float yoffset = GROUND_OFFSET - waterHeight; vec3 camera = vec3(cameraLocation.x, max(cameraLocation.y + yoffset, 0.0), cameraLocation.z); From 3d54ce974a1da68e1e12db1c4dd9e7498af58909 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Lemaire?= Date: Tue, 24 Dec 2013 13:22:34 +0100 Subject: [PATCH 14/17] Added view distance blending in opengl renderer --- src/render/opengl/OpenGLRenderer.cpp | 5 +++++ src/render/opengl/OpenGLTerrain.cpp | 4 ++-- src/render/opengl/shaders/terrain.frag | 3 +++ src/render/opengl/shaders/water.frag | 3 +++ 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/render/opengl/OpenGLRenderer.cpp b/src/render/opengl/OpenGLRenderer.cpp index 311de4d..d06fd5c 100644 --- a/src/render/opengl/OpenGLRenderer.cpp +++ b/src/render/opengl/OpenGLRenderer.cpp @@ -15,6 +15,8 @@ OpenGLRenderer::OpenGLRenderer(Scenery* scenery): functions = new OpenGLFunctions(); shared_state = new OpenGLSharedState(); + shared_state->set("viewDistance", 20.0); + skybox = new OpenGLSkybox(this); water = new OpenGLWater(this); terrain = new OpenGLTerrain(this); @@ -84,6 +86,9 @@ void OpenGLRenderer::paint() functions->glClearColor(0.0, 0.0, 0.0, 0.0); functions->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + functions->glEnable(GL_BLEND); + functions->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + skybox->render(); terrain->render(); water->render(); diff --git a/src/render/opengl/OpenGLTerrain.cpp b/src/render/opengl/OpenGLTerrain.cpp index 73b29c5..1a02fc2 100644 --- a/src/render/opengl/OpenGLTerrain.cpp +++ b/src/render/opengl/OpenGLTerrain.cpp @@ -57,8 +57,8 @@ void OpenGLTerrain::initialize() program->addFragmentSource("terrain"); // Add terrain chunks - int chunks = 20; - double size = 400.0; + int chunks = 25; + double size = 800.0; double chunksize = size / (double) chunks; double start = -size / 2.0; double water_height = renderer->getWaterRenderer()->getHeightInfo().base_height; diff --git a/src/render/opengl/shaders/terrain.frag b/src/render/opengl/shaders/terrain.frag index 77054be..4ba3625 100644 --- a/src/render/opengl/shaders/terrain.frag +++ b/src/render/opengl/shaders/terrain.frag @@ -1,5 +1,6 @@ uniform sampler2D groundTexture; varying vec2 texcoord; +uniform float viewDistance; void main(void) { @@ -27,4 +28,6 @@ void main(void) gl_FragColor = gl_FragColor * vec4(attenuation, 0.0) + vec4(inscattering, 0.0); gl_FragColor = _toneMappingUncharted(gl_FragColor, 2.0); + + gl_FragColor.a = mix(1.0, 0.0, clamp((t - viewDistance * 0.8) / (viewDistance * 0.2), 0.0, 1.0)); } diff --git a/src/render/opengl/shaders/water.frag b/src/render/opengl/shaders/water.frag index a4318fc..9f5f361 100644 --- a/src/render/opengl/shaders/water.frag +++ b/src/render/opengl/shaders/water.frag @@ -1,4 +1,5 @@ uniform vec4 waterColor; +uniform float viewDistance; void main(void) { @@ -26,4 +27,6 @@ void main(void) gl_FragColor = gl_FragColor * vec4(attenuation, 0.0) + vec4(inscattering, 0.0); gl_FragColor = _toneMappingUncharted(gl_FragColor, 2.0); + + gl_FragColor.a = mix(1.0, 0.0, clamp((t - viewDistance * 0.8) / (viewDistance * 0.2), 0.0, 1.0)); } From 806ab7424422b93dff9eb8f9cc73ec87c1d260be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Lemaire?= Date: Tue, 24 Dec 2013 13:30:32 +0100 Subject: [PATCH 15/17] Fixed camera definition to avoid going underground in opengl view --- src/definition/Scenery.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/definition/Scenery.cpp b/src/definition/Scenery.cpp index 1543e2a..38e489e 100644 --- a/src/definition/Scenery.cpp +++ b/src/definition/Scenery.cpp @@ -199,8 +199,8 @@ void Scenery::getWater(WaterDefinition* water) void Scenery::checkCameraAboveGround() { Vector3 camera_location = camera->getLocation(); - double terrain_height = terrain->getInterpolatedHeight(camera_location.x, camera_location.z, 1, 1) + 0.5; - double water_height = terrain->getWaterHeight() + 0.5; + double terrain_height = terrain->getInterpolatedHeight(camera_location.x, camera_location.z, 1, 1) + 2.0; + double water_height = terrain->getWaterHeight() + 1.0; if (camera_location.y < water_height || camera_location.y < terrain_height) { double diff = ((water_height > terrain_height) ? water_height : terrain_height) - camera_location.y; From 742b93d3d97baaec142caf41cdfd89a7d6647587 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Lemaire?= Date: Tue, 24 Dec 2013 15:00:32 +0100 Subject: [PATCH 16/17] Small fixes to opengl rendering --- src/basics/ColorProfile.cpp | 2 +- src/definition/Scenery.cpp | 2 +- src/render/opengl/OpenGLRenderer.cpp | 5 +++- src/render/opengl/OpenGLTerrain.cpp | 1 + src/render/opengl/OpenGLWater.cpp | 1 + src/render/opengl/opengl.pro | 3 ++- src/render/opengl/shaders/bruneton.frag | 27 +++++++++++++++++-- src/render/opengl/shaders/fadeout.frag | 8 ++++++ src/render/opengl/shaders/resources.qrc | 1 + src/render/opengl/shaders/skybox.frag | 2 +- src/render/opengl/shaders/terrain.frag | 26 +++--------------- src/render/opengl/shaders/tonemapping.frag | 11 ++++++-- src/render/opengl/shaders/water.frag | 26 +++--------------- .../software/AtmosphereModelBruneton.cpp | 2 +- 14 files changed, 61 insertions(+), 56 deletions(-) create mode 100644 src/render/opengl/shaders/fadeout.frag diff --git a/src/basics/ColorProfile.cpp b/src/basics/ColorProfile.cpp index 25c2ff3..99af627 100644 --- a/src/basics/ColorProfile.cpp +++ b/src/basics/ColorProfile.cpp @@ -4,7 +4,7 @@ ColorProfile::ColorProfile() { - setToneMapping(TONE_MAPPING_UNCHARTED, 2.0); + setToneMapping(TONE_MAPPING_UNCHARTED, 1.6); } ColorProfile::ColorProfile(ToneMappingOperator tonemapper, double exposure) diff --git a/src/definition/Scenery.cpp b/src/definition/Scenery.cpp index 38e489e..337fea1 100644 --- a/src/definition/Scenery.cpp +++ b/src/definition/Scenery.cpp @@ -200,7 +200,7 @@ void Scenery::checkCameraAboveGround() { Vector3 camera_location = camera->getLocation(); double terrain_height = terrain->getInterpolatedHeight(camera_location.x, camera_location.z, 1, 1) + 2.0; - double water_height = terrain->getWaterHeight() + 1.0; + double water_height = terrain->getWaterHeight() + 1.5; if (camera_location.y < water_height || camera_location.y < terrain_height) { double diff = ((water_height > terrain_height) ? water_height : terrain_height) - camera_location.y; diff --git a/src/render/opengl/OpenGLRenderer.cpp b/src/render/opengl/OpenGLRenderer.cpp index d06fd5c..5a5d0f1 100644 --- a/src/render/opengl/OpenGLRenderer.cpp +++ b/src/render/opengl/OpenGLRenderer.cpp @@ -15,7 +15,8 @@ OpenGLRenderer::OpenGLRenderer(Scenery* scenery): functions = new OpenGLFunctions(); shared_state = new OpenGLSharedState(); - shared_state->set("viewDistance", 20.0); + shared_state->set("viewDistance", 300.0); + shared_state->set("exposure", 1.6); skybox = new OpenGLSkybox(this); water = new OpenGLWater(this); @@ -60,6 +61,8 @@ void OpenGLRenderer::initialize() prepare(); + disableClouds(); + skybox->initialize(); skybox->updateScenery(); diff --git a/src/render/opengl/OpenGLTerrain.cpp b/src/render/opengl/OpenGLTerrain.cpp index 1a02fc2..c251f84 100644 --- a/src/render/opengl/OpenGLTerrain.cpp +++ b/src/render/opengl/OpenGLTerrain.cpp @@ -54,6 +54,7 @@ void OpenGLTerrain::initialize() program->addVertexSource("terrain"); program->addFragmentSource("bruneton"); program->addFragmentSource("tonemapping"); + program->addFragmentSource("fadeout"); program->addFragmentSource("terrain"); // Add terrain chunks diff --git a/src/render/opengl/OpenGLWater.cpp b/src/render/opengl/OpenGLWater.cpp index 6ef79b5..7de134b 100644 --- a/src/render/opengl/OpenGLWater.cpp +++ b/src/render/opengl/OpenGLWater.cpp @@ -25,6 +25,7 @@ void OpenGLWater::initialize() program->addVertexSource("water"); program->addFragmentSource("bruneton"); program->addFragmentSource("tonemapping"); + program->addFragmentSource("fadeout"); program->addFragmentSource("water"); setVertex(0, -1.0f, 0.0f, -1.0f); diff --git a/src/render/opengl/opengl.pro b/src/render/opengl/opengl.pro index 30e51d5..889cb72 100644 --- a/src/render/opengl/opengl.pro +++ b/src/render/opengl/opengl.pro @@ -84,4 +84,5 @@ OTHER_FILES += \ shaders/bruneton.frag \ shaders/tonemapping.frag \ shaders/terrain.frag \ - shaders/terrain.vert + shaders/terrain.vert \ + shaders/fadeout.frag diff --git a/src/render/opengl/shaders/bruneton.frag b/src/render/opengl/shaders/bruneton.frag index ec61346..acefca0 100644 --- a/src/render/opengl/shaders/bruneton.frag +++ b/src/render/opengl/shaders/bruneton.frag @@ -2,7 +2,6 @@ const float GROUND_OFFSET = 0.5; const float Rg = 6360.0; const float Rt = 6420.0; const float RL = 6421.0; -const float exposure = 0.4; const float ISun = 100.0; const float AVERAGE_GROUND_REFLECTANCE = 0.1; const float HR = 8.0; @@ -90,7 +89,7 @@ vec4 _sunTransmittance(vec3 v, vec3 s, float r, float mu, float radius) { vec4 transmittance = r <= Rt ? _transmittanceWithShadow(r, mu) : vec4(1.0); /* T(x,xo) */ float d = _limit(r, mu); - radius *= (1.0 + 10.0 * d / Rt); /* Inflating due to lens effect near horizon */ + radius *= (1.0 + 25.0 * d / Rt); /* Inflating due to lens effect near horizon */ float isun = step(cos(radius * M_PI / 180.0), dot(v, s)) * ISun; /* Lsun */ transmittance.r *= isun; transmittance.g *= isun; @@ -186,3 +185,27 @@ vec3 _getInscatterColor(inout vec3 x, inout float t, vec3 v, vec3 s, out float r } return result * ISun; } + +vec4 applyAerialPerspective(vec4 base) +{ + float yoffset = GROUND_OFFSET - waterHeight; + vec3 camera = vec3(cameraLocation.x, max(cameraLocation.y + yoffset, 0.0), cameraLocation.z); + vec3 location = vec3(unprojected.x, max(unprojected.y + yoffset, 0.0), unprojected.z); + vec3 x = vec3(0.0, Rg + camera.y * WORLD_SCALING, 0.0); + vec3 v = normalize(location - camera); + vec3 s = normalize(sunDirection * SUN_DISTANCE_SCALED - x); + + if (v.y == 0.0) + { + v.y = -0.000001; + } + + float r = length(x); + float mu = dot(x, v) / r; + float t = length(location - camera) * WORLD_SCALING; + + vec3 attenuation; + vec3 inscattering = _getInscatterColor(x, t, v, s, r, mu, attenuation); + + return base * vec4(attenuation, 0.0) + vec4(inscattering, 0.0); +} diff --git a/src/render/opengl/shaders/fadeout.frag b/src/render/opengl/shaders/fadeout.frag new file mode 100644 index 0000000..484b005 --- /dev/null +++ b/src/render/opengl/shaders/fadeout.frag @@ -0,0 +1,8 @@ +uniform float viewDistance; + +float distanceFadeout() +{ + vec3 camera = vec3(cameraLocation.x, 0.0, cameraLocation.z); + vec3 location = vec3(unprojected.x, 0.0, unprojected.z); + return mix(1.0, 0.0, clamp((length(location - camera) - viewDistance * 0.8) / (viewDistance * 0.2), 0.0, 1.0)); +} diff --git a/src/render/opengl/shaders/resources.qrc b/src/render/opengl/shaders/resources.qrc index d73512f..5dc91be 100644 --- a/src/render/opengl/shaders/resources.qrc +++ b/src/render/opengl/shaders/resources.qrc @@ -8,5 +8,6 @@ tonemapping.frag terrain.frag terrain.vert + fadeout.frag diff --git a/src/render/opengl/shaders/skybox.frag b/src/render/opengl/shaders/skybox.frag index cbb700b..8acc7da 100644 --- a/src/render/opengl/shaders/skybox.frag +++ b/src/render/opengl/shaders/skybox.frag @@ -15,5 +15,5 @@ void main(void) vec3 attenuation; vec3 inscattering = _getInscatterColor(x, t, v, s, r, mu, attenuation); - gl_FragColor = _toneMappingUncharted(sunTransmittance + vec4(inscattering, 0.0), 2.0); + gl_FragColor = applyToneMapping(sunTransmittance + vec4(inscattering, 0.0)); } diff --git a/src/render/opengl/shaders/terrain.frag b/src/render/opengl/shaders/terrain.frag index 4ba3625..de2f60c 100644 --- a/src/render/opengl/shaders/terrain.frag +++ b/src/render/opengl/shaders/terrain.frag @@ -1,33 +1,13 @@ uniform sampler2D groundTexture; varying vec2 texcoord; -uniform float viewDistance; void main(void) { gl_FragColor = texture2D(groundTexture, texcoord); - float yoffset = GROUND_OFFSET - waterHeight; - vec3 camera = vec3(cameraLocation.x, max(cameraLocation.y + yoffset, 0.0), cameraLocation.z); - vec3 location = vec3(unprojected.x, max(unprojected.y + yoffset, 0.0), unprojected.z); - vec3 x = vec3(0.0, Rg + camera.y * WORLD_SCALING, 0.0); - vec3 v = normalize(location - camera); - vec3 s = normalize(sunDirection * SUN_DISTANCE_SCALED - x); + gl_FragColor = applyAerialPerspective(gl_FragColor); - if (v.y == 0.0) - { - v.y = -0.000001; - } + gl_FragColor = applyToneMapping(gl_FragColor); - float r = length(x); - float mu = dot(x, v) / r; - float t = length(location - camera) * WORLD_SCALING; - - vec3 attenuation; - vec3 inscattering = _getInscatterColor(x, t, v, s, r, mu, attenuation); - - gl_FragColor = gl_FragColor * vec4(attenuation, 0.0) + vec4(inscattering, 0.0); - - gl_FragColor = _toneMappingUncharted(gl_FragColor, 2.0); - - gl_FragColor.a = mix(1.0, 0.0, clamp((t - viewDistance * 0.8) / (viewDistance * 0.2), 0.0, 1.0)); + gl_FragColor.a = distanceFadeout(); } diff --git a/src/render/opengl/shaders/tonemapping.frag b/src/render/opengl/shaders/tonemapping.frag index 89f9f19..2ea09af 100644 --- a/src/render/opengl/shaders/tonemapping.frag +++ b/src/render/opengl/shaders/tonemapping.frag @@ -1,3 +1,5 @@ +uniform float exposure; + float _uncharted2Tonemap(float x) { float A = 0.15; @@ -10,7 +12,12 @@ float _uncharted2Tonemap(float x) return ((x * (A * x + C * B) + D * E) / (x * (A * x + B) + D * F)) - E / F; } -vec4 _toneMappingUncharted(vec4 color, float exposure) +vec4 applyToneMapping(vec4 color) +{ + return vec4(((color * exposure) / (1.0 + color * exposure)).rgb, 1.0); +} + +/*vec4 applyToneMapping(vec4 color) { float W = 11.2; float white_scale = 1.0 / _uncharted2Tonemap(W); @@ -22,4 +29,4 @@ vec4 _toneMappingUncharted(vec4 color, float exposure) result.a = 1.0; return result; -} +}*/ diff --git a/src/render/opengl/shaders/water.frag b/src/render/opengl/shaders/water.frag index 9f5f361..06c68b6 100644 --- a/src/render/opengl/shaders/water.frag +++ b/src/render/opengl/shaders/water.frag @@ -1,32 +1,12 @@ uniform vec4 waterColor; -uniform float viewDistance; void main(void) { gl_FragColor = waterColor; - float yoffset = GROUND_OFFSET - waterHeight; - vec3 camera = vec3(cameraLocation.x, max(cameraLocation.y + yoffset, 0.0), cameraLocation.z); - vec3 location = vec3(unprojected.x, max(unprojected.y + yoffset, 0.0), unprojected.z); - vec3 x = vec3(0.0, Rg + camera.y * WORLD_SCALING, 0.0); - vec3 v = normalize(location - camera); - vec3 s = normalize(sunDirection * SUN_DISTANCE_SCALED - x); + gl_FragColor = applyAerialPerspective(gl_FragColor); - if (v.y == 0.0) - { - v.y = -0.000001; - } + gl_FragColor = applyToneMapping(gl_FragColor); - float r = length(x); - float mu = dot(x, v) / r; - float t = length(location - camera) * WORLD_SCALING; - - vec3 attenuation; - vec3 inscattering = _getInscatterColor(x, t, v, s, r, mu, attenuation); - - gl_FragColor = gl_FragColor * vec4(attenuation, 0.0) + vec4(inscattering, 0.0); - - gl_FragColor = _toneMappingUncharted(gl_FragColor, 2.0); - - gl_FragColor.a = mix(1.0, 0.0, clamp((t - viewDistance * 0.8) / (viewDistance * 0.2), 0.0, 1.0)); + gl_FragColor.a = distanceFadeout(); } diff --git a/src/render/software/AtmosphereModelBruneton.cpp b/src/render/software/AtmosphereModelBruneton.cpp index a723a4d..ccaed98 100644 --- a/src/render/software/AtmosphereModelBruneton.cpp +++ b/src/render/software/AtmosphereModelBruneton.cpp @@ -934,7 +934,7 @@ static Color _sunColor(Vector3 v, Vector3 s, double r, double mu, double radius) { Color transmittance = r <= Rt ? _transmittanceWithShadow(r, mu) : COLOR_WHITE; /* T(x,xo) */ double d = _limit(r, mu); - radius *= (1.0 + 10.0 * d / Rt); /* Inflating due to lens effect near horizon */ + radius *= (1.0 + 25.0 * d / Rt); /* Inflating due to lens effect near horizon */ double isun = step(cos(radius * M_PI / 180.0), v.dotProduct(s)) * ISun; /* Lsun */ transmittance.r *= isun; transmittance.g *= isun; From de79f912c347799616fff5087605694ee2a4655c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Lemaire?= Date: Tue, 24 Dec 2013 16:36:45 +0100 Subject: [PATCH 17/17] Moved small things from WidgetExplorer to OpenGLRenderer --- src/render/opengl/OpenGLRenderer.cpp | 22 ++++++++++++++++++++++ src/render/opengl/WidgetExplorer.cpp | 10 ---------- src/render/opengl/opengl.pro | 2 ++ 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/render/opengl/OpenGLRenderer.cpp b/src/render/opengl/OpenGLRenderer.cpp index 5a5d0f1..e86ef48 100644 --- a/src/render/opengl/OpenGLRenderer.cpp +++ b/src/render/opengl/OpenGLRenderer.cpp @@ -6,6 +6,11 @@ #include "OpenGLSkybox.h" #include "OpenGLWater.h" #include "OpenGLTerrain.h" +#include "Scenery.h" +#include "LightingManager.h" +#include "Logs.h" + +#include "GL/glu.h" // TEMP OpenGLRenderer::OpenGLRenderer(Scenery* scenery): SoftwareRenderer(scenery) @@ -62,6 +67,7 @@ void OpenGLRenderer::initialize() prepare(); disableClouds(); + getLightingManager()->setSpecularity(false); skybox->initialize(); skybox->updateScenery(); @@ -71,6 +77,12 @@ void OpenGLRenderer::initialize() terrain->initialize(); terrain->updateScenery(); + + cameraChangeEvent(getScenery()->getCamera()); + } + else + { + logError("Failed to initialize OpenGL bindings"); } } @@ -80,6 +92,10 @@ void OpenGLRenderer::resize(int width, int height) { functions->glViewport(0, 0, width, height); } + getScenery()->getCamera()->setRenderSize(width, height); + render_camera->setRenderSize(width, height); + + cameraChangeEvent(getScenery()->getCamera()); } void OpenGLRenderer::paint() @@ -95,6 +111,12 @@ void OpenGLRenderer::paint() skybox->render(); terrain->render(); water->render(); + + int error_code; + while ((error_code = glGetError()) != GL_NO_ERROR) + { + logWarning("[OpenGL] ERROR : %s", (const char*)gluErrorString(error_code)); + } } } diff --git a/src/render/opengl/WidgetExplorer.cpp b/src/render/opengl/WidgetExplorer.cpp index 00e191d..0569964 100644 --- a/src/render/opengl/WidgetExplorer.cpp +++ b/src/render/opengl/WidgetExplorer.cpp @@ -28,10 +28,6 @@ QGLWidget(parent) camera->copy(_current_camera); _renderer = new OpenGLRenderer(scenery); - _renderer->prepare(); - _renderer->render_quality = 3; - _renderer->getLightingManager()->setSpecularity(false); - _renderer->disableClouds(); _average_frame_time = 0.05; _quality = 3; @@ -205,7 +201,6 @@ void WidgetExplorer::resizeGL(int w, int h) void WidgetExplorer::paintGL() { - GLenum error_code; QTime start_time; double frame_time; @@ -241,9 +236,4 @@ void WidgetExplorer::paintGL() glColor3f(1.0, 1.0, 1.0); renderText(5, height() - 9, tr("Please wait while loading scene...")); }*/ - - while ((error_code = glGetError()) != GL_NO_ERROR) - { - qDebug("[OpenGL] ERROR : %s", (const char*)gluErrorString(error_code)); - } } diff --git a/src/render/opengl/opengl.pro b/src/render/opengl/opengl.pro index 889cb72..e08d5a8 100644 --- a/src/render/opengl/opengl.pro +++ b/src/render/opengl/opengl.pro @@ -13,6 +13,8 @@ DEFINES += OPENGL_LIBRARY include(../../common.pri) +unix:LIBS += -lGLU + SOURCES += \ OpenGLRenderer.cpp \ ExplorerChunkTerrain.cpp \