diff options
| author | x2048 <codeforsmile@gmail.com> | 2022-09-29 20:34:05 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-09-29 20:34:05 +0200 |
| commit | 9df79a4b2d68979c3e15797d518d957787ba4e21 (patch) | |
| tree | 027f372a420f1aa3aa72bf72de34c5e6062b9090 /src/client/render | |
| parent | 3978b9b8ed1c318c3f9a088beb331c26bca6de6b (diff) | |
| download | minetest-9df79a4b2d68979c3e15797d518d957787ba4e21.tar.xz | |
Bloom (#12791)
Adds configurable light exposure control and bloom effect (light bleeding) with client-side settings.
Diffstat (limited to 'src/client/render')
| -rw-r--r-- | src/client/render/pipeline.cpp | 101 | ||||
| -rw-r--r-- | src/client/render/pipeline.h | 36 | ||||
| -rw-r--r-- | src/client/render/secondstage.cpp | 66 | ||||
| -rw-r--r-- | src/client/render/secondstage.h | 18 |
4 files changed, 124 insertions, 97 deletions
diff --git a/src/client/render/pipeline.cpp b/src/client/render/pipeline.cpp index baf215d8e..eb38adbad 100644 --- a/src/client/render/pipeline.cpp +++ b/src/client/render/pipeline.cpp @@ -27,9 +27,6 @@ with this program; if not, write to the Free Software Foundation, Inc., TextureBuffer::~TextureBuffer() { - if (m_render_target) - m_driver->removeRenderTarget(m_render_target); - m_render_target = nullptr; for (u32 index = 0; index < m_textures.size(); index++) m_driver->removeTexture(m_textures[index]); m_textures.clear(); @@ -37,8 +34,6 @@ TextureBuffer::~TextureBuffer() video::ITexture *TextureBuffer::getTexture(u8 index) { - if (index == m_depth_texture_index) - return m_depth_texture; if (index >= m_textures.size()) return nullptr; return m_textures[index]; @@ -52,9 +47,6 @@ void TextureBuffer::setTexture(u8 index, core::dimension2du size, const std::str if (m_definitions.size() <= index) m_definitions.resize(index + 1); - if (m_depth_texture_index == index) - m_depth_texture_index = NO_DEPTH_TEXTURE; - auto &definition = m_definitions[index]; definition.valid = true; definition.dirty = true; @@ -71,9 +63,6 @@ void TextureBuffer::setTexture(u8 index, v2f scale_factor, const std::string &na if (m_definitions.size() <= index) m_definitions.resize(index + 1); - if (m_depth_texture_index == index) - m_depth_texture_index = NO_DEPTH_TEXTURE; - auto &definition = m_definitions[index]; definition.valid = true; definition.dirty = true; @@ -83,20 +72,6 @@ void TextureBuffer::setTexture(u8 index, v2f scale_factor, const std::string &na definition.format = format; } -void TextureBuffer::setDepthTexture(u8 index, core::dimension2du size, const std::string &name, video::ECOLOR_FORMAT format) -{ - assert(index != NO_DEPTH_TEXTURE); - setTexture(index, size, name, format); - m_depth_texture_index = index; -} - -void TextureBuffer::setDepthTexture(u8 index, v2f scale_factor, const std::string &name, video::ECOLOR_FORMAT format) -{ - assert(index != NO_DEPTH_TEXTURE); - setTexture(index, scale_factor, name, format); - m_depth_texture_index = index; -} - void TextureBuffer::reset(PipelineContext &context) { if (!m_driver) @@ -116,41 +91,14 @@ void TextureBuffer::reset(PipelineContext &context) m_textures.push_back(nullptr); // change textures to match definitions - bool modified = false; for (u32 i = 0; i < m_definitions.size(); i++) { video::ITexture **ptr = &m_textures[i]; - if (i == m_depth_texture_index) { - if (*ptr) { - m_driver->removeTexture(*ptr); - *ptr = nullptr; - } - ptr = &m_depth_texture; - } - - if (ensureTexture(ptr, m_definitions[i], context)) - modified = true; + + ensureTexture(ptr, m_definitions[i], context); m_definitions[i].dirty = false; } - // make sude depth texture is removed and reset - if (m_depth_texture_index == NO_DEPTH_TEXTURE && m_depth_texture) { - m_driver->removeTexture(m_depth_texture); - m_depth_texture = nullptr; - } - - if (!m_render_target) - m_render_target = m_driver->addRenderTarget(); - - if (modified) - m_render_target->setTexture(m_textures, m_depth_texture); - - RenderTarget::reset(context); -} - -void TextureBuffer::activate(PipelineContext &context) -{ - m_driver->setRenderTargetEx(m_render_target, m_clear ? video::ECBF_DEPTH | video::ECBF_COLOR : 0, context.clear_color); - RenderTarget::activate(context); + RenderSource::reset(context); } bool TextureBuffer::ensureTexture(video::ITexture **texture, const TextureDefinition& definition, PipelineContext &context) @@ -186,15 +134,48 @@ bool TextureBuffer::ensureTexture(video::ITexture **texture, const TextureDefini } TextureBufferOutput::TextureBufferOutput(TextureBuffer *_buffer, u8 _texture_index) - : buffer(_buffer), texture_index(_texture_index) + : buffer(_buffer), texture_map({_texture_index}) +{} + +TextureBufferOutput::TextureBufferOutput(TextureBuffer *_buffer, const std::vector<u8> &_texture_map) + : buffer(_buffer), texture_map(_texture_map) +{} + +TextureBufferOutput::TextureBufferOutput(TextureBuffer *_buffer, const std::vector<u8> &_texture_map, u8 _depth_stencil) + : buffer(_buffer), texture_map(_texture_map), depth_stencil(_depth_stencil) {} +TextureBufferOutput::~TextureBufferOutput() +{ + if (render_target && driver) + driver->removeRenderTarget(render_target); +} + void TextureBufferOutput::activate(PipelineContext &context) { - auto texture = buffer->getTexture(texture_index); - auto driver = context.device->getVideoDriver(); - driver->setRenderTarget(texture, m_clear, m_clear, context.clear_color); - driver->OnResize(texture->getSize()); + if (!driver) + driver = context.device->getVideoDriver(); + + if (!render_target) + render_target = driver->addRenderTarget(); + + core::array<video::ITexture *> textures; + core::dimension2du size(0, 0); + for (size_t i = 0; i < texture_map.size(); i++) { + video::ITexture *texture = buffer->getTexture(texture_map[i]); + textures.push_back(texture); + if (texture && size.Width == 0) + size = texture->getSize(); + } + + video::ITexture *depth_texture = nullptr; + if (depth_stencil != NO_DEPTH_TEXTURE) + depth_texture = buffer->getTexture(depth_stencil); + + render_target->setTexture(textures, depth_texture); + + driver->setRenderTargetEx(render_target, m_clear ? video::ECBF_ALL : video::ECBF_NONE, context.clear_color); + driver->OnResize(size); RenderTarget::activate(context); } diff --git a/src/client/render/pipeline.h b/src/client/render/pipeline.h index 4a6df7de2..771c6f1d5 100644 --- a/src/client/render/pipeline.h +++ b/src/client/render/pipeline.h @@ -112,7 +112,7 @@ protected: * * @note Use of TextureBuffer requires use of gl_FragData[] in the shader */ -class TextureBuffer : public RenderSource, public RenderTarget +class TextureBuffer : public RenderSource { public: virtual ~TextureBuffer() override; @@ -138,29 +138,8 @@ public: */ void setTexture(u8 index, v2f scale_factor, const std::string& name, video::ECOLOR_FORMAT format); - /** - * @Configure depth texture and assign index - * - * @param index index to use for the depth texture - * @param size width and height of the texture in pixels - * @param name unique name for the texture - * @param format color format - */ - void setDepthTexture(u8 index, core::dimension2du size, const std::string& name, video::ECOLOR_FORMAT format); - - /** - * @Configure depth texture and assign index - * - * @param index index to use for the depth texture - * @param scale_factor relation of the texture dimensions to the screen dimensions - * @param name unique name for the texture - * @param format color format - */ - void setDepthTexture(u8 index, v2f scale_factor, const std::string& name, video::ECOLOR_FORMAT format); - virtual u8 getTextureCount() override { return m_textures.size(); } virtual video::ITexture *getTexture(u8 index) override; - virtual void activate(PipelineContext &context) override; virtual void reset(PipelineContext &context) override; private: static const u8 NO_DEPTH_TEXTURE = 255; @@ -189,9 +168,6 @@ private: video::IVideoDriver *m_driver { nullptr }; std::vector<TextureDefinition> m_definitions; core::array<video::ITexture *> m_textures; - video::ITexture *m_depth_texture { nullptr }; - u8 m_depth_texture_index { NO_DEPTH_TEXTURE }; - video::IRenderTarget *m_render_target { nullptr }; }; /** @@ -201,10 +177,18 @@ class TextureBufferOutput : public RenderTarget { public: TextureBufferOutput(TextureBuffer *buffer, u8 texture_index); + TextureBufferOutput(TextureBuffer *buffer, const std::vector<u8> &texture_map); + TextureBufferOutput(TextureBuffer *buffer, const std::vector<u8> &texture_map, u8 depth_stencil); + virtual ~TextureBufferOutput() override; void activate(PipelineContext &context) override; private: + static const u8 NO_DEPTH_TEXTURE = 255; + TextureBuffer *buffer; - u8 texture_index; + std::vector<u8> texture_map; + u8 depth_stencil { NO_DEPTH_TEXTURE }; + video::IRenderTarget* render_target { nullptr }; + video::IVideoDriver* driver { nullptr }; }; /** diff --git a/src/client/render/secondstage.cpp b/src/client/render/secondstage.cpp index 8f6f59537..860b277bd 100644 --- a/src/client/render/secondstage.cpp +++ b/src/client/render/secondstage.cpp @@ -88,31 +88,77 @@ void PostProcessingStep::run(PipelineContext &context) driver->drawVertexPrimitiveList(&vertices, 4, &indices, 2); } +void PostProcessingStep::setBilinearFilter(u8 index, bool value) +{ + assert(index < video::MATERIAL_MAX_TEXTURES); + material.TextureLayer[index].BilinearFilter = value; +} + RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep, v2f scale, Client *client) { auto buffer = pipeline->createOwned<TextureBuffer>(); - static const u8 TEXTURE_COLOR = 0; - static const u8 TEXTURE_DEPTH = 3; + auto driver = client->getSceneManager()->getVideoDriver(); - // init post-processing buffer - buffer->setTexture(TEXTURE_COLOR, scale, "3d_render", video::ECF_A8R8G8B8); + // configure texture formats + video::ECOLOR_FORMAT color_format = video::ECF_A8R8G8B8; + if (driver->queryTextureFormat(video::ECF_A16B16G16R16F)) + color_format = video::ECF_A16B16G16R16F; video::ECOLOR_FORMAT depth_format = video::ECF_D16; // fallback depth format - auto driver = client->getSceneManager()->getVideoDriver(); if (driver->queryTextureFormat(video::ECF_D32)) depth_format = video::ECF_D32; else if (driver->queryTextureFormat(video::ECF_D24S8)) depth_format = video::ECF_D24S8; - buffer->setDepthTexture(TEXTURE_DEPTH, scale, "3d_depthmap", depth_format); + + + // init post-processing buffer + static const u8 TEXTURE_COLOR = 0; + static const u8 TEXTURE_DEPTH = 1; + static const u8 TEXTURE_BLOOM = 2; + static const u8 TEXTURE_BLUR = 3; + static const u8 TEXTURE_BLUR_SECONDARY = 4; + + buffer->setTexture(TEXTURE_COLOR, scale, "3d_render", color_format); + buffer->setTexture(TEXTURE_DEPTH, scale, "3d_depthmap", depth_format); // attach buffer to the previous step - previousStep->setRenderTarget(buffer); + previousStep->setRenderTarget(pipeline->createOwned<TextureBufferOutput>(buffer, std::vector<u8> { TEXTURE_COLOR }, TEXTURE_DEPTH)); // post-processing stage - // set up shader - u32 shader_id = client->getShaderSource()->getShader("second_stage", TILE_MATERIAL_PLAIN, NDT_MESH); + // set up bloom + if (g_settings->getBool("enable_bloom")) { + + buffer->setTexture(TEXTURE_BLUR, scale * 0.5, "blur", color_format); + buffer->setTexture(TEXTURE_BLOOM, scale * 0.5, "bloom", color_format); + u8 bloom_input_texture = TEXTURE_BLOOM; + + if (g_settings->getBool("enable_bloom_dedicated_texture")) { + buffer->setTexture(TEXTURE_BLUR_SECONDARY, scale * 0.5, "blur2", color_format); + bloom_input_texture = TEXTURE_BLUR_SECONDARY; + } + + // get bright spots + u32 shader_id = client->getShaderSource()->getShader("extract_bloom", TILE_MATERIAL_PLAIN, NDT_MESH); + RenderStep *extract_bloom = pipeline->addStep<PostProcessingStep>(shader_id, std::vector<u8> { TEXTURE_COLOR }); + extract_bloom->setRenderSource(buffer); + extract_bloom->setRenderTarget(pipeline->createOwned<TextureBufferOutput>(buffer, bloom_input_texture)); + // horizontal blur + shader_id = client->getShaderSource()->getShader("blur_h", TILE_MATERIAL_PLAIN, NDT_MESH); + RenderStep *blur_h = pipeline->addStep<PostProcessingStep>(shader_id, std::vector<u8> { bloom_input_texture }); + blur_h->setRenderSource(buffer); + blur_h->setRenderTarget(pipeline->createOwned<TextureBufferOutput>(buffer, TEXTURE_BLUR)); + // vertical blur + shader_id = client->getShaderSource()->getShader("blur_v", TILE_MATERIAL_PLAIN, NDT_MESH); + RenderStep *blur_v = pipeline->addStep<PostProcessingStep>(shader_id, std::vector<u8> { TEXTURE_BLUR }); + blur_v->setRenderSource(buffer); + blur_v->setRenderTarget(pipeline->createOwned<TextureBufferOutput>(buffer, TEXTURE_BLOOM)); + } - RenderStep *effect = pipeline->addStep<PostProcessingStep>(shader_id, std::vector<u8> { TEXTURE_COLOR }); + // final post-processing + u32 shader_id = client->getShaderSource()->getShader("second_stage", TILE_MATERIAL_PLAIN, NDT_MESH); + PostProcessingStep *effect = pipeline->createOwned<PostProcessingStep>(shader_id, std::vector<u8> { TEXTURE_COLOR, TEXTURE_BLOOM }); + pipeline->addStep(effect); + effect->setBilinearFilter(1, true); // apply filter to the bloom effect->setRenderSource(buffer); return effect; } diff --git a/src/client/render/secondstage.h b/src/client/render/secondstage.h index 0c3c0a447..37d5b5071 100644 --- a/src/client/render/secondstage.h +++ b/src/client/render/secondstage.h @@ -22,17 +22,33 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "stereo.h" #include "pipeline.h" +/** + * Step to apply post-processing filter to the rendered image + */ class PostProcessingStep : public RenderStep { public: + /** + * Construct a new PostProcessingStep object + * + * @param shader_id ID of the shader in IShaderSource + * @param texture_map Map of textures to be chosen from the render source + */ PostProcessingStep(u32 shader_id, const std::vector<u8> &texture_map); - + void setRenderSource(RenderSource *source) override; void setRenderTarget(RenderTarget *target) override; void reset(PipelineContext &context) override; void run(PipelineContext &context) override; + /** + * Configure bilinear filtering for a specific texture layer + * + * @param index Index of the texture layer + * @param value true to enable the bilinear filter, false to disable + */ + void setBilinearFilter(u8 index, bool value); private: u32 shader_id; std::vector<u8> texture_map; |
