Browse Source

Separate render context into a render context and render queue. Change signature of render pass render functions. Pass time variables to render context. Add a visitor pattern render function to scene objects. Add a refresh function for text objects. Remove obsolete time tweens.

master
C. J. Howard 2 years ago
parent
commit
1e7328c1aa
35 changed files with 299 additions and 268 deletions
  1. +6
    -1
      src/entity/systems/render.cpp
  2. +2
    -0
      src/entity/systems/render.hpp
  3. +0
    -15
      src/game/bootloader.cpp
  4. +0
    -1
      src/game/context.hpp
  5. +2
    -2
      src/renderer/compositor.cpp
  6. +3
    -2
      src/renderer/compositor.hpp
  7. +34
    -6
      src/renderer/context.hpp
  8. +6
    -3
      src/renderer/operation.hpp
  9. +2
    -2
      src/renderer/passes/bloom-pass.cpp
  10. +1
    -1
      src/renderer/passes/bloom-pass.hpp
  11. +1
    -1
      src/renderer/passes/clear-pass.cpp
  12. +1
    -1
      src/renderer/passes/clear-pass.hpp
  13. +4
    -11
      src/renderer/passes/final-pass.cpp
  14. +1
    -4
      src/renderer/passes/final-pass.hpp
  15. +30
    -37
      src/renderer/passes/material-pass.cpp
  16. +1
    -5
      src/renderer/passes/material-pass.hpp
  17. +6
    -6
      src/renderer/passes/outline-pass.cpp
  18. +1
    -1
      src/renderer/passes/outline-pass.hpp
  19. +12
    -12
      src/renderer/passes/shadow-map-pass.cpp
  20. +1
    -1
      src/renderer/passes/shadow-map-pass.hpp
  21. +20
    -27
      src/renderer/passes/sky-pass.cpp
  22. +1
    -3
      src/renderer/passes/sky-pass.hpp
  23. +6
    -12
      src/renderer/passes/ui-pass.cpp
  24. +1
    -4
      src/renderer/passes/ui-pass.hpp
  25. +33
    -0
      src/renderer/queue.hpp
  26. +3
    -3
      src/renderer/render-pass.hpp
  27. +48
    -52
      src/renderer/renderer.cpp
  28. +12
    -11
      src/renderer/renderer.hpp
  29. +1
    -1
      src/renderer/shader-template.hpp
  30. +5
    -14
      src/renderer/simple-render-pass.cpp
  31. +1
    -5
      src/renderer/simple-render-pass.hpp
  32. +3
    -0
      src/scene/object.cpp
  33. +13
    -0
      src/scene/object.hpp
  34. +29
    -0
      src/scene/text.cpp
  35. +9
    -24
      src/scene/text.hpp

+ 6
- 1
src/entity/systems/render.cpp View File

@ -32,6 +32,8 @@ namespace system {
render::render(entity::registry& registry):
updatable(registry),
t(0.0),
dt(0.0),
renderer(nullptr)
{
registry.on_construct<component::model>().connect<&render::on_model_construct>(this);
@ -45,6 +47,9 @@ render::render(entity::registry& registry):
void render::update(double t, double dt)
{
this->t = t;
this->dt = dt;
// Update model instance transforms
registry.view<component::transform, component::model>().each
(
@ -101,7 +106,7 @@ void render::draw(double alpha)
{
for (const scene::collection* collection: layers)
{
renderer->render(alpha, *collection);
renderer->render(static_cast<float>(t + dt * alpha), static_cast<float>(dt), static_cast<float>(alpha), *collection);
}
}
}

+ 2
- 0
src/entity/systems/render.hpp View File

@ -64,6 +64,8 @@ private:
void on_light_replace(entity::registry& registry, entity::id entity_id, entity::component::light& light);
void on_light_destroy(entity::registry& registry, entity::id entity_id);
double t;
double dt;
renderer* renderer;
std::vector<scene::collection*> layers;
std::unordered_map<entity::id, scene::model_instance*> model_instances;

+ 0
- 15
src/game/bootloader.cpp View File

@ -766,10 +766,6 @@ void setup_animation(game::context* ctx)
// Setup animator
ctx->animator = new animator();
// Initialize time tween
ctx->time_tween = new tween<double>(0.0);
ctx->time_tween->set_interpolator(math::lerp<double, double>);
// Create fade transition
ctx->fade_transition = new screen_transition();
ctx->fade_transition->get_material()->set_shader_program(ctx->resource_manager->load<gl::shader_program>("fade-transition.glsl"));
@ -799,13 +795,6 @@ void setup_animation(game::context* ctx)
channel->insert_keyframe({0.0f, 1.0f});
channel->insert_keyframe({duration, 0.0f});
}
// Set material pass tweens
ctx->common_final_pass->set_time_tween(ctx->time_tween);
ctx->surface_sky_pass->set_time_tween(ctx->time_tween);
ctx->surface_material_pass->set_time_tween(ctx->time_tween);
ctx->underground_material_pass->set_time_tween(ctx->time_tween);
ctx->ui_material_pass->set_time_tween(ctx->time_tween);
}
void setup_entities(game::context* ctx)
@ -969,15 +958,11 @@ void setup_callbacks(game::context* ctx)
);
// Update tweens
ctx->time_tween->update();
ctx->surface_sky_pass->update_tweens();
ctx->surface_scene->update_tweens();
ctx->underground_scene->update_tweens();
ctx->ui_scene->update_tweens();
// Set time tween time
(*ctx->time_tween)[1] = t;
ctx->timeline->advance(dt);

+ 0
- 1
src/game/context.hpp View File

@ -202,7 +202,6 @@ struct context
// Animation
timeline* timeline;
animator* animator;
tween<double>* time_tween;
animation<float>* radial_transition_in;
animation<float>* radial_transition_out;
screen_transition* fade_transition;

+ 2
- 2
src/renderer/compositor.cpp View File

@ -35,13 +35,13 @@ void compositor::remove_passes()
passes.clear();
}
void compositor::composite(render_context* context) const
void compositor::composite(const render::context& ctx, render::queue& queue) const
{
for (const render_pass* pass: passes)
{
if (pass->is_enabled())
{
pass->render(context);
pass->render(ctx, queue);
}
}
}

+ 3
- 2
src/renderer/compositor.hpp View File

@ -20,10 +20,11 @@
#ifndef ANTKEEPER_COMPOSITOR_HPP
#define ANTKEEPER_COMPOSITOR_HPP
#include "renderer/context.hpp"
#include "renderer/queue.hpp"
#include <list>
class render_pass;
struct render_context;
/**
*
@ -35,7 +36,7 @@ public:
void remove_pass(render_pass* pass);
void remove_passes();
void composite(render_context* context) const;
void composite(const render::context& ctx, render::queue& queue) const;
const std::list<render_pass*>* get_passes() const;

src/renderer/render-context.hpp → src/renderer/context.hpp View File

@ -20,27 +20,55 @@
#ifndef ANTKEEPER_RENDER_CONTEXT_HPP
#define ANTKEEPER_RENDER_CONTEXT_HPP
#include "renderer/render-operation.hpp"
#include "geom/plane.hpp"
#include "geom/bounding-volume.hpp"
#include "utility/fundamental-types.hpp"
#include "scene/camera.hpp"
#include "scene/collection.hpp"
#include <list>
struct render_context
namespace scene
{
class camera;
class collection;
}
namespace render {
/**
* Context of a renderer.
*/
struct context
{
/// Pointer to the camera.
const scene::camera* camera;
/// Camera transform.
math::transform<float> camera_transform;
/// Camera forward vector
float3 camera_forward;
/// Camera up vector.
float3 camera_up;
/// Camera culling volume.
const geom::bounding_volume<float>* camera_culling_volume;
/// Near clipping plane of the camera
geom::plane<float> clip_near;
/// Collection of scene objects being rendered.
const scene::collection* collection;
std::list<render_operation> operations;
/// Current time, in seconds.
float t;
/// Timestep, in seconds.
float dt;
/// Subframe interpolation factor.
float alpha;
};
#endif // ANTKEEPER_RENDER_CONTEXT_HPP
} // namespace render
#endif // ANTKEEPER_RENDER_CONTEXT_HPP

