Improved the opengl terrain rendering queue

This commit is contained in:
Michaël Lemaire 2013-12-30 16:02:33 +01:00 committed by Michael Lemaire
parent eb795b0f83
commit 1131972759
8 changed files with 144 additions and 127 deletions

View file

@ -12,26 +12,27 @@
ExplorerChunkTerrain::ExplorerChunkTerrain(OpenGLRenderer* renderer, double x, double z, double size, int nbchunks, double water_height): ExplorerChunkTerrain::ExplorerChunkTerrain(OpenGLRenderer* renderer, double x, double z, double size, int nbchunks, double water_height):
_renderer(renderer) _renderer(renderer)
{ {
_color_profile = new ColorProfile(ColorProfile::TONE_MAPPING_REIHNARD, 2.0);
priority = 0.0; priority = 0.0;
_reset_needed = false; _reset_needed = false;
interrupt = false;
_texture = new QImage(1, 1, QImage::Format_RGBA8888); _texture = new QImage(1, 1, QImage::Format_RGBA8888);
texture_id = 0; texture_id = 0;
_texture_changed = false; _texture_changed = false;
_texture_current_size = 0; _texture_current_size = 0;
_texture_max_size = 0; _texture_wanted_size = 0;
_texture_max_size = 256;
_startx = x; _startx = x;
_startz = z; _startz = z;
_size = size; _size = size;
_overall_step = size * (double) nbchunks; _overall_step = size * (double) nbchunks;
_distance_to_camera = 0.0; distance_to_camera = 0.0;
_water_height = water_height; _water_height = water_height;
_overwater = false; overwater = false;
tessellation_count = 33; tessellation_count = 33;
tessellated = new VertexArray<TerrainVertex>(); tessellated = new VertexArray<TerrainVertex>();
@ -41,15 +42,12 @@ ExplorerChunkTerrain::ExplorerChunkTerrain(OpenGLRenderer* renderer, double x, d
_tessellation_current_size = 0; _tessellation_current_size = 0;
_tessellation_step = _size / (double) _tessellation_max_size; _tessellation_step = _size / (double) _tessellation_max_size;
setMaxTextureSize(128);
maintain(); maintain();
} }
ExplorerChunkTerrain::~ExplorerChunkTerrain() ExplorerChunkTerrain::~ExplorerChunkTerrain()
{ {
_lock_data.lock(); _lock_data.lock();
delete _color_profile;
delete _texture; delete _texture;
delete tessellated; delete tessellated;
_lock_data.unlock(); _lock_data.unlock();
@ -65,55 +63,14 @@ bool ExplorerChunkTerrain::maintain()
_reset_needed = false; _reset_needed = false;
_texture_current_size = 0; _texture_current_size = 0;
_tessellation_current_size = 0; _tessellation_current_size = 0;
_overwater = false; overwater = false;
} }
_lock_data.unlock(); _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.to32BitRGBA());
}
}
}
_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()
{
// Improve heightmap resolution // Improve heightmap resolution
if (_tessellation_current_size < _tessellation_max_size) 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 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 old_tessellation_inc = _tessellation_current_size ? _tessellation_max_size / _tessellation_current_size : 1;
@ -131,7 +88,7 @@ bool ExplorerChunkTerrain::onMaintainEvent()
double height = _renderer->getTerrainRenderer()->getHeight(x, z, 1); double height = _renderer->getTerrainRenderer()->getHeight(x, z, 1);
if (height >= _water_height) if (height >= _water_height)
{ {
_overwater = true; overwater = true;
} }
TerrainVertex v; TerrainVertex v;
@ -146,6 +103,10 @@ bool ExplorerChunkTerrain::onMaintainEvent()
tessellated->setGridVertex(tessellation_count, i, j, v); tessellated->setGridVertex(tessellation_count, i, j, v);
} }
} }
if (interrupt or _reset_needed)
{
return false;
}
} }
_lock_data.lock(); _lock_data.lock();
@ -153,34 +114,58 @@ bool ExplorerChunkTerrain::onMaintainEvent()
tessellated->setAutoGridIndices(tessellation_count, new_tessellation_inc); tessellated->setAutoGridIndices(tessellation_count, new_tessellation_inc);
_lock_data.unlock(); _lock_data.unlock();
if (_tessellation_current_size < 4 && _tessellation_current_size < _tessellation_max_size) if (_tessellation_current_size >= 4)
{ {
onMaintainEvent(); break;
} }
}
subchanged = true;
}
else
{
subchanged = false;
}
// Improve texture resolution
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));
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.normalize();
new_image->setPixel(i, j, color.to32BitRGBA());
}
}
if (interrupt or _reset_needed)
{
return false;
}
}
_lock_data.lock();
delete _texture;
_texture = new_image;
_texture_current_size = new_texture_size;
_texture_changed = true;
_lock_data.unlock();
return true; return true;
} }
else else
{ {
return false; return subchanged;
} }
} }
void ExplorerChunkTerrain::updatePriority(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(); Vector3 camera_location = camera->getLocation();
// Handle position // Handle position
@ -205,10 +190,45 @@ void ExplorerChunkTerrain::updatePriority(CameraDefinition* camera)
_startz -= _overall_step; _startz -= _overall_step;
askReset(); askReset();
} }
distance_to_camera = getCenter().sub(camera_location).getNorm();
_distance_to_camera = getCenter().sub(camera_location).getNorm();
_lock_data.unlock(); _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) void ExplorerChunkTerrain::render(QOpenGLShaderProgram* program, OpenGLFunctions* functions)
@ -245,19 +265,18 @@ void ExplorerChunkTerrain::render(QOpenGLShaderProgram* program, OpenGLFunctions
int tessellation_size = _tessellation_current_size; int tessellation_size = _tessellation_current_size;
_lock_data.unlock(); _lock_data.unlock();
if (tessellation_size <= 1 or not _overwater) if (tessellation_size <= 1 or not overwater)
{ {
return; return;
} }
_lock_data.lock(); // TEMP _lock_data.lock();
// TEMP // TEMP
functions->glActiveTexture(GL_TEXTURE0 + 3); functions->glActiveTexture(GL_TEXTURE0 + 3);
functions->glBindTexture(GL_TEXTURE_2D, texture_id); functions->glBindTexture(GL_TEXTURE_2D, texture_id);
program->setUniformValue("groundTexture", 3); program->setUniformValue("groundTexture", 3);
tessellated->render(program, functions); tessellated->render(program, functions);
_lock_data.unlock(); // TEMP _lock_data.unlock();
} }
} }
@ -266,33 +285,9 @@ void ExplorerChunkTerrain::askReset()
_reset_needed = true; _reset_needed = true;
} }
void ExplorerChunkTerrain::setMaxTextureSize(int size) void ExplorerChunkTerrain::askInterrupt()
{ {
_texture_max_size = size; interrupt = true;
}
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;
}
} }
Color ExplorerChunkTerrain::getTextureColor(double x, double y) Color ExplorerChunkTerrain::getTextureColor(double x, double y)

