aboutsummaryrefslogtreecommitdiff
path: root/src/client/render
diff options
context:
space:
mode:
authorx2048 <codeforsmile@gmail.com>2023-01-06 22:33:25 +0100
committerGitHub <noreply@github.com>2023-01-06 22:33:25 +0100
commit6d45c243f85942b20dab58753e735ec89a68f710 (patch)
treebfe6207d73d1b111af82ea9e5794bdaac4ce26e3 /src/client/render
parent2715cc8bf68a2cc8cd583cd5b0bb732ee13a1b49 (diff)
downloadminetest-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.cpp20
-rw-r--r--src/client/render/pipeline.h44
-rw-r--r--src/client/render/secondstage.cpp55
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;
}