src/renderer/render-operation.hpp → src/renderer/operation.hpp View File

@ -28,10 +28,12 @@
class pose;
class material;
namespace render {
/**
* Describes a render operation with a single mesh and single material.
* Encapsulates an atomic render operation.
*/
struct render_operation
struct operation
{
const pose* pose;
const material* material;
@ -44,5 +46,6 @@ struct render_operation
std::size_t instance_count;
};
#endif // ANTKEEPER_RENDER_OPERATION_HPP
} // namespace render
#endif // ANTKEEPER_RENDER_OPERATION_HPP

+ 2
- 2
src/renderer/passes/bloom-pass.cpp View File

@ -31,7 +31,7 @@
#include "gl/texture-wrapping.hpp"
#include "gl/texture-filter.hpp"
#include "renderer/vertex-attribute.hpp"
#include "renderer/render-context.hpp"
#include "renderer/context.hpp"
#include "math/math.hpp"
#include <cmath>
#include <glad/glad.h>
@ -114,7 +114,7 @@ bloom_pass::~bloom_pass()
delete quad_vbo;
}
void bloom_pass::render(render_context* context) const
void bloom_pass::render(const render::context& ctx, render::queue& queue) const
{
glDisable(GL_BLEND);
glDisable(GL_DEPTH_TEST);

+ 1
- 1
src/renderer/passes/bloom-pass.hpp View File

@ -38,7 +38,7 @@ class bloom_pass: public render_pass
public:
bloom_pass(gl::rasterizer* rasterizer, const gl::framebuffer* framebuffer, resource_manager* resource_manager);
virtual ~bloom_pass();
virtual void render(render_context* context) const final;
virtual void render(const render::context& ctx, render::queue& queue) const final;
void set_source_texture(const gl::texture_2d* texture);
void set_brightness_threshold(float threshold);

+ 1
- 1
src/renderer/passes/clear-pass.cpp View File

@ -35,7 +35,7 @@ clear_pass::clear_pass(gl::rasterizer* rasterizer, const gl::framebuffer* frameb
clear_pass::~clear_pass()
{}
void clear_pass::render(render_context* context) const
void clear_pass::render(const render::context& ctx, render::queue& queue) const
{
if (clear_color_buffer)
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);

+ 1
- 1
src/renderer/passes/clear-pass.hpp View File

@ -31,7 +31,7 @@ class clear_pass: public render_pass
public:
clear_pass(gl::rasterizer* rasterizer, const gl::framebuffer* framebuffer);
virtual ~clear_pass();
virtual void render(render_context* context) const final;
virtual void render(const render::context& ctx, render::queue& queue) const final;
void set_cleared_buffers(bool color, bool depth, bool stencil);

+ 4
- 11
src/renderer/passes/final-pass.cpp View File

@ -31,7 +31,7 @@
#include "gl/texture-wrapping.hpp"
#include "gl/texture-filter.hpp"
#include "renderer/vertex-attribute.hpp"
#include "renderer/render-context.hpp"
#include "renderer/context.hpp"
#include "math/math.hpp"
#include <cmath>
#include <glad/glad.h>
@ -41,8 +41,7 @@ final_pass::final_pass(gl::rasterizer* rasterizer, const gl::framebuffer* frameb
color_texture(nullptr),
bloom_texture(nullptr),
blue_noise_texture(nullptr),
blue_noise_scale(1.0),
time_tween(nullptr)
blue_noise_scale(1.0)
{
shader_program = resource_manager->load<gl::shader_program>("final.glsl");
color_texture_input = shader_program->get_input("color_texture");
@ -87,7 +86,7 @@ final_pass::~final_pass()
delete quad_vbo;
}
void final_pass::render(render_context* context) const
void final_pass::render(const render::context& ctx, render::queue& queue) const
{
rasterizer->use_framebuffer(*framebuffer);
@ -101,7 +100,6 @@ void final_pass::render(render_context* context) const
rasterizer->set_viewport(0, 0, std::get<0>(viewport), std::get<1>(viewport));
float2 resolution = {std::get<0>(viewport), std::get<1>(viewport)};
float time = (time_tween) ? (*time_tween)[context->alpha] : 0.0f;
// Change shader program
rasterizer->use_program(*shader_program);
@ -117,7 +115,7 @@ void final_pass::render(render_context* context) const
if (resolution_input)
resolution_input->upload(resolution);
if (time_input)
time_input->upload(time);
time_input->upload(ctx.t);
// Draw quad
rasterizer->draw_arrays(*quad_vao, gl::drawing_mode::triangles, 0, 6);
@ -138,8 +136,3 @@ void final_pass::set_blue_noise_texture(const gl::texture_2d* texture)
this->blue_noise_texture = texture;
blue_noise_scale = 1.0f / static_cast<float>(texture->get_dimensions()[0]);
}
void final_pass::set_time_tween(const tween<double>* time)
{
this->time_tween = time;
}

+ 1
- 4
src/renderer/passes/final-pass.hpp View File

@ -39,12 +39,11 @@ class final_pass: public render_pass
public:
final_pass(gl::rasterizer* rasterizer, const gl::framebuffer* framebuffer, resource_manager* resource_manager);
virtual ~final_pass();
virtual void render(render_context* context) const final;
virtual void render(const render::context& ctx, render::queue& queue) const final;
void set_color_texture(const gl::texture_2d* texture);
void set_bloom_texture(const gl::texture_2d* texture);
void set_blue_noise_texture(const gl::texture_2d* texture);
void set_time_tween(const tween<double>* time);
private:
gl::shader_program* shader_program;
@ -61,8 +60,6 @@ private:
const gl::texture_2d* bloom_texture;
const gl::texture_2d* blue_noise_texture;
float blue_noise_scale;
const tween<double>* time_tween;
};
#endif // ANTKEEPER_FINAL_PASS_HPP

+ 30
- 37
src/renderer/passes/material-pass.cpp View File

@ -34,7 +34,7 @@
#include "renderer/vertex-attribute.hpp"
#include "renderer/material-flags.hpp"
#include "renderer/model.hpp"
#include "renderer/render-context.hpp"
#include "renderer/context.hpp"
#include "scene/camera.hpp"
#include "scene/collection.hpp"
#include "scene/ambient-light.hpp"
@ -48,12 +48,11 @@
#include "shadow-map-pass.hpp"
static bool operation_compare(const render_operation& a, const render_operation& b);
static bool operation_compare(const render::operation& a, const render::operation& b);
material_pass::material_pass(gl::rasterizer* rasterizer, const gl::framebuffer* framebuffer, resource_manager* resource_manager):
render_pass(rasterizer, framebuffer),
fallback_material(nullptr),
time_tween(nullptr),
mouse_position({0.0f, 0.0f}),
shadow_map_pass(nullptr),
shadow_map(nullptr)
@ -98,7 +97,7 @@ material_pass::~material_pass()
delete[] spot_light_cutoffs;
}
void material_pass::render(render_context* context) const
void material_pass::render(const render::context& ctx, render::queue& queue) const
{
rasterizer->use_framebuffer(*framebuffer);
@ -119,10 +118,9 @@ void material_pass::render(render_context* context) const
float2 resolution = {static_cast<float>(std::get<0>(viewport)), static_cast<float>(std::get<1>(viewport))};
float time = time_tween->interpolate(context->alpha);
const float3& camera_position = context->camera_transform.translation;
float4x4 view = context->camera->get_view_tween().interpolate(context->alpha);
float4x4 projection = context->camera->get_projection_tween().interpolate(context->alpha);
const float3& camera_position = ctx.camera_transform.translation;
float4x4 view = ctx.camera->get_view_tween().interpolate(ctx.alpha);
float4x4 projection = ctx.camera->get_projection_tween().interpolate(ctx.alpha);
float4x4 view_projection = projection * view;
float4x4 model_view_projection;
float4x4 model;
@ -130,11 +128,11 @@ void material_pass::render(render_context* context) const
float3x3 normal_model;
float3x3 normal_model_view;
float2 clip_depth;
clip_depth[0] = context->camera->get_clip_near_tween().interpolate(context->alpha);
clip_depth[1] = context->camera->get_clip_far_tween().interpolate(context->alpha);
clip_depth[0] = ctx.camera->get_clip_near_tween().interpolate(ctx.alpha);
clip_depth[1] = ctx.camera->get_clip_far_tween().interpolate(ctx.alpha);
float log_depth_coef = 2.0f / std::log2(clip_depth[1] + 1.0f);
float camera_exposure = std::exp2(context->camera->get_exposure_tween().interpolate(context->alpha));
float camera_exposure = std::exp2(ctx.camera->get_exposure_tween().interpolate(ctx.alpha));
int active_material_flags = 0;
@ -149,7 +147,7 @@ void material_pass::render(render_context* context) const
spot_light_count = 0;
// Collect lights
const std::list<scene::object_base*>* lights = context->collection->get_objects(scene::light::object_type_id);
const std::list<scene::object_base*>* lights = ctx.collection->get_objects(scene::light::object_type_id);
for (const scene::object_base* object: *lights)
{
// Skip inactive lights
@ -165,7 +163,7 @@ void material_pass::render(render_context* context) const
if (ambient_light_count < max_ambient_light_count)
{
// Pre-expose light
ambient_light_colors[ambient_light_count] = light->get_scaled_color_tween().interpolate(context->alpha) * camera_exposure;
ambient_light_colors[ambient_light_count] = light->get_scaled_color_tween().interpolate(ctx.alpha) * camera_exposure;
++ambient_light_count;
}
break;
@ -177,12 +175,12 @@ void material_pass::render(render_context* context) const
if (point_light_count < max_point_light_count)
{
// Pre-expose light
point_light_colors[point_light_count] = light->get_scaled_color_tween().interpolate(context->alpha) * camera_exposure;
point_light_colors[point_light_count] = light->get_scaled_color_tween().interpolate(ctx.alpha) * camera_exposure;
float3 position = light->get_transform_tween().interpolate(context->alpha).translation;
float3 position = light->get_transform_tween().interpolate(ctx.alpha).translation;
point_light_positions[point_light_count] = position;
point_light_attenuations[point_light_count] = static_cast<const scene::point_light*>(light)->get_attenuation_tween().interpolate(context->alpha);
point_light_attenuations[point_light_count] = static_cast<const scene::point_light*>(light)->get_attenuation_tween().interpolate(ctx.alpha);
++point_light_count;
}
break;
@ -196,23 +194,23 @@ void material_pass::render(render_context* context) const
const scene::directional_light* directional_light = static_cast<const scene::directional_light*>(light);
// Pre-expose light
directional_light_colors[directional_light_count] = light->get_scaled_color_tween().interpolate(context->alpha) * camera_exposure;
directional_light_colors[directional_light_count] = light->get_scaled_color_tween().interpolate(ctx.alpha) * camera_exposure;
float3 direction = static_cast<const scene::directional_light*>(light)->get_direction_tween().interpolate(context->alpha);
float3 direction = static_cast<const scene::directional_light*>(light)->get_direction_tween().interpolate(ctx.alpha);
directional_light_directions[directional_light_count] = direction;
if (directional_light->get_light_texture())
{
directional_light_textures[directional_light_count] = directional_light->get_light_texture();
directional_light_texture_opacities[directional_light_count] = directional_light->get_light_texture_opacity_tween().interpolate(context->alpha);
directional_light_texture_opacities[directional_light_count] = directional_light->get_light_texture_opacity_tween().interpolate(ctx.alpha);
math::transform<float> light_transform = light->get_transform_tween().interpolate(context->alpha);
math::transform<float> light_transform = light->get_transform_tween().interpolate(ctx.alpha);
float3 forward = light_transform.rotation * global_forward;
float3 up = light_transform.rotation * global_up;
float4x4 light_view = math::look_at(light_transform.translation, light_transform.translation + forward, up);
float2 scale = directional_light->get_light_texture_scale_tween().interpolate(context->alpha);
float2 scale = directional_light->get_light_texture_scale_tween().interpolate(ctx.alpha);
float4x4 light_projection = math::ortho(-scale.x, scale.x, -scale.y, scale.y, -1.0f, 1.0f);
directional_light_texture_matrices[directional_light_count] = light_projection * light_view;
@ -236,16 +234,16 @@ void material_pass::render(render_context* context) const
const scene::spot_light* spot_light = static_cast<const scene::spot_light*>(light);
// Pre-expose light
spot_light_colors[spot_light_count] = light->get_scaled_color_tween().interpolate(context->alpha) * camera_exposure;
spot_light_colors[spot_light_count] = light->get_scaled_color_tween().interpolate(ctx.alpha) * camera_exposure;
float3 position = light->get_transform_tween().interpolate(context->alpha).translation;
float3 position = light->get_transform_tween().interpolate(ctx.alpha).translation;
spot_light_positions[spot_light_count] = position;
float3 direction = spot_light->get_direction_tween().interpolate(context->alpha);
float3 direction = spot_light->get_direction_tween().interpolate(ctx.alpha);
spot_light_directions[spot_light_count] = direction;
spot_light_attenuations[spot_light_count] = spot_light->get_attenuation_tween().interpolate(context->alpha);
spot_light_cutoffs[spot_light_count] = spot_light->get_cosine_cutoff_tween().interpolate(context->alpha);
spot_light_attenuations[spot_light_count] = spot_light->get_attenuation_tween().interpolate(ctx.alpha);
spot_light_cutoffs[spot_light_count] = spot_light->get_cosine_cutoff_tween().interpolate(ctx.alpha);
++spot_light_count;
}
@ -270,10 +268,10 @@ void material_pass::render(render_context* context) const
shadow_splits_directional[i] = shadow_map_pass->get_split_distances()[i + 1];
}
// Sort render operations
context->operations.sort(operation_compare);
// Sort render queue
queue.sort(operation_compare);
for (const render_operation& operation: context->operations)
for (const render::operation& operation: queue)
{
// Get operation material
const ::material* material = operation.material;
@ -439,7 +437,7 @@ void material_pass::render(render_context* context) const
// Upload context-dependent shader parameters
if (parameters->time)
parameters->time->upload(time);
parameters->time->upload(ctx.t);
if (parameters->mouse)
parameters->mouse->upload(mouse_position);
if (parameters->resolution)
@ -500,7 +498,7 @@ void material_pass::render(render_context* context) const
}
// Upload material properties to shader
active_material->upload(context->alpha);
active_material->upload(ctx.alpha);
}
// Calculate operation-dependent parameters
@ -539,11 +537,6 @@ void material_pass::set_fallback_material(const material* fallback)
this->fallback_material = fallback;
}
void material_pass::set_time_tween(const tween<double>* time)
{
this->time_tween = time;
}
const material_pass::parameter_set* material_pass::load_parameter_set(const gl::shader_program* program) const
{
// Allocate a new parameter set
@ -598,7 +591,7 @@ void material_pass::handle_event(const mouse_moved_event& event)
mouse_position = {static_cast<float>(event.x), static_cast<float>(event.y)};
}
bool operation_compare(const render_operation& a, const render_operation& b)
bool operation_compare(const render::operation& a, const render::operation& b)
{
if (!a.material)
return false;

+ 1
- 5
src/renderer/passes/material-pass.hpp View File

@ -44,14 +44,11 @@ class material_pass: public render_pass,
public:
material_pass(gl::rasterizer* rasterizer, const gl::framebuffer* framebuffer, resource_manager* resource_manager);
virtual ~material_pass();
virtual void render(render_context* context) const final;
virtual void render(const render::context& ctx, render::queue& queue) const final;
/// Sets the material to be used when a render operation is missing a material. If no fallback material is specified, render operations without materials will not be processed.
void set_fallback_material(const material* fallback);
/// Sets the time tween, which is interpolated between updates
void set_time_tween(const tween<double>* time);
const ::shadow_map_pass* shadow_map_pass;
const gl::texture_2d* shadow_map;
@ -107,7 +104,6 @@ private:
mutable std::unordered_map<const gl::shader_program*, parameter_set*> parameter_sets;
const material* fallback_material;
const tween<double>* time_tween;
float2 mouse_position;
int max_ambient_light_count;

+ 6
- 6
src/renderer/passes/outline-pass.cpp View File

@ -28,7 +28,7 @@
#include "gl/vertex-attribute.hpp"
#include "gl/drawing-mode.hpp"
#include "renderer/vertex-attribute.hpp"
#include "renderer/render-context.hpp"
#include "renderer/context.hpp"
#include "renderer/material.hpp"
#include "renderer/material-flags.hpp"
#include "scene/camera.hpp"
@ -55,7 +55,7 @@ outline_pass::outline_pass(gl::rasterizer* rasterizer, const gl::framebuffer* fr
outline_pass::~outline_pass()
{}
void outline_pass::render(render_context* context) const
void outline_pass::render(const render::context& ctx, render::queue& queue) const
{
rasterizer->use_framebuffer(*framebuffer);
@ -64,8 +64,8 @@ void outline_pass::render(render_context* context) const
rasterizer->set_viewport(0, 0, std::get<0>(viewport), std::get<1>(viewport));
// Get camera matrices
float4x4 view = context->camera->get_view_tween().interpolate(context->alpha);
float4x4 view_projection = context->camera->get_view_projection_tween().interpolate(context->alpha);
float4x4 view = ctx.camera->get_view_tween().interpolate(ctx.alpha);
float4x4 view_projection = ctx.camera->get_view_projection_tween().interpolate(ctx.alpha);
float4x4 model_view_projection;
@ -86,7 +86,7 @@ void outline_pass::render(render_context* context) const
rasterizer->use_program(*fill_shader);
// Render fills
for (const render_operation& operation: context->operations)
for (const render::operation& operation: queue)
{
const ::material* material = operation.material;
if (!material || !(material->get_flags() & MATERIAL_FLAG_OUTLINE))
@ -122,7 +122,7 @@ void outline_pass::render(render_context* context) const
stroke_color_input->upload(outline_color);
// Render strokes
for (const render_operation& operation: context->operations)
for (const render::operation& operation: queue)
{
const ::material* material = operation.material;
if (!material || !(material->get_flags() & MATERIAL_FLAG_OUTLINE))

+ 1
- 1
src/renderer/passes/outline-pass.hpp View File

@ -35,7 +35,7 @@ class outline_pass: public render_pass
public:
outline_pass(gl::rasterizer* rasterizer, const gl::framebuffer* framebuffer, resource_manager* resource_manager);
virtual ~outline_pass();
virtual void render(render_context* context) const final;
virtual void render(const render::context& ctx, render::queue& queue) const final;
void set_outline_width(float width);
void set_outline_color(const float4& color);

+ 12
- 12
src/renderer/passes/shadow-map-pass.cpp View File

@ -24,7 +24,7 @@
#include "gl/shader-program.hpp"
#include "gl/shader-input.hpp"
#include "gl/drawing-mode.hpp"
#include "renderer/render-context.hpp"
#include "renderer/context.hpp"
#include "renderer/material.hpp"
#include "renderer/material-flags.hpp"
#include "scene/camera.hpp"
@ -36,7 +36,7 @@
#include <cmath>
#include <glad/glad.h>
static bool operation_compare(const render_operation& a, const render_operation& b);
static bool operation_compare(const render::operation& a, const render::operation& b);
void shadow_map_pass::distribute_frustum_splits(float* split_distances, std::size_t split_count, float split_scheme, float near, float far)
{
@ -84,7 +84,7 @@ shadow_map_pass::shadow_map_pass(gl::rasterizer* rasterizer, const gl::framebuff
shadow_map_pass::~shadow_map_pass()
{}
void shadow_map_pass::render(render_context* context) const
void shadow_map_pass::render(const render::context& ctx, render::queue& queue) const
{
// Abort if no directional light was set
if (!light)
@ -110,11 +110,11 @@ void shadow_map_pass::render(render_context* context) const
//glDepthRange(-1.0f, 1.0f);
// Get camera
const scene::camera& camera = *context->camera;
const scene::camera& camera = *ctx.camera;
// Calculate distances to the depth clipping planes of each frustum split
float clip_near = camera.get_clip_near_tween().interpolate(context->alpha);
float clip_far = camera.get_clip_far_tween().interpolate(context->alpha);
float clip_near = camera.get_clip_near_tween().interpolate(ctx.alpha);
float clip_far = camera.get_clip_far_tween().interpolate(ctx.alpha);
split_distances[0] = clip_near;
split_distances[4] = clip_far;
distribute_frustum_splits(&split_distances[1], 3, split_scheme_weight, clip_near, clip_far);
@ -135,7 +135,7 @@ void shadow_map_pass::render(render_context* context) const
}
// Calculate a view-projection matrix from the directional light's transform
math::transform<float> light_transform = light->get_transform_tween().interpolate(context->alpha);
math::transform<float> light_transform = light->get_transform_tween().interpolate(ctx.alpha);
float3 forward = light_transform.rotation * global_forward;
float3 up = light_transform.rotation * global_up;
float4x4 light_view = math::look_at(light_transform.translation, light_transform.translation + forward, up);
@ -143,14 +143,14 @@ void shadow_map_pass::render(render_context* context) const
float4x4 light_view_projection = light_projection * light_view;
// Get the camera's view matrix
float4x4 camera_view = camera.get_view_tween().interpolate(context->alpha);
float4x4 camera_view = camera.get_view_tween().interpolate(ctx.alpha);
float4x4 crop_matrix;
float4x4 cropped_view_projection;
float4x4 model_view_projection;
// Sort render operations
context->operations.sort(operation_compare);
// Sort render queue
queue.sort(operation_compare);
gl::shader_program* active_shader_program = nullptr;
@ -214,7 +214,7 @@ void shadow_map_pass::render(render_context* context) const
// Calculate shadow matrix
shadow_matrices[i] = bias_tile_matrices[i] * cropped_view_projection;
for (const render_operation& operation: context->operations)
for (const render::operation& operation: queue)
{
// Skip materials which don't cast shadows
const ::material* material = operation.material;
@ -260,7 +260,7 @@ void shadow_map_pass::set_light(const scene::directional_light* light)
this->light = light;
}
bool operation_compare(const render_operation& a, const render_operation& b)
bool operation_compare(const render::operation& a, const render::operation& b)
{
// Determine transparency
bool skinned_a = (a.pose != nullptr);

+ 1
- 1
src/renderer/passes/shadow-map-pass.hpp View File

@ -36,7 +36,7 @@ class shadow_map_pass: public render_pass
public:
shadow_map_pass(gl::rasterizer* rasterizer, const gl::framebuffer* framebuffer, resource_manager* resource_manager);
virtual ~shadow_map_pass();
virtual void render(render_context* context) const final;
virtual void render(const render::context& ctx, render::queue& queue) const final;
/**
* Sets the linear interpolation weight between uniform and logarithmic frustum-splitting schemes.

+ 20
- 27
src/renderer/passes/sky-pass.cpp View File

@ -32,7 +32,7 @@
#include "gl/texture-wrapping.hpp"
#include "gl/texture-filter.hpp"
#include "renderer/vertex-attribute.hpp"
#include "renderer/render-context.hpp"
#include "renderer/context.hpp"
#include "renderer/model.hpp"
#include "renderer/material.hpp"
#include "scene/camera.hpp"
@ -68,7 +68,6 @@ sky_pass::sky_pass(gl::rasterizer* rasterizer, const gl::framebuffer* framebuffe
clouds_model_vao(nullptr),
cloud_material(nullptr),
cloud_shader_program(nullptr),
time_tween(nullptr),
observer_altitude_tween(0.0f, math::lerp<float, float>),
sun_position_tween(float3{1.0f, 0.0f, 0.0f}, math::lerp<float3, float>),
sun_color_outer_tween(float3{1.0f, 1.0f, 1.0f}, math::lerp<float3, float>),
@ -80,7 +79,7 @@ sky_pass::sky_pass(gl::rasterizer* rasterizer, const gl::framebuffer* framebuffe
sky_pass::~sky_pass()
{}
void sky_pass::render(render_context* context) const
void sky_pass::render(const render::context& ctx, render::queue& queue) const
{
rasterizer->use_framebuffer(*framebuffer);
@ -93,38 +92,37 @@ void sky_pass::render(render_context* context) const
auto viewport = framebuffer->get_dimensions();
rasterizer->set_viewport(0, 0, std::get<0>(viewport), std::get<1>(viewport));
float time = static_cast<float>((*time_tween)[context->alpha]);
float2 resolution = {static_cast<float>(std::get<0>(viewport)), static_cast<float>(std::get<1>(viewport))};
const scene::camera& camera = *context->camera;
float clip_near = camera.get_clip_near_tween().interpolate(context->alpha);
float clip_far = camera.get_clip_far_tween().interpolate(context->alpha);
const scene::camera& camera = *ctx.camera;
float clip_near = camera.get_clip_near_tween().interpolate(ctx.alpha);
float clip_far = camera.get_clip_far_tween().interpolate(ctx.alpha);
float3 model_scale = float3{1.0f, 1.0f, 1.0f} * (clip_near + clip_far) * 0.5f;
float4x4 model = math::scale(math::identity4x4<float>, model_scale);
float4x4 view = math::resize<4, 4>(math::resize<3, 3>(camera.get_view_tween().interpolate(context->alpha)));
float4x4 view = math::resize<4, 4>(math::resize<3, 3>(camera.get_view_tween().interpolate(ctx.alpha)));
float4x4 model_view = view * model;
float4x4 projection = camera.get_projection_tween().interpolate(context->alpha);
float4x4 projection = camera.get_projection_tween().interpolate(ctx.alpha);
float4x4 view_projection = projection * view;
float4x4 model_view_projection = projection * model_view;
float exposure = std::exp2(camera.get_exposure_tween().interpolate(context->alpha));
float exposure = std::exp2(camera.get_exposure_tween().interpolate(ctx.alpha));
// Interpolate observer altitude
float observer_altitude = observer_altitude_tween.interpolate(context->alpha);
float observer_altitude = observer_altitude_tween.interpolate(ctx.alpha);
// Construct tweened inertial to topocentric frame
physics::frame<float> topocentric_frame =
{
topocentric_frame_translation.interpolate(context->alpha),
topocentric_frame_rotation.interpolate(context->alpha)
topocentric_frame_translation.interpolate(ctx.alpha),
topocentric_frame_rotation.interpolate(ctx.alpha)
};
// Get topocentric space direction to sun
float3 sun_position = sun_position_tween.interpolate(context->alpha);
float3 sun_position = sun_position_tween.interpolate(ctx.alpha);
float3 sun_direction = math::normalize(sun_position);
// Interpolate sun color
float3 sun_color_outer = sun_color_outer_tween.interpolate(context->alpha);
float3 sun_color_inner = sun_color_inner_tween.interpolate(context->alpha);
float3 sun_color_outer = sun_color_outer_tween.interpolate(ctx.alpha);
float3 sun_color_inner = sun_color_inner_tween.interpolate(ctx.alpha);
// Draw atmosphere
if (sky_model)
@ -139,7 +137,7 @@ void sky_pass::render(render_context* context) const
if (resolution_input)
resolution_input->upload(resolution);
if (time_input)
time_input->upload(time);
time_input->upload(ctx.t);
if (exposure_input)
exposure_input->upload(exposure);
@ -162,7 +160,7 @@ void sky_pass::render(render_context* context) const
if (atmosphere_radii_input)
atmosphere_radii_input->upload(atmosphere_radii);
sky_material->upload(context->alpha);
sky_material->upload(ctx.alpha);
rasterizer->draw_arrays(*sky_model_vao, sky_model_drawing_mode, sky_model_start_index, sky_model_index_count);
}
@ -179,11 +177,11 @@ void sky_pass::render(render_context* context) const
if (cloud_sun_color_input)
cloud_sun_color_input->upload(sun_color_inner);
if (cloud_camera_position_input)
cloud_camera_position_input->upload(context->camera_transform.translation);
cloud_camera_position_input->upload(ctx.camera_transform.translation);
if (cloud_camera_exposure_input)
cloud_camera_exposure_input->upload(exposure);
cloud_material->upload(context->alpha);
cloud_material->upload(ctx.alpha);
rasterizer->draw_arrays(*clouds_model_vao, clouds_model_drawing_mode, clouds_model_start_index, clouds_model_index_count);
}
@ -212,7 +210,7 @@ void sky_pass::render(render_context* context) const
if (star_exposure_input)
star_exposure_input->upload(exposure);
star_material->upload(context->alpha);
star_material->upload(ctx.alpha);
rasterizer->draw_arrays(*stars_model_vao, stars_model_drawing_mode, stars_model_start_index, stars_model_index_count);
}
@ -246,7 +244,7 @@ void sky_pass::render(render_context* context) const
moon_moon_position_input->upload(moon_position);
if (moon_sun_position_input)
moon_sun_position_input->upload(sun_position);
moon_material->upload(context->alpha);
moon_material->upload(ctx.alpha);
rasterizer->draw_arrays(*moon_model_vao, moon_model_drawing_mode, moon_model_start_index, moon_model_index_count);
}
*/
@ -420,11 +418,6 @@ void sky_pass::update_tweens()
topocentric_frame_rotation.update();
}
void sky_pass::set_time_tween(const tween<double>* time)
{
this->time_tween = time;
}
void sky_pass::set_topocentric_frame(const physics::frame<float>& frame)
{
topocentric_frame_translation[1] = frame.translation;

+ 1
- 3
src/renderer/passes/sky-pass.hpp View File

@ -48,12 +48,11 @@ class sky_pass: public render_pass,
public:
sky_pass(gl::rasterizer* rasterizer, const gl::framebuffer* framebuffer, resource_manager* resource_manager);
virtual ~sky_pass();
virtual void render(render_context* context) const final;
virtual void render(const render::context& ctx, render::queue& queue) const final;
void update_tweens();
void set_sky_model(const model* model);
void set_time_tween(const tween<double>* time);
void set_moon_model(const model* model);
void set_stars_model(const model* model);
void set_clouds_model(const model* model);
@ -139,7 +138,6 @@ private:
const gl::texture_2d* sky_gradient2;
float2 mouse_position;
const tween<double>* time_tween;
tween<float> observer_altitude_tween;
tween<float3> sun_position_tween;
tween<float3> sun_color_outer_tween;

+ 6
- 12
src/renderer/passes/ui-pass.cpp View File

@ -32,7 +32,7 @@
#include "gl/texture-filter.hpp"
#include "renderer/vertex-attribute.hpp"
#include "renderer/material-flags.hpp"
#include "renderer/render-context.hpp"
#include "renderer/context.hpp"
#include "scene/camera.hpp"
#include "scene/collection.hpp"
#include "scene/ambient-light.hpp"
@ -43,14 +43,13 @@
#include <glad/glad.h>
ui_pass::ui_pass(gl::rasterizer* rasterizer, const gl::framebuffer* framebuffer, resource_manager* resource_manager):
render_pass(rasterizer, framebuffer),
time(0.0f)
render_pass(rasterizer, framebuffer)
{}
ui_pass::~ui_pass()
{}
void ui_pass::render(render_context* context) const
void ui_pass::render(const render::context& ctx, render::queue& queue) const
{
glEnable(GL_BLEND);
glDisable(GL_DEPTH_TEST);
@ -60,24 +59,19 @@ void ui_pass::render(render_context* context) const
auto viewport = framebuffer->get_dimensions();
rasterizer->set_viewport(0, 0, std::get<0>(viewport), std::get<1>(viewport));
float4x4 view = context->camera->get_view_tween().interpolate(context->alpha);
float4x4 projection = context->camera->get_projection_tween().interpolate(context->alpha);
float4x4 view = ctx.camera->get_view_tween().interpolate(ctx.alpha);
float4x4 projection = ctx.camera->get_projection_tween().interpolate(ctx.alpha);
float4x4 view_projection = projection * view;
float4x4 model_view_projection;
// Collect billboards
std::list<scene::object_base*> billboards = *context->collection->get_objects(scene::billboard::object_type_id);
std::list<scene::object_base*> billboards = *ctx.collection->get_objects(scene::billboard::object_type_id);
// Sort billboards
// Rebuild vertex buffer
}
void ui_pass::set_time(float time)
{
this->time = time;
}
const ui_pass::parameter_set* ui_pass::load_parameter_set(const gl::shader_program* program) const
{
// Allocate a new parameter set

+ 1
- 4
src/renderer/passes/ui-pass.hpp View File

@ -37,9 +37,7 @@ class ui_pass: public render_pass
public:
ui_pass(gl::rasterizer* rasterizer, const gl::framebuffer* framebuffer, resource_manager* resource_manager);
virtual ~ui_pass();
virtual void render(render_context* context) const final;
void set_time(float time);
virtual void render(const render::context& ctx, render::queue& queue) const final;
private:
/**
@ -54,7 +52,6 @@ private:
const parameter_set* load_parameter_set(const gl::shader_program* program) const;
mutable std::unordered_map<const gl::shader_program*, parameter_set*> parameter_sets;
float time;
};
#endif // ANTKEEPER_UI_PASS_HPP

+ 33
- 0
src/renderer/queue.hpp View File

@ -0,0 +1,33 @@
/*
* Copyright (C) 2021 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_QUEUE_HPP
#define ANTKEEPER_RENDER_QUEUE_HPP
#include "renderer/operation.hpp"
#include <list>
namespace render {
/// Queue of render operations
typedef std::list<render::operation> queue;
} // namespace render
#endif // ANTKEEPER_RENDER_QUEUE_HPP

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

@ -22,8 +22,8 @@
#include "gl/rasterizer.hpp"
#include "gl/framebuffer.hpp"
struct render_context;
#include "renderer/context.hpp"
#include "renderer/queue.hpp"
/**
*
@ -34,7 +34,7 @@ public:
render_pass(gl::rasterizer* rasterizer, const gl::framebuffer* framebuffer);
virtual ~render_pass();
virtual void render(render_context* context) const = 0;
virtual void render(const render::context& ctx, render::queue& queue) const = 0;
void set_enabled(bool enabled);
bool is_enabled() const;

+ 48
- 52
src/renderer/renderer.cpp View File

@ -18,7 +18,7 @@
*/
#include "renderer/renderer.hpp"
#include "renderer/render-context.hpp"
#include "renderer/context.hpp"
#include "renderer/compositor.hpp"
#include "scene/collection.hpp"
#include "scene/camera.hpp"
@ -45,7 +45,7 @@ renderer::renderer()
billboard_op.instance_count = 0;
}
void renderer::render(float alpha, const scene::collection& collection) const
void renderer::render(float t, float dt, float alpha, const scene::collection& collection) const
{
// Get list of all objects in the collection
const std::list<scene::object_base*>* objects = collection.get_objects();
@ -66,6 +66,13 @@ void renderer::render(float alpha, const scene::collection& collection) const
return a->get_composite_index() < b->get_composite_index();
}
);
// Init render context
render::context ctx;
ctx.collection = &collection;
ctx.t = t;
ctx.dt = dt;
ctx.alpha = alpha;
// Process cameras in order
for (const scene::camera* camera: sorted_cameras)
@ -83,22 +90,22 @@ void renderer::render(float alpha, const scene::collection& collection) const
continue;
}
// Setup render context
render_context context;
context.camera = camera;
context.camera_transform = camera->get_transform_tween().interpolate(alpha);
context.camera_forward = context.camera_transform.rotation * global_forward;
context.camera_up = context.camera_transform.rotation * global_up;
context.clip_near = camera->get_view_frustum().get_near(); ///< TODO: tween this
context.collection = &collection;
context.alpha = alpha;
// Update render context with camera parameters
ctx.camera = camera;
ctx.camera_transform = camera->get_transform_tween().interpolate(alpha);
ctx.camera_forward = ctx.camera_transform.rotation * global_forward;
ctx.camera_up = ctx.camera_transform.rotation * global_up;
ctx.clip_near = camera->get_view_frustum().get_near(); ///< TODO: tween this
// Create render queue
render::queue queue;
// Get camera culling volume
context.camera_culling_volume = camera->get_culling_mask();
if (!context.camera_culling_volume)
context.camera_culling_volume = &camera->get_bounds();
ctx.camera_culling_volume = camera->get_culling_mask();
if (!ctx.camera_culling_volume)
ctx.camera_culling_volume = &camera->get_bounds();
// Generate render operations for each visible scene object
// Queue render operations for each visible scene object
for (const scene::object_base* object: *objects)
{
// Skip inactive objects
@ -106,11 +113,11 @@ void renderer::render(float alpha, const scene::collection& collection) const
continue;
// Process object
process_object(context, object);
process_object(ctx, queue, object);
}
// Pass render context to the camera's compositor
compositor->composite(&context);
compositor->composite(ctx, queue);
}
}
@ -119,21 +126,21 @@ void renderer::set_billboard_vao(gl::vertex_array* vao)
billboard_op.vertex_array = vao;
}
void renderer::process_object(render_context& context, const scene::object_base* object) const
void renderer::process_object(const render::context& ctx, render::queue& queue, const scene::object_base* object) const
{
std::size_t type = object->get_object_type_id();
if (type == scene::model_instance::object_type_id)
process_model_instance(context, static_cast<const scene::model_instance*>(object));
process_model_instance(ctx, queue, static_cast<const scene::model_instance*>(object));
else if (type == scene::billboard::object_type_id)
process_billboard(context, static_cast<const scene::billboard*>(object));
process_billboard(ctx, queue, static_cast<const scene::billboard*>(object));
else if (type == scene::lod_group::object_type_id)
process_lod_group(context, static_cast<const scene::lod_group*>(object));
process_lod_group(ctx, queue, static_cast<const scene::lod_group*>(object));
else if (type == scene::text::object_type_id)
process_text(context, static_cast<const scene::text*>(object));
process_text(ctx, queue, static_cast<const scene::text*>(object));
}
void renderer::process_model_instance(render_context& context, const scene::model_instance* model_instance) const
void renderer::process_model_instance(const render::context& ctx, render::queue& queue, const scene::model_instance* model_instance) const
{
const model* model = model_instance->get_model();
if (!model)
@ -145,7 +152,7 @@ void renderer::process_model_instance(render_context& context, const scene::mode
object_culling_volume = &model_instance->get_bounds();
// Perform view-frustum culling
if (!context.camera_culling_volume->intersects(*object_culling_volume))
if (!ctx.camera_culling_volume->intersects(*object_culling_volume))
return;
const std::vector<material*>* instance_materials = model_instance->get_materials();
@ -153,7 +160,7 @@ void renderer::process_model_instance(render_context& context, const scene::mode
for (model_group* group: *groups)
{
render_operation operation;
render::operation operation;
// Determine operation material
operation.material = group->get_material();
@ -168,15 +175,15 @@ void renderer::process_model_instance(render_context& context, const scene::mode
operation.drawing_mode = group->get_drawing_mode();
operation.start_index = group->get_start_index();
operation.index_count = group->get_index_count();
operation.transform = math::matrix_cast(model_instance->get_transform_tween().interpolate(context.alpha));
operation.depth = context.clip_near.signed_distance(math::resize<3>(operation.transform[3]));
operation.transform = math::matrix_cast(model_instance->get_transform_tween().interpolate(ctx.alpha));
operation.depth = ctx.clip_near.signed_distance(math::resize<3>(operation.transform[3]));
operation.instance_count = model_instance->get_instance_count();
context.operations.push_back(operation);
queue.push_back(operation);
}
}
void renderer::process_billboard(render_context& context, 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();
@ -184,22 +191,22 @@ void renderer::process_billboard(render_context& context, const scene::billboard
object_culling_volume = &billboard->get_bounds();
// Perform view-frustum culling
if (!context.camera_culling_volume->intersects(*object_culling_volume))
if (!ctx.camera_culling_volume->intersects(*object_culling_volume))
return;
math::transform<float> billboard_transform = billboard->get_transform_tween().interpolate(context.alpha);
math::transform<float> billboard_transform = billboard->get_transform_tween().interpolate(ctx.alpha);
billboard_op.material = billboard->get_material();
billboard_op.depth = context.clip_near.signed_distance(math::resize<3>(billboard_transform.translation));
billboard_op.depth = ctx.clip_near.signed_distance(math::resize<3>(billboard_transform.translation));
// Align billboard
if (billboard->get_billboard_type() == scene::billboard_type::spherical)
{
billboard_transform.rotation = math::normalize(math::look_rotation(context.camera_forward, context.camera_up) * billboard_transform.rotation);
billboard_transform.rotation = math::normalize(math::look_rotation(ctx.camera_forward, ctx.camera_up) * billboard_transform.rotation);
}
else if (billboard->get_billboard_type() == scene::billboard_type::cylindrical)
{
const float3& alignment_axis = billboard->get_alignment_axis();
float3 look = math::normalize(geom::project_on_plane(billboard_transform.translation - context.camera_transform.translation, {0.0f, 0.0f, 0.0f}, alignment_axis));
float3 look = math::normalize(geom::project_on_plane(billboard_transform.translation - ctx.camera_transform.translation, {0.0f, 0.0f, 0.0f}, alignment_axis));
float3 right = math::normalize(math::cross(alignment_axis, look));
look = math::cross(right, alignment_axis);
float3 up = math::cross(look, right);
@ -208,23 +215,23 @@ void renderer::process_billboard(render_context& context, const scene::billboard
billboard_op.transform = math::matrix_cast(billboard_transform);
context.operations.push_back(billboard_op);
queue.push_back(billboard_op);
}
void renderer::process_lod_group(render_context& context, const scene::lod_group* lod_group) const
void renderer::process_lod_group(const render::context& ctx, render::queue& queue, const scene::lod_group* lod_group) const
{
// Select level of detail
std::size_t level = lod_group->select_lod(*context.camera);
std::size_t level = lod_group->select_lod(*ctx.camera);
// Process all objects in the group with the selected level of detail
const std::list<scene::object_base*>& objects = lod_group->get_objects(level);
for (const scene::object_base* object: objects)
{
process_object(context, object);
process_object(ctx, queue, object);
}
}
void renderer::process_text(render_context& context, 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();
@ -232,19 +239,8 @@ void renderer::process_text(render_context& context, const scene::text* text) co
object_culling_volume = &text->get_bounds();
// Perform view-frustum culling
if (!context.camera_culling_volume->intersects(*object_culling_volume))
if (!ctx.camera_culling_volume->intersects(*object_culling_volume))
return;
render_operation operation;
operation.material = text->get_material();
operation.pose = nullptr;
operation.vertex_array = text->get_vertex_array();
operation.drawing_mode = gl::drawing_mode::triangles;
operation.start_index = 0;
operation.index_count = text->get_vertex_count();
operation.transform = math::matrix_cast(text->get_transform_tween().interpolate(context.alpha));
operation.depth = context.clip_near.signed_distance(math::resize<3>(operation.transform[3]));
operation.instance_count = 0;
context.operations.push_back(operation);
text->render(ctx, queue);
}

+ 12
- 11
src/renderer/renderer.hpp View File

@ -20,11 +20,11 @@
#ifndef ANTKEEPER_RENDERER_HPP
#define ANTKEEPER_RENDERER_HPP
#include "render-operation.hpp"
#include "renderer/operation.hpp"
#include "renderer/context.hpp"
#include "renderer/queue.hpp"
#include "gl/vertex-array.hpp"
struct render_context;
namespace scene
{
class collection;
@ -57,10 +57,12 @@ public:
/**
* Renders a collection of scene objects.
*
* @param t Current time, in seconds.
* @param dt Timestep, in seconds.
* @param alpha Subframe interpolation factor.
* @parma collection Collection of scene objects to render.
*/
void render(float alpha, const scene::collection& collection) const;
void render(float t, float dt, float alpha, const scene::collection& collection) const;
/**
* Sets the VAO to be used when generating render operations for billboards.
@ -68,14 +70,13 @@ public:
void set_billboard_vao(gl::vertex_array* vao);
private:
void process_object(render_context& context, const scene::object_base* object) const;
void process_model_instance(render_context& context, const scene::model_instance* model_instance) const;
void process_billboard(render_context& context, const scene::billboard* billboard) const;
void process_lod_group(render_context& context, const scene::lod_group* lod_group) const;
void process_text(render_context& context, const scene::text* text) const;
void process_object(const render::context& ctx, render::queue& queue, const scene::object_base* object) const;
void process_model_instance(const render::context& ctx, render::queue& queue, const scene::model_instance* model_instance) const;
void process_billboard(const render::context& ctx, render::queue& queue, const scene::billboard* billboard) const;
void process_lod_group(const render::context& ctx, render::queue& queue, const scene::lod_group* lod_group) const;
void process_text(const render::context& ctx, render::queue& queue, const scene::text* text) const;
mutable render_operation billboard_op;
mutable render::operation billboard_op;
};
#endif // ANTKEEPER_RENDERER_HPP

+ 1
- 1
src/renderer/shader-template.hpp View File

@ -35,7 +35,7 @@
* * `#pragma vertex`: Replaced with `#define __VERTEX__` when generating vertex shader objects.
* * `#pragma fragment`: Replaced with `#define __FRAGMENT__` when generating fragment shader objects.
* * `#pragma geometry`: Replaced with `#define __GEOMETRY__` when generating geometry shader objects.
* * `#pragma define <key> <value>`: Will be replaced with `#define <key> <value>` if its definition is passed to the shader template.
* * `#pragma define <key>`: Will be replaced with `#define <key> <value>` if its definition is passed to the shader template.
*
* @see gl::shader_stage
* @see gl::shader_object

+ 5
- 14
src/renderer/simple-render-pass.cpp View File

@ -30,7 +30,7 @@
#include "gl/texture-wrapping.hpp"
#include "gl/texture-filter.hpp"
#include "renderer/vertex-attribute.hpp"
#include "renderer/render-context.hpp"
#include "renderer/context.hpp"
#include "renderer/material.hpp"
#include "renderer/material-property.hpp"
#include "math/math.hpp"
@ -38,8 +38,7 @@
simple_render_pass::simple_render_pass(gl::rasterizer* rasterizer, const gl::framebuffer* framebuffer, gl::shader_program* shader_program):
render_pass(rasterizer, framebuffer),
shader_program(shader_program),
time_tween(nullptr)
shader_program(shader_program)
{
// Create material
material = new ::material(shader_program);
@ -84,7 +83,7 @@ simple_render_pass::~simple_render_pass()
delete quad_vbo;
}
void simple_render_pass::render(render_context* context) const
void simple_render_pass::render(const render::context& ctx, render::queue& queue) const
{
// Bind framebuffer
rasterizer->use_framebuffer(*framebuffer);
@ -103,21 +102,13 @@ void simple_render_pass::render(render_context* context) const
// Change shader program
rasterizer->use_program(*shader_program);
// Get interpolated time
float time = (time_tween) ? time_tween->interpolate(context->alpha) : 0.0f;
// Update material properties
time_property->set_value(time);
time_property->set_value(ctx.t);
resolution_property->set_value({static_cast<float>(std::get<0>(viewport)), static_cast<float>(std::get<1>(viewport))});
// Upload material properties
material->upload(context->alpha);
material->upload(ctx.alpha);
// Draw quad
rasterizer->draw_arrays(*quad_vao, gl::drawing_mode::triangles, 0, 6);
}
void simple_render_pass::set_time_tween(const tween<double>* time)
{
this->time_tween = time;
}

+ 1
- 5
src/renderer/simple-render-pass.hpp View File

@ -40,9 +40,7 @@ class simple_render_pass: public render_pass
public:
simple_render_pass(gl::rasterizer* rasterizer, const gl::framebuffer* framebuffer, gl::shader_program* shader_program);
virtual ~simple_render_pass();
virtual void render(render_context* context) const final;
void set_time_tween(const tween<double>* time);
virtual void render(const render::context& ctx, render::queue& queue) const final;
const ::material* get_material() const;
::material* get_material();
@ -53,8 +51,6 @@ private:
material_property<float>* time_property;
material_property<float2>* resolution_property;
const tween<double>* time_tween;
gl::vertex_buffer* quad_vbo;
gl::vertex_array* quad_vao;
};

+ 3
- 0
src/scene/object.cpp View File

@ -49,6 +49,9 @@ std::size_t object_base::next_object_type_id()
return id++;
}
void object_base::render(const render::context& ctx, render::queue& queue) const
{}
void object_base::update_tweens()
{
transform.update();

+ 13
- 0
src/scene/object.hpp View File

@ -25,6 +25,8 @@
#include "math/vector-type.hpp"
#include "math/quaternion-type.hpp"
#include "math/transform-type.hpp"
#include "renderer/context.hpp"
#include "renderer/queue.hpp"
#include <atomic>
#include <cstddef>
@ -53,6 +55,17 @@ public:
* Destroys a scene object base.
*/
virtual ~object_base() = default;
/**
* Adds a render operation describing this object to a render queue.
*
* @param ctx Render context.
* @param queue Render queue.
*
* @see render::context
* @see render::operation
*/
virtual void render(const render::context& ctx, render::queue& queue) const;
/**
* Updates all tweens in the scene object.

+ 29
- 0
src/scene/text.cpp View File

@ -81,6 +81,15 @@ text::text():
vao->bind(render::vertex_attribute::position, position_attribute);
vao->bind(render::vertex_attribute::uv, uv_attribute);
vao->bind(render::vertex_attribute::color, color_attribute);
// Init render operation
render_op.material = nullptr;
render_op.pose = nullptr;
render_op.vertex_array = vao;
render_op.drawing_mode = gl::drawing_mode::triangles;
render_op.start_index = 0;
render_op.index_count = 0;
render_op.instance_count = 0;
}
text::~text()
@ -90,9 +99,25 @@ text::~text()
delete vbo;
}
void text::render(const render::context& ctx, render::queue& queue) const
{
if (!vertex_count)
return;
render_op.transform = math::matrix_cast(get_transform_tween().interpolate(ctx.alpha));
render_op.depth = ctx.clip_near.signed_distance(math::resize<3>(render_op.transform[3]));
queue.push_back(render_op);
}
void text::refresh()
{
update_content();
}
void text::set_material(::material* material)
{
this->material = material;
render_op.material = material;
}
void text::set_font(const type::bitmap_font* font)
@ -162,6 +187,9 @@ void text::update_content()
if (!font || content_u32.empty())
{
vertex_count = 0;
render_op.index_count = vertex_count;
local_bounds = {{0, 0, 0}, {0, 0, 0}};
transformed();
return;
}
@ -287,6 +315,7 @@ void text::update_content()
// Update vertex count
this->vertex_count = vertex_count;
render_op.index_count = vertex_count;
// Update world-space bounds
transformed();

+ 9
- 24
src/scene/text.hpp View File

@ -45,6 +45,14 @@ public:
/// Destructs a text object.
~text();
/// @copydoc scene::object_base::render(const render::context&, render::queue&) const
virtual void render(const render::context& ctx, render::queue& queue) const;
/**
* Manually updates the text object if its font has been updated or altered in any way.
*/
void refresh();
/**
* Sets the text material.
*
@ -97,15 +105,6 @@ public:
/// Returns the text color.
const float4& get_color() const;
/// Returns the text vertex array.
const gl::vertex_array* get_vertex_array() const;
/// Returns the text vertex buffer.
const gl::vertex_buffer* get_vertex_buffer() const;
/// Returns the number of vertices.
std::size_t get_vertex_count() const;
/// @copydoc scene::object::get_bounds() const
virtual const bounding_volume_type& get_bounds() const;
@ -118,6 +117,7 @@ private:
virtual void transformed();
mutable render::operation render_op;
aabb_type local_bounds;
aabb_type world_bounds;
material* material;
@ -158,21 +158,6 @@ inline const float4& text::get_color() const
return color;
}
inline const gl::vertex_array* text::get_vertex_array() const
{
return vao;
}
inline const gl::vertex_buffer* text::get_vertex_buffer() const
{
return vbo;
}
inline std::size_t text::get_vertex_count() const
{
return vertex_count;
}
inline const typename object_base::bounding_volume_type& text::get_bounds() const
{
return world_bounds;

Loading…
Cancel
Save