Skip to content

Commit

Permalink
Zephyr: Renderer: implement more proper frustum culling (WIP)
Browse files Browse the repository at this point in the history
  • Loading branch information
fleroviux committed May 11, 2024
1 parent 86fbfac commit 5a48502
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 33 deletions.
5 changes: 4 additions & 1 deletion app/next/src/main_window.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
#include "main_window.hpp"

static const bool enable_validation_layers = true;
static const bool benchmark_scene_size = false;
static const bool benchmark_scene_size = true;

namespace zephyr {

Expand Down Expand Up @@ -262,6 +262,9 @@ namespace zephyr {
};
std::copy_n(index_data, sizeof(index_data) / sizeof(u32), indices.begin());

fmt::print("min: {} {} {}\n", cube_geometry->GetAABB().Min().X(), cube_geometry->GetAABB().Min().Y(), cube_geometry->GetAABB().Min().X());
fmt::print("max: {} {} {}\n", cube_geometry->GetAABB().Max().X(), cube_geometry->GetAABB().Max().Y(), cube_geometry->GetAABB().Max().X());

const int grid_size = 37;

for(int x = -grid_size / 2; x < grid_size / 2; x++) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ namespace zephyr {
};

struct RenderCamera {
/**
* This struct may be uploaded to a GPU buffer directly and therefore must match the following std430/std140 data layout:
* mat4 projection;
* mat4 view;
* vec4 frustum_planes[6];
*/
Matrix4 projection{};
Matrix4 view{};
Frustum frustum{};
Expand Down
99 changes: 69 additions & 30 deletions zephyr/renderer/src/backend/opengl/render_backend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,14 @@ namespace zephyr {
glCreateBuffers(1u, &m_gl_render_bundle_ssbo);
glNamedBufferStorage(m_gl_render_bundle_ssbo, sizeof(RenderBundleItem) * k_max_draws_per_draw_call, nullptr, GL_DYNAMIC_STORAGE_BIT);

glCreateBuffers(1u, &m_gl_draw_list_ssbo);
glNamedBufferStorage(m_gl_draw_list_ssbo, sizeof(OpenGLDrawElementsIndirectCommand) * k_max_draws_per_draw_call, nullptr, 0);
glCreateBuffers(1u, &m_gl_draw_list_command_ssbo);
glNamedBufferStorage(m_gl_draw_list_command_ssbo, sizeof(OpenGLDrawElementsIndirectCommand) * k_max_draws_per_draw_call, nullptr, 0);

glCreateBuffers(1u, &m_gl_draw_list_transform_ssbo);
glNamedBufferStorage(m_gl_draw_list_transform_ssbo, sizeof(Matrix4) * k_max_draws_per_draw_call, nullptr, 0);

glCreateBuffers(1u, &m_gl_camera_ubo);
glNamedBufferStorage(m_gl_camera_ubo, sizeof(Matrix4), nullptr, GL_DYNAMIC_STORAGE_BIT);
glNamedBufferStorage(m_gl_camera_ubo, sizeof(RenderCamera), nullptr, GL_DYNAMIC_STORAGE_BIT);

glCreateBuffers(1u, &m_gl_draw_count_ubo);
glNamedBufferStorage(m_gl_draw_count_ubo, sizeof(u32), nullptr, GL_DYNAMIC_STORAGE_BIT);
Expand All @@ -45,7 +48,8 @@ namespace zephyr {
glDeleteBuffers(1u, &m_gl_draw_count_out_ac);
glDeleteBuffers(1u, &m_gl_draw_count_ubo);
glDeleteBuffers(1u, &m_gl_camera_ubo);
glDeleteBuffers(1u, &m_gl_draw_list_ssbo);
glDeleteBuffers(1u, &m_gl_draw_list_transform_ssbo);
glDeleteBuffers(1u, &m_gl_draw_list_command_ssbo);
glDeleteBuffers(1u, &m_gl_render_bundle_ssbo);
glDeleteProgram(m_gl_draw_list_builder_program);
glDeleteProgram(m_gl_draw_program);
Expand Down Expand Up @@ -93,12 +97,12 @@ namespace zephyr {
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

const Matrix4 view_projection = render_camera.projection * render_camera.view;
glNamedBufferSubData(m_gl_camera_ubo, 0, sizeof(Matrix4), &view_projection);
glNamedBufferSubData(m_gl_camera_ubo, 0, sizeof(RenderCamera), &render_camera);

// TODO(fleroviux): attempt to keep buffers bound throughout the entire rendering process for minimal number of OpenGL calls.
// TODO(fleroviux): attempt to keep more buffers bound throughout the entire rendering process for minimal number of OpenGL calls.

glBindBufferBase(GL_UNIFORM_BUFFER, 0u, m_gl_camera_ubo);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0u, m_gl_draw_list_transform_ssbo);

for(const auto& [key, render_bundle] : render_bundles) {
const size_t render_bundle_size = render_bundle.size();
Expand All @@ -115,19 +119,19 @@ namespace zephyr {
{
glUseProgram(m_gl_draw_list_builder_program);

glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0u, m_render_geometry_manager->GetDrawCommandBuffer());
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1u, m_gl_render_bundle_ssbo);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2u, m_gl_draw_list_ssbo);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2u, m_render_geometry_manager->GetGeometryRenderDataBuffer());
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3u, m_gl_draw_list_command_ssbo);
glBindBufferBase(GL_UNIFORM_BUFFER, 1u, m_gl_draw_count_ubo);
glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0u, m_gl_draw_count_out_ac);

const GLuint workgroup_size = 32u;
const GLuint workgroup_group_count = (number_of_draws + workgroup_size - 1u) / workgroup_size;
glDispatchCompute(workgroup_group_count, 1u, 1u);

glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0u, 0u);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1u, 0u);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2u, 0u);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3u, 0u);
glBindBufferBase(GL_UNIFORM_BUFFER, 1u, 0u);
glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0u, 0u);
}
Expand All @@ -137,22 +141,21 @@ namespace zephyr {
glUseProgram(m_gl_draw_program);

glBindVertexArray(m_render_geometry_manager->GetVAOFromLayout(RenderGeometryLayout{key}));
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, m_gl_draw_list_ssbo);
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, m_gl_draw_list_command_ssbo);
glBindBuffer(GL_PARAMETER_BUFFER, m_gl_draw_count_out_ac);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0u, m_gl_render_bundle_ssbo);

