Skip to content

Commit

Permalink
Merge branch 'occlusion_culling_no_query'
Browse files Browse the repository at this point in the history
  • Loading branch information
mrDIMAS committed Aug 27, 2024
2 parents 4e27d96 + 353a7e7 commit aa032b2
Show file tree
Hide file tree
Showing 8 changed files with 770 additions and 45 deletions.
75 changes: 47 additions & 28 deletions fyrox-impl/src/renderer/debug_renderer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,24 +23,26 @@
//! shapes, contact information (normals, positions, etc.), paths build by navmesh and so
//! on. It contains implementations to draw most common shapes (line, box, oob, frustum, etc).

use crate::core::sstorage::ImmutableString;
use crate::renderer::framework::geometry_buffer::ElementRange;
use crate::{
core::{algebra::Vector3, math::Rect, scope_profile},
renderer::framework::{
error::FrameworkError,
framebuffer::{DrawParameters, FrameBuffer},
geometry_buffer::{
AttributeDefinition, AttributeKind, BufferBuilder, ElementKind, GeometryBuffer,
GeometryBufferBuilder, GeometryBufferKind,
core::{algebra::Vector3, math::Rect, scope_profile, sstorage::ImmutableString},
renderer::{
framework::{
error::FrameworkError,
framebuffer::{DrawParameters, FrameBuffer},
geometry_buffer::{
AttributeDefinition, AttributeKind, BufferBuilder, ElementKind, ElementRange,
GeometryBuffer, GeometryBufferBuilder, GeometryBufferKind,
},
gpu_program::{GpuProgram, UniformLocation},
state::PipelineState,
},
gpu_program::{GpuProgram, UniformLocation},
state::PipelineState,
RenderPassStatistics,
},
renderer::RenderPassStatistics,
scene::{camera::Camera, debug::SceneDrawingContext},
scene::debug::Line,
};
use bytemuck::{Pod, Zeroable};
use fyrox_core::color::Color;
use rapier2d::na::Matrix4;

#[repr(C)]
#[derive(Copy, Pod, Zeroable, Clone)]
Expand All @@ -62,6 +64,22 @@ pub(crate) struct DebugShader {
wvp_matrix: UniformLocation,
}

/// "Draws" a rectangle into a list of lines.
pub fn draw_rect(rect: &Rect<f32>, lines: &mut Vec<Line>, color: Color) {
for (a, b) in [
(rect.left_top_corner(), rect.right_top_corner()),
(rect.right_top_corner(), rect.right_bottom_corner()),
(rect.right_bottom_corner(), rect.left_bottom_corner()),
(rect.left_bottom_corner(), rect.left_top_corner()),
] {
lines.push(Line {
begin: a.to_homogeneous(),
end: b.to_homogeneous(),
color,
});
}
}

impl DebugShader {
fn new(state: &PipelineState) -> Result<Self, FrameworkError> {
let fragment_source = include_str!("shaders/debug_fs.glsl");
Expand Down Expand Up @@ -104,23 +122,13 @@ impl DebugRenderer {
})
}

pub(crate) fn render(
&mut self,
state: &PipelineState,
viewport: Rect<i32>,
framebuffer: &mut FrameBuffer,
drawing_context: &SceneDrawingContext,
camera: &Camera,
) -> Result<RenderPassStatistics, FrameworkError> {
scope_profile!();

let mut statistics = RenderPassStatistics::default();

/// Uploads the new set of lines to GPU.
pub fn set_lines(&mut self, state: &PipelineState, lines: &[Line]) {
self.vertices.clear();
self.line_indices.clear();

let mut i = 0;
for line in drawing_context.lines.iter() {
for line in lines.iter() {
let color = line.color.into();
self.vertices.push(Vertex {
position: line.begin,
Expand All @@ -135,6 +143,18 @@ impl DebugRenderer {
}
self.geometry.set_buffer_data(state, 0, &self.vertices);
self.geometry.bind(state).set_lines(&self.line_indices);
}

pub(crate) fn render(
&mut self,
state: &PipelineState,
viewport: Rect<i32>,
framebuffer: &mut FrameBuffer,
view_projection: Matrix4<f32>,
) -> Result<RenderPassStatistics, FrameworkError> {
scope_profile!();

let mut statistics = RenderPassStatistics::default();

statistics += framebuffer.draw(
&self.geometry,
Expand All @@ -152,8 +172,7 @@ impl DebugRenderer {
},
ElementRange::Full,
|mut program_binding| {
program_binding
.set_matrix4(&self.shader.wvp_matrix, &camera.view_projection_matrix());
program_binding.set_matrix4(&self.shader.wvp_matrix, &view_projection);
},
)?;

Expand Down
50 changes: 43 additions & 7 deletions fyrox-impl/src/renderer/gbuffer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@
//! Every alpha channel is used for layer blending for terrains. This is inefficient, but for
//! now I don't know better solution.

use crate::renderer::debug_renderer::DebugRenderer;
use crate::renderer::visibility::OcclusionTester;
use crate::renderer::QualitySettings;
use crate::{
core::{
algebra::{Matrix4, Vector2},
Expand Down Expand Up @@ -65,6 +68,7 @@ use crate::{
mesh::{surface::SurfaceData, RenderPath},
},
};
use fxhash::FxHashSet;
use fyrox_core::math::Matrix4Ext;
use std::{cell::RefCell, rc::Rc};

Expand All @@ -78,6 +82,7 @@ pub struct GBuffer {
cube: GeometryBuffer,
decal_shader: DecalShader,
render_pass_name: ImmutableString,
occlusion_tester: OcclusionTester,
}

pub(crate) struct GBufferRenderContext<'a, 'b> {
Expand All @@ -87,15 +92,16 @@ pub(crate) struct GBufferRenderContext<'a, 'b> {
pub bundle_storage: &'a RenderDataBundleStorage,
pub texture_cache: &'a mut TextureCache,
pub shader_cache: &'a mut ShaderCache,
#[allow(dead_code)]
pub environment_dummy: Rc<RefCell<GpuTexture>>,
pub white_dummy: Rc<RefCell<GpuTexture>>,
pub normal_dummy: Rc<RefCell<GpuTexture>>,
pub black_dummy: Rc<RefCell<GpuTexture>>,
pub volume_dummy: Rc<RefCell<GpuTexture>>,
pub use_parallax_mapping: bool,
pub quality_settings: &'a QualitySettings,
pub graph: &'b Graph,
pub matrix_storage: &'a mut MatrixStorageCache,
#[allow(dead_code)]
pub screen_space_debug_renderer: &'a mut DebugRenderer,
pub unit_quad: &'a GeometryBuffer,
}

impl GBuffer {
Expand Down Expand Up @@ -247,6 +253,7 @@ impl GBuffer {
)?,
decal_framebuffer,
render_pass_name: ImmutableString::new("GBuffer"),
occlusion_tester: OcclusionTester::new(state, width, height, 64)?,
})
}

Expand Down Expand Up @@ -293,16 +300,41 @@ impl GBuffer {
bundle_storage,
texture_cache,
shader_cache,
use_parallax_mapping,
quality_settings,
white_dummy,
normal_dummy,
black_dummy,
volume_dummy,
graph,
matrix_storage,
unit_quad,
..
} = args;

let initial_view_projection = camera.view_projection_matrix();

let visibility = if quality_settings.use_occlusion_culling {
let mut objects = FxHashSet::default();
for bundle in bundle_storage.bundles.iter() {
for instance in bundle.instances.iter() {
objects.insert(instance.node_handle);
}
}
let objects = objects.into_iter().collect::<Vec<_>>();
self.occlusion_tester.check(
camera.global_position(),
&initial_view_projection,
state,
&self.framebuffer,
graph,
&objects,
None,
unit_quad,
)?
} else {
Default::default()
};

let viewport = Rect::new(0, 0, self.width, self.height);
self.framebuffer.clear(
state,
Expand All @@ -312,8 +344,6 @@ impl GBuffer {
Some(0),
);

let initial_view_projection = camera.view_projection_matrix();

let inv_view = camera.inv_view_matrix().unwrap();

let camera_up = inv_view.up();
Expand Down Expand Up @@ -349,6 +379,12 @@ impl GBuffer {
};

for instance in bundle.instances.iter() {
if quality_settings.use_occlusion_culling
&& !visibility.get(&instance.node_handle).map_or(true, |v| *v)
{
continue;
}

let apply_uniforms = |mut program_binding: GpuProgramBinding| {
let view_projection = if instance.depth_offset != 0.0 {
let mut projection = camera.projection_matrix();
Expand All @@ -372,7 +408,7 @@ impl GBuffer {
camera_up_vector: &camera_up,
camera_side_vector: &camera_side,
z_near: camera.projection().z_near(),
use_pom: use_parallax_mapping,
use_pom: quality_settings.use_parallax_mapping,
light_position: &Default::default(),
blend_shapes_storage: blend_shapes_storage.as_ref(),
blend_shapes_weights: &instance.blend_shapes_weights,
Expand Down
32 changes: 28 additions & 4 deletions fyrox-impl/src/renderer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,11 @@ pub struct QualitySettings {

/// Whether to use bloom effect.
pub use_bloom: bool,

/// Whether to use occlusion culling technique or not. Warning: this is experimental feature
/// that wasn't properly tested yet!
#[serde(default)]
pub use_occlusion_culling: bool,
}

impl Default for QualitySettings {
Expand Down Expand Up @@ -290,6 +295,7 @@ impl QualitySettings {

use_bloom: true,

use_occlusion_culling: false,
use_parallax_mapping: true,

csm_settings: Default::default(),
Expand Down Expand Up @@ -323,6 +329,7 @@ impl QualitySettings {

use_bloom: true,

use_occlusion_culling: false,
use_parallax_mapping: true,

csm_settings: CsmSettings {
Expand Down Expand Up @@ -361,6 +368,7 @@ impl QualitySettings {

use_bloom: true,

use_occlusion_culling: false,
use_parallax_mapping: false,

csm_settings: CsmSettings {
Expand Down Expand Up @@ -399,6 +407,7 @@ impl QualitySettings {

use_bloom: false,

use_occlusion_culling: false,
use_parallax_mapping: false,

csm_settings: CsmSettings {
Expand Down Expand Up @@ -670,6 +679,9 @@ pub struct Renderer {
quality_settings: QualitySettings,
/// Debug renderer instance can be used for debugging purposes
pub debug_renderer: DebugRenderer,
/// Screen space debug renderer instance can be used for debugging purposes to draw lines directly
/// on screen. It is useful to debug some rendering algorithms.
pub screen_space_debug_renderer: DebugRenderer,
/// A set of associated data for each scene that was rendered.
pub scene_data_map: FxHashMap<Handle<Scene>, AssociatedSceneData>,
backbuffer_clear_color: Color,
Expand Down Expand Up @@ -1290,6 +1302,7 @@ impl Renderer {
ui_renderer: UiRenderer::new(&state)?,
quality_settings: settings,
debug_renderer: DebugRenderer::new(&state)?,
screen_space_debug_renderer: DebugRenderer::new(&state)?,
scene_data_map: Default::default(),
backbuffer_clear_color: Color::BLACK,
texture_cache: Default::default(),
Expand Down Expand Up @@ -1657,14 +1670,15 @@ impl Renderer {
bundle_storage: &bundle_storage,
texture_cache: &mut self.texture_cache,
shader_cache: &mut self.shader_cache,
environment_dummy: self.environment_dummy.clone(),
use_parallax_mapping: self.quality_settings.use_parallax_mapping,
quality_settings: &self.quality_settings,
normal_dummy: self.normal_dummy.clone(),
white_dummy: self.white_dummy.clone(),
black_dummy: self.black_dummy.clone(),
volume_dummy: self.volume_dummy.clone(),
graph,
matrix_storage: &mut self.matrix_storage,
screen_space_debug_renderer: &mut self.screen_space_debug_renderer,
unit_quad: &self.quad,
})?;

state.set_polygon_fill_mode(PolygonFace::FrontAndBack, PolygonFillMode::Fill);
Expand Down Expand Up @@ -1807,12 +1821,13 @@ impl Renderer {
}

// Render debug geometry in the LDR frame buffer.
self.debug_renderer
.set_lines(state, &scene.drawing_context.lines);
scene_associated_data.statistics += self.debug_renderer.render(
state,
viewport,
&mut scene_associated_data.ldr_scene_framebuffer,
&scene.drawing_context,
camera,
camera.view_projection_matrix(),
)?;

for render_pass in self.scene_render_passes.iter() {
Expand Down Expand Up @@ -1925,6 +1940,15 @@ impl Renderer {
})?;
}

let screen_matrix =
Matrix4::new_orthographic(0.0, backbuffer_width, backbuffer_height, 0.0, -1.0, 1.0);
self.screen_space_debug_renderer.render(
&self.state,
window_viewport,
&mut self.backbuffer,
screen_matrix,
)?;

Ok(())
}

Expand Down
29 changes: 29 additions & 0 deletions fyrox-impl/src/renderer/shaders/visibility_fs.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
uniform int tileSize;
uniform usampler2D tileBuffer;
uniform float frameBufferHeight;

out vec4 FragColor;

flat in uint objectIndex;

void main()
{
int x = int(gl_FragCoord.x - 0.5) / tileSize;
int y = int(frameBufferHeight - gl_FragCoord.y - 0.5) / tileSize;

// TODO: Replace with binary search.
int bitIndex = -1;
for (int i = 0; i < 32; ++i) {
uint pixelObjectIndex = uint(texelFetch(tileBuffer, ivec2(x * 32 + i, y), 0).x);
if (pixelObjectIndex == objectIndex) {
bitIndex = i;
break;
}
}

if (bitIndex < 0) {
FragColor = vec4(0.0, 0.0, 0.0, 0.0);
} else {
FragColor = vec4(float(1 << bitIndex), 0.0, 0.0, 0.0);
}
}
Loading

0 comments on commit aa032b2

Please sign in to comment.