terrain-gen/src/terrain.cpp

276 lines
9.6 KiB
C++

#include "terrain.h"
Terrain::Terrain():
m_showNormals(Config::terrainShowNormals()), m_skyAnimation(Config::skyAnimation()),
m_skybox(2048), m_shadowMap(2048),
m_camera(Config::cameraPosition(), Config::cameraRotation()),
m_light(Config::skyTime(), Config::skyInclination())
{
connect(&m_light, SIGNAL(directionChanged(QVector3D)), &m_shadowMap, SLOT(setLightDirection(QVector3D)));
createTerrain();
m_timeSinceStart.start();
m_lastFrameTime = m_timeSinceStart.elapsed();
m_light.updateSunlightDirection();
}
Terrain::~Terrain()
{
deleteFrameBufferObject();
delete m_landProgram;
delete m_waterProgram;
delete m_skyboxProgram;
delete m_normalProgram;
delete m_shadingProgram;
}
Light* Terrain::light()
{
return &m_light;
}
Camera* Terrain::camera()
{
return &m_camera;
}
void Terrain::setSkyAnimation(bool newState)
{
m_skyAnimation = newState;
}
void Terrain::setShowNormals(bool newState)
{
m_showNormals = newState;
}
QOpenGLShaderProgram* Terrain::getProgram(QString shaderName, bool useGeom)
{
QOpenGLShaderProgram* program = new QOpenGLShaderProgram;
program->addShaderFromSourceFile(QOpenGLShader::Vertex, "shaders/" + shaderName + ".vert");
if (useGeom) {
program->addShaderFromSourceFile(QOpenGLShader::Geometry, "shaders/" + shaderName +".geom");
}
program->addShaderFromSourceFile(QOpenGLShader::Fragment, "shaders/" + shaderName + ".frag");
program->link();
return program;
}
void Terrain::createTerrain()
{
QTime time;
time.start();
qDebug() << "Generating terrain...";
for (int j = -3; j < 4; j ++) {
for (int i = -3; i < 4; i++) {
m_blocks.push_back(std::make_shared<Block>(i, j, 32, .5));
}
}
qDebug() << "Terrain generated in " << double(time.elapsed()) / 1000 << "s";
}
void Terrain::setViewPort(int width, int height)
{
m_viewWidth = width;
m_viewHeight = height;
m_camera.setRatio(float(width) / float(height));
deleteFrameBufferObject();
createFrameBufferObject();
}
void Terrain::createSimpleTextures(GLuint* texturesId, GLsizei nbTextures, GLsizei width, GLsizei height)
{
glGenTextures(nbTextures, texturesId);
for (GLsizei i = 0; i < nbTextures; i++) {
glBindTexture(GL_TEXTURE_2D, texturesId[i]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, width, height, 0, GL_RGB, GL_FLOAT, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_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);
}
}
void Terrain::createFrameBufferObject()
{
createSimpleTextures(m_renderedTextures, Terrain::TextureCount - 1, m_viewWidth, m_viewHeight);
glGenFramebuffers(2, m_frameBuffers);
// G-Buffer
glBindFramebuffer(GL_FRAMEBUFFER, m_frameBuffers[0]);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_renderedTextures[Terrain::Colors], 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, m_renderedTextures[Terrain::Position], 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, m_renderedTextures[Terrain::Normals], 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D, m_renderedTextures[Terrain::MeshProperties], 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT4, GL_TEXTURE_2D, m_renderedTextures[Terrain::WaterDepth], 0);
glGenTextures(1, &m_renderedTextures[Terrain::Depth]);
glBindTexture(GL_TEXTURE_2D, m_renderedTextures[Terrain::Depth]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, m_viewWidth, m_viewHeight, 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_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);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_renderedTextures[Terrain::Depth], 0);
GLenum drawGBuffer[5] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3, GL_COLOR_ATTACHMENT4};
glDrawBuffers(5, drawGBuffer);
// Shading buffer
glBindFramebuffer(GL_FRAMEBUFFER, m_frameBuffers[1]);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
glReadBuffer(GL_COLOR_ATTACHMENT0);
}
void Terrain::deleteFrameBufferObject()
{
glDeleteFramebuffers(2, m_frameBuffers);
glDeleteTextures(Terrain::TextureCount, m_renderedTextures);
}
void Terrain::initGl()
{
initializeOpenGLFunctions();
m_landProgram = new Shader("land", false);
m_waterProgram = new Shader("water", false);
m_normalProgram = new Shader("normal", true);
m_skyboxProgram = new Shader("skybox", false);
m_shadingProgram = new Shader("shading", false);
for (std::shared_ptr<Block> block: m_blocks) {
block->water()->initGl(m_waterProgram, m_normalProgram);
block->land()->initGl(m_landProgram, m_normalProgram);
}
m_skybox.initGl(m_skyboxProgram);
m_quad.initGl(m_shadingProgram);
m_shadowMap.initGl();
m_light.initGl();
m_camera.initGl();
GLint viewPort[4];
glGetIntegerv(GL_VIEWPORT, viewPort);
m_viewWidth = viewPort[2];
m_viewHeight = viewPort[3];
createFrameBufferObject();
}
void Terrain::setUniforms(Shader* program, RenderPassType renderPass)
{
glUniform1i(program->uniformLocation("u_time"), m_timeSinceStart.elapsed());
glUniform1i(program->uniformLocation("u_renderPass"), renderPass);
glUniform2i(program->uniformLocation("u_screenSize"), m_viewWidth, m_viewHeight);
}
void Terrain::setAllUniformsForProgram(Shader* program, RenderPassType renderPass)
{
program->bind();
setUniforms(program, renderPass);
m_light.setUniforms(program, renderPass);
m_camera.setUniforms(program, renderPass);
m_shadowMap.setUniforms(program, renderPass);
program->release();
}
void Terrain::defferedShadingPipeline(RenderPassType renderPass)
{
setAllUniformsForProgram(m_landProgram, renderPass);
setAllUniformsForProgram(m_waterProgram, renderPass);
setAllUniformsForProgram(m_shadingProgram, renderPass);
setAllUniformsForProgram(m_skyboxProgram, renderPass);
m_shadingProgram->setTexture("colorTexture", GL_TEXTURE0, m_renderedTextures[Terrain::Colors]);
m_shadingProgram->setTexture("positionTexture", GL_TEXTURE1, m_renderedTextures[Terrain::Position]);
m_shadingProgram->setTexture("normalTexture", GL_TEXTURE2, m_renderedTextures[Terrain::Normals]);
m_shadingProgram->setTexture("meshPropertyTexture", GL_TEXTURE4, m_renderedTextures[Terrain::MeshProperties]);
m_shadingProgram->setTexture("depthTexture", GL_TEXTURE5, m_renderedTextures[Terrain::Depth]);
m_shadingProgram->setTexture("shadowMapTexture", GL_TEXTURE6, m_shadowMap.depthTexture());
// Geometry pass
glBindFramebuffer(GL_FRAMEBUFFER, m_frameBuffers[0]);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
if (m_showNormals) {
setAllUniformsForProgram(m_normalProgram, RenderPassType::FINAL);
}
for (std::shared_ptr<Block> block: m_blocks) {
block->land()->render(m_model);
if (m_showNormals) {
block->land()->renderNormals(m_model);
}
}
// Final pass
glBindFramebuffer(GL_FRAMEBUFFER, m_frameBuffers[1]);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_renderedTextures[Terrain::Depth], 0);
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
m_quad.render();
m_skybox.render();
}
void Terrain::render(GLuint defaultFrameBuffer)
{
if (m_skyAnimation) {
m_light.addToTimeOfDay(float(m_timeSinceStart.elapsed() - m_lastFrameTime) / (120 * 1000) * 1440);
}
m_lastFrameTime = m_timeSinceStart.elapsed();
// Shadow pass
m_shadowMap.preRender();
setAllUniformsForProgram(m_landProgram, RenderPassType::SHADOW);
for (std::shared_ptr<Block> block: m_blocks) {
block->land()->render(m_model);
}
glViewport(0, 0, m_viewWidth, m_viewHeight);
// DEFFERED SHADING PIPELINE
// Reflection render
glBindFramebuffer(GL_FRAMEBUFFER, m_frameBuffers[1]);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_renderedTextures[Terrain::Reflection], 0);
defferedShadingPipeline(RenderPassType::REFLECTION);
// Final render
glBindFramebuffer(GL_FRAMEBUFFER, m_frameBuffers[1]);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_renderedTextures[Terrain::Refraction], 0);
defferedShadingPipeline(RenderPassType::FINAL);
// FORWARD SHADING PIPELINE
glBindFramebuffer(GL_READ_FRAMEBUFFER, m_frameBuffers[1]);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, defaultFrameBuffer);
glBlitFramebuffer(0, 0, m_viewWidth, m_viewHeight, 0, 0, m_viewWidth, m_viewHeight, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST);
m_waterProgram->setTexture("reflectionTexture", GL_TEXTURE0, m_renderedTextures[Terrain::Reflection]);
m_waterProgram->setTexture("refractionTexture", GL_TEXTURE1, m_renderedTextures[Terrain::Refraction]);
m_waterProgram->setTexture("waterDepthTexture", GL_TEXTURE2, m_renderedTextures[Terrain::WaterDepth]);
m_waterProgram->setTexture("shadowMapTexture", GL_TEXTURE3, m_shadowMap.depthTexture());
for (std::shared_ptr<Block> block: m_blocks) {
block->water()->render(m_model);
}
}