Added vegetation impostors to OpenGL renderer
This is currently an unoptimized and broken version, to be improved
This commit is contained in:
parent
9e3c43f510
commit
9d7a7a0ff7
35 changed files with 935 additions and 15 deletions
|
@ -27,6 +27,7 @@ class BASICSSHARED_EXPORT Color {
|
||||||
|
|
||||||
void mask(const Color &mask);
|
void mask(const Color &mask);
|
||||||
double normalize();
|
double normalize();
|
||||||
|
Color normalized();
|
||||||
double getValue() const;
|
double getValue() const;
|
||||||
double getPower() const;
|
double getPower() const;
|
||||||
void limitPower(double max_power);
|
void limitPower(double max_power);
|
||||||
|
|
|
@ -118,6 +118,12 @@ METHSPEC double Color::normalize() {
|
||||||
return max;*/
|
return max;*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
METHSPEC Color Color::normalized() {
|
||||||
|
Color col = *this;
|
||||||
|
col.normalize();
|
||||||
|
return col;
|
||||||
|
}
|
||||||
|
|
||||||
METHSPEC double Color::getValue() const {
|
METHSPEC double Color::getValue() const {
|
||||||
double max;
|
double max;
|
||||||
|
|
||||||
|
|
|
@ -42,11 +42,14 @@ bool VegetationPresenceDefinition::collectInstances(std::vector<VegetationInstan
|
||||||
double size =
|
double size =
|
||||||
0.1 + 0.2 * fabs(generator->get2DTotal(z * 10.0, x * 10.0)) * (noise_presence * 0.5 + 0.5);
|
0.1 + 0.2 * fabs(generator->get2DTotal(z * 10.0, x * 10.0)) * (noise_presence * 0.5 + 0.5);
|
||||||
double angle = 3.0 * generator->get2DTotal(-x * 20.0, z * 20.0); // TODO balanced distribution
|
double angle = 3.0 * generator->get2DTotal(-x * 20.0, z * 20.0); // TODO balanced distribution
|
||||||
double xoffset = fabs(generator->get2DTotal(x * 12.0, -z * 12.0));
|
double xo = x + fabs(generator->get2DTotal(x * 12.0, -z * 12.0));
|
||||||
double zoffset = fabs(generator->get2DTotal(-x * 27.0, -z * 27.0));
|
double zo = z + fabs(generator->get2DTotal(-x * 27.0, -z * 27.0));
|
||||||
double y = getScenery()->getTerrain()->getInterpolatedHeight(x + xoffset, z + zoffset, true, true);
|
if (xo >= xmin and xo < xmax and zo >= zmin and zo < zmax)
|
||||||
result->push_back(VegetationInstance(model, Vector3(x + xoffset, y, z + zoffset), size, angle));
|
{
|
||||||
added++;
|
double y = getScenery()->getTerrain()->getInterpolatedHeight(xo, zo, true, true);
|
||||||
|
result->push_back(VegetationInstance(model, Vector3(xo, y, zo), size, angle));
|
||||||
|
added++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,3 +32,9 @@ else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../../render/softwa
|
||||||
else:unix: LIBS += -L$$OUT_PWD/../../render/software/ -lpaysages_render_software
|
else:unix: LIBS += -L$$OUT_PWD/../../render/software/ -lpaysages_render_software
|
||||||
INCLUDEPATH += $$PWD/../../render/software
|
INCLUDEPATH += $$PWD/../../render/software
|
||||||
DEPENDPATH += $$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
|
||||||
|
|
|
@ -23,12 +23,15 @@
|
||||||
#include "VegetationInstance.h"
|
#include "VegetationInstance.h"
|
||||||
#include "VegetationRenderer.h"
|
#include "VegetationRenderer.h"
|
||||||
#include "RayCastingResult.h"
|
#include "RayCastingResult.h"
|
||||||
|
#include "OpenGLVegetationImpostor.h"
|
||||||
|
#include "Texture2D.h"
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
void startRender(SoftwareCanvasRenderer *renderer, const char *outputpath);
|
void startRender(SoftwareCanvasRenderer *renderer, const char *outputpath);
|
||||||
|
|
||||||
static void startTestRender(SoftwareCanvasRenderer *renderer, const std::string &name, int iteration = -1) {
|
static std::string getFileName(const std::string &name, int iteration = -1) {
|
||||||
std::ostringstream stream;
|
std::ostringstream stream;
|
||||||
|
|
||||||
stream << "pic_test_" << name;
|
stream << "pic_test_" << name;
|
||||||
|
@ -40,7 +43,11 @@ static void startTestRender(SoftwareCanvasRenderer *renderer, const std::string
|
||||||
}
|
}
|
||||||
stream << ".png";
|
stream << ".png";
|
||||||
|
|
||||||
startRender(renderer, stream.str().data());
|
return stream.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void startTestRender(SoftwareCanvasRenderer *renderer, const std::string &name, int iteration = -1) {
|
||||||
|
startRender(renderer, getFileName(name, iteration).data());
|
||||||
}
|
}
|
||||||
|
|
||||||
static void testGroundShadowQuality() {
|
static void testGroundShadowQuality() {
|
||||||
|
@ -288,6 +295,19 @@ static void testVegetationModels() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void testOpenGLVegetationImpostor() {
|
||||||
|
std::string filename = getFileName("opengl_vegetation_impostor");
|
||||||
|
std::cout << "Rendering " << filename << "..." << std::endl;
|
||||||
|
|
||||||
|
Scenery scenery;
|
||||||
|
scenery.autoPreset(1);
|
||||||
|
OpenGLVegetationImpostor impostor(200);
|
||||||
|
VegetationModelDefinition model(NULL);
|
||||||
|
bool interrupted = false;
|
||||||
|
impostor.prepareTexture(model, scenery, &interrupted);
|
||||||
|
impostor.getTexture()->saveToFile(filename);
|
||||||
|
}
|
||||||
|
|
||||||
void runTestSuite() {
|
void runTestSuite() {
|
||||||
testGroundShadowQuality();
|
testGroundShadowQuality();
|
||||||
testRasterizationQuality();
|
testRasterizationQuality();
|
||||||
|
@ -297,4 +317,5 @@ void runTestSuite() {
|
||||||
testCloudsNearGround();
|
testCloudsNearGround();
|
||||||
testSunNearHorizon();
|
testSunNearHorizon();
|
||||||
testVegetationModels();
|
testVegetationModels();
|
||||||
|
testOpenGLVegetationImpostor();
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,3 +40,13 @@ void OpenGLPart::updateScenery(bool onlyCommon) {
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Scenery *OpenGLPart::getScenery() const
|
||||||
|
{
|
||||||
|
return renderer->getScenery();
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenGLFunctions *OpenGLPart::getOpenGlFunctions() const
|
||||||
|
{
|
||||||
|
return renderer->getOpenGlFunctions();
|
||||||
|
}
|
||||||
|
|
|
@ -30,6 +30,16 @@ class OPENGLSHARED_EXPORT OpenGLPart {
|
||||||
|
|
||||||
void updateScenery(bool onlyCommon = false);
|
void updateScenery(bool onlyCommon = false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get access to rendered scenery.
|
||||||
|
*/
|
||||||
|
Scenery *getScenery() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get access to OpenGL functions.
|
||||||
|
*/
|
||||||
|
OpenGLFunctions *getOpenGlFunctions() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Create a shader program
|
// Create a shader program
|
||||||
OpenGLShaderProgram *createShader(QString name);
|
OpenGLShaderProgram *createShader(QString name);
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "OpenGLSkybox.h"
|
#include "OpenGLSkybox.h"
|
||||||
#include "OpenGLWater.h"
|
#include "OpenGLWater.h"
|
||||||
#include "OpenGLTerrain.h"
|
#include "OpenGLTerrain.h"
|
||||||
|
#include "OpenGLVegetation.h"
|
||||||
#include "CloudsRenderer.h"
|
#include "CloudsRenderer.h"
|
||||||
#include "VegetationRenderer.h"
|
#include "VegetationRenderer.h"
|
||||||
#include "Color.h"
|
#include "Color.h"
|
||||||
|
@ -40,9 +41,11 @@ OpenGLRenderer::OpenGLRenderer(Scenery *scenery) : SoftwareRenderer(scenery) {
|
||||||
skybox = new OpenGLSkybox(this);
|
skybox = new OpenGLSkybox(this);
|
||||||
water = new OpenGLWater(this);
|
water = new OpenGLWater(this);
|
||||||
terrain = new OpenGLTerrain(this);
|
terrain = new OpenGLTerrain(this);
|
||||||
|
vegetation = new OpenGLVegetation(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenGLRenderer::~OpenGLRenderer() {
|
OpenGLRenderer::~OpenGLRenderer() {
|
||||||
|
vegetation->interrupt();
|
||||||
terrain->interrupt();
|
terrain->interrupt();
|
||||||
water->interrupt();
|
water->interrupt();
|
||||||
skybox->interrupt();
|
skybox->interrupt();
|
||||||
|
@ -54,6 +57,7 @@ OpenGLRenderer::~OpenGLRenderer() {
|
||||||
delete skybox;
|
delete skybox;
|
||||||
delete water;
|
delete water;
|
||||||
delete terrain;
|
delete terrain;
|
||||||
|
delete vegetation;
|
||||||
|
|
||||||
delete functions;
|
delete functions;
|
||||||
delete shared_state;
|
delete shared_state;
|
||||||
|
@ -69,9 +73,9 @@ void OpenGLRenderer::prepare() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLRenderer::initialize() {
|
void OpenGLRenderer::initialize() {
|
||||||
ready = functions->initializeOpenGLFunctions();
|
bool init = functions->initializeOpenGLFunctions();
|
||||||
|
|
||||||
if (ready) {
|
if (init) {
|
||||||
prepareOpenGLState();
|
prepareOpenGLState();
|
||||||
|
|
||||||
prepare();
|
prepare();
|
||||||
|
@ -85,7 +89,12 @@ void OpenGLRenderer::initialize() {
|
||||||
terrain->initialize();
|
terrain->initialize();
|
||||||
terrain->updateScenery();
|
terrain->updateScenery();
|
||||||
|
|
||||||
|
vegetation->initialize();
|
||||||
|
vegetation->updateScenery();
|
||||||
|
|
||||||
cameraChangeEvent(render_camera);
|
cameraChangeEvent(render_camera);
|
||||||
|
|
||||||
|
ready = true;
|
||||||
} else {
|
} else {
|
||||||
Logs::error() << "Failed to initialize OpenGL bindings" << std::endl;
|
Logs::error() << "Failed to initialize OpenGL bindings" << std::endl;
|
||||||
}
|
}
|
||||||
|
@ -100,7 +109,7 @@ void OpenGLRenderer::prepareOpenGLState() {
|
||||||
functions->glEnable(GL_CULL_FACE);
|
functions->glEnable(GL_CULL_FACE);
|
||||||
|
|
||||||
functions->glDepthFunc(GL_LESS);
|
functions->glDepthFunc(GL_LESS);
|
||||||
functions->glDepthMask(1);
|
functions->glDepthMask(GL_TRUE);
|
||||||
functions->glEnable(GL_DEPTH_TEST);
|
functions->glEnable(GL_DEPTH_TEST);
|
||||||
|
|
||||||
functions->glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
functions->glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||||
|
@ -145,6 +154,7 @@ void OpenGLRenderer::paint() {
|
||||||
skybox->render();
|
skybox->render();
|
||||||
terrain->render();
|
terrain->render();
|
||||||
water->render();
|
water->render();
|
||||||
|
vegetation->render();
|
||||||
|
|
||||||
if (mouse_tracking) {
|
if (mouse_tracking) {
|
||||||
updateMouseProjection();
|
updateMouseProjection();
|
||||||
|
@ -164,6 +174,7 @@ void OpenGLRenderer::reset() {
|
||||||
skybox->updateScenery();
|
skybox->updateScenery();
|
||||||
water->updateScenery();
|
water->updateScenery();
|
||||||
terrain->updateScenery();
|
terrain->updateScenery();
|
||||||
|
vegetation->updateScenery();
|
||||||
|
|
||||||
cameraChangeEvent(render_camera);
|
cameraChangeEvent(render_camera);
|
||||||
}
|
}
|
||||||
|
@ -210,6 +221,9 @@ void OpenGLRenderer::cameraChangeEvent(CameraDefinition *camera) {
|
||||||
// Set in shaders
|
// Set in shaders
|
||||||
shared_state->set("cameraLocation", location);
|
shared_state->set("cameraLocation", location);
|
||||||
shared_state->set("viewMatrix", *view_matrix);
|
shared_state->set("viewMatrix", *view_matrix);
|
||||||
|
|
||||||
|
// Broadcast to parts
|
||||||
|
vegetation->cameraChanged(camera);
|
||||||
}
|
}
|
||||||
|
|
||||||
double OpenGLRenderer::getPrecision(const Vector3 &) {
|
double OpenGLRenderer::getPrecision(const Vector3 &) {
|
||||||
|
|
|
@ -27,6 +27,9 @@ class OPENGLSHARED_EXPORT OpenGLRenderer : public SoftwareRenderer {
|
||||||
inline OpenGLTerrain *getTerrain() const {
|
inline OpenGLTerrain *getTerrain() const {
|
||||||
return terrain;
|
return terrain;
|
||||||
}
|
}
|
||||||
|
inline OpenGLVegetation *getVegetation() const {
|
||||||
|
return vegetation;
|
||||||
|
}
|
||||||
inline bool isDisplayed() const {
|
inline bool isDisplayed() const {
|
||||||
return displayed;
|
return displayed;
|
||||||
}
|
}
|
||||||
|
@ -106,6 +109,7 @@ class OPENGLSHARED_EXPORT OpenGLRenderer : public SoftwareRenderer {
|
||||||
OpenGLSkybox *skybox;
|
OpenGLSkybox *skybox;
|
||||||
OpenGLWater *water;
|
OpenGLWater *water;
|
||||||
OpenGLTerrain *terrain;
|
OpenGLTerrain *terrain;
|
||||||
|
OpenGLVegetation *vegetation;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,11 +15,13 @@ OpenGLShaderProgram::OpenGLShaderProgram(const std::string &name, OpenGLRenderer
|
||||||
: renderer(renderer), name(name) {
|
: renderer(renderer), name(name) {
|
||||||
program = new QOpenGLShaderProgram();
|
program = new QOpenGLShaderProgram();
|
||||||
functions = renderer->getOpenGlFunctions();
|
functions = renderer->getOpenGlFunctions();
|
||||||
|
state = new OpenGLSharedState();
|
||||||
compiled = false;
|
compiled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenGLShaderProgram::~OpenGLShaderProgram() {
|
OpenGLShaderProgram::~OpenGLShaderProgram() {
|
||||||
delete program;
|
delete program;
|
||||||
|
delete state;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLShaderProgram::addVertexSource(QString path) {
|
void OpenGLShaderProgram::addVertexSource(QString path) {
|
||||||
|
@ -63,6 +65,7 @@ void OpenGLShaderProgram::bind() {
|
||||||
|
|
||||||
int texture_unit = 0;
|
int texture_unit = 0;
|
||||||
renderer->getSharedState()->apply(this, texture_unit);
|
renderer->getSharedState()->apply(this, texture_unit);
|
||||||
|
state->apply(this, texture_unit);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLShaderProgram::release() {
|
void OpenGLShaderProgram::release() {
|
||||||
|
|
|
@ -30,6 +30,9 @@ class OPENGLSHARED_EXPORT OpenGLShaderProgram {
|
||||||
inline OpenGLRenderer *getRenderer() const {
|
inline OpenGLRenderer *getRenderer() const {
|
||||||
return renderer;
|
return renderer;
|
||||||
}
|
}
|
||||||
|
inline OpenGLSharedState *getState() const {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class OpenGLVariable;
|
friend class OpenGLVariable;
|
||||||
|
@ -45,6 +48,8 @@ class OPENGLSHARED_EXPORT OpenGLShaderProgram {
|
||||||
QOpenGLShaderProgram *program;
|
QOpenGLShaderProgram *program;
|
||||||
OpenGLFunctions *functions;
|
OpenGLFunctions *functions;
|
||||||
|
|
||||||
|
OpenGLSharedState *state;
|
||||||
|
|
||||||
std::string source_vertex;
|
std::string source_vertex;
|
||||||
std::string source_fragment;
|
std::string source_fragment;
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
OpenGLSharedState::OpenGLSharedState() {
|
OpenGLSharedState::OpenGLSharedState() {
|
||||||
}
|
}
|
||||||
|
|
||||||
paysages::opengl::OpenGLSharedState::~OpenGLSharedState()
|
OpenGLSharedState::~OpenGLSharedState()
|
||||||
{
|
{
|
||||||
for (const auto &pair : variables) {
|
for (const auto &pair : variables) {
|
||||||
delete pair.second;
|
delete pair.second;
|
||||||
|
|
|
@ -28,6 +28,12 @@ class OPENGLSHARED_EXPORT OpenGLSharedState {
|
||||||
OpenGLVariable *get(const std::string &name);
|
OpenGLVariable *get(const std::string &name);
|
||||||
|
|
||||||
// Shortcuts
|
// Shortcuts
|
||||||
|
inline void setInt(const std::string &name, int value) {
|
||||||
|
get(name)->set(value);
|
||||||
|
}
|
||||||
|
inline void set(const std::string &name, float value) {
|
||||||
|
get(name)->set(value);
|
||||||
|
}
|
||||||
inline void set(const std::string &name, const Texture2D *texture, bool repeat = false, bool color = true) {
|
inline void set(const std::string &name, const Texture2D *texture, bool repeat = false, bool color = true) {
|
||||||
get(name)->set(texture, repeat, color);
|
get(name)->set(texture, repeat, color);
|
||||||
}
|
}
|
||||||
|
@ -37,9 +43,6 @@ class OPENGLSHARED_EXPORT OpenGLSharedState {
|
||||||
inline void set(const std::string &name, const Texture4D *texture, bool repeat = false, bool color = true) {
|
inline void set(const std::string &name, const Texture4D *texture, bool repeat = false, bool color = true) {
|
||||||
get(name)->set(texture, repeat, color);
|
get(name)->set(texture, repeat, color);
|
||||||
}
|
}
|
||||||
inline void set(const std::string &name, float value) {
|
|
||||||
get(name)->set(value);
|
|
||||||
}
|
|
||||||
inline void set(const std::string &name, const Vector3 &vector) {
|
inline void set(const std::string &name, const Vector3 &vector) {
|
||||||
get(name)->set(vector);
|
get(name)->set(vector);
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,9 @@ void OpenGLVariable::apply(OpenGLShaderProgram *program, int &texture_unit) {
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
case TYPE_INTEGER:
|
||||||
|
pr->setUniformValue(name.c_str(), value_int);
|
||||||
|
break;
|
||||||
case TYPE_FLOAT:
|
case TYPE_FLOAT:
|
||||||
pr->setUniformValue(name.c_str(), value_float);
|
pr->setUniformValue(name.c_str(), value_float);
|
||||||
break;
|
break;
|
||||||
|
@ -88,6 +91,14 @@ void OpenGLVariable::set(const Texture4D *texture, bool repeat, bool color) {
|
||||||
texture_color = color;
|
texture_color = color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OpenGLVariable::set(int value)
|
||||||
|
{
|
||||||
|
assert(type == TYPE_NONE or type == TYPE_INTEGER);
|
||||||
|
|
||||||
|
type = TYPE_INTEGER;
|
||||||
|
value_int = value;
|
||||||
|
}
|
||||||
|
|
||||||
void OpenGLVariable::set(float value) {
|
void OpenGLVariable::set(float value) {
|
||||||
assert(type == TYPE_NONE or type == TYPE_FLOAT);
|
assert(type == TYPE_NONE or type == TYPE_FLOAT);
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ class OpenGLVariable {
|
||||||
TYPE_TEXTURE_2D,
|
TYPE_TEXTURE_2D,
|
||||||
TYPE_TEXTURE_3D,
|
TYPE_TEXTURE_3D,
|
||||||
TYPE_TEXTURE_4D,
|
TYPE_TEXTURE_4D,
|
||||||
|
TYPE_INTEGER,
|
||||||
TYPE_FLOAT,
|
TYPE_FLOAT,
|
||||||
TYPE_VECTOR3,
|
TYPE_VECTOR3,
|
||||||
TYPE_MATRIX4,
|
TYPE_MATRIX4,
|
||||||
|
@ -34,6 +35,7 @@ class OpenGLVariable {
|
||||||
void set(const Texture2D *texture, bool repeat = false, bool color = true);
|
void set(const Texture2D *texture, bool repeat = false, bool color = true);
|
||||||
void set(const Texture3D *texture, bool repeat = false, bool color = true);
|
void set(const Texture3D *texture, bool repeat = false, bool color = true);
|
||||||
void set(const Texture4D *texture, bool repeat = false, bool color = true);
|
void set(const Texture4D *texture, bool repeat = false, bool color = true);
|
||||||
|
void set(int value);
|
||||||
void set(float value);
|
void set(float value);
|
||||||
void set(const Vector3 &vector);
|
void set(const Vector3 &vector);
|
||||||
void set(const QVector3D &vector);
|
void set(const QVector3D &vector);
|
||||||
|
@ -48,6 +50,7 @@ class OpenGLVariable {
|
||||||
std::string name;
|
std::string name;
|
||||||
OpenGLVariableType type;
|
OpenGLVariableType type;
|
||||||
|
|
||||||
|
int value_int;
|
||||||
float value_float;
|
float value_float;
|
||||||
QColor value_color;
|
QColor value_color;
|
||||||
QVector3D value_vector3;
|
QVector3D value_vector3;
|
||||||
|
|
155
src/render/opengl/OpenGLVegetation.cpp
Normal file
155
src/render/opengl/OpenGLVegetation.cpp
Normal file
|
@ -0,0 +1,155 @@
|
||||||
|
#include "OpenGLVegetation.h"
|
||||||
|
|
||||||
|
#include "OpenGLRenderer.h"
|
||||||
|
#include "OpenGLShaderProgram.h"
|
||||||
|
#include "OpenGLVegetationLayer.h"
|
||||||
|
#include "Thread.h"
|
||||||
|
#include "Mutex.h"
|
||||||
|
#include "Scenery.h"
|
||||||
|
#include "VegetationDefinition.h"
|
||||||
|
#include "VegetationLayerDefinition.h"
|
||||||
|
|
||||||
|
class paysages::opengl::VegetationUpdater : public Thread {
|
||||||
|
public:
|
||||||
|
VegetationUpdater(OpenGLVegetation *vegetation) : vegetation(vegetation) {
|
||||||
|
interrupted = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void interrupt(bool wait = true) {
|
||||||
|
interrupted = true;
|
||||||
|
if (wait) {
|
||||||
|
join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void run() override {
|
||||||
|
while (not interrupted) {
|
||||||
|
std::vector<OpenGLVegetationLayer *> layers;
|
||||||
|
vegetation->acquireLayers(layers);
|
||||||
|
for (auto layer: layers) {
|
||||||
|
layer->threadedUpdate();
|
||||||
|
}
|
||||||
|
vegetation->releaseLayers(layers);
|
||||||
|
timeSleepMs(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool interrupted;
|
||||||
|
OpenGLVegetation *vegetation;
|
||||||
|
};
|
||||||
|
|
||||||
|
OpenGLVegetation::OpenGLVegetation(OpenGLRenderer *renderer) : OpenGLPart(renderer) {
|
||||||
|
layers_lock = new Mutex();
|
||||||
|
updater = new VegetationUpdater(this);
|
||||||
|
enabled = true;
|
||||||
|
|
||||||
|
// Watch scenery changes
|
||||||
|
renderer->getScenery()->getVegetation()->addWatcher(this, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenGLVegetation::~OpenGLVegetation() {
|
||||||
|
for (auto layer: layers) {
|
||||||
|
delete layer;
|
||||||
|
}
|
||||||
|
layers.clear();
|
||||||
|
|
||||||
|
delete layers_lock;
|
||||||
|
|
||||||
|
updater->interrupt();
|
||||||
|
delete updater;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLVegetation::initialize() {
|
||||||
|
// Start the threaded updater
|
||||||
|
updater->start();
|
||||||
|
|
||||||
|
// Prepare shader programs
|
||||||
|
program = createShader("vegetation");
|
||||||
|
program->addVertexSource("vegetation");
|
||||||
|
program->addFragmentSource("atmosphere");
|
||||||
|
program->addFragmentSource("tonemapping");
|
||||||
|
program->addFragmentSource("ui");
|
||||||
|
program->addFragmentSource("vegetation");
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLVegetation::update() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLVegetation::render() {
|
||||||
|
if (enabled) {
|
||||||
|
std::vector<OpenGLVegetationLayer *> layers;
|
||||||
|
acquireLayers(layers);
|
||||||
|
for (auto layer: layers) {
|
||||||
|
layer->render();
|
||||||
|
}
|
||||||
|
releaseLayers(layers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLVegetation::nodeChanged(const DefinitionNode *node, const DefinitionDiff *) {
|
||||||
|
if (node->getPath() == "/vegetation") {
|
||||||
|
updateLayers();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Scenery *OpenGLVegetation::getScenery() const
|
||||||
|
{
|
||||||
|
return renderer->getScenery();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLVegetation::cameraChanged(const CameraDefinition *camera)
|
||||||
|
{
|
||||||
|
std::vector<OpenGLVegetationLayer *> layers;
|
||||||
|
acquireLayers(layers);
|
||||||
|
for (auto layer: layers) {
|
||||||
|
layer->setCamera(camera);
|
||||||
|
}
|
||||||
|
releaseLayers(layers);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLVegetation::acquireLayers(std::vector<OpenGLVegetationLayer *> &layers) {
|
||||||
|
layers_lock->acquire();
|
||||||
|
|
||||||
|
for (auto layer : this->layers) {
|
||||||
|
// TODO Reference count
|
||||||
|
layers.push_back(layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
layers_lock->release();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLVegetation::releaseLayers(const std::vector<OpenGLVegetationLayer *> &layers) {
|
||||||
|
// TODO Reference count
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenGLVegetationLayer *OpenGLVegetation::findLayer(VegetationLayerDefinition *layer) {
|
||||||
|
for (auto &l : layers) {
|
||||||
|
if (l->getDefinition() == layer) {
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLVegetation::setEnabled(bool enabled) {
|
||||||
|
this->enabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLVegetation::updateLayers() {
|
||||||
|
layers_lock->acquire();
|
||||||
|
|
||||||
|
// Add missing layers
|
||||||
|
int n = renderer->getScenery()->getVegetation()->getLayerCount();
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
VegetationLayerDefinition *layer = renderer->getScenery()->getVegetation()->getVegetationLayer(i);
|
||||||
|
if (!findLayer(layer)) {
|
||||||
|
layers.push_back(new OpenGLVegetationLayer(this, layer));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Mark extraneous layers for deletion
|
||||||
|
|
||||||
|
layers_lock->release();
|
||||||
|
}
|
89
src/render/opengl/OpenGLVegetation.h
Normal file
89
src/render/opengl/OpenGLVegetation.h
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
#ifndef OPENGLVEGETATION_H
|
||||||
|
#define OPENGLVEGETATION_H
|
||||||
|
|
||||||
|
#include "opengl_global.h"
|
||||||
|
|
||||||
|
#include "OpenGLPart.h"
|
||||||
|
#include "DefinitionWatcher.h"
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
namespace paysages {
|
||||||
|
namespace opengl {
|
||||||
|
|
||||||
|
class VegetationUpdater;
|
||||||
|
|
||||||
|
class OPENGLSHARED_EXPORT OpenGLVegetation : public OpenGLPart, public DefinitionWatcher {
|
||||||
|
public:
|
||||||
|
OpenGLVegetation(OpenGLRenderer *renderer);
|
||||||
|
virtual ~OpenGLVegetation();
|
||||||
|
|
||||||
|
inline int getLayerCount() {
|
||||||
|
return layers.size();
|
||||||
|
}
|
||||||
|
inline OpenGLVegetationLayer *getLayer(int i) {
|
||||||
|
return layers[i];
|
||||||
|
}
|
||||||
|
inline OpenGLShaderProgram *getProgram() {
|
||||||
|
return program;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void initialize() override;
|
||||||
|
virtual void update() override;
|
||||||
|
virtual void render() override;
|
||||||
|
|
||||||
|
virtual void nodeChanged(const DefinitionNode *node, const DefinitionDiff *diff) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the currently rendered scenery.
|
||||||
|
*/
|
||||||
|
Scenery *getScenery() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call this when the dynamic camera (not the scenery one) changed.
|
||||||
|
*/
|
||||||
|
void cameraChanged(const CameraDefinition *camera);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Acquire the current layers for processing.
|
||||||
|
*
|
||||||
|
* Don't forget to call releaseLayers once done with them.
|
||||||
|
*
|
||||||
|
* This will not hold a lock on them, but increment a reference counter to not delete them while in use.
|
||||||
|
*/
|
||||||
|
void acquireLayers(std::vector<OpenGLVegetationLayer *> &layers);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Release the layers acquired by acquireLayers.
|
||||||
|
*/
|
||||||
|
void releaseLayers(const std::vector<OpenGLVegetationLayer *> &layers);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find a rendering layer, by the matching definition layer.
|
||||||
|
*/
|
||||||
|
OpenGLVegetationLayer *findLayer(VegetationLayerDefinition *layer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable or disable the whole vegetation rendering.
|
||||||
|
*/
|
||||||
|
void setEnabled(bool enabled);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the *layers* member from the scenery.
|
||||||
|
*
|
||||||
|
* This will create missing layers, and mark extraneous ones for deletion.
|
||||||
|
* This will not update existing layers (they should update themselves by watching their definition).
|
||||||
|
*/
|
||||||
|
void updateLayers();
|
||||||
|
|
||||||
|
private:
|
||||||
|
OpenGLShaderProgram *program;
|
||||||
|
bool enabled;
|
||||||
|
std::vector<OpenGLVegetationLayer *> layers;
|
||||||
|
Mutex *layers_lock;
|
||||||
|
VegetationUpdater *updater;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // OPENGLVEGETATION_H
|
106
src/render/opengl/OpenGLVegetationImpostor.cpp
Normal file
106
src/render/opengl/OpenGLVegetationImpostor.cpp
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
#include "OpenGLVegetationImpostor.h"
|
||||||
|
|
||||||
|
#include "OpenGLShaderProgram.h"
|
||||||
|
#include "OpenGLSharedState.h"
|
||||||
|
#include "OpenGLVegetationInstance.h"
|
||||||
|
#include "Texture2D.h"
|
||||||
|
#include "SoftwareRenderer.h"
|
||||||
|
#include "Scenery.h"
|
||||||
|
#include "AtmosphereDefinition.h"
|
||||||
|
#include "GodRaysSampler.h"
|
||||||
|
#include "VegetationRenderer.h"
|
||||||
|
#include "VegetationInstance.h"
|
||||||
|
#include "RayCastingResult.h"
|
||||||
|
#include "SpaceSegment.h"
|
||||||
|
#include "Matrix4.h"
|
||||||
|
#include "LightingManager.h"
|
||||||
|
#include "CameraDefinition.h"
|
||||||
|
|
||||||
|
OpenGLVegetationImpostor::OpenGLVegetationImpostor(int partsize) {
|
||||||
|
vertices = new float[4 * 3];
|
||||||
|
texture_size = partsize * 4;
|
||||||
|
texture = new Texture2D(texture_size, texture_size);
|
||||||
|
texture_changed = true;
|
||||||
|
|
||||||
|
setVertex(0, 0.0f, 0.0f, 0.0f);
|
||||||
|
setVertex(1, 0.0f, 0.0f, 1.0f);
|
||||||
|
setVertex(2, 0.0f, 1.0f, 0.0f);
|
||||||
|
setVertex(3, 0.0f, 1.0f, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenGLVegetationImpostor::~OpenGLVegetationImpostor() {
|
||||||
|
delete[] vertices;
|
||||||
|
delete texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLVegetationImpostor::render(OpenGLShaderProgram *program, const OpenGLVegetationInstance *instance,
|
||||||
|
int index) {
|
||||||
|
if (index == 0 or texture_changed) {
|
||||||
|
texture_changed = false;
|
||||||
|
program->getState()->set("impostorTexture", texture);
|
||||||
|
}
|
||||||
|
program->getState()->setInt("index", 15); // TODO
|
||||||
|
program->getState()->set("offset", instance->getBase());
|
||||||
|
program->getState()->set("size", instance->getSize());
|
||||||
|
program->drawTriangleStrip(vertices, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLVegetationImpostor::prepareTexture(const VegetationModelDefinition &model, const Scenery &environment,
|
||||||
|
bool *interrupt) {
|
||||||
|
Scenery scenery;
|
||||||
|
environment.getAtmosphere()->copy(scenery.getAtmosphere());
|
||||||
|
SoftwareRenderer renderer(&scenery);
|
||||||
|
// FIXME Self light filtering
|
||||||
|
renderer.getLightingManager()->clearFilters();
|
||||||
|
renderer.getGodRaysSampler()->setEnabled(false);
|
||||||
|
VegetationRenderer *vegetation = renderer.getVegetationRenderer();
|
||||||
|
VegetationInstance instance(model, VECTOR_ZERO);
|
||||||
|
|
||||||
|
int parts = 4;
|
||||||
|
int partsize = texture_size / parts;
|
||||||
|
Matrix4 rotation;
|
||||||
|
for (int py = 0; py < parts; py++) {
|
||||||
|
for (int px = 0; px < parts; px++) {
|
||||||
|
int index = py * parts + px;
|
||||||
|
if (index == 0) {
|
||||||
|
rotation = Matrix4::newRotateX(-M_PI_2);
|
||||||
|
} else if (index < 6) {
|
||||||
|
rotation = Matrix4::newRotateY(M_2PI * (double)(index - 1) * 0.2).mult(Matrix4::newRotateX(-M_PI_4));
|
||||||
|
} else {
|
||||||
|
rotation = Matrix4::newRotateY(M_2PI * (double)(index - 6) * 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3 cam(0.0, 0.0, 5.0);
|
||||||
|
scenery.getCamera()->setLocation(rotation.multPoint(cam));
|
||||||
|
scenery.getCamera()->setTarget(VECTOR_ZERO);
|
||||||
|
renderer.prepare();
|
||||||
|
|
||||||
|
int startx = px * partsize;
|
||||||
|
int starty = py * partsize;
|
||||||
|
|
||||||
|
for (int x = 0; x < partsize; x++) {
|
||||||
|
double dx = (double)x / (double)partsize;
|
||||||
|
for (int y = 0; y < partsize; y++) {
|
||||||
|
double dy = (double)y / (double)partsize;
|
||||||
|
|
||||||
|
Vector3 near(dx - 0.5, dy - 0.5, 5.0);
|
||||||
|
Vector3 far(dx - 0.5, dy - 0.5, -5.0);
|
||||||
|
SpaceSegment segment(rotation.multPoint(near.scale(1.3)).add(VECTOR_UP.scale(0.5)),
|
||||||
|
rotation.multPoint(far.scale(1.3)).add(VECTOR_UP.scale(0.5)));
|
||||||
|
|
||||||
|
RayCastingResult result = vegetation->renderInstance(segment, instance, false, true);
|
||||||
|
texture->setPixel(startx + x, starty + y,
|
||||||
|
result.hit ? result.hit_color.normalized() : COLOR_TRANSPARENT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
texture_changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLVegetationImpostor::setVertex(int i, float x, float y, float z) {
|
||||||
|
vertices[i * 3] = x;
|
||||||
|
vertices[i * 3 + 1] = y;
|
||||||
|
vertices[i * 3 + 2] = z;
|
||||||
|
}
|
43
src/render/opengl/OpenGLVegetationImpostor.h
Normal file
43
src/render/opengl/OpenGLVegetationImpostor.h
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
#ifndef OPENGLVEGETATIONIMPOSTOR_H
|
||||||
|
#define OPENGLVEGETATIONIMPOSTOR_H
|
||||||
|
|
||||||
|
#include "opengl_global.h"
|
||||||
|
|
||||||
|
namespace paysages {
|
||||||
|
namespace opengl {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A tool to render an "impostor" of a vegetation layer.
|
||||||
|
*/
|
||||||
|
class OPENGLSHARED_EXPORT OpenGLVegetationImpostor {
|
||||||
|
public:
|
||||||
|
OpenGLVegetationImpostor(int partsize = 64);
|
||||||
|
~OpenGLVegetationImpostor();
|
||||||
|
|
||||||
|
inline const Texture2D *getTexture() const {
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render a single instance using this impostor.
|
||||||
|
*/
|
||||||
|
void render(OpenGLShaderProgram *program, const OpenGLVegetationInstance *instance, int index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepare the texture grid for a given model.
|
||||||
|
*/
|
||||||
|
void prepareTexture(const VegetationModelDefinition &model, const Scenery &environment, bool *interrupt);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setVertex(int i, float x, float y, float z);
|
||||||
|
|
||||||
|
private:
|
||||||
|
float *vertices;
|
||||||
|
int texture_size;
|
||||||
|
bool texture_changed;
|
||||||
|
Texture2D *texture;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // OPENGLVEGETATIONIMPOSTOR_H
|
11
src/render/opengl/OpenGLVegetationInstance.cpp
Normal file
11
src/render/opengl/OpenGLVegetationInstance.cpp
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#include "OpenGLVegetationInstance.h"
|
||||||
|
|
||||||
|
#include "VegetationInstance.h"
|
||||||
|
|
||||||
|
OpenGLVegetationInstance::OpenGLVegetationInstance(const VegetationInstance &wrapped) : wrapped(wrapped) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLVegetationInstance::setDistance(double distance)
|
||||||
|
{
|
||||||
|
this->distance = distance;
|
||||||
|
}
|
43
src/render/opengl/OpenGLVegetationInstance.h
Normal file
43
src/render/opengl/OpenGLVegetationInstance.h
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
#ifndef OPENGLVEGETATIONINSTANCE_H
|
||||||
|
#define OPENGLVEGETATIONINSTANCE_H
|
||||||
|
|
||||||
|
#include "opengl_global.h"
|
||||||
|
|
||||||
|
#include "VegetationInstance.h"
|
||||||
|
|
||||||
|
namespace paysages {
|
||||||
|
namespace opengl {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A single instance of vegetation.
|
||||||
|
*/
|
||||||
|
class OPENGLSHARED_EXPORT OpenGLVegetationInstance {
|
||||||
|
public:
|
||||||
|
OpenGLVegetationInstance(const VegetationInstance &wrapped);
|
||||||
|
|
||||||
|
inline const VegetationModelDefinition &getModel() const {
|
||||||
|
return wrapped.getModel();
|
||||||
|
}
|
||||||
|
inline const Vector3 &getBase() const {
|
||||||
|
return wrapped.getBase();
|
||||||
|
}
|
||||||
|
inline double getSize() const {
|
||||||
|
return wrapped.getSize();
|
||||||
|
}
|
||||||
|
inline double getDistance() const {
|
||||||
|
return distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the distance to camera, mainly for sorting.
|
||||||
|
*/
|
||||||
|
void setDistance(double distance);
|
||||||
|
|
||||||
|
private:
|
||||||
|
VegetationInstance wrapped;
|
||||||
|
double distance;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // OPENGLVEGETATIONINSTANCE_H
|
141
src/render/opengl/OpenGLVegetationLayer.cpp
Normal file
141
src/render/opengl/OpenGLVegetationLayer.cpp
Normal file
|
@ -0,0 +1,141 @@
|
||||||
|
#include "OpenGLVegetationLayer.h"
|
||||||
|
|
||||||
|
#include OPENGL_FUNCTIONS_INCLUDE
|
||||||
|
#include <algorithm>
|
||||||
|
#include "Vector3.h"
|
||||||
|
#include "CameraDefinition.h"
|
||||||
|
#include "Mutex.h"
|
||||||
|
#include "OpenGLVegetation.h"
|
||||||
|
#include "OpenGLVegetationInstance.h"
|
||||||
|
#include "OpenGLVegetationImpostor.h"
|
||||||
|
#include "VegetationLayerDefinition.h"
|
||||||
|
#include "VegetationPresenceDefinition.h"
|
||||||
|
|
||||||
|
OpenGLVegetationLayer::OpenGLVegetationLayer(OpenGLVegetation *parent, VegetationLayerDefinition *definition,
|
||||||
|
bool own_instances)
|
||||||
|
: parent(parent), definition(definition), own_instances(own_instances) {
|
||||||
|
lock_instances = new Mutex;
|
||||||
|
camera_location = new Vector3(0.0, 0.0, 0.0);
|
||||||
|
impostor = new OpenGLVegetationImpostor();
|
||||||
|
range = 10.0;
|
||||||
|
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenGLVegetationLayer::~OpenGLVegetationLayer() {
|
||||||
|
delete camera_location;
|
||||||
|
delete lock_instances;
|
||||||
|
delete impostor;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLVegetationLayer::produceInstancesInArea(double xmin, double xmax, double zmin, double zmax,
|
||||||
|
std::vector<OpenGLVegetationInstance *> *instances) const {
|
||||||
|
std::vector<VegetationInstance> result;
|
||||||
|
definition->getPresence()->collectInstances(&result, *definition->getModel(), xmin, zmin, xmax, zmax, false);
|
||||||
|
for (auto raw_instance : result) {
|
||||||
|
instances->push_back(new OpenGLVegetationInstance(raw_instance));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isNull(void *ptr) {
|
||||||
|
return ptr == NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool compareInstances(OpenGLVegetationInstance *instance1, OpenGLVegetationInstance *instance2) {
|
||||||
|
return instance1->getDistance() > instance2->getDistance();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLVegetationLayer::removeInstancesOutsideArea(double xmin, double xmax, double zmin, double zmax,
|
||||||
|
std::vector<OpenGLVegetationInstance *> *instances) const {
|
||||||
|
for (auto &instance : *instances) {
|
||||||
|
Vector3 base = instance->getBase();
|
||||||
|
if (base.x < xmin or base.x >= xmax or base.z < zmin or base.z >= zmax) {
|
||||||
|
if (own_instances) {
|
||||||
|
delete instance;
|
||||||
|
}
|
||||||
|
instance = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
instances->erase(std::remove_if(instances->begin(), instances->end(), isNull), instances->end());
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLVegetationLayer::threadedUpdate() {
|
||||||
|
if (camera_changed) {
|
||||||
|
camera_changed = false;
|
||||||
|
|
||||||
|
// Compute new area around camera
|
||||||
|
double newxmin, newxmax, newzmin, newzmax;
|
||||||
|
newxmin = camera_location->x - range;
|
||||||
|
newxmax = camera_location->x + range;
|
||||||
|
newzmin = camera_location->z - range;
|
||||||
|
newzmax = camera_location->z + range;
|
||||||
|
|
||||||
|
// Prepare instances where area grew
|
||||||
|
std::vector<OpenGLVegetationInstance *> new_instances;
|
||||||
|
if (newxmin < xmin) {
|
||||||
|
produceInstancesInArea(newxmin, xmin, newzmin, newzmax, &new_instances);
|
||||||
|
}
|
||||||
|
if (newxmax > xmax) {
|
||||||
|
produceInstancesInArea(xmax, newxmax, newzmin, newzmax, &new_instances);
|
||||||
|
}
|
||||||
|
if (newzmin < zmin) {
|
||||||
|
produceInstancesInArea(xmin, xmax, newzmin, zmin, &new_instances);
|
||||||
|
}
|
||||||
|
if (newzmax > zmax) {
|
||||||
|
produceInstancesInArea(xmin, xmax, zmax, newzmax, &new_instances);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply the changes
|
||||||
|
lock_instances->acquire();
|
||||||
|
xmin = newxmin;
|
||||||
|
xmax = newxmax;
|
||||||
|
zmin = newzmin;
|
||||||
|
zmax = newzmax;
|
||||||
|
removeInstancesOutsideArea(xmin, xmax, zmin, zmax, &instances);
|
||||||
|
instances.insert(instances.end(), new_instances.begin(), new_instances.end());
|
||||||
|
for (auto instance: instances) {
|
||||||
|
instance->setDistance(instance->getBase().sub(*camera_location).getNorm());
|
||||||
|
}
|
||||||
|
std::sort(instances.begin(), instances.end(), compareInstances);
|
||||||
|
lock_instances->release();
|
||||||
|
|
||||||
|
// Update impostor texture
|
||||||
|
bool interrupted = false;
|
||||||
|
impostor->prepareTexture(*definition->getModel(), *parent->getScenery(), &interrupted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLVegetationLayer::render() {
|
||||||
|
lock_instances->acquire();
|
||||||
|
|
||||||
|
// TODO Instanced rendering
|
||||||
|
int index = 0;
|
||||||
|
for (auto instance : instances) {
|
||||||
|
impostor->render(parent->getProgram(), instance, index++);
|
||||||
|
}
|
||||||
|
|
||||||
|
lock_instances->release();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLVegetationLayer::reset() {
|
||||||
|
lock_instances->acquire();
|
||||||
|
camera_changed = true;
|
||||||
|
xmin = 0.0;
|
||||||
|
xmax = 0.0;
|
||||||
|
zmin = 0.0;
|
||||||
|
zmax = 0.0;
|
||||||
|
if (own_instances) {
|
||||||
|
for (auto instance : instances) {
|
||||||
|
delete instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
instances.clear();
|
||||||
|
lock_instances->release();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLVegetationLayer::setCamera(const CameraDefinition *camera) {
|
||||||
|
if (camera_location->sub(camera->getLocation()).getNorm() > 1.0) {
|
||||||
|
*camera_location = camera->getLocation();
|
||||||
|
camera_changed = true;
|
||||||
|
}
|
||||||
|
}
|
82
src/render/opengl/OpenGLVegetationLayer.h
Normal file
82
src/render/opengl/OpenGLVegetationLayer.h
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
#ifndef OPENGLVEGETATIONLAYER_H
|
||||||
|
#define OPENGLVEGETATIONLAYER_H
|
||||||
|
|
||||||
|
#include "opengl_global.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace paysages {
|
||||||
|
namespace opengl {
|
||||||
|
|
||||||
|
class OPENGLSHARED_EXPORT OpenGLVegetationLayer {
|
||||||
|
public:
|
||||||
|
OpenGLVegetationLayer(OpenGLVegetation *parent, VegetationLayerDefinition *definition, bool own_instances = true);
|
||||||
|
virtual ~OpenGLVegetationLayer();
|
||||||
|
|
||||||
|
inline auto getDefinition() const {
|
||||||
|
return definition;
|
||||||
|
}
|
||||||
|
inline int getInstanceCount() const {
|
||||||
|
return (int)instances.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collect instances in a given area, and add them to the array *instances*.
|
||||||
|
*
|
||||||
|
* The array is not checked for already present instances.
|
||||||
|
*/
|
||||||
|
virtual void produceInstancesInArea(double xmin, double xmax, double zmin, double zmax,
|
||||||
|
std::vector<OpenGLVegetationInstance *> *instances) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove instances outside of a given area.
|
||||||
|
*/
|
||||||
|
virtual void removeInstancesOutsideArea(double xmin, double xmax, double zmin, double zmax,
|
||||||
|
std::vector<OpenGLVegetationInstance *> *instances) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform maintenance tasks that can be perform in a thread.
|
||||||
|
*
|
||||||
|
* This will be called from a thread separate from the main GUI thread,
|
||||||
|
* so it should not call OpenGL functions.
|
||||||
|
*/
|
||||||
|
void threadedUpdate();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the vegetation layer.
|
||||||
|
*
|
||||||
|
* This is called from the GUI thread.
|
||||||
|
*/
|
||||||
|
void render();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset to an initial state.
|
||||||
|
*
|
||||||
|
* It is only useful (and safe) from unit testing.
|
||||||
|
*/
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the current camera in use.
|
||||||
|
*/
|
||||||
|
void setCamera(const CameraDefinition *camera);
|
||||||
|
|
||||||
|
private:
|
||||||
|
OpenGLVegetation *parent;
|
||||||
|
VegetationLayerDefinition *definition;
|
||||||
|
double xmin;
|
||||||
|
double xmax;
|
||||||
|
double zmin;
|
||||||
|
double zmax;
|
||||||
|
double range;
|
||||||
|
bool own_instances;
|
||||||
|
std::vector<OpenGLVegetationInstance *> instances;
|
||||||
|
Mutex *lock_instances;
|
||||||
|
OpenGLVegetationImpostor *impostor;
|
||||||
|
Vector3 *camera_location;
|
||||||
|
bool camera_changed;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // OPENGLVEGETATIONLAYER_H
|
|
@ -55,3 +55,7 @@ RESOURCES += \
|
||||||
OTHER_FILES += \
|
OTHER_FILES += \
|
||||||
shaders/*.frag \
|
shaders/*.frag \
|
||||||
shaders/*.vert
|
shaders/*.vert
|
||||||
|
|
||||||
|
DISTFILES += \
|
||||||
|
shaders/vegetation.frag \
|
||||||
|
shaders/vegetation.vert
|
||||||
|
|
|
@ -19,6 +19,10 @@ class OpenGLVariable;
|
||||||
class OpenGLSkybox;
|
class OpenGLSkybox;
|
||||||
class OpenGLWater;
|
class OpenGLWater;
|
||||||
class OpenGLTerrain;
|
class OpenGLTerrain;
|
||||||
|
class OpenGLVegetation;
|
||||||
|
class OpenGLVegetationLayer;
|
||||||
|
class OpenGLVegetationInstance;
|
||||||
|
class OpenGLVegetationImpostor;
|
||||||
class ExplorerChunkTerrain;
|
class ExplorerChunkTerrain;
|
||||||
template <typename Vertex> class VertexArray;
|
template <typename Vertex> class VertexArray;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,5 +11,7 @@
|
||||||
<file>fadeout.frag</file>
|
<file>fadeout.frag</file>
|
||||||
<file>noise.frag</file>
|
<file>noise.frag</file>
|
||||||
<file>ui.frag</file>
|
<file>ui.frag</file>
|
||||||
|
<file>vegetation.vert</file>
|
||||||
|
<file>vegetation.frag</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|
15
src/render/opengl/shaders/vegetation.frag
Normal file
15
src/render/opengl/shaders/vegetation.frag
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
varying vec2 texcoord;
|
||||||
|
uniform sampler2D impostorTexture;
|
||||||
|
|
||||||
|
void main(void)
|
||||||
|
{
|
||||||
|
gl_FragColor = texture2D(impostorTexture, texcoord);
|
||||||
|
float alpha = gl_FragColor.a;
|
||||||
|
|
||||||
|
gl_FragColor = applyAerialPerspective(gl_FragColor);
|
||||||
|
|
||||||
|
gl_FragColor = applyToneMapping(gl_FragColor);
|
||||||
|
|
||||||
|
gl_FragColor = applyMouseTracking(unprojected, gl_FragColor);
|
||||||
|
gl_FragColor.a = alpha;
|
||||||
|
}
|
16
src/render/opengl/shaders/vegetation.vert
Normal file
16
src/render/opengl/shaders/vegetation.vert
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
attribute highp vec4 vertex;
|
||||||
|
uniform highp mat4 viewMatrix;
|
||||||
|
uniform highp vec3 offset;
|
||||||
|
uniform float size;
|
||||||
|
uniform int index;
|
||||||
|
varying vec3 unprojected;
|
||||||
|
varying vec2 texcoord;
|
||||||
|
uniform float waterOffset;
|
||||||
|
|
||||||
|
void main(void)
|
||||||
|
{
|
||||||
|
vec3 final = offset + size * (vertex.xyz - vec3(0.0, 0.0, 0.5)); // + vec3(0, waterOffset, 0)
|
||||||
|
unprojected = final.xyz;
|
||||||
|
texcoord = vec2(0.25 * (vertex.z + float(mod(index, 4))), 0.25 * (vertex.y + float(index / 4)));
|
||||||
|
gl_Position = viewMatrix * vec4(final.xyz, 1.0);
|
||||||
|
}
|
|
@ -64,6 +64,7 @@ SoftwareRenderer::~SoftwareRenderer() {
|
||||||
delete clouds_renderer;
|
delete clouds_renderer;
|
||||||
delete terrain_renderer;
|
delete terrain_renderer;
|
||||||
delete textures_renderer;
|
delete textures_renderer;
|
||||||
|
delete vegetation_renderer;
|
||||||
delete water_renderer;
|
delete water_renderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,13 @@
|
||||||
#include "VegetationModelDefinition.h"
|
#include "VegetationModelDefinition.h"
|
||||||
#include "VegetationResult.h"
|
#include "VegetationResult.h"
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
//#define DEBUG_VEGETATION_CONTAINERS 1
|
||||||
|
#endif
|
||||||
|
#ifdef DEBUG_VEGETATION_CONTAINERS
|
||||||
|
SurfaceMaterial DEBUG_MATERIAL1(Color(1.0, 0.0, 0.0));
|
||||||
|
#endif
|
||||||
|
|
||||||
VegetationModelRenderer::VegetationModelRenderer(SoftwareRenderer *parent, const VegetationModelDefinition *model)
|
VegetationModelRenderer::VegetationModelRenderer(SoftwareRenderer *parent, const VegetationModelDefinition *model)
|
||||||
: parent(parent), model(model) {
|
: parent(parent), model(model) {
|
||||||
}
|
}
|
||||||
|
@ -98,6 +105,16 @@ VegetationResult VegetationModelRenderer::getResult(const SpaceSegment &segment,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#ifdef DEBUG_VEGETATION_CONTAINERS
|
||||||
|
if (!hit) {
|
||||||
|
Vector3 near, far;
|
||||||
|
intersections = foliage.findRayIntersection(ray, &near, &far);
|
||||||
|
location = near;
|
||||||
|
normal = VECTOR_ZERO;
|
||||||
|
material = &DEBUG_MATERIAL1;
|
||||||
|
hit = true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,9 @@ VegetationRenderer::VegetationRenderer(SoftwareRenderer *parent) : parent(parent
|
||||||
enabled = true;
|
enabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VegetationRenderer::~VegetationRenderer() {
|
||||||
|
}
|
||||||
|
|
||||||
void VegetationRenderer::setEnabled(bool enabled) {
|
void VegetationRenderer::setEnabled(bool enabled) {
|
||||||
this->enabled = enabled;
|
this->enabled = enabled;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ namespace software {
|
||||||
class SOFTWARESHARED_EXPORT VegetationRenderer : public LightFilter {
|
class SOFTWARESHARED_EXPORT VegetationRenderer : public LightFilter {
|
||||||
public:
|
public:
|
||||||
VegetationRenderer(SoftwareRenderer *parent);
|
VegetationRenderer(SoftwareRenderer *parent);
|
||||||
|
virtual ~VegetationRenderer();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Totally enable or disable the vegetation layers rendering.
|
* Totally enable or disable the vegetation layers rendering.
|
||||||
|
|
67
src/tests/OpenGLVegetationLayer_Test.cpp
Normal file
67
src/tests/OpenGLVegetationLayer_Test.cpp
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
#include "BaseTestCase.h"
|
||||||
|
#include "OpenGLVegetationLayer.h"
|
||||||
|
|
||||||
|
#include "VegetationLayerDefinition.h"
|
||||||
|
#include "VegetationModelDefinition.h"
|
||||||
|
#include "VegetationInstance.h"
|
||||||
|
#include "OpenGLVegetationInstance.h"
|
||||||
|
#include "CameraDefinition.h"
|
||||||
|
|
||||||
|
class FakeLayerRenderer : public OpenGLVegetationLayer {
|
||||||
|
public:
|
||||||
|
FakeLayerRenderer(VegetationLayerDefinition *definition) : OpenGLVegetationLayer(NULL, definition, false) {
|
||||||
|
}
|
||||||
|
virtual ~FakeLayerRenderer() {
|
||||||
|
for (auto instance : static_instances) {
|
||||||
|
delete instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
virtual void produceInstancesInArea(double xmin, double xmax, double zmin, double zmax,
|
||||||
|
std::vector<OpenGLVegetationInstance *> *instances) const override {
|
||||||
|
for (auto instance : static_instances) {
|
||||||
|
Vector3 location = instance->getBase();
|
||||||
|
if (location.x >= xmin and location.z >= zmin and location.x < xmax and location.z < zmax) {
|
||||||
|
instances->push_back(instance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::vector<OpenGLVegetationInstance *> static_instances;
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST(OpenGLVegetationLayer, threadedUpdate) {
|
||||||
|
CameraDefinition camera;
|
||||||
|
VegetationLayerDefinition definition(NULL, "test");
|
||||||
|
FakeLayerRenderer rendering(&definition);
|
||||||
|
VegetationModelDefinition model(NULL);
|
||||||
|
|
||||||
|
EXPECT_EQ(0, rendering.getInstanceCount());
|
||||||
|
|
||||||
|
rendering.threadedUpdate();
|
||||||
|
EXPECT_EQ(0, rendering.getInstanceCount());
|
||||||
|
|
||||||
|
rendering.static_instances.push_back(
|
||||||
|
new OpenGLVegetationInstance(VegetationInstance(model, Vector3(0.0, 0.0, 0.0))));
|
||||||
|
rendering.reset();
|
||||||
|
rendering.threadedUpdate();
|
||||||
|
EXPECT_EQ(1, rendering.getInstanceCount());
|
||||||
|
|
||||||
|
camera.setLocation(Vector3(-5.0, 0.0, 0.0));
|
||||||
|
rendering.setCamera(&camera);
|
||||||
|
rendering.threadedUpdate();
|
||||||
|
EXPECT_EQ(1, rendering.getInstanceCount());
|
||||||
|
|
||||||
|
camera.setLocation(Vector3(-11.0, 0.0, 0.0));
|
||||||
|
rendering.setCamera(&camera);
|
||||||
|
rendering.threadedUpdate();
|
||||||
|
EXPECT_EQ(0, rendering.getInstanceCount());
|
||||||
|
|
||||||
|
camera.setLocation(Vector3(0.0, 0.0, 5.0));
|
||||||
|
rendering.setCamera(&camera);
|
||||||
|
rendering.threadedUpdate();
|
||||||
|
EXPECT_EQ(1, rendering.getInstanceCount());
|
||||||
|
|
||||||
|
camera.setLocation(Vector3(0.0, 0.0, 15.0));
|
||||||
|
rendering.setCamera(&camera);
|
||||||
|
rendering.threadedUpdate();
|
||||||
|
EXPECT_EQ(0, rendering.getInstanceCount());
|
||||||
|
}
|
19
src/tests/OpenGLVegetation_Test.cpp
Normal file
19
src/tests/OpenGLVegetation_Test.cpp
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
#include "BaseTestCase.h"
|
||||||
|
#include "OpenGLVegetation.h"
|
||||||
|
|
||||||
|
#include "Scenery.h"
|
||||||
|
#include "VegetationDefinition.h"
|
||||||
|
#include "VegetationLayerDefinition.h"
|
||||||
|
#include "OpenGLRenderer.h"
|
||||||
|
|
||||||
|
TEST(OpenGLVegetation, updateLayers) {
|
||||||
|
Scenery scenery;
|
||||||
|
OpenGLRenderer renderer(&scenery);
|
||||||
|
OpenGLVegetation glvegetation(&renderer);
|
||||||
|
|
||||||
|
EXPECT_EQ(0, glvegetation.getLayerCount());
|
||||||
|
|
||||||
|
scenery.getVegetation()->addLayer("test");
|
||||||
|
|
||||||
|
EXPECT_EQ(1, glvegetation.getLayerCount());
|
||||||
|
}
|
|
@ -40,8 +40,9 @@ TEST(OverlayRasterizer, pixelProcessing) {
|
||||||
|
|
||||||
Scenery scenery;
|
Scenery scenery;
|
||||||
SoftwareCanvasRenderer renderer(&scenery);
|
SoftwareCanvasRenderer renderer(&scenery);
|
||||||
|
MockOverlayRasterizer rasterizer(&renderer);
|
||||||
renderer.setSize(4, 3);
|
renderer.setSize(4, 3);
|
||||||
renderer.setSoloRasterizer(new MockOverlayRasterizer(&renderer));
|
renderer.setSoloRasterizer(&rasterizer);
|
||||||
renderer.render();
|
renderer.render();
|
||||||
|
|
||||||
ASSERT_EQ(12, (int)calls.size());
|
ASSERT_EQ(12, (int)calls.size());
|
||||||
|
|
Loading…
Reference in a new issue