17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-11-02 06:59:13 +01:00

Take the ambient occlusion into the lighting and add a probe of the cab

This commit is contained in:
2026-10-27 13:23:52 +01:00
parent ac0b4e5f15
commit 9dde5b0e5e
43 changed files with 2402 additions and 45 deletions

View File

@@ -103,6 +103,15 @@ void opengl46_ao::apply(int const Mode, opengl_texture &Depth, opengl_texture &O
}
}
void opengl46_ao::end_timing()
{
if (m_timing)
{
m_timer.end();
m_timing = false;
}
}
std::string opengl46_ao::info_times()
{
std::string text;
@@ -127,4 +136,5 @@ void opengl46_ao::draw_debug_ui(bool const Available)
ImGui::SliderFloat("ao bounce albedo", &Global.gfx_postfx_ao_bounce, 0.f, 1.f);
ImGui::SliderInt("ao slices", &Global.gfx_postfx_ao_slices, 1, 8);
ImGui::SliderInt("ao steps per side", &Global.gfx_postfx_ao_steps, 1, 16);
ImGui::Checkbox("ao in the ambient light, not over the image (gfx.postfx.ao.lighting)", &Global.gfx_postfx_ao_lighting);
}

View File

@@ -24,7 +24,9 @@ class opengl_texture;
// (gtao_main.comp) and a depth aware smoothing (gtao_denoise.comp)
// - its application to the image: a multiplier drawn over it (postfx_ssao_apply.frag), which also applies the older
// ssao (postfx_ssao.frag, run by the renderer) when that one is chosen
// switched by Global.gfx_postfx_ao (0 off, 1 older ssao, 2 gtao); the targets are made with the viewport when it is not 0
// switched by Global.gfx_postfx_ao (0 off, 1 older ssao, 2 gtao); the targets are made with the viewport when it is not 0. with
// Global.gfx_postfx_ao_lighting the ground truth one is computed from the depth of the scene drawn before the colour and read by the
// shading of the colour pass (light_common.glsl, ambient_occlusion()) instead of being applied to the image
class opengl46_ao
{
public:
@@ -40,6 +42,8 @@ class opengl46_ao
// multiplies the image of the framebuffer by the occlusion. Mode: Global.gfx_postfx_ao. the viewport has to be set
// to the size of Depth. leaves the framebuffer bound
void apply(int const Mode, opengl_texture &Depth, opengl_texture &Occlusion, gl::framebuffer &Target, glm::mat4 const &Projection);
// ends the gpu time of the occlusion computed for the light of the surfaces (gfx.postfx.ao.lighting), which isn't applied
void end_timing();
// lines for the gpu times of the debug panel
std::string info_times();
// controls of the debug window. Available: the targets were made, so the mode can be changed

View File

@@ -0,0 +1,162 @@
/*
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
*/
#include "stdafx.h"
#include "rendering/opengl46/opengl46cabprobe.h"
#include "gl/framebuffer.h"
#include "gl/ubo.h"
#include "model/Texture.h"
#include "utilities/Globals.h"
#include "utilities/Logs.h"
#include "utilities/utilities.h"
namespace
{
// uniform location of cabprobe_sh.comp: the level of the probe read and its size
GLint const SH_LEVEL_LOCATION{0};
// cube map of Size x Size faces with its mipmaps
GLuint make_cube(GLenum const Format, int const Size, bool const Mipmaps)
{
GLuint texture{0};
glCreateTextures(GL_TEXTURE_CUBE_MAP, 1, &texture);
auto const levels{Mipmaps ? static_cast<GLsizei>(std::floor(std::log2(static_cast<float>(std::max(Size, 1))))) + 1 : 1};
glTextureStorage2D(texture, levels, Format, Size, Size);
glTextureParameteri(texture, GL_TEXTURE_MIN_FILTER, Mipmaps ? GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST);
glTextureParameteri(texture, GL_TEXTURE_MAG_FILTER, Mipmaps ? GL_LINEAR : GL_NEAREST);
glTextureParameteri(texture, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTextureParameteri(texture, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTextureParameteri(texture, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
return texture;
}
} // namespace
opengl46_cab_probe::~opengl46_cab_probe()
{
gpu_release();
if (m_empty != 0)
glDeleteTextures(1, &m_empty);
if (m_white != 0)
glDeleteTextures(1, &m_white);
}
void opengl46_cab_probe::init()
{
gl::shader vertex("cabprobe.vert");
gl::shader geometry("cabprobe.geom");
{
gl::shader fragment("cabprobe.frag");
m_program = std::make_unique<gl::program>(std::vector<std::reference_wrapper<const gl::shader>>{vertex, geometry, fragment});
}
{
gl::shader fragment("cabprobe_alpha.frag");
m_alpha_program = std::make_unique<gl::program>(std::vector<std::reference_wrapper<const gl::shader>>{vertex, geometry, fragment});
}
{
gl::shader compute("cabprobe_sh.comp");
m_sh_program = std::make_unique<gl::program>(std::vector<std::reference_wrapper<const gl::shader>>{compute});
}
m_sh = std::make_unique<gl::ssbo>(static_cast<GLsizeiptr>(sizeof(gl::cab_probe_data)), gl::CAB_PROBE_SSBO_BINDING);
m_sh->update(gl::cab_probe_data{});
// a sampler with no texture to read from is undefined, also where the shading doesn't read it
m_empty = make_cube(GL_RGBA8, 1, false);
std::uint8_t const nothing[4]{0, 0, 0, 0};
glClearTexImage(m_empty, 0, GL_RGBA, GL_UNSIGNED_BYTE, nothing);
glCreateTextures(GL_TEXTURE_2D, 1, &m_white);
glTextureStorage2D(m_white, 1, GL_RGBA8, 1, 1);
std::uint8_t const white[4]{255, 255, 255, 255};
glClearTexImage(m_white, 0, GL_RGBA, GL_UNSIGNED_BYTE, white);
}
void opengl46_cab_probe::bind()
{
glBindTextureUnit(gl::CAB_PROBE_TEX, (m_light != 0) ? m_light : m_empty);
glBindTextureUnit(gl::CAB_PROBE_ALBEDO_TEX, (m_albedo != 0) ? m_albedo : m_empty);
if (m_sh)
m_sh->bind_base();
}
bool opengl46_cab_probe::gpu_allocate(int const Size)
{
m_light = make_cube(GL_RGBA16F, Size, true);
m_albedo = make_cube(GL_RGBA8, Size, true);
m_depth = make_cube(GL_DEPTH_COMPONENT32F, Size, false);
// all the faces at once, the geometry shader picks the face
glCreateFramebuffers(1, &m_framebuffer);
glNamedFramebufferTexture(m_framebuffer, GL_COLOR_ATTACHMENT0, m_light, 0);
glNamedFramebufferTexture(m_framebuffer, GL_COLOR_ATTACHMENT1, m_albedo, 0);
glNamedFramebufferTexture(m_framebuffer, GL_DEPTH_ATTACHMENT, m_depth, 0);
GLenum const buffers[2]{GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1};
glNamedFramebufferDrawBuffers(m_framebuffer, 2, buffers);
glNamedFramebufferReadBuffer(m_framebuffer, GL_NONE);
return (glCheckNamedFramebufferStatus(m_framebuffer, GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
}
void opengl46_cab_probe::gpu_release()
{
if (m_framebuffer != 0)
glDeleteFramebuffers(1, &m_framebuffer);
for (auto *texture : {&m_light, &m_albedo, &m_depth})
{
if (*texture != 0)
glDeleteTextures(1, texture);
*texture = 0;
}
m_framebuffer = 0;
if (m_sh)
m_sh->update(gl::cab_probe_data{});
}
void opengl46_cab_probe::gpu_begin()
{
m_timer.begin();
// the framebuffer is bound past the cache of gl::framebuffer, which the end of the drawing resets
gl::framebuffer::unbind();
glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
glViewport(0, 0, m_size, m_size);
float const nothing[4]{0.f, 0.f, 0.f, 0.f};
glClearNamedFramebufferfv(m_framebuffer, GL_COLOR, 0, nothing);
glClearNamedFramebufferfv(m_framebuffer, GL_COLOR, 1, nothing);
float const farthest{0.f};
glClearNamedFramebufferfv(m_framebuffer, GL_DEPTH, 0, &farthest);
glDisable(GL_BLEND);
glDepthMask(GL_TRUE);
glEnable(GL_DEPTH_TEST);
// one sided walls face the probe from either side
glDisable(GL_CULL_FACE);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
void opengl46_cab_probe::gpu_end()
{
glEnable(GL_CULL_FACE);
gl::framebuffer::unbind();
glGenerateTextureMipmap(m_light);
glGenerateTextureMipmap(m_albedo);
// the light the cab lights itself with again, from a small level of the light reflected
glBindTextureUnit(0, m_light);
glProgramUniform2i(*m_sh_program, SH_LEVEL_LOCATION, sh_level(), sh_size());
m_sh->bind_base();
m_sh_program->dispatch(1);
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
opengl_texture::reset_unit_cache();
m_timer.end();
}
std::string opengl46_cab_probe::info_times()
{
std::string text;
if (auto const time = m_timer.result())
text += " cab probe: " + to_string(static_cast<double>(*time) / 1000000.0, 3) + " ms\n";
return text;
}

View File

@@ -0,0 +1,67 @@
/*
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <memory>
#include <string>
#include "gl/shader.h"
#include "gl/query.h"
#include "gl/ssbo.h"
#include "rendering/common/cabprobe.h"
// the probe of the occupied cab of the opengl 4.6 renderer (Global.gfx_cabprobe): the maps and the drawing to them of gfx::cab_probe,
// which tells when they're drawn and what the shading reads. the six faces of the maps are drawn at once, by a geometry shader
// (cabprobe.vert/.geom/.frag), the spherical harmonics of the light worked out by cabprobe_sh.comp
class opengl46_cab_probe : public gfx::cab_probe
{
public:
opengl46_cab_probe() = default;
~opengl46_cab_probe() override;
// creates the programs, the stand-ins and the storage of the spherical harmonics. throws gl::shader_exception
void init();
// puts the maps (or the stand-ins) on their texture units, gl::CAB_PROBE_TEX and gl::CAB_PROBE_ALBEDO_TEX, and the spherical
// harmonics on gl::CAB_PROBE_SSBO_BINDING. once per context and frame
void bind();
// program of the probe, of the alpha tested materials when Alpha
gl::program &program(bool const Alpha)
{
return Alpha ? *m_alpha_program : *m_program;
}
// a white texture, for the materials without a diffuse texture
GLuint white() const
{
return m_white;
}
// lines for the gpu times of the debug panel
std::string info_times();
protected:
bool gpu_allocate(int const Size) override;
void gpu_release() override;
void gpu_begin() override;
void gpu_end() override;
private:
std::unique_ptr<gl::program> m_program;
std::unique_ptr<gl::program> m_alpha_program;
std::unique_ptr<gl::program> m_sh_program;
std::unique_ptr<gl::ssbo> m_sh;
// the light reflected and the albedo (cube maps with mipmaps), the depth of the faces, and the framebuffer drawing to all faces
GLuint m_light{0};
GLuint m_albedo{0};
GLuint m_depth{0};
GLuint m_framebuffer{0};
// stand-ins: a cube map of 1x1 faces of nothing, a 1x1 white texture
GLuint m_empty{0};
GLuint m_white{0};
gl::gpu_timer m_timer;
};

View File

@@ -217,6 +217,7 @@ bool opengl46_renderer::Init(GLFWwindow *Window)
m_exposure.init();
m_ao.init();
m_localshadows.init();
m_cabprobe.init();
}
catch (gl::shader_exception const &e)
{
@@ -952,6 +953,7 @@ void opengl46_renderer::SwapBuffers()
text += m_weather.info_times();
text += m_exposure.info_times();
text += m_ao.info_times();
text += m_cabprobe.info_times();
text += m_instancecull.info_times();
// the cullings of the other passes; the environment map is drawn now and then, its numbers are of its last update
if( Global.gfx_gpucull_shadows ) {
@@ -1052,6 +1054,7 @@ void opengl46_renderer::SwapBuffers()
", rays " + to_string( Global.gfx_contactshadows_length, 2 ) + " m within " + to_string( Global.gfx_contactshadows_range, 0 ) + " m\n" :
", off in this view\n" ) :
std::string{} )
+ ( Global.gfx_cabprobe > 0 ? " " + m_cabprobe.info() + "\n" : std::string{} )
+ shadowcascadestext
+ " instance buffer: " + std::to_string( m_instancestream->used() / static_cast<GLsizeiptr>( sizeof( glm::mat4 ) ) ) + " matrices, "
+ std::to_string( m_instancestream->size() / 1024 ) + " KiB\n"
@@ -1466,6 +1469,7 @@ void opengl46_renderer::draw_debug_ui()
m_exposure.draw_debug_ui();
ImGui::Separator();
m_ao.draw_debug_ui(!m_viewports.empty() && m_viewports.front()->ssao_tex != nullptr);
m_cabprobe.draw_debug_ui();
ImGui::Separator();
m_ssr.draw_debug_ui(nullptr);
}
@@ -1669,6 +1673,8 @@ void opengl46_renderer::Render_pass(viewport_config &vp, rendermode const Mode)
setup_env_map(nullptr);
// the cube shadow maps of the lamps, or the stand-in for them
m_localshadows.bind();
// the probe of the cab, or the stand-ins
m_cabprobe.bind();
if (Global.gfx_shadowmap_enabled && vp.main)
{
@@ -1704,6 +1710,9 @@ void opengl46_renderer::Render_pass(viewport_config &vp, rendermode const Mode)
Render_local_shadows();
Render_lamp_shadows();
Render_headlight_shadows();
// after the map of the cab lamp, which it reads
gpupart("cab probe");
Render_cab_probe();
}
gpupart("clear, clusters, lights");
@@ -1822,18 +1831,31 @@ void opengl46_renderer::Render_pass(viewport_config &vp, rendermode const Mode)
if( Global.gfx_shadowmap_enabled )
setup_shadow_bind_map();
// the probe of the cab, which the parts of the cab drawn in the colour pass of the main view read
if (vp.main)
{
auto const *cab{Cab_Probe_Vehicle()};
m_cabprobe.setup_scene(scene_ubs, cab, m_colorpass.pass_camera.position(), glm::mat3{m_colorpass.pass_camera.modelview()});
m_cabprobelit = (scene_ubs.cab_probe_box.w > 0.f);
if (m_cabprobelit)
scene_ubo->update(scene_ubs);
}
// the depth of the whole opaque scene before its colour, which the contact shadows need
m_scenedepthdrawn = false;
m_indirectcolourpending = false;
m_scenerecorded = false;
m_aolighting = false;
auto const contactshadows{Contact_Shadows_Wanted(vp)};
// the screen space reflections trace the depth of the whole scene, not only of what the contact shadows reach
auto const reflections{m_ssrframe && (false == Global.bWireFrame)};
if ((Global.gfx_depthprepass_scene || contactshadows || reflections) && vp.main && (false == Global.bWireFrame))
// and so does the ambient occlusion in the light of the surfaces
auto const aolighting{Ao_Lighting_Wanted(vp)};
if ((Global.gfx_depthprepass_scene || contactshadows || reflections || aolighting) && vp.main && (false == Global.bWireFrame))
{
glDebug("render scene depth");
gpupart("scene depth");
Render_Scene_Depth(future, contactshadows && (false == Global.gfx_depthprepass_scene) && (false == reflections));
Render_Scene_Depth(future, contactshadows && (false == Global.gfx_depthprepass_scene) && (false == reflections) && (false == aolighting));
if (contactshadows)
{
gpupart("contact shadows depth");
@@ -1843,6 +1865,11 @@ void opengl46_renderer::Render_pass(viewport_config &vp, rendermode const Mode)
{
Setup_Screen_Reflections(vp, taa);
}
if (aolighting)
{
gpupart("ambient occlusion");
Setup_Ao_Lighting(vp);
}
}
if (vp.main)
m_contactshadowslast = m_contactshadows;
@@ -1946,14 +1973,17 @@ void opengl46_renderer::Render_pass(viewport_config &vp, rendermode const Mode)
}
}
if (m_contactshadows || m_ssractive)
if (m_contactshadows || m_ssractive || m_aolighting || m_cabprobelit)
{
// the depth they read is of this view only
// the depth they read is of this view only, and so is the probe of the cab
m_contactshadows = false;
m_ssractive = false;
m_cabprobelit = false;
scene_ubs.contact_shadow_params = glm::vec4{0.f};
scene_ubs.contact_shadow_lamps = glm::vec4{0.f};
scene_ubs.ao_params = glm::vec4{0.f};
gfx::screen_reflections::clear(scene_ubs);
gfx::cab_probe::clear_scene(scene_ubs);
scene_ubo->update(scene_ubs);
}
@@ -1970,8 +2000,10 @@ void opengl46_renderer::Render_pass(viewport_config &vp, rendermode const Mode)
if (!Global.gfx_skippipeline)
{
gpupart("resolve, ambient occlusion, motion blur");
// the targets of the ambient occlusion are there only when it was on at the start
auto const aomode{(vp.ssao_tex != nullptr) ? Global.gfx_postfx_ao : 0};
// the targets of the ambient occlusion are there only when it was on at the start. in the light of the surfaces it's
// in the image already
auto const aomode{((vp.ssao_tex != nullptr) && (false == m_aolighting)) ? Global.gfx_postfx_ao : 0};
m_aolighting = false;
if (motionblur || taa)
{
vp.main_fb->clear(GL_COLOR_BUFFER_BIT);
@@ -3297,7 +3329,7 @@ void opengl46_renderer::Bind_Material( material_handle const Material, TSubModel
material.textures :
material.GetTextures(TSubModel::VariantId(sm))};
if (m_scenedepthpass)
if (m_scenedepthpass || m_cabprobepass)
{
// the depth of the whole scene: the programs of the depth prepass, the same choice as for the instances in
// Render_Instances_Indirect(). what they can't draw (blended, materials of other programs) is left to the colour pass
@@ -3307,6 +3339,24 @@ void opengl46_renderer::Bind_Material( material_handle const Material, TSubModel
auto const prepassclass{Prepass_Class(Material)};
if (prepassclass == 0)
return;
if (m_cabprobepass)
{
// the probe of the cab: the programs of the probe, of the same materials, the albedo from the diffuse texture (a white
// one without it), alpha tested as the depth prepass tests it
auto texturebound{false};
if (materialtextures[0] != null_handle)
texturebound = m_textures.mark_as_used(materialtextures[0]).bind(0);
if (false == texturebound)
{
if (prepassclass == 2)
return;
::glBindTextureUnit(0, m_cabprobe.white());
opengl_texture::units[0] = m_cabprobe.white();
}
m_cabprobe.program(prepassclass == 2).bind();
m_scenedepthskip = false;
return;
}
if (prepassclass == 2)
{
// a texture which isn't there (yet) would leave the one bound before to the alpha test
@@ -3488,7 +3538,7 @@ void opengl46_renderer::draw(const gfx::geometry_handle &handle)
Record_Scene_Draw( &handle, 1, false );
return;
}
if( m_scenedepthpass && ( false == Scene_Depth_Draws( handle ) ) ) {
if( ( m_scenedepthpass || m_cabprobepass ) && ( false == Scene_Depth_Draws( handle ) ) ) {
return;
}
model_ubo->update(model_ubs);
@@ -3512,7 +3562,7 @@ void opengl46_renderer::draw(std::vector<gfx::geometrybank_handle>::iterator it,
}
return;
}
if( m_scenedepthpass && ( ( it == end ) || ( false == Scene_Depth_Draws( *it ) ) ) ) {
if( ( m_scenedepthpass || m_cabprobepass ) && ( ( it == end ) || ( false == Scene_Depth_Draws( *it ) ) ) ) {
return;
}
model_ubo->update(model_ubs);
@@ -4496,6 +4546,46 @@ void opengl46_renderer::Setup_Contact_Shadows( viewport_config &Viewport )
m_contactshadows = true;
}
// the ambient occlusion goes into the light of the surfaces of the colour pass of the main view (gfx.postfx.ao.lighting): the ground
// truth one, made from the depth of the whole scene drawn before the colour, which needs the targets of the occlusion and a
// perspective projection with the far plane at infinity (the distance of a surface worked out from its depth), as the contact shadows
bool opengl46_renderer::Ao_Lighting_Wanted( viewport_config const &Viewport ) const
{
if( ( Global.gfx_postfx_ao != 2 ) || ( false == Global.gfx_postfx_ao_lighting ) || ( false == Viewport.main ) || Global.bWireFrame || Global.gfx_skippipeline
|| ( Viewport.msaa_fb == nullptr ) || ( Viewport.ssao_tex == nullptr ) || ( Viewport.ssao_blur_tex == nullptr ) ) {
return false;
}
auto const &projection { scene_ubs.projection };
return ( projection[ 2 ][ 3 ] != 0.f ) && ( projection[ 2 ][ 2 ] == 0.f ) && ( projection[ 3 ][ 2 ] > 0.f );
}
void opengl46_renderer::Setup_Ao_Lighting( viewport_config &Viewport )
{
if( ( false == m_contactshadows ) && ( false == m_ssractive ) ) {
// the depth resolved apart from the buffer the colour pass draws to, as for the contact shadows
if( false == Resolved_Depth_Target( Viewport ) ) { return; }
Viewport.msaa_fb->bind();
auto const scissor { ::glIsEnabled( GL_SCISSOR_TEST ) == GL_TRUE };
if( scissor ) { ::glDisable( GL_SCISSOR_TEST ); }
::glBlitNamedFramebuffer(
*Viewport.msaa_fb, *Viewport.clusters_depth_fb,
0, 0, Viewport.width, Viewport.height, 0, 0, Viewport.width, Viewport.height,
GL_DEPTH_BUFFER_BIT, GL_NEAREST );
if( scissor ) { ::glEnable( GL_SCISSOR_TEST ); }
::glBindTextureUnit( gl::SCENE_DEPTH_TEX, Viewport.clusters_depth_tex->id );
}
glDebug( "ambient occlusion" );
// the projection the depth was drawn with
m_ao.compute( *Viewport.clusters_depth_tex, *Viewport.ssao_tex, *Viewport.ssao_blur_tex, m_colorpass.pass_camera.projection() );
m_ao.end_timing();
// the compute passes leave the units of the textures to be bound anew
::glBindTextureUnit( gl::SCENE_DEPTH_TEX, Viewport.clusters_depth_tex->id );
::glBindTextureUnit( gl::SCENE_AO_TEX, Viewport.ssao_blur_tex->id );
scene_ubs.ao_params = glm::vec4{ 1.f, Global.gfx_postfx_ao_strength, 0.f, 0.f };
scene_ubo->update( scene_ubs );
m_aolighting = true;
}
// Renders the per-track sleeper instances (TTrack::m_sleeper_local_transforms) using the
// existing GPU-instanced submodel pipeline. The track owns a vector of pre-baked
// local-space matrices; we compose each with `view * translate(track_origin - camera)`
@@ -6194,6 +6284,54 @@ void opengl46_renderer::Render_local_shadows()
glPolygonMode(GL_FRONT_AND_BACK, Global.bWireFrame ? GL_LINE : GL_FILL);
}
TDynamicObject *opengl46_renderer::Cab_Probe_Vehicle() const
{
if (FreeFlyModeFlag || (false == Global.render_cab) || (simulation::Train == nullptr))
return nullptr;
auto *vehicle{simulation::Train->Dynamic()};
if ((vehicle == nullptr) || (false == vehicle->bDisplayCab) || (vehicle->mdKabina == nullptr) || (vehicle->mdKabina == vehicle->mdModel))
return nullptr;
return vehicle;
}
void opengl46_renderer::Render_cab_probe()
{
auto *vehicle{Cab_Probe_Vehicle()};
glm::vec3 center{0.f};
glm::vec3 extent{0.f};
if ((vehicle != nullptr) && (false == m_locallights.cab_bounds(vehicle->mdKabina, m_geometry, center, extent)))
vehicle = nullptr;
// the cab lamp lights the probe when it's a light of the frame
auto const *lamp{(vehicle != nullptr) && (m_locallights.cab_lamp_vehicle() == vehicle) ? m_locallights.cab_lamp() : nullptr};
if (false == m_cabprobe.update_wanted(vehicle, (vehicle != nullptr ? vehicle->mdKabina : nullptr), center, extent, lamp, m_framestamp))
return;
glDebug("render cab probe");
// the lamp with its shadow map, when the map holds the shadows of the lamp where it is
auto const shadows{(lamp != nullptr) && m_localshadows.ready(vehicle) && (m_localshadows.lamp() == m_locallights.cab_lamp_local())};
m_cabprobe.setup_drawing(scene_ubs, lamp, m_locallights.cab_lamp_local(), shadows, m_localshadows.weights());
scene_ubo->update(scene_ubs);
// the cab drawn by the colour mode with the programs of the probe. the camera is put at the vehicle, which Render_cab() places
// the cab relative to, and the modelview takes the cab model to the space of the probe
m_renderpass.draw_mode = rendermode::color;
m_renderpass.pass_camera.position() = vehicle->GetPosition();
m_renderpass.draw_stats = {};
OpenGLMatrices.mode(GL_MODELVIEW);
OpenGLMatrices.load_matrix(glm::mat4{m_cabprobe.model_to_probe() * glm::inverse(vehicle->mMatrix)});
setup_drawing(false);
m_cabprobe.begin();
m_cabprobepass = true;
m_scenedepthskip = true;
Render_cab(vehicle, 0.0f, false);
m_cabprobepass = false;
m_scenedepthskip = true;
m_cabprobe.end(static_cast<std::uint32_t>(m_renderpass.draw_stats.drawcalls));
m_renderpass = m_colorpass;
glPolygonMode(GL_FRONT_AND_BACK, Global.bWireFrame ? GL_LINE : GL_FILL);
// the maps may have been made anew
m_cabprobe.bind();
}
void opengl46_renderer::Render_lamp_shadows()
{
m_lampscenerydrawn = 0;

View File

@@ -43,6 +43,7 @@ http://mozilla.org/MPL/2.0/.
#include "rendering/opengl46/opengl46ao.h"
#include "rendering/common/locallights.h"
#include "rendering/opengl46/opengl46localshadows.h"
#include "rendering/opengl46/opengl46cabprobe.h"
#include "rendering/opengl46/opengl46instancecull.h"
#include "rendering/opengl46/opengl46hiz.h"
#include "rendering/opengl46/opengl46shadowfit.h"
@@ -319,6 +320,10 @@ class opengl46_renderer : public gfx_renderer, public gfx::scene_walk {
bool Render_reflections(viewport_config &vp);
// draws the cube shadow maps of the lamps which need it in this frame (the cab lamp: the cab)
void Render_local_shadows();
// the occupied vehicle whose cab is drawn in the colour pass, nullptr when there's none (the conditions of Render_cab())
TDynamicObject *Cab_Probe_Vehicle() const;
// draws the probe of the occupied cab when it needs it in this frame
void Render_cab_probe();
// draws the parts of the cube shadow maps of the scenery lamps which need it in this frame
void Render_lamp_shadows();
// one part of the map of a scenery lamp: the scenery, or the vehicles by it (and Cab, the occupied cab) over a copy of it
@@ -415,6 +420,11 @@ class opengl46_renderer : public gfx_renderer, public gfx::scene_walk {
void Setup_Contact_Shadows( viewport_config &Viewport );
// makes the target of the resolved depth of the viewport if it isn't there yet; false if it can't be made
bool Resolved_Depth_Target( viewport_config &Viewport );
// whether the colour pass of the viewport takes the ambient occlusion into the light of its surfaces (gfx.postfx.ao.lighting),
// which needs the depth pass of the scene
bool Ao_Lighting_Wanted( viewport_config const &Viewport ) const;
// works out the ambient occlusion of the depth drawn by Render_Scene_Depth() and sets it up for the colour pass
void Setup_Ao_Lighting( viewport_config &Viewport );
// resolves the depth drawn so far in the colour pass of the viewport for the soft particles (gfx.particles.soft) and binds it
// to gl::SCENE_DEPTH_TEX; false when the viewport has no such depth
bool Setup_Particles_Depth( viewport_config &Viewport );
@@ -708,6 +718,9 @@ class opengl46_renderer : public gfx_renderer, public gfx::scene_walk {
// contact shadows: set up for the colour pass under way, and whether the last main view had them
bool m_contactshadows { false };
bool m_contactshadowslast { false };
// the ambient occlusion of the colour pass of the main view under way is in the light of its surfaces (gfx.postfx.ao.lighting),
// not applied to its image
bool m_aolighting { false };
// a vehicle drawn in the colour pass of the last frame moved, and one drawn in this frame did (motion blur, Render_pass())
bool m_vehiclesmoved { true };
gl::gpu_timer m_contactshadowstimer; // resolve of the depth
@@ -767,6 +780,9 @@ class opengl46_renderer : public gfx_renderer, public gfx::scene_walk {
opengl46_local_shadows m_localshadows;
// the shadow pass draws to a cube shadow map, with the programs of m_localshadows
bool m_cubeshadows = false;
// the probe of the occupied cab, and the colour mode draws the cab into it with its programs (Render_cab_probe())
opengl46_cab_probe m_cabprobe;
bool m_cabprobepass = false;
double m_precipitationrotation;