Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

API for light intensity and color at night and day #14091

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions builtin/game/features.lua
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ core.features = {
dynamic_add_media_filepath = true,
lsystem_decoration_type = true,
item_meta_range = true,
light_intensity = true,
}

function core.has_feature(arg)
Expand Down
14 changes: 14 additions & 0 deletions doc/lua_api.md
Original file line number Diff line number Diff line change
Expand Up @@ -5431,6 +5431,8 @@ Utilities
lsystem_decoration_type = true,
-- Overrideable pointing range using the itemstack meta key `"range"` (5.9.0)
item_meta_range = true,
-- set_lighting support light_intensity table (5.9.0)
light_intensity = true,
}
```

Expand Down Expand Up @@ -8336,6 +8338,18 @@ child will follow movement and rotation of that bone.
* `volumetric_light`: is a table that controls volumetric light (a.k.a. "godrays")
* `strength`: sets the strength of the volumetric light effect from 0 (off, default) to 1 (strongest)
* This value has no effect on clients who have the "Volumetric Lighting" or "Bloom" shaders disabled.
* `light_intensity` is a table that controls calculation of sun light color.
`sun_color = color_offset + color_ratio_coef*daynight_ratio` where `daynight_ratio` is not linear to day time.
Result color lesser or equal to 0.0 means no color in light.
Result color greater or equal to 1.0 means full color in light.
* `color_offset` is a table that controls red, green and blue color offsets.
* `r` (default: `-0.04`)
* `g` (default: `-0.04`)
* `b` (default: `0.078`)
* `color_ratio_coef` is a table that controls red, green and blue color ration coefficients.
* `r` (default: `0.001`)
* `g` (default: `0.001`)
* `b` (default: `0.00098`)

* `get_lighting()`: returns the current state of lighting for the player.
* Result is a table with the same fields as `light_definition` in `set_lighting`.
Expand Down
212 changes: 135 additions & 77 deletions games/devtest/mods/lighting/init.lua
Original file line number Diff line number Diff line change
@@ -1,30 +1,15 @@
local lighting_sections = {
{n = "shadows", d = "Shadows",
entries = {
{ n = "intensity", d = "Shadow Intensity", min = 0, max = 1 }
}
},
{
n = "exposure", d = "Exposure",
entries = {
{n = "luminance_min", d = "Minimum Luminance", min = -10, max = 10},
{n = "luminance_max", d = "Maximum Luminance", min = -10, max = 10},
{n = "exposure_correction", d = "Exposure Correction", min = -10, max = 10},
{n = "speed_dark_bright", d = "Bright light adaptation speed", min = -10, max = 10, type="log2"},
{n = "speed_bright_dark", d = "Dark scene adaptation speed", min = -10, max = 10, type="log2"},
{n = "center_weight_power", d = "Power factor for center-weighting", min = 0.1, max = 10},
}
}
}

local function dump_lighting(lighting)
local modpath = minetest.get_modpath(minetest.get_current_modname())


local function dumpByRecipe(data, recipe)
local result = "{\n"
local section_count = 0
for _,section in ipairs(lighting_sections) do
for _,section in ipairs(recipe) do
section_count = section_count + 1

local parameters = section.entries or {}
local state = lighting[section.n] or {}
local state = data[section.n] or {}

result = result.." "..section.n.." = {\n"

Expand All @@ -40,7 +25,7 @@ local function dump_lighting(lighting)

result = result.." }"

if section_count < #lighting_sections then
if section_count < #recipe then
result = result..","
end
result = result.."\n"
Expand All @@ -49,74 +34,59 @@ local function dump_lighting(lighting)
return result
end

minetest.register_chatcommand("set_lighting", {
params = "",
description = "Tune lighting parameters",
func = function(player_name, param)
local player = minetest.get_player_by_name(player_name);
if not player then return end
local function buildGUI(player, data, recipe, gui_name)
local form = {
"formspec_version[2]",
"size[15,30]",
"position[0.99,0.15]",
"anchor[1,0]",
"padding[0.05,0.1]",
"no_prepend[]"
};

local line = 1
for _,section in ipairs(recipe) do
local parameters = section.entries or {}
local state = data[section.n] or {}

local lighting = player:get_lighting()
local exposure = lighting.exposure or {}

local form = {
"formspec_version[2]",
"size[15,30]",
"position[0.99,0.15]",
"anchor[1,0]",
"padding[0.05,0.1]",
"no_prepend[]"
};

local line = 1
for _,section in ipairs(lighting_sections) do
local parameters = section.entries or {}
local state = lighting[section.n] or {}

table.insert(form, "label[1,"..line..";"..section.d.."]")
line = line + 1

for _,v in ipairs(parameters) do
table.insert(form, "label[2,"..line..";"..v.d.."]")
table.insert(form, "scrollbaroptions[min=0;max=1000;smallstep=10;largestep=100;thumbsize=10]")
local value = state[v.n]
if v.type == "log2" then
value = math.log(value or 1) / math.log(2)
end
local sb_scale = math.floor(1000 * (math.max(v.min, value or 0) - v.min) / (v.max - v.min))
table.insert(form, "scrollbar[2,"..(line+0.7)..";12,1;horizontal;"..section.n.."."..v.n..";"..sb_scale.."]")
line = line + 2.7
end
table.insert(form, "label[1,"..line..";"..section.d.."]")
line = line + 1

line = line + 1
for _,v in ipairs(parameters) do
table.insert(form, "label[2,"..line..";"..v.d.."]")
table.insert(form, "scrollbaroptions[min=0;max=1000;smallstep=10;largestep=100;thumbsize=10]")
local value = state[v.n]
if v.type == "log2" then
value = math.log(value or 1) / math.log(2)
end
local sb_scale = math.floor(1000 * (math.max(v.min, value or 0) - v.min) / (v.max - v.min))
table.insert(form, "scrollbar[2,"..(line+0.7)..";12,1;horizontal;"..section.n.."."..v.n..";"..sb_scale.."]")
line = line + 2.7
end

minetest.show_formspec(player_name, "lighting", table.concat(form))
local debug_value = dump_lighting(lighting)
local debug_ui = player:hud_add({type="text", position={x=0.1, y=0.3}, scale={x=1,y=1}, alignment = {x=1, y=1}, text=debug_value, number=0xFFFFFF})
player:get_meta():set_int("lighting_hud", debug_ui)
line = line + 1
end
})

minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname ~= "lighting" then return end

if not player then return end
minetest.show_formspec(player:get_player_name(), gui_name, table.concat(form))
local debug_value = dumpByRecipe(data, recipe)
local debug_ui = player:hud_add({type="text", position={x=0.1, y=0.3}, scale={x=1,y=1}, alignment = {x=1, y=1}, text=debug_value, number=0xFFFFFF})
player:get_meta():set_int(gui_name.."_hud", debug_ui)
end

local hud_id = player:get_meta():get_int("lighting_hud")
local function receiveFields(player, fields, data, recipe, gui_name)
local hud_id = player:get_meta():get_int(gui_name.."_hud")

if fields.quit then
player:hud_remove(hud_id)
player:get_meta():set_int("lighting_hud", -1)
player:get_meta():set_int(gui_name.."_hud", -1)
return
end

local lighting = player:get_lighting()
for _,section in ipairs(lighting_sections) do
for _,section in ipairs(recipe) do
local parameters = section.entries or {}

local state = (lighting[section.n] or {})
lighting[section.n] = state
local state = (data[section.n] or {})
data[section.n] = state

for _,v in ipairs(parameters) do

Expand All @@ -133,8 +103,96 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
end
end

local debug_value = dump_lighting(lighting)
local debug_value = dumpByRecipe(data, recipe)
player:hud_change(hud_id, "text", debug_value)
end

local lighting_recipe = {
{n = "shadows", d = "Shadows",
entries = {
{ n = "intensity", d = "Shadow Intensity", min = 0, max = 1 }
}
},
{
n = "exposure", d = "Exposure",
entries = {
{n = "luminance_min", d = "Minimum Luminance", min = -10, max = 10},
{n = "luminance_max", d = "Maximum Luminance", min = -10, max = 10},
{n = "exposure_correction", d = "Exposure Correction", min = -10, max = 10},
{n = "speed_dark_bright", d = "Bright light adaptation speed", min = -10, max = 10, type="log2"},
{n = "speed_bright_dark", d = "Dark scene adaptation speed", min = -10, max = 10, type="log2"},
{n = "center_weight_power", d = "Power factor for center-weighting", min = 0.1, max = 10},
}
},
}

minetest.register_chatcommand("set_lighting", {
params = "",
description = "Tune lighting parameters",
func = function(player_name, param)
local player = minetest.get_player_by_name(player_name)
if not player then return end

local lighting = player:get_lighting()

buildGUI(player, lighting, lighting_recipe, "lighting")
end
})

minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname ~= "lighting" then return end

if not player then return end

local lighting = player:get_lighting()

receiveFields(player, fields, lighting, lighting_recipe, "lighting")

player:set_lighting(lighting)
end)
end)

local light_intensity_recipe = {
{n = "color_offset", d = "Color offset",
entries = {
{n = "r", d = "Red color offset", min = -1, max = 2},
{n = "g", d = "Green color offset", min = -1, max = 2},
{n = "b", d = "Blue color offset", min = -1, max = 2},
}
},
{n = "color_ratio_coef", d = "Color day-night ratio coefficient",
entries = {
{n = "r", d = "Red color day-night ratio coefficient", min = -1e-3, max = 2e-3},
{n = "g", d = "Green color day-night ratio coefficient", min = -1e-3, max = 2e-3},
{n = "b", d = "Blue color day-night ratio coefficient", min = -1e-3, max = 2e-3},
}
}
}


minetest.register_chatcommand("set_light_intensity", {
params = "",
description = "Tune lighting light_intensity parameters",
func = function(player_name, param)
local player = minetest.get_player_by_name(player_name)
if not player then return end

local lighting = player:get_lighting()
local light_intensity = lighting.light_intensity

buildGUI(player, light_intensity, light_intensity_recipe, "light_intensity")
end
})

minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname ~= "light_intensity" then return end

if not player then return end

local lighting = player:get_lighting()
local light_intensity = lighting.light_intensity

receiveFields(player, fields, light_intensity, light_intensity_recipe, "light_intensity")

player:set_lighting(lighting)
end)

3 changes: 2 additions & 1 deletion src/client/clientenvironment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,8 @@ void ClientEnvironment::step(float dtime)

u16 light = getInteriorLight(node_at_lplayer, 0, m_client->ndef());
lplayer->light_color = encode_light(light, 0); // this transfers light.alpha
final_color_blend(&lplayer->light_color, light, day_night_ratio);
const LightIntensity &lightIntensity = m_client->getEnv().getLocalPlayer()->getLighting().lightIntensity;
final_color_blend(&lplayer->light_color, light, day_night_ratio, lightIntensity);
}

/*
Expand Down
3 changes: 2 additions & 1 deletion src/client/clientmap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -719,6 +719,7 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
const float animation_time = m_client->getAnimationTime();
const int crack = m_client->getCrackLevel();
const u32 daynight_ratio = m_client->getEnv().getDayNightRatio();
const Lighting &lighting = m_client->getEnv().getLocalPlayer()->getLighting();

const v3f camera_position = m_camera_position;

Expand Down Expand Up @@ -780,7 +781,7 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
mesh_animate_count < (m_control.range_all ? 200 : 50)) {

bool animated = block_mesh->animate(faraway, animation_time,
crack, daynight_ratio);
crack, daynight_ratio, lighting.lightIntensity);
if (animated)
mesh_animate_count++;
} else {
Expand Down
6 changes: 4 additions & 2 deletions src/client/content_cao.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -908,8 +908,10 @@ void GenericCAO::updateLight(u32 day_night_ratio)
// based on the entity glow.
if (m_enable_shaders)
light = encode_light(light_at_pos, m_prop.glow);
else
final_color_blend(&light, light_at_pos, day_night_ratio);
else {
const LightIntensity &lightIntensity = m_env->getLocalPlayer()->getLighting().lightIntensity;
final_color_blend(&light, light_at_pos, day_night_ratio, lightIntensity);
}

if (light != m_last_light) {
m_last_light = light;
Expand Down
9 changes: 5 additions & 4 deletions src/client/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -470,8 +470,9 @@ class GameGlobalShaderConstantSetter : public IShaderConstantSetter
void onSetConstants(video::IMaterialRendererServices *services) override
{
u32 daynight_ratio = (float)m_client->getEnv().getDayNightRatio();
const auto &lighting = m_client->getEnv().getLocalPlayer()->getLighting();
video::SColorf sunlight;
get_sunlight_color(&sunlight, daynight_ratio);
get_sunlight_color(&sunlight, daynight_ratio, lighting.lightIntensity);
m_day_light.set(sunlight, services);

u32 animation_timer = m_client->getEnv().getFrameTime() % 1000000;
Expand Down Expand Up @@ -509,7 +510,7 @@ class GameGlobalShaderConstantSetter : public IShaderConstantSetter
m_texel_size0_vertex.set(m_texel_size0, services);
m_texel_size0_pixel.set(m_texel_size0, services);

const AutoExposure &exposure_params = m_client->getEnv().getLocalPlayer()->getLighting().exposure;
const AutoExposure &exposure_params = lighting.exposure;
std::array<float, 7> exposure_buffer = {
std::pow(2.0f, exposure_params.luminance_min),
std::pow(2.0f, exposure_params.luminance_max),
Expand All @@ -527,7 +528,6 @@ class GameGlobalShaderConstantSetter : public IShaderConstantSetter
m_bloom_strength_pixel.set(&m_bloom_strength, services);
}

const auto &lighting = m_client->getEnv().getLocalPlayer()->getLighting();
float saturation = lighting.saturation;
m_saturation_pixel.set(&saturation, services);

Expand Down Expand Up @@ -3458,8 +3458,9 @@ PointedThing Game::updatePointedThing(
}

u32 daynight_ratio = client->getEnv().getDayNightRatio();
const Lighting &lighting = client->getEnv().getLocalPlayer()->getLighting();
video::SColor c;
final_color_blend(&c, light_level, daynight_ratio);
final_color_blend(&c, light_level, daynight_ratio, lighting.lightIntensity);

// Modify final color a bit with time
u32 timer = client->getEnv().getFrameTime() % 5000;
Expand Down