From 9d6a2d71e4c8c3bb5ef8d9088a5cec985f869b9b Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Fri, 4 Jul 2025 17:27:11 -0700 Subject: Refactor scene renderer to use the LLR --- include/gfx/llr/llr.h | 7 +- src/llr/llr.c | 42 +++++--- src/llr/llr_impl.h | 3 + src/renderer/renderer.c | 243 +++++++------------------------------------ src/renderer/renderer_impl.h | 4 - 5 files changed, 73 insertions(+), 226 deletions(-) diff --git a/include/gfx/llr/llr.h b/include/gfx/llr/llr.h index 57abffc..77df33f 100644 --- a/include/gfx/llr/llr.h +++ b/include/gfx/llr/llr.h @@ -30,8 +30,8 @@ void gfx_llr_pop_light(LLR*); /// animated, unload the skeleton prior to rendering them. void gfx_llr_set_skeleton(LLR*, const Anima*, const Skeleton*); -/// Unload the loaded skeleton. -void gfx_llr_unset_skeleton(LLR*); +/// Clear the loaded skeleton. +void gfx_llr_clear_skeleton(LLR*); /// Set the camera. void gfx_llr_set_camera(LLR*, const Camera*); @@ -39,6 +39,9 @@ void gfx_llr_set_camera(LLR*, const Camera*); /// Set the view-projection matrix. // void gfx_llr_set_view_projection_matrix(LLR*, const mat4*); +/// Set the aspect ratio. +void gfx_llr_set_aspect(LLR*, float aspect); + /// Render the geometry. void gfx_llr_render_geometry(LLR*, const Geometry*); diff --git a/src/llr/llr.c b/src/llr/llr.c index 746f4b3..74cfaed 100644 --- a/src/llr/llr.c +++ b/src/llr/llr.c @@ -171,6 +171,9 @@ static void configure_state(LLR* renderer) { gfx_set_mat4_uniform(shader, "ViewProjection", &view_proj); gfx_set_mat4_uniform(shader, "MVP", &mvp); gfx_set_vec3_uniform(shader, "CameraPosition", renderer->camera_position); + gfx_set_mat4_uniform(shader, "CameraRotation", &renderer->camera_rotation); + gfx_set_float_uniform(shader, "Fovy", renderer->fovy); + gfx_set_float_uniform(shader, "Aspect", renderer->aspect); } if (renderer->lights_changed || renderer->shader_changed) { @@ -188,9 +191,11 @@ static void configure_state(LLR* renderer) { if (renderer->skeleton_changed || renderer->shader_changed) { renderer->skeleton_changed = false; - gfx_set_mat4_array_uniform( - shader, "JointMatrices", renderer->joint_matrices, - renderer->num_joints); + if (renderer->num_joints > 0) { + gfx_set_mat4_array_uniform( + shader, "JointMatrices", renderer->joint_matrices, + renderer->num_joints); + } } if (renderer->shader_changed) { @@ -211,6 +216,9 @@ bool gfx_llr_make(LLR* renderer, GfxCore* gfxcore) { goto cleanup; } gfx_llr_load_identity(renderer); + renderer->view = mat4_id(); + renderer->projection = mat4_id(); + renderer->camera_rotation = mat4_id(); return true; cleanup: @@ -278,7 +286,7 @@ void gfx_llr_set_skeleton( renderer->skeleton_changed = true; } -void gfx_llr_unset_skeleton(LLR* renderer) { +void gfx_llr_clear_skeleton(LLR* renderer) { assert(renderer); renderer->num_joints = 0; @@ -288,22 +296,22 @@ void gfx_llr_unset_skeleton(LLR* renderer) { void gfx_llr_set_camera(LLR* renderer, const Camera* camera) { assert(renderer); - const mat4 view = spatial3_inverse_transform(&camera->spatial); - // const mat4 view_proj = mat4_mul(camera->projection, view); - // gfx_llr_set_view_projection_matrix(renderer, &view_proj); - renderer->view = view; - renderer->projection = camera->projection; + renderer->camera_position = camera->spatial.p; + renderer->camera_rotation = + mat4_rotation(spatial3_transform(&camera->spatial)); + renderer->view = spatial3_inverse_transform(&camera->spatial); + renderer->projection = camera->projection; + // Assuming a perspective matrix. + renderer->fovy = (R)atan(1.0 / (mat4_at(camera->projection, 1, 1))) * 2; renderer->camera_changed = true; } -// void gfx_llr_set_view_projection_matrix( -// LLR* renderer, const mat4* view_proj) { -// assert(renderer); -// assert(renderer->shader); -// -// gfx_llr_flush(renderer); -// gfx_set_mat4_uniform(renderer->shader, "ViewProjection", view_proj); -// } +void gfx_llr_set_aspect(LLR* renderer, float aspect) { + assert(renderer); + + renderer->aspect = aspect; + renderer->camera_changed = true; +} void gfx_llr_render_geometry(LLR* renderer, const Geometry* geometry) { assert(renderer); diff --git a/src/llr/llr_impl.h b/src/llr/llr_impl.h index e9dc0ac..ada2d79 100644 --- a/src/llr/llr_impl.h +++ b/src/llr/llr_impl.h @@ -54,8 +54,11 @@ typedef struct LLR { ShaderProgram* shader; // Active shader. Not owned. vec3 camera_position; + mat4 camera_rotation; mat4 view; // Camera view matrix. mat4 projection; // Camera projection matrix. + R fovy; // Camera vertical field of view. + R aspect; // Aspect ratio. // Lights are not const because environment lights store lazily-computed // irradiance maps. diff --git a/src/renderer/renderer.c b/src/renderer/renderer.c index 0c1fe78..29a1813 100644 --- a/src/renderer/renderer.c +++ b/src/renderer/renderer.c @@ -1,7 +1,6 @@ #include "renderer_impl.h" #include "llr/light_impl.h" -#include "llr/material_impl.h" #include "llr/mesh_impl.h" #include "scene/animation_impl.h" #include "scene/camera_impl.h" @@ -13,24 +12,12 @@ #include #include -#include #include -// #include -#include "gfx/gfx.h" - #include -#include #include -static const int IRRADIANCE_MAP_WIDTH = 1024; -static const int IRRADIANCE_MAP_HEIGHT = 1024; -static const int PREFILTERED_ENVIRONMENT_MAP_WIDTH = 128; -static const int PREFILTERED_ENVIRONMENT_MAP_HEIGHT = 128; -static const int BRDF_INTEGRATION_MAP_WIDTH = 512; -static const int BRDF_INTEGRATION_MAP_HEIGHT = 512; - bool gfx_renderer_make(Renderer* renderer, LLR* llr, GfxCore* gfxcore) { assert(renderer); assert(llr); @@ -48,9 +35,6 @@ void gfx_renderer_destroy(Renderer* renderer) { } assert(renderer->gfxcore); GfxCore* gfxcore = renderer->gfxcore; - if (renderer->ibl) { - gfx_destroy_ibl(gfxcore, &renderer->ibl); - } if (renderer->shaders.debug) { gfx_destroy_shader_program(gfxcore, &renderer->shaders.debug); } @@ -66,24 +50,6 @@ void gfx_renderer_destroy(Renderer* renderer) { } } -/// Initialize renderer state for IBL if not already initialized. -static bool init_ibl(Renderer* renderer) { - assert(renderer); - - if (!renderer->ibl && !(renderer->ibl = gfx_make_ibl(renderer->gfxcore))) { - return false; - } - - if (!renderer->brdf_integration_map && - !(renderer->brdf_integration_map = gfx_make_brdf_integration_map( - renderer->ibl, renderer->gfxcore, BRDF_INTEGRATION_MAP_WIDTH, - BRDF_INTEGRATION_MAP_HEIGHT))) { - return false; - } - - return true; -} - static ShaderProgram* load_shader(Renderer* renderer, RenderSceneMode mode) { assert(renderer); @@ -121,90 +87,17 @@ static ShaderProgram* load_shader(Renderer* renderer, RenderSceneMode mode) { // } // } -/// Compute irradiance and prefiltered environment maps for the light if they -/// have not been already computed. -static bool set_up_environment_light( - Renderer* renderer, GfxCore* gfxcore, EnvironmentLight* light) { - assert(renderer); - assert(light); - - if (!init_ibl(renderer)) { - return false; - } - - if (light->irradiance_map) { - assert(light->prefiltered_environment_map); - return true; - } - - Texture* irradiance_map = 0; - Texture* prefiltered_environment_map = 0; - - if (!(irradiance_map = gfx_make_irradiance_map( - renderer->ibl, gfxcore, light->environment_map, - IRRADIANCE_MAP_WIDTH, IRRADIANCE_MAP_HEIGHT))) { - goto cleanup; - } - - int max_mip_level = 0; - if (!(prefiltered_environment_map = gfx_make_prefiltered_environment_map( - renderer->ibl, gfxcore, light->environment_map, - PREFILTERED_ENVIRONMENT_MAP_WIDTH, - PREFILTERED_ENVIRONMENT_MAP_HEIGHT, &max_mip_level))) { - goto cleanup; - } - - light->irradiance_map = irradiance_map; - light->prefiltered_environment_map = prefiltered_environment_map; - light->max_reflection_lod = max_mip_level; - - return true; - -cleanup: - if (irradiance_map) { - gfx_destroy_texture(gfxcore, &irradiance_map); - } - if (prefiltered_environment_map) { - gfx_destroy_texture(gfxcore, &prefiltered_environment_map); - } - return false; -} - typedef struct RenderState { GfxCore* gfxcore; LLR* llr; Renderer* renderer; ShaderProgram* shader; // Null to use scene shaders. const Scene* scene; - const Camera* camera; - const mat4* camera_rotation; // From camera to world space, rotation only. - const mat4* view_matrix; - const mat4* projection; - const float fovy; - const float aspect; - Light* environment_light; const Anima* anima; - size_t num_joints; - mat4 joint_matrices[GFX_MAX_NUM_JOINTS]; } RenderState; -/// Load joint matrices into the render state. -static void load_skeleton(RenderState* state, skeleton_idx skeleton_index) { - assert(state); - assert(skeleton_index.val != 0); - - const Skeleton* skeleton = mem_get_skeleton(skeleton_index); - assert(skeleton); - assert(skeleton->num_joints <= GFX_MAX_NUM_JOINTS); - - state->num_joints = skeleton->num_joints; - - for (size_t i = 0; i < skeleton->num_joints; ++i) { - const joint_idx joint_index = skeleton->joints[i]; - const Joint* joint = &state->anima->joints[joint_index]; - state->joint_matrices[i] = joint->joint_matrix; - } -} +static void draw_children( + RenderState* state, const mat4* node_transform, const SceneNode* node); /// Draw the scene recursively. static void draw_recursively( @@ -216,25 +109,25 @@ static void draw_recursively( if (node->type == AnimaNode) { // Save the anima so that we can animate objects. state->anima = gfx_get_node_anima(node); + + draw_children(state, &node_transform, node); } // Activate light. else if (node->type == LightNode) { Light* light = mem_get_light(node->light); assert(light); - - if (light->type == EnvironmentLightType) { - bool result = set_up_environment_light( - state->renderer, state->gfxcore, &light->environment); - // TODO: Handle the result in a better way. - assert(result); - state->environment_light = light; + gfx_llr_push_light(state->llr, light); + { + draw_children(state, &node_transform, node); } + gfx_llr_pop_light(state->llr); } // Model. else if (node->type == ModelNode) { const Model* model = gfx_get_node_model(node); const SceneNode* root = mem_get_node(model->root); draw_recursively(state, parent_transform, root); + draw_children(state, &node_transform, node); } // Render object. else if (node->type == ObjectNode) { @@ -243,18 +136,15 @@ static void draw_recursively( // TODO: Here we would frustum-cull the object. - // TODO: Avoid computing matrices like Modelview or MVP if the shader does - // not use them. - const mat4 model_matrix = node_transform; - const mat4 modelview = mat4_mul(*state->view_matrix, model_matrix); - const mat4 mvp = mat4_mul(*state->projection, modelview); - // A model/anima can have many skeletons. We need to animate the given // object using its skeleton, not just any skeleton of the anima. if (object->skeleton.val) { - load_skeleton(state, object->skeleton); + const Skeleton* skeleton = mem_get_skeleton(object->skeleton); + gfx_llr_set_skeleton(state->llr, state->anima, skeleton); } + const mat4 model_matrix = node_transform; + for (mesh_link_idx mesh_link_index = object->mesh_link; mesh_link_index.val;) { const MeshLink* mesh_link = mem_get_mesh_link(mesh_link_index); @@ -264,68 +154,34 @@ static void draw_recursively( if (!mesh) { continue; } - assert(mesh->geometry); - assert(mesh->material); // TODO: Here we would frustum-cull the mesh. The AABB would have to be // transformed by the model matrix. Rotation would make the AABB // relatively large, but still, the culling would be conservative. - // TODO: Make sure we strictly set only the uniforms that are required by - // mesh rendering. See the other item below. - // Apply common shader uniforms not captured by materials. ShaderProgram* shader = state->shader ? state->shader : mesh->shader; - gfx_set_mat4_uniform(shader, "ModelMatrix", &model_matrix); - gfx_set_mat4_uniform(shader, "Modelview", &modelview); - gfx_set_mat4_uniform(shader, "View", state->view_matrix); - gfx_set_mat4_uniform(shader, "Projection", state->projection); - gfx_set_mat4_uniform(shader, "MVP", &mvp); - // TODO: CameraRotation is only used by the skyquad and cubemap_filtering - // shaders, not mesh rendering. - gfx_set_mat4_uniform(shader, "CameraRotation", state->camera_rotation); - // TODO: Fovy and Aspect are only used by the skyquad, not necessary here. - gfx_set_float_uniform(shader, "Fovy", state->fovy); - gfx_set_float_uniform(shader, "Aspect", state->aspect); - if (state->camera) { - gfx_set_vec3_uniform( - shader, "CameraPosition", state->camera->spatial.p); - } - if (state->num_joints > 0) { - gfx_set_mat4_array_uniform( - shader, "JointMatrices", state->joint_matrices, state->num_joints); - } - // Apply lights. - if (state->environment_light) { - const EnvironmentLight* light = &state->environment_light->environment; - assert(light->environment_map); - assert(light->irradiance_map); - assert(light->prefiltered_environment_map); - assert(state->renderer->brdf_integration_map); - gfx_set_texture_uniform( - shader, "BRDFIntegrationMap", - state->renderer->brdf_integration_map); - gfx_set_texture_uniform(shader, "Sky", light->environment_map); - gfx_set_texture_uniform(shader, "IrradianceMap", light->irradiance_map); - gfx_set_texture_uniform( - shader, "PrefilteredEnvironmentMap", - light->prefiltered_environment_map); - gfx_set_float_uniform( - shader, "MaxReflectionLOD", (float)light->max_reflection_lod); - } - gfx_material_activate(shader, mesh->material); - gfx_activate_shader_program(shader); - gfx_apply_uniforms(shader); - gfx_render_geometry(mesh->geometry); + gfx_llr_set_shader(state->llr, shader); + gfx_llr_set_model_matrix(state->llr, &model_matrix); + gfx_llr_render_mesh(state->llr, mesh); } - // Reset state for next object. - state->num_joints = 0; + if (object->skeleton.val) { + gfx_llr_clear_skeleton(state->llr); + } + + draw_children(state, &node_transform, node); + } else { + draw_children(state, &node_transform, node); } +} +/// Draw the node's children. +static void draw_children( + RenderState* state, const mat4* node_transform, const SceneNode* node) { // Render children recursively. for (node_idx child_index = node->child; child_index.val;) { const SceneNode* child = mem_get_node(child_index); - draw_recursively(state, node_transform, child); + draw_recursively(state, *node_transform, child); child_index = child->next; } } @@ -337,42 +193,23 @@ void gfx_render_scene(Renderer* renderer, const RenderSceneParams* params) { ShaderProgram* const shader = load_shader(renderer, params->mode); - const Scene* scene = params->scene; - const SceneCamera* camera = params->camera; - - GfxCore* const gfxcore = renderer->gfxcore; - - mat4 projection, camera_rotation, view_matrix; - if (camera) { - projection = camera->camera.projection; - camera_rotation = - mat4_rotation(spatial3_transform(&camera->camera.spatial)); - view_matrix = spatial3_inverse_transform(&camera->camera.spatial); - } else { - projection = mat4_id(); - camera_rotation = mat4_id(); - view_matrix = mat4_id(); - } + const Scene* scene = params->scene; + const SceneCamera* camera = params->camera; + GfxCore* const gfxcore = renderer->gfxcore; int x, y, width, height; gfx_get_viewport(gfxcore, &x, &y, &width, &height); - const float aspect = (float)width / (float)height; + const R aspect = (R)width / (R)height; RenderState state = { - .gfxcore = gfxcore, - .llr = renderer->llr, - .renderer = renderer, - .shader = shader, - .scene = scene, - .camera = &camera->camera, - .camera_rotation = &camera_rotation, - .view_matrix = &view_matrix, - .projection = &projection, - .environment_light = 0, - // Assuming a perspective matrix. - .fovy = atan(1.0 / (mat4_at(projection, 1, 1))) * 2, - .aspect = aspect}; - + .gfxcore = gfxcore, + .llr = renderer->llr, + .renderer = renderer, + .shader = shader, + .scene = scene}; + + gfx_llr_set_camera(renderer->llr, &camera->camera); + gfx_llr_set_aspect(renderer->llr, aspect); draw_recursively(&state, mat4_id(), scene->root); } diff --git a/src/renderer/renderer_impl.h b/src/renderer/renderer_impl.h index 6fd0c15..7395915 100644 --- a/src/renderer/renderer_impl.h +++ b/src/renderer/renderer_impl.h @@ -4,16 +4,12 @@ #include -typedef struct IBL IBL; typedef struct LLR LLR; typedef struct ShaderProgram ShaderProgram; -typedef struct Texture Texture; typedef struct Renderer { GfxCore* gfxcore; LLR* llr; - IBL* ibl; - Texture* brdf_integration_map; struct { ShaderProgram* debug; ShaderProgram* normals; -- cgit v1.2.3