Browse Source

Add render stage base class and culling stage class

master
C. J. Howard 1 year ago
parent
commit
0b41ff3def
7 changed files with 187 additions and 37 deletions
  1. +1
    -0
      CMakeLists.txt
  2. +4
    -0
      src/render/context.hpp
  3. +8
    -37
      src/render/renderer.cpp
  4. +3
    -0
      src/render/renderer.hpp
  5. +49
    -0
      src/render/stage.hpp
  6. +77
    -0
      src/render/stage/culling-stage.cpp
  7. +45
    -0
      src/render/stage/culling-stage.hpp

+ 1
- 0
CMakeLists.txt View File

@ -1,5 +1,6 @@
cmake_minimum_required(VERSION 3.7) cmake_minimum_required(VERSION 3.7)
option(VERSION_STRING "Project version string" "0.0.0") option(VERSION_STRING "Project version string" "0.0.0")
project(antkeeper VERSION ${VERSION_STRING} LANGUAGES CXX) project(antkeeper VERSION ${VERSION_STRING} LANGUAGES CXX)

+ 4
- 0
src/render/context.hpp View File

@ -30,6 +30,7 @@ namespace scene
{ {
class camera; class camera;
class collection; class collection;
class object_base;
} }
namespace render { namespace render {
@ -80,6 +81,9 @@ struct context
/// Subframe interpolation factor. /// Subframe interpolation factor.
float alpha; float alpha;
/// List of objects visible to the active camera.
std::list<scene::object_base*> visible_objects;
}; };
} // namespace render } // namespace render

+ 8
- 37
src/render/renderer.cpp View File

