post-processing test

This commit is contained in:
MihailRis
2024-03-08 21:49:38 +03:00
parent e7af5830cf
commit 8ed65ca51e
13 changed files with 268 additions and 113 deletions
+13
View File
@@ -0,0 +1,13 @@
in vec2 v_coord;
out vec4 f_color;
uniform sampler2D u_texture0;
uniform float u_timer;
void main(){
vec2 coord = v_coord;
coord.x += sin(u_timer*5.0+coord.x*4.0) * 0.02;
coord.y += cos(u_timer*5.0+coord.y*4.0) * 0.02;
f_color = texture(u_texture0, coord);
}
+12
View File
@@ -0,0 +1,12 @@
layout (location = 0) in vec2 v_position;
out vec2 v_coord;
uniform ivec2 u_screenSize;
uniform float u_timer;
void main(){
v_coord = v_position * 0.5 + 0.5;
gl_Position = vec4(v_position, 0.0, 1.0);
}
+1
View File
@@ -74,6 +74,7 @@ void AssetsLoader::addDefaults(AssetsLoader& loader, const Content* content) {
loader.add(ASSET_TEXTURE, TEXTURES_FOLDER"/gui/cross.png", "gui/cross"); loader.add(ASSET_TEXTURE, TEXTURES_FOLDER"/gui/cross.png", "gui/cross");
if (content) { if (content) {
loader.add(ASSET_SHADER, SHADERS_FOLDER"/ui3d", "ui3d"); loader.add(ASSET_SHADER, SHADERS_FOLDER"/ui3d", "ui3d");
loader.add(ASSET_SHADER, SHADERS_FOLDER"/screen", "screen");
loader.add(ASSET_SHADER, SHADERS_FOLDER"/background", "background"); loader.add(ASSET_SHADER, SHADERS_FOLDER"/background", "background");
loader.add(ASSET_SHADER, SHADERS_FOLDER"/skybox_gen", "skybox_gen"); loader.add(ASSET_SHADER, SHADERS_FOLDER"/skybox_gen", "skybox_gen");
loader.add(ASSET_TEXTURE, TEXTURES_FOLDER"/misc/moon.png", "misc/moon"); loader.add(ASSET_TEXTURE, TEXTURES_FOLDER"/misc/moon.png", "misc/moon");
+115 -95
View File
@@ -14,6 +14,7 @@
#include "../graphics/Batch3D.h" #include "../graphics/Batch3D.h"
#include "../graphics/Texture.h" #include "../graphics/Texture.h"
#include "../graphics/LineBatch.h" #include "../graphics/LineBatch.h"
#include "../graphics/PostProcessing.h"
#include "../voxels/Chunks.h" #include "../voxels/Chunks.h"
#include "../voxels/Chunk.h" #include "../voxels/Chunk.h"
#include "../voxels/Block.h" #include "../voxels/Block.h"
@@ -39,6 +40,7 @@ WorldRenderer::WorldRenderer(Engine* engine, LevelFrontend* frontend, Player* pl
level(frontend->getLevel()), level(frontend->getLevel()),
player(player) player(player)
{ {
postProcessing = std::make_unique<PostProcessing>();
frustumCulling = std::make_unique<Frustum>(); frustumCulling = std::make_unique<Frustum>();
lineBatch = std::make_unique<LineBatch>(); lineBatch = std::make_unique<LineBatch>();
renderer = std::make_unique<ChunksRenderer>( renderer = std::make_unique<ChunksRenderer>(
@@ -139,8 +141,6 @@ void WorldRenderer::drawChunks(Chunks* chunks, Camera* camera, Shader* shader) {
void WorldRenderer::draw(const GfxContext& pctx, Camera* camera, bool hudVisible){ void WorldRenderer::draw(const GfxContext& pctx, Camera* camera, bool hudVisible){
EngineSettings& settings = engine->getSettings(); EngineSettings& settings = engine->getSettings();
Window::clearDepth();
skybox->refresh(pctx, level->world->daytime, 1.0f+fog*2.0f, 4); skybox->refresh(pctx, level->world->daytime, 1.0f+fog*2.0f, 4);
const Content* content = level->content; const Content* content = level->content;
@@ -153,116 +153,136 @@ void WorldRenderer::draw(const GfxContext& pctx, Camera* camera, bool hudVisible
const Viewport& viewport = pctx.getViewport(); const Viewport& viewport = pctx.getViewport();
int displayWidth = viewport.getWidth(); int displayWidth = viewport.getWidth();
int displayHeight = viewport.getHeight(); int displayHeight = viewport.getHeight();
// Drawing background sky plane
skybox->draw(pctx, camera, assets, level->getWorld()->daytime, fog);
// Actually world render with depth buffer on // World render scope with diegetic HUD included
{ {
GfxContext ctx = pctx.sub(); GfxContext wctx = pctx.sub();
ctx.setDepthTest(true); postProcessing->use(wctx);
ctx.setCullFace(true);
float fogFactor = 15.0f / ((float)settings.chunks.loadDistance-2); Window::clearDepth();
// Setting up main shader // Drawing background sky plane
shader->use(); skybox->draw(pctx, camera, assets, level->getWorld()->daytime, fog);
shader->uniformMatrix("u_proj", camera->getProjection());
shader->uniformMatrix("u_view", camera->getView()); // Actually world render with depth buffer on
shader->uniform1f("u_gamma", settings.graphics.gamma);
shader->uniform1f("u_fogFactor", fogFactor);
shader->uniform1f("u_fogCurve", settings.graphics.fogCurve);
shader->uniform1f("u_dayTime", level->world->daytime);
shader->uniform3f("u_cameraPos", camera->position);
shader->uniform1i("u_cubemap", 1);
// Light emission when an emissive item is chosen
{ {
auto inventory = player->getInventory(); GfxContext ctx = wctx.sub();
ItemStack& stack = inventory->getSlot(player->getChosenSlot()); ctx.setDepthTest(true);
auto item = indices->getItemDef(stack.getItemId()); ctx.setCullFace(true);
float multiplier = 0.5f;
shader->uniform3f("u_torchlightColor", float fogFactor = 15.0f / ((float)settings.chunks.loadDistance-2);
item->emission[0] / 15.0f * multiplier,
item->emission[1] / 15.0f * multiplier, // Setting up main shader
item->emission[2] / 15.0f * multiplier shader->use();
); shader->uniformMatrix("u_proj", camera->getProjection());
shader->uniform1f("u_torchlightDistance", 6.0f); shader->uniformMatrix("u_view", camera->getView());
shader->uniform1f("u_gamma", settings.graphics.gamma);
shader->uniform1f("u_fogFactor", fogFactor);
shader->uniform1f("u_fogCurve", settings.graphics.fogCurve);
shader->uniform1f("u_dayTime", level->world->daytime);
shader->uniform3f("u_cameraPos", camera->position);
shader->uniform1i("u_cubemap", 1);
// Light emission when an emissive item is chosen
{
auto inventory = player->getInventory();
ItemStack& stack = inventory->getSlot(player->getChosenSlot());
auto item = indices->getItemDef(stack.getItemId());
float multiplier = 0.5f;
shader->uniform3f("u_torchlightColor",
item->emission[0] / 15.0f * multiplier,
item->emission[1] / 15.0f * multiplier,
item->emission[2] / 15.0f * multiplier
);
shader->uniform1f("u_torchlightDistance", 6.0f);
}
// Binding main shader textures
skybox->bind();
atlas->getTexture()->bind();
drawChunks(level->chunks.get(), camera, shader);
// Selected block
if (PlayerController::selectedBlockId != -1 && hudVisible){
blockid_t id = PlayerController::selectedBlockId;
auto block = indices->getBlockDef(id);
const glm::vec3 pos = PlayerController::selectedBlockPosition;
const glm::vec3 point = PlayerController::selectedPointPosition;
const glm::vec3 norm = PlayerController::selectedBlockNormal;
std::vector<AABB>& hitboxes = block->rotatable
? block->rt.hitboxes[PlayerController::selectedBlockStates]
: block->hitboxes;
linesShader->use();
linesShader->uniformMatrix("u_projview", camera->getProjView());
lineBatch->lineWidth(2.0f);
for (auto& hitbox: hitboxes) {
const glm::vec3 center = pos + hitbox.center();
const glm::vec3 size = hitbox.size();
lineBatch->box(center, size + glm::vec3(0.02), glm::vec4(0.f, 0.f, 0.f, 0.5f));
if (player->debug) {
lineBatch->line(point, point+norm*0.5f, glm::vec4(1.0f, 0.0f, 1.0f, 1.0f));
}
}
lineBatch->render();
}
skybox->unbind();
} }
// Binding main shader textures if (hudVisible && player->debug) {
skybox->bind(); GfxContext ctx = pctx.sub();
atlas->getTexture()->bind(); ctx.setDepthTest(true);
drawChunks(level->chunks.get(), camera, shader);
// Selected block
if (PlayerController::selectedBlockId != -1 && hudVisible){
blockid_t id = PlayerController::selectedBlockId;
auto block = indices->getBlockDef(id);
const glm::vec3 pos = PlayerController::selectedBlockPosition;
const glm::vec3 point = PlayerController::selectedPointPosition;
const glm::vec3 norm = PlayerController::selectedBlockNormal;
std::vector<AABB>& hitboxes = block->rotatable
? block->rt.hitboxes[PlayerController::selectedBlockStates]
: block->hitboxes;
linesShader->use(); linesShader->use();
linesShader->uniformMatrix("u_projview", camera->getProjView());
lineBatch->lineWidth(2.0f); if (settings.debug.showChunkBorders){
for (auto& hitbox: hitboxes) { linesShader->uniformMatrix("u_projview", camera->getProjView());
const glm::vec3 center = pos + hitbox.center(); glm::vec3 coord = player->camera->position;
const glm::vec3 size = hitbox.size(); if (coord.x < 0) coord.x--;
lineBatch->box(center, size + glm::vec3(0.02), glm::vec4(0.f, 0.f, 0.f, 0.5f)); if (coord.z < 0) coord.z--;
if (player->debug) { int cx = floordiv((int)coord.x, CHUNK_W);
lineBatch->line(point, point+norm*0.5f, glm::vec4(1.0f, 0.0f, 1.0f, 1.0f)); int cz = floordiv((int)coord.z, CHUNK_D);
}
drawBorders(cx * CHUNK_W, 0, cz * CHUNK_D,
(cx + 1) * CHUNK_W, CHUNK_H, (cz + 1) * CHUNK_D);
} }
float length = 40.f;
glm::vec3 tsl(displayWidth/2, displayHeight/2, 0.f);
glm::mat4 model(glm::translate(glm::mat4(1.f), tsl));
linesShader->uniformMatrix("u_projview", glm::ortho(
0.f, (float)displayWidth,
0.f, (float)displayHeight,
-length, length) * model * glm::inverse(camera->rotation));
ctx.setDepthTest(false);
lineBatch->lineWidth(4.0f);
lineBatch->line(0.f, 0.f, 0.f, length, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f);
lineBatch->line(0.f, 0.f, 0.f, 0.f, length, 0.f, 0.f, 0.f, 0.f, 1.f);
lineBatch->line(0.f, 0.f, 0.f, 0.f, 0.f, length, 0.f, 0.f, 0.f, 1.f);
lineBatch->render();
ctx.setDepthTest(true);
lineBatch->lineWidth(2.0f);
lineBatch->line(0.f, 0.f, 0.f, length, 0.f, 0.f, 1.f, 0.f, 0.f, 1.f);
lineBatch->line(0.f, 0.f, 0.f, 0.f, length, 0.f, 0.f, 1.f, 0.f, 1.f);
lineBatch->line(0.f, 0.f, 0.f, 0.f, 0.f, length, 0.f, 0.f, 1.f, 1.f);
lineBatch->render(); lineBatch->render();
} }
skybox->unbind();
} }
if (hudVisible && player->debug) { {
GfxContext ctx = pctx.sub(); GfxContext ctx = pctx.sub();
ctx.setDepthTest(true);
linesShader->use();
if (settings.debug.showChunkBorders){
linesShader->uniformMatrix("u_projview", camera->getProjView());
glm::vec3 coord = player->camera->position;
if (coord.x < 0) coord.x--;
if (coord.z < 0) coord.z--;
int cx = floordiv((int)coord.x, CHUNK_W);
int cz = floordiv((int)coord.z, CHUNK_D);
drawBorders(cx * CHUNK_W, 0, cz * CHUNK_D,
(cx + 1) * CHUNK_W, CHUNK_H, (cz + 1) * CHUNK_D);
}
float length = 40.f;
glm::vec3 tsl(displayWidth/2, displayHeight/2, 0.f);
glm::mat4 model(glm::translate(glm::mat4(1.f), tsl));
linesShader->uniformMatrix("u_projview", glm::ortho(
0.f, (float)displayWidth,
0.f, (float)displayHeight,
-length, length) * model * glm::inverse(camera->rotation));
ctx.setDepthTest(false); ctx.setDepthTest(false);
lineBatch->lineWidth(4.0f);
lineBatch->line(0.f, 0.f, 0.f, length, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f); auto shader = assets->getShader("screen");
lineBatch->line(0.f, 0.f, 0.f, 0.f, length, 0.f, 0.f, 0.f, 0.f, 1.f); shader->use();
lineBatch->line(0.f, 0.f, 0.f, 0.f, 0.f, length, 0.f, 0.f, 0.f, 1.f); shader->uniform1f("u_timer", Window::time());
lineBatch->render(); shader->uniform1f("u_dayTime", level->world->daytime);
ctx.setDepthTest(true); postProcessing->render(ctx, shader);
lineBatch->lineWidth(2.0f);
lineBatch->line(0.f, 0.f, 0.f, length, 0.f, 0.f, 1.f, 0.f, 0.f, 1.f);
lineBatch->line(0.f, 0.f, 0.f, 0.f, length, 0.f, 0.f, 1.f, 0.f, 1.f);
lineBatch->line(0.f, 0.f, 0.f, 0.f, 0.f, length, 0.f, 0.f, 1.f, 1.f);
lineBatch->render();
} }
} }
+2 -1
View File
@@ -20,17 +20,18 @@ class Batch3D;
class LineBatch; class LineBatch;
class ChunksRenderer; class ChunksRenderer;
class Shader; class Shader;
class Texture;
class Frustum; class Frustum;
class Engine; class Engine;
class Chunks; class Chunks;
class LevelFrontend; class LevelFrontend;
class Skybox; class Skybox;
class PostProcessing;
class WorldRenderer { class WorldRenderer {
Engine* engine; Engine* engine;
Level* level; Level* level;
Player* player; Player* player;
std::unique_ptr<PostProcessing> postProcessing;
std::unique_ptr<Frustum> frustumCulling; std::unique_ptr<Frustum> frustumCulling;
std::unique_ptr<LineBatch> lineBatch; std::unique_ptr<LineBatch> lineBatch;
std::unique_ptr<ChunksRenderer> renderer; std::unique_ptr<ChunksRenderer> renderer;
+11 -1
View File
@@ -23,7 +23,7 @@ Framebuffer::Framebuffer(uint width, uint height, bool alpha)
// Setup color attachment (texture) // Setup color attachment (texture)
GLuint tex; GLuint tex;
GLuint format = alpha ? GL_RGBA : GL_RGB; format = alpha ? GL_RGBA : GL_RGB;
glGenTextures(1, &tex); glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex); glBindTexture(GL_TEXTURE_2D, tex);
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, nullptr); glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, nullptr);
@@ -55,6 +55,16 @@ void Framebuffer::unbind() {
glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0);
} }
void Framebuffer::resize(uint width, uint height) {
if (this->width == width && this->height == height) {
return;
}
GLuint texid = texture->getId();
texture->bind();
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, nullptr);
texture->unbind();
}
Texture* Framebuffer::getTexture() const { Texture* Framebuffer::getTexture() const {
return texture.get(); return texture.get();
} }
+26 -13
View File
@@ -8,22 +8,35 @@
class Texture; class Texture;
class Framebuffer { class Framebuffer {
uint fbo; uint fbo;
uint depth; uint depth;
uint width; uint width;
uint height; uint height;
std::unique_ptr<Texture> texture; uint format;
std::unique_ptr<Texture> texture;
public: public:
Framebuffer(uint fbo, uint depth, std::unique_ptr<Texture> texture); Framebuffer(uint fbo, uint depth, std::unique_ptr<Texture> texture);
Framebuffer(uint width, uint height, bool alpha=false); Framebuffer(uint width, uint height, bool alpha=false);
~Framebuffer(); ~Framebuffer();
void bind(); /// @brief Use framebuffer
void unbind(); void bind();
Texture* getTexture() const; /// @brief Stop using framebuffer
uint getWidth() const; void unbind();
uint getHeight() const;
/// @brief Update framebuffer texture size
/// @param width new width
/// @param height new height
void resize(uint width, uint height);
/// @brief Get framebuffer color attachment
Texture* getTexture() const;
/// @brief Get framebuffer width
uint getWidth() const;
/// @brief Get framebuffer height
uint getHeight() const;
}; };
#endif /* SRC_GRAPHICS_FRAMEBUFFER_H_ */ #endif /* SRC_GRAPHICS_FRAMEBUFFER_H_ */
+1 -1
View File
@@ -31,7 +31,7 @@ GfxContext::~GfxContext() {
fbo->unbind(); fbo->unbind();
} }
if (parent->fbo) { if (parent->fbo) {
fbo->bind(); parent->fbo->bind();
} }
} }
+42
View File
@@ -0,0 +1,42 @@
#include "PostProcessing.h"
#include "Mesh.h"
#include "Shader.h"
#include "Texture.h"
#include "Framebuffer.h"
#include <stdexcept>
PostProcessing::PostProcessing() {
// Fullscreen quad mesh bulding
float vertices[] {
-1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f,
-1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f
};
vattr attrs[] {{2}, {0}};
quadMesh = std::make_unique<Mesh>(vertices, 6, attrs);
}
PostProcessing::~PostProcessing() {
}
void PostProcessing::use(GfxContext& context) {
const auto& vp = context.getViewport();
if (fbo) {
fbo->resize(vp.getWidth(), vp.getHeight());
} else {
fbo = std::make_unique<Framebuffer>(vp.getWidth(), vp.getHeight());
}
context.setFramebuffer(fbo.get());
}
void PostProcessing::render(GfxContext& context, Shader* screenShader) {
if (fbo == nullptr) {
throw std::runtime_error("'use(...)' was never called");
}
const auto& viewport = context.getViewport();
screenShader->use();
screenShader->uniform2i("u_screenSize", viewport.size());
fbo->getTexture()->bind();
quadMesh->draw();
}
+37
View File
@@ -0,0 +1,37 @@
#ifndef GRAPHICS_POST_PROCESSING_H_
#define GRAPHICS_POST_PROCESSING_H_
#include "Viewport.h"
#include "GfxContext.h"
#include <memory>
class Mesh;
class Shader;
class Framebuffer;
/// @brief Framebuffer with blitting with shaders.
/// @attention Current implementation does not support multiple render passes
/// for multiple effects. Will be implemented in v0.21
class PostProcessing {
/// @brief Main framebuffer (lasy field)
std::unique_ptr<Framebuffer> fbo;
/// @brief Fullscreen quad mesh as the post-processing canvas
std::unique_ptr<Mesh> quadMesh;
public:
PostProcessing();
~PostProcessing();
/// @brief Prepare and bind framebuffer
/// @param context graphics context will be modified
void use(GfxContext& context);
/// @brief Render fullscreen quad using the passed shader
/// with framebuffer texture bound
/// @param context graphics context
/// @param screenShader shader used for fullscreen quad
/// @throws std::runtime_error if use(...) wasn't called before
void render(GfxContext& context, Shader* screenShader);
};
#endif // GRAPHICS_POST_PROCESSING_H_
+5
View File
@@ -52,6 +52,11 @@ void Shader::uniform2f(std::string name, glm::vec2 xy){
glUniform2f(transformLoc, xy.x, xy.y); glUniform2f(transformLoc, xy.x, xy.y);
} }
void Shader::uniform2i(std::string name, glm::ivec2 xy){
GLuint transformLoc = glGetUniformLocation(id, name.c_str());
glUniform2i(transformLoc, xy.x, xy.y);
}
void Shader::uniform3f(std::string name, float x, float y, float z){ void Shader::uniform3f(std::string name, float x, float y, float z){
GLuint transformLoc = glGetUniformLocation(id, name.c_str()); GLuint transformLoc = glGetUniformLocation(id, name.c_str());
glUniform3f(transformLoc, x,y,z); glUniform3f(transformLoc, x,y,z);
+1
View File
@@ -21,6 +21,7 @@ public:
void uniform1f(std::string name, float x); void uniform1f(std::string name, float x);
void uniform2f(std::string name, float x, float y); void uniform2f(std::string name, float x, float y);
void uniform2f(std::string name, glm::vec2 xy); void uniform2f(std::string name, glm::vec2 xy);
void uniform2i(std::string name, glm::ivec2 xy);
void uniform3f(std::string name, float x, float y, float z); void uniform3f(std::string name, float x, float y, float z);
void uniform3f(std::string name, glm::vec3 xyz); void uniform3f(std::string name, glm::vec3 xyz);
+2 -2
View File
@@ -14,8 +14,8 @@ public:
virtual uint getWidth() const; virtual uint getWidth() const;
virtual uint getHeight() const; virtual uint getHeight() const;
glm::vec2 size() const { glm::ivec2 size() const {
return glm::vec2(width, height); return glm::ivec2(width, height);
} }
}; };