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);
|
||||
double normalize();
|
||||
Color normalized();
|
||||
double getValue() const;
|
||||
double getPower() const;
|
||||
void limitPower(double max_power);
|
||||
|
|
|
@ -118,6 +118,12 @@ METHSPEC double Color::normalize() {
|
|||
return max;*/
|
||||
}
|
||||
|
||||
METHSPEC Color Color::normalized() {
|
||||
Color col = *this;
|
||||
col.normalize();
|
||||
return col;
|
||||
}
|
||||
|
||||
METHSPEC double Color::getValue() const {
|
||||
double max;
|
||||
|
||||
|
|
|
@ -42,14 +42,17 @@ bool VegetationPresenceDefinition::collectInstances(std::vector<VegetationInstan
|
|||
double size =
|
||||
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 xoffset = fabs(generator->get2DTotal(x * 12.0, -z * 12.0));
|
||||
double zoffset = fabs(generator->get2DTotal(-x * 27.0, -z * 27.0));
|
||||
double y = getScenery()->getTerrain()->getInterpolatedHeight(x + xoffset, z + zoffset, true, true);
|
||||
result->push_back(VegetationInstance(model, Vector3(x + xoffset, y, z + zoffset), size, angle));
|
||||
double xo = x + fabs(generator->get2DTotal(x * 12.0, -z * 12.0));
|
||||
double zo = z + fabs(generator->get2DTotal(-x * 27.0, -z * 27.0));
|
||||
if (xo >= xmin and xo < xmax and zo >= zmin and zo < zmax)
|
||||
{
|
||||
double y = getScenery()->getTerrain()->getInterpolatedHeight(xo, zo, true, true);
|
||||
result->push_back(VegetationInstance(model, Vector3(xo, y, zo), size, angle));
|
||||
added++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return added > 0;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
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
|
||||
|
|
|
@ -23,12 +23,15 @@
|
|||
#include "VegetationInstance.h"
|
||||
#include "VegetationRenderer.h"
|
||||
#include "RayCastingResult.h"
|
||||
#include "OpenGLVegetationImpostor.h"
|
||||
#include "Texture2D.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
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;
|
||||
|
||||
stream << "pic_test_" << name;
|
||||
|
@ -40,7 +43,11 @@ static void startTestRender(SoftwareCanvasRenderer *renderer, const std::string
|
|||
}
|
||||
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() {
|
||||
|
@ -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() {
|
||||
testGroundShadowQuality();
|
||||
testRasterizationQuality();
|
||||
|
@ -297,4 +317,5 @@ void runTestSuite() {
|
|||
testCloudsNearGround();
|
||||
testSunNearHorizon();
|
||||
testVegetationModels();
|
||||
testOpenGLVegetationImpostor();
|
||||
}
|
||||
|
|
|
@ -40,3 +40,13 @@ void OpenGLPart::updateScenery(bool onlyCommon) {
|
|||
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);
|
||||
|
||||
/**
|
||||
* Get access to rendered scenery.
|
||||
*/
|
||||
Scenery *getScenery() const;
|
||||
|
||||
/**
|
||||
* Get access to OpenGL functions.
|
||||
*/
|
||||
OpenGLFunctions *getOpenGlFunctions() const;
|
||||
|
||||
protected:
|
||||
// Create a shader program
|
||||
OpenGLShaderProgram *createShader(QString name);
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "OpenGLSkybox.h"
|
||||
#include "OpenGLWater.h"
|
||||
#include "OpenGLTerrain.h"
|
||||
#include "OpenGLVegetation.h"
|
||||
#include "CloudsRenderer.h"
|
||||
#include "VegetationRenderer.h"
|
||||
#include "Color.h"
|
||||
|
@ -40,9 +41,11 @@ OpenGLRenderer::OpenGLRenderer(Scenery *scenery) : SoftwareRenderer(scenery) {
|
|||
skybox = new OpenGLSkybox(this);
|
||||
water = new OpenGLWater(this);
|
||||
terrain = new OpenGLTerrain(this);
|
||||
vegetation = new OpenGLVegetation(this);
|
||||
}
|
||||
|
||||
OpenGLRenderer::~OpenGLRenderer() {
|
||||
vegetation->interrupt();
|
||||
terrain->interrupt();
|
||||
water->interrupt();
|
||||
skybox->interrupt();
|
||||
|
@ -54,6 +57,7 @@ OpenGLRenderer::~OpenGLRenderer() {
|
|||
delete skybox;
|
||||
delete water;
|
||||
delete terrain;
|
||||
delete vegetation;
|
||||
|
||||
delete functions;
|
||||
delete shared_state;
|
||||
|
@ -69,9 +73,9 @@ void OpenGLRenderer::prepare() {
|
|||
}
|
||||
|
||||
void OpenGLRenderer::initialize() {
|
||||
ready = functions->initializeOpenGLFunctions();
|
||||
bool init = functions->initializeOpenGLFunctions();
|
||||
|
||||
if (ready) {
|
||||
if (init) {
|
||||
prepareOpenGLState();
|
||||
|
||||
prepare();
|
||||
|
@ -85,7 +89,12 @@ void OpenGLRenderer::initialize() {
|
|||
terrain->initialize();
|
||||
terrain->updateScenery();
|
||||
|
||||
vegetation->initialize();
|
||||
vegetation->updateScenery();
|
||||
|
||||
cameraChangeEvent(render_camera);
|
||||
|
||||
ready = true;
|
||||
} else {
|
||||
Logs::error() << "Failed to initialize OpenGL bindings" << std::endl;
|
||||
}
|
||||
|
@ -100,7 +109,7 @@ void OpenGLRenderer::prepareOpenGLState() {
|
|||
functions->glEnable(GL_CULL_FACE);
|
||||
|
||||
functions->glDepthFunc(GL_LESS);
|
||||
functions->glDepthMask(1);
|
||||
functions->glDepthMask(GL_TRUE);
|
||||
functions->glEnable(GL_DEPTH_TEST);
|
||||
|
||||
functions->glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
|
@ -145,6 +154,7 @@ void OpenGLRenderer::paint() {
|
|||
skybox->render();
|
||||
terrain->render();
|
||||
water->render();
|
||||
vegetation->render();
|
||||
|
||||
if (mouse_tracking) {
|
||||
updateMouseProjection();
|
||||
|
@ -164,6 +174,7 @@ void OpenGLRenderer::reset() {
|
|||
skybox->updateScenery();
|
||||
water->updateScenery();
|
||||
terrain->updateScenery();
|
||||
vegetation->updateScenery();
|
||||
|
||||
cameraChangeEvent(render_camera);
|
||||
}
|
||||
|
@ -210,6 +221,9 @@ void OpenGLRenderer::cameraChangeEvent(CameraDefinition *camera) {
|
|||
// Set in shaders
|
||||
shared_state->set("cameraLocation", location);
|
||||
shared_state->set("viewMatrix", *view_matrix);
|
||||
|
||||
// Broadcast to parts
|
||||
vegetation->cameraChanged(camera);
|
||||
}
|
||||
|
||||
double OpenGLRenderer::getPrecision(const Vector3 &) {
|
||||
|
|
|
@ -27,6 +27,9 @@ class OPENGLSHARED_EXPORT OpenGLRenderer : public SoftwareRenderer {
|
|||
inline OpenGLTerrain *getTerrain() const {
|
||||
return terrain;
|
||||
}
|
||||
inline OpenGLVegetation *getVegetation() const {
|
||||
return vegetation;
|
||||
}
|
||||
inline bool isDisplayed() const {
|
||||
return displayed;
|
||||
}
|
||||
|
@ -106,6 +109,7 @@ class OPENGLSHARED_EXPORT OpenGLRenderer : public SoftwareRenderer {
|
|||
OpenGLSkybox *skybox;
|
||||
OpenGLWater *water;
|
||||
OpenGLTerrain *terrain;
|
||||
OpenGLVegetation *vegetation;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,11 +15,13 @@ OpenGLShaderProgram::OpenGLShaderProgram(const std::string &name, OpenGLRenderer
|
|||
: renderer(renderer), name(name) {
|
||||
program = new QOpenGLShaderProgram();
|
||||
functions = renderer->getOpenGlFunctions();
|
||||
state = new OpenGLSharedState();
|
||||
compiled = false;
|
||||
}
|
||||
|
||||
OpenGLShaderProgram::~OpenGLShaderProgram() {
|
||||
delete program;
|
||||
delete state;
|
||||
}
|
||||
|
||||
void OpenGLShaderProgram::addVertexSource(QString path) {
|
||||
|
@ -63,6 +65,7 @@ void OpenGLShaderProgram::bind() {
|
|||
|
||||
int texture_unit = 0;
|
||||
renderer->getSharedState()->apply(this, texture_unit);
|
||||
state->apply(this, texture_unit);
|
||||
}
|
||||
|
||||
void OpenGLShaderProgram::release() {
|
||||
|
|
|
@ -30,6 +30,9 @@ class OPENGLSHARED_EXPORT OpenGLShaderProgram {
|
|||
inline OpenGLRenderer *getRenderer() const {
|
||||
return renderer;
|
||||
}
|
||||
inline OpenGLSharedState *getState() const {
|
||||
return state;
|
||||
}
|
||||
|
||||
protected:
|
||||
friend class OpenGLVariable;
|
||||
|
@ -45,6 +48,8 @@ class OPENGLSHARED_EXPORT OpenGLShaderProgram {
|
|||
QOpenGLShaderProgram *program;
|
||||
OpenGLFunctions *functions;
|
||||
|
||||
OpenGLSharedState *state;
|
||||
|
||||
std::string source_vertex;
|
||||
std::string source_fragment;
|
||||
};
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
OpenGLSharedState::OpenGLSharedState() {
|
||||
}
|
||||
|
||||
paysages::opengl::OpenGLSharedState::~OpenGLSharedState()
|
||||
OpenGLSharedState::~OpenGLSharedState()
|
||||
{
|
||||
for (const auto &pair : variables) {
|
||||
delete pair.second;
|
||||
|
|
|
@ -28,6 +28,12 @@ class OPENGLSHARED_EXPORT OpenGLSharedState {
|
|||
OpenGLVariable *get(const std::string &name);
|
||||
|
||||
// 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) {
|
||||
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) {
|
||||
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) {
|
||||
get(name)->set(vector);
|
||||
}
|
||||
|
|
|
@ -28,6 +28,9 @@ void OpenGLVariable::apply(OpenGLShaderProgram *program, int &texture_unit) {
|
|||
}
|
||||
|
||||
switch (type) {
|
||||
case TYPE_INTEGER:
|
||||
pr->setUniformValue(name.c_str(), value_int);
|
||||
break;
|
||||
case TYPE_FLOAT:
|
||||
pr->setUniformValue(name.c_str(), value_float);
|
||||
break;
|
||||
|
@ -88,6 +91,14 @@ void OpenGLVariable::set(const Texture4D *texture, bool repeat, bool 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) {
|
||||
assert(type == TYPE_NONE or type == TYPE_FLOAT);
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ class OpenGLVariable {
|
|||
TYPE_TEXTURE_2D,
|
||||
TYPE_TEXTURE_3D,
|
||||
TYPE_TEXTURE_4D,
|
||||
TYPE_INTEGER,
|
||||
TYPE_FLOAT,
|
||||
TYPE_VECTOR3,
|
||||
TYPE_MATRIX4,
|
||||
|
@ -34,6 +35,7 @@ class OpenGLVariable {
|
|||
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 Texture4D *texture, bool repeat = false, bool color = true);
|
||||
void set(int value);
|
||||
void set(float value);
|
||||
void set(const Vector3 &vector);
|
||||
void set(const QVector3D &vector);
|
||||
|
@ -48,6 +50,7 @@ class OpenGLVariable {
|
|||
std::string name;
|
||||
OpenGLVariableType type;
|
||||
|
||||
int value_int;
|
||||
float value_float;
|
||||
QColor value_color;
|
||||
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 += \
|
||||
shaders/*.frag \
|
||||
shaders/*.vert
|
||||
|
||||
DISTFILES += \
|
||||
shaders/vegetation.frag \
|
||||
shaders/vegetation.vert
|
||||
|
|
|
@ -19,6 +19,10 @@ class OpenGLVariable;
|
|||
class OpenGLSkybox;
|
||||
class OpenGLWater;
|
||||
class OpenGLTerrain;
|
||||
class OpenGLVegetation;
|
||||
class OpenGLVegetationLayer;
|
||||
class OpenGLVegetationInstance;
|
||||
class OpenGLVegetationImpostor;
|
||||
class ExplorerChunkTerrain;
|
||||
template <typename Vertex> class VertexArray;
|
||||
}
|
||||
|
|
|
@ -11,5 +11,7 @@
|
|||
<file>fadeout.frag</file>
|
||||
<file>noise.frag</file>
|
||||
<file>ui.frag</file>
|
||||
<file>vegetation.vert</file>
|
||||
<file>vegetation.frag</file>
|
||||
</qresource>
|
||||
</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 terrain_renderer;
|
||||
delete textures_renderer;
|
||||
delete vegetation_renderer;
|
||||
delete water_renderer;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,13 @@
|
|||
#include "VegetationModelDefinition.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)
|
||||
: 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;
|
||||
}
|
||||
|
||||
VegetationRenderer::~VegetationRenderer() {
|
||||
}
|
||||
|
||||
void VegetationRenderer::setEnabled(bool enabled) {
|
||||
this->enabled = enabled;
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ namespace software {
|
|||
class SOFTWARESHARED_EXPORT VegetationRenderer : public LightFilter {
|
||||
public:
|
||||
VegetationRenderer(SoftwareRenderer *parent);
|
||||
virtual ~VegetationRenderer();
|
||||
|
||||
/**
|
||||
* 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;
|
||||
SoftwareCanvasRenderer renderer(&scenery);
|
||||
MockOverlayRasterizer rasterizer(&renderer);
|
||||
renderer.setSize(4, 3);
|
||||
renderer.setSoloRasterizer(new MockOverlayRasterizer(&renderer));
|
||||
renderer.setSoloRasterizer(&rasterizer);
|
||||
renderer.render();
|
||||
|
||||
ASSERT_EQ(12, (int)calls.size());
|
||||
|
|
Loading…
Reference in a new issue