17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-11-02 16:19:13 +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 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 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. 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) - **Lights of the cab model.** Every light point (`FreeSpotLight`) of the cab model lights the cab, in place of the lamp
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 light points at all. They are switched by the
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 visibility of the submodels they are children of: under the submodel of `i-cablight:` a light point shines with the
`dashboardlight` are the lights of the desk: they shine with the dashboard light (`i-dashboardlight:` / lamp of the cab, under `i-dashboardlight:` with the dashboard light, and so on (one not under any switched submodel
`dashboardlight_sw:`). Their colour, power, cone and the optional `Radius:`/`SoftFalloff:`/`CastShadows:` are those of the shines always). Their colour, power, cone and the optional `Radius:`/`SoftFalloff:`/`CastShadows:` are those of the light
light point (brightness `gfx.lights.freespot.intensity`, the self-illumination threshold doesn't matter), and they fade point (brightness `gfx.lights.freespot.intensity`, the self-illumination threshold doesn't matter), and they fade in the
in the daylight as the cab lamp does. Visibility counts: a light point under a submodel that is hidden doesn't shine. daylight as the cab lamp does. The dimming of the cab lamp applies only to the lamp under the top.
Other light points of the cab only glare, as before.
The lamps of models and compartments fade in from the light level at which scenery lamps switch on (`ls_Dark`) to full 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 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.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.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` | `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` | `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.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 | | `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 <algorithm>
#include <array> #include <array>
#include <cctype>
#include <chrono> #include <chrono>
#include <limits> #include <limits>
#include <string_view>
#include "utilities/Globals.h" #include "utilities/Globals.h"
#include "rendering/common/skyocclusion.h" #include "rendering/common/skyocclusion.h"
@@ -42,18 +40,6 @@ float const LIGHT_DUSK_LUMINANCE{0.325f};
float const LIGHT_DAY_LUMINANCE{1.0f}; float const LIGHT_DAY_LUMINANCE{1.0f};
// lights of the occupied cab, at most // lights of the occupied cab, at most
std::size_t const CAB_LIGHTS_MAX{16}; 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) glm::vec3 to_linear(glm::vec3 const &Color)
{ {
@@ -209,7 +195,6 @@ void gfx::local_lights::reset()
m_cablights.clear(); m_cablights.clear();
m_cablampon = false; m_cablampon = false;
m_modellights.clear(); m_modellights.clear();
m_cabkinds.clear();
m_cells.clear(); m_cells.clear();
m_sections.clear(); m_sections.clear();
m_models.clear(); m_models.clear();
@@ -341,25 +326,21 @@ void gfx::local_lights::gather_cab_lights(gfx::geometrybank_manager const &Geome
{ {
return; 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 // as bright as the ambient light the lamp used to add to the cab: lost in the daylight
// their switch (off, dimmed, with or without the 110 V), the lights of the desk with the dashboard light (i-dashboardlight:)
auto const luminance{Global.fLuminance * gfx::vehicle_light_level(vehicle)}; 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 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 lightpoints{has_light_points(vehicle->mdKabina)};
auto const dashboardlevel{(train->btDashboardLight.GetValue() ? 1.f : 0.f) * daylight};
auto const kinds{cab_light_kinds(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::iInstance = reinterpret_cast<std::uintptr_t>(vehicle);
TSubModel::iVariantSeed = vehicle->variant_seed(); TSubModel::iVariantSeed = vehicle->variant_seed();
TSubModel::fSquareDist = 0.f; TSubModel::fSquareDist = 0.f;
auto const count{m_lights.size()}; auto const count{m_lights.size()};
m_walkcab = true; m_walkcab = true;
m_walkcablevel = cablevel; walk(vehicle->mdKabina->Root, glm::mat4{1.f}, glm::dmat4{1.0}, Global.gfx_lights_freespot_intensity * daylight);
m_walkdashboardlevel = dashboardlevel;
walk(vehicle->mdKabina->Root, glm::mat4{1.f}, glm::dmat4{1.0}, Global.gfx_lights_freespot_intensity);
m_walkcab = false; m_walkcab = false;
// within the cab: without shadows (gfx.lights.shadows) the light goes through its walls // 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)}; 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); m_lights.resize(count);
} }
// the lamp of a cab model without lamps of its own: under the ceiling, in the middle of the cab // 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
if (((kinds & CAB_LIGHT_LAMP) == 0) && (cablevel > 0.f)) // 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}}; 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; cab_light cablight;
@@ -441,10 +424,8 @@ void gfx::local_lights::add_light_point(TSubModel const &Submodel, glm::mat4 con
{ {
if (m_walkcab) if (m_walkcab)
{ {
// the lights of the cab: with their switches, whatever the self-illumination threshold. other light points of the cab only glare // the lights of the cab: switched with the submodels they're in, whatever the self-illumination threshold
auto const kind{cab_light_kind(Submodel.pName)}; if ((Submodel.f4Emision.a <= 0.f) || (Submodel.fVisible <= 0.f))
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))
{ {
return; return;
} }
@@ -520,35 +501,6 @@ bool gfx::local_lights::has_light_points(TModel3d *Model)
return found; 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) 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 // 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::TextUnformatted("local lights (need clustered lights)");
ImGui::Checkbox("light points of scenery models", &Global.gfx_lights_scenery); 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("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("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("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); 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 // 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 // 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 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) // - 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 // any of them, switched by the visibility of the submodels they're in (children of i-cablight:, i-dashboardlight: ...). a cab
// with the dashboard light, i-dashboardlight:). a cab model without any cablight... gets a point light under its top instead // 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()) // gathered once per frame around the camera, written to the light buffers by the renderers (Update_Lights())
namespace gfx 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_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); void gather_cab_lights(gfx::geometrybank_manager const &Geometry);
bool has_light_points(TModel3d *Model); 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); 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 &section(TModel3d *Model, TSubModel *Section, gfx::geometrybank_manager const &Geometry);
section_data const &model_bounds(TModel3d *Model, 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; std::vector<cab_light> m_cablights;
bool m_cablampon{false}; bool m_cablampon{false};
TDynamicObject const *m_cablampvehicle{nullptr}; 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, // walk() goes through the cab model: its light points shine while they're visible, whatever the self-illumination threshold
// whatever the self-illumination threshold
bool m_walkcab{false}; 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 *, 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<scene::basic_cell const *, cell_data> m_cells;
std::unordered_map<TSubModel const *, section_data> m_sections; // compartments, by their submodel 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 std::unordered_map<TModel3d const *, section_data> m_models; // bounds of cab models