post processing working, outlining not so much

main
Brett 2024-05-04 03:15:43 -04:00
parent ecae5287cc
commit fa2b314453
14 changed files with 227 additions and 54 deletions

View File

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.25)
set(BLT_GRAPHICS_VERSION 0.13.3)
set(BLT_GRAPHICS_VERSION 0.13.4)
set(BLT_GRAPHICS_TEST_VERSION 0.0.1)
project(BLT_WITH_GRAPHICS VERSION ${BLT_GRAPHICS_VERSION})

View File

@ -24,6 +24,7 @@
#include <vector>
#include "blt/std/types.h"
namespace blt::gfx
{
@ -127,6 +128,16 @@ namespace blt::gfx
void destroy();
[[nodiscard]] auto& getTexture(attachment_t attachment)
{
return *texture_buffers[static_cast<GLuint>(attachment) - static_cast<GLuint>(attachment_t::COLOR0)];
}
[[nodiscard]] const auto& getTexture(attachment_t attachment) const
{
return *texture_buffers[static_cast<GLuint>(attachment)];
}
[[nodiscard]] i32 getHeight() const
{
return height_;
@ -136,6 +147,11 @@ namespace blt::gfx
{
return width_;
}
auto getBufferID() const
{
return fboID;
}
public:
static frame_buffer_t make_render_texture(blt::i32 width, blt::i32 height);

View File

@ -149,7 +149,8 @@ namespace blt::gfx
class batch_renderer_2d
{
private:
pp_engine_t engine;
std::unique_ptr<pp_engine_t> engine = pp_engine_t::make_multi_pp(std::make_unique<pp_outline_target>(),
std::make_unique<pp_outline_step_t>());
template<typename T>
struct render_object_t

View File

@ -35,20 +35,32 @@ namespace blt::gfx
class pp_step_t
{
public:
virtual void create() = 0;
virtual void create()
{}
virtual void draw() = 0;
// only called on render()
virtual void draw(pp_step_t&)
{}
frame_buffer_t& getBuffer()
// only called on bind()
virtual void draw()
{}
auto& getBuffer()
{
return draw_buffer;
}
shader_t& getShader()
auto& getShader()
{
return *shader;
}
bool hasShader()
{
return shader != nullptr;
}
virtual ~pp_step_t() = default;
protected:
@ -69,9 +81,26 @@ namespace blt::gfx
public:
void create() override;
void draw(pp_step_t& previous) override;
};
class pp_outline_target : public pp_step_t
{
public:
void create() override;
void draw() override;
};
class pp_outline_step_t : public pp_step_t
{
public:
void create() override;
void draw(pp_step_t& previous) override;
};
class pp_engine_t
{
public:
@ -89,13 +118,32 @@ namespace blt::gfx
}
static std::unique_ptr<shader_t> createShader(std::string_view fragment);
static std::unique_ptr<pp_engine_t> make_basic_pp()
{
return make_single_pp(std::make_unique<pp_render_target_t>());
}
static std::unique_ptr<pp_engine_t> make_single_pp(std::unique_ptr<pp_step_t> step)
{
auto engine = new pp_engine_t();
engine->addStep(std::move(step));
return std::unique_ptr<pp_engine_t>(engine);
}
template<typename... Args>
static std::unique_ptr<pp_engine_t> make_multi_pp(Args... steps)
{
auto engine = new pp_engine_t();
(engine->addStep(std::move(steps)), ...);
return std::unique_ptr<pp_engine_t>(engine);
}
private:
pp_engine_t() = default;
std::vector<std::unique_ptr<pp_step_t>> steps;
std::unique_ptr<vertex_array_t> screen_vao;
#ifdef __EMSCRIPTEN__
std::unique_ptr<pp_to_screen_step_t> to_screen;
#endif
};
}

View File

@ -4,13 +4,15 @@ const std::string shader_2d_textured_frag = R"("
#version 300 es
precision mediump float;
out vec4 FragColor;
layout (location = 0) out vec4 FragColor;
layout (location = 1) out vec4 Mask;
in vec2 uv;
in vec2 pos;
uniform sampler2D tex;
uniform vec4 color;
uniform vec4 use_texture;
uniform vec4 outline_color;
vec4 linear_iter(vec4 i, vec4 p, float factor){
return (i + p) * factor;
@ -18,6 +20,8 @@ vec4 linear_iter(vec4 i, vec4 p, float factor){
void main() {
FragColor = (texture(tex, uv) * use_texture) + color;
Mask = outline_color;
//Mask.a = FragColor.a;
}
")";

View File

@ -4,13 +4,15 @@ const std::string shader_2d_textured_cirlce_frag = R"("
#version 300 es
precision mediump float;
out vec4 FragColor;
layout (location = 0) out vec4 FragColor;
layout (location = 1) out vec4 Mask;
in vec2 uv;
in vec2 pos;
uniform sampler2D tex;
uniform vec4 color;
uniform vec4 use_texture;
uniform vec4 outline_color;
const float offset = 1.0 / 32.0;
@ -25,10 +27,9 @@ void main() {
const float sq = 0.5 * 0.5;
if (ts >= sq)
discard;
if (ts + offset >= sq)
FragColor = vec4(1.0, 1.0, 1.0, 1.0);
else
FragColor = (texture(tex, uv) * use_texture) + color;
FragColor = (texture(tex, uv) * use_texture) + color;
Mask = outline_color;
//Mask.a = FragColor.a;
}
")";

View File

@ -23,7 +23,7 @@ uniform mat4 model;
uniform float z_index;
void main() {
gl_Position = ovm * model * vec4(vertex.xy, z_index, 1.0);
gl_Position = vec4(vertex.xy, z_index, 1.0);
pos = vertex.xy;
uv = uv_in;
}

View File

@ -0,0 +1,48 @@
#ifdef __cplusplus
#include <string>
const std::string shader_pp_outline_step_frag = R"("
#version 300 es
precision mediump float;
out vec4 FragColor;
in vec2 uv;
in vec2 pos;
uniform vec2 viewportSize;
uniform sampler2D albedo;
uniform sampler2D mask;
#define LINE_WEIGHT 3.0
void main() {
float dx = (1.0 / viewportSize.x) * LINE_WEIGHT;
float dy = (1.0 / viewportSize.y) * LINE_WEIGHT;
vec2 uvCenter = uv;
vec2 uvRight = vec2(uvCenter.x + dx, uvCenter.y);
vec2 uvTop = vec2(uvCenter.x, uvCenter.y - dx);
vec2 uvTopRight = vec2(uvCenter.x + dx, uvCenter.y - dx);
float mCenter = texture(mask, uvCenter).r;
float mTop = texture(mask, uvTop).r;
float mRight = texture(mask, uvRight).r;
float mTopRight = texture(mask, uvTopRight).r;
float dT = abs(mCenter - mTop);
float dR = abs(mCenter - mRight);
float dTR = abs(mCenter - mTopRight);
float delta = 0.0;
delta = max(delta, dT);
delta = max(delta, dR);
delta = max(delta, dTR);
vec4 outline = vec4(delta, delta, delta, 1.0);
vec4 albedo = texture(albedo, uv);
FragColor = albedo - outline;
}
")";
#endif

View File

@ -1,6 +1,6 @@
#ifdef __cplusplus
#include <string>
const std::string shader_pp_to_screen_frag = R"("
const std::string shader_pp_screen_frag = R"("
#version 300 es
precision mediump float;

View File

@ -135,7 +135,7 @@ namespace blt::gfx
}
protected:
void setDefaults() const;
void setDefaults(GLint type) const;
inline void generateMipmaps() const
{

View File

@ -24,7 +24,7 @@ namespace blt::gfx
i32 GL_MINOR = 6;
i32 DOUBLE_BUFFER = GLFW_TRUE;
i32 GL_PROFILE = GLFW_OPENGL_CORE_PROFILE;
i32 SAMPLES = 8;
i32 SAMPLES = 4;
};
struct window_data

View File

@ -89,8 +89,7 @@ namespace blt::gfx
point_shader->bindAttribute(0, "vertex");
point_shader->bindAttribute(1, "uv_in");
engine.addStep(std::make_unique<pp_render_target_t>());
engine.create();
engine->create();
// draw_buffer.create();
// draw_buffer.bind();
@ -164,17 +163,18 @@ namespace blt::gfx
void batch_renderer_2d::cleanup()
{
engine.cleanup();
engine->cleanup();
engine = nullptr;
delete square_vao;
delete square_shader;
delete point_shader;
}
void batch_renderer_2d::render(i32 width, i32 height, const bool transparency)
void batch_renderer_2d::render(i32, i32, const bool transparency)
{
//draw_buffer.bind();
//draw_buffer.updateBuffersStorage(width, height);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
if (transparency)
{
glEnable(GL_BLEND);
@ -183,17 +183,15 @@ namespace blt::gfx
glEnable(GL_DEPTH_TEST);
glActiveTexture(GL_TEXTURE0);
engine.bind();
engine->bind();
draw_objects();
glDisable(GL_DEPTH_TEST);
if (transparency)
glDisable(GL_BLEND);
engine->render();
render_reset();
frame_buffer_t::unbind();
engine.render();
}
void batch_renderer_2d::draw_objects()
@ -220,6 +218,7 @@ namespace blt::gfx
square_shader->setVec4("color", render_info.color);
square_shader->setVec4("use_texture", render_info.blend);
square_shader->setVec4("outline_color", render_info.outline_color);
square_shader->setFloat("z_index", (z_index - draw.z_min) * denominator);
square_shader->setMatrix("model", model);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
@ -244,6 +243,7 @@ namespace blt::gfx
square_shader->setVec4("color", render_info.color);
square_shader->setVec4("use_texture", render_info.blend);
square_shader->setVec4("outline_color", render_info.outline_color);
square_shader->setFloat("z_index", (z_index - draw.z_min) * denominator);
// 0, 1 (top right)
@ -297,6 +297,7 @@ namespace blt::gfx
point_shader->setVec4("color", render_info.color);
point_shader->setVec4("use_texture", render_info.blend);
point_shader->setVec4("outline_color", render_info.outline_color);
point_shader->setFloat("z_index", (z_index - draw.z_min) * denominator);
point_shader->setMatrix("model", model);

View File

@ -18,9 +18,11 @@
#include <blt/gfx/window.h>
#include <blt/gfx/renderer/postprocess.h>
#include <blt/gfx/renderer/shaders/postprocess.vert>
#include <blt/gfx/renderer/shaders/pp_to_screen.frag>
#include <blt/gfx/renderer/shaders/pp_screen.frag>
#include <blt/gfx/renderer/shaders/pp_outline_step.frag>
#include <blt/std/ranges.h>
#define __EMSCRIPTEN__
float full_screen_vertices[20] = {
1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
@ -33,6 +35,13 @@ const unsigned int full_screen_indices[6] = {
1, 2, 3
};
template<typename T>
bool once()
{
static bool ran = true;
return std::exchange(ran, false);
}
namespace blt::gfx
{
void pp_engine_t::create()
@ -53,7 +62,7 @@ namespace blt::gfx
screen_vao->bindElement(indices_vbo);
}
#ifdef __EMSCRIPTEN__
to_screen = std::make_unique<pp_to_screen_step_t>();
addStep(std::make_unique<pp_to_screen_step_t>());
#endif
for (auto& step : steps)
step->create();
@ -65,22 +74,18 @@ namespace blt::gfx
for (const auto& [index, step] : blt::enumerate(steps))
{
if (index == 0)
{
continue;
} else
steps[index - 1]->getBuffer().bind(frame_buffer_t::draw_t::READ);
step->draw();
step->getBuffer().bind(frame_buffer_t::draw_t::DRAW);
step->getShader().bind();
auto& previous = steps[index - 1];
step->getBuffer().bind(frame_buffer_t::draw_t::BOTH);
step->draw(*previous);
if (step->hasShader())
step->getShader().bind();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
}
glBindTexture(GL_TEXTURE_2D, 0);
frame_buffer_t::unbind();
#ifdef __EMSCRIPTEN__
to_screen->getShader().bind();
steps.back()->getBuffer().bind(frame_buffer_t::draw_t::READ);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
#else
#ifndef __EMSCRIPTEN__
steps.back()->getBuffer().blitToScreen(getWindowWidth(), getWindowHeight());
#endif
}
@ -104,26 +109,73 @@ namespace blt::gfx
void pp_engine_t::bind()
{
steps.front()->draw();
steps.front()->getBuffer().bind(frame_buffer_t::draw_t::DRAW);
steps.front()->getBuffer().bind();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
}
void pp_to_screen_step_t::create()
{
shader = pp_engine_t::createShader(shader_pp_to_screen_frag);
shader = pp_engine_t::createShader(shader_pp_screen_frag);
}
void pp_to_screen_step_t::draw()
{}
void pp_to_screen_step_t::draw(pp_step_t& previous)
{
glActiveTexture(GL_TEXTURE0);
previous.getBuffer().getTexture(frame_buffer_t::attachment_t::COLOR0).bind();
}
void pp_render_target_t::create()
{
shader = pp_engine_t::createShader(shader_pp_to_screen_frag);
draw_buffer = frame_buffer_t::make_render_target(getWindowWidth(), getWindowHeight());
draw_buffer = frame_buffer_t::make_render_texture(getWindowWidth(), getWindowHeight());
}
void pp_render_target_t::draw()
{
draw_buffer.updateBuffersStorage(getWindowWidth(), getWindowHeight());
}
void pp_outline_target::create()
{
draw_buffer.create();
draw_buffer.bind();
auto* texture = new texture_gl2D(getWindowWidth(), getWindowHeight(), GL_RGBA8);
draw_buffer.attachTexture(texture, frame_buffer_t::attachment_t::COLOR0);
auto* mask = new texture_gl2D(getWindowWidth(), getWindowHeight(), GL_RGBA8);
draw_buffer.attachTexture(mask, frame_buffer_t::attachment_t::COLOR1);
render_buffer_t depth_rbo = render_buffer_t::make_render_buffer(GL_DEPTH24_STENCIL8, getWindowWidth(), getWindowHeight());
draw_buffer.attachRenderBuffer(depth_rbo, frame_buffer_t::attachment_t::DEPTH_STENCIL);
if (!frame_buffer_t::validate())
BLT_ERROR("Failed to create render texture framebuffer!");
frame_buffer_t::unbind();
}
void pp_outline_target::draw()
{
draw_buffer.updateBuffersStorage(getWindowWidth(), getWindowHeight());
glEnable(GL_TEXTURE0);
glEnable(GL_TEXTURE1);
}
void pp_outline_step_t::create()
{
draw_buffer = frame_buffer_t::make_render_texture(getWindowHeight(), getWindowHeight());
shader = pp_engine_t::createShader(shader_pp_outline_step_frag);
shader->setInt("albedo", 0);
shader->setInt("mask", 1);
}
void pp_outline_step_t::draw(pp_step_t& previous)
{
draw_buffer.updateBuffersStorage(getWindowWidth(), getWindowHeight());
glActiveTexture(GL_TEXTURE0);
previous.getBuffer().getTexture(frame_buffer_t::attachment_t::COLOR0).bind();
glActiveTexture(GL_TEXTURE1);
previous.getBuffer().getTexture(frame_buffer_t::attachment_t::COLOR1).bind();
shader->bind();
shader->setVec2("viewportSize", static_cast<f32>(getWindowWidth()), static_cast<f32>(getWindowHeight()));
}
}

View File

@ -152,7 +152,7 @@ blt::gfx::texture_file& blt::gfx::texture_file::resize(int target_width, int tar
return *this;
}
void blt::gfx::texture_gl::setDefaults() const
void blt::gfx::texture_gl::setDefaults(GLint type) const
{
glTexParameteri(textureBindType, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(textureBindType, GL_TEXTURE_WRAP_T, GL_REPEAT);
@ -161,8 +161,10 @@ void blt::gfx::texture_gl::setDefaults() const
glTexParameteri(textureBindType, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(textureBindType, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
#else
glTexParameteri(textureBindType, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);
glTexParameteri(textureBindType, GL_TEXTURE_MAG_FILTER, GL_NEAREST_MIPMAP_LINEAR);
// glTexParameteri(textureBindType, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);
// glTexParameteri(textureBindType, GL_TEXTURE_MAG_FILTER, GL_NEAREST_MIPMAP_LINEAR);
glTexParameteri(textureBindType, GL_TEXTURE_MIN_FILTER, type);
glTexParameteri(textureBindType, GL_TEXTURE_MAG_FILTER, type);
#endif
#ifdef GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT
// Anisotropy helps preserve textures at oblique angles
@ -213,7 +215,7 @@ void blt::gfx::texture_gl2D::resize(int width, int height)
blt::gfx::texture_gl2D::texture_gl2D(int width, int height, GLint colorMode): texture_gl(width, height, GL_TEXTURE_2D, colorMode)
{
bind();
setDefaults();
setDefaults(GL_LINEAR);
resize(width, height);
//glTexStorage2D(textureBindType, 4, colorMode, width, height);
}
@ -222,7 +224,7 @@ blt::gfx::texture_gl2D::texture_gl2D(const blt::gfx::texture_data& data):
texture_gl(data.width(), data.height(), GL_TEXTURE_2D, data.channels() == 4 ? GL_RGBA8 : GL_RGB8)
{
bind();
setDefaults();
setDefaults(GL_NEAREST);
glTexStorage2D(textureBindType, 4, textureColorMode, data.width(), data.height());
upload((void*) data.data(), data.channels() == 4 ? GL_RGBA : GL_RGB, 0, 0, 0, data.width(), data.height());
bind();
@ -247,7 +249,7 @@ blt::gfx::texture_gl2D_multisample::texture_gl2D_multisample(int width, int heig
texture_gl(width, height, GL_TEXTURE_2D_MULTISAMPLE, colorMode), samples(samples)
{
bind();
setDefaults();
setDefaults(GL_LINEAR);
//glTexImage2DMultisample(textureBindType, samples, colorMode, width, height, GL_TRUE);
glTexStorage2DMultisample(textureBindType, samples, colorMode, width, height, GL_TRUE);
}
@ -262,7 +264,7 @@ void blt::gfx::texture_gl2D_multisample::resize(int width, int height)
blt::gfx::gl_texture2D_array::gl_texture2D_array(int width, int height, int layers, GLint colorMode): texture_gl(width, height, layers, colorMode)
{
bind();
setDefaults();
setDefaults(GL_LINEAR);
// 6+ mipmaps is about where I stop noticing any difference (size is 4x4 pixels, so that makes sense)
glTexStorage3D(textureBindType, 6, colorMode, width, height, layers);
BLT_DEBUG("Creating 2D Texture Array with ID: %d", textureID);