WIP on impostor instancing

This commit is contained in:
Michaël Lemaire 2015-12-16 09:13:22 +01:00
parent 1a59c44d0c
commit a7b3068e9f
7 changed files with 98 additions and 6 deletions

View file

@ -29,9 +29,9 @@ void VegetationDefinition::applyPreset(VegetationPreset preset, RandomGenerator
clear();
/*if (preset == VEGETATION_PRESET_TEMPERATE) {
if (preset == VEGETATION_PRESET_TEMPERATE) {
layer.applyPreset(VegetationLayerDefinition::VEGETATION_BASIC_TREES, random);
layer.setName("Basic tree");
addLayer(layer);
}*/
}
}

View file

@ -59,12 +59,41 @@ void OpenGLVegetationImpostor::render(OpenGLShaderProgram *program, const OpenGL
state->set("impostorTexture", texture);
}
// FIXME Deprecated, use renderBatch always
vertices->clearIndexes();
int index = getIndex(camera_location, instance->getBase());
state->set("offset", instance->getBase());
state->set("size", 2.0 * instance->getSize());
program->draw(vertices, state, index * 4, 4);
}
void OpenGLVegetationImpostor::renderBatch(OpenGLShaderProgram *program,
const vector<OpenGLVegetationInstance *> &instances,
const Vector3 &camera_location) {
if (texture_changed) {
texture_changed = false;
state->set("impostorTexture", texture);
}
// TODO Cache buffers
vector<unsigned short> indexes(instances.size() * 5);
int i = 0;
for (auto &instance: instances) {
int index = getIndex(camera_location, instance->getBase());
for (int j = 0; j < 4; j++) {
indexes[i * 5 + j] = index * 4 + j;
}
indexes[i * 5 + 4] = OPENGL_RESTART_PRIMITIVE_INDEX;
i++;
}
vertices->setIndexes(indexes);
state->set("offset", VECTOR_UP.scale(10.0));
state->set("size", 1.0);
program->draw(vertices, state);
}
void OpenGLVegetationImpostor::prepareTexture(const VegetationModelDefinition &model, const Scenery &environment,
bool *interrupt) {
Scenery scenery;

View file

@ -3,6 +3,8 @@
#include "opengl_global.h"
#include <vector>
namespace paysages {
namespace opengl {
@ -23,6 +25,12 @@ class OPENGLSHARED_EXPORT OpenGLVegetationImpostor {
*/
void render(OpenGLShaderProgram *program, const OpenGLVegetationInstance *instance, const Vector3 &camera_location);
/**
* Render a whole lot of instances using this impostor.
*/
void renderBatch(OpenGLShaderProgram *program, const vector<OpenGLVegetationInstance *> &instances,
const Vector3 &camera_location);
/**
* Prepare the texture grid for a given model.
*/

View file

@ -115,9 +115,10 @@ void OpenGLVegetationLayer::render() {
lock_instances->acquire();
// TODO Instanced rendering
for (auto instance : instances) {
/*for (auto instance : instances) {
impostor->render(parent->getProgram(), instance, *camera_location);
}
}*/
impostor->renderBatch(parent->getProgram(), instances, *camera_location);
lock_instances->release();
}

View file

@ -1,5 +1,6 @@
#include "OpenGLVertexArray.h"
#include <cassert>
#include "OpenGLFunctions.h"
#include "Logs.h"
#include "Vector3.h"
@ -51,15 +52,32 @@ void OpenGLVertexArray::render(OpenGLFunctions *functions, int start, int count)
update(functions);
}
assert(start >= 0);
int max_count = indexes.empty() ? vertexcount : indexes.size();
if (count < 0) {
count = max_count - start;
}
assert(start + count <= max_count);
if (vertexcount and vao) {
functions->glBindVertexArray(vao);
functions->glDrawArrays(draw_mode, start, count < 0 ? vertexcount : count);
if (indexes.empty()) {
functions->glDrawArrays(draw_mode, start, count);
} else {
// TODO Break in sub-ranges if count is too big
functions->glPrimitiveRestartIndex(OPENGL_RESTART_PRIMITIVE_INDEX);
functions->glDrawRangeElements(draw_mode, 0, vertexcount, count, GL_UNSIGNED_SHORT, indexes.data() + start);
}
functions->glBindVertexArray(0);
}
}
void OpenGLVertexArray::setVertexCount(int count) {
if (count != vertexcount) {
if (count >= OPENGL_RESTART_PRIMITIVE_INDEX) {
Logs::error("OpenGL") << "Can't set vertex count higher than " << OPENGL_RESTART_PRIMITIVE_INDEX << endl;
} else if (count != vertexcount) {
vertexcount = count;
if (count < 1) {
count = 1;
@ -101,9 +119,23 @@ void OpenGLVertexArray::copyTo(OpenGLVertexArray *destination) const {
memcpy(destination->array_vertex, array_vertex, sizeof(float) * vertexcount * 3);
memcpy(destination->array_uv, array_uv, sizeof(float) * vertexcount * 2);
}
destination->setIndexes(indexes);
destination->changed = true;
}
void OpenGLVertexArray::setIndexes(const vector<unsigned short> &indexes) {
#ifndef NDEBUG
for (auto index : indexes) {
assert(index < vertexcount or index == OPENGL_RESTART_PRIMITIVE_INDEX);
}
#endif
this->indexes = indexes;
}
void OpenGLVertexArray::clearIndexes() {
indexes.clear();
}
void OpenGLVertexArray::update(OpenGLFunctions *functions) {
if (not vao) {
functions->glGenVertexArrays(1, &vao);

View file

@ -3,9 +3,13 @@
#include "opengl_global.h"
#include <vector>
namespace paysages {
namespace opengl {
const unsigned short OPENGL_RESTART_PRIMITIVE_INDEX = 65535;
/**
* Vertex arrays storage and binding, to render triangles.
*
@ -62,6 +66,21 @@ class OpenGLVertexArray {
*/
void copyTo(OpenGLVertexArray *destination) const;
/**
* Set the indexes to define the draw order.
*
* Vertex count must have been properly set before calling this.
*
* When this is called, vertices are drawn by specified indexes order,
* instead of their sequential order, thus allowing vertex reuse.
*/
void setIndexes(const vector<unsigned short> &indexes);
/**
* Go back to sequential drawing, after calling setIndexes.
*/
void clearIndexes();
private:
/**
* Update the opengl state.
@ -87,6 +106,7 @@ class OpenGLVertexArray {
int vertexcount;
float *array_vertex;
float *array_uv;
vector<unsigned short> indexes;
};
}
}

View file

@ -13,4 +13,6 @@ void main(void)
final_color = applyMouseTracking(unprojected, final_color);
final_color.a = alpha;
//final_color = vec4(0, 1, 0, 1);
}