Switched opengl skybox to shaders
This commit is contained in:
parent
c497cf2127
commit
7b790d2015
21 changed files with 948 additions and 207 deletions
|
@ -20,6 +20,9 @@ namespace basics {
|
|||
class NoiseGenerator;
|
||||
class Curve;
|
||||
class ColorProfile;
|
||||
class Texture2D;
|
||||
class Texture3D;
|
||||
class Texture4D;
|
||||
}
|
||||
}
|
||||
using namespace paysages::basics;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define DEFINITION_GLOBAL_H
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
|
||||
#if defined(DEFINITION_LIBRARY)
|
||||
# define DEFINITIONSHARED_EXPORT Q_DECL_EXPORT
|
||||
#else
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
109
src/render/opengl/OpenGLPart.cpp
Normal file
109
src/render/opengl/OpenGLPart.cpp
Normal file
|
@ -0,0 +1,109 @@
|
|||
#include "OpenGLPart.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <cmath>
|
||||
#include "OpenGLRenderer.h"
|
||||
#include "OpenGLShaderProgram.h"
|
||||
#include "CameraDefinition.h"
|
||||
#include "AtmosphereDefinition.h"
|
||||
#include "AtmosphereRenderer.h"
|
||||
#include "WaterRenderer.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->getOpenGlFunctions());
|
||||
|
||||
if (!shaders.contains(name))
|
||||
{
|
||||
shaders[name] = program;
|
||||
return program;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLPart::postInitialize()
|
||||
{
|
||||
QMapIterator<QString, OpenGLShaderProgram*> i(shaders);
|
||||
while (i.hasNext())
|
||||
{
|
||||
i.next();
|
||||
i.value()->compile();
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLPart::updateCamera(CameraDefinition* camera)
|
||||
{
|
||||
// Get camera info
|
||||
Vector3 location = camera->getLocation();
|
||||
Vector3 target = camera->getTarget();
|
||||
Vector3 up = camera->getUpVector();
|
||||
CameraPerspective perspective = camera->getPerspective();
|
||||
|
||||
QVector3D vlocation(location.x, location.y, location.z);
|
||||
|
||||
// Compute matrix
|
||||
QMatrix4x4 transform;
|
||||
transform.setToIdentity();
|
||||
transform.lookAt(vlocation,
|
||||
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
|
||||
QMapIterator<QString, OpenGLShaderProgram*> i(shaders);
|
||||
while (i.hasNext())
|
||||
{
|
||||
i.next();
|
||||
i.value()->updateCamera(vlocation, projection * transform);
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLPart::updateScenery(bool onlyCommon)
|
||||
{
|
||||
Scenery* scenery = renderer->getScenery();
|
||||
|
||||
// Collect common info
|
||||
double water_height = renderer->getWaterRenderer()->getHeightInfo().max_height;
|
||||
Vector3 orig_sun_direction = renderer->getAtmosphereRenderer()->getSunDirection();
|
||||
QVector3D sun_direction = QVector3D(orig_sun_direction.x, orig_sun_direction.y, orig_sun_direction.z);
|
||||
Color orig_sun_color = scenery->getAtmosphere()->sun_color;
|
||||
QColor sun_color = QColor(orig_sun_color.r, orig_sun_color.g, orig_sun_color.b);
|
||||
|
||||
// Update shaders
|
||||
QMapIterator<QString, OpenGLShaderProgram*> i(shaders);
|
||||
while (i.hasNext())
|
||||
{
|
||||
i.next();
|
||||
|
||||
i.value()->updateWaterHeight(water_height);
|
||||
i.value()->updateSun(sun_direction, sun_color);
|
||||
}
|
||||
|
||||
// Let subclass do its own collecting
|
||||
if (not onlyCommon)
|
||||
{
|
||||
update();
|
||||
}
|
||||
}
|
46
src/render/opengl/OpenGLPart.h
Normal file
46
src/render/opengl/OpenGLPart.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
#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 postInitialize();
|
||||
void updateCamera(CameraDefinition* camera);
|
||||
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
|
|
@ -1,18 +1,22 @@
|
|||
#include "OpenGLRenderer.h"
|
||||
|
||||
#include <QOpenGLFunctions>
|
||||
#include <cmath>
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glu.h>
|
||||
#include "Scenery.h"
|
||||
#include "CameraDefinition.h"
|
||||
#include "OpenGLSkybox.h"
|
||||
|
||||
OpenGLRenderer::OpenGLRenderer(Scenery* scenery):
|
||||
SoftwareRenderer(scenery)
|
||||
{
|
||||
skybox = new OpenGLSkybox(this);
|
||||
}
|
||||
|
||||
OpenGLRenderer::~OpenGLRenderer()
|
||||
{
|
||||
delete skybox;
|
||||
}
|
||||
|
||||
void OpenGLRenderer::initialize()
|
||||
|
@ -38,6 +42,11 @@ void OpenGLRenderer::initialize()
|
|||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
prepare();
|
||||
|
||||
functions = new QOpenGLFunctions();
|
||||
|
||||
skybox->initialize();
|
||||
skybox->updateScenery();
|
||||
}
|
||||
|
||||
void OpenGLRenderer::resize(int width, int height)
|
||||
|
@ -56,7 +65,15 @@ void OpenGLRenderer::resize(int width, int height)
|
|||
|
||||
void OpenGLRenderer::paint()
|
||||
{
|
||||
glClearColor(0.0, 0.0, 0.0, 0.0);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
skybox->render();
|
||||
}
|
||||
|
||||
void OpenGLRenderer::cameraChangeEvent(CameraDefinition *camera)
|
||||
{
|
||||
skybox->updateCamera(camera);
|
||||
}
|
||||
|
||||
double OpenGLRenderer::getPrecision(const Vector3 &)
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
#include "SoftwareRenderer.h"
|
||||
|
||||
class QOpenGLFunctions;
|
||||
|
||||
namespace paysages {
|
||||
namespace opengl {
|
||||
|
||||
|
@ -21,8 +23,17 @@ public:
|
|||
void resize(int width, int height);
|
||||
void paint();
|
||||
|
||||
void cameraChangeEvent(CameraDefinition* camera);
|
||||
|
||||
inline QOpenGLFunctions* getOpenGlFunctions() {return functions;}
|
||||
|
||||
virtual double getPrecision(const Vector3 &location) override;
|
||||
virtual Color applyMediumTraversal(Vector3 location, Color color) override;
|
||||
|
||||
private:
|
||||
QOpenGLFunctions* functions;
|
||||
|
||||
OpenGLSkybox* skybox;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
277
src/render/opengl/OpenGLShaderProgram.cpp
Normal file
277
src/render/opengl/OpenGLShaderProgram.cpp
Normal file
|
@ -0,0 +1,277 @@
|
|||
#include "OpenGLShaderProgram.h"
|
||||
|
||||
#include <QOpenGLShaderProgram>
|
||||
#include <QOpenGLFunctions>
|
||||
#include <QDir>
|
||||
#include "Texture2D.h"
|
||||
#include "Texture3D.h"
|
||||
#include "Texture4D.h"
|
||||
#include "Color.h"
|
||||
|
||||
OpenGLShaderProgram::OpenGLShaderProgram(QString name, QOpenGLFunctions* functions):
|
||||
name(name), functions(functions)
|
||||
{
|
||||
program = new QOpenGLShaderProgram();
|
||||
}
|
||||
|
||||
OpenGLShaderProgram::~OpenGLShaderProgram()
|
||||
{
|
||||
delete program;
|
||||
}
|
||||
|
||||
void OpenGLShaderProgram::addVertexSource(QString path)
|
||||
{
|
||||
program->addShaderFromSourceFile(QOpenGLShader::Vertex, QString(":/shaders/%1.vert").arg(path));
|
||||
}
|
||||
|
||||
void OpenGLShaderProgram::addFragmentSource(QString path)
|
||||
{
|
||||
program->addShaderFromSourceFile(QOpenGLShader::Fragment, QString(":/shaders/%1.frag").arg(path));
|
||||
}
|
||||
|
||||
void OpenGLShaderProgram::compile()
|
||||
{
|
||||
if (not program->link())
|
||||
{
|
||||
qWarning() << "Error while compiling shader " << name << "\n" << program->log() << "\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "Shader " << name << " compilation output:\n" << program->log() << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLShaderProgram::updateCamera(const QVector3D& location, const QMatrix4x4& view)
|
||||
{
|
||||
this->camera_location = location;
|
||||
this->view = view;
|
||||
}
|
||||
|
||||
void OpenGLShaderProgram::updateWaterHeight(double height)
|
||||
{
|
||||
this->water_height = height;
|
||||
}
|
||||
|
||||
void OpenGLShaderProgram::updateSun(const QVector3D& direction, const QColor& color)
|
||||
{
|
||||
this->sun_direction = direction;
|
||||
this->sun_color = color;
|
||||
}
|
||||
|
||||
void OpenGLShaderProgram::addTexture(QString sampler_name, Texture2D* texture)
|
||||
{
|
||||
GLuint texid;
|
||||
|
||||
if (textures.contains(sampler_name))
|
||||
{
|
||||
texid = textures[sampler_name].second;
|
||||
}
|
||||
else
|
||||
{
|
||||
glGenTextures(1, &texid);
|
||||
textures[sampler_name] = QPair<int, unsigned int>(GL_TEXTURE_2D, texid);
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, texid);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
int sx, sy;
|
||||
texture->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 = texture->getPixel(x, y);
|
||||
pixel[0] = (float)col.r;
|
||||
pixel[1] = (float)col.g;
|
||||
pixel[2] = (float)col.b;
|
||||
pixel[3] = (float)col.a;
|
||||
}
|
||||
}
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, sx, sy, 0, GL_RGBA, GL_FLOAT, pixels);
|
||||
delete[] pixels;
|
||||
}
|
||||
|
||||
void OpenGLShaderProgram::addTexture(QString sampler_name, Texture3D* texture)
|
||||
{
|
||||
GLuint texid;
|
||||
|
||||
if (textures.contains(sampler_name))
|
||||
{
|
||||
texid = textures[sampler_name].second;
|
||||
}
|
||||
else
|
||||
{
|
||||
glGenTextures(1, &texid);
|
||||
textures[sampler_name] = QPair<int, unsigned int>(GL_TEXTURE_3D, texid);
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_3D, texid);
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
|
||||
|
||||
int sx, sy, sz;
|
||||
texture->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 = texture->getPixel(x, y, z);
|
||||
pixel[0] = (float)col.r;
|
||||
pixel[1] = (float)col.g;
|
||||
pixel[2] = (float)col.b;
|
||||
pixel[3] = (float)col.a;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, sx, sy, sz, 0, GL_RGBA, GL_FLOAT, pixels);
|
||||
delete[] pixels;
|
||||
}
|
||||
|
||||
void OpenGLShaderProgram::addTexture(QString sampler_name, Texture4D* texture)
|
||||
{
|
||||
GLuint texid;
|
||||
|
||||
if (textures.contains(sampler_name))
|
||||
{
|
||||
texid = textures[sampler_name].second;
|
||||
}
|
||||
else
|
||||
{
|
||||
glGenTextures(1, &texid);
|
||||
textures[sampler_name] = QPair<int, unsigned int>(GL_TEXTURE_3D, texid);
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_3D, texid);
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
|
||||
|
||||
int sx, sy, sz, sw;
|
||||
texture->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 = texture->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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, sx, sy, sz * sw, 0, GL_RGBA, GL_FLOAT, pixels);
|
||||
delete[] pixels;
|
||||
}
|
||||
|
||||
void OpenGLShaderProgram::bind()
|
||||
{
|
||||
program->bind();
|
||||
|
||||
// TODO Keep locations in cache
|
||||
|
||||
int viewMatrix = program->uniformLocation("viewMatrix");
|
||||
if (viewMatrix >= 0)
|
||||
{
|
||||
program->setUniformValue(viewMatrix, view);
|
||||
}
|
||||
|
||||
int cameraLocation = program->uniformLocation("cameraLocation");
|
||||
if (cameraLocation >= 0)
|
||||
{
|
||||
program->setUniformValue(cameraLocation, camera_location);
|
||||
}
|
||||
|
||||
int waterHeight = program->uniformLocation("waterHeight");
|
||||
if (waterHeight >= 0)
|
||||
{
|
||||
program->setUniformValue(waterHeight, water_height);
|
||||
}
|
||||
|
||||
int sunDirection = program->uniformLocation("sunDirection");
|
||||
if (sunDirection >= 0)
|
||||
{
|
||||
program->setUniformValue(sunDirection, sun_direction);
|
||||
}
|
||||
|
||||
int sunColor = program->uniformLocation("sunColor");
|
||||
if (sunColor >= 0)
|
||||
{
|
||||
program->setUniformValue(sunColor, sun_color);
|
||||
}
|
||||
|
||||
QMapIterator<QString, QPair<int, unsigned int> > iter(textures);
|
||||
int i = 0;
|
||||
while (iter.hasNext())
|
||||
{
|
||||
iter.next();
|
||||
int textureSampler = program->uniformLocation(iter.key());
|
||||
if (textureSampler >= 0)
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE0 + i);
|
||||
glBindTexture(iter.value().first, iter.value().second);
|
||||
program->setUniformValue(textureSampler, i);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, vertex_count);
|
||||
|
||||
program->disableAttributeArray(vertex);
|
||||
|
||||
release();
|
||||
}
|
61
src/render/opengl/OpenGLShaderProgram.h
Normal file
61
src/render/opengl/OpenGLShaderProgram.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
#ifndef OPENGLSHADERPROGRAM_H
|
||||
#define OPENGLSHADERPROGRAM_H
|
||||
|
||||
#include "opengl_global.h"
|
||||
|
||||
#include <QString>
|
||||
#include <QMatrix4x4>
|
||||
#include <QColor>
|
||||
#include <QMap>
|
||||
#include <QPair>
|
||||
|
||||
class QOpenGLShaderProgram;
|
||||
class QOpenGLFunctions;
|
||||
|
||||
namespace paysages {
|
||||
namespace opengl {
|
||||
|
||||
class OPENGLSHARED_EXPORT OpenGLShaderProgram
|
||||
{
|
||||
public:
|
||||
OpenGLShaderProgram(QString name, QOpenGLFunctions* functions);
|
||||
~OpenGLShaderProgram();
|
||||
|
||||
void addVertexSource(QString path);
|
||||
void addFragmentSource(QString path);
|
||||
void compile();
|
||||
|
||||
void updateCamera(const QVector3D& location, const QMatrix4x4& view);
|
||||
void updateWaterHeight(double height);
|
||||
void updateSun(const QVector3D& direction, const QColor& color);
|
||||
|
||||
void addTexture(QString sampler_name, Texture2D* texture);
|
||||
void addTexture(QString sampler_name, Texture3D* texture);
|
||||
void addTexture(QString sampler_name, Texture4D* texture);
|
||||
|
||||
void drawTriangles(float* vertices, int triangle_count);
|
||||
void drawTriangleStrip(float* vertices, int vertex_count);
|
||||
|
||||
private:
|
||||
void bind();
|
||||
void release();
|
||||
|
||||
QMatrix4x4 view;
|
||||
QVector3D camera_location;
|
||||
|
||||
float water_height;
|
||||
|
||||
QVector3D sun_direction;
|
||||
QColor sun_color;
|
||||
|
||||
QString name;
|
||||
QOpenGLShaderProgram* program;
|
||||
QOpenGLFunctions* functions;
|
||||
|
||||
QMap<QString, QPair<int, unsigned int> > textures;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // OPENGLSHADERPROGRAM_H
|
96
src/render/opengl/OpenGLSkybox.cpp
Normal file
96
src/render/opengl/OpenGLSkybox.cpp
Normal file
|
@ -0,0 +1,96 @@
|
|||
#include "OpenGLSkybox.h"
|
||||
|
||||
#include <cmath>
|
||||
#include "OpenGLRenderer.h"
|
||||
#include "OpenGLShaderProgram.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("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()
|
||||
{
|
||||
SoftwareBrunetonAtmosphereRenderer* bruneton = (SoftwareBrunetonAtmosphereRenderer*)renderer->getAtmosphereRenderer();
|
||||
|
||||
program->addTexture("transmittanceTexture", bruneton->getModel()->getTextureTransmittance());
|
||||
program->addTexture("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;
|
||||
}
|
35
src/render/opengl/OpenGLSkybox.h
Normal file
35
src/render/opengl/OpenGLSkybox.h
Normal 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
|
|
@ -11,7 +11,6 @@
|
|||
#include "WaterDefinition.h"
|
||||
#include "SurfaceMaterial.h"
|
||||
#include "CameraDefinition.h"
|
||||
#include "ExplorerChunkSky.h"
|
||||
#include "ExplorerChunkTerrain.h"
|
||||
#include "TerrainRenderer.h"
|
||||
#include "WaterRenderer.h"
|
||||
|
@ -113,14 +112,6 @@ void WidgetExplorer::startRendering()
|
|||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
@ -374,9 +365,13 @@ void WidgetExplorer::paintGL()
|
|||
// Don't do this at each frame, only on camera change
|
||||
_renderer->getScenery()->setCamera(_current_camera);
|
||||
_renderer->getScenery()->getCamera(_current_camera);
|
||||
_renderer->cameraChangeEvent(_current_camera);
|
||||
|
||||
start_time = QTime::currentTime();
|
||||
|
||||
// Background
|
||||
_renderer->paint();
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
Vector3 camera_location = _current_camera->getLocation();
|
||||
|
@ -384,10 +379,6 @@ void WidgetExplorer::paintGL()
|
|||
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
|
||||
glClearColor(0.0, 0.0, 0.0, 0.0);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
// Render water
|
||||
double water_height = _renderer->getTerrainRenderer()->getWaterHeight();
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
|
|
|
@ -16,17 +16,21 @@ include(../../common.pri)
|
|||
SOURCES += \
|
||||
OpenGLRenderer.cpp \
|
||||
BaseExplorerChunk.cpp \
|
||||
ExplorerChunkSky.cpp \
|
||||
ExplorerChunkTerrain.cpp \
|
||||
WidgetExplorer.cpp
|
||||
WidgetExplorer.cpp \
|
||||
OpenGLShaderProgram.cpp \
|
||||
OpenGLPart.cpp \
|
||||
OpenGLSkybox.cpp
|
||||
|
||||
HEADERS +=\
|
||||
opengl_global.h \
|
||||
OpenGLRenderer.h \
|
||||
BaseExplorerChunk.h \
|
||||
ExplorerChunkSky.h \
|
||||
ExplorerChunkTerrain.h \
|
||||
WidgetExplorer.h
|
||||
WidgetExplorer.h \
|
||||
OpenGLShaderProgram.h \
|
||||
OpenGLPart.h \
|
||||
OpenGLSkybox.h
|
||||
|
||||
unix:!symbian {
|
||||
maemo5 {
|
||||
|
@ -60,3 +64,10 @@ else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../software/debug/
|
|||
else:unix: LIBS += -L$$OUT_PWD/../software/ -lpaysages_render_software
|
||||
INCLUDEPATH += $$PWD/../software
|
||||
DEPENDPATH += $$PWD/../software
|
||||
|
||||
RESOURCES += \
|
||||
shaders/resources.qrc
|
||||
|
||||
OTHER_FILES += \
|
||||
shaders/skybox.frag \
|
||||
shaders/skybox.vert
|
||||
|
|
|
@ -16,6 +16,8 @@ namespace opengl {
|
|||
class WidgetExplorer;
|
||||
class OpenGLRenderer;
|
||||
class BaseExplorerChunk;
|
||||
class OpenGLShaderProgram;
|
||||
class OpenGLSkybox;
|
||||
}
|
||||
}
|
||||
using namespace paysages::opengl;
|
||||
|
|
6
src/render/opengl/shaders/resources.qrc
Normal file
6
src/render/opengl/shaders/resources.qrc
Normal file
|
@ -0,0 +1,6 @@
|
|||
<RCC>
|
||||
<qresource prefix="/shaders">
|
||||
<file>skybox.frag</file>
|
||||
<file>skybox.vert</file>
|
||||
</qresource>
|
||||
</RCC>
|
233
src/render/opengl/shaders/skybox.frag
Normal file
233
src/render/opengl/shaders/skybox.frag
Normal file
|
@ -0,0 +1,233 @@
|
|||
const float GROUND_OFFSET = 0.5;
|
||||
const float Rg = 6360.0;
|
||||
const float Rt = 6420.0;
|
||||
const float RL = 6421.0;
|
||||
const float exposure = 0.4;
|
||||
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 + 10.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;
|
||||
}
|
||||
|
||||
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 _toneMappingUncharted(vec4 color, float exposure)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
void main(void)
|
||||
{
|
||||
float yoffset = GROUND_OFFSET - waterHeight;
|
||||
float cameray = max(cameraLocation[1] + yoffset, 0.0);
|
||||
vec3 x = vec3(0.0, Rg + cameray * WORLD_SCALING, 0.0);
|
||||
vec3 v = normalize(unprojected - cameraLocation);
|
||||
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 = _toneMappingUncharted(sunTransmittance + vec4(inscattering, 0.0), 2.0);
|
||||
}
|
10
src/render/opengl/shaders/skybox.vert
Normal file
10
src/render/opengl/shaders/skybox.vert
Normal 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);
|
||||
}
|
|
@ -1268,3 +1268,18 @@ void AtmosphereModelBruneton::fillLightingStatus(LightStatus *status, const Vect
|
|||
|
||||
status->pushComponent(irradiance);
|
||||
}
|
||||
|
||||
Texture2D *AtmosphereModelBruneton::getTextureTransmittance() const
|
||||
{
|
||||
return _transmittanceTexture;
|
||||
}
|
||||
|
||||
Texture2D *AtmosphereModelBruneton::getTextureIrradiance() const
|
||||
{
|
||||
return _irradianceTexture;
|
||||
}
|
||||
|
||||
Texture4D *AtmosphereModelBruneton::getTextureInscatter() const
|
||||
{
|
||||
return _inscatterTexture;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,11 @@ public:
|
|||
AtmosphereResult applyAerialPerspective(Vector3 location, const Color &base);
|
||||
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:
|
||||
SoftwareRenderer* parent;
|
||||
};
|
||||
|
|
|
@ -39,6 +39,8 @@ public:
|
|||
virtual AtmosphereResult applyAerialPerspective(Vector3 location, Color base) override;
|
||||
virtual AtmosphereResult getSkyColor(Vector3 direction) override;
|
||||
|
||||
inline const AtmosphereModelBruneton* getModel() const {return model;}
|
||||
|
||||
private:
|
||||
AtmosphereModelBruneton* model;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue