Browse Source

Everywhere: Work towards lighting support

master
Riyyi 3 months ago
parent
commit
d16fade497
  1. 11
      assets/glsl/batch-3d.frag
  2. 3
      assets/glsl/batch-3d.vert
  3. 4
      assets/glsl/batch-cubemap.vert
  4. 14
      assets/glsl/lightsource.frag
  5. 24
      assets/glsl/lightsource.vert
  6. 78
      assets/glsl/post-process.frag
  7. 25
      assets/glsl/post-process.vert
  8. 58
      src/inferno/application.cpp
  9. 2
      src/inferno/application.h
  10. 3
      src/inferno/component/cubemap-component.cpp
  11. 1
      src/inferno/component/cubemap-component.h
  12. 1
      src/inferno/render/buffer.h
  13. 47
      src/inferno/render/framebuffer.cpp
  14. 12
      src/inferno/render/framebuffer.h
  15. 22
      src/inferno/render/render-command.cpp
  16. 2
      src/inferno/render/render-command.h
  17. 69
      src/inferno/render/renderer.cpp
  18. 64
      src/inferno/render/renderer.h
  19. 18
      src/inferno/render/uniformbuffer.h
  20. 13
      src/inferno/scene/scene.cpp
  21. 13
      src/inferno/system/camerasystem.cpp
  22. 1
      src/inferno/system/camerasystem.h
  23. 177
      src/inferno/system/rendersystem.cpp
  24. 20
      src/inferno/system/rendersystem.h

11
assets/glsl/batch-3d.frag

@ -1,7 +1,10 @@
#version 450 core
layout(location = 0) out vec4 color;
layout(location = 0) out vec4 albedoSpec; // RGB diffuse color
layout(location = 1) out vec4 position;
layout(location = 2) out vec4 normal;
in vec3 v_position;
in vec3 v_normal;
in vec4 v_color;
in vec2 v_textureCoordinates;
@ -46,5 +49,9 @@ void main()
case 30: textureColor *= texture(u_textures[30], v_textureCoordinates); break;
case 31: textureColor *= texture(u_textures[31], v_textureCoordinates); break;
}
color = textureColor;
albedoSpec.rgb = textureColor.rgb;
albedoSpec.a = 1.0; // TODO: read specular from model material
position = vec4(v_position, 1.0f);
normal = vec4(normalize(v_normal), 1.0f);
}

3
assets/glsl/batch-3d.vert