glMemoryBarrier(GL_COMMAND_BARRIER_BIT | GL_ATOMIC_COUNTER_BARRIER_BIT);
glMultiDrawElementsIndirectCount(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr, 0u, (GLsizei)number_of_draws, sizeof(OpenGLDrawElementsIndirectCommand));

glBindVertexArray(0u);
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0u);
glBindBuffer(GL_PARAMETER_BUFFER, 0u);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0u, 0u);
}
}
}

glBindBufferBase(GL_UNIFORM_BUFFER, 0u, 0u);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0u, 0u);
}

void OpenGLRenderBackend::SwapBuffers() {
Expand All @@ -163,17 +166,13 @@ namespace zephyr {
GLuint vert_shader = CreateShader(R"(
#version 460 core
struct RenderBundleItem {
mat4 local_to_world;
uint draw_command_id;
};
layout(std430, binding = 0) readonly buffer RenderBundleBuffer {
RenderBundleItem rb_render_bundle_items[];
layout(std430, binding = 0) readonly buffer DrawListTransformBuffer {
mat4 rb_draw_list_transform[];
};
layout(std140, binding = 0) uniform Transform {
layout(std140, binding = 0) uniform Camera {
mat4 u_projection;
mat4 u_view;
};
layout(location = 0) in vec3 a_position;
Expand All @@ -187,7 +186,7 @@ namespace zephyr {
void main() {
v_normal = a_normal;
v_color = a_color;
gl_Position = u_projection * rb_render_bundle_items[gl_DrawID].local_to_world * vec4(a_position, 1.0);
gl_Position = u_projection * u_view * rb_draw_list_transform[gl_DrawID] * vec4(a_position, 1.0);
}
)", GL_VERTEX_SHADER);

Expand Down Expand Up @@ -231,20 +230,26 @@ namespace zephyr {
uint geometry_id;
};
layout(std430, binding = 0) readonly buffer GeometryBuffer {
RenderGeometryRenderData rb_render_geometry_render_data[];
layout(std430, binding = 0) buffer DrawListTransformBuffer {
mat4 b_draw_list_transform[];
};
layout(std430, binding = 1) readonly buffer RenderBundleBuffer {
RenderBundleItem rb_render_bundle_items[];
};
layout(std430, binding = 2) buffer CommandBuffer {
layout(std430, binding = 2) readonly buffer GeometryBuffer {
RenderGeometryRenderData rb_render_geometry_render_data[];
};
layout(std430, binding = 3) buffer CommandBuffer {
DrawIndirectCommand b_command_buffer[];
};
layout(std140, binding = 0) uniform Transform {
layout(std140, binding = 0) uniform Camera {
mat4 u_projection;
mat4 u_view;
vec4 u_frustum_planes[6];
};
layout(std140, binding = 1) uniform DrawCount {
Expand All @@ -265,10 +270,44 @@ namespace zephyr {
RenderBundleItem render_bundle_item = rb_render_bundle_items[draw_index];
RenderGeometryRenderData render_data = rb_render_geometry_render_data[render_bundle_item.geometry_id];
vec4 clip_aabb_center = u_projection * render_bundle_item.local_to_world * vec4((render_data.aabb_min.xyz + render_data.aabb_max.xyz) * 0.5, 1.0);
if(abs(clip_aabb_center.x) < clip_aabb_center.w && abs(clip_aabb_center.y) < clip_aabb_center.w && abs(clip_aabb_center.z) < clip_aabb_center.w) {
b_command_buffer[draw_index] = render_data.draw_command;
atomicCounterIncrement(u_draw_count_out);
bool inside_frustum = true;
vec4 model_aabb_min = render_data.aabb_min;
vec4 model_aabb_max = render_data.aabb_max;
mat4 mv = u_view * render_bundle_item.local_to_world;
// TODO(fleroviux): optimize this plenty!
vec4[] aabb_points = vec4[](
mv * vec4(model_aabb_min.x, model_aabb_min.y, model_aabb_min.z, 1.0),
mv * vec4(model_aabb_min.x, model_aabb_min.y, model_aabb_max.z, 1.0),
mv * vec4(model_aabb_min.x, model_aabb_max.y, model_aabb_min.z, 1.0),
mv * vec4(model_aabb_min.x, model_aabb_max.y, model_aabb_max.z, 1.0),
mv * vec4(model_aabb_max.x, model_aabb_min.y, model_aabb_min.z, 1.0),
mv * vec4(model_aabb_max.x, model_aabb_min.y, model_aabb_max.z, 1.0),
mv * vec4(model_aabb_max.x, model_aabb_max.y, model_aabb_min.z, 1.0),
mv * vec4(model_aabb_max.x, model_aabb_max.y, model_aabb_max.z, 1.0)
);
vec4 view_aabb_min = min(aabb_points[0], min(aabb_points[1], min(aabb_points[2], min(aabb_points[3], min(aabb_points[4], min(aabb_points[5], min(aabb_points[6], aabb_points[7])))))));
vec4 view_aabb_max = max(aabb_points[0], max(aabb_points[1], max(aabb_points[2], max(aabb_points[3], max(aabb_points[4], max(aabb_points[5], max(aabb_points[6], aabb_points[7])))))));
for(int i = 0; i < 6; i++) {
vec4 frustum_plane = u_frustum_planes[i];
// TODO(fleroviux): can this be shortened?
vec4 aabb_corner = vec4(
frustum_plane.x > 0 ? view_aabb_max.x : view_aabb_min.x,
frustum_plane.y > 0 ? view_aabb_max.y : view_aabb_min.y,
frustum_plane.z > 0 ? view_aabb_max.z : view_aabb_min.z,
-1.0
);
inside_frustum = inside_frustum && dot(aabb_corner, frustum_plane) >= 0.0;
}
if(inside_frustum) {
uint draw_id = atomicCounterIncrement(u_draw_count_out);
b_draw_list_transform[draw_id] = render_bundle_item.local_to_world;
b_command_buffer[draw_id] = render_data.draw_command;
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion zephyr/renderer/src/backend/opengl/render_backend.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ namespace zephyr {
GLuint m_gl_draw_program{};
GLuint m_gl_draw_list_builder_program{};
GLuint m_gl_render_bundle_ssbo{};
GLuint m_gl_draw_list_ssbo{};
GLuint m_gl_draw_list_command_ssbo{};
GLuint m_gl_draw_list_transform_ssbo{};
GLuint m_gl_camera_ubo{};
GLuint m_gl_draw_count_ubo{};
GLuint m_gl_draw_count_out_ac{};
Expand Down
2 changes: 1 addition & 1 deletion zephyr/renderer/src/backend/opengl/render_geometry.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ namespace zephyr {
return bucket.vao;
}

GLuint GetDrawCommandBuffer() {
GLuint GetGeometryRenderDataBuffer() {
return m_geometry_render_data->GetBufferHandle();
}

Expand Down
1 change: 1 addition & 0 deletions zephyr/renderer/src/render_engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ namespace zephyr {
const PerspectiveCameraComponent& camera_component = node->GetComponent<PerspectiveCameraComponent>();
m_render_camera[1].projection = camera_component.GetProjectionMatrix();
m_render_camera[1].view = node->GetTransform().GetWorld().Inverse();
m_render_camera[1].frustum = camera_component.GetFrustum();
}

return true;
Expand Down

0 comments on commit 5a48502

Please sign in to comment.