Commit 74a780c3 authored by Felix Schröder's avatar Felix Schröder
Browse files

Merge Renderer and RendererDeferred into a single class. Resolves #36

parent 1d36a806
......@@ -19,7 +19,7 @@ std::vector<const char*> materialNames = {"No Texture",
"Stippling"};
int materialID = 0;
Editor::Editor(std::shared_ptr<Window> window, std::shared_ptr<dino::RendererDeferred> renderer)
Editor::Editor(std::shared_ptr<Window> window, std::shared_ptr<dino::Renderer> renderer)
: m_window(std::move(window))
, m_renderer(std::move(renderer))
{
......
#pragma once
#include "dino\opengl\TextureResource.h"
#include "dino/opengl/TextureResource.h"
#include <dino/editor/Blueprints.h>
#include <dino/input/Window.h>
#include <optional>
......@@ -45,7 +45,7 @@ private:
class Editor
{
public:
explicit Editor(std::shared_ptr<Window> window, std::shared_ptr<RendererDeferred> renderer);
explicit Editor(std::shared_ptr<Window> window, std::shared_ptr<Renderer> renderer);
void drawSettings();
void drawBlueprint();
......@@ -84,7 +84,7 @@ private:
std::unique_ptr<dino::FrameBuffer> m_previewFramebuffer;
std::shared_ptr<dino::Texture> m_previewTexture;
std::shared_ptr<Window> m_window = nullptr;
std::shared_ptr<RendererDeferred> m_renderer;
std::shared_ptr<Renderer> m_renderer;
std::unique_ptr<Window> m_editorWindow;
std::unordered_set<uint32_t> m_selectedFieldIndices;
std::unordered_set<uint32_t> m_selectedLightIndices;
......
......@@ -7,7 +7,7 @@
#include <random>
#include "Editor.hpp"
std::shared_ptr<dino::RendererDeferred> renderer;
std::shared_ptr<dino::Renderer> renderer;
std::shared_ptr<dino::Window> mainWindow;
bool mainHasFocus = true;
int pixelObjectId = -1;
......@@ -164,7 +164,7 @@ int main()
dino::RenderLayer::TONE_MAPPING,
dino::RenderLayer::FXAA,
});
renderer = std::make_unique<dino::RendererDeferred>(
renderer = std::make_unique<dino::Renderer>(
deferredPipeline,
glm::ivec2(1280, 720) /*, dino::ShaderFile::load("post_process/stepVis.frag")*/);
renderer->add(outerBlend, std::make_shared<dino::Material>(glm::vec3(0.4, 0.7, 0.9)));
......
......@@ -102,7 +102,6 @@
#include "./rendering/Light.h"
#include "./rendering/Material.h"
#include "./rendering/Renderer.h"
#include "./rendering/RendererDeferred.h"
#include "./rendering/RenderLayer.h"
#include "./rendering/RingBuffer.h"
#include "./rendering/SkyBox.h"
......
......@@ -16,7 +16,7 @@
#include <variant>
#include <dino/Function.h>
#include <dino/rendering/RendererDeferred.h>
#include <dino/rendering/Renderer.h>
namespace dino
{
......
#pragma once
#include "Renderer.h"
#include <memory>
#include <vector>
#include "dino/opengl/Shader.h"
namespace dino
{
/**
......@@ -31,7 +33,7 @@ public:
SKYBOX,
SKYBOX_REFLECTIONS,
SILHOUETTE,
TONE_MAPPING,
TONE_MAPPING,
FXAA,
};
......
#include "Renderer.h"
#include "DistanceField.h"
#include "Renderer.h"
namespace dino
{
......@@ -10,6 +9,56 @@ Renderer::Renderer(const Shader::ShaderSource& onTrace)
createSkybox();
}
Renderer::Renderer(std::vector<std::shared_ptr<RenderLayer>> renderLayers, glm::ivec2 windowSize)
: Renderer(dino::ShaderFile::load("trace_plugin/gBuffer.glsl"))
{
m_renderLayers = renderLayers;
m_renderLayers.push_back(std::make_shared<RenderLayer>(RenderLayer::SILHOUETTE));
init(windowSize);
}
Renderer::Renderer(std::vector<RenderLayer::Type> renderLayers, glm::ivec2 windowSize)
: Renderer(dino::ShaderFile::load("trace_plugin/gBuffer.glsl"))
{
renderLayers.push_back(RenderLayer::SILHOUETTE);
m_renderLayers = RenderLayer::createRenderPipeline(renderLayers);
init(windowSize);
}
void Renderer::init(glm::ivec2 windowSize)
{
// gbuffer
m_gBufferFbo = std::make_shared<FrameBuffer>(windowSize);
m_normalTex = std::make_shared<Texture>(GL_TEXTURE_2D, GL_RGB16F, windowSize);
m_tTex = std::make_shared<Texture>(GL_TEXTURE_2D, GL_R16F, windowSize);
m_idTex = std::make_shared<Texture>(GL_TEXTURE_2D, GL_R16F, windowSize);
m_stepCountTex = std::make_shared<Texture>(GL_TEXTURE_2D, GL_R16F, windowSize);
m_minDistanceTex = std::make_shared<Texture>(GL_TEXTURE_2D, GL_R16F, windowSize);
m_gBufferFbo->addColorAttachment(0, m_normalTex);
m_gBufferFbo->addColorAttachment(1, m_tTex);
m_gBufferFbo->addColorAttachment(2, m_idTex);
m_gBufferFbo->addColorAttachment(3, m_stepCountTex);
m_gBufferFbo->addColorAttachment(4, m_minDistanceTex);
m_postProcessFbo[0].first = std::make_shared<Texture>(GL_TEXTURE_2D, GL_RGB16F, windowSize);
m_postProcessFbo[0].second = std::make_shared<FrameBuffer>();
m_postProcessFbo[0].second->addColorAttachment(0, m_postProcessFbo[0].first);
m_postProcessFbo[1].first = std::make_shared<Texture>(GL_TEXTURE_2D, GL_RGB16F, windowSize);
m_postProcessFbo[1].second = std::make_shared<FrameBuffer>();
m_postProcessFbo[1].second->addColorAttachment(0, m_postProcessFbo[1].first);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
m_deferredPrograms.resize(m_renderLayers.size());
for(auto& prog : m_deferredPrograms)
{
prog = Program();
prog.attachNew(GL_VERTEX_SHADER, dino::ShaderFile::load("screenFilling.vert"));
}
}
void Renderer::add(const std::shared_ptr<Operator>& op, const std::shared_ptr<Material>& material)
{
const auto max_id_iter =
......@@ -111,6 +160,28 @@ void Renderer::render(const glm::mat4& view, const glm::mat4& projection)
{
static Cube cube;
// render to gbuffer
m_gBufferFbo->bind();
// clear deferred textures
glm::vec3 clearValNormal(0.f);
GLfloat clearValId = -1;
GLfloat clearValSteps = 0.f;
GLfloat clearValMinDist = std::numeric_limits<float>::max();
GLfloat clearValT = 0.f;
FrameBufferCompat::get().clearNamedFramebufferfv(
m_gBufferFbo->id(), GL_COLOR, 0, value_ptr(clearValNormal));
FrameBufferCompat::get().clearNamedFramebufferfv(m_gBufferFbo->id(), GL_COLOR, 1, &clearValT);
FrameBufferCompat::get().clearNamedFramebufferfv(m_gBufferFbo->id(), GL_COLOR, 2, &clearValId);
FrameBufferCompat::get().clearNamedFramebufferfv(
m_gBufferFbo->id(), GL_COLOR, 3, &clearValSteps);
FrameBufferCompat::get().clearNamedFramebufferfv(
m_gBufferFbo->id(), GL_COLOR, 4, &clearValMinDist);
FrameBufferCompat::get().clearNamedFramebufferfi(
m_gBufferFbo->id(), GL_DEPTH_STENCIL, 0, 1.f, 0);
// construct render info and material vector
std::vector<Material> materials(m_materials.size());
m_dataProxy.clear();
auto fieldIter = m_distanceFields.begin();
......@@ -130,18 +201,21 @@ void Renderer::render(const glm::mat4& view, const glm::mat4& projection)
++fieldIter;
}
// update render info buffer
if(m_infoBuffer.size() < static_cast<GLsizeiptr>(m_distanceFields.size()))
{
m_infoBuffer.resize(m_infoBuffer.size() + 16, GL_DYNAMIC_STORAGE_BIT);
}
m_infoBuffer.assign(m_infos);
// update material buffer
if(m_materialBuffer.size() < static_cast<GLsizeiptr>(m_materials.size()))
{
m_materialBuffer.resize(m_materialBuffer.size() + 16, GL_DYNAMIC_STORAGE_BIT);
}
m_materialBuffer.assign(materials);
// update render data buffer
if(m_dataProxy.size() == 0)
m_dataProxy.push_back(1.f); // Fix Buffer size of 0
......@@ -152,6 +226,7 @@ void Renderer::render(const glm::mat4& view, const glm::mat4& projection)
if(m_invalidRenderables)
{
// construct distance field shader code
std::stringstream shader;
shader << "#pragma optionNV(inline all)\n"; // What the fuck, let's do like Donald Duck
shader << "\nlayout(std430, binding=" << DATA_STORAGE_BINDING
......@@ -209,23 +284,56 @@ void Renderer::render(const glm::mat4& view, const glm::mat4& projection)
std::for_each(m_lights.begin(), m_lights.end(), [&](auto& light) {
if(light.second->shadowType() == ShadowType::SHADOWMAP_SHADOW)
std::static_pointer_cast<ShadowMapLight>(light.second)->setGeneratedFragmentSource(
m_generatedShaderSource);
std::static_pointer_cast<ShadowMapLight>(light.second)
->setGeneratedFragmentSource(m_generatedShaderSource);
});
// construct common deferred shader code
const std::vector<Shader::ShaderSource> sharedSource = {
dino::ShaderFile::load("post_process/commonDeferred.glsl"),
dino::ShaderFile::load("implicit/ad_functions.glsl"),
m_generatedShaderSource,
dino::ShaderFile::load("common/light.glsl"),
dino::ShaderFile::load("common/material.glsl"),
dino::ShaderFile::load("trace.glsl"),
};
// updatede deferred shader programs
for(size_t i = 0; i < m_deferredPrograms.size() - 1; ++i)
{
std::vector<Shader::ShaderSource> src = sharedSource;
src.push_back(m_renderLayers[i]->getShaderSource());
m_deferredPrograms[i] = Program();
m_deferredPrograms[i].attachNew(GL_VERTEX_SHADER,
dino::ShaderFile::load("screenFilling.vert"));
m_deferredPrograms[i].attachNew(GL_FRAGMENT_SHADER, src);
m_deferredPrograms[i].link();
}
// update silhouette shader
std::vector<Shader::ShaderSource> src = sharedSource;
src.push_back(dino::ShaderFile::load("post_process/silhouette.glsl"));
m_deferredPrograms[m_deferredPrograms.size() - 1].attachNew(GL_FRAGMENT_SHADER, src);
m_deferredPrograms[m_deferredPrograms.size() - 1].use();
m_activeDfIdUniform = glGetUniformLocation(
m_deferredPrograms[m_deferredPrograms.size() - 1].id(), "activeDfId");
m_invalidRenderables = false;
}
// bind buffers
cube.vertexArray.bind();
m_data.bind(GL_SHADER_STORAGE_BUFFER, DATA_STORAGE_BINDING);
m_infoBuffer.bind(GL_SHADER_STORAGE_BUFFER, OBJECT_STORAGE_BINDING);
m_materialBuffer.bind(GL_SHADER_STORAGE_BUFFER, MATERIAL_STORAGE_BINDING);
// update camera buffer
if(m_cameraInfo.size() == 0)
m_cameraInfo.resize(1, CameraInfo(view, projection), GL_DYNAMIC_STORAGE_BIT);
else
m_cameraInfo.assign(CameraInfo(view, projection));
// update light buffer
if(m_lightBuffer.size() != static_cast<GLsizeiptr>(m_lights.size()))
{
m_lightBuffer.resize(m_lights.size(), GL_DYNAMIC_STORAGE_BIT);
......@@ -277,46 +385,104 @@ void Renderer::render(const glm::mat4& view, const glm::mat4& projection)
static_cast<GLsizei>(cube.vertexBuffer.size()),
static_cast<int>(m_distanceFields.size()),
0);
m_gBufferFbo->unbind();
// clear ping pong FBO
glm::vec3 clearColor{0, 0, 0};
FrameBufferCompat::get().clearNamedFramebufferfv(
m_postProcessFbo[0].second->id(), GL_COLOR, 0, value_ptr(clearColor));
FrameBufferCompat::get().clearNamedFramebufferfv(
m_postProcessFbo[1].second->id(), GL_COLOR, 0, value_ptr(clearColor));
// render render-layers
m_vao.bind();
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
for(size_t i = 0; i < m_deferredPrograms.size(); ++i)
{
if(m_renderLayers[i]->isActive())
{
m_deferredPrograms[i].use();
m_normalTex->bind(0);
m_tTex->bind(1);
m_idTex->bind(2);
m_stepCountTex->bind(3);
m_minDistanceTex->bind(4);
m_postProcessFbo.get().first->bind(6);
++m_postProcessFbo;
m_postProcessFbo.get().second->bind();
// render SFQ
glDrawArrays(GL_TRIANGLES, 0, 3);
}
}
m_postProcessFbo.get().second->unbind();
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
// blit framebuffer to screen
m_postProcessFbo.get().second->blit();
m_gBufferFbo->blitDepth();
}
void Renderer::addLightAt(std::shared_ptr<Light> light, uint32_t lightIndex)
{
m_lights[lightIndex] = light;
if (light->shadowType() == ShadowType::SHADOWMAP_SHADOW)
{
if (!m_generatedShaderSource.empty())
std::static_pointer_cast<ShadowMapLight>(light)->setGeneratedFragmentSource(
m_generatedShaderSource);
int smCount = 0;
for (auto& l : m_lights)
{
if (l.second->shadowType() == ShadowType::SHADOWMAP_SHADOW)
{
smCount++;
}
}
// const auto sm = std::get<std::shared_ptr<ShadowMapLight>>(light);
std::static_pointer_cast<ShadowMapLight>(light)->setShadowMapIndex(smCount - 1);
}
m_lights[lightIndex] = light;
if(light->shadowType() == ShadowType::SHADOWMAP_SHADOW)
{
if(!m_generatedShaderSource.empty())
std::static_pointer_cast<ShadowMapLight>(light)->setGeneratedFragmentSource(
m_generatedShaderSource);
int smCount = 0;
for(auto& l : m_lights)
{
if(l.second->shadowType() == ShadowType::SHADOWMAP_SHADOW)
{
smCount++;
}
}
// const auto sm = std::get<std::shared_ptr<ShadowMapLight>>(light);
std::static_pointer_cast<ShadowMapLight>(light)->setShadowMapIndex(smCount - 1);
}
}
uint32_t Renderer::addLight(std::shared_ptr<Light> light)
{
const auto max_id_iter =
std::max_element(m_lights.begin(),
m_lights.end(),
[](const std::pair<uint32_t, std::shared_ptr<Light>>& item1,
const std::pair<uint32_t, std::shared_ptr<Light>>& item2) {
return item1.first < item2.first;
});
const uint32_t id = max_id_iter == m_lights.end() ? 0 : max_id_iter->first + 1;
addLightAt(std::move(light), id);
return id;
const auto max_id_iter =
std::max_element(m_lights.begin(),
m_lights.end(),
[](const std::pair<uint32_t, std::shared_ptr<Light>>& item1,
const std::pair<uint32_t, std::shared_ptr<Light>>& item2) {
return item1.first < item2.first;
});
const uint32_t id = max_id_iter == m_lights.end() ? 0 : max_id_iter->first + 1;
if(light->shadowType() == ShadowType::SHADOWMAP_SHADOW) // is TracedLight or ShadowMapLight
{
std::static_pointer_cast<ShadowMapLight>(light)->setSsShadowTextureSize(
m_gBufferFbo->getDepthAttachment()->size());
}
else if(light->shadowType() == ShadowType::TRACED_SHADOW)
{
std::static_pointer_cast<TracedLight>(light)->setSsShadowTextureSize(
m_gBufferFbo->getDepthAttachment()->size());
}
addLightAt(std::move(light), id);
return id;
}
const std::unordered_map<uint32_t, std::shared_ptr<Light>>& Renderer::getLights() const { return m_lights; }
const std::unordered_map<uint32_t, std::shared_ptr<Light>>& Renderer::getLights() const
{
return m_lights;
}
void Renderer::removeLight(int lightIndex)
{
......@@ -340,32 +506,42 @@ void Renderer::convertLight(int lightIndex, ShadowType toType)
if(toType == ShadowType::TRACED_SHADOW)
{
auto sm = std::static_pointer_cast<Light>(light);
addLightAt(std::make_shared<dino::TracedLight>(sm->type(),
sm->position(),
sm->color(),
sm->intensity(),
sm->direction(),
sm->cutoff()), lightIndex);
addLightAt(std::make_shared<dino::TracedLight>(sm->type(),
sm->position(),
sm->color(),
sm->intensity(),
sm->direction(),
sm->cutoff()),
lightIndex);
}
else if(toType == ShadowType::SHADOWMAP_SHADOW)
{
auto tl = std::static_pointer_cast<Light>(light);
addLightAt(std::make_shared<dino::ShadowMapLight>(tl->type(),
tl->position(),
tl->color(),
tl->intensity(),
tl->direction(),
tl->cutoff()), lightIndex);
addLightAt(std::make_shared<dino::ShadowMapLight>(tl->type(),
tl->position(),
tl->color(),
tl->intensity(),
tl->direction(),
tl->cutoff()),
lightIndex);
}
else if(toType == ShadowType::NO_SHADOW)
{
auto l = std::static_pointer_cast<Light>(light);
addLightAt(std::make_shared<dino::Light>(
l->type(), l->position(), l->color(), l->intensity(), l->direction(), l->cutoff()), lightIndex);
addLightAt(std::make_shared<dino::Light>(l->type(),
l->position(),
l->color(),
l->intensity(),
l->direction(),
l->cutoff()),
lightIndex);
}
}
const std::unordered_map<uint32_t, std::shared_ptr<Material>>& Renderer::getMaterials() const { return m_materials; }
const std::unordered_map<uint32_t, std::shared_ptr<Material>>& Renderer::getMaterials() const
{
return m_materials;
}
int Renderer::fieldCount() const { return m_distanceFields.size(); }
......@@ -404,4 +580,81 @@ std::unordered_map<uint32_t, std::shared_ptr<Function>> Renderer::packFunctions(
result.emplace(item.first, item.second->target());
return result;
}
int Renderer::getPixelObjectID(glm::ivec2 pixelPosition) const
{
m_gBufferFbo->bind();
glReadBuffer(GL_COLOR_ATTACHMENT2);
float id = 0;
glReadPixels(pixelPosition.x, pixelPosition.y, 1, 1, GL_RED, GL_FLOAT, &id);
glReadBuffer(GL_COLOR_ATTACHMENT0);
m_gBufferFbo->unbind();
GLint currentId;
glGetUniformiv(m_deferredPrograms[m_deferredPrograms.size() - 1].id(),
m_activeDfIdUniform,
&currentId);
if(currentId == static_cast<int>(id))
{
id = -1.0f;
}
setActivePixelObjectId(static_cast<int>(id));
return static_cast<int>(id);
}
void Renderer::setActivePixelObjectId(int id) const
{
if(m_activeDfIdUniform != GL_INVALID_INDEX)
glProgramUniform1i(
m_deferredPrograms[m_deferredPrograms.size() - 1].id(), m_activeDfIdUniform, id);
}
void Renderer::setFramebufferSize(glm::ivec2 size)
{
m_gBufferFbo->resize(size);
m_postProcessFbo[0].second->resize(size);
m_postProcessFbo[1].second->resize(size);
for(auto& l : m_lights)
{
if(l.second->shadowType() == ShadowType::SHADOWMAP_SHADOW ||
l.second->shadowType() == ShadowType::TRACED_SHADOW)
{
std::static_pointer_cast<TracedLight>(l.second)->setSsShadowTextureSize(size);
}
}
}
void Renderer::addRenderLayer(RenderLayer::Type type)
{
m_renderLayers.insert(m_renderLayers.begin() + m_renderLayers.size() - 1,
std::make_shared<RenderLayer>(type));
m_deferredPrograms.insert(m_deferredPrograms.begin() + m_deferredPrograms.size() - 1,
Program());
m_deferredPrograms[m_deferredPrograms.size() - 2].attachNew(
GL_VERTEX_SHADER, dino::ShaderFile::load("screenFilling.vert"));
m_invalidRenderables = true;
}
void Renderer::removeRenderLayer(int layerIndex)
{
if(m_renderLayers[layerIndex]->getType() == RenderLayer::SILHOUETTE)
return;
m_renderLayers.erase(m_renderLayers.begin() + layerIndex);
m_deferredPrograms.erase(m_deferredPrograms.begin() + layerIndex);
}
void Renderer::swapLayers(int firstIndex, int secondIndex)
{
std::swap(m_renderLayers[firstIndex], m_renderLayers[secondIndex]);
std::swap(m_deferredPrograms[firstIndex], m_deferredPrograms[secondIndex]);
}
std::vector<std::shared_ptr<RenderLayer>> Renderer::getRenderLayers() const
{
return m_renderLayers;
}
} // namespace dino
......@@ -8,10 +8,14 @@
#include "../opengl/Shader.h"
#include "../opengl/Texture.h"
#include "../opengl/VertexArray.h"
#include "dino\rendering\SkyBox.h"
#include "dino/opengl/FrameBuffer.h"
#include "SkyBox.h"
#include "RenderLayer.h"
#include "RingBuffer.h"
#include "Light.h"
#include "Material.h"
#include <cinttypes>
#include <glm/glm.hpp>
......@@ -87,6 +91,23 @@ public:
constexpr static int SM_STORAGE_BINDING = 4;
constexpr static int CAMERA_UNIFORM_BINDING = 0;
/**
* @brief Creates a Renderer object for deferred rendering
* @param windowSize The size used for the framebuffer
* @param renderLayers The RenderLayers that are executed (i.e. rendered) in order
*/
Renderer(std::vector<std::shared_ptr<RenderLayer>> renderLayers,
glm::ivec2 windowSize = glm::ivec2(1280, 720));
/**
* @brief Creates a Renderer object for deferred rendering
* @param windowSize The size used for the framebuffer
* @param renderLayers The types of the RenderLayers that are
* created and executed (i.e. rendered) in order
*/
Renderer(std::vector<RenderLayer::Type> renderLayers,
glm::ivec2 windowSize = glm::ivec2(1280, 720));
/**
* @brief Creates a renderer. Creates a dataBuffer and a rendering shader program.
* @param onTrace A ShaderSource providing a shader for the rendering.
......@@ -148,18 +169,22 @@ public:
* Uses instanced rendering and uses the instanceID to identify separate distance fields.
* They are rendered in the order they are added.
* If shadow maps are added to the renderer, they are also rendered.
* Renders all previously added distance fields into a g-buffer
* and then renders a screen filling quad to apply effects like lighting.
* Post-process effects are applied via render layers.
* Only activated render layers are applied.
* @param view A view matrix as mat4 reference.
* @param projection A projection matrix as mat4 reference.
* @details Creates a Cube to render a distance field into.
*/
virtual void render(const glm::mat4& view, const glm::mat4& projection);
void render(const glm::mat4& view, const glm::mat4& projection);