@ -6,6 +6,7 @@ layout(location = 2) in vec4 a_color;
layout(location = 3) in vec2 a_textureCoordinates;
layout(location = 4) in uint a_textureIndex;
out vec3 v_position;
out vec3 v_normal;
out vec4 v_color;
out vec2 v_textureCoordinates;
@ -14,10 +15,12 @@ out flat uint v_textureIndex;
layout(std140, binding = 0) uniform Camera
{
mat4 u_projectionView;
vec3 u_position;
};
void main()
{
v_position = a_position;
v_normal = a_normal;
v_color = a_color;
v_textureCoordinates = a_textureCoordinates;

4
assets/glsl/batch-cubemap.vert

@ -8,7 +8,7 @@ out vec4 v_color;
out vec3 v_textureCoordinates;
out flat uint v_textureIndex;
uniform mat4 u_projectionView;
uniform mat4 u_projectionView2;
void main()
{
@ -16,5 +16,5 @@ void main()
v_textureCoordinates = a_position;
v_textureIndex = a_textureIndex;
// Vclip = Camera projection * Camera view * Model transform * Vlocal
gl_Position = u_projectionView * vec4(a_position, 1.0f);
gl_Position = u_projectionView2 * vec4(a_position, 1.0f);
}

14
assets/glsl/lightsource.frag

@ -0,0 +1,14 @@
#version 450 core
layout(location = 0) out vec4 color;
in vec4 v_color;
in vec3 v_textureCoordinates;
in flat uint v_textureIndex;
uniform samplerCube u_textures[32];
void main()
{
color = v_color;
}

24
assets/glsl/lightsource.vert

@ -0,0 +1,24 @@
#version 450 core
layout(location = 0) in vec3 a_position;
layout(location = 1) in vec4 a_color;
layout(location = 2) in uint a_textureIndex;
out vec4 v_color;
out vec3 v_textureCoordinates;
out flat uint v_textureIndex;
layout(std140, binding = 0) uniform Camera
{
mat4 u_projectionView;
vec3 u_position;
};
void main()
{
v_color = a_color;
v_textureCoordinates = a_position;
v_textureIndex = a_textureIndex;
// Vclip = Camera projection * Camera view * Model transform * Vlocal
gl_Position = u_projectionView * vec4(a_position, 1.0f);
}

78
assets/glsl/post-process.frag

@ -0,0 +1,78 @@
#version 450 core
layout(location = 0) out vec4 color;
in vec4 v_color;
in vec2 v_textureCoordinates;
in flat uint v_textureIndex;
uniform sampler2D u_textures[32];
// -----------------------------------------
layout(std140, binding = 0) uniform Camera {
mat4 u_projectionView;
vec3 u_position;
};
// -----------------------------------------
struct DirectionalLight {
vec3 direction;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
const int MAX_DIRECTIONAL_LIGHTS = 32;
layout(std140, binding = 1) uniform DirectionalLights {
DirectionalLight u_directionalLight[MAX_DIRECTIONAL_LIGHTS];
};
// -----------------------------------------
void main()
{
float isObject = texture(u_textures[v_textureIndex + 1], v_textureCoordinates).a;
if (isObject == 0.0f) {
color = vec4(0,0,0,0);
return;
}
vec3 albedo = texture(u_textures[v_textureIndex + 0], v_textureCoordinates).rgb;
float specular = texture(u_textures[v_textureIndex + 0], v_textureCoordinates).a;
vec3 position = texture(u_textures[v_textureIndex + 1], v_textureCoordinates).rgb;
vec3 normal = texture(u_textures[v_textureIndex + 2], v_textureCoordinates).rgb;
vec3 lighting = vec3(0.0f, 0.0f, 0.0f);//albedo * v_color.xyz;
vec3 viewDirection = normalize(u_position - position);
// Loop through all directional lights
for (int i = 0; i < MAX_DIRECTIONAL_LIGHTS; ++i) {
// Diffuse
vec3 lightDirection = normalize(-u_directionalLight[i].direction);
float diffuse = max(dot(normal, lightDirection), 0.0f);
// Specular
vec3 reflectionDirection = reflect(-lightDirection, normal);
float specular = pow(max(dot(viewDirection, reflectionDirection), 0.0f), 32);
lighting +=
(albedo * u_directionalLight[i].ambient) +
(albedo * diffuse * u_directionalLight[i].diffuse) +
(specular * u_directionalLight[i].specular);
}
// Loop through all point lights
// TODO
// vec3 lightDirection = normalize(lightPosition - position);
// float diffuse = max(dot(normal, lightDirection), 0.0f);
// lighting += diffuse * albedo * u_lightColor;
// Loop through all spot lights
// TODO
color = vec4(lighting, 1.0f);
}

25
assets/glsl/post-process.vert

@ -0,0 +1,25 @@
#version 450 core
layout(location = 0) in vec3 a_position;
layout(location = 1) in vec4 a_color;
layout(location = 2) in vec2 a_textureCoordinates;
layout(location = 3) in uint a_textureIndex;
out vec4 v_color;
out vec2 v_textureCoordinates;
out flat uint v_textureIndex;
layout(std140, binding = 0) uniform Camera
{
mat4 u_projectionView;
vec3 u_position;
};
void main()
{
v_color = a_color;
v_textureCoordinates = a_textureCoordinates;
v_textureIndex = a_textureIndex;
// Vclip = Model transform * Vlocal
gl_Position = vec4(a_position, 1.0f);
}

58
src/inferno/application.cpp

@ -24,6 +24,7 @@
#include "inferno/render/context.h"
#include "inferno/render/framebuffer.h"
#include "inferno/render/uniformbuffer.h"
#include "inferno/system/rendersystem.h"
// #include "inferno/render/gltf.h"
#include "inferno/asset/shader.h"
#include "inferno/asset/texture.h"
@ -53,27 +54,7 @@ Application::Application()
Input::initialize();
RenderCommand::initialize();
m_framebuffer = Framebuffer::create({
.attachments = { Framebuffer::Type::Color, Framebuffer::Type::Depth },
.width = m_window->getWidth(),
.height = m_window->getHeight(),
.clearColor = { 0.2f, 0.3f, 0.3f, 1.0f },
.clearBit = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT,
});
m_screenFramebuffer = Framebuffer::create({
.renderToScreen = true,
.clearColor = { 1.0f, 1.0f, 1.0f, 1.0f },
.clearBit = GL_COLOR_BUFFER_BIT,
});
Uniformbuffer::the().setLayout(
"Camera", 0,
{
{ BufferElementType::Mat4, "u_projectionView" },
});
Uniformbuffer::the().create("Camera");
RenderSystem::the().initialize(m_window->getWidth(), m_window->getHeight());
m_scene = std::make_shared<Scene>();
m_scene->initialize();
@ -104,6 +85,8 @@ Application::~Application()
Renderer2D::destroy();
Renderer3D::destroy();
RendererCubemap::destroy();
RendererPostProcess::destroy();
RendererLightCube::destroy();
RenderCommand::destroy();
AssetManager::destroy();
// Input::destroy();
@ -167,10 +150,6 @@ int Application::run()
// offset
#endif
constexpr glm::vec4 vectorOne { 1.0f, 1.0f, 1.0f, 1.0f };
constexpr glm::mat4 matIdentity { 1.0f };
constexpr TransformComponent transformIdentity;
double gametime = 0;
uint64_t frames = 0;
@ -196,33 +175,7 @@ int Application::run()
// ---------------------------------
// Render
m_framebuffer->bind();
RenderCommand::clearColor(m_framebuffer->clearColor());
RenderCommand::clearBit(m_framebuffer->clearBit());
render();
m_scene->render();
// RendererCharacter::the().drawCharacter(character, f->texture());
m_framebuffer->unbind();
// ---------------------------------
// Framebuffer
m_screenFramebuffer->bind();
RenderCommand::clearColor(m_screenFramebuffer->clearColor());
RenderCommand::clearBit(m_screenFramebuffer->clearBit());
Renderer2D::the().setEnableDepthBuffer(false);
Uniformbuffer::the().setValue("Camera", "u_projectionView", matIdentity);
Renderer2D::the().drawQuad(transformIdentity, vectorOne, m_framebuffer->texture(0));
Renderer2D::the().endScene();
Renderer2D::the().setEnableDepthBuffer(true);
m_screenFramebuffer->unbind();
m_window->render();
}
@ -259,8 +212,7 @@ bool Application::onWindowResize(WindowResizeEvent& e)
{
ruc::info("WindowResizeEvent {}x{}", e.getWidth(), e.getHeight());
RenderCommand::setViewport(0, 0, e.getWidth(), e.getHeight());
m_framebuffer->resize(e.getWidth(), e.getHeight());
RenderSystem::the().resize(e.getWidth(), e.getHeight());
return true;
}

2
src/inferno/application.h

@ -51,8 +51,6 @@ private:
float m_lastFrameTime { 0.0f };
std::unique_ptr<Window> m_window;
std::shared_ptr<Framebuffer> m_framebuffer;
std::shared_ptr<Framebuffer> m_screenFramebuffer;
std::shared_ptr<Scene> m_scene;
//

3
src/inferno/component/cubemap-component.cpp

@ -22,6 +22,9 @@ void fromJson(const ruc::Json& json, CubemapComponent& value)
if (json.exists("texture") && json.at("texture").type() == ruc::Json::Type::String) {
value.texture = AssetManager::the().load<TextureCubemap>(json.at("texture").asString());
}
if (json.exists("isLight")) {
json.at("isLight").getTo(value.isLight);
}
}
} // namespace Inferno

