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:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
162
rendering/opengl46/opengl46cabprobe.cpp
Normal file
162
rendering/opengl46/opengl46cabprobe.cpp
Normal 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;
|
||||
}
|
||||
67
rendering/opengl46/opengl46cabprobe.h
Normal file
67
rendering/opengl46/opengl46cabprobe.h
Normal 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;
|
||||
};
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user