#include "scene_render.h" #include "render/render_mesh.h" #include #include #include namespace scene_render_impl { glm::vec3 vec3_from_ptr(const float *ptr) { static_assert(sizeof(glm::vec3) == 3 * sizeof(float)); return *(glm::vec3 *) ptr; } } using namespace scene_render_impl; struct scene_render::impl { struct actor_store_type { std::shared_ptr model; actor_store_type *background = nullptr; float alpha_factor = 0.25f; bool visible = true; glm::mat4 transform = {}; using material_type = mesh_info_type::material_type; material_type material = {}; mesh_info_type get_mesh_info() const { return {.mesh = model.get(), .transform = transform, .material = material}; } }; bool enable_light_follow_camera = false; glm::vec3 light_direction = {1.0f, 0.0f, 0.0f}; float camera_fov = 60.0f; // in degree float camera_near = 0.1f, camera_far = 1000.0f; glm::mat4 camera_transform = {}; std::list actor_list; void *create_actor(const char *model_path, void *bg_actor) { auto &actor = actor_list.emplace_back(); actor.model = mesh_type::create({.path = model_path}); actor.background = (actor_store_type *) bg_actor; return &actor; } void draw() { auto info = mesh_render_info(); info.camera.transform = camera_transform; float aspect = query_viewport_size().aspectRatio(); info.camera.project = glm::perspective(camera_fov, aspect, camera_near, camera_far); if (enable_light_follow_camera) { auto camera_rot = glm::inverse(glm::mat3{camera_transform}); light_direction = -glm::column(camera_rot, 2); } info.light.direction = light_direction; for (const auto &actor: actor_list) { if (!actor.visible) continue; info.model = actor.get_mesh_info(); if (actor.background == nullptr) { // no background info.mode = MESH_NORMAL; render_mesh(info); } else { // with background info.mode = MESH_DEPTH_ALPHA; auto &ext = info.extra.depth_alpha; ext.bg = actor.background->get_mesh_info(); ext.alpha_factor = actor.alpha_factor; ext.show_bg = false; render_mesh(info); } } } }; scene_render::scene_render() : pimpl(std::make_unique()) {} scene_render::~scene_render() = default; void *scene_render::create_actor(const char *model_path, void *bg_actor) { return pimpl->create_actor(model_path, bg_actor); } void scene_render::set_actor_visibility(void *actor, bool visible) { auto real_ptr = (impl::actor_store_type *) actor; real_ptr->visible = visible; } void scene_render::set_actor_color(void *actor, const float *color, float ambient_factor) { auto real_ptr = (impl::actor_store_type *) actor; auto color_vec = vec3_from_ptr(color); real_ptr->material.diffuse = color_vec; real_ptr->material.ambient = ambient_factor * color_vec; } void scene_render::set_actor_alpha_factor(void *actor, float alpha_factor) { auto real_ptr = (impl::actor_store_type *) actor; real_ptr->alpha_factor = alpha_factor; } void scene_render::set_actor_transform(void *actor, glm::mat4 transform) { auto real_ptr = (impl::actor_store_type *) actor; real_ptr->transform = transform; } void scene_render::set_light_direction(glm::vec3 direction) { pimpl->light_direction = direction; } void scene_render::set_light_follow_camera(bool enable) { pimpl->enable_light_follow_camera = enable; } void scene_render::set_camera_fov(float fov) { pimpl->camera_fov = fov; } void scene_render::set_camera_clip_range(float near, float far) { pimpl->camera_near = near; pimpl->camera_far = far; } void scene_render::set_camera_transform(glm::mat4 transform) { static constexpr auto default_focal_length = 8.0f; // 8mm auto trans_part = glm::vec3(transform[3]); auto rot_part = glm::mat3(transform); auto focal_point = trans_part + rot_part[2] * default_focal_length; auto view_up = -rot_part[1]; auto view_mat = glm::lookAt(trans_part, focal_point, view_up); pimpl->camera_transform = view_mat; } void scene_render::render() { pimpl->draw(); }