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:
@@ -187,7 +187,9 @@ shadows (see below); the others (lamps of vehicles, compartments, farther scener
|
||||
within their reach, which is kept short for compartments.
|
||||
|
||||
**Shadows of the cab lamp** (`gfx.lights.shadows`): the cab casts shadows in the light of its lamp (and of the brightest
|
||||
`gfx.lights.shadows.cab` lights of the cab model, each with a map of its own; the maps are made as they're needed), the desk, the seats,
|
||||
`gfx.lights.shadows.cab` lights of the cab model, each with a map of its own, made as they're needed; the other lights of the
|
||||
cab take the map of the closest light with one; for the light points the near plane is 3 cm, or their `Radius:`, so the desk
|
||||
right under its lights holds their light back; a few maps are redrawn per frame), the desk, the seats,
|
||||
the levers and the walls (light leaves the cab only through the windows, glass doesn't stop it). They come from a cube
|
||||
shadow map around the lamp, drawn with the opaque parts of the cab model only. The map is kept in the space of the cab, so
|
||||
it stays right as the vehicle moves; it is drawn anew every few frames, for the moving parts of the cab, and at once when
|
||||
@@ -247,7 +249,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 or the light points of the cab model) cast the shadows of the cab, a cube map each; 0: none |
|
||||
| `gfx.lights.shadows.cab` | `8` | 0..16: how many lights of the cab (the brightest; the lamp or the light points of the cab model) have a cube shadow map of their own; the others take the map of the closest light with one (within 1 m); 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 |
|
||||
|
||||
@@ -35,6 +35,18 @@ float lamp_near(gfx::local_lights::light const &Light)
|
||||
{
|
||||
return std::clamp(Light.radius, local_shadows::shadow_near, std::max(local_shadows::shadow_near, Light.range * 0.5f));
|
||||
}
|
||||
// the same for a light of the cab, which is often right by what it lights and what holds its light back (the lights of the desk
|
||||
// under its edge): only what is within a few centimetres, or within its sphere, casts no shadow
|
||||
float const CAB_SHADOW_NEAR{0.03f};
|
||||
float cab_near(gfx::local_lights::light const &Light)
|
||||
{
|
||||
return std::clamp(Light.radius, CAB_SHADOW_NEAR, std::max(CAB_SHADOW_NEAR, Light.range * 0.5f));
|
||||
}
|
||||
// lights of the cab with a shorter reach aren't worth a map of their own, metres
|
||||
float const CAB_RANGE_MIN{0.25f};
|
||||
// a light of the cab without a map of its own takes the shadows of the map of the closest light within this, metres: the desk, the
|
||||
// walls are where they are for both
|
||||
float const CAB_SHARE_DISTANCE{1.0f};
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -172,7 +184,7 @@ void local_shadows::update_cab(TDynamicObject const *Vehicle, TModel3d const *Ca
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (light.source.cast_shadows && (light.source.range >= LAMP_RANGE_MIN))
|
||||
if (light.source.cast_shadows && (light.source.range >= CAB_RANGE_MIN))
|
||||
{
|
||||
picked.emplace_back(&light);
|
||||
}
|
||||
@@ -191,7 +203,8 @@ void local_shadows::update_cab(TDynamicObject const *Vehicle, TModel3d const *Ca
|
||||
}
|
||||
}
|
||||
auto const place = [&](cab_slot &Slot, std::size_t const Index, gfx::local_lights::cab_light const &Light) {
|
||||
auto const nearplane{lamp_near(Light.source)};
|
||||
// the lamp put under the top of a cab model without lights of its own keeps the near plane it had
|
||||
auto const nearplane{Light.source.part == static_cast<void const *>(Vehicle) ? lamp_near(Light.source) : cab_near(Light.source)};
|
||||
if ((Slot.lamp != Light.local) || (Slot.nearplane != nearplane))
|
||||
{
|
||||
Slot.valid = false;
|
||||
@@ -200,12 +213,6 @@ void local_shadows::update_cab(TDynamicObject const *Vehicle, TModel3d const *Ca
|
||||
Slot.nearplane = nearplane;
|
||||
Slot.wantedframe = Framestamp;
|
||||
m_cabwanted.emplace_back(Index);
|
||||
// the moving parts of the cab are followed every few frames
|
||||
if ((false == Slot.valid) || (Framestamp - Slot.drawnframe >= setup(level).interval))
|
||||
{
|
||||
Slot.drawnframe = Framestamp;
|
||||
m_cabdraws.emplace_back(Index);
|
||||
}
|
||||
};
|
||||
// lights which already have a slot keep it, the others take the slots of lights no longer picked
|
||||
std::vector<gfx::local_lights::cab_light const *> unplaced;
|
||||
@@ -242,6 +249,33 @@ void local_shadows::update_cab(TDynamicObject const *Vehicle, TModel3d const *Ca
|
||||
break;
|
||||
}
|
||||
}
|
||||
// the maps to be drawn: those which don't hold their light yet, at once, and those of the moving parts of the cab, every few
|
||||
// frames, a few of them per frame (the ones drawn longest ago first): a cab may have many lights
|
||||
std::vector<std::size_t> refresh;
|
||||
for (auto const idx : m_cabwanted)
|
||||
{
|
||||
auto const &slot{m_cabslots[idx]};
|
||||
if (false == slot.valid)
|
||||
{
|
||||
m_cabdraws.emplace_back(idx);
|
||||
}
|
||||
else if (Framestamp - slot.drawnframe >= setup(level).interval)
|
||||
{
|
||||
refresh.emplace_back(idx);
|
||||
}
|
||||
}
|
||||
auto const refreshes{static_cast<std::size_t>(level >= 3 ? 4 : 2)};
|
||||
if (refresh.size() > refreshes)
|
||||
{
|
||||
std::partial_sort(std::begin(refresh), std::begin(refresh) + refreshes, std::end(refresh),
|
||||
[this, Framestamp](std::size_t const Left, std::size_t const Right) { return Framestamp - m_cabslots[Left].drawnframe > Framestamp - m_cabslots[Right].drawnframe; });
|
||||
refresh.resize(refreshes);
|
||||
}
|
||||
m_cabdraws.insert(std::end(m_cabdraws), std::begin(refresh), std::end(refresh));
|
||||
for (auto const idx : m_cabdraws)
|
||||
{
|
||||
m_cabslots[idx].drawnframe = Framestamp;
|
||||
}
|
||||
}
|
||||
|
||||
void local_shadows::begin(std::size_t const Slot)
|
||||
@@ -277,15 +311,28 @@ int local_shadows::cab_slot_of(TDynamicObject const *Vehicle, gfx::local_lights:
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
auto closest{-1};
|
||||
auto closestdistance{CAB_SHARE_DISTANCE};
|
||||
for (auto const idx : m_cabwanted)
|
||||
{
|
||||
auto const &slot{m_cabslots[idx]};
|
||||
if ((slot.part == Light.source.part) && slot.valid && (slot.lamp == Light.local))
|
||||
if (false == slot.valid)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if ((slot.part == Light.source.part) && (slot.lamp == Light.local))
|
||||
{
|
||||
return static_cast<int>(idx);
|
||||
}
|
||||
// a light without a map of its own takes the one closest to it
|
||||
auto const distance{glm::length(slot.lamp - Light.local)};
|
||||
if (Light.source.cast_shadows && (distance <= closestdistance))
|
||||
{
|
||||
closest = static_cast<int>(idx);
|
||||
closestdistance = distance;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
return closest;
|
||||
}
|
||||
|
||||
glm::vec4 local_shadows::weights(std::size_t const Slot) const
|
||||
|
||||
@@ -31,8 +31,9 @@ namespace gfx
|
||||
// - the lights of the occupied cab (gfx::local_lights::cab_lights(): its lamps, the lights of its desk), the brightest
|
||||
// Global.gfx_lights_shadows_cab of them, with the shadows cast by the cab (the model drawn by Render_cab()). the map of a light is
|
||||
// kept in the space of the cab model, centred on the light: it stays right while the vehicle moves and turns, and is drawn anew only
|
||||
// every few frames (for the moving parts of the cab: levers, doors, wipers) or when the light, the cab or the level change. a light
|
||||
// keeps its map (slot) while it's among those picked;
|
||||
// every few frames (for the moving parts of the cab: levers, doors, wipers; a few maps per frame) or when the light, the cab or the
|
||||
// level change. a light keeps its map (slot) while it's among those picked; the other lights of the cab take the map of the
|
||||
// closest light with one. the near plane of these maps is a few centimetres: the desk right under its lights holds their light back;
|
||||
// - the lamps of scenery models closest to the camera (Global.gfx_lights_shadows_lamps of them, within
|
||||
// Global.gfx_lights_shadows_lamps_range). the map of such a lamp is kept in world axes, centred on the lamp, and has two parts:
|
||||
// the scenery (drawn once, when the lamp gets its slot or the scene changes) and a working copy of it, with the vehicles near
|
||||
@@ -54,7 +55,7 @@ class local_shadows
|
||||
// near plane of the maps, metres. surfaces closer to the lamp (its own fitting) cast no shadow
|
||||
static constexpr float shadow_near{0.15f};
|
||||
// lights of the cab with shadow maps, at most
|
||||
static constexpr int cab_slots_max{8};
|
||||
static constexpr int cab_slots_max{16};
|
||||
|
||||
local_shadows() = default;
|
||||
virtual ~local_shadows() = default;
|
||||
@@ -92,7 +93,8 @@ class local_shadows
|
||||
void begin(std::size_t const Slot);
|
||||
// ends the drawing to the map
|
||||
void end(std::uint32_t const Drawcalls);
|
||||
// the slot of the light of the cab of Vehicle with its shadows ready, -1 if it has none
|
||||
// the slot of the light of the cab of Vehicle with its shadows ready, -1 if it has none. a light without a map of its own (past
|
||||
// the number of maps, or too weak for one) takes the map of the closest light within a metre, whose shadows are close to its own
|
||||
int cab_slot_of(TDynamicObject const *Vehicle, gfx::local_lights::cab_light const &Light) const;
|
||||
// the headlight_weights of the light which reads the map of the slot: layer, near plane, size of a texel one metre from the lamp,
|
||||
// radius of the filter in texels
|
||||
|
||||
@@ -1975,7 +1975,7 @@ global_settings::ConfigParse_gfx_sky( cParser &Parser, std::string_view const To
|
||||
else if( Token == "gfx.lights.shadows.cab" ) {
|
||||
Parser.getTokens( 1 );
|
||||
Parser >> gfx_lights_shadows_cab;
|
||||
gfx_lights_shadows_cab = std::clamp( gfx_lights_shadows_cab, 0, 8 ); }
|
||||
gfx_lights_shadows_cab = std::clamp( gfx_lights_shadows_cab, 0, 16 ); }
|
||||
else if( Token == "gfx.lights.shadows.lamps" ) {
|
||||
Parser.getTokens( 1 );
|
||||
Parser >> gfx_lights_shadows_lamps;
|
||||
|
||||
@@ -539,8 +539,8 @@ struct global_settings {
|
||||
// occupied cab, its shadows cast by the cab
|
||||
int gfx_lights_shadows { 2 };
|
||||
// with gfx_lights_shadows above 0: how many lights of the occupied cab (its lamps, the lights of its desk) at most have shadows
|
||||
// cast by the cab, the brightest ones (0-8)
|
||||
int gfx_lights_shadows_cab { 4 };
|
||||
// cast by the cab, the brightest ones (0-16); the others take the shadows of the map of the closest light with one
|
||||
int gfx_lights_shadows_cab { 8 };
|
||||
// shadows of the lamps of scenery models (cube maps of the scenery around them, kept; vehicles added as they pass), with
|
||||
// gfx_lights_shadows above 0: how many lamps at once, the size of a face of their maps, the distance from the camera within
|
||||
// which lamps get shadows and within which vehicles (and the cab) cast them
|
||||
|
||||
Reference in New Issue
Block a user