1
0
Fork 0
mirror of https://github.com/luanti-org/luanti.git synced 2025-09-10 18:51:05 +00:00

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
This commit is contained in:
x2048 2023-01-06 22:33:25 +01:00 committed by GitHub
parent 2715cc8bf6
commit 6d45c243f8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
29 changed files with 567 additions and 71 deletions

View file

@ -375,6 +375,7 @@ set(common_SRCS
itemdef.cpp
itemstackmetadata.cpp
light.cpp
lighting.cpp
log.cpp
main.cpp
map.cpp

View file

@ -531,8 +531,13 @@ void ClientEnvironment::updateFrameTime(bool is_paused)
{
// if paused, m_frame_time_pause_accumulator increases by dtime,
// otherwise, m_frame_time increases by dtime
if (is_paused)
if (is_paused) {
m_frame_dtime = 0;
m_frame_time_pause_accumulator = porting::getTimeMs() - m_frame_time;
else
m_frame_time = porting::getTimeMs() - m_frame_time_pause_accumulator;
}
else {
auto new_frame_time = porting::getTimeMs() - m_frame_time_pause_accumulator;
m_frame_dtime = new_frame_time - MYMAX(m_frame_time, m_frame_time_pause_accumulator);
m_frame_time = new_frame_time;
}
}

View file

@ -144,6 +144,7 @@ public:
void updateFrameTime(bool is_paused);
u64 getFrameTime() const { return m_frame_time; }
u64 getFrameTimeDelta() const { return m_frame_dtime; }
private:
ClientMap *m_map;
@ -158,5 +159,6 @@ private:
std::list<std::string> m_player_names;
v3s16 m_camera_offset;
u64 m_frame_time = 0;
u64 m_frame_dtime = 0;
u64 m_frame_time_pause_accumulator = 0;
};

View file

