17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-10-29 04:37:30 +01:00

Light the occupied cab with the light points of its model

This commit is contained in:
2026-10-28 21:06:02 +01:00
parent 9904eddd0d
commit 65e104f813
3 changed files with 25 additions and 80 deletions

View File

@@ -173,14 +173,13 @@ scales can also be changed in the **Light clusters** debug window.
light of the whole cab and weakened the shadows of the sun in it; now a share of that ambient light is kept for the light
which bounces around the cab (`gfx.lights.cab.bounce`), and the sun shadows stay. With the probe of the cab (below) the
light which bounces comes from the probe instead and nothing of the lamp is kept in the ambient light.
- **Lights of the cab model.** Light points (`FreeSpotLight`) of the cab model whose names start with `cablight` (any case)
are the lamps of the cab: they shine with its lamp switch (off, dimmed, half bright without 110 V), in place of the lamp
under the top of the cab, which a cab model gets only when it has no `cablight` of its own. Those whose names start with
`dashboardlight` are the lights of the desk: they shine with the dashboard light (`i-dashboardlight:` /
`dashboardlight_sw:`). Their colour, power, cone and the optional `Radius:`/`SoftFalloff:`/`CastShadows:` are those of the
light point (brightness `gfx.lights.freespot.intensity`, the self-illumination threshold doesn't matter), and they fade
in the daylight as the cab lamp does. Visibility counts: a light point under a submodel that is hidden doesn't shine.
Other light points of the cab only glare, as before.
- **Lights of the cab model.** Every light point (`FreeSpotLight`) of the cab model lights the cab, in place of the lamp
under the top of the cab, which a cab model gets only when it has no light points at all. They are switched by the
visibility of the submodels they are children of: under the submodel of `i-cablight:` a light point shines with the
lamp of the cab, under `i-dashboardlight:` with the dashboard light, and so on (one not under any switched submodel
shines always). Their colour, power, cone and the optional `Radius:`/`SoftFalloff:`/`CastShadows:` are those of the light
point (brightness `gfx.lights.freespot.intensity`, the self-illumination threshold doesn't matter), and they fade in the
daylight as the cab lamp does. The dimming of the cab lamp applies only to the lamp under the top.
The lamps of models and compartments fade in from the light level at which scenery lamps switch on (`ls_Dark`) to full
darkness; in daylight they are not gathered at all. The cab lamp and the lamps of scenery models nearest to the camera cast
@@ -248,7 +247,7 @@ shadows of the sun, see `headlight shadows:` in Shift+F12); with the vehicle on
| `gfx.lights.cab.bounce` | `0.3` | 0..1: share of the former ambient light of the cab lamp kept with the lamp on |
| `gfx.lights.range` | `300` | distance from the camera the lamps of models and vehicles are gathered from, metres |
| `gfx.lights.shadows` | `medium` | `no`/`low`/`medium`/`high` (or 0..3): shadows of the cab lamp and the scenery lamps, see above |
| `gfx.lights.shadows.cab` | `4` | 0..8: how many lights of the cab (the brightest; the lamp, `cablight`/`dashboardlight` light points) cast the shadows of the cab, a cube map each; 0: none |
| `gfx.lights.shadows.cab` | `4` | 0..8: how many lights of the cab (the brightest; the lamp or the light points of the cab model) cast the shadows of the cab, a cube map each; 0: none |
| `gfx.lights.shadows.lamps` | `8` | 0..32: how many scenery lamps nearest to the camera cast shadows; 0: none |
| `gfx.lights.shadows.lamps.size` | `512` | 128..2048: size of a face of the shadow map of a scenery lamp |
| `gfx.lights.shadows.lamps.range` | `100` | distance from the camera within which scenery lamps cast shadows, metres |

View File

@@ -13,10 +13,8 @@ http://mozilla.org/MPL/2.0/.
#include <algorithm>
#include <array>
#include <cctype>
#include <chrono>
#include <limits>
#include <string_view>
#include "utilities/Globals.h"
#include "rendering/common/skyocclusion.h"
@@ -42,18 +40,6 @@ float const LIGHT_DUSK_LUMINANCE{0.325f};
float const LIGHT_DAY_LUMINANCE{1.0f};
// lights of the occupied cab, at most
std::size_t const CAB_LIGHTS_MAX{16};
// kinds of the light points of a cab model, by the start of their names (any case): the lamps of the cab and the lights of the desk
std::uint8_t const CAB_LIGHT_LAMP{0x1};
std::uint8_t const CAB_LIGHT_DASHBOARD{0x2};
std::uint8_t cab_light_kind(std::string const &Name)
{
auto const starts = [&Name](std::string_view const Prefix) {
return (Name.size() >= Prefix.size()) &&
std::equal(std::begin(Prefix), std::end(Prefix), std::begin(Name), [](char const Left, char const Right) { return Left == static_cast<char>(std::tolower(static_cast<unsigned char>(Right))); });
};
return starts("cablight") ? CAB_LIGHT_LAMP : starts("dashboardlight") ? CAB_LIGHT_DASHBOARD : 0;
}
glm::vec3 to_linear(glm::vec3 const &Color)
{
@@ -209,7 +195,6 @@ void gfx::local_lights::reset()
m_cablights.clear();
m_cablampon = false;
m_modellights.clear();
m_cabkinds.clear();
m_cells.clear();
m_sections.clear();
m_models.clear();
@@ -341,25 +326,21 @@ void gfx::local_lights::gather_cab_lights(gfx::geometrybank_manager const &Geome
{
return;
}
// as bright as the ambient light the lamp used to add to the cab: lost in the daylight. the lamps of the cab at the level of
// their switch (off, dimmed, with or without the 110 V), the lights of the desk with the dashboard light (i-dashboardlight:)
// as bright as the ambient light the lamp used to add to the cab: lost in the daylight
auto const luminance{Global.fLuminance * gfx::vehicle_light_level(vehicle)};
auto const daylight{std::clamp(1.25f - static_cast<float>(luminance), 0.f, 1.f)};
auto const cablevel{std::max(vehicle->InteriorLightLevel, 0.f) * daylight};
auto const dashboardlevel{(train->btDashboardLight.GetValue() ? 1.f : 0.f) * daylight};
auto const kinds{cab_light_kinds(vehicle->mdKabina)};
auto const lightpoints{has_light_points(vehicle->mdKabina)};
if ((kinds != 0) && ((cablevel > 0.f) || (dashboardlevel > 0.f)))
if (lightpoints && (daylight > 0.f))
{
// the light points of the cab model, in its space, the way Render_cab() sets it up
// the light points of the cab model, in its space, the way Render_cab() sets it up. they are switched by the visibility of
// the submodels they're in (the lamp of the cab under i-cablight:, the lights of the desk under i-dashboardlight:, ...)
TSubModel::iInstance = reinterpret_cast<std::uintptr_t>(vehicle);
TSubModel::iVariantSeed = vehicle->variant_seed();
TSubModel::fSquareDist = 0.f;
auto const count{m_lights.size()};
m_walkcab = true;
m_walkcablevel = cablevel;
m_walkdashboardlevel = dashboardlevel;
walk(vehicle->mdKabina->Root, glm::mat4{1.f}, glm::dmat4{1.0}, Global.gfx_lights_freespot_intensity);
walk(vehicle->mdKabina->Root, glm::mat4{1.f}, glm::dmat4{1.0}, Global.gfx_lights_freespot_intensity * daylight);
m_walkcab = false;
// within the cab: without shadows (gfx.lights.shadows) the light goes through its walls
auto const reach{std::max(2.f * glm::length(bounds.extent), 2.5f)};
@@ -378,8 +359,10 @@ void gfx::local_lights::gather_cab_lights(gfx::geometrybank_manager const &Geome
m_lights.resize(count);
}
// the lamp of a cab model without lamps of its own: under the ceiling, in the middle of the cab
if (((kinds & CAB_LIGHT_LAMP) == 0) && (cablevel > 0.f))
// the lamp of a cab model without light points of its own: under the ceiling, in the middle of the cab, at the level of its
// switch (off, dimmed, with or without the 110 V)
auto const cablevel{std::max(vehicle->InteriorLightLevel, 0.f) * daylight};
if ((false == lightpoints) && (cablevel > 0.f))
{
auto const lamp{glm::vec3{bounds.center.x, std::max(bounds.center.y, bounds.center.y + bounds.extent.y - 0.25f), bounds.center.z}};
cab_light cablight;
@@ -441,10 +424,8 @@ void gfx::local_lights::add_light_point(TSubModel const &Submodel, glm::mat4 con
{
if (m_walkcab)
{
// the lights of the cab: with their switches, whatever the self-illumination threshold. other light points of the cab only glare
auto const kind{cab_light_kind(Submodel.pName)};
Brightness *= (kind == CAB_LIGHT_LAMP ? m_walkcablevel : kind == CAB_LIGHT_DASHBOARD ? m_walkdashboardlevel : 0.f);
if ((Brightness <= 0.f) || (Submodel.f4Emision.a <= 0.f) || (Submodel.fVisible <= 0.f))
// the lights of the cab: switched with the submodels they're in, whatever the self-illumination threshold
if ((Submodel.f4Emision.a <= 0.f) || (Submodel.fVisible <= 0.f))
{
return;
}
@@ -520,35 +501,6 @@ bool gfx::local_lights::has_light_points(TModel3d *Model)
return found;
}
std::uint8_t gfx::local_lights::cab_light_kinds(TModel3d *Model)
{
auto lookup{m_cabkinds.find(Model)};
if (lookup != m_cabkinds.end())
{
return lookup->second;
}
std::uint8_t kinds{0};
std::vector<TSubModel const *> pending{Model->Root};
while (false == pending.empty())
{
auto const *submodel{pending.back()};
pending.pop_back();
for (; submodel != nullptr; submodel = submodel->Next)
{
if (submodel->eType == TP_FREESPOTLIGHT)
{
kinds |= cab_light_kind(submodel->pName);
}
if (submodel->Child != nullptr)
{
pending.emplace_back(submodel->Child);
}
}
}
m_cabkinds.emplace(Model, kinds);
return kinds;
}
gfx::local_lights::cell_data const &gfx::local_lights::cell_instances(scene::basic_cell &Cell, bool const Rebuild)
{
// light points are drawn in the translucent phase, so the instances which have them are on the translucent list of the cell
@@ -636,7 +588,7 @@ void gfx::local_lights::draw_debug_ui()
ImGui::TextUnformatted("local lights (need clustered lights)");
ImGui::Checkbox("light points of scenery models", &Global.gfx_lights_scenery);
ImGui::Checkbox("light points and compartments of vehicles", &Global.gfx_lights_vehicles);
ImGui::Checkbox("cab lamp as a light (cablight... / dashboardlight... light points of the cab)", &Global.gfx_lights_cab);
ImGui::Checkbox("cab lamp as a light (or the light points of the cab model)", &Global.gfx_lights_cab);
ImGui::SliderFloat("light point brightness", &Global.gfx_lights_freespot_intensity, 0.f, 50.f);
ImGui::SliderFloat("compartment brightness", &Global.gfx_lights_compartment_intensity, 0.f, 10.f);
ImGui::SliderFloat("cab lamp brightness", &Global.gfx_lights_cab_intensity, 0.f, 10.f);

View File

@@ -34,9 +34,9 @@ class TDynamicObject;
// light along the -z axis of its submodel, with the cone of its glare. lamps of scenery models switched with Light_On / Light_Off
// and the self-illumination of vehicle compartments (TDynamicObject::Sections) work through the same state
// - the lit compartments of vehicles (low poly interior sections) without light points of their own: a point light in the middle
// - the lights of the occupied cab, in place of the ambient light its lamp used to add: the light points of the cab model (mdKabina)
// named cablight... (the lamps of the cab, switched and dimmed with them) and dashboardlight... (the lights of the desk, switched
// with the dashboard light, i-dashboardlight:). a cab model without any cablight... gets a point light under its top instead
// - the lights of the occupied cab, in place of the ambient light its lamp used to add: the light points of the cab model (mdKabina),
// any of them, switched by the visibility of the submodels they're in (children of i-cablight:, i-dashboardlight: ...). a cab
// model without light points gets a point light under its top instead, switched and dimmed with the lamp of the cab
// gathered once per frame around the camera, written to the light buffers by the renderers (Update_Lights())
namespace gfx
{
@@ -139,8 +139,6 @@ class local_lights
void gather_vehicle(TDynamicObject *Vehicle, glm::dvec3 const &Camera, gfx::geometrybank_manager const &Geometry, float const Freespotbrightness, float const Compartmentbrightness);
void gather_cab_lights(gfx::geometrybank_manager const &Geometry);
bool has_light_points(TModel3d *Model);
// the kinds of the light points of a cab model by their names, CAB_LIGHT_LAMP | CAB_LIGHT_DASHBOARD (locallights.cpp)
std::uint8_t cab_light_kinds(TModel3d *Model);
cell_data const &cell_instances(scene::basic_cell &Cell, bool const Rebuild);
section_data const &section(TModel3d *Model, TSubModel *Section, gfx::geometrybank_manager const &Geometry);
section_data const &model_bounds(TModel3d *Model, gfx::geometrybank_manager const &Geometry);
@@ -149,13 +147,9 @@ class local_lights
std::vector<cab_light> m_cablights;
bool m_cablampon{false};
TDynamicObject const *m_cablampvehicle{nullptr};
// walk() goes through the cab model: only its light points of the cab and of the desk, at these levels (0-1) of their switches,
// whatever the self-illumination threshold
// walk() goes through the cab model: its light points shine while they're visible, whatever the self-illumination threshold
bool m_walkcab{false};
float m_walkcablevel{0.f};
float m_walkdashboardlevel{0.f};
std::unordered_map<TModel3d const *, bool> m_modellights; // whether the model has light points
std::unordered_map<TModel3d const *, std::uint8_t> m_cabkinds; // the kinds of light points of cab models
std::unordered_map<scene::basic_cell const *, cell_data> m_cells;
std::unordered_map<TSubModel const *, section_data> m_sections; // compartments, by their submodel
std::unordered_map<TModel3d const *, section_data> m_models; // bounds of cab models