mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-10-17 03:59:19 +02:00
Build view-space light cluster grid in a compute pass
This commit is contained in:
@@ -169,6 +169,11 @@ bool opengl46_renderer::Init(GLFWwindow *Window)
|
||||
m_celestial_shader = make_shader("celestial.vert", "celestial.frag");
|
||||
m_hiddenarea_shader = make_shader("hiddenarea.vert", "hiddenarea.frag");
|
||||
m_copy_shader = make_shader("quad.vert", "copy.frag");
|
||||
{
|
||||
gl::shader cluster_build("cluster_build.comp");
|
||||
m_cluster_build_shader = std::make_unique<gl::program>(std::vector<std::reference_wrapper<const gl::shader>>{cluster_build});
|
||||
}
|
||||
m_cluster_heatmap_shader = make_shader("quad.vert", "cluster_heatmap.frag");
|
||||
m_invalid_material = Fetch_Material("invalid");
|
||||
}
|
||||
catch (gl::shader_exception const &e)
|
||||
@@ -456,6 +461,8 @@ bool opengl46_renderer::init_viewport(viewport_config &vp)
|
||||
scene_ubo->bind_uniform();
|
||||
light_ssbo->bind_base();
|
||||
|
||||
vp.clusters = std::make_unique<gl::cluster_grid>();
|
||||
|
||||
if (!Global.gfx_skippipeline)
|
||||
{
|
||||
vp.msaa_rbc = std::make_unique<gl::renderbuffer>();
|
||||
@@ -713,6 +720,18 @@ void opengl46_renderer::draw_debug_ui()
|
||||
}
|
||||
ImGui::End();
|
||||
|
||||
if (ImGui::Begin("Light clusters"))
|
||||
{
|
||||
ImGui::Checkbox("heatmap", &Global.gfx_lights_clusterheatmap);
|
||||
if (auto const &clusters{m_viewports.front()->clusters})
|
||||
{
|
||||
auto const ¶ms{clusters->params()};
|
||||
ImGui::Text("grid %u x %u x %u, %s", gl::CLUSTER_GRID_X, gl::CLUSTER_GRID_Y, gl::CLUSTER_GRID_Z, params.valid ? "built" : "none (orthographic view)");
|
||||
ImGui::Text("near %.3f m, far %.1f m", params.znear, params.zfar);
|
||||
}
|
||||
}
|
||||
ImGui::End();
|
||||
|
||||
ImGui::SetNextWindowSize(ImVec2S(400, 400));
|
||||
if (ImGui::Begin("Pickbuffer") && m_pick_tex) {
|
||||
ImGui::Image((ImTextureID)(intptr_t)(m_pick_tex->id), ImGui::GetContentRegionAvail(), ImVec2(0, 1.0), ImVec2(1.0, 0));
|
||||
@@ -897,6 +916,7 @@ void opengl46_renderer::Render_pass(viewport_config &vp, rendermode const Mode)
|
||||
future = glm::translate(mv, -glm::vec3(vehicle->get_future_movement())) * glm::inverse(mv);
|
||||
}
|
||||
|
||||
Update_Clusters( vp );
|
||||
Update_Lights( simulation::Lights );
|
||||
|
||||
glDebug("render environment");
|
||||
@@ -1049,6 +1069,9 @@ if (!Global.gfx_skippipeline)
|
||||
m_pfx_tonemapping->apply( *vp.main2_tex, target );
|
||||
}
|
||||
|
||||
if (Global.gfx_lights_clusterheatmap && vp.clusters->valid())
|
||||
Render_cluster_heatmap(vp, target, target_size);
|
||||
|
||||
if (vr) {
|
||||
if (vp.proj_type == viewport_config::vr_left)
|
||||
vr->submit(vr_interface::eye_left, vp.backbuffer_tex.get());
|
||||
@@ -1587,6 +1610,8 @@ void opengl46_renderer::setup_pass(viewport_config &Viewport, renderpass_config
|
||||
auto const znear = ( Znear > 1.f ? Znear : Znear > 0.f ? Znear * zfar : 0.1f * Global.ZoomFactor);
|
||||
if (EditorModeFlag && Viewport.main)
|
||||
zfar = editor_track_view_range(zfar, true);
|
||||
Config.znear = znear;
|
||||
Config.zfar = zfar;
|
||||
|
||||
camera.projection() = perspective_projection(Viewport.projection, znear, zfar, frustumtest_proj);
|
||||
editor_ortho_projection(Viewport, zfar, camera.projection(), frustumtest_proj);
|
||||
@@ -6004,6 +6029,78 @@ void opengl46_renderer::Update_Lights(light_array &Lights)
|
||||
light_ssbo->update(light_data);
|
||||
}
|
||||
|
||||
void opengl46_renderer::Update_Clusters(viewport_config &vp)
|
||||
{
|
||||
glDebug("Update_Clusters");
|
||||
|
||||
auto &grid{*vp.clusters};
|
||||
grid.bind();
|
||||
// the boxes of the clusters depend only on the projection and the depth range, so they are rebuilt only when those change
|
||||
if (grid.update(OpenGLMatrices.data(GL_PROJECTION), m_renderpass.znear, m_renderpass.zfar, glm::vec2{static_cast<float>(vp.width), static_cast<float>(vp.height)}))
|
||||
{
|
||||
m_clusterstimer.begin();
|
||||
grid.build(*m_cluster_build_shader);
|
||||
m_clusterstimer.end();
|
||||
}
|
||||
}
|
||||
|
||||
void opengl46_renderer::Render_cluster_heatmap(viewport_config &vp, gl::framebuffer *Target, glm::ivec2 const &Targetsize)
|
||||
{
|
||||
glDebug("Render_cluster_heatmap");
|
||||
|
||||
if (!vp.msaa_fb)
|
||||
return;
|
||||
|
||||
if (!vp.clusters_depth_fb)
|
||||
{
|
||||
auto texture{std::make_unique<opengl_texture>()};
|
||||
texture->alloc_rendertarget(Global.gfx_format_depth, GL_DEPTH_COMPONENT, vp.width, vp.height, 1, 1, GL_CLAMP_TO_EDGE);
|
||||
// render target textures of depth are made for the shadow sampler; here the values themselves are read
|
||||
glTextureParameteri(texture->id, GL_TEXTURE_COMPARE_MODE, GL_NONE);
|
||||
glTextureParameteri(texture->id, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTextureParameteri(texture->id, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
|
||||
auto framebuffer{std::make_unique<gl::framebuffer>()};
|
||||
framebuffer->attach(*texture, GL_DEPTH_ATTACHMENT);
|
||||
// depth only
|
||||
framebuffer->setup_drawing(0);
|
||||
if (!framebuffer->is_complete())
|
||||
{
|
||||
ErrorLog("cluster heatmap framebuffer setup failed");
|
||||
Global.gfx_lights_clusterheatmap = false;
|
||||
return;
|
||||
}
|
||||
vp.clusters_depth_tex = std::move(texture);
|
||||
vp.clusters_depth_fb = std::move(framebuffer);
|
||||
}
|
||||
|
||||
// the depth of the scene is still in the msaa buffer, the post processing worked on its colour
|
||||
vp.msaa_fb->blit_to(vp.clusters_depth_fb.get(), vp.width, vp.height, GL_DEPTH_BUFFER_BIT, GL_DEPTH_ATTACHMENT);
|
||||
|
||||
if (Target)
|
||||
Target->bind();
|
||||
else
|
||||
gl::framebuffer::unbind();
|
||||
glViewport(0, 0, Targetsize.x, Targetsize.y);
|
||||
|
||||
vp.clusters->bind();
|
||||
m_cluster_heatmap_shader->bind();
|
||||
m_empty_vao->bind();
|
||||
vp.clusters_depth_tex->bind(0);
|
||||
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDepthMask(GL_FALSE);
|
||||
auto const blending{glIsEnabled(GL_BLEND) == GL_TRUE};
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
if (!blending)
|
||||
glDisable(GL_BLEND);
|
||||
vp.clusters_depth_tex->unbind(0);
|
||||
}
|
||||
|
||||
bool opengl46_renderer::Init_caps()
|
||||
{
|
||||
std::string gl_renderer((char *)glGetString(GL_RENDERER));
|
||||
|
||||
@@ -22,6 +22,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "vr/vr_interface.h"
|
||||
#include "gl/ubo.h"
|
||||
#include "gl/ssbo.h"
|
||||
#include "gl/cluster_grid.h"
|
||||
#include "gl/framebuffer.h"
|
||||
#include "gl/renderbuffer.h"
|
||||
#include "gl/postfx.h"
|
||||
@@ -206,6 +207,10 @@ class opengl46_renderer : public gfx_renderer {
|
||||
opengl_camera viewport_camera;
|
||||
rendermode draw_mode{rendermode::none};
|
||||
float draw_range{0.0f};
|
||||
// depth range of the projection of a color pass; the far plane is only the end of the range which is drawn,
|
||||
// as the projection matrix itself has none
|
||||
float znear{0.0f};
|
||||
float zfar{0.0f};
|
||||
debug_stats draw_stats;
|
||||
};
|
||||
|
||||
@@ -256,6 +261,12 @@ class opengl46_renderer : public gfx_renderer {
|
||||
std::unique_ptr<gl::framebuffer> backbuffer_fb;
|
||||
std::unique_ptr<opengl_texture> backbuffer_tex;
|
||||
|
||||
// light cluster grid of the viewport
|
||||
std::unique_ptr<gl::cluster_grid> clusters;
|
||||
// depth of the finished scene resolved from the msaa buffer, for the cluster heatmap; made when it is first needed
|
||||
std::unique_ptr<gl::framebuffer> clusters_depth_fb;
|
||||
std::unique_ptr<opengl_texture> clusters_depth_tex;
|
||||
|
||||
bool initialized = false;
|
||||
};
|
||||
|
||||
@@ -331,6 +342,11 @@ class opengl46_renderer : public gfx_renderer {
|
||||
void Render_Alpha(TSubModel *Submodel);
|
||||
void Render_Alpha_text(TSubModel *Submodel); // characters of a text display
|
||||
void Update_Lights(light_array &Lights);
|
||||
// brings the light cluster grid of the viewport up to date with the projection of the color pass being drawn
|
||||
void Update_Clusters(viewport_config &vp);
|
||||
// debug view: tints the finished image of the viewport with the cluster of every pixel. Target is the framebuffer
|
||||
// holding the image (null for the default one), Targetsize its size
|
||||
void Render_cluster_heatmap(viewport_config &vp, gl::framebuffer *Target, glm::ivec2 const &Targetsize);
|
||||
glm::vec3 pick_color(std::size_t const Index);
|
||||
std::size_t pick_index(glm::ivec3 const &Color);
|
||||
|
||||
@@ -500,6 +516,8 @@ class opengl46_renderer : public gfx_renderer {
|
||||
std::unique_ptr<gl::program> m_celestial_shader;
|
||||
std::unique_ptr<gl::program> m_hiddenarea_shader;
|
||||
std::unique_ptr<gl::program> m_copy_shader;
|
||||
std::unique_ptr<gl::program> m_cluster_build_shader;
|
||||
std::unique_ptr<gl::program> m_cluster_heatmap_shader;
|
||||
|
||||
std::unique_ptr<gl::vao> m_empty_vao;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user