@ -414,6 +414,8 @@ class GameGlobalShaderConstantSetter : public IShaderConstantSetter
CachedPixelShaderSetting<float> m_fog_distance;
CachedVertexShaderSetting<float> m_animation_timer_vertex;
CachedPixelShaderSetting<float> m_animation_timer_pixel;
CachedVertexShaderSetting<float> m_animation_timer_delta_vertex;
CachedPixelShaderSetting<float> m_animation_timer_delta_pixel;
CachedPixelShaderSetting<float, 3> m_day_light;
CachedPixelShaderSetting<float, 4> m_star_color;
CachedPixelShaderSetting<float, 3> m_eye_position_pixel;
@ -427,8 +429,8 @@ class GameGlobalShaderConstantSetter : public IShaderConstantSetter
CachedPixelShaderSetting<SamplerLayer_t> m_texture3;
CachedPixelShaderSetting<float, 2> m_texel_size0;
std::array<float, 2> m_texel_size0_values;
CachedPixelShaderSetting<float> m_exposure_factor_pixel;
float m_user_exposure_factor;
CachedStructPixelShaderSetting<float, 7> m_exposure_params_pixel;
float m_user_exposure_compensation;
bool m_bloom_enabled;
CachedPixelShaderSetting<float> m_bloom_intensity_pixel;
float m_bloom_intensity;
@ -443,8 +445,8 @@ public:
{
if (name == "enable_fog")
m_fog_enabled = g_settings->getBool("enable_fog");
if (name == "exposure_factor")
m_user_exposure_factor = g_settings->getFloat("exposure_factor", 0.1f, 10.0f);
if (name == "exposure_compensation")
m_user_exposure_compensation = g_settings->getFloat("exposure_compensation", -1.0f, 1.0f);
if (name == "bloom_intensity")
m_bloom_intensity = g_settings->getFloat("bloom_intensity", 0.01f, 1.0f);
if (name == "bloom_strength_factor")
@ -470,6 +472,8 @@ public:
m_fog_distance("fogDistance"),
m_animation_timer_vertex("animationTimer"),
m_animation_timer_pixel("animationTimer"),
m_animation_timer_delta_vertex("animationTimerDelta"),
m_animation_timer_delta_pixel("animationTimerDelta"),
m_day_light("dayLight"),
m_star_color("starColor"),
m_eye_position_pixel("eyePosition"),
@ -482,20 +486,24 @@ public:
m_texture2("texture2"),
m_texture3("texture3"),
m_texel_size0("texelSize0"),
m_exposure_factor_pixel("exposureFactor"),
m_exposure_params_pixel("exposureParams",
std::array<const char*, 7> {
"luminanceMin", "luminanceMax", "exposureCorrection",
"speedDarkBright", "speedBrightDark", "centerWeightPower", "compensationFactor"
}),
m_bloom_intensity_pixel("bloomIntensity"),
m_bloom_strength_pixel("bloomStrength"),
m_bloom_radius_pixel("bloomRadius"),
m_saturation_pixel("saturation")
{
g_settings->registerChangedCallback("enable_fog", settingsCallback, this);
g_settings->registerChangedCallback("exposure_factor", settingsCallback, this);
g_settings->registerChangedCallback("exposure_compensation", settingsCallback, this);
g_settings->registerChangedCallback("bloom_intensity", settingsCallback, this);
g_settings->registerChangedCallback("bloom_strength_factor", settingsCallback, this);
g_settings->registerChangedCallback("bloom_radius", settingsCallback, this);
g_settings->registerChangedCallback("saturation", settingsCallback, this);
m_fog_enabled = g_settings->getBool("enable_fog");
m_user_exposure_factor = g_settings->getFloat("exposure_factor", 0.1f, 10.0f);
m_user_exposure_compensation = g_settings->getFloat("exposure_compensation", -1.0f, 1.0f);
m_bloom_enabled = g_settings->getBool("enable_bloom");
m_bloom_intensity = g_settings->getFloat("bloom_intensity", 0.01f, 1.0f);
m_bloom_strength = RenderingEngine::BASE_BLOOM_STRENGTH * g_settings->getFloat("bloom_strength_factor", 0.1f, 10.0f);
@ -546,6 +554,10 @@ public:
m_animation_timer_vertex.set(&animation_timer_f, services);
m_animation_timer_pixel.set(&animation_timer_f, services);
float animation_timer_delta_f = (float)m_client->getEnv().getFrameTimeDelta() / 100000.f;
m_animation_timer_delta_vertex.set(&animation_timer_delta_f, services);
m_animation_timer_delta_pixel.set(&animation_timer_delta_f, services);
float eye_position_array[3];
v3f epos = m_client->getEnv().getLocalPlayer()->getEyePosition();
epos.getAs3Values(eye_position_array);
@ -577,10 +589,17 @@ public:
m_texel_size0.set(m_texel_size0_values.data(), services);
float exposure_factor = m_user_exposure_factor;
if (std::isnan(exposure_factor))
exposure_factor = 1.0f;
m_exposure_factor_pixel.set(&exposure_factor, services);
const AutoExposure &exposure_params = m_client->getEnv().getLocalPlayer()->getLighting().exposure;
std::array<float, 7> exposure_buffer = {
std::pow(2.0f, exposure_params.luminance_min),
std::pow(2.0f, exposure_params.luminance_max),
exposure_params.exposure_correction,
exposure_params.speed_dark_bright,
exposure_params.speed_bright_dark,
exposure_params.center_weight_power,
powf(2.f, m_user_exposure_compensation)
};
m_exposure_params_pixel.set(exposure_buffer.data(), services);
if (m_bloom_enabled) {
m_bloom_intensity_pixel.set(&m_bloom_intensity, services);

View file

@ -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;

View file

@ -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
@ -332,9 +333,24 @@ private:
RenderTarget *target;
};
/**
* 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.
*/

View file

@ -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;
}

View file

@ -56,7 +56,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#endif
RenderingEngine *RenderingEngine::s_singleton = nullptr;
const float RenderingEngine::BASE_BLOOM_STRENGTH = 8.0f;
const float RenderingEngine::BASE_BLOOM_STRENGTH = 1.0f;
static gui::GUISkin *createSkin(gui::IGUIEnvironment *environment,

View file

@ -784,6 +784,9 @@ ShaderInfo ShaderSource::generateShader(const std::string &name,
shaders_header << "#define ENABLE_BLOOM_DEBUG 1\n";
}
if (g_settings->getBool("enable_auto_exposure"))
shaders_header << "#define ENABLE_AUTO_EXPOSURE 1\n";
shaders_header << "#line 0\n"; // reset the line counter for meaningful diagnostics
std::string common_header = shaders_header.str();

View file

@ -121,6 +121,43 @@ public:
CachedShaderSetting<T, count, cache>(name, false){}
};
template <typename T, std::size_t count, bool cache, bool is_pixel>
class CachedStructShaderSetting {
const char *m_name;
T m_sent[count];
bool has_been_set = false;
std::array<const char*, count> m_fields;
public:
CachedStructShaderSetting(const char *name, std::array<const char*, count> &&fields) :
m_name(name), m_fields(std::move(fields))
{}
void set(const T value[count], video::IMaterialRendererServices *services)
{
if (cache && has_been_set && std::equal(m_sent, m_sent + count, value))
return;
for (std::size_t i = 0; i < count; i++) {
std::string uniform_name = std::string(m_name) + "." + m_fields[i];
if (is_pixel)
services->setPixelShaderConstant(services->getPixelShaderConstantID(uniform_name.c_str()), value + i, 1);
else
services->setVertexShaderConstant(services->getVertexShaderConstantID(uniform_name.c_str()), value + i, 1);
}
if (cache) {
std::copy(value, value + count, m_sent);
has_been_set = true;
}
}
};
template<typename T, std::size_t count, bool cache = true>
using CachedStructVertexShaderSetting = CachedStructShaderSetting<T, count, cache, false>;
template<typename T, std::size_t count, bool cache = true>
using CachedStructPixelShaderSetting = CachedStructShaderSetting<T, count, cache, true>;
/*
ShaderSource creates and caches shaders.

View file

@ -278,7 +278,8 @@ void set_default_settings()
settings->setDefault("water_wave_speed", "5.0");
settings->setDefault("enable_waving_leaves", "false");
settings->setDefault("enable_waving_plants", "false");
settings->setDefault("exposure_factor", "1.0");
settings->setDefault("exposure_compensation", "0.0");
settings->setDefault("enable_auto_exposure", "false");
settings->setDefault("enable_bloom", "false");
settings->setDefault("enable_bloom_debug", "false");
settings->setDefault("bloom_strength_factor", "1.0");

29
src/lighting.cpp Normal file
View file

@ -0,0 +1,29 @@
/*
Minetest
Copyright (C) 2021 x2048, Dmitry Kostenko <codeforsmile@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "lighting.h"
AutoExposure::AutoExposure()
: luminance_min(-3.f),
luminance_max(-3.f),
exposure_correction(0.0f),
speed_dark_bright(1000.f),
speed_bright_dark(1000.f),
center_weight_power(1.f)
{}

View file

@ -19,10 +19,38 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#pragma once
/**
* Parameters for automatic exposure compensation
*
* Automatic exposure compensation uses the following equation:
*
* wanted_exposure = 2^exposure_correction / clamp(observed_luminance, 2^luminance_min, 2^luminance_max)
*
*/
struct AutoExposure
{
/// @brief Minimum boundary for computed luminance
float luminance_min;
/// @brief Maximum boundary for computed luminance
float luminance_max;
/// @brief Luminance bias. Higher values make the scene darker, can be negative.
float exposure_correction;
/// @brief Speed of transition from dark to bright scenes
float speed_dark_bright;
/// @brief Speed of transition from bright to dark scenes
float speed_bright_dark;
/// @brief Power value for center-weighted metering. Value of 1.0 measures entire screen uniformly
float center_weight_power;
AutoExposure();
};
/** Describes ambient light settings for a player
*/
struct Lighting
{
AutoExposure exposure;
float shadow_intensity {0.0f};
float saturation {1.0f};
};

View file

@ -1766,4 +1766,12 @@ void Client::handleCommand_SetLighting(NetworkPacket *pkt)
*pkt >> lighting.shadow_intensity;
if (pkt->getRemainingBytes() >= 4)
*pkt >> lighting.saturation;
if (pkt->getRemainingBytes() >= 24) {
*pkt >> lighting.exposure.luminance_min
>> lighting.exposure.luminance_max
>> lighting.exposure.exposure_correction
>> lighting.exposure.speed_dark_bright
>> lighting.exposure.speed_bright_dark
>> lighting.exposure.center_weight_power;
}
}

