Merge branch 'opengl_shaders'

This commit is contained in:
Michaël Lemaire 2013-12-25 16:29:04 +01:00
commit 7d2d022a98
60 changed files with 2207 additions and 763 deletions

View file

@ -4,7 +4,7 @@
ColorProfile::ColorProfile() ColorProfile::ColorProfile()
{ {
setToneMapping(TONE_MAPPING_UNCHARTED, 2.0); setToneMapping(TONE_MAPPING_UNCHARTED, 1.6);
} }
ColorProfile::ColorProfile(ToneMappingOperator tonemapper, double exposure) ColorProfile::ColorProfile(ToneMappingOperator tonemapper, double exposure)

View file

@ -4,6 +4,9 @@
#include "basics_global.h" #include "basics_global.h"
#include "Vector3.h" #include "Vector3.h"
#ifdef QT_GUI_LIB
#include <QMatrix4x4>
#endif
namespace paysages { namespace paysages {
namespace basics { namespace basics {
@ -35,6 +38,15 @@ public:
double getDeterminant() const; double getDeterminant() const;
#ifdef QT_GUI_LIB
inline QMatrix4x4 toQMatrix() const {
return QMatrix4x4(a, b, c, d,
e, f, g, h,
i, j, k, l,
m, n, o, p);
}
#endif
private: private:
double a; double a;
double b; double b;

View file

@ -19,7 +19,7 @@ Texture2D::~Texture2D()
delete[] data; delete[] data;
} }
void Texture2D::getSize(int* xsize, int* ysize) void Texture2D::getSize(int* xsize, int* ysize) const
{ {
*xsize = this->xsize; *xsize = this->xsize;
*ysize = this->ysize; *ysize = this->ysize;
@ -33,7 +33,7 @@ void Texture2D::setPixel(int x, int y, Color col)
data[y * xsize + x] = col; data[y * xsize + x] = col;
} }
Color Texture2D::getPixel(int x, int y) Color Texture2D::getPixel(int x, int y) const
{ {
assert(x >= 0 && x < xsize); assert(x >= 0 && x < xsize);
assert(y >= 0 && y < ysize); assert(y >= 0 && y < ysize);
@ -41,7 +41,7 @@ Color Texture2D::getPixel(int x, int y)
return data[y * xsize + x]; return data[y * xsize + x];
} }
Color Texture2D::getNearest(double dx, double dy) Color Texture2D::getNearest(double dx, double dy) const
{ {
if (dx < 0.0) dx = 0.0; if (dx < 0.0) dx = 0.0;
if (dx > 1.0) dx = 1.0; if (dx > 1.0) dx = 1.0;
@ -57,7 +57,7 @@ Color Texture2D::getNearest(double dx, double dy)
return this->data[iy * this->xsize + ix]; return this->data[iy * this->xsize + ix];
} }
Color Texture2D::getLinear(double dx, double dy) Color Texture2D::getLinear(double dx, double dy) const
{ {
if (dx < 0.0) dx = 0.0; if (dx < 0.0) dx = 0.0;
if (dx > 1.0) dx = 1.0; if (dx > 1.0) dx = 1.0;
@ -89,7 +89,7 @@ Color Texture2D::getLinear(double dx, double dy)
return c1.lerp(c2, dy); return c1.lerp(c2, dy);
} }
Color Texture2D::getCubic(double dx, double dy) Color Texture2D::getCubic(double dx, double dy) const
{ {
/* TODO */ /* TODO */
return getLinear(dx, dy); return getLinear(dx, dy);
@ -122,7 +122,7 @@ void Texture2D::add(Texture2D* source)
} }
} }
void Texture2D::save(PackStream* stream) void Texture2D::save(PackStream* stream) const
{ {
int i, n; int i, n;
stream->write(&this->xsize); stream->write(&this->xsize);
@ -151,17 +151,17 @@ void Texture2D::load(PackStream* stream)
class Texture2DWriter:public PictureWriter class Texture2DWriter:public PictureWriter
{ {
public: public:
Texture2DWriter(Texture2D *tex): tex(tex) {} Texture2DWriter(const Texture2D *tex): tex(tex) {}
virtual unsigned int getPixel(int x, int y) override virtual unsigned int getPixel(int x, int y) override
{ {
return tex->getPixel(x, y).to32BitBGRA(); return tex->getPixel(x, y).to32BitBGRA();
} }
private: private:
Texture2D *tex; const Texture2D *tex;
}; };
void Texture2D::saveToFile(const std::string &filepath) void Texture2D::saveToFile(const std::string &filepath) const
{ {
Texture2DWriter writer(this); Texture2DWriter writer(this);
writer.save(filepath, xsize, ysize); writer.save(filepath, xsize, ysize);

View file

@ -12,17 +12,17 @@ public:
Texture2D(int xsize, int ysize); Texture2D(int xsize, int ysize);
~Texture2D(); ~Texture2D();
void getSize(int* xsize, int* ysize); void getSize(int* xsize, int* ysize) const;
void setPixel(int x, int y, Color col); void setPixel(int x, int y, Color col);
Color getPixel(int x, int y); Color getPixel(int x, int y) const;
Color getNearest(double dx, double dy); Color getNearest(double dx, double dy) const;
Color getLinear(double dx, double dy); Color getLinear(double dx, double dy) const;
Color getCubic(double dx, double dy); Color getCubic(double dx, double dy) const;
void fill(Color col); void fill(Color col);
void add(Texture2D* other); void add(Texture2D* other);
void save(PackStream* stream); void save(PackStream* stream) const;
void load(PackStream* stream); void load(PackStream* stream);
void saveToFile(const std::string &filepath); void saveToFile(const std::string &filepath) const;
private: private:
int xsize; int xsize;

View file

@ -20,7 +20,7 @@ Texture3D::~Texture3D()
delete[] data; delete[] data;
} }
void Texture3D::getSize(int* xsize, int* ysize, int* zsize) void Texture3D::getSize(int* xsize, int* ysize, int* zsize) const
{ {
*xsize = this->xsize; *xsize = this->xsize;
*ysize = this->ysize; *ysize = this->ysize;
@ -36,7 +36,7 @@ void Texture3D::setPixel(int x, int y, int z, Color col)
this->data[z * this->xsize * this->ysize + y * this->xsize + x] = col; this->data[z * this->xsize * this->ysize + y * this->xsize + x] = col;
} }
Color Texture3D::getPixel(int x, int y, int z) Color Texture3D::getPixel(int x, int y, int z) const
{ {
assert(x >= 0 && x < this->xsize); assert(x >= 0 && x < this->xsize);
assert(y >= 0 && y < this->ysize); assert(y >= 0 && y < this->ysize);
@ -45,7 +45,7 @@ Color Texture3D::getPixel(int x, int y, int z)
return this->data[z * this->xsize * this->ysize + y * this->xsize + x]; return this->data[z * this->xsize * this->ysize + y * this->xsize + x];
} }
Color Texture3D::getNearest(double dx, double dy, double dz) Color Texture3D::getNearest(double dx, double dy, double dz) const
{ {
if (dx < 0.0) dx = 0.0; if (dx < 0.0) dx = 0.0;
if (dx > 1.0) dx = 1.0; if (dx > 1.0) dx = 1.0;
@ -65,7 +65,7 @@ Color Texture3D::getNearest(double dx, double dy, double dz)
return this->data[iz * this->xsize * this->ysize + iy * this->xsize + ix]; return this->data[iz * this->xsize * this->ysize + iy * this->xsize + ix];
} }
Color Texture3D::getLinear(double dx, double dy, double dz) Color Texture3D::getLinear(double dx, double dy, double dz) const
{ {
if (dx < 0.0) dx = 0.0; if (dx < 0.0) dx = 0.0;
if (dx > 1.0) dx = 1.0; if (dx > 1.0) dx = 1.0;
@ -112,7 +112,7 @@ Color Texture3D::getLinear(double dx, double dy, double dz)
return cy1.lerp(cy2, dz); return cy1.lerp(cy2, dz);
} }
Color Texture3D::getCubic(double dx, double dy, double dz) Color Texture3D::getCubic(double dx, double dy, double dz) const
{ {
/* TODO */ /* TODO */
return getLinear(dx, dy, dz); return getLinear(dx, dy, dz);
@ -146,7 +146,7 @@ void Texture3D::add(Texture3D* source)
} }
} }
void Texture3D::save(PackStream* stream) void Texture3D::save(PackStream* stream) const
{ {
int i, n; int i, n;
stream->write(&this->xsize); stream->write(&this->xsize);
@ -177,7 +177,7 @@ void Texture3D::load(PackStream* stream)
class Texture3DWriter:public PictureWriter class Texture3DWriter:public PictureWriter
{ {
public: public:
Texture3DWriter(Texture3D *tex): tex(tex) {} Texture3DWriter(const Texture3D *tex): tex(tex) {}
virtual unsigned int getPixel(int x, int y) override virtual unsigned int getPixel(int x, int y) override
{ {
@ -190,10 +190,10 @@ public:
return tex->getPixel(x, y, z).to32BitBGRA(); return tex->getPixel(x, y, z).to32BitBGRA();
} }
private: private:
Texture3D *tex; const Texture3D *tex;
}; };
void Texture3D::saveToFile(const std::string &filepath) void Texture3D::saveToFile(const std::string &filepath) const
{ {
Texture3DWriter writer(this); Texture3DWriter writer(this);
writer.save(filepath, xsize, ysize * zsize); writer.save(filepath, xsize, ysize * zsize);

View file

@ -12,17 +12,17 @@ public:
Texture3D(int xsize, int ysize, int zsize); Texture3D(int xsize, int ysize, int zsize);
~Texture3D(); ~Texture3D();
void getSize(int* xsize, int* ysize, int* zsize); void getSize(int* xsize, int* ysize, int* zsize) const;
void setPixel(int x, int y, int z, Color col); void setPixel(int x, int y, int z, Color col);
Color getPixel(int x, int y, int z); Color getPixel(int x, int y, int z) const;
Color getNearest(double dx, double dy, double dz); Color getNearest(double dx, double dy, double dz) const;
Color getLinear(double dx, double dy, double dz); Color getLinear(double dx, double dy, double dz) const;
Color getCubic(double dx, double dy, double dz); Color getCubic(double dx, double dy, double dz) const;
void fill(Color col); void fill(Color col);
void add(Texture3D* other); void add(Texture3D* other);
void save(PackStream* stream); void save(PackStream* stream) const;
void load(PackStream* stream); void load(PackStream* stream);
void saveToFile(const std::string &filepath); void saveToFile(const std::string &filepath) const;
private: private:
int xsize; int xsize;

View file

@ -21,7 +21,7 @@ Texture4D::~Texture4D()
delete[] data; delete[] data;
} }
void Texture4D::getSize(int* xsize, int* ysize, int* zsize, int* wsize) void Texture4D::getSize(int* xsize, int* ysize, int* zsize, int* wsize) const
{ {
*xsize = this->xsize; *xsize = this->xsize;
*ysize = this->ysize; *ysize = this->ysize;
@ -39,7 +39,7 @@ void Texture4D::setPixel(int x, int y, int z, int w, Color col)
this->data[w * this->xsize * this->ysize * this->zsize + z * this->xsize * this->ysize + y * this->xsize + x] = col; this->data[w * this->xsize * this->ysize * this->zsize + z * this->xsize * this->ysize + y * this->xsize + x] = col;
} }
Color Texture4D::getPixel(int x, int y, int z, int w) Color Texture4D::getPixel(int x, int y, int z, int w) const
{ {
assert(x >= 0 && x < this->xsize); assert(x >= 0 && x < this->xsize);
assert(y >= 0 && y < this->ysize); assert(y >= 0 && y < this->ysize);
@ -49,7 +49,7 @@ Color Texture4D::getPixel(int x, int y, int z, int w)
return this->data[w * this->xsize * this->ysize * this->zsize + z * this->xsize * this->ysize + y * this->xsize + x]; return this->data[w * this->xsize * this->ysize * this->zsize + z * this->xsize * this->ysize + y * this->xsize + x];
} }
Color Texture4D::getNearest(double dx, double dy, double dz, double dw) Color Texture4D::getNearest(double dx, double dy, double dz, double dw) const
{ {
if (dx < 0.0) dx = 0.0; if (dx < 0.0) dx = 0.0;
if (dx > 1.0) dx = 1.0; if (dx > 1.0) dx = 1.0;
@ -73,7 +73,7 @@ Color Texture4D::getNearest(double dx, double dy, double dz, double dw)
return this->data[iw * this->xsize * this->ysize * this->zsize + iz * this->xsize * this->ysize + iy * this->xsize + ix]; return this->data[iw * this->xsize * this->ysize * this->zsize + iz * this->xsize * this->ysize + iy * this->xsize + ix];
} }
Color Texture4D::getLinear(double dx, double dy, double dz, double dw) Color Texture4D::getLinear(double dx, double dy, double dz, double dw) const
{ {
if (dx < 0.0) dx = 0.0; if (dx < 0.0) dx = 0.0;
if (dx > 1.0) dx = 1.0; if (dx > 1.0) dx = 1.0;
@ -143,7 +143,7 @@ Color Texture4D::getLinear(double dx, double dy, double dz, double dw)
return cz1.lerp(cz2, dw); return cz1.lerp(cz2, dw);
} }
Color Texture4D::getCubic(double dx, double dy, double dz, double dw) Color Texture4D::getCubic(double dx, double dy, double dz, double dw) const
{ {
/* TODO */ /* TODO */
return getLinear(dx, dy, dz, dw); return getLinear(dx, dy, dz, dw);
@ -178,7 +178,7 @@ void Texture4D::add(Texture4D* source)
} }
} }
void Texture4D::save(PackStream* stream) void Texture4D::save(PackStream* stream) const
{ {
int i, n; int i, n;
stream->write(&this->xsize); stream->write(&this->xsize);
@ -212,7 +212,7 @@ void Texture4D::load(PackStream* stream)
class Texture4DWriter:public PictureWriter class Texture4DWriter:public PictureWriter
{ {
public: public:
Texture4DWriter(Texture4D *tex): tex(tex) {} Texture4DWriter(const Texture4D *tex): tex(tex) {}
virtual unsigned int getPixel(int x, int y) override virtual unsigned int getPixel(int x, int y) override
{ {
@ -228,10 +228,10 @@ public:
return tex->getPixel(x, y, z, w).to32BitBGRA(); return tex->getPixel(x, y, z, w).to32BitBGRA();
} }
private: private:
Texture4D *tex; const Texture4D *tex;
}; };
void Texture4D::saveToFile(const std::string &filepath) void Texture4D::saveToFile(const std::string &filepath) const
{ {
Texture4DWriter writer(this); Texture4DWriter writer(this);
writer.save(filepath, xsize * wsize, ysize * zsize); writer.save(filepath, xsize * wsize, ysize * zsize);

View file

@ -12,17 +12,17 @@ public:
Texture4D(int xsize, int ysize, int zsize, int wsize); Texture4D(int xsize, int ysize, int zsize, int wsize);
~Texture4D(); ~Texture4D();
void getSize(int* xsize, int* ysize, int* zsize, int* wsize); void getSize(int* xsize, int* ysize, int* zsize, int* wsize) const;
void setPixel(int x, int y, int z, int w, Color col); void setPixel(int x, int y, int z, int w, Color col);
Color getPixel(int x, int y, int z, int w); Color getPixel(int x, int y, int z, int w) const;
Color getNearest(double dx, double dy, double dz, double dw); Color getNearest(double dx, double dy, double dz, double dw) const;
Color getLinear(double dx, double dy, double dz, double dw); Color getLinear(double dx, double dy, double dz, double dw) const;
Color getCubic(double dx, double dy, double dz, double dw); Color getCubic(double dx, double dy, double dz, double dw) const;
void fill(Color col); void fill(Color col);
void add(Texture4D* other); void add(Texture4D* other);
void save(PackStream* stream); void save(PackStream* stream) const;
void load(PackStream* stream); void load(PackStream* stream);
void saveToFile(const std::string &filepath); void saveToFile(const std::string &filepath) const;
private: private:
int xsize; int xsize;

View file

@ -20,6 +20,9 @@ namespace basics {
class NoiseGenerator; class NoiseGenerator;
class Curve; class Curve;
class ColorProfile; class ColorProfile;
class Texture2D;
class Texture3D;
class Texture4D;
} }
} }
using namespace paysages::basics; using namespace paysages::basics;

View file

@ -36,6 +36,7 @@ public:
inline double getRoll() const {return roll;} inline double getRoll() const {return roll;}
inline Vector3 getDirection() const {return Vector3(direction);} inline Vector3 getDirection() const {return Vector3(direction);}
inline Vector3 getDirectionNormalized() const {return forward;} inline Vector3 getDirectionNormalized() const {return forward;}
inline const Matrix4 &getTransformationMatrix() const {return projector;}
inline VectorSpherical getDirectionSpherical() const {return direction;} inline VectorSpherical getDirectionSpherical() const {return direction;}
inline CameraPerspective getPerspective() const {return perspective;} inline CameraPerspective getPerspective() const {return perspective;}

View file

@ -199,8 +199,8 @@ void Scenery::getWater(WaterDefinition* water)
void Scenery::checkCameraAboveGround() void Scenery::checkCameraAboveGround()
{ {
Vector3 camera_location = camera->getLocation(); Vector3 camera_location = camera->getLocation();
double terrain_height = terrain->getInterpolatedHeight(camera_location.x, camera_location.z, 1, 1) + 0.5; double terrain_height = terrain->getInterpolatedHeight(camera_location.x, camera_location.z, 1, 1) + 2.0;
double water_height = terrain->getWaterHeight() + 0.5; double water_height = terrain->getWaterHeight() + 1.5;
if (camera_location.y < water_height || camera_location.y < terrain_height) if (camera_location.y < water_height || camera_location.y < terrain_height)
{ {
double diff = ((water_height > terrain_height) ? water_height : terrain_height) - camera_location.y; double diff = ((water_height > terrain_height) ? water_height : terrain_height) - camera_location.y;

View file

@ -2,6 +2,7 @@
#define DEFINITION_GLOBAL_H #define DEFINITION_GLOBAL_H
#include <QtCore/qglobal.h> #include <QtCore/qglobal.h>
#if defined(DEFINITION_LIBRARY) #if defined(DEFINITION_LIBRARY)
# define DEFINITIONSHARED_EXPORT Q_DECL_EXPORT # define DEFINITIONSHARED_EXPORT Q_DECL_EXPORT
#else #else

View file

@ -1,170 +0,0 @@
#include "BaseExplorerChunk.h"
#include <QImage>
#include <QGLWidget>
#include "ColorProfile.h"
#ifndef GL_CLAMP_TO_EDGE
#define GL_CLAMP_TO_EDGE 0x812F
#endif
BaseExplorerChunk::BaseExplorerChunk(SoftwareRenderer* renderer)
{
_renderer = renderer;
_color_profile = new ColorProfile;
priority = 0.0;
_reset_needed = false;
_texture = new QImage(1, 1, QImage::Format_ARGB32);
_texture_id = 0;
_texture_changed = false;
_texture_current_size = 0;
_texture_max_size = 0;
}
BaseExplorerChunk::~BaseExplorerChunk()
{
_lock_data.lock();
delete _color_profile;
delete _texture;
_lock_data.unlock();
}
bool BaseExplorerChunk::maintain()
{
bool subchanged;
_lock_data.lock();
if (_reset_needed)
{
_reset_needed = false;
_texture_current_size = 0;
onResetEvent();
}
_lock_data.unlock();
subchanged = onMaintainEvent();
// Improve texture resolution
if (_texture_current_size < _texture_max_size)
{
int new_texture_size = _texture_current_size ? _texture_current_size * 2 : 1;
QImage* new_image = new QImage(_texture->scaled(new_texture_size + 1, new_texture_size + 1, Qt::IgnoreAspectRatio, Qt::FastTransformation));
for (int j = 0; j <= new_texture_size; j++)
{
for (int i = 0; i <= new_texture_size; i++)
{
if (_texture_current_size <= 1 || i % 2 != 0 || j % 2 != 0)
{
Color color = getTextureColor((double)i / (double)new_texture_size, 1.0 - (double)j / (double)new_texture_size);
color = _color_profile->apply(color);
color.normalize();
new_image->setPixel(i, j, color.to32BitBGRA());
}
}
}
_lock_data.lock();
delete _texture;
_texture = new_image;
_texture_current_size = new_texture_size;
_texture_changed = true;
_lock_data.unlock();
/*if (_texture_current_size < 4 && _texture_current_size < _texture_max_size)
{
maintain();
}*/
return true;
}
else
{
return subchanged;
}
}
void BaseExplorerChunk::updatePriority(CameraDefinition* camera)
{
if (_reset_needed || (_texture_max_size > 1 && _texture_current_size <= 1))
{
priority = 1000.0;
}
else if (_texture_current_size == _texture_max_size)
{
priority = -1000.0;
}
else
{
priority = getDisplayedSizeHint(camera) - _texture_current_size;
}
onCameraEvent(camera);
}
void BaseExplorerChunk::render(QGLWidget* widget)
{
// Put texture in place
_lock_data.lock();
if (_texture_changed)
{
_texture_changed = false;
if (_texture_id)
{
widget->deleteTexture(_texture_id);
}
// TODO Only do the scale if not power-of-two textures are unsupported by GPU
_texture_id = widget->bindTexture(_texture->scaled(_texture_current_size, _texture_current_size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
//_texture_id = widget->bindTexture(*_texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
else
{
glBindTexture(GL_TEXTURE_2D, _texture_id);
}
_lock_data.unlock();
// Delegate poly rendering to subclass
if (!_reset_needed)
{
onRenderEvent(widget);
}
}
void BaseExplorerChunk::askReset()
{
_reset_needed = true;
}
void BaseExplorerChunk::setMaxTextureSize(int size)
{
_texture_max_size = size;
}
void BaseExplorerChunk::onCameraEvent(CameraDefinition*)
{
}
void BaseExplorerChunk::onResetEvent()
{
}
bool BaseExplorerChunk::onMaintainEvent()
{
return false;
}
void BaseExplorerChunk::onRenderEvent(QGLWidget*)
{
}
double BaseExplorerChunk::getDisplayedSizeHint(CameraDefinition*)
{
return 0.0;
}
Color BaseExplorerChunk::getTextureColor(double, double)
{
return COLOR_TRANSPARENT;
}

View file

@ -1,58 +0,0 @@
#ifndef BASEEXPLORERCHUNK_H
#define BASEEXPLORERCHUNK_H
#include "opengl_global.h"
#include <QMutex>
#include "Color.h"
class QImage;
class QGLWidget;
namespace paysages {
namespace opengl {
class BaseExplorerChunk
{
public:
virtual ~BaseExplorerChunk();
bool maintain();
void updatePriority(CameraDefinition* camera);
void render(QGLWidget* widget);
double priority;
protected:
BaseExplorerChunk(SoftwareRenderer* renderer);
inline SoftwareRenderer* renderer() {return _renderer;}
void askReset();
void setMaxTextureSize(int size);
virtual void onCameraEvent(CameraDefinition* camera);
virtual void onResetEvent();
virtual bool onMaintainEvent();
virtual void onRenderEvent(QGLWidget* widget);
virtual double getDisplayedSizeHint(CameraDefinition* camera);
virtual Color getTextureColor(double x, double y);
QMutex _lock_data;
private:
SoftwareRenderer* _renderer;
ColorProfile* _color_profile;
bool _reset_needed;
QImage* _texture;
unsigned int _texture_id;
bool _texture_changed;
int _texture_current_size;
int _texture_max_size;
};
}
}
#endif // BASEEXPLORERCHUNK_H

View file

@ -1,148 +0,0 @@
#include "ExplorerChunkSky.h"
#include <cmath>
#include <GL/gl.h>
#include "CameraDefinition.h"
#include "SoftwareRenderer.h"
#include "AtmosphereRenderer.h"
#include "AtmosphereResult.h"
ExplorerChunkSky::ExplorerChunkSky(SoftwareRenderer* renderer, double size, SkyboxOrientation orientation) : BaseExplorerChunk(renderer)
{
_box_size = size;
_orientation = orientation;
_center = VECTOR_ZERO;
setMaxTextureSize(256);
maintain();
}
void ExplorerChunkSky::onCameraEvent(CameraDefinition* camera)
{
_center = camera->getLocation();
}
void ExplorerChunkSky::onRenderEvent(QGLWidget*)
{
double size = _box_size;
Vector3 camera = _center;
glBegin(GL_QUADS);
switch (_orientation)
{
case SKYBOX_NORTH:
glTexCoord2d(0.0, 0.0);
glVertex3d(camera.x - size, camera.y + size, camera.z - size);
glTexCoord2d(0.0, 1.0);
glVertex3d(camera.x - size, camera.y - size, camera.z - size);
glTexCoord2d(1.0, 1.0);
glVertex3d(camera.x + size, camera.y - size, camera.z - size);
glTexCoord2d(1.0, 0.0);
glVertex3d(camera.x + size, camera.y + size, camera.z - size);
break;
case SKYBOX_SOUTH:
glTexCoord2d(0.0, 0.0);
glVertex3d(camera.x + size, camera.y + size, camera.z + size);
glTexCoord2d(0.0, 1.0);
glVertex3d(camera.x + size, camera.y - size, camera.z + size);
glTexCoord2d(1.0, 1.0);
glVertex3d(camera.x - size, camera.y - size, camera.z + size);
glTexCoord2d(1.0, 0.0);
glVertex3d(camera.x - size, camera.y + size, camera.z + size);
break;
case SKYBOX_EAST:
glTexCoord2d(0.0, 0.0);
glVertex3d(camera.x + size, camera.y + size, camera.z - size);
glTexCoord2d(0.0, 1.0);
glVertex3d(camera.x + size, camera.y - size, camera.z - size);
glTexCoord2d(1.0, 1.0);
glVertex3d(camera.x + size, camera.y - size, camera.z + size);
glTexCoord2d(1.0, 0.0);
glVertex3d(camera.x + size, camera.y + size, camera.z + size);
break;
case SKYBOX_WEST:
glTexCoord2d(0.0, 0.0);
glVertex3d(camera.x - size, camera.y + size, camera.z + size);
glTexCoord2d(0.0, 1.0);
glVertex3d(camera.x - size, camera.y - size, camera.z + size);
glTexCoord2d(1.0, 1.0);
glVertex3d(camera.x - size, camera.y - size, camera.z - size);
glTexCoord2d(1.0, 0.0);
glVertex3d(camera.x - size, camera.y + size, camera.z - size);
break;
case SKYBOX_TOP:
glTexCoord2d(0.0, 0.0);
glVertex3d(camera.x - size, camera.y + size, camera.z + size);
glTexCoord2d(0.0, 1.0);
glVertex3d(camera.x - size, camera.y + size, camera.z - size);
glTexCoord2d(1.0, 1.0);
glVertex3d(camera.x + size, camera.y + size, camera.z - size);
glTexCoord2d(1.0, 0.0);
glVertex3d(camera.x + size, camera.y + size, camera.z + size);
break;
case SKYBOX_BOTTOM:
/*glTexCoord2d(0.0, 0.0);
glVertex3d(camera.x - size, camera.y - size, camera.z - size);
glTexCoord2d(0.0, 1.0);
glVertex3d(camera.x - size, camera.y - size, camera.z + size);
glTexCoord2d(1.0, 1.0);
glVertex3d(camera.x + size, camera.y - size, camera.z + size);
glTexCoord2d(1.0, 0.0);
glVertex3d(camera.x + size, camera.y - size, camera.z - size);*/
break;
}
glEnd();
}
double ExplorerChunkSky::getDisplayedSizeHint(CameraDefinition*)
{
return 1000.0;
}
Color ExplorerChunkSky::getTextureColor(double x, double y)
{
Vector3 location;
x -= 0.5;
y -= 0.5;
switch (_orientation)
{
case SKYBOX_NORTH:
location.x = x;
location.y = -y;
location.z = -0.5;
break;
case SKYBOX_SOUTH:
location.x = -x;
location.y = -y;
location.z = 0.5;
break;
case SKYBOX_EAST:
location.x = 0.5;
location.y = -y;
location.z = x;
break;
case SKYBOX_WEST:
location.x = -0.5;
location.y = -y;
location.z = -x;
break;
case SKYBOX_TOP:
location.x = x;
location.y = 0.5;
location.z = -y;
break;
case SKYBOX_BOTTOM:
location.x = x;
location.y = -0.5;
location.z = y;
break;
}
location = location.normalize();
if (location.y < 0.0)
{
location.y = 0.0;
}
return renderer()->getAtmosphereRenderer()->getSkyColor(location).final;
}

View file

@ -1,42 +0,0 @@
#ifndef EXPLORERCHUNKSKY_H
#define EXPLORERCHUNKSKY_H
#include "opengl_global.h"
#include "BaseExplorerChunk.h"
#include "Vector3.h"
namespace paysages {
namespace opengl {
enum SkyboxOrientation
{
SKYBOX_NORTH,
SKYBOX_SOUTH,
SKYBOX_WEST,
SKYBOX_EAST,
SKYBOX_TOP,
SKYBOX_BOTTOM
};
class OPENGLSHARED_EXPORT ExplorerChunkSky:public BaseExplorerChunk
{
public:
ExplorerChunkSky(SoftwareRenderer* renderer, double size, SkyboxOrientation orientation);
void onCameraEvent(CameraDefinition* camera);
void onRenderEvent(QGLWidget* widget);
double getDisplayedSizeHint(CameraDefinition* camera);
Color getTextureColor(double x, double y);
private:
SkyboxOrientation _orientation;
double _box_size;
Vector3 _center;
};
}
}
#endif // EXPLORERCHUNKSKY_H

View file

@ -1,13 +1,28 @@
#include "ExplorerChunkTerrain.h" #include "ExplorerChunkTerrain.h"
#include OPENGL_FUNCTIONS_INCLUDE
#include <cmath> #include <cmath>
#include <GL/gl.h> #include <QImage>
#include "ColorProfile.h"
#include "CameraDefinition.h" #include "CameraDefinition.h"
#include "SoftwareRenderer.h" #include "OpenGLRenderer.h"
#include "TerrainRenderer.h" #include "TerrainRenderer.h"
#include "VertexArray.h"
ExplorerChunkTerrain::ExplorerChunkTerrain(SoftwareRenderer* renderer, double x, double z, double size, int nbchunks, double water_height) : BaseExplorerChunk(renderer) ExplorerChunkTerrain::ExplorerChunkTerrain(OpenGLRenderer* renderer, double x, double z, double size, int nbchunks, double water_height):
_renderer(renderer)
{ {
_color_profile = new ColorProfile(ColorProfile::TONE_MAPPING_REIHNARD, 2.0);
priority = 0.0;
_reset_needed = false;
_texture = new QImage(1, 1, QImage::Format_RGBA8888);
texture_id = 0;
_texture_changed = false;
_texture_current_size = 0;
_texture_max_size = 0;
_startx = x; _startx = x;
_startz = z; _startz = z;
_size = size; _size = size;
@ -18,8 +33,11 @@ ExplorerChunkTerrain::ExplorerChunkTerrain(SoftwareRenderer* renderer, double x,
_water_height = water_height; _water_height = water_height;
_overwater = false; _overwater = false;
_tessellation_max_size = 32; tessellation_count = 33;
_tessellation = new double[(_tessellation_max_size + 1) * (_tessellation_max_size + 1)]; tessellated = new VertexArray<TerrainVertex>();
tessellated->setGridSize(tessellation_count);
tessellated->setAutoGridIndices(tessellation_count);
_tessellation_max_size = tessellation_count - 1;
_tessellation_current_size = 0; _tessellation_current_size = 0;
_tessellation_step = _size / (double) _tessellation_max_size; _tessellation_step = _size / (double) _tessellation_max_size;
@ -31,44 +49,108 @@ ExplorerChunkTerrain::ExplorerChunkTerrain(SoftwareRenderer* renderer, double x,
ExplorerChunkTerrain::~ExplorerChunkTerrain() ExplorerChunkTerrain::~ExplorerChunkTerrain()
{ {
_lock_data.lock(); _lock_data.lock();
delete [] _tessellation; delete _color_profile;
delete _texture;
delete tessellated;
_lock_data.unlock(); _lock_data.unlock();
} }
void ExplorerChunkTerrain::onResetEvent() bool ExplorerChunkTerrain::maintain()
{ {
_tessellation_current_size = 0; bool subchanged;
_overwater = false;
_lock_data.lock();
if (_reset_needed)
{
_reset_needed = false;
_texture_current_size = 0;
_tessellation_current_size = 0;
_overwater = false;
}
_lock_data.unlock();
subchanged = onMaintainEvent();
// Improve texture resolution
if (_texture_current_size < _texture_max_size)
{
int new_texture_size = _texture_current_size ? _texture_current_size * 2 : 1;
QImage* new_image = new QImage(_texture->scaled(new_texture_size + 1, new_texture_size + 1, Qt::IgnoreAspectRatio, Qt::FastTransformation));
for (int j = 0; j <= new_texture_size; j++)
{
for (int i = 0; i <= new_texture_size; i++)
{
if (_texture_current_size <= 1 || i % 2 != 0 || j % 2 != 0)
{
Color color = getTextureColor((double)i / (double)new_texture_size, (double)j / (double)new_texture_size);
//color = _color_profile->apply(color);
color.normalize();
new_image->setPixel(i, j, color.to32BitRGBA());
}
}
}
_lock_data.lock();
delete _texture;
_texture = new_image;
_texture_current_size = new_texture_size;
_texture_changed = true;
_lock_data.unlock();
/*if (_texture_current_size < 4 && _texture_current_size < _texture_max_size)
{
maintain();
}*/
return true;
}
else
{
return subchanged;
}
} }
bool ExplorerChunkTerrain::onMaintainEvent() bool ExplorerChunkTerrain::onMaintainEvent()
{ {
SoftwareRenderer* renderer = this->renderer();
// Improve heightmap resolution // Improve heightmap resolution
if (_tessellation_current_size < _tessellation_max_size) if (_tessellation_current_size < _tessellation_max_size)
{ {
int new_tessellation_size = _tessellation_current_size ? _tessellation_current_size * 4 : 2; int new_tessellation_size = _tessellation_current_size ? _tessellation_current_size * 4 : 2;
int old_tessellation_inc = _tessellation_current_size ? _tessellation_max_size / _tessellation_current_size : 1; int old_tessellation_inc = _tessellation_current_size ? _tessellation_max_size / _tessellation_current_size : 1;
int new_tessellation_inc = _tessellation_max_size / new_tessellation_size; int new_tessellation_inc = _tessellation_max_size / new_tessellation_size;
float internal_step = 1.0f / (float)_tessellation_max_size;
for (int j = 0; j <= _tessellation_max_size; j += new_tessellation_inc) for (int j = 0; j <= _tessellation_max_size; j += new_tessellation_inc)
{ {
for (int i = 0; i <= _tessellation_max_size; i += new_tessellation_inc) for (int i = 0; i <= _tessellation_max_size; i += new_tessellation_inc)
{ {
if (_tessellation_current_size == 0 || i % old_tessellation_inc != 0 || j % old_tessellation_inc != 0) if (_tessellation_current_size == 0 || i % old_tessellation_inc != 0 || j % old_tessellation_inc != 0)
{ {
double height = renderer->getTerrainRenderer()->getHeight(_startx + _tessellation_step * (double) i, _startz + _tessellation_step * (double) j, 1); double x = _startx + _tessellation_step * (float)i;
double z = _startz + _tessellation_step * (float)j;
double height = _renderer->getTerrainRenderer()->getHeight(x, z, 1);
if (height >= _water_height) if (height >= _water_height)
{ {
_overwater = true; _overwater = true;
} }
_tessellation[j * (_tessellation_max_size + 1) + i] = height;
TerrainVertex v;
v.uv[0] = internal_step * (float)i;
v.uv[1] = internal_step * (float)j;
v.location[0] = x;
v.location[1] = height;
v.location[2] = z;
tessellated->setGridVertex(tessellation_count, i, j, v);
} }
} }
} }
_lock_data.lock(); _lock_data.lock();
_tessellation_current_size = new_tessellation_size; _tessellation_current_size = new_tessellation_size;
tessellated->setAutoGridIndices(tessellation_count, new_tessellation_inc);
_lock_data.unlock(); _lock_data.unlock();
if (_tessellation_current_size < 4 && _tessellation_current_size < _tessellation_max_size) if (_tessellation_current_size < 4 && _tessellation_current_size < _tessellation_max_size)
@ -84,8 +166,21 @@ bool ExplorerChunkTerrain::onMaintainEvent()
} }
} }
void ExplorerChunkTerrain::onCameraEvent(CameraDefinition* camera) void ExplorerChunkTerrain::updatePriority(CameraDefinition* camera)
{ {
if (_reset_needed || (_texture_max_size > 1 && _texture_current_size <= 1))
{
priority = 1000.0;
}
else if (_texture_current_size == _texture_max_size)
{
priority = -1000.0;
}
else
{
priority = getDisplayedSizeHint(camera) - _texture_current_size;
}
Vector3 camera_location = camera->getLocation(); Vector3 camera_location = camera->getLocation();
// Handle position // Handle position
@ -116,33 +211,66 @@ void ExplorerChunkTerrain::onCameraEvent(CameraDefinition* camera)
_lock_data.unlock(); _lock_data.unlock();
} }
void ExplorerChunkTerrain::onRenderEvent(QGLWidget*) void ExplorerChunkTerrain::render(QOpenGLShaderProgram* program, OpenGLFunctions* functions)
{ {
// Put texture in place
_lock_data.lock(); _lock_data.lock();
int tessellation_size = _tessellation_current_size; if (_texture_changed)
double tsize = 1.0 / (double) _tessellation_max_size; {
_texture_changed = false;
// TODO Only do the scale if not power-of-two textures are unsupported by GPU
QImage tex = _texture->scaled(_texture_current_size, _texture_current_size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
if (texture_id == 0)
{
GLuint texid;
functions->glGenTextures(1, &texid);
texture_id = texid;
}
functions->glBindTexture(GL_TEXTURE_2D, texture_id);
functions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
functions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
functions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
functions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
functions->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, tex.bits());
}
_lock_data.unlock(); _lock_data.unlock();
if (tessellation_size <= 1 or not _overwater) // Render tessellated mesh
if (!_reset_needed)
{ {
return; _lock_data.lock();
} int tessellation_size = _tessellation_current_size;
_lock_data.unlock();
int tessellation_inc = _tessellation_max_size / (double) tessellation_size; if (tessellation_size <= 1 or not _overwater)
for (int j = 0; j < _tessellation_max_size; j += tessellation_inc)
{
glBegin(GL_QUAD_STRIP);
for (int i = 0; i <= _tessellation_max_size; i += tessellation_inc)
{ {
glTexCoord2d(tsize * (double) i, tsize * (double) j); return;
glVertex3d(_startx + _tessellation_step * (double) i, _tessellation[j * (_tessellation_max_size + 1) + i], _startz + _tessellation_step * (double) j);
glTexCoord2d(tsize * (double) i, tsize * (double) (j + tessellation_inc));
glVertex3d(_startx + _tessellation_step * (double) i, _tessellation[(j + tessellation_inc) * (_tessellation_max_size + 1) + i], _startz + _tessellation_step * (double) (j + tessellation_inc));
} }
glEnd();
_lock_data.lock(); // TEMP
// TEMP
functions->glActiveTexture(GL_TEXTURE0 + 3);
functions->glBindTexture(GL_TEXTURE_2D, texture_id);
program->setUniformValue("groundTexture", 3);
tessellated->render(program, functions);
_lock_data.unlock(); // TEMP
} }
} }
void ExplorerChunkTerrain::askReset()
{
_reset_needed = true;
}
void ExplorerChunkTerrain::setMaxTextureSize(int size)
{
_texture_max_size = size;
}
double ExplorerChunkTerrain::getDisplayedSizeHint(CameraDefinition* camera) double ExplorerChunkTerrain::getDisplayedSizeHint(CameraDefinition* camera)
{ {
double distance; double distance;
@ -170,7 +298,7 @@ double ExplorerChunkTerrain::getDisplayedSizeHint(CameraDefinition* camera)
Color ExplorerChunkTerrain::getTextureColor(double x, double y) Color ExplorerChunkTerrain::getTextureColor(double x, double y)
{ {
Vector3 location = {_startx + x * _size, 0.0, _startz + y * _size}; Vector3 location = {_startx + x * _size, 0.0, _startz + y * _size};
return renderer()->getTerrainRenderer()->getFinalColor(location, 0.01); return _renderer->getTerrainRenderer()->getFinalColor(location, 0.01);
} }
Vector3 ExplorerChunkTerrain::getCenter() Vector3 ExplorerChunkTerrain::getCenter()

View file

@ -1,26 +1,41 @@
#ifndef EXPLORERCHUNKTERRAIN_H #ifndef EXPLORERCHUNKTERRAIN_H
#define EXPLORERCHUNKTERRAIN_H #define EXPLORERCHUNKTERRAIN_H
#include "BaseExplorerChunk.h" #include "opengl_global.h"
#include "Vector3.h" #include <QMutex>
class QImage;
class QOpenGLShaderProgram;
namespace paysages { namespace paysages {
namespace opengl { namespace opengl {
class OPENGLSHARED_EXPORT ExplorerChunkTerrain:public BaseExplorerChunk class OPENGLSHARED_EXPORT ExplorerChunkTerrain
{ {
public: public:
ExplorerChunkTerrain(SoftwareRenderer* renderer, double x, double z, double size, int nbchunks, double water_height); typedef struct
{
float location[3];
float uv[2];
} TerrainVertex;
public:
ExplorerChunkTerrain(OpenGLRenderer* renderer, double x, double z, double size, int nbchunks, double water_height);
~ExplorerChunkTerrain(); ~ExplorerChunkTerrain();
void onCameraEvent(CameraDefinition* camera); bool maintain();
void onResetEvent(); void updatePriority(CameraDefinition* camera);
void render(QOpenGLShaderProgram* program, OpenGLFunctions* functions);
void askReset();
void setMaxTextureSize(int size);
bool onMaintainEvent(); bool onMaintainEvent();
void onRenderEvent(QGLWidget* widget);
double getDisplayedSizeHint(CameraDefinition* camera); double getDisplayedSizeHint(CameraDefinition* camera);
Color getTextureColor(double x, double y); Color getTextureColor(double x, double y);
double priority;
private: private:
Vector3 getCenter(); Vector3 getCenter();
@ -33,11 +48,24 @@ private:
double _water_height; double _water_height;
bool _overwater; bool _overwater;
double* _tessellation; int tessellation_count;
VertexArray<TerrainVertex> *tessellated;
int _tessellation_max_size; int _tessellation_max_size;
int _tessellation_current_size; int _tessellation_current_size;
double _tessellation_step; double _tessellation_step;
QMutex _lock_data;
OpenGLRenderer* _renderer;
ColorProfile* _color_profile;
bool _reset_needed;
QImage* _texture;
unsigned int texture_id;
bool _texture_changed;
int _texture_current_size;
int _texture_max_size;
}; };
} }

View file

@ -0,0 +1,49 @@
#include "OpenGLPart.h"
#include <QDir>
#include <cmath>
#include "OpenGLRenderer.h"
#include "OpenGLShaderProgram.h"
#include "CameraDefinition.h"
#include "AtmosphereDefinition.h"
#include "AtmosphereRenderer.h"
#include "Scenery.h"
OpenGLPart::OpenGLPart(OpenGLRenderer* renderer):
renderer(renderer)
{
}
OpenGLPart::~OpenGLPart()
{
QMapIterator<QString, OpenGLShaderProgram*> i(shaders);
while (i.hasNext())
{
i.next();
delete i.value();
}
}
OpenGLShaderProgram* OpenGLPart::createShader(QString name)
{
OpenGLShaderProgram* program = new OpenGLShaderProgram(name, renderer);
if (!shaders.contains(name))
{
shaders[name] = program;
return program;
}
else
{
return 0;
}
}
void OpenGLPart::updateScenery(bool onlyCommon)
{
// Let subclass do its own collecting
if (not onlyCommon)
{
update();
}
}

View file

@ -0,0 +1,44 @@
#ifndef OPENGLPART_H
#define OPENGLPART_H
#include "opengl_global.h"
#include <QMap>
#include <QString>
namespace paysages {
namespace opengl {
// Class that can be inherited by scenery parts, to use OpenGL features
class OPENGLSHARED_EXPORT OpenGLPart
{
public:
OpenGLPart(OpenGLRenderer* renderer);
virtual ~OpenGLPart();
// Initialize the part rendering (create shaders, prepare static textures...)
virtual void initialize() = 0;
// Update parameters from scenery
virtual void update() = 0;
// Do the rendering
virtual void render() = 0;
void updateScenery(bool onlyCommon=false);
protected:
// Create a shader program
OpenGLShaderProgram* createShader(QString name);
// Access to the main scenery renderer
OpenGLRenderer* renderer;
private:
QMap<QString, OpenGLShaderProgram*> shaders;
};
}
}
#endif // OPENGLPART_H

View file

@ -1,62 +1,147 @@
#include "OpenGLRenderer.h" #include "OpenGLRenderer.h"
#include <cmath> #include OPENGL_FUNCTIONS_INCLUDE
#include <GL/gl.h>
#include <GL/glu.h>
#include "Scenery.h"
#include "CameraDefinition.h" #include "CameraDefinition.h"
#include "OpenGLSharedState.h"
#include "OpenGLSkybox.h"
#include "OpenGLWater.h"
#include "OpenGLTerrain.h"
#include "Scenery.h"
#include "LightingManager.h"
#include "Logs.h"
#include "GL/glu.h" // TEMP
OpenGLRenderer::OpenGLRenderer(Scenery* scenery): OpenGLRenderer::OpenGLRenderer(Scenery* scenery):
SoftwareRenderer(scenery) SoftwareRenderer(scenery)
{ {
ready = false;
functions = new OpenGLFunctions();
shared_state = new OpenGLSharedState();
shared_state->set("viewDistance", 300.0);
shared_state->set("exposure", 1.6);
skybox = new OpenGLSkybox(this);
water = new OpenGLWater(this);
terrain = new OpenGLTerrain(this);
} }
OpenGLRenderer::~OpenGLRenderer() OpenGLRenderer::~OpenGLRenderer()
{ {
delete skybox;
delete water;
delete terrain;
delete functions;
delete shared_state;
} }
void OpenGLRenderer::initialize() void OpenGLRenderer::initialize()
{ {
glClearColor(0.0, 0.0, 0.0, 0.0); ready = functions->initializeOpenGLFunctions();
glDisable(GL_LIGHTING); if (ready)
{
functions->glClearColor(0.0, 0.0, 0.0, 0.0);
glFrontFace(GL_CCW); functions->glDisable(GL_LIGHTING);
glCullFace(GL_BACK);
glEnable(GL_CULL_FACE);
glDepthFunc(GL_LESS); functions->glFrontFace(GL_CCW);
glDepthMask(1); functions->glCullFace(GL_BACK);
glEnable(GL_DEPTH_TEST); functions->glEnable(GL_CULL_FACE);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); functions->glDepthFunc(GL_LESS);
glEnable(GL_LINE_SMOOTH); functions->glDepthMask(1);
glLineWidth(1.0); functions->glEnable(GL_DEPTH_TEST);
glDisable(GL_FOG); functions->glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
functions->glEnable(GL_LINE_SMOOTH);
functions->glLineWidth(1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); functions->glDisable(GL_FOG);
prepare(); functions->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
prepare();
disableClouds();
getLightingManager()->setSpecularity(false);
skybox->initialize();
skybox->updateScenery();
water->initialize();
water->updateScenery();
terrain->initialize();
terrain->updateScenery();
cameraChangeEvent(getScenery()->getCamera());
}
else
{
logError("Failed to initialize OpenGL bindings");
}
} }
void OpenGLRenderer::resize(int width, int height) void OpenGLRenderer::resize(int width, int height)
{ {
CameraPerspective perspective; if (ready)
{
functions->glViewport(0, 0, width, height);
}
getScenery()->getCamera()->setRenderSize(width, height);
render_camera->setRenderSize(width, height);
glViewport(0, 0, width, height); cameraChangeEvent(getScenery()->getCamera());
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
perspective = render_camera->getPerspective();
gluPerspective(perspective.yfov * 180.0 / M_PI, perspective.xratio, perspective.znear, perspective.zfar);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
} }
void OpenGLRenderer::paint() void OpenGLRenderer::paint()
{ {
if (ready)
{
functions->glClearColor(0.0, 0.0, 0.0, 0.0);
functions->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
functions->glEnable(GL_BLEND);
functions->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
skybox->render();
terrain->render();
water->render();
int error_code;
while ((error_code = glGetError()) != GL_NO_ERROR)
{
logWarning("[OpenGL] ERROR : %s", (const char*)gluErrorString(error_code));
}
}
}
void OpenGLRenderer::cameraChangeEvent(CameraDefinition *camera)
{
// Get camera info
Vector3 location = camera->getLocation();
Vector3 target = camera->getTarget();
Vector3 up = camera->getUpVector();
CameraPerspective perspective = camera->getPerspective();
// Compute matrix
QMatrix4x4 transform;
transform.setToIdentity();
transform.lookAt(QVector3D(location.x, location.y, location.z),
QVector3D(target.x, target.y, target.z),
QVector3D(up.x, up.y, up.z));
QMatrix4x4 projection;
projection.setToIdentity();
projection.perspective(perspective.yfov * 180.0 / M_PI, perspective.xratio, perspective.znear, perspective.zfar);
// Set in shaders
shared_state->set("cameraLocation", location);
shared_state->set("viewMatrix", projection * transform);
} }
double OpenGLRenderer::getPrecision(const Vector3 &) double OpenGLRenderer::getPrecision(const Vector3 &)

View file

@ -21,8 +21,23 @@ public:
void resize(int width, int height); void resize(int width, int height);
void paint(); void paint();
void cameraChangeEvent(CameraDefinition* camera);
inline OpenGLFunctions* getOpenGlFunctions() const {return functions;}
inline OpenGLSharedState* getSharedState() const {return shared_state;}
virtual double getPrecision(const Vector3 &location) override; virtual double getPrecision(const Vector3 &location) override;
virtual Color applyMediumTraversal(Vector3 location, Color color) override; virtual Color applyMediumTraversal(Vector3 location, Color color) override;
private:
bool ready;
OpenGLFunctions* functions;
OpenGLSharedState* shared_state;
OpenGLSkybox* skybox;
OpenGLWater* water;
OpenGLTerrain* terrain;
}; };
} }

View file

@ -0,0 +1,115 @@
#include "OpenGLShaderProgram.h"
#include OPENGL_FUNCTIONS_INCLUDE
#include <QOpenGLShaderProgram>
#include <QDir>
#include "OpenGLRenderer.h"
#include "OpenGLSharedState.h"
#include "Texture2D.h"
#include "Texture3D.h"
#include "Texture4D.h"
#include "Color.h"
#include "Logs.h"
OpenGLShaderProgram::OpenGLShaderProgram(QString name, OpenGLRenderer* renderer):
renderer(renderer), name(name)
{
program = new QOpenGLShaderProgram();
functions = renderer->getOpenGlFunctions();
compiled = false;
}
OpenGLShaderProgram::~OpenGLShaderProgram()
{
delete program;
}
void OpenGLShaderProgram::addVertexSource(QString path)
{
QFile file(QString(":/shaders/%1.vert").arg(path));
if (file.open(QIODevice::ReadOnly | QIODevice::Text))
{
source_vertex += QString(file.readAll()).toStdString();
}
else
{
logError() << "Can't open vertex file " << file.fileName();
}
}
void OpenGLShaderProgram::addFragmentSource(QString path)
{
QFile file(QString(":/shaders/%1.frag").arg(path));
if (file.open(QIODevice::ReadOnly | QIODevice::Text))
{
source_fragment += QString(file.readAll()).toStdString();
}
else
{
logError() << "Can't open fragment file " << file.fileName();
}
}
void OpenGLShaderProgram::compile()
{
program->addShaderFromSourceCode(QOpenGLShader::Vertex, QString::fromStdString(source_vertex));
program->addShaderFromSourceCode(QOpenGLShader::Fragment, QString::fromStdString(source_fragment));
if (not program->link())
{
qWarning() << "Error while compiling shader " << name << "\n" << program->log() << "\n";
}
else if (program->log().length() > 0)
{
qDebug() << "Shader " << name << " compilation output:\n" << program->log() << "\n";
}
}
void OpenGLShaderProgram::bind()
{
if (not compiled)
{
compile();
compiled = true;
}
program->bind();
int texture_unit = 0;
renderer->getSharedState()->apply(this, texture_unit);
}
void OpenGLShaderProgram::release()
{
program->release();
}
void OpenGLShaderProgram::drawTriangles(float* vertices, int triangle_count)
{
bind();
GLuint vertex = program->attributeLocation("vertex");
program->setAttributeArray(vertex, GL_FLOAT, vertices, 3);
program->enableAttributeArray(vertex);
functions->glDrawArrays(GL_TRIANGLES, 0, triangle_count * 3);
program->disableAttributeArray(vertex);
release();
}
void OpenGLShaderProgram::drawTriangleStrip(float* vertices, int vertex_count)
{
bind();
GLuint vertex = program->attributeLocation("vertex");
program->setAttributeArray(vertex, GL_FLOAT, vertices, 3);
program->enableAttributeArray(vertex);
functions->glDrawArrays(GL_TRIANGLE_STRIP, 0, vertex_count);
program->disableAttributeArray(vertex);
release();
}

View file

@ -0,0 +1,52 @@
#ifndef OPENGLSHADERPROGRAM_H
#define OPENGLSHADERPROGRAM_H
#include "opengl_global.h"
#include <QString>
class QOpenGLShaderProgram;
namespace paysages {
namespace opengl {
class OPENGLSHARED_EXPORT OpenGLShaderProgram
{
public:
OpenGLShaderProgram(QString name, OpenGLRenderer* renderer);
~OpenGLShaderProgram();
void addVertexSource(QString path);
void addFragmentSource(QString path);
void drawTriangles(float* vertices, int triangle_count);
void drawTriangleStrip(float* vertices, int vertex_count);
void bind();
void release();
inline QOpenGLShaderProgram* getProgram() const {return program;}
inline OpenGLRenderer* getRenderer() const {return renderer;}
protected:
friend class OpenGLVariable;
private:
void compile();
bool compiled;
OpenGLRenderer* renderer;
QString name;
QOpenGLShaderProgram* program;
OpenGLFunctions* functions;
std::string source_vertex;
std::string source_fragment;
};
}
}
#endif // OPENGLSHADERPROGRAM_H

View file

@ -0,0 +1,23 @@
#include "OpenGLSharedState.h"
OpenGLSharedState::OpenGLSharedState()
{
}
void OpenGLSharedState::apply(OpenGLShaderProgram *program, int &texture_unit)
{
for (const auto &pair : variables)
{
pair.second->apply(program, texture_unit);
}
}
OpenGLVariable *OpenGLSharedState::get(const std::string &name)
{
OpenGLVariable*& var = variables[name];
if (var == 0)
{
var = new OpenGLVariable(name);
}
return var;
}

View file

@ -0,0 +1,48 @@
#ifndef OPENGLSHAREDSTATE_H
#define OPENGLSHAREDSTATE_H
#include "opengl_global.h"
#include <map>
#include "OpenGLVariable.h"
namespace paysages {
namespace opengl {
/*!
* \brief OpenGL variables that can be shared between shaders.
*/
class OPENGLSHARED_EXPORT OpenGLSharedState
{
public:
OpenGLSharedState();
/*!
* \brief Apply the stored variables to the bound program.
*/
void apply(OpenGLShaderProgram* program, int &texture_unit);
/*!
* \brief Get or create a variable in the state.
*/
OpenGLVariable *get(const std::string &name);
// Shortcuts
inline void set(const std::string &name, const Texture2D *texture) {get(name)->set(texture);}
inline void set(const std::string &name, const Texture3D *texture) {get(name)->set(texture);}
inline void set(const std::string &name, const Texture4D *texture) {get(name)->set(texture);}
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);}
inline void set(const std::string &name, const QVector3D &vector) {get(name)->set(vector);}
inline void set(const std::string &name, const Matrix4 &matrix) {get(name)->set(matrix);}
inline void set(const std::string &name, const QMatrix4x4 &matrix) {get(name)->set(matrix);}
inline void set(const std::string &name, const Color &color) {get(name)->set(color);}
private:
std::map<std::string, OpenGLVariable*> variables;
};
}
}
#endif // OPENGLSHAREDSTATE_H

View file

@ -0,0 +1,104 @@
#include "OpenGLSkybox.h"
#include <cmath>
#include "OpenGLRenderer.h"
#include "OpenGLShaderProgram.h"
#include "OpenGLSharedState.h"
#include "Scenery.h"
#include "AtmosphereDefinition.h"
#include "AtmosphereRenderer.h"
#include "AtmosphereModelBruneton.h"
OpenGLSkybox::OpenGLSkybox(OpenGLRenderer* renderer):
OpenGLPart(renderer)
{
vertices = new float[14 * 3];
daytime = renderer->getScenery()->getAtmosphere()->_daytime;
}
OpenGLSkybox::~OpenGLSkybox()
{
delete[] vertices;
}
void OpenGLSkybox::initialize()
{
program = createShader("skybox");
program->addVertexSource("skybox");
program->addFragmentSource("bruneton");
program->addFragmentSource("tonemapping");
program->addFragmentSource("skybox");
setVertex(0, 1.0f, 1.0f, 1.0f);
setVertex(12, 1.0f, 1.0f, 1.0f);
setVertex(1, 1.0f, -1.0f, 1.0f);
setVertex(5, 1.0f, -1.0f, 1.0f);
setVertex(13, 1.0f, -1.0f, 1.0f);
setVertex(2, -1.0f, 1.0f, 1.0f);
setVertex(10, -1.0f, 1.0f, 1.0f);
setVertex(3, -1.0f, -1.0f, 1.0f);
setVertex(4, -1.0f, -1.0f, -1.0f);
setVertex(8, -1.0f, -1.0f, -1.0f);
setVertex(6, 1.0f, -1.0f, -1.0f);
setVertex(7, 1.0f, 1.0f, -1.0f);
setVertex(11, 1.0f, 1.0f, -1.0f);
setVertex(9, -1.0f, 1.0f, -1.0f);
}
void OpenGLSkybox::update()
{
Vector3 sun_direction = renderer->getAtmosphereRenderer()->getSunDirection();
renderer->getSharedState()->set("sunDirection", sun_direction);
Color sun_color = renderer->getScenery()->getAtmosphere()->sun_color;
renderer->getSharedState()->set("sunColor", sun_color);
SoftwareBrunetonAtmosphereRenderer* bruneton = (SoftwareBrunetonAtmosphereRenderer*)renderer->getAtmosphereRenderer();
renderer->getSharedState()->set("transmittanceTexture", bruneton->getModel()->getTextureTransmittance());
renderer->getSharedState()->set("inscatterTexture", bruneton->getModel()->getTextureInscatter());
}
void OpenGLSkybox::render()
{
program->drawTriangleStrip(vertices, 14);
}
void OpenGLSkybox::alterDayTime(double delta)
{
#if 0
Scenery* scenery = renderer->getScenery();
AtmosphereDefinition* definition = scenery->getAtmosphere()->definition;
daytime = fmod(daytime + delta * 0.001, 1.0);
// TEMP
if (daytime > 0.8)
{
daytime -= 0.6;
}
if (daytime < 0.2)
{
daytime += 0.6;
}
definition->hour = (int)(daytime * 24.0);
definition->minute = (int)((daytime - (((double)definition->hour) / 24.0)) * 1440.0);
AtmosphereDefinitionClass.validate(definition);
// TODO Update only the sun
updateScenery(scenery, true);
#endif
}
void OpenGLSkybox::setVertex(int i, float x, float y, float z)
{
vertices[i * 3] = x;
vertices[i * 3 + 1] = y;
vertices[i * 3 + 2] = z;
}

View file

@ -0,0 +1,35 @@
#ifndef OPENGLSKYBOX_H
#define OPENGLSKYBOX_H
#include "opengl_global.h"
#include "OpenGLPart.h"
namespace paysages {
namespace opengl {
class OPENGLSHARED_EXPORT OpenGLSkybox: public OpenGLPart
{
public:
OpenGLSkybox(OpenGLRenderer* renderer);
virtual ~OpenGLSkybox();
virtual void initialize() override;
virtual void update() override;
virtual void render() override;
void alterDayTime(double delta);
private:
void setVertex(int i, float x, float y, float z);
OpenGLShaderProgram* program;
float* vertices;
double daytime;
};
}
}
#endif // OPENGLSKYBOX_H

View file

@ -0,0 +1,128 @@
#include "OpenGLTerrain.h"
#include OPENGL_FUNCTIONS_INCLUDE
#include "OpenGLRenderer.h"
#include "OpenGLShaderProgram.h"
#include "ParallelPool.h"
#include "Thread.h"
#include "ExplorerChunkTerrain.h"
#include "WaterRenderer.h"
#include "CameraDefinition.h"
#include "Scenery.h"
class ChunkMaintenanceThreads:public ParallelPool
{
public:
ChunkMaintenanceThreads(OpenGLTerrain* terrain):
terrain(terrain)
{
}
virtual void work() override
{
while (running)
{
terrain->performChunksMaintenance();
Thread::timeSleepMs(10);
}
}
private:
OpenGLTerrain* terrain;
};
OpenGLTerrain::OpenGLTerrain(OpenGLRenderer *renderer):
OpenGLPart(renderer)
{
work = new ChunkMaintenanceThreads(this);
}
OpenGLTerrain::~OpenGLTerrain()
{
delete work;
for (int i = 0; i < _chunks.count(); i++)
{
delete _chunks[i];
}
}
void OpenGLTerrain::initialize()
{
// Prepare shader programs
program = createShader("terrain");
program->addVertexSource("terrain");
program->addFragmentSource("bruneton");
program->addFragmentSource("tonemapping");
program->addFragmentSource("fadeout");
program->addFragmentSource("terrain");
// Add terrain chunks
int chunks = 25;
double size = 800.0;
double chunksize = size / (double) chunks;
double start = -size / 2.0;
double water_height = renderer->getWaterRenderer()->getHeightInfo().base_height;
for (int i = 0; i < chunks; i++)
{
for (int j = 0; j < chunks; j++)
{
ExplorerChunkTerrain* chunk = new ExplorerChunkTerrain(renderer, start + chunksize * (double) i, start + chunksize * (double) j, chunksize, chunks, water_height);
_chunks.append(chunk);
_updateQueue.append(chunk);
}
}
// Start chunks maintenance
work->start();
}
void OpenGLTerrain::update()
{
}
void OpenGLTerrain::render()
{
program->bind();
for (int i = 0; i < _chunks.count(); i++)
{
_chunks[i]->render(program->getProgram(), renderer->getOpenGlFunctions());
}
program->release();
}
static bool _cmpChunks(const ExplorerChunkTerrain* c1, const ExplorerChunkTerrain* c2)
{
return c1->priority > c2->priority;
}
void OpenGLTerrain::performChunksMaintenance()
{
CameraDefinition* camera = renderer->getScenery()->getCamera();
ExplorerChunkTerrain* chunk;
_lock_chunks.lock();
if (_updateQueue.count() > 0)
{
chunk = _updateQueue.takeFirst();
_lock_chunks.unlock();
}
else
{
_lock_chunks.unlock();
return;
}
chunk->maintain();
_lock_chunks.lock();
_updateQueue.append(chunk);
for (int i = 0; i < _chunks.count(); i++)
{
_chunks[i]->updatePriority(camera);
}
qSort(_updateQueue.begin(), _updateQueue.end(), _cmpChunks);
_lock_chunks.unlock();
}

View file

@ -0,0 +1,40 @@
#ifndef OPENGLTERRAIN_H
#define OPENGLTERRAIN_H
#include "opengl_global.h"
#include "OpenGLPart.h"
#include <QVector>
#include <QList>
#include <QMutex>
namespace paysages {
namespace opengl {
class OPENGLSHARED_EXPORT OpenGLTerrain:public OpenGLPart
{
public:
OpenGLTerrain(OpenGLRenderer* renderer);
virtual ~OpenGLTerrain();
virtual void initialize() override;
virtual void update() override;
virtual void render() override;
void performChunksMaintenance();
private:
OpenGLShaderProgram* program;
ParallelPool* work;
QVector<ExplorerChunkTerrain*> _chunks;
QList<ExplorerChunkTerrain*> _updateQueue;
QMutex _lock_chunks;
};
}
}
#endif // OPENGLTERRAIN_H

View file

@ -0,0 +1,231 @@
#include "OpenGLVariable.h"
#include OPENGL_FUNCTIONS_INCLUDE
#include <QOpenGLShaderProgram>
#include <cassert>
#include "OpenGLRenderer.h"
#include "OpenGLShaderProgram.h"
#include "Vector3.h"
#include "Matrix4.h"
#include "Color.h"
#include "Texture2D.h"
#include "Texture3D.h"
#include "Texture4D.h"
OpenGLVariable::OpenGLVariable(const std::string &name):
name(name)
{
type = TYPE_NONE;
texture_toupload = false;
}
void OpenGLVariable::apply(OpenGLShaderProgram *program, int &texture_unit)
{
QOpenGLShaderProgram* pr = program->getProgram();
OpenGLFunctions* functions = program->getRenderer()->getOpenGlFunctions();
if (texture_toupload)
{
uploadTexture(program->getRenderer());
texture_toupload = false;
}
switch (type)
{
case TYPE_FLOAT:
pr->setUniformValue(name.c_str(), value_float);
break;
case TYPE_COLOR:
pr->setUniformValue(name.c_str(), value_color);
break;
case TYPE_VECTOR3:
pr->setUniformValue(name.c_str(), value_vector3);
break;
case TYPE_MATRIX4:
pr->setUniformValue(name.c_str(), value_matrix4);
break;
case TYPE_TEXTURE_2D:
functions->glActiveTexture(GL_TEXTURE0 + texture_unit);
functions->glBindTexture(GL_TEXTURE_2D, texture_id);
pr->setUniformValue(name.c_str(), texture_unit);
texture_unit++;
break;
case TYPE_TEXTURE_3D:
case TYPE_TEXTURE_4D:
functions->glActiveTexture(GL_TEXTURE0 + texture_unit);
functions->glBindTexture(GL_TEXTURE_3D, texture_id);
pr->setUniformValue(name.c_str(), texture_unit);
texture_unit++;
break;
case TYPE_NONE:
break;
}
}
void OpenGLVariable::set(const Texture2D *texture)
{
assert(type == TYPE_NONE or type == TYPE_TEXTURE_2D);
type = TYPE_TEXTURE_2D;
value_tex2d = texture;
texture_toupload = true;
}
void OpenGLVariable::set(const Texture3D *texture)
{
assert(type == TYPE_NONE or type == TYPE_TEXTURE_3D);
type = TYPE_TEXTURE_3D;
value_tex3d = texture;
texture_toupload = true;
}
void OpenGLVariable::set(const Texture4D *texture)
{
assert(type == TYPE_NONE or type == TYPE_TEXTURE_4D);
type = TYPE_TEXTURE_4D;
value_tex4d = texture;
texture_toupload = true;
}
void OpenGLVariable::set(float value)
{
assert(type == TYPE_NONE or type == TYPE_FLOAT);
type = TYPE_FLOAT;
value_float = value;
}
void OpenGLVariable::set(const Vector3 &vector)
{
set(QVector3D(vector.x, vector.y, vector.z));
}
void OpenGLVariable::set(const QVector3D &vector)
{
assert(type == TYPE_NONE or type == TYPE_VECTOR3);
type = TYPE_VECTOR3;
value_vector3 = vector;
}
void OpenGLVariable::set(const Matrix4 &matrix)
{
set(matrix.toQMatrix());
}
void OpenGLVariable::set(const QMatrix4x4 &matrix)
{
assert(type == TYPE_NONE or type == TYPE_MATRIX4);
type = TYPE_MATRIX4;
value_matrix4 = matrix;
}
void OpenGLVariable::set(const Color &color)
{
assert(type == TYPE_NONE or type == TYPE_COLOR);
type = TYPE_COLOR;
value_color = QColor(color.r, color.g, color.b);
}
void OpenGLVariable::uploadTexture(OpenGLRenderer* renderer)
{
OpenGLFunctions* functions = renderer->getOpenGlFunctions();
assert(type == TYPE_TEXTURE_2D or type == TYPE_TEXTURE_3D or type == TYPE_TEXTURE_4D);
if (texture_id == 0)
{
GLuint texid;
functions->glGenTextures(1, &texid);
texture_id = texid;
}
GLenum textype = (type == TYPE_TEXTURE_2D) ? GL_TEXTURE_2D : GL_TEXTURE_3D;
functions->glBindTexture(textype, texture_id);
functions->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
functions->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
functions->glTexParameteri(textype, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
functions->glTexParameteri(textype, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
if (textype == GL_TEXTURE_3D)
{
functions->glTexParameteri(textype, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
}
if (type == TYPE_TEXTURE_2D)
{
int sx, sy;
value_tex2d->getSize(&sx, &sy);
float* pixels = new float[sx * sy * 4];
for (int x = 0; x < sx; x++)
{
for (int y = 0; y < sy; y++)
{
float* pixel = pixels + (y * sx + x) * 4;
Color col = value_tex2d->getPixel(x, y);
pixel[0] = (float)col.r;
pixel[1] = (float)col.g;
pixel[2] = (float)col.b;
pixel[3] = (float)col.a;
}
}
functions->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, sx, sy, 0, GL_RGBA, GL_FLOAT, pixels);
delete[] pixels;
}
else if (type == TYPE_TEXTURE_3D)
{
int sx, sy, sz;
value_tex3d->getSize(&sx, &sy, &sz);
float* pixels = new float[sx * sy * sz * 4];
for (int x = 0; x < sx; x++)
{
for (int y = 0; y < sy; y++)
{
for (int z = 0; z < sz; z++)
{
float* pixel = pixels + (z * (sx * sy) + y * sx + x) * 4;
Color col = value_tex3d->getPixel(x, y, z);
pixel[0] = (float)col.r;
pixel[1] = (float)col.g;
pixel[2] = (float)col.b;
pixel[3] = (float)col.a;
}
}
}
functions->glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, sx, sy, sz, 0, GL_RGBA, GL_FLOAT, pixels);
delete[] pixels;
}
else
{
int sx, sy, sz, sw;
value_tex4d->getSize(&sx, &sy, &sz, &sw);
float* pixels = new float[sx * sy * sz * sw * 4];
for (int x = 0; x < sx; x++)
{
for (int y = 0; y < sy; y++)
{
for (int z = 0; z < sz; z++)
{
for (int w = 0; w < sw; w++)
{
float* pixel = pixels + (w * (sx * sy * sz) + z * (sx * sy) + y * sx + x) * 4;
Color col = value_tex4d->getPixel(x, y, z, w);
pixel[0] = (float)col.r;
pixel[1] = (float)col.g;
pixel[2] = (float)col.b;
pixel[3] = (float)col.a;
}
}
}
}
functions->glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, sx, sy, sz * sw, 0, GL_RGBA, GL_FLOAT, pixels);
delete[] pixels;
}
}

View file

@ -0,0 +1,67 @@
#ifndef OPENGLVARIABLE_H
#define OPENGLVARIABLE_H
#include "opengl_global.h"
#include <QColor>
#include <QVector3D>
#include <QMatrix4x4>
namespace paysages {
namespace opengl {
/*!
* \brief OpenGL variable that can be bound to a uniform for shaders.
*/
class OpenGLVariable
{
public:
typedef enum {
TYPE_NONE,
TYPE_TEXTURE_2D,
TYPE_TEXTURE_3D,
TYPE_TEXTURE_4D,
TYPE_FLOAT,
TYPE_VECTOR3,
TYPE_MATRIX4,
TYPE_COLOR
} OpenGLVariableType;
public:
OpenGLVariable(const std::string &name);
void apply(OpenGLShaderProgram *program, int &texture_unit);
void set(const Texture2D *texture);
void set(const Texture3D *texture);
void set(const Texture4D *texture);
void set(float value);
void set(const Vector3 &vector);
void set(const QVector3D &vector);
void set(const Matrix4 &matrix);
void set(const QMatrix4x4 &matrix);
void set(const Color &color);
protected:
void uploadTexture(OpenGLRenderer* renderer);
private:
std::string name;
OpenGLVariableType type;
float value_float;
QColor value_color;
QVector3D value_vector3;
QMatrix4x4 value_matrix4;
const Texture2D* value_tex2d;
const Texture3D* value_tex3d;
const Texture4D* value_tex4d;
bool texture_toupload;
unsigned int texture_id;
};
}
}
#endif // OPENGLVARIABLE_H

View file

@ -0,0 +1,56 @@
#include "OpenGLWater.h"
#include "OpenGLRenderer.h"
#include "OpenGLShaderProgram.h"
#include "OpenGLSharedState.h"
#include "WaterRenderer.h"
#include "Scenery.h"
#include "WaterDefinition.h"
#include "SurfaceMaterial.h"
OpenGLWater::OpenGLWater(OpenGLRenderer *renderer):
OpenGLPart(renderer)
{
vertices = new float[4 * 3];
}
OpenGLWater::~OpenGLWater()
{
delete[] vertices;
}
void OpenGLWater::initialize()
{
program = createShader("water");
program->addVertexSource("water");
program->addFragmentSource("bruneton");
program->addFragmentSource("tonemapping");
program->addFragmentSource("fadeout");
program->addFragmentSource("water");
setVertex(0, -1.0f, 0.0f, -1.0f);
setVertex(1, -1.0f, 0.0f, 1.0f);
setVertex(2, 1.0f, 0.0f, -1.0f);
setVertex(3, 1.0f, 0.0f, 1.0f);
}
void OpenGLWater::update()
{
double water_height = renderer->getWaterRenderer()->getHeightInfo().max_height;
renderer->getSharedState()->set("waterHeight", water_height);
Color water_color = renderer->getScenery()->getWater()->material->_rgb;
renderer->getSharedState()->set("waterColor", water_color);
}
void OpenGLWater::render()
{
program->drawTriangleStrip(vertices, 4);
}
void OpenGLWater::setVertex(int i, float x, float y, float z)
{
vertices[i * 3] = x;
vertices[i * 3 + 1] = y;
vertices[i * 3 + 2] = z;
}

View file

@ -0,0 +1,31 @@
#ifndef OPENGLWATER_H
#define OPENGLWATER_H
#include "opengl_global.h"
#include "OpenGLPart.h"
namespace paysages {
namespace opengl {
class OPENGLSHARED_EXPORT OpenGLWater: public OpenGLPart
{
public:
OpenGLWater(OpenGLRenderer* renderer);
virtual ~OpenGLWater();
virtual void initialize() override;
virtual void update() override;
virtual void render() override;
private:
void setVertex(int i, float x, float y, float z);
OpenGLShaderProgram* program;
float* vertices;
};
}
}
#endif // OPENGLWATER_H

View file

@ -0,0 +1,155 @@
#ifndef VERTEXARRAY_H
#define VERTEXARRAY_H
#include "opengl_global.h"
#include OPENGL_FUNCTIONS_INCLUDE
#include <cassert>
#include <QOpenGLShaderProgram>
namespace paysages {
namespace opengl {
/*!
* Wrapper for OpenGL vertex arrays.
*/
template <typename Vertex> class VertexArray
{
public:
VertexArray()
{
ready = false;
changed = false;
vertex_count = 1;
vertices = new Vertex[1];
index_count = 1;
indices = new unsigned short[1];
}
~VertexArray()
{
delete[] vertices;
delete[] indices;
}
inline int getVertexCount() {return vertex_count;}
inline int getIndexCount() {return index_count;}
inline bool isReady() {return ready;}
inline bool isChanged() {return changed;}
void setVertexCount(int count)
{
assert(count > 0 and count <= 16384);
delete[] vertices;
vertices = new Vertex[count];
vertex_count = count;
}
void setGridSize(int edge_vertex_count)
{
assert(edge_vertex_count >= 2);
setVertexCount(edge_vertex_count * edge_vertex_count);
}
void setVertex(int position, const Vertex &vertex)
{
assert(position >= 0 and position < vertex_count);
vertices[position] = vertex;
changed = true;
}
void setGridVertex(int edge_vertex_count, int x, int y, const Vertex &vertex)
{
setVertex(y * edge_vertex_count + x, vertex);
}
void setAutoGridIndices(int edge_vertex_count, int stride=1)
{
assert(stride >= 1);
delete[] indices;
int cell_count = edge_vertex_count - 1;
index_count = (cell_count / stride) * (cell_count / stride) * 6;
indices = new unsigned short[index_count];
int idx = 0;
for (int y = 0; y < cell_count; y += stride)
{
for (int x = 0; x < cell_count; x += stride)
{
int base = y * edge_vertex_count + x;
indices[idx++] = base;
indices[idx++] = base + edge_vertex_count * stride;
indices[idx++] = base + stride;
indices[idx++] = base + stride;
indices[idx++] = base + edge_vertex_count * stride;
indices[idx++] = base + edge_vertex_count * stride + stride;
}
}
}
Vertex getVertex(int position)
{
assert(position >= 0 and position < vertex_count);
return vertices[position];
}
Vertex getVertexByIndex(unsigned short index)
{
assert(index >= 0 and index < index_count);
return getVertex(indices[index]);
}
Vertex getGridVertex(int edge_vertex_count, int x, int y)
{
return getVertex(y * edge_vertex_count + x);
}
unsigned short getIndex(int position)
{
assert(position >= 0 and position < index_count);
return indices[position];
}
void render(QOpenGLShaderProgram* program, OpenGLFunctions* functions)
{
size_t ptr = (size_t)vertices;
GLuint vertex = program->attributeLocation("vertex");
program->setAttributeArray(vertex, GL_FLOAT, (void*)(ptr + offsetof(Vertex, location)), 3, sizeof(Vertex));
program->enableAttributeArray(vertex);
GLuint uv = program->attributeLocation("uv");
program->setAttributeArray(uv, GL_FLOAT, (void*)(ptr + offsetof(Vertex, uv)), 2, sizeof(Vertex));
program->enableAttributeArray(uv);
functions->glDrawElements(GL_TRIANGLES, index_count, GL_UNSIGNED_SHORT, indices);
program->disableAttributeArray(vertex);
program->disableAttributeArray(uv);
}
private:
bool ready;
bool changed;
int vertex_count;
Vertex* vertices;
int index_count;
unsigned short* indices;
};
}
}
#endif // VERTEXARRAY_H

View file

@ -11,51 +11,12 @@
#include "WaterDefinition.h" #include "WaterDefinition.h"
#include "SurfaceMaterial.h" #include "SurfaceMaterial.h"
#include "CameraDefinition.h" #include "CameraDefinition.h"
#include "ExplorerChunkSky.h"
#include "ExplorerChunkTerrain.h" #include "ExplorerChunkTerrain.h"
#include "TerrainRenderer.h" #include "TerrainRenderer.h"
#include "WaterRenderer.h" #include "WaterRenderer.h"
#include "Scenery.h" #include "Scenery.h"
#include "LightingManager.h" #include "LightingManager.h"
class ChunkMaintenanceThread : public QThread
{
public:
ChunkMaintenanceThread(WidgetExplorer* wanderer)
{
_wanderer = wanderer;
_running = true;
}
void askStop()
{
_running = false;
}
static inline void usleep(unsigned long us)
{
QThread::usleep(us);
}
protected:
void run()
{
while (_running)
{
_wanderer->performChunksMaintenance();
QThread::usleep(10000);
}
}
private:
bool _running;
WidgetExplorer* _wanderer;
};
static QVector<ChunkMaintenanceThread*> _threads;
WidgetExplorer::WidgetExplorer(QWidget *parent, CameraDefinition* camera, Scenery* scenery) : WidgetExplorer::WidgetExplorer(QWidget *parent, CameraDefinition* camera, Scenery* scenery) :
QGLWidget(parent) QGLWidget(parent)
{ {
@ -67,13 +28,6 @@ QGLWidget(parent)
camera->copy(_current_camera); camera->copy(_current_camera);
_renderer = new OpenGLRenderer(scenery); _renderer = new OpenGLRenderer(scenery);
_renderer->prepare();
_renderer->render_quality = 3;
_renderer->getLightingManager()->setSpecularity(false);
_renderer->disableClouds();
_inited = false;
_updated = false;
_average_frame_time = 0.05; _average_frame_time = 0.05;
_quality = 3; _quality = 3;
@ -85,111 +39,10 @@ QGLWidget(parent)
WidgetExplorer::~WidgetExplorer() WidgetExplorer::~WidgetExplorer()
{ {
stopRendering();
for (int i = 0; i < _chunks.count(); i++)
{
delete _chunks[i];
}
delete _current_camera; delete _current_camera;
delete _renderer; delete _renderer;
} }
void WidgetExplorer::startRendering()
{
// Add terrain
int chunks = 20;
double size = 400.0;
double chunksize = size / (double) chunks;
double start = -size / 2.0;
double water_height = _renderer->getWaterRenderer()->getHeightInfo().base_height;
for (int i = 0; i < chunks; i++)
{
for (int j = 0; j < chunks; j++)
{
ExplorerChunkTerrain* chunk = new ExplorerChunkTerrain(_renderer, start + chunksize * (double) i, start + chunksize * (double) j, chunksize, chunks, water_height);
_chunks.append(chunk);
_updateQueue.append(chunk);
}
}
// Add skybox
for (int orientation = 0; orientation < 5; orientation++)
{
ExplorerChunkSky* chunk = new ExplorerChunkSky(_renderer, 500.0, (SkyboxOrientation) orientation);
_chunks.append(chunk);
_updateQueue.append(chunk);
}
// Start rendering workers
int nbcore;
_alive = true;
nbcore = QThread::idealThreadCount();
if (nbcore < 1)
{
nbcore = 1;
}
for (int i = 0; i < nbcore; i++)
{
_threads.append(new ChunkMaintenanceThread(this));
}
for (int i = 0; i < _threads.count(); i++)
{
_threads[i]->start();
}
}
void WidgetExplorer::stopRendering()
{
for (int i = 0; i < _threads.count(); i++)
{
_threads[i]->askStop();
}
_alive = false;
for (int i = 0; i < _threads.count(); i++)
{
_threads[i]->wait();
}
}
bool _cmpChunks(const BaseExplorerChunk* c1, const BaseExplorerChunk* c2)
{
return c1->priority > c2->priority;
}
void WidgetExplorer::performChunksMaintenance()
{
BaseExplorerChunk* chunk;
_lock_chunks.lock();
if (_updateQueue.count() > 0)
{
chunk = _updateQueue.takeFirst();
_lock_chunks.unlock();
}
else
{
_lock_chunks.unlock();
return;
}
if (chunk->maintain())
{
if (!_alive)
{
return;
}
_updated = true;
}
_lock_chunks.lock();
_updateQueue.append(chunk);
_lock_chunks.unlock();
}
void WidgetExplorer::resetCamera() void WidgetExplorer::resetCamera()
{ {
_base_camera->copy(_current_camera); _base_camera->copy(_current_camera);
@ -332,25 +185,7 @@ void WidgetExplorer::wheelEvent(QWheelEvent* event)
void WidgetExplorer::timerEvent(QTimerEvent*) void WidgetExplorer::timerEvent(QTimerEvent*)
{ {
if (!_inited) updateGL();
{
_inited = true;
startRendering();
}
if (_updated)
{
_updated = false;
updateGL();
}
for (int i = 0; i < _chunks.count(); i++)
{
_chunks[i]->updatePriority(_current_camera);
}
_lock_chunks.lock();
qSort(_updateQueue.begin(), _updateQueue.end(), _cmpChunks);
_lock_chunks.unlock();
} }
void WidgetExplorer::initializeGL() void WidgetExplorer::initializeGL()
@ -366,46 +201,18 @@ void WidgetExplorer::resizeGL(int w, int h)
void WidgetExplorer::paintGL() void WidgetExplorer::paintGL()
{ {
GLenum error_code;
QTime start_time; QTime start_time;
double frame_time; double frame_time;
WaterDefinition* water = _renderer->getScenery()->getWater();
// Don't do this at each frame, only on camera change // Don't do this at each frame, only on camera change
_renderer->getScenery()->setCamera(_current_camera); _renderer->getScenery()->setCamera(_current_camera);
_renderer->getScenery()->getCamera(_current_camera); _renderer->getScenery()->getCamera(_current_camera);
_renderer->cameraChangeEvent(_current_camera);
start_time = QTime::currentTime(); start_time = QTime::currentTime();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
Vector3 camera_location = _current_camera->getLocation();
Vector3 camera_target = _current_camera->getTarget();
Vector3 camera_up = _current_camera->getUpVector();
gluLookAt(camera_location.x, camera_location.y, camera_location.z, camera_target.x, camera_target.y, camera_target.z, camera_up.x, camera_up.y, camera_up.z);
// Background // Background
glClearColor(0.0, 0.0, 0.0, 0.0); _renderer->paint();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Render water
double water_height = _renderer->getTerrainRenderer()->getWaterHeight();
glDisable(GL_TEXTURE_2D);
glColor3f(water->material->_rgb.r, water->material->_rgb.g, water->material->_rgb.b);
glBegin(GL_QUADS);
glVertex3f(camera_location.x - 500.0, water_height, camera_location.z - 500.0);
glVertex3f(camera_location.x - 500.0, water_height, camera_location.z + 500.0);
glVertex3f(camera_location.x + 500.0, water_height, camera_location.z + 500.0);
glVertex3f(camera_location.x + 500.0, water_height, camera_location.z - 500.0);
glEnd();
// Render chunks
glEnable(GL_TEXTURE_2D);
for (int i = 0; i < _chunks.count(); i++)
{
glColor3f(1.0, 1.0, 1.0);
_chunks[i]->render(this);
}
frame_time = 0.001 * (double) start_time.msecsTo(QTime::currentTime()); frame_time = 0.001 * (double) start_time.msecsTo(QTime::currentTime());
@ -422,16 +229,11 @@ void WidgetExplorer::paintGL()
} }
// Messages // Messages
if (!_inited) /*if (!_inited)
{ {
glColor3f(0.0, 0.0, 0.0); glColor3f(0.0, 0.0, 0.0);
renderText(6, height() - 10, tr("Please wait while loading scene...")); renderText(6, height() - 10, tr("Please wait while loading scene..."));
glColor3f(1.0, 1.0, 1.0); glColor3f(1.0, 1.0, 1.0);
renderText(5, height() - 9, tr("Please wait while loading scene...")); renderText(5, height() - 9, tr("Please wait while loading scene..."));
} }*/
while ((error_code = glGetError()) != GL_NO_ERROR)
{
qDebug("[OpenGL] ERROR : %s", (const char*)gluErrorString(error_code));
}
} }

View file

@ -5,8 +5,6 @@
#include <QGLWidget> #include <QGLWidget>
#include <QMutex>
namespace paysages { namespace paysages {
namespace opengl { namespace opengl {
@ -17,8 +15,6 @@ public:
WidgetExplorer(QWidget* parent, CameraDefinition* camera, Scenery* scenery); WidgetExplorer(QWidget* parent, CameraDefinition* camera, Scenery* scenery);
~WidgetExplorer(); ~WidgetExplorer();
void performChunksMaintenance();
public slots: public slots:
void resetCamera(); void resetCamera();
void validateCamera(); void validateCamera();
@ -35,20 +31,10 @@ protected:
void paintGL(); void paintGL();
private: private:
void startRendering();
void stopRendering();
CameraDefinition* _current_camera; CameraDefinition* _current_camera;
CameraDefinition* _base_camera; CameraDefinition* _base_camera;
OpenGLRenderer* _renderer; OpenGLRenderer* _renderer;
bool _inited;
bool _updated;
QVector<BaseExplorerChunk*> _chunks;
QList<BaseExplorerChunk*> _updateQueue;
bool _alive;
QMutex _lock_chunks;
double _average_frame_time; double _average_frame_time;
int _quality; int _quality;

View file

@ -13,20 +13,33 @@ DEFINES += OPENGL_LIBRARY
include(../../common.pri) include(../../common.pri)
unix:LIBS += -lGLU
SOURCES += \ SOURCES += \
OpenGLRenderer.cpp \ OpenGLRenderer.cpp \
BaseExplorerChunk.cpp \
ExplorerChunkSky.cpp \
ExplorerChunkTerrain.cpp \ ExplorerChunkTerrain.cpp \
WidgetExplorer.cpp WidgetExplorer.cpp \
OpenGLShaderProgram.cpp \
OpenGLPart.cpp \
OpenGLSkybox.cpp \
OpenGLWater.cpp \
OpenGLSharedState.cpp \
OpenGLVariable.cpp \
OpenGLTerrain.cpp
HEADERS +=\ HEADERS +=\
opengl_global.h \ opengl_global.h \
OpenGLRenderer.h \ OpenGLRenderer.h \
BaseExplorerChunk.h \
ExplorerChunkSky.h \
ExplorerChunkTerrain.h \ ExplorerChunkTerrain.h \
WidgetExplorer.h WidgetExplorer.h \
OpenGLShaderProgram.h \
OpenGLPart.h \
OpenGLSkybox.h \
OpenGLWater.h \
OpenGLSharedState.h \
OpenGLVariable.h \
OpenGLTerrain.h \
VertexArray.h
unix:!symbian { unix:!symbian {
maemo5 { maemo5 {
@ -60,3 +73,18 @@ else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../software/debug/
else:unix: LIBS += -L$$OUT_PWD/../software/ -lpaysages_render_software else:unix: LIBS += -L$$OUT_PWD/../software/ -lpaysages_render_software
INCLUDEPATH += $$PWD/../software INCLUDEPATH += $$PWD/../software
DEPENDPATH += $$PWD/../software DEPENDPATH += $$PWD/../software
RESOURCES += \
shaders/resources.qrc
OTHER_FILES += \
shaders/skybox.frag \
shaders/skybox.vert \
shaders/water.vert \
shaders/water.frag \
shaders/bruneton.frag \
shaders/bruneton.frag \
shaders/tonemapping.frag \
shaders/terrain.frag \
shaders/terrain.vert \
shaders/fadeout.frag

View file

@ -15,9 +15,21 @@ namespace paysages {
namespace opengl { namespace opengl {
class WidgetExplorer; class WidgetExplorer;
class OpenGLRenderer; class OpenGLRenderer;
class BaseExplorerChunk; class OpenGLShaderProgram;
class OpenGLSharedState;
class OpenGLVariable;
class OpenGLSkybox;
class OpenGLWater;
class OpenGLTerrain;
class ExplorerChunkTerrain;
template <typename Vertex> class VertexArray;
} }
} }
using namespace paysages::opengl; using namespace paysages::opengl;
//#define OpenGLFunctions QOpenGLFunctions_3_2_Core
#define OpenGLFunctions QOpenGLFunctions_3_0
#define OPENGL_FUNCTIONS_INCLUDE <OpenGLFunctions>
class OpenGLFunctions;
#endif // OPENGL_GLOBAL_H #endif // OPENGL_GLOBAL_H

View file

@ -0,0 +1,211 @@
const float GROUND_OFFSET = 0.5;
const float Rg = 6360.0;
const float Rt = 6420.0;
const float RL = 6421.0;
const float ISun = 100.0;
const float AVERAGE_GROUND_REFLECTANCE = 0.1;
const float HR = 8.0;
const vec3 betaR = vec3(5.8e-3, 1.35e-2, 3.31e-2);
const float HM = 1.2;
const vec3 betaMSca = vec3(4e-3);
const vec3 betaMEx = vec3(4e-3 / 0.9);
const float mieG = 0.8;
const float SPHERE_SIZE = 20000.0;
const float WORLD_SCALING = 0.05;
const float SUN_DISTANCE = 149597870.0;
const float SUN_DISTANCE_SCALED = (SUN_DISTANCE / WORLD_SCALING);
const float SUN_RADIUS = 6.955e5;
const float SUN_RADIUS_SCALED = (SUN_RADIUS / WORLD_SCALING);
const float M_PI = 3.141592657;
const int RES_MU = 128;
const int RES_MU_S = 32;
const int RES_R = 32;
const int RES_NU = 8;
uniform float waterHeight;
uniform vec3 cameraLocation;
uniform vec3 sunDirection;
uniform vec4 sunColor;
const float sunRadius = 1.0; // TODO -> uniform
varying vec3 unprojected;
uniform sampler2D transmittanceTexture;
uniform sampler3D inscatterTexture;
vec4 texture4D(sampler3D tex, float r, float mu, float muS, float nu)
{
if (r < Rg + 0.00000001) r = Rg + 0.00000001;
float H = sqrt(Rt * Rt - Rg * Rg);
float rho = sqrt(r * r - Rg * Rg);
float rmu = r * mu;
float delta = rmu * rmu - r * r + Rg * Rg;
vec4 cst = (rmu < 0.0 && delta > 0.0) ? vec4(1.0, 0.0, 0.0, 0.5 - 0.5 / float(RES_MU)) : vec4(-1.0, H * H, H, 0.5 + 0.5 / float(RES_MU));
float uR = 0.5 / float(RES_R) + rho / H * (1.0 - 1.0 / float(RES_R));
float uMu = cst.a + (rmu * cst.r + sqrt(delta + cst.g)) / (rho + cst.b) * (0.5 - 1.0 / float(RES_MU));
float uMuS = 0.5 / float(RES_MU_S) + (atan(max(muS, -0.1975) * tan(1.26 * 1.1)) / 1.1 + (1.0 - 0.26)) * 0.5 * (1.0 - 1.0 / float(RES_MU_S));
float sr = 1.0 / float(RES_R);
int br = int(floor(uR / sr));
vec4 r1 = texture3D(tex, vec3(uMu, uMuS, float(br) * sr + nu * sr));
vec4 r2 = texture3D(tex, vec3(uMu, uMuS, float(br + 1) * sr + nu * sr));
return mix(r1, r2, (uR - float(br) * sr) / sr);
}
float _limit(float r, float mu)
{
float dout = -r * mu + sqrt(r * r * (mu * mu - 1.0) + RL * RL);
float delta2 = r * r * (mu * mu - 1.0) + Rg * Rg;
if (delta2 >= 0.0)
{
float din = -r * mu - sqrt(delta2);
if (din >= 0.0) {
dout = min(dout, din);
}
}
return dout;
}
vec2 _getTransmittanceUV(float r, float mu)
{
if (r < Rg + 0.00000001) r = Rg + 0.00000001;
float dr = (r - Rg) / (Rt - Rg);
return vec2(atan((mu + 0.15) / (1.0 + 0.15) * tan(1.5)) / 1.5, sqrt(dr));
}
vec4 _transmittance(float r, float mu)
{
vec2 uv = _getTransmittanceUV(r, mu);
return texture2D(transmittanceTexture, uv);
}
vec4 _transmittanceWithShadow(float r, float mu)
{
return mu < -sqrt(1.0 - (Rg / r) * (Rg / r)) ? vec4(0.0) : _transmittance(r, mu);
}
vec4 _sunTransmittance(vec3 v, vec3 s, float r, float mu, float radius)
{
vec4 transmittance = r <= Rt ? _transmittanceWithShadow(r, mu) : vec4(1.0); /* T(x,xo) */
float d = _limit(r, mu);
radius *= (1.0 + 25.0 * d / Rt); /* Inflating due to lens effect near horizon */
float isun = step(cos(radius * M_PI / 180.0), dot(v, s)) * ISun; /* Lsun */
transmittance.r *= isun;
transmittance.g *= isun;
transmittance.b *= isun;
transmittance.a = 1.0;
return transmittance; /* Eq (9) */
}
float phaseFunctionR(float mu) {
return (3.0 / (16.0 * M_PI)) * (1.0 + mu * mu);
}
float phaseFunctionM(float mu) {
return 1.5 * 1.0 / (4.0 * M_PI) * (1.0 - mieG*mieG) * pow(1.0 + (mieG*mieG) - 2.0*mieG*mu, -3.0/2.0) * (1.0 + mu * mu) / (2.0 + mieG*mieG);
}
float opticalDepth(float H, float r, float mu, float d) {
float a = sqrt((0.5/H)*r);
vec2 a01 = a*vec2(mu, mu + d / r);
vec2 a01s = sign(a01);
vec2 a01sq = a01*a01;
float x = a01s.y > a01s.x ? exp(a01sq.x) : 0.0;
vec2 y = a01s / (2.3193*abs(a01) + sqrt(1.52*a01sq + 4.0)) * vec2(1.0, exp(-d/H*(d/(2.0*r)+mu)));
return sqrt((6.2831*H)*r) * exp((Rg-r)/H) * (x + dot(y, vec2(1.0, -1.0)));
}
vec3 analyticTransmittance(float r, float mu, float d) {
return exp(- betaR * opticalDepth(HR, r, mu, d) - betaMEx * opticalDepth(HM, r, mu, d));
}
vec3 getMie(vec4 rayMie) { // rayMie.rgb=C*, rayMie.w=Cm,r
return rayMie.rgb * rayMie.w / max(rayMie.r, 1e-4) * (betaR.r / betaR);
}
vec3 _getInscatterColor(inout vec3 x, inout float t, vec3 v, vec3 s, out float r, out float mu, out vec3 attenuation) {
vec3 result;
r = length(x);
mu = dot(x, v) / r;
float d = -r * mu - sqrt(r * r * (mu * mu - 1.0) + Rt * Rt);
if (d > 0.0) { // if x in space and ray intersects atmosphere
// move x to nearest intersection of ray with top atmosphere boundary
x += d * v;
t -= d;
mu = (r * mu + d) / Rt;
r = Rt;
}
if (r <= Rt) { // if ray intersects atmosphere
float nu = dot(v, s);
float muS = dot(x, s) / r;
float phaseR = phaseFunctionR(nu);
float phaseM = phaseFunctionM(nu);
vec4 inscatter = max(texture4D(inscatterTexture, r, mu, muS, nu), 0.0);
if (t > 0.0) {
vec3 x0 = x + t * v;
float r0 = length(x0);
float rMu0 = dot(x0, v);
float mu0 = rMu0 / r0;
float muS0 = dot(x0, s) / r0;
// avoids imprecision problems in transmittance computations based on textures
attenuation = analyticTransmittance(r, mu, t);
if (r0 > Rg + 0.001) {
// computes S[L]-T(x,x0)S[L]|x0
inscatter = max(inscatter - attenuation.rgbr * texture4D(inscatterTexture, r0, mu0, muS0, nu), 0.0);
// avoids imprecision problems near horizon by interpolating between two points above and below horizon
const float EPS = 0.02;
float muHoriz = -sqrt(1.0 - (Rg / r) * (Rg / r));
if (abs(mu - muHoriz) < EPS) {
float a = ((mu - muHoriz) + EPS) / (2.0 * EPS);
mu = muHoriz - EPS;
r0 = sqrt(r * r + t * t + 2.0 * r * t * mu);
mu0 = (r * mu + t) / r0;
vec4 inScatter0 = texture4D(inscatterTexture, r, mu, muS, nu);
vec4 inScatter1 = texture4D(inscatterTexture, r0, mu0, muS0, nu);
vec4 inScatterA = max(inScatter0 - attenuation.rgbr * inScatter1, 0.0);
mu = muHoriz + EPS;
r0 = sqrt(r * r + t * t + 2.0 * r * t * mu);
mu0 = (r * mu + t) / r0;
inScatter0 = texture4D(inscatterTexture, r, mu, muS, nu);
inScatter1 = texture4D(inscatterTexture, r0, mu0, muS0, nu);
vec4 inScatterB = max(inScatter0 - attenuation.rgbr * inScatter1, 0.0);
inscatter = mix(inScatterA, inScatterB, a);
}
}
}
// avoids imprecision problems in Mie scattering when sun is below horizon
inscatter.w *= smoothstep(0.00, 0.02, muS);
result = max(inscatter.rgb * phaseR + getMie(inscatter) * phaseM, 0.0);
} else { // x in space and ray looking in space
result = vec3(0.0);
}
return result * ISun;
}
vec4 applyAerialPerspective(vec4 base)
{
float yoffset = GROUND_OFFSET - waterHeight;
vec3 camera = vec3(cameraLocation.x, max(cameraLocation.y + yoffset, 0.0), cameraLocation.z);
vec3 location = vec3(unprojected.x, max(unprojected.y + yoffset, 0.0), unprojected.z);
vec3 x = vec3(0.0, Rg + camera.y * WORLD_SCALING, 0.0);
vec3 v = normalize(location - camera);
vec3 s = normalize(sunDirection * SUN_DISTANCE_SCALED - x);
if (v.y == 0.0)
{
v.y = -0.000001;
}
float r = length(x);
float mu = dot(x, v) / r;
float t = length(location - camera) * WORLD_SCALING;
vec3 attenuation;
vec3 inscattering = _getInscatterColor(x, t, v, s, r, mu, attenuation);
return base * vec4(attenuation, 0.0) + vec4(inscattering, 0.0);
}

View file

@ -0,0 +1,8 @@
uniform float viewDistance;
float distanceFadeout()
{
vec3 camera = vec3(cameraLocation.x, 0.0, cameraLocation.z);
vec3 location = vec3(unprojected.x, 0.0, unprojected.z);
return mix(1.0, 0.0, clamp((length(location - camera) - viewDistance * 0.8) / (viewDistance * 0.2), 0.0, 1.0));
}

View file

@ -0,0 +1,13 @@
<RCC>
<qresource prefix="/shaders">
<file>skybox.frag</file>
<file>skybox.vert</file>
<file>water.frag</file>
<file>water.vert</file>
<file>bruneton.frag</file>
<file>tonemapping.frag</file>
<file>terrain.frag</file>
<file>terrain.vert</file>
<file>fadeout.frag</file>
</qresource>
</RCC>

View file

@ -0,0 +1,19 @@
void main(void)
{
float yoffset = GROUND_OFFSET - waterHeight;
vec3 camera = vec3(cameraLocation.x, max(cameraLocation.y + yoffset, 0.0), cameraLocation.z);
vec3 location = vec3(unprojected.x, max(unprojected.y + yoffset, 0.0), unprojected.z);
vec3 x = vec3(0.0, Rg + camera.y * WORLD_SCALING, 0.0);
vec3 v = normalize(location - camera);
vec3 s = normalize(sunDirection * SUN_DISTANCE_SCALED - x);
float r = length(x);
float mu = dot(x, v) / r;
float t = -r * mu - sqrt(r * r * (mu * mu - 1.0) + Rg * Rg);
vec4 sunTransmittance = _sunTransmittance(v, s, r, mu, sunRadius);
vec3 attenuation;
vec3 inscattering = _getInscatterColor(x, t, v, s, r, mu, attenuation);
gl_FragColor = applyToneMapping(sunTransmittance + vec4(inscattering, 0.0));
}

View file

@ -0,0 +1,10 @@
attribute highp vec4 vertex;
uniform highp mat4 viewMatrix;
uniform vec3 cameraLocation;
varying vec3 unprojected;
void main(void)
{
unprojected = cameraLocation + vertex.xyz * 500.0;
gl_Position = viewMatrix * vec4(unprojected, 1.0);
}

View file

@ -0,0 +1,13 @@
uniform sampler2D groundTexture;
varying vec2 texcoord;
void main(void)
{
gl_FragColor = texture2D(groundTexture, texcoord);
gl_FragColor = applyAerialPerspective(gl_FragColor);
gl_FragColor = applyToneMapping(gl_FragColor);
gl_FragColor.a = distanceFadeout();
}

View file

@ -0,0 +1,12 @@
attribute highp vec4 vertex;
attribute highp vec2 uv;
uniform highp mat4 viewMatrix;
varying vec3 unprojected;
varying vec2 texcoord;
void main(void)
{
unprojected = vertex.xyz;
texcoord = uv;
gl_Position = viewMatrix * vertex;
}

View file

@ -0,0 +1,32 @@
uniform float exposure;
float _uncharted2Tonemap(float x)
{
float A = 0.15;
float B = 0.50;
float C = 0.10;
float D = 0.20;
float E = 0.02;
float F = 0.30;
return ((x * (A * x + C * B) + D * E) / (x * (A * x + B) + D * F)) - E / F;
}
vec4 applyToneMapping(vec4 color)
{
return vec4(((color * exposure) / (1.0 + color * exposure)).rgb, 1.0);
}
/*vec4 applyToneMapping(vec4 color)
{
float W = 11.2;
float white_scale = 1.0 / _uncharted2Tonemap(W);
vec4 result;
result.r = pow(_uncharted2Tonemap(color.r * exposure) * white_scale, 1.0 / 2.2);
result.g = pow(_uncharted2Tonemap(color.g * exposure) * white_scale, 1.0 / 2.2);
result.b = pow(_uncharted2Tonemap(color.b * exposure) * white_scale, 1.0 / 2.2);
result.a = 1.0;
return result;
}*/

View file

@ -0,0 +1,12 @@
uniform vec4 waterColor;
void main(void)
{
gl_FragColor = waterColor;
gl_FragColor = applyAerialPerspective(gl_FragColor);
gl_FragColor = applyToneMapping(gl_FragColor);
gl_FragColor.a = distanceFadeout();
}

View file

@ -0,0 +1,11 @@
attribute highp vec4 vertex;
uniform highp mat4 viewMatrix;
uniform float waterHeight;
uniform vec3 cameraLocation;
varying vec3 unprojected;
void main(void)
{
unprojected = vec3(cameraLocation.x + vertex.x * 500.0, vertex.y + waterHeight, cameraLocation.z + vertex.z * 500.0);
gl_Position = viewMatrix * vec4(unprojected, 1.0);
}

View file

@ -934,7 +934,7 @@ static Color _sunColor(Vector3 v, Vector3 s, double r, double mu, double radius)
{ {
Color transmittance = r <= Rt ? _transmittanceWithShadow(r, mu) : COLOR_WHITE; /* T(x,xo) */ Color transmittance = r <= Rt ? _transmittanceWithShadow(r, mu) : COLOR_WHITE; /* T(x,xo) */
double d = _limit(r, mu); double d = _limit(r, mu);
radius *= (1.0 + 10.0 * d / Rt); /* Inflating due to lens effect near horizon */ radius *= (1.0 + 25.0 * d / Rt); /* Inflating due to lens effect near horizon */
double isun = step(cos(radius * M_PI / 180.0), v.dotProduct(s)) * ISun; /* Lsun */ double isun = step(cos(radius * M_PI / 180.0), v.dotProduct(s)) * ISun; /* Lsun */
transmittance.r *= isun; transmittance.r *= isun;
transmittance.g *= isun; transmittance.g *= isun;
@ -1268,3 +1268,18 @@ void AtmosphereModelBruneton::fillLightingStatus(LightStatus *status, const Vect
status->pushComponent(irradiance); status->pushComponent(irradiance);
} }
Texture2D *AtmosphereModelBruneton::getTextureTransmittance() const
{
return _transmittanceTexture;
}
Texture2D *AtmosphereModelBruneton::getTextureIrradiance() const
{
return _irradianceTexture;
}
Texture4D *AtmosphereModelBruneton::getTextureInscatter() const
{
return _inscatterTexture;
}

View file

@ -17,6 +17,11 @@ public:
AtmosphereResult applyAerialPerspective(Vector3 location, const Color &base); AtmosphereResult applyAerialPerspective(Vector3 location, const Color &base);
void fillLightingStatus(LightStatus *status, const Vector3 &normal, int opaque); void fillLightingStatus(LightStatus *status, const Vector3 &normal, int opaque);
/* Functions to get access to internal textures (for opengl shaders) */
Texture2D* getTextureTransmittance() const;
Texture2D* getTextureIrradiance() const;
Texture4D* getTextureInscatter() const;
private: private:
SoftwareRenderer* parent; SoftwareRenderer* parent;
}; };

View file

@ -39,6 +39,8 @@ public:
virtual AtmosphereResult applyAerialPerspective(Vector3 location, Color base) override; virtual AtmosphereResult applyAerialPerspective(Vector3 location, Color base) override;
virtual AtmosphereResult getSkyColor(Vector3 direction) override; virtual AtmosphereResult getSkyColor(Vector3 direction) override;
inline const AtmosphereModelBruneton* getModel() const {return model;}
private: private:
AtmosphereModelBruneton* model; AtmosphereModelBruneton* model;
}; };

1
src/system/Logs.cpp Normal file
View file

@ -0,0 +1 @@
#include "Logs.h"

9
src/system/Logs.h Normal file
View file

@ -0,0 +1,9 @@
#ifndef LOGS_H
#define LOGS_H
#include "system_global.h"
#define logWarning qWarning
#define logError qCritical
#endif // LOGS_H

View file

@ -0,0 +1,55 @@
#include "ParallelPool.h"
#include "System.h"
#include "Thread.h"
static void* _threadFunction(void* data)
{
ParallelPool* pool = (ParallelPool*)data;
pool->work();
return NULL;
}
ParallelPool::ParallelPool()
{
running = false;
}
ParallelPool::~ParallelPool()
{
if (running)
{
interrupt();
}
for (auto thread : threads)
{
thread->join();
delete thread;
}
threads.clear();
}
void ParallelPool::start(int thread_count)
{
if (running)
{
qCritical("Starting an already started parallel pool !");
return;
}
running = true;
if (thread_count < 0)
{
thread_count = System::getCoreCount();
}
for (int i = 0; i < thread_count; i++)
{
Thread* thread = new Thread(_threadFunction);
thread->start(this);
threads.push_back(thread);
}
}
void ParallelPool::interrupt()
{
running = false;
}

43
src/system/ParallelPool.h Normal file
View file

@ -0,0 +1,43 @@
#ifndef PARALLELPOOL_H
#define PARALLELPOOL_H
#include "system_global.h"
namespace paysages {
namespace system {
/*!
* Pool to handle a group of threads doing the same task.
*/
class ParallelPool
{
public:
ParallelPool();
virtual ~ParallelPool();
/*!
* Start the effective work.
*/
void start(int thread_count=-1);
/*!
* Method called from each thread to do actual work.
*/
virtual void work() = 0;
/*!
* Method called once to interrupt all threads.
*/
virtual void interrupt();
protected:
bool running;
private:
std::vector<Thread*> threads;
};
}
}
#endif // PARALLELPOOL_H

View file

@ -23,7 +23,9 @@ SOURCES += \
ParallelWork.cpp \ ParallelWork.cpp \
ParallelQueue.cpp \ ParallelQueue.cpp \
CacheFile.cpp \ CacheFile.cpp \
PictureWriter.cpp PictureWriter.cpp \
Logs.cpp \
ParallelPool.cpp
HEADERS += \ HEADERS += \
system_global.h \ system_global.h \
@ -36,7 +38,9 @@ HEADERS += \
ParallelWork.h \ ParallelWork.h \
ParallelQueue.h \ ParallelQueue.h \
CacheFile.h \ CacheFile.h \
PictureWriter.h PictureWriter.h \
Logs.h \
ParallelPool.h
unix:!symbian { unix:!symbian {
maemo5 { maemo5 {

View file

@ -15,6 +15,7 @@ namespace system {
class PackStream; class PackStream;
class ParallelQueue; class ParallelQueue;
class ParallelWork; class ParallelWork;
class ParallelPool;
class Thread; class Thread;
class Mutex; class Mutex;
} }

View file

@ -0,0 +1,100 @@
#include "BaseTestCase.h"
#include "VertexArray.h"
class TestVertex
{
public:
float uv[2];
int loc[3];
bool operator==(const TestVertex &other) const
{
return other.uv[0] == uv[0]
and other.uv[1] == uv[1]
and other.loc[0] == loc[0]
and other.loc[1] == loc[1]
and other.loc[2] == loc[2];
}
};
TEST(VertexArray, grid)
{
VertexArray<TestVertex> array;
array.setGridSize(3);
ASSERT_EQ(9, array.getVertexCount());
TestVertex v1 = {{0.1, 0.2}, {1, 2, 3}};
TestVertex vgot;
array.setGridVertex(3, 1, 2, v1);
vgot = array.getGridVertex(3, 1, 2);
EXPECT_EQ(v1, vgot);
vgot = array.getVertex(7);
EXPECT_EQ(v1, vgot);
}
TEST(VertexArray, gridIndices)
{
VertexArray<TestVertex> array;
array.setGridSize(3);
array.setAutoGridIndices(3);
ASSERT_EQ(24, array.getIndexCount());
EXPECT_EQ(0, array.getIndex(0));
EXPECT_EQ(3, array.getIndex(1));
EXPECT_EQ(1, array.getIndex(2));
EXPECT_EQ(1, array.getIndex(3));
EXPECT_EQ(3, array.getIndex(4));
EXPECT_EQ(4, array.getIndex(5));
EXPECT_EQ(1, array.getIndex(6));
EXPECT_EQ(4, array.getIndex(7));
EXPECT_EQ(2, array.getIndex(8));
EXPECT_EQ(2, array.getIndex(9));
EXPECT_EQ(4, array.getIndex(10));
EXPECT_EQ(5, array.getIndex(11));
EXPECT_EQ(3, array.getIndex(12));
EXPECT_EQ(6, array.getIndex(13));
EXPECT_EQ(4, array.getIndex(14));
}
TEST(VertexArray, gridIndicesStride)
{
VertexArray<TestVertex> array;
array.setGridSize(5);
array.setAutoGridIndices(5, 1);
ASSERT_EQ(96, array.getIndexCount());
array.setAutoGridIndices(5, 2);
ASSERT_EQ(24, array.getIndexCount());
EXPECT_EQ(0, array.getIndex(0));
EXPECT_EQ(10, array.getIndex(1));
EXPECT_EQ(2, array.getIndex(2));
EXPECT_EQ(2, array.getIndex(3));
EXPECT_EQ(10, array.getIndex(4));
EXPECT_EQ(12, array.getIndex(5));
EXPECT_EQ(2, array.getIndex(6));
EXPECT_EQ(12, array.getIndex(7));
EXPECT_EQ(4, array.getIndex(8));
EXPECT_EQ(4, array.getIndex(9));
EXPECT_EQ(12, array.getIndex(10));
EXPECT_EQ(14, array.getIndex(11));
EXPECT_EQ(10, array.getIndex(12));
EXPECT_EQ(20, array.getIndex(13));
EXPECT_EQ(12, array.getIndex(14));
}

View file

@ -17,7 +17,8 @@ SOURCES += main.cpp \
Bruneton_Test.cpp \ Bruneton_Test.cpp \
Camera_Test.cpp \ Camera_Test.cpp \
Clouds_Test.cpp \ Clouds_Test.cpp \
FluidMediumManager_Test.cpp FluidMediumManager_Test.cpp \
VertexArray_Test.cpp
HEADERS += \ HEADERS += \
BaseTestCase.h BaseTestCase.h
@ -51,3 +52,9 @@ else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../render/software/
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