View file

@ -28,10 +28,8 @@ public:
void render(QOpenGLShaderProgram* program, OpenGLFunctions* functions); void render(QOpenGLShaderProgram* program, OpenGLFunctions* functions);
void askReset(); void askReset();
void setMaxTextureSize(int size); void askInterrupt();
bool onMaintainEvent();
double getDisplayedSizeHint(CameraDefinition* camera);
Color getTextureColor(double x, double y); Color getTextureColor(double x, double y);
double priority; double priority;
@ -44,9 +42,7 @@ private:
double _size; double _size;
double _overall_step; double _overall_step;
double _distance_to_camera;
double _water_height; double _water_height;
bool _overwater;
int tessellation_count; int tessellation_count;
VertexArray<TerrainVertex> *tessellated; VertexArray<TerrainVertex> *tessellated;
@ -57,15 +53,20 @@ private:
QMutex _lock_data; QMutex _lock_data;
OpenGLRenderer* _renderer; OpenGLRenderer* _renderer;
ColorProfile* _color_profile;
bool _reset_needed; bool _reset_needed;
bool interrupt;
QImage* _texture; QImage* _texture;
unsigned int texture_id; unsigned int texture_id;
bool _texture_changed; bool _texture_changed;
int _texture_current_size; int _texture_current_size;
int _texture_wanted_size;
int _texture_max_size; int _texture_max_size;
// LOD control
double distance_to_camera;
bool overwater;
}; };
} }