View file

@ -831,6 +831,13 @@ enum ToClientCommand
/*
f32 shadow_intensity
f32 saturation
exposure parameters
f32 luminance_min
f32 luminance_max
f32 exposure_correction
f32 speed_dark_bright
f32 speed_bright_dark
f32 center_weight_power
*/
TOCLIENT_NUM_MSG_TYPES = 0x64,

View file

@ -2297,8 +2297,20 @@ int ObjectRef::l_set_lighting(lua_State *L)
getfloatfield(L, -1, "intensity", lighting.shadow_intensity);
}
lua_pop(L, 1); // shadows
getfloatfield(L, -1, "saturation", lighting.saturation);
lua_getfield(L, 2, "exposure");
if (lua_istable(L, -1)) {
lighting.exposure.luminance_min = getfloatfield_default(L, -1, "luminance_min", lighting.exposure.luminance_min);
lighting.exposure.luminance_max = getfloatfield_default(L, -1, "luminance_max", lighting.exposure.luminance_max);
lighting.exposure.exposure_correction = getfloatfield_default(L, -1, "exposure_correction", lighting.exposure.exposure_correction);
lighting.exposure.speed_dark_bright = getfloatfield_default(L, -1, "speed_dark_bright", lighting.exposure.speed_dark_bright);
lighting.exposure.speed_bright_dark = getfloatfield_default(L, -1, "speed_bright_dark", lighting.exposure.speed_bright_dark);
lighting.exposure.center_weight_power = getfloatfield_default(L, -1, "center_weight_power", lighting.exposure.center_weight_power);
}
lua_pop(L, 1); // exposure
getServer(L)->setLighting(player, lighting);
return 0;
}
@ -2321,6 +2333,20 @@ int ObjectRef::l_get_lighting(lua_State *L)
lua_setfield(L, -2, "shadows");
lua_pushnumber(L, lighting.saturation);
lua_setfield(L, -2, "saturation");
lua_newtable(L); // "exposure"
lua_pushnumber(L, lighting.exposure.luminance_min);
lua_setfield(L, -2, "luminance_min");
lua_pushnumber(L, lighting.exposure.luminance_max);
lua_setfield(L, -2, "luminance_max");
lua_pushnumber(L, lighting.exposure.exposure_correction);
lua_setfield(L, -2, "exposure_correction");
lua_pushnumber(L, lighting.exposure.speed_dark_bright);
lua_setfield(L, -2, "speed_dark_bright");
lua_pushnumber(L, lighting.exposure.speed_bright_dark);
lua_setfield(L, -2, "speed_bright_dark");
lua_pushnumber(L, lighting.exposure.center_weight_power);
lua_setfield(L, -2, "center_weight_power");
lua_setfield(L, -2, "exposure");
return 1;
}

View file

@ -1866,6 +1866,13 @@ void Server::SendSetLighting(session_t peer_id, const Lighting &lighting)
pkt << lighting.shadow_intensity;
pkt << lighting.saturation;
pkt << lighting.exposure.luminance_min
<< lighting.exposure.luminance_max
<< lighting.exposure.exposure_correction
<< lighting.exposure.speed_dark_bright
<< lighting.exposure.speed_bright_dark
<< lighting.exposure.center_weight_power;
Send(&pkt);
}