1
src/inferno/component/cubemap-component.h

@ -18,6 +18,7 @@ namespace Inferno {
struct CubemapComponent {
glm::vec4 color { 1.0f };
std::shared_ptr<Texture> texture;
bool isLight { false };
};
void fromJson(const ruc::Json& json, CubemapComponent& value);

1
src/inferno/render/buffer.h

@ -10,7 +10,6 @@
#include <cstdint> // int32_t, uint8_t, uint32_t
#include <memory> // std::shared_ptr
#include <string>
#include <utility> // std::pair
#include <vector>
namespace Inferno {

47
src/inferno/render/framebuffer.cpp

@ -36,6 +36,14 @@ Framebuffer::~Framebuffer()
glDeleteFramebuffers(1, &m_id);
}
void Framebuffer::copyBuffer(std::shared_ptr<Framebuffer> from, std::shared_ptr<Framebuffer> to, uint32_t bits, uint32_t filter)
{
glBindFramebuffer(GL_READ_FRAMEBUFFER, from->m_id);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); // write to default framebuffer
glBlitFramebuffer(0, 0, from->m_width, from->m_height, 0, 0, to->m_width, to->m_height, bits, filter);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
// -----------------------------------------
void Framebuffer::bind() const
@ -86,22 +94,47 @@ void Framebuffer::createTextures()
bind();
auto it = m_attachments.begin();
uint8_t color_attachment = 0;
m_colorAttachmentCount = 0;
size_t size = m_attachments.size();
m_textures.resize(size);
for (size_t i = 0; i < size; ++i) {
TypeProperties type = *(it + i);
if (type.type == Type::Color) {
if (type.type == Type::RGB8) {
// Set color attachment 0 out of 32
m_textures[i] = (TextureFramebuffer::create(
"", m_width, m_height, GL_RGB, GL_RGB));
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + color_attachment, GL_TEXTURE_2D, m_textures[i]->id(), 0);
m_textures[i] = TextureFramebuffer::create("", m_width, m_height, GL_RGB8, GL_RGB);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + m_colorAttachmentCount, GL_TEXTURE_2D, m_textures[i]->id(), 0);
m_colorAttachmentCount++;
continue;
}
if (type.type == Type::RGBA8) { // Color
// Set color attachment 0 out of 32
m_textures[i] = TextureFramebuffer::create("", m_width, m_height, GL_RGBA8, GL_RGBA);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + m_colorAttachmentCount, GL_TEXTURE_2D, m_textures[i]->id(), 0);
m_colorAttachmentCount++;
continue;
}
if (type.type == Type::RGBA16F) {
// Set color attachment 0 out of 32
m_textures[i] = TextureFramebuffer::create("", m_width, m_height, GL_RGBA16F, GL_RGBA, GL_FLOAT);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + m_colorAttachmentCount, GL_TEXTURE_2D, m_textures[i]->id(), 0);
m_colorAttachmentCount++;
continue;
}
if (type.type == Type::RGBA32F) {
// Set color attachment 0 out of 32
m_textures[i] = TextureFramebuffer::create("", m_width, m_height, GL_RGBA32F, GL_RGBA, GL_FLOAT);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + m_colorAttachmentCount, GL_TEXTURE_2D, m_textures[i]->id(), 0);
m_colorAttachmentCount++;
continue;
}
// This combined texture is required for older GPUs
if (type.type == Type::Depth24Stencil8) {
if (type.type == Type::Depth24Stencil8) { // Depth
m_textures[i] = (TextureFramebuffer::create(
"", m_width, m_height, GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8));
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, m_textures[i]->id(), 0);
@ -117,7 +150,7 @@ void Framebuffer::createTextures()
}
}
VERIFY(color_attachment <= 32, "maximum color attachments was exceeded: {}/32", color_attachment);
VERIFY(m_colorAttachmentCount <= 32, "maximum color attachments was exceeded: {}/32", m_colorAttachmentCount);
check();
unbind();

