diff options
| author | x2048 <codeforsmile@gmail.com> | 2023-01-06 22:33:25 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-01-06 22:33:25 +0100 |
| commit | 6d45c243f85942b20dab58753e735ec89a68f710 (patch) | |
| tree | bfe6207d73d1b111af82ea9e5794bdaac4ce26e3 /src/client/render | |
| parent | 2715cc8bf68a2cc8cd583cd5b0bb732ee13a1b49 (diff) | |
| download | minetest-6d45c243f85942b20dab58753e735ec89a68f710.tar.xz | |
Add dynamic exposure correction (#12959)
* Add uniform for frame delta time
* Adjust exposure in logarithmic (EV) space
* Add network support and LUA API
* Add testing mod
Diffstat (limited to 'src/client/render')
| -rw-r--r-- | src/client/render/pipeline.cpp | 20 | ||||
| -rw-r--r-- | src/client/render/pipeline.h | 44 | ||||
| -rw-r--r-- | src/client/render/secondstage.cpp | 55 |
3 files changed, 92 insertions, 27 deletions
diff --git a/src/client/render/pipeline.cpp b/src/client/render/pipeline.cpp index 13898f8a4..cc275a7ef 100644 --- a/src/client/render/pipeline.cpp +++ b/src/client/render/pipeline.cpp @@ -101,6 +101,16 @@ void TextureBuffer::reset(PipelineContext &context) RenderSource::reset(context); } +void TextureBuffer::swapTextures(u8 texture_a, u8 texture_b) +{ + assert(m_definitions[texture_a].valid && m_definitions[texture_b].valid); + + video::ITexture *temp = m_textures[texture_a]; + m_textures[texture_a] = m_textures[texture_b]; + m_textures[texture_b] = temp; +} + + bool TextureBuffer::ensureTexture(video::ITexture **texture, const TextureDefinition& definition, PipelineContext &context) { bool modify; @@ -230,6 +240,16 @@ void SetRenderTargetStep::run(PipelineContext &context) step->setRenderTarget(target); } +SwapTexturesStep::SwapTexturesStep(TextureBuffer *_buffer, u8 _texture_a, u8 _texture_b) + : buffer(_buffer), texture_a(_texture_a), texture_b(_texture_b) +{ +} + +void SwapTexturesStep::run(PipelineContext &context) +{ + buffer->swapTextures(texture_a, texture_b); +} + RenderSource *RenderPipeline::getInput() { return &m_input; diff --git a/src/client/render/pipeline.h b/src/client/render/pipeline.h index 354624102..bfdef2931 100644 --- a/src/client/render/pipeline.h +++ b/src/client/render/pipeline.h @@ -53,7 +53,7 @@ struct PipelineContext /** * Base object that can be owned by RenderPipeline - * + * */ class RenderPipelineObject { @@ -74,7 +74,7 @@ public: virtual u8 getTextureCount() = 0; /** - * Get a texture by index. + * Get a texture by index. * Returns nullptr is the texture does not exist. */ virtual video::ITexture *getTexture(u8 index) = 0; @@ -119,7 +119,7 @@ public: /** * Configure fixed-size texture for the specific index - * + * * @param index index of the texture * @param size width and height of the texture in pixels * @param height height of the texture in pixels @@ -130,7 +130,7 @@ public: /** * Configure relative-size texture for the specific index - * + * * @param index index of the texture * @param scale_factor relation of the texture dimensions to the screen dimensions * @param name unique name of the texture @@ -141,6 +141,7 @@ public: virtual u8 getTextureCount() override { return m_textures.size(); } virtual video::ITexture *getTexture(u8 index) override; virtual void reset(PipelineContext &context) override; + void swapTextures(u8 texture_a, u8 texture_b); private: static const u8 NO_DEPTH_TEXTURE = 255; @@ -193,7 +194,7 @@ private: /** * Allows remapping texture indicies in another RenderSource. - * + * * @note all unmapped indexes are passed through to the underlying render source. */ class RemappingSource : RenderSource @@ -205,7 +206,7 @@ public: /** * Maps texture index to a different index in the dependent source. - * + * * @param index texture index as requested by the @see RenderStep. * @param target_index matching texture index in the underlying @see RenderSource. */ @@ -250,7 +251,7 @@ public: virtual u8 getTextureCount() override; /** - * Get a texture by index. + * Get a texture by index. * Returns nullptr is the texture does not exist. */ virtual video::ITexture *getTexture(u8 index) override; @@ -288,14 +289,14 @@ class RenderStep : virtual public RenderPipelineObject public: /** * Assigns render source to this step. - * + * * @param source source of rendering information */ virtual void setRenderSource(RenderSource *source) = 0; /** * Assigned render target to this step. - * + * * @param target render target to send output to. */ virtual void setRenderTarget(RenderTarget *target) = 0; @@ -319,7 +320,7 @@ public: /** * Dynamically changes render target of another step. - * + * * This allows re-running parts of the pipeline with different outputs */ class SetRenderTargetStep : public TrivialRenderStep @@ -333,8 +334,23 @@ private: }; /** + * Swaps two textures in the texture buffer. + * + */ +class SwapTexturesStep : public TrivialRenderStep +{ +public: + SwapTexturesStep(TextureBuffer *buffer, u8 texture_a, u8 texture_b); + virtual void run(PipelineContext &context) override; +private: + TextureBuffer *buffer; + u8 texture_a; + u8 texture_b; +}; + +/** * Render Pipeline provides a flexible way to execute rendering steps in the engine. - * + * * RenderPipeline also implements @see RenderStep, allowing for nesting of the pipelines. */ class RenderPipeline : public RenderStep @@ -342,7 +358,7 @@ class RenderPipeline : public RenderStep public: /** * Add a step to the end of the pipeline - * + * * @param step reference to a @see RenderStep implementation. */ RenderStep *addStep(RenderStep *step) @@ -353,9 +369,9 @@ public: /** * Capture ownership of a dynamically created @see RenderStep instance. - * + * * RenderPipeline will delete the instance when the pipeline is destroyed. - * + * * @param step reference to the instance. * @return RenderStep* value of the 'step' parameter. */ diff --git a/src/client/render/secondstage.cpp b/src/client/render/secondstage.cpp index ebc7e7411..395a0fe6b 100644 --- a/src/client/render/secondstage.cpp +++ b/src/client/render/secondstage.cpp @@ -115,10 +115,14 @@ RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep static const u8 TEXTURE_COLOR = 0; static const u8 TEXTURE_DEPTH = 1; static const u8 TEXTURE_BLOOM = 2; + static const u8 TEXTURE_EXPOSURE_1 = 3; + static const u8 TEXTURE_EXPOSURE_2 = 4; static const u8 TEXTURE_BLOOM_DOWN = 10; static const u8 TEXTURE_BLOOM_UP = 20; buffer->setTexture(TEXTURE_COLOR, scale, "3d_render", color_format); + buffer->setTexture(TEXTURE_EXPOSURE_1, core::dimension2du(1,1), "exposure_1", color_format); + buffer->setTexture(TEXTURE_EXPOSURE_2, core::dimension2du(1,1), "exposure_2", color_format); buffer->setTexture(TEXTURE_DEPTH, scale, "3d_depthmap", depth_format); // attach buffer to the previous step @@ -127,30 +131,40 @@ RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep // shared variables u32 shader_id; + // Number of mipmap levels of the bloom downsampling texture + const u8 MIPMAP_LEVELS = 4; + + const bool enable_bloom = g_settings->getBool("enable_bloom"); + const bool enable_auto_exposure = g_settings->getBool("enable_auto_exposure"); + // post-processing stage - // set up bloom - if (g_settings->getBool("enable_bloom")) { + u8 source = TEXTURE_COLOR; - buffer->setTexture(TEXTURE_BLOOM, scale, "bloom", color_format); + // common downsampling step for bloom or autoexposure + if (enable_bloom || enable_auto_exposure) { - const u8 MIPMAP_LEVELS = 4; v2f downscale = scale * 0.5; for (u8 i = 0; i < MIPMAP_LEVELS; i++) { - buffer->setTexture(TEXTURE_BLOOM_DOWN + i, downscale, std::string("bloom_down") + std::to_string(i), color_format); - buffer->setTexture(TEXTURE_BLOOM_UP + i, downscale, std::string("bloom_up") + std::to_string(i), color_format); + buffer->setTexture(TEXTURE_BLOOM_DOWN + i, downscale, std::string("downsample") + std::to_string(i), color_format); + if (enable_bloom) + buffer->setTexture(TEXTURE_BLOOM_UP + i, downscale, std::string("upsample") + std::to_string(i), color_format); downscale *= 0.5; } - // 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, TEXTURE_BLOOM)); + if (enable_bloom) { + buffer->setTexture(TEXTURE_BLOOM, scale, "bloom", color_format); + + // 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, TEXTURE_EXPOSURE_1 }); + extract_bloom->setRenderSource(buffer); + extract_bloom->setRenderTarget(pipeline->createOwned<TextureBufferOutput>(buffer, TEXTURE_BLOOM)); + source = TEXTURE_BLOOM; + } // downsample shader_id = client->getShaderSource()->getShader("bloom_downsample", TILE_MATERIAL_PLAIN, NDT_MESH); - u8 source = TEXTURE_BLOOM; for (u8 i = 0; i < MIPMAP_LEVELS; i++) { auto step = pipeline->addStep<PostProcessingStep>(shader_id, std::vector<u8> { source }); step->setRenderSource(buffer); @@ -158,7 +172,9 @@ RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep step->setRenderTarget(pipeline->createOwned<TextureBufferOutput>(buffer, TEXTURE_BLOOM_DOWN + i)); source = TEXTURE_BLOOM_DOWN + i; } + } + if (enable_bloom) { // upsample shader_id = client->getShaderSource()->getShader("bloom_upsample", TILE_MATERIAL_PLAIN, NDT_MESH); for (u8 i = MIPMAP_LEVELS - 1; i > 0; i--) { @@ -171,11 +187,24 @@ RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep } } + if (enable_auto_exposure) { + shader_id = client->getShaderSource()->getShader("update_exposure", TILE_MATERIAL_PLAIN, NDT_MESH); + auto update_exposure = pipeline->addStep<PostProcessingStep>(shader_id, std::vector<u8> { TEXTURE_EXPOSURE_1, u8(TEXTURE_BLOOM_DOWN + MIPMAP_LEVELS - 1) }); + update_exposure->setBilinearFilter(1, true); + update_exposure->setRenderSource(buffer); + update_exposure->setRenderTarget(pipeline->createOwned<TextureBufferOutput>(buffer, TEXTURE_EXPOSURE_2)); + } + // final post-processing 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_UP }); + PostProcessingStep *effect = pipeline->createOwned<PostProcessingStep>(shader_id, std::vector<u8> { TEXTURE_COLOR, TEXTURE_BLOOM_UP, TEXTURE_EXPOSURE_2 }); pipeline->addStep(effect); effect->setBilinearFilter(1, true); // apply filter to the bloom effect->setRenderSource(buffer); + + if (enable_auto_exposure) { + pipeline->addStep<SwapTexturesStep>(buffer, TEXTURE_EXPOSURE_1, TEXTURE_EXPOSURE_2); + } + return effect; } |