View file

@ -24,6 +24,10 @@ OpenGLPart::~OpenGLPart()
} }
} }
void OpenGLPart::interrupt()
{
}
OpenGLShaderProgram* OpenGLPart::createShader(QString name) OpenGLShaderProgram* OpenGLPart::createShader(QString name)
{ {
OpenGLShaderProgram* program = new OpenGLShaderProgram(name, renderer); OpenGLShaderProgram* program = new OpenGLShaderProgram(name, renderer);

View file

@ -26,6 +26,9 @@ public:
// Do the rendering // Do the rendering
virtual void render() = 0; virtual void render() = 0;
// Interrupt the rendering
virtual void interrupt();
void updateScenery(bool onlyCommon=false); void updateScenery(bool onlyCommon=false);
protected: protected:

View file

@ -32,6 +32,10 @@ OpenGLRenderer::OpenGLRenderer(Scenery* scenery):
OpenGLRenderer::~OpenGLRenderer() OpenGLRenderer::~OpenGLRenderer()
{ {
terrain->interrupt();
water->interrupt();
skybox->interrupt();
delete skybox; delete skybox;
delete water; delete water;
delete terrain; delete terrain;

View file

@ -58,7 +58,7 @@ void OpenGLTerrain::initialize()
program->addFragmentSource("terrain"); program->addFragmentSource("terrain");
// Add terrain chunks // Add terrain chunks
int chunks = 25; int chunks = 16;
double size = 800.0; double size = 800.0;
double chunksize = size / (double) chunks; double chunksize = size / (double) chunks;
double start = -size / 2.0; double start = -size / 2.0;
@ -93,6 +93,14 @@ void OpenGLTerrain::render()
program->release(); program->release();
} }
void OpenGLTerrain::interrupt()
{
for (auto chunk: _chunks)
{
chunk->askInterrupt();
}
}
static bool _cmpChunks(const ExplorerChunkTerrain* c1, const ExplorerChunkTerrain* c2) static bool _cmpChunks(const ExplorerChunkTerrain* c1, const ExplorerChunkTerrain* c2)
{ {
return c1->priority > c2->priority; return c1->priority > c2->priority;

View file

@ -21,6 +21,7 @@ public:
virtual void initialize() override; virtual void initialize() override;
virtual void update() override; virtual void update() override;
virtual void render() override; virtual void render() override;
virtual void interrupt() override;
void performChunksMaintenance(); void performChunksMaintenance();

View file

@ -28,6 +28,7 @@ QGLWidget(parent)
camera->copy(_current_camera); camera->copy(_current_camera);
_renderer = new OpenGLRenderer(scenery); _renderer = new OpenGLRenderer(scenery);
scenery->setCamera(_current_camera);
_average_frame_time = 0.05; _average_frame_time = 0.05;
_quality = 3; _quality = 3;
@ -130,7 +131,7 @@ void WidgetExplorer::mouseMoveEvent(QMouseEvent* event)
{ {
factor = 0.01; factor = 0.01;
} }
else if (event->modifiers() & Qt::ShiftModifier) else if ((event->modifiers() & Qt::ShiftModifier) and not (event->buttons() & Qt::LeftButton))
{ {
factor = 1.0; factor = 1.0;
} }