12
src/inferno/render/framebuffer.h

@ -24,11 +24,14 @@ public:
None = 0,
// Color
RGBA8 = 1,
RGB8 = 1,
RGBA8 = 2,
RGBA16F = 3,
RGBA32F = 4,
// Depth/stencil
Depth32F = 2,
Depth24Stencil8 = 3,
Depth24Stencil8 = 5,
Depth32F = 6,
// Defaults
Color = RGBA8,
@ -59,12 +62,14 @@ public:
// Factory function
static std::shared_ptr<Framebuffer> create(const Properties& properties);
static void copyBuffer(std::shared_ptr<Framebuffer> from, std::shared_ptr<Framebuffer> to, uint32_t bits, uint32_t filter);
void bind() const;
void unbind() const;
bool check() const;
void resize(uint32_t width, uint32_t height);
uint8_t colorAttachmentCount() const { return m_colorAttachmentCount; }
uint32_t id() const { return m_id; }
uint32_t width() const { return m_width; }
uint32_t height() const { return m_height; }
@ -87,6 +92,7 @@ private:
private:
bool m_renderToScreen { false };
uint8_t m_colorAttachmentCount { 1 };
uint32_t m_id { 0 };
uint32_t m_width { 0 };
uint32_t m_height { 0 };

22
src/inferno/render/render-command.cpp