@ -51,11 +51,15 @@ renderer::renderer()
// Allocate skinning palette // Allocate skinning palette
skinning_palette = new float4x4[MATERIAL_PASS_MAX_BONE_COUNT]; skinning_palette = new float4x4[MATERIAL_PASS_MAX_BONE_COUNT];
// Construct culling stage
culling_stage = new render::culling_stage();
} }
renderer::~renderer() renderer::~renderer()
{ {
delete[] skinning_palette; delete[] skinning_palette;
delete culling_stage;
} }
void renderer::render(float t, float dt, float alpha, const scene::collection& collection) const void renderer::render(float t, float dt, float alpha, const scene::collection& collection) const
@ -114,21 +118,15 @@ void renderer::render(float t, float dt, float alpha, const scene::collection& c
ctx.view_projection = ctx.projection * ctx.view; ctx.view_projection = ctx.projection * ctx.view;
ctx.exposure = std::exp2(-camera->get_exposure_tween().interpolate(alpha)); ctx.exposure = std::exp2(-camera->get_exposure_tween().interpolate(alpha));
// Execute culling stage
culling_stage->execute(ctx);
// Create render queue // Create render queue
render::queue queue; render::queue queue;
// Get camera culling volume
ctx.camera_culling_volume = camera->get_culling_mask();
if (!ctx.camera_culling_volume)
ctx.camera_culling_volume = &camera->get_world_bounds();
// Queue render operations for each visible scene object // Queue render operations for each visible scene object
for (const scene::object_base* object: *objects)
for (const scene::object_base* object: ctx.visible_objects)
{ {
// Skip inactive objects
if (!object->is_active())
continue;
// Process object // Process object
process_object(ctx, queue, object); process_object(ctx, queue, object);
} }
@ -163,15 +161,6 @@ void renderer::process_model_instance(const render::context& ctx, render::queue&
if (!model) if (!model)
return; return;
// Get object culling volume
const geom::bounding_volume<float>* object_culling_volume = model_instance->get_culling_mask();
if (!object_culling_volume)
object_culling_volume = &model_instance->get_world_bounds();
// Perform view-frustum culling
if (!ctx.camera_culling_volume->intersects(*object_culling_volume))
return;
const std::vector<material*>* instance_materials = model_instance->get_materials(); const std::vector<material*>* instance_materials = model_instance->get_materials();
const std::vector<model_group*>* groups = model->get_groups(); const std::vector<model_group*>* groups = model->get_groups();
@ -213,15 +202,6 @@ void renderer::process_model_instance(const render::context& ctx, render::queue&
void renderer::process_billboard(const render::context& ctx, render::queue& queue, const scene::billboard* billboard) const void renderer::process_billboard(const render::context& ctx, render::queue& queue, const scene::billboard* billboard) const
{ {
// Get object culling volume
const geom::bounding_volume<float>* object_culling_volume = billboard->get_culling_mask();
if (!object_culling_volume)
object_culling_volume = &billboard->get_world_bounds();
// Perform view-frustum culling
if (!ctx.camera_culling_volume->intersects(*object_culling_volume))
return;
math::transform<float> billboard_transform = billboard->get_transform_tween().interpolate(ctx.alpha); math::transform<float> billboard_transform = billboard->get_transform_tween().interpolate(ctx.alpha);
billboard_op.material = billboard->get_material(); billboard_op.material = billboard->get_material();
billboard_op.depth = ctx.clip_near.signed_distance(float3(billboard_transform.translation)); billboard_op.depth = ctx.clip_near.signed_distance(float3(billboard_transform.translation));
@ -261,15 +241,6 @@ void renderer::process_lod_group(const render::context& ctx, render::queue& queu
void renderer::process_text(const render::context& ctx, render::queue& queue, const scene::text* text) const void renderer::process_text(const render::context& ctx, render::queue& queue, const scene::text* text) const
{ {
// Get object culling volume
const geom::bounding_volume<float>* object_culling_volume = text->get_culling_mask();
if (!object_culling_volume)
object_culling_volume = &text->get_world_bounds();
// Perform view-frustum culling
if (!ctx.camera_culling_volume->intersects(*object_culling_volume))
return;
text->render(ctx, queue); text->render(ctx, queue);
} }

+ 3
- 0
src/render/renderer.hpp View File

@ -23,6 +23,7 @@
#include "render/operation.hpp" #include "render/operation.hpp"
#include "render/context.hpp" #include "render/context.hpp"
#include "render/queue.hpp" #include "render/queue.hpp"
#include "render/stage/culling-stage.hpp"
#include "gl/vertex-array.hpp" #include "gl/vertex-array.hpp"
namespace scene namespace scene
@ -70,6 +71,8 @@ private:
mutable render::operation billboard_op; mutable render::operation billboard_op;
float4x4* skinning_palette; float4x4* skinning_palette;
render::culling_stage* culling_stage;
}; };
} // namespace render } // namespace render

+ 49
- 0
src/render/stage.hpp View File

@ -0,0 +1,49 @@
/*
* Copyright (C) 2023 Christopher J. Howard
*
* This file is part of Antkeeper source code.
*
* Antkeeper source code is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Antkeeper source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ANTKEEPER_RENDER_STAGE_HPP
#define ANTKEEPER_RENDER_STAGE_HPP
#include "render/context.hpp"
namespace render {
/**
* Abstract base class for a single stage in a render pipeline.
*/
class stage
{
public:
/// Constructs a render stage.
stage() = default;
/// Destructs a render stage.
virtual ~stage() = default;
/**
* Executes the render stage.
*
* @param ctx Render context.
*/
virtual void execute(render::context& ctx) = 0;
};
} // namespace render
#endif // ANTKEEPER_RENDER_STAGE_HPP

+ 77
- 0
src/render/stage/culling-stage.cpp View File

@ -0,0 +1,77 @@
/*
* Copyright (C) 2023 Christopher J. Howard
*
* This file is part of Antkeeper source code.
*
* Antkeeper source code is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Antkeeper source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#include "render/stage/culling-stage.hpp"
#include "scene/camera.hpp"
#include "scene/collection.hpp"
#include <algorithm>
#include <execution>
#include <mutex>
namespace render {
void culling_stage::execute(render::context& ctx)
{
// Get list of all objects in the collection
const std::list<scene::object_base*>& objects = *(ctx.collection->get_objects());
// Get camera culling volume
ctx.camera_culling_volume = ctx.camera->get_culling_mask();
if (!ctx.camera_culling_volume)
ctx.camera_culling_volume = &ctx.camera->get_world_bounds();
// Clear set of visible objects
ctx.visible_objects.clear();
// Construct mutex to guard set of visible objects
std::mutex mutex;
// For each object in the scene collection
std::for_each
(
std::execution::par_unseq,
std::begin(objects),
std::end(objects),
[&](scene::object_base* object)
{
// Ignore inactive objects and cameras
if (!object->is_active() || object->get_object_type_id() == scene::camera::object_type_id)
return;
// Cull object if it doesn't share any common layers with the camera
//if (!(object->get_layer_mask() & camera_layer_mask))
// return;
// Get object culling volume
const geom::bounding_volume<float>* object_culling_volume = object->get_culling_mask();
if (!object_culling_volume)
object_culling_volume = &object->get_world_bounds();
// Cull object if it's outside of the camera culling volume
if (!ctx.camera_culling_volume->intersects(*object_culling_volume))
return;
// Insert object into set of visible objects
std::lock_guard<std::mutex> guard(mutex);
ctx.visible_objects.push_back(object);
}
);
}
} // namespace render

+ 45
- 0
src/render/stage/culling-stage.hpp View File

@ -0,0 +1,45 @@
/*
* Copyright (C) 2023 Christopher J. Howard
*
* This file is part of Antkeeper source code.
*
* Antkeeper source code is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Antkeeper source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ANTKEEPER_RENDER_CULLING_STAGE_HPP
#define ANTKEEPER_RENDER_CULLING_STAGE_HPP
#include "render/stage.hpp"
namespace render {
/**
* Builds a set of scene objects visible to the current camera and stores it in the render context.
*/
class culling_stage: public stage
{
public:
/// Constructs a culling stage.
culling_stage() = default;
/// Destructs a culling stage.
virtual ~culling_stage() = default;
/// @copydoc render::stage::execute(render::context&)
virtual void execute(render::context& ctx) final;
};
} // namespace render
#endif // ANTKEEPER_RENDER_CULLING_STAGE_HPP

Loading…
Cancel
Save