From 1131972759237a7bcf7d0e45f3ecbce30064e6b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Lemaire?= Date: Mon, 30 Dec 2013 16:02:33 +0100 Subject: [PATCH] Improved the opengl terrain rendering queue --- src/render/opengl/ExplorerChunkTerrain.cpp | 233 ++++++++++----------- src/render/opengl/ExplorerChunkTerrain.h | 13 +- src/render/opengl/OpenGLPart.cpp | 4 + src/render/opengl/OpenGLPart.h | 3 + src/render/opengl/OpenGLRenderer.cpp | 4 + src/render/opengl/OpenGLTerrain.cpp | 10 +- src/render/opengl/OpenGLTerrain.h | 1 + src/render/opengl/WidgetExplorer.cpp | 3 +- 8 files changed, 144 insertions(+), 127 deletions(-) diff --git a/src/render/opengl/ExplorerChunkTerrain.cpp b/src/render/opengl/ExplorerChunkTerrain.cpp index 05edbba..4586b60 100644 --- a/src/render/opengl/ExplorerChunkTerrain.cpp +++ b/src/render/opengl/ExplorerChunkTerrain.cpp @@ -12,26 +12,27 @@ ExplorerChunkTerrain::ExplorerChunkTerrain(OpenGLRenderer* renderer, double x, double z, double size, int nbchunks, double water_height): _renderer(renderer) { - _color_profile = new ColorProfile(ColorProfile::TONE_MAPPING_REIHNARD, 2.0); - priority = 0.0; _reset_needed = false; + interrupt = false; + _texture = new QImage(1, 1, QImage::Format_RGBA8888); texture_id = 0; _texture_changed = false; _texture_current_size = 0; - _texture_max_size = 0; + _texture_wanted_size = 0; + _texture_max_size = 256; _startx = x; _startz = z; _size = size; _overall_step = size * (double) nbchunks; - _distance_to_camera = 0.0; + distance_to_camera = 0.0; _water_height = water_height; - _overwater = false; + overwater = false; tessellation_count = 33; tessellated = new VertexArray(); @@ -41,15 +42,12 @@ ExplorerChunkTerrain::ExplorerChunkTerrain(OpenGLRenderer* renderer, double x, d _tessellation_current_size = 0; _tessellation_step = _size / (double) _tessellation_max_size; - setMaxTextureSize(128); - maintain(); } ExplorerChunkTerrain::~ExplorerChunkTerrain() { _lock_data.lock(); - delete _color_profile; delete _texture; delete tessellated; _lock_data.unlock(); @@ -65,14 +63,71 @@ bool ExplorerChunkTerrain::maintain() _reset_needed = false; _texture_current_size = 0; _tessellation_current_size = 0; - _overwater = false; + overwater = false; } _lock_data.unlock(); - subchanged = onMaintainEvent(); + // Improve heightmap resolution + if (_tessellation_current_size < _tessellation_max_size) + { + while (_tessellation_current_size < _tessellation_max_size) + { + 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 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; + } + + 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); + } + } + if (interrupt or _reset_needed) + { + return false; + } + } + + _lock_data.lock(); + _tessellation_current_size = new_tessellation_size; + tessellated->setAutoGridIndices(tessellation_count, new_tessellation_inc); + _lock_data.unlock(); + + if (_tessellation_current_size >= 4) + { + break; + } + } + subchanged = true; + } + else + { + subchanged = false; + } // Improve texture resolution - if (_texture_current_size < _texture_max_size) + if (_texture_current_size < _texture_wanted_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)); @@ -83,11 +138,15 @@ 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.normalize(); new_image->setPixel(i, j, color.to32BitRGBA()); } } + + if (interrupt or _reset_needed) + { + return false; + } } _lock_data.lock(); @@ -97,11 +156,6 @@ bool ExplorerChunkTerrain::maintain() _texture_changed = true; _lock_data.unlock(); - /*if (_texture_current_size < 4 && _texture_current_size < _texture_max_size) - { - maintain(); - }*/ - return true; } else @@ -110,77 +164,8 @@ bool ExplorerChunkTerrain::maintain() } } -bool ExplorerChunkTerrain::onMaintainEvent() -{ - // Improve heightmap resolution - if (_tessellation_current_size < _tessellation_max_size) - { - 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 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; - } - - 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) - { - onMaintainEvent(); - } - - return true; - } - else - { - return false; - } -} - 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 @@ -205,10 +190,45 @@ void ExplorerChunkTerrain::updatePriority(CameraDefinition* camera) _startz -= _overall_step; askReset(); } - - _distance_to_camera = getCenter().sub(camera_location).getNorm(); - + distance_to_camera = getCenter().sub(camera_location).getNorm(); _lock_data.unlock(); + + // Update wanted LOD + if (not overwater) + { + _texture_wanted_size = 2; + } + else if (distance_to_camera < 50.0) + { + _texture_wanted_size = _texture_max_size; + } + else if (distance_to_camera < 100.0) + { + _texture_wanted_size = _texture_max_size / 4; + } + else if (distance_to_camera < 200.0) + { + _texture_wanted_size = _texture_max_size / 8; + } + else + { + _texture_wanted_size = 8; + } + + // Update priority + if (_reset_needed || (_texture_max_size > 1 && _texture_current_size <= 1)) + { + priority = 1000.0; + } + else if (_texture_current_size == _texture_wanted_size) + { + priority = -1000.0; + } + else + { + priority = _texture_wanted_size / _texture_current_size; + } + } void ExplorerChunkTerrain::render(QOpenGLShaderProgram* program, OpenGLFunctions* functions) @@ -245,19 +265,18 @@ void ExplorerChunkTerrain::render(QOpenGLShaderProgram* program, OpenGLFunctions int tessellation_size = _tessellation_current_size; _lock_data.unlock(); - if (tessellation_size <= 1 or not _overwater) + if (tessellation_size <= 1 or not overwater) { return; } - _lock_data.lock(); // TEMP + _lock_data.lock(); // 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 + _lock_data.unlock(); } } @@ -266,33 +285,9 @@ void ExplorerChunkTerrain::askReset() _reset_needed = true; } -void ExplorerChunkTerrain::setMaxTextureSize(int size) +void ExplorerChunkTerrain::askInterrupt() { - _texture_max_size = size; -} - -double ExplorerChunkTerrain::getDisplayedSizeHint(CameraDefinition* camera) -{ - double distance; - Vector3 center; - - if (not _overwater) - { - return -1000.0; - } - - center = getCenter(); - - if (camera->isBoxInView(center, _size, 40.0, _size)) - { - distance = _distance_to_camera; - distance = distance < 0.1 ? 0.1 : distance; - return (int) ceil(120.0 - distance / 1.5); - } - else - { - return -800.0; - } + interrupt = true; } Color ExplorerChunkTerrain::getTextureColor(double x, double y) diff --git a/src/render/opengl/ExplorerChunkTerrain.h b/src/render/opengl/ExplorerChunkTerrain.h index c1ae2ca..8cbd0ee 100644 --- a/src/render/opengl/ExplorerChunkTerrain.h +++ b/src/render/opengl/ExplorerChunkTerrain.h @@ -28,10 +28,8 @@ public: void render(QOpenGLShaderProgram* program, OpenGLFunctions* functions); void askReset(); - void setMaxTextureSize(int size); + void askInterrupt(); - bool onMaintainEvent(); - double getDisplayedSizeHint(CameraDefinition* camera); Color getTextureColor(double x, double y); double priority; @@ -44,9 +42,7 @@ private: double _size; double _overall_step; - double _distance_to_camera; double _water_height; - bool _overwater; int tessellation_count; VertexArray *tessellated; @@ -57,15 +53,20 @@ private: QMutex _lock_data; OpenGLRenderer* _renderer; - ColorProfile* _color_profile; bool _reset_needed; + bool interrupt; QImage* _texture; unsigned int texture_id; bool _texture_changed; int _texture_current_size; + int _texture_wanted_size; int _texture_max_size; + + // LOD control + double distance_to_camera; + bool overwater; }; } diff --git a/src/render/opengl/OpenGLPart.cpp b/src/render/opengl/OpenGLPart.cpp index 807f8cf..fad4347 100644 --- a/src/render/opengl/OpenGLPart.cpp +++ b/src/render/opengl/OpenGLPart.cpp @@ -24,6 +24,10 @@ OpenGLPart::~OpenGLPart() } } +void OpenGLPart::interrupt() +{ +} + OpenGLShaderProgram* OpenGLPart::createShader(QString name) { OpenGLShaderProgram* program = new OpenGLShaderProgram(name, renderer); diff --git a/src/render/opengl/OpenGLPart.h b/src/render/opengl/OpenGLPart.h index 906ad7c..8cd5034 100644 --- a/src/render/opengl/OpenGLPart.h +++ b/src/render/opengl/OpenGLPart.h @@ -26,6 +26,9 @@ public: // Do the rendering virtual void render() = 0; + // Interrupt the rendering + virtual void interrupt(); + void updateScenery(bool onlyCommon=false); protected: diff --git a/src/render/opengl/OpenGLRenderer.cpp b/src/render/opengl/OpenGLRenderer.cpp index 48e4204..8eb2424 100644 --- a/src/render/opengl/OpenGLRenderer.cpp +++ b/src/render/opengl/OpenGLRenderer.cpp @@ -32,6 +32,10 @@ OpenGLRenderer::OpenGLRenderer(Scenery* scenery): OpenGLRenderer::~OpenGLRenderer() { + terrain->interrupt(); + water->interrupt(); + skybox->interrupt(); + delete skybox; delete water; delete terrain; diff --git a/src/render/opengl/OpenGLTerrain.cpp b/src/render/opengl/OpenGLTerrain.cpp index c251f84..44798a4 100644 --- a/src/render/opengl/OpenGLTerrain.cpp +++ b/src/render/opengl/OpenGLTerrain.cpp @@ -58,7 +58,7 @@ void OpenGLTerrain::initialize() program->addFragmentSource("terrain"); // Add terrain chunks - int chunks = 25; + int chunks = 16; double size = 800.0; double chunksize = size / (double) chunks; double start = -size / 2.0; @@ -93,6 +93,14 @@ void OpenGLTerrain::render() program->release(); } +void OpenGLTerrain::interrupt() +{ + for (auto chunk: _chunks) + { + chunk->askInterrupt(); + } +} + static bool _cmpChunks(const ExplorerChunkTerrain* c1, const ExplorerChunkTerrain* c2) { return c1->priority > c2->priority; diff --git a/src/render/opengl/OpenGLTerrain.h b/src/render/opengl/OpenGLTerrain.h index d61c657..6a695d1 100644 --- a/src/render/opengl/OpenGLTerrain.h +++ b/src/render/opengl/OpenGLTerrain.h @@ -21,6 +21,7 @@ public: virtual void initialize() override; virtual void update() override; virtual void render() override; + virtual void interrupt() override; void performChunksMaintenance(); diff --git a/src/render/opengl/WidgetExplorer.cpp b/src/render/opengl/WidgetExplorer.cpp index 2e35fb5..0dc9f5f 100644 --- a/src/render/opengl/WidgetExplorer.cpp +++ b/src/render/opengl/WidgetExplorer.cpp @@ -28,6 +28,7 @@ QGLWidget(parent) camera->copy(_current_camera); _renderer = new OpenGLRenderer(scenery); + scenery->setCamera(_current_camera); _average_frame_time = 0.05; _quality = 3; @@ -130,7 +131,7 @@ void WidgetExplorer::mouseMoveEvent(QMouseEvent* event) { factor = 0.01; } - else if (event->modifiers() & Qt::ShiftModifier) + else if ((event->modifiers() & Qt::ShiftModifier) and not (event->buttons() & Qt::LeftButton)) { factor = 1.0; }