@ -4,10 +4,12 @@
* SPDX-License-Identifier: MIT
*/
#include <cstdint> // int32_t, uint32_t
#include <memory> // std::shared_ptr
#include "glad/glad.h"
#include "ruc/format/log.h"
#include "ruc/meta/assert.h"
#include "inferno/render/buffer.h"
#include "inferno/render/render-command.h"
@ -57,6 +59,26 @@ void RenderCommand::setDepthTest(bool enabled)
enabled ? glEnable(GL_DEPTH_TEST) : glDisable(GL_DEPTH_TEST);
}
void RenderCommand::setColorAttachmentCount(uint32_t count)
{
static constexpr uint32_t colorAttachments[] = {
GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2,
GL_COLOR_ATTACHMENT3, GL_COLOR_ATTACHMENT4, GL_COLOR_ATTACHMENT5,
GL_COLOR_ATTACHMENT6, GL_COLOR_ATTACHMENT7, GL_COLOR_ATTACHMENT8,
GL_COLOR_ATTACHMENT9, GL_COLOR_ATTACHMENT10, GL_COLOR_ATTACHMENT11,
GL_COLOR_ATTACHMENT12, GL_COLOR_ATTACHMENT13, GL_COLOR_ATTACHMENT14,
GL_COLOR_ATTACHMENT15, GL_COLOR_ATTACHMENT16, GL_COLOR_ATTACHMENT17,
GL_COLOR_ATTACHMENT18, GL_COLOR_ATTACHMENT19, GL_COLOR_ATTACHMENT20,
GL_COLOR_ATTACHMENT21, GL_COLOR_ATTACHMENT22, GL_COLOR_ATTACHMENT23,
GL_COLOR_ATTACHMENT24, GL_COLOR_ATTACHMENT25, GL_COLOR_ATTACHMENT26,
GL_COLOR_ATTACHMENT27, GL_COLOR_ATTACHMENT28, GL_COLOR_ATTACHMENT29,
GL_COLOR_ATTACHMENT30, GL_COLOR_ATTACHMENT31
};
static constexpr uint32_t maxCount = sizeof(colorAttachments) / sizeof(colorAttachments[0]);
VERIFY(count > 0 && count <= maxCount, "incorrect colorbuffer count: {}/{}", count, maxCount);
glDrawBuffers(static_cast<int32_t>(count), colorAttachments); // Multiple Render Targets (MRT)
}
bool RenderCommand::depthTest()
{
unsigned char depthTest = GL_FALSE;

2
src/inferno/render/render-command.h

@ -6,6 +6,7 @@
#pragma once
#include <cstdint> // int32_t, uint32_t
#include <memory> // std::shadred_ptr
#include "glm/ext/vector_float4.hpp" // glm::vec4
@ -25,6 +26,7 @@ public:
static void setViewport(int32_t x, int32_t y, uint32_t width, uint32_t height);
static void setDepthTest(bool enabled);
static void setColorAttachmentCount(uint32_t count);
static bool depthTest();
static int32_t textureUnitAmount();

69
src/inferno/render/renderer.cpp

@ -171,6 +171,7 @@ void Renderer<T>::flush()
// Render
bool depthTest = RenderCommand::depthTest();
RenderCommand::setDepthTest(m_enableDepthBuffer);
RenderCommand::setColorAttachmentCount(m_colorAttachmentCount);
RenderCommand::drawIndexed(m_vertexArray, m_elementIndex);
RenderCommand::setDepthTest(depthTest);
@ -197,6 +198,11 @@ void Renderer<T>::nextBatch()
// -----------------------------------------
Renderer2D::Renderer2D(s)
{
Renderer2D::initialize();
}
void Renderer2D::initialize()
{
Renderer::initialize();
@ -216,6 +222,8 @@ Renderer2D::Renderer2D(s)
// ---------------------------------
// GPU
m_enableDepthBuffer = false;
// Create vertex buffer
auto vertexBuffer = std::make_shared<VertexBuffer>(sizeof(QuadVertex) * maxVertices);
vertexBuffer->setLayout({
@ -275,12 +283,17 @@ void Renderer2D::drawQuad(const TransformComponent& transform, glm::mat4 color,
void Renderer2D::loadShader()
{
m_shader = AssetManager::the().load<Shader>("assets/glsl/batch-2d");
m_shader = AssetManager::the().load<Shader>("assets/glsl/post-process");
}
// -----------------------------------------
RendererCubemap::RendererCubemap(s)
{
RendererCubemap::initialize();
}
void RendererCubemap::initialize()
{
Renderer::initialize();
@ -354,10 +367,10 @@ void RendererCubemap::beginScene(glm::mat4 cameraProjection, glm::mat4 cameraVie
// x x x 0
// x x x 0
// 0 0 0 1
cameraView = glm::mat4(glm::mat3(cameraView));
// cameraView = glm::mat4(glm::mat3(cameraView));
m_shader->bind();
m_shader->setFloat("u_projectionView", cameraProjection * cameraView);
m_shader->setFloat("u_projectionView2", cameraProjection * cameraView);
m_shader->unbind();
}
@ -482,6 +495,7 @@ Renderer3D::Renderer3D(s)
// GPU
m_enableDepthBuffer = true;
m_colorAttachmentCount = 3;
// Create vertex buffer
auto vertexBuffer = std::make_shared<VertexBuffer>(sizeof(Vertex) * maxVertices);
@ -501,8 +515,8 @@ void Renderer3D::drawModel(std::span<const Vertex> vertices, std::span<const uin
{
// ruc::error("drawModel");
VERIFY(vertices.size() <= maxVertices, "model vertices too big for buffer");
VERIFY(elements.size() <= maxElements, "model elements too big for buffer");
VERIFY(vertices.size() <= maxVertices, "model vertices too big for buffer, {}/{}", vertices.size(), maxVertices);
VERIFY(elements.size() <= maxElements, "model elements too big for buffer, {}/{}", elements.size(), maxElements);
// Create a new batch if the quad limit has been reached
if (m_vertexIndex + vertices.size() > maxVertices || m_elementIndex + elements.size() > maxElements) {
@ -512,9 +526,10 @@ void Renderer3D::drawModel(std::span<const Vertex> vertices, std::span<const uin
uint32_t textureUnitIndex = addTextureUnit(texture);
// Add the vertices
glm::mat3 normalMatrix = glm::mat3(glm::transpose(glm::inverse(transform.transform)));
for (const auto& vertex : vertices) {
m_vertexBufferPtr->position = transform.transform * glm::vec4(vertex.position, 1.0f);
m_vertexBufferPtr->normal = vertex.normal;
m_vertexBufferPtr->normal = normalMatrix * vertex.normal; // take non-uniform scaling into consideration
m_vertexBufferPtr->color = color;
m_vertexBufferPtr->textureCoordinates = vertex.textureCoordinates;
m_vertexBufferPtr->textureIndex = textureUnitIndex;
@ -565,4 +580,46 @@ void Renderer3D::startBatch()
m_elementBufferPtr = m_elementBufferBase;
}
// -----------------------------------------
void RendererPostProcess::drawQuad(const TransformComponent& transform, std::shared_ptr<Texture> albedo, std::shared_ptr<Texture> position, std::shared_ptr<Texture> normal)
{
nextBatch();
constexpr glm::vec2 textureCoordinates[] = {
{ 0.0f, 0.0f },
{ 1.0f, 0.0f },
{ 1.0f, 1.0f },
{ 0.0f, 1.0f }
};
uint32_t textureUnitIndex = addTextureUnit(albedo);
addTextureUnit(position);
addTextureUnit(normal);
// Add the quads 4 vertices
for (uint32_t i = 0; i < vertexPerQuad; i++) {
m_vertexBufferPtr->position = transform.transform * m_vertexPositions[i];
m_vertexBufferPtr->textureCoordinates = textureCoordinates[i];
m_vertexBufferPtr->textureIndex = textureUnitIndex;
m_vertexBufferPtr++;
}
m_vertexIndex += vertexPerQuad;
m_elementIndex += elementPerQuad;
}
void RendererPostProcess::loadShader()
{
ruc::error("POSTPROCESSING!");
m_shader = AssetManager::the().load<Shader>("assets/glsl/post-process");
}
// -----------------------------------------
void RendererLightCube::loadShader()
{
m_shader = AssetManager::the().load<Shader>("assets/glsl/lightsource");
}
} // namespace Inferno

64
src/inferno/render/renderer.h

@ -112,6 +112,7 @@ protected:
// GPU objects
bool m_enableDepthBuffer { true };
uint32_t m_colorAttachmentCount { 1 };
std::shared_ptr<Shader> m_shader;
std::shared_ptr<VertexArray> m_vertexArray;
};
@ -124,7 +125,7 @@ protected:
// -------------------------------------
class Renderer2D final
class Renderer2D
: public Renderer<QuadVertex>
, public ruc::Singleton<Renderer2D> {
public:
@ -138,15 +139,20 @@ public:
void drawQuad(const TransformComponent& transform, glm::vec4 color, std::shared_ptr<Texture> texture);
void drawQuad(const TransformComponent& transform, glm::mat4 color, std::shared_ptr<Texture> texture);
private:
void loadShader() override;
protected:
Renderer2D() { Renderer2D::initialize(); } // Needed for derived classes
void initialize();
// Default quad vertex positions
glm::vec4 m_vertexPositions[vertexPerQuad];
private:
virtual void loadShader() override;
};
// -------------------------------------
class RendererCubemap final
class RendererCubemap
: public Renderer<CubemapVertex>
, public ruc::Singleton<RendererCubemap> {
public:
@ -163,8 +169,13 @@ public:
void drawCubemap(const TransformComponent& transform, glm::vec4 color, std::shared_ptr<Texture> texture);
void drawCubemap(const TransformComponent& transform, glm::mat4 color, std::shared_ptr<Texture> texture);
protected:
RendererCubemap() { RendererCubemap::initialize(); } // Needed for derived classes
void initialize();
private:
void loadShader() override;
virtual void loadShader() override;
// Default cubemap vertex positions
glm::vec4 m_vertexPositions[vertexPerQuad * quadPerCube];
@ -212,4 +223,47 @@ private:
uint32_t* m_elementBufferPtr { nullptr };
};
// -----------------------------------------
class RendererPostProcess final
: public Renderer2D
, public ruc::Singleton<RendererPostProcess> {
public:
RendererPostProcess(ruc::Singleton<RendererPostProcess>::s)
: Renderer2D()
{
}
virtual ~RendererPostProcess() = default;
using Singleton<RendererPostProcess>::the;
using Singleton<RendererPostProcess>::destroy;
void drawQuad(const TransformComponent& transform, std::shared_ptr<Texture> albedo, std::shared_ptr<Texture> position, std::shared_ptr<Texture> normal);
private:
virtual void loadShader() override;
};
// -----------------------------------------
class RendererLightCube final
: public RendererCubemap
, public ruc::Singleton<RendererLightCube> {
public:
RendererLightCube(ruc::Singleton<RendererLightCube>::s)
: RendererCubemap()
{
m_enableDepthBuffer = true;
}
virtual ~RendererLightCube() = default;
using Singleton<RendererLightCube>::the;
using Singleton<RendererLightCube>::destroy;
void beginScene(glm::mat4, glm::mat4) override {}
private:
virtual void loadShader() override;
};
} // namespace Inferno

18
src/inferno/render/uniformbuffer.h

@ -13,6 +13,7 @@
#include "glad/glad.h"
#include "glm/ext/matrix_float2x2.hpp" // glm::mat2
#include "glm/ext/matrix_float3x3.hpp" // glm::mat3
#include "glm/ext/vector_float3.hpp" // glm::vec3
#include "ruc/singleton.h"
#include "inferno/render/buffer.h"
@ -25,6 +26,23 @@
namespace Inferno {
// Uniform block layouts, using std140 memory layout rules
#define MAX_DIRECTIONAL_LIGHTS 32
struct UniformDirectionalLight {
glm::vec3 direction { 0 };
float __padding0 { 0 };
glm::vec3 ambient { 0 };
float __padding1 { 0 };
glm::vec3 diffuse { 0 };
float __padding2 { 0 };
glm::vec3 specular { 0 };
float __padding3 { 0 };
};
// -----------------------------------------
struct UniformbufferBlock {
uint32_t id { 0 };
uint32_t size { 0 };

13
src/inferno/scene/scene.cpp

@ -9,7 +9,7 @@
#include <limits> // std::numeric_limits
#include <utility> // std::pair
#include "entt/entity/entity.hpp" // ent::entity
#include "entt/entity/fwd.hpp" // ent::entity
#include "ruc/file.h"
#include "ruc/format/log.h"
#include "ruc/json/json.h"
@ -25,6 +25,7 @@
#include "inferno/component/tagcomponent.h"
#include "inferno/component/textareacomponent.h"
#include "inferno/component/transformcomponent.h"
#include "inferno/render/renderer.h"
#include "inferno/render/uniformbuffer.h"
#include "inferno/scene/scene.h"
#include "inferno/script/nativescript.h"
@ -84,17 +85,7 @@ void Scene::update(float deltaTime)
void Scene::render()
{
auto [projection, view] = CameraSystem::the().projectionView();
Uniformbuffer::the().setValue("Camera", "u_projectionView", projection * view);
RendererCubemap::the().beginScene(projection, view); // camera, lights, environment
RenderSystem::the().render();
TextAreaSystem::the().render();
RendererCubemap::the().endScene();
Renderer3D::the().endScene();
Renderer2D::the().endScene();
RendererFont::the().endScene();
}
void Scene::destroy()

13
src/inferno/system/camerasystem.cpp

@ -53,10 +53,23 @@ std::pair<glm::mat4, glm::mat4> CameraSystem::projectionView()
}
VERIFY_NOT_REACHED();
return {};
}
glm::vec3 CameraSystem::translate()
{
auto view = m_registry->view<TransformComponent, CameraComponent>();
for (auto [entity, transform, camera] : view.each()) {
return transform.translate;
}
VERIFY_NOT_REACHED();
return {};
}
// -----------------------------------------
void CameraSystem::updateOrthographic(TransformComponent& transform, CameraComponent& camera)
{
// Update camera matrix

1
src/inferno/system/camerasystem.h

@ -32,6 +32,7 @@ public:
* @brief Return a pair from the camera component: { projection, view }
*/
std::pair<glm::mat4, glm::mat4> projectionView();
glm::vec3 translate();
void setRegistry(std::shared_ptr<entt::registry> registry) { m_registry = registry; };

177
src/inferno/system/rendersystem.cpp

@ -4,41 +4,148 @@
* SPDX-License-Identifier: MIT
*/
#include "glm/ext/matrix_transform.hpp" // glm::translate, glm::rotate, glm::scale, glm::radians
#include "inferno/component/model-component.h"
#include <cstdint> // int32_t
#include "glad/glad.h"
#include "ruc/format/log.h"
#include "inferno/component/cubemap-component.h"
#include "inferno/component/model-component.h"
#include "inferno/component/spritecomponent.h"
#include "inferno/component/transformcomponent.h"
#include "inferno/render/framebuffer.h"
#include "inferno/render/render-command.h"
#include "inferno/render/renderer.h"
#include "inferno/render/uniformbuffer.h"
#include "inferno/system/camerasystem.h"
#include "inferno/system/rendersystem.h"
#include "inferno/system/textareasystem.h"
namespace Inferno {
RenderSystem::RenderSystem(s)
{
ruc::info("RenderSystem initialized");
}
RenderSystem::~RenderSystem()
{
}
// -----------------------------------------
void RenderSystem::initialize(uint32_t width, uint32_t height)
{
m_framebuffer = Framebuffer::create({
.attachments = { Framebuffer::Type::Color, Framebuffer::Type::RGBA16F, Framebuffer::Type::RGBA16F, Framebuffer::Type::Depth },
.width = width,
.height = height,
.clearColor = { 0.0f, 0.0f, 0.0f, 0.0f },
.clearBit = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT,
});
m_screenFramebuffer = Framebuffer::create({
.renderToScreen = true,
.clearColor = { 1.0f, 1.0f, 1.0f, 1.0f },
.clearBit = GL_COLOR_BUFFER_BIT,
});
Uniformbuffer::the().setLayout(
"Camera", 0,
{
{ BufferElementType::Mat4, "u_projectionView" },
{ BufferElementType::Vec3, "u_position" },
});
Uniformbuffer::the().create("Camera");
Uniformbuffer::the().setLayout(
"DirectionalLights",
{
.size = sizeof(UniformDirectionalLight) * MAX_DIRECTIONAL_LIGHTS,
.bindingPoint = 1,
.uniformLocations = {
{ "u_directionalLight", 0 },
},
});
Uniformbuffer::the().create("DirectionalLights");
ruc::info("RenderSystem initialized");
}
void RenderSystem::render()
{
auto quadView = m_registry->view<TransformComponent, SpriteComponent>();
static constexpr TransformComponent transformIdentity;
for (auto [entity, transform, sprite] : quadView.each()) {
Renderer2D::the().drawQuad(transform, sprite.color, sprite.texture);
}
// ---------------------------------
// Deferred rendering to a framebuffer
auto cubemapView = m_registry->view<TransformComponent, CubemapComponent>();
framebufferSetup(m_framebuffer);
for (auto [entity, transform, cubemap] : cubemapView.each()) {
RendererCubemap::the().drawCubemap(transform, cubemap.color, cubemap.texture);
}
renderGeometry();
framebufferTeardown(m_framebuffer);
// ---------------------------------
// Forward rendering to the screen
framebufferSetup(m_screenFramebuffer);
renderSkybox();
// Render 3D geometry post-processing
RendererPostProcess::the().drawQuad(transformIdentity, m_framebuffer->texture(0), m_framebuffer->texture(1), m_framebuffer->texture(2));
RendererPostProcess::the().endScene();
// Visual representation of light sources
Framebuffer::copyBuffer(m_framebuffer, m_screenFramebuffer, GL_DEPTH_BUFFER_BIT, GL_NEAREST);
renderLightCubes();
// Render 2D, UI
renderOverlay();
framebufferTeardown(m_screenFramebuffer);
}
void RenderSystem::resize(int32_t width, int32_t height)
{
RenderCommand::setViewport(0, 0, width, height);
m_framebuffer->resize(width, height);
m_screenFramebuffer->resize(width, height);
}
// -----------------------------------------
void RenderSystem::framebufferSetup(std::shared_ptr<Framebuffer> framebuffer)
{
framebuffer->bind();
RenderCommand::setColorAttachmentCount(framebuffer->colorAttachmentCount());
RenderCommand::clearColor(framebuffer->clearColor());
RenderCommand::clearBit(framebuffer->clearBit());
}
void RenderSystem::framebufferTeardown(std::shared_ptr<Framebuffer> framebuffer)
{
framebuffer->unbind();
RenderCommand::setColorAttachmentCount(1);
}
void RenderSystem::renderGeometry()
{
auto [projection, view] = CameraSystem::the().projectionView();
auto translate = CameraSystem::the().translate();
Uniformbuffer::the().setValue("Camera", "u_projectionView", projection * view);
Uniformbuffer::the().setValue("Camera", "u_position", translate);
static UniformDirectionalLight directionalLights[1] = {
{
.direction = { -8.0f, -8.0f, -8.0f },
.ambient = { 0.1f, 0.1f, 0.1f },
.diffuse = { 1.0f, 1.0f, 1.0f },
.specular = { 1.0f, 1.0f, 1.0f },
},
};
Uniformbuffer::the().setValue("DirectionalLights", "u_directionalLight", directionalLights);
auto modelView = m_registry->view<TransformComponent, ModelComponent>();
@ -49,6 +156,54 @@ void RenderSystem::render()
model.color,
model.model->texture() ? model.model->texture() : model.texture);
}
Renderer3D::the().endScene();
}
void RenderSystem::renderSkybox()
{
auto [projection, view] = CameraSystem::the().projectionView();
RendererCubemap::the().beginScene(projection, view); // camera, lights, environment
auto cubemapView = m_registry->view<TransformComponent, CubemapComponent>();
for (auto [entity, transform, cubemap] : cubemapView.each()) {
if (!cubemap.isLight) {
RendererCubemap::the().drawCubemap(transform, cubemap.color, cubemap.texture);
}
}
RendererCubemap::the().endScene();
}
void RenderSystem::renderLightCubes()
{
auto [projection, view] = CameraSystem::the().projectionView();
RendererLightCube::the().beginScene(projection, view); // camera, lights, environment
auto cubemapView = m_registry->view<TransformComponent, CubemapComponent>();
for (auto [entity, transform, cubemap] : cubemapView.each()) {
if (cubemap.isLight) {
RendererLightCube::the().drawCubemap(transform, cubemap.color, nullptr);
}
}
RendererLightCube::the().endScene();
}
void RenderSystem::renderOverlay()
{
auto quadView = m_registry->view<TransformComponent, SpriteComponent>();
for (auto [entity, transform, sprite] : quadView.each()) {
Renderer2D::the().drawQuad(transform, sprite.color, sprite.texture);
}
Renderer2D::the().endScene();
TextAreaSystem::the().render();
RendererFont::the().endScene();
}
} // namespace Inferno

20
src/inferno/system/rendersystem.h

@ -6,25 +6,39 @@
#pragma once
#include <cstdint> // int32_t, uint32_t
#include <memory> //std::shared_ptr
#include "entt/entity/registry.hpp" // entt::entity, entt::registry
#include "ruc/singleton.h"
#include "entt/entity/fwd.hpp" // entt::registry
#include "inferno/render/renderer.h"
#include "ruc/singleton.h"
namespace Inferno {
class Framebuffer;
class RenderSystem final : public ruc::Singleton<RenderSystem> {
public:
RenderSystem(s);
virtual ~RenderSystem();
void initialize(uint32_t width, uint32_t height);
void render();
void resize(int32_t width, int32_t height);
void setRegistry(std::shared_ptr<entt::registry> registry) { m_registry = registry; };
private:
void framebufferSetup(std::shared_ptr<Framebuffer> framebuffer);
void framebufferTeardown(std::shared_ptr<Framebuffer> framebuffer);
void renderGeometry();
void renderSkybox();
void renderLightCubes();
void renderOverlay();
std::shared_ptr<Framebuffer> m_framebuffer;
std::shared_ptr<Framebuffer> m_screenFramebuffer;
std::shared_ptr<entt::registry> m_registry;
};

Loading…
Cancel
Save