Files
cell/docs/rendering.md
2025-02-08 17:09:34 -06:00

8.3 KiB
Raw Blame History

Rendering, the camera & the world

  • Pipeline & Shader Setup:
    The engine defines a base rendering pipeline and derives specialized pipelines (e.g. for sprites) by modifying properties such as blend state, stencil settings, and target textures.
  • Command Buffers & Uploads:
    Data (vertex buffers, index buffers, UBOs, etc.) is uploaded via command buffers obtained from the GPU context.
  • Render Queues:
    There are separate queues for the main scene and for HUD elements.
  • Camera & Render Passes:
    A camera is created with its size set from configuration (width and height). Rendering is performed by executing a render pass for the scene, then a separate HUD pass.
  • Presentation:
    After rendering, the engine performs a blit from the cameras render target to the swapchain (the actual computer screen) and optionally renders an ImGui pass.

Coordinate System

  • World Space:
    • Y-Axis Direction: Y always goes up.
    • Camera Centering: In world space, when viewing through a camera, the camera's center (i.e. coordinate (0,0)) corresponds to the center of the computer screen.
      Example: If the camera is at (0,0), a sprite positioned at (0,0) will be drawn at the center of the screen.
  • HUD Space:
    • The HUD pass is rendered in a fixed coordinate space where (0,0) is at the bottom left of the computer screen. This coordinate system is independent of the world space camera.

Rendering Pipeline

  • Base Pipeline:
    A base pipeline is defined with the following key properties:

    • Shaders:
      • Vertex shader: "sprite.vert"
      • Fragment shader: "sprite.frag"
    • Primitive Type: "triangle"
    • Fill Mode: Filled (set by fill: true for solid rendering; can be switched to lines for wireframe)
    • Depth & Stencil:
      • Depth testing is configured but often disabled (test: false).
      • Stencil is enabled with a default compare mode of "equal".
    • Blending:
      The base pipeline has blending disabled, but specialized pipelines (e.g., the sprite pipeline) enable blending with parameters using source alpha and one-minus source alpha.
  • Sprite Pipeline:
    Derived from the base pipeline, the sprite pipeline:

    • Enables blending.
    • Sets the target render output with a color target (format "rgba8") and a depth target (format "d32 float s8").

Shader Creation and Reflection

  • Shader Loading:
    Shaders are loaded from disk based on a platform-dependent shader format (e.g. Vulkan, Metal). The function make_shader:

    • Constructs the file path from a base name and shader type.
    • Loads shader code and accompanying reflection metadata (from a JSON file).
    • Compiles the shader and caches the result.
  • Reflection Data:
    The reflection metadata is used to:

    • Determine the required number and type of uniform buffers.
    • Build vertex buffer descriptions and attribute bindings dynamically by inspecting the shaders input definitions.
    • Calculate the byte size for various float-based types (e.g. float, vec2, vec3, vec4, mat4).

Render Queues and Model Uploading

  • Render Queues:

    • Scene Render Queue (render_queue): Used for normal scene drawing.
    • HUD Render Queue (hud_queue): Used for drawing HUD elements.

    Commands are enqueued into these queues using helper functions. Later, during the render pass, these commands are processed in batches.

  • Buffer Uploads:
    The function full_upload(buffers):

    • Acquires a command buffer.
    • Uploads an array of data buffers (e.g. vertex, color, UV, and index buffers) to the GPU.
    • Submits the command buffer.
  • Model Binding:
    Functions such as bind_model and bind_mat:

    • Bind a models vertex and index buffers to the pipeline.
    • Bind material textures and their samplers to the fragment shader based on reflection data.
  • Grouping Sprites:
    The helper group_sprites_by_texture assigns each sprite a mesh and sets its index range (assuming 6 indices per sprite). This simplifies rendering multiple sprites with a single draw call.


Camera and Render Passes

  • Camera Setup:

    • A camera is created and its size is set from the configuration (typically matching the window dimensions).
    • In world space, the camera centers rendering so that objects at (0,0) appear at the center of the screen.
  • Render Pass (render_camera):
    The function render_camera performs the following:

    • Target Setup:
      If the camera does not already have a render target, one is created with a color texture (cleared to a cornflower blue) and a depth-stencil texture.
    • Buffer Collection:
      Gathers all buffers from both the scene and HUD render queues.
    • Uniform Data:
      Sets up camera and model uniform buffers using reflection data (e.g. for transformation matrices).
    • Drawing:
      Iterates over the render queue and draws each group using indexed drawing commands.
    • HUD Pass:
      After drawing the main scene, a separate HUD pass is executed. In the HUD pass, a helper (e.g. cmds.hud) is used so that coordinates are fixed with (0,0) at the bottom left.

Presentation and Swapchain

  • Blitting to Screen:
    After the render passes are complete, the function gpupresent:

    • Acquires a swapchain texture.
    • Uses a blit operation to copy the rendered image from the cameras render target to the swapchain, taking into account the cameras draw rectangle.
  • Optional ImGui Rendering:
    If ImGui is enabled, an additional render pass is executed to draw UI elements on top of the swapchain image.

  • Submission:
    Finally, the command buffer is submitted to the GPU, completing the frame.


Device Profiles

A set of predefined device profiles is provided (e.g., for PC, MacBook, Nintendo Switch, Game Boy, etc.) with resolution and diagonal size in inches. These profiles are useful for testing how content will appear on different screens.


Advanced Topics

  • Stencil Operations & Masks:

    • Functions such as stencil_writer, fillmask, and mask allow for advanced stencil buffer operations.
    • These are used to control where drawing occurs (for example, drawing a fullscreen shape to populate the stencil buffer or masking specific areas with an image).
  • Viewport and Scissor:

    • render.viewport and its alias render.scissor set the active drawing rectangle on the GPU.
  • Uniform Buffer Object (UBO) Management:

    • Functions such as ubo_obj_to_array convert objects into ArrayBuffers that match the UBO structure defined by the shaders reflection data.
    • The helper get_pipeline_ubo_slot retrieves the correct slot for UBO data based on name suffix matching.

Useful Functions Summary

  • full_upload(buffers):
    Uploads an array of buffers to the GPU.

  • bind_pipeline(pass, pipeline):
    Ensures a pipeline is created and binds it to a render pass.

  • make_pipeline(pipeline):
    Creates a GPU pipeline based on shader reflection data and input attribute descriptions.

  • make_shader(sh_file):
    Loads, compiles, and caches a shader, including its reflection metadata.

  • bind_model(pass, pipeline, model):
    Binds vertex and index buffers for a model.

  • bind_mat(pass, pipeline, mat):
    Binds textures and samplers to the fragment shader.

  • render_camera(cmds, camera):
    Executes a complete render pass for a given camera, drawing both scene and HUD elements.

  • gpupresent():
    Acquires the swapchain texture, performs blitting, and submits the final frame.


Key Points for Developers

  • Coordinate Systems:

    • In world space, the cameras center is (0,0); objects are drawn relative to this center.
    • In the HUD pass, (0,0) is fixed at the bottom left of the screen.
  • Y-Axis Orientation:
    Y always increases upward.

  • Pipeline Customization:
    The base pipeline can be adapted by modifying shader files, blend states, depth/stencil settings, and more.

  • Shader Reflection:
    Utilize reflection data to automatically set up vertex attributes and UBO bindings. This minimizes manual configuration when updating shaders.

  • Device Adaptation:
    Use the predefined device profiles to test and optimize your rendering for various screen resolutions and aspect ratios.