Renderling

repository·main·Indexed 42 days ago

https://github.com/schell/renderling

A project featuring specialized utility crates for cross-platform data loading, timing, and UI rendering. Includes `loading-bytes` for unified native and WASM data loading, `img-diff` for image comparison testing, and `renderling-ui` for managing GPU-backed UI elements like UiRect, UiCircle, UiEllipse, and complex vector paths via UiPathBuilder.

Tokens
25.3K
Snippets
108
Records
128
Agent score
52%

What's inside Renderling

  1. Overview of renderling

    main

    What is renderling?

    renderling is a GPU-driven renderer written in Rust. It is designed for high-performance graphics rendering, specifically targeting indie game developers and researchers.

    Key Features:

    • GPU-Driven: Leverages GPU capabilities for most rendering operations to handle complex scenes efficiently.
    • GLTF Support: Optimized for working with GLTF files.
    • Modern Rendering Techniques: Supports Forward+ rendering and Physically Based Shading (PBR) for advanced lighting and material effects.
    • Scalability: Designed to handle large-scale scenes.
  2. Use loading-bytes to load data across native and WASM environments

    main
    The loading-bytes library provides a unified way to load raw bytes from the filesystem when running on native platforms, or via web requests when running in a WebAssembly (WASM) environment. This abstraction allows you to write code that handles data loading without needing to manually switch between filesystem APIs and fetch APIs based on the target runtime.
  3. What is Image Based Lighting (IBL)?

    main
    Image-based lighting (IBL) is a technique that uses environment maps to illuminate scenes. It captures real-world lighting conditions and applies them to 3D models, providing realistic reflections and ambient lighting. IBL is used to simulate complex lighting scenarios that are difficult to achieve with traditional analytical lights alone.
  4. How the Stage and Resource Builder pattern work

    main

    The Stage acts as a factory for scene resources. Most Stage::new_* functions return resources that follow the builder pattern. This allows you to chain configuration methods immediately after creation to customize the resource.

    Example: Stage::new_camera(...).with_default_perspective().

  5. Choose a lighting method in renderling

    main

    Renderling supports three distinct lighting models depending on your scene requirements:

    1. Unlit: No lighting is applied to the stage. This is useful for debugging or specific stylized effects.
    2. Analytical lights: Specific, mathematically defined light sources created by the programmer. Supported types include:
      • directional
      • point
      • spot
    3. Image based lighting (IBL): Lighting derived from 3D environment maps (e.g., HDR images) used in a skybox.
  6. Understand the role of `renderling::context::Context`

    main

    The Context is the entry point for any renderling program. It manages the underlying wgpu runtime, including the instance, adapter, and queue. It is also responsible for setting up the RenderTarget based on how the Context was initialized.

    There are two primary ways to create a Context:

    1. Headless Context: Renders to a texture. Use Context::headless or Context::try_new_headless (depending on your error handling preference).
    2. Surface Context: Renders to a window (e.g., via winit) or a web canvas (via web-sys).
  7. Acquire and present frames using `Context` and `Frame`

    main

    To render images, you must follow a lifecycle of acquiring and presenting frames:

    1. Acquire a frame from the Context using Context::get_next_frame.
    2. Present the frame using Frame::present.

    Platform-specific behavior for Frame::present:

    • Native: Presents the frame to the configured RenderTarget.
    • WASM (Browser): Frame::present is a no-op. However, it is recommended to keep the call in your code to maintain cross-platform compatibility.
  8. Load GLTF files into renderling

    main

    When you load a GLTF file into renderling, the engine automatically stages a collection of GPU resources including Camera, Vertices, Material, Primitive, and Transform.

    Depending on your target platform, use one of the following methods on the Stage object:

    • Desktop/Filesystem access: Use Stage::load_gltf_document_from_path to load from a file path.
    • WASM/No filesystem: Use Stage::load_gltf_document_from_bytes to load from a byte buffer.

    Both methods return a GltfDocument if successful. To optimize memory usage by unloading mesh geometry from the CPU after it has been uploaded to the GPU, call GltfDocument::into_gpu_only.

    // Loading from a path
    let gltf_document = stage.load_gltf_document_from_path("path/to/model.gltf")?;
    
    // Unloading geometry from CPU to save memory
    gltf_document.into_gpu_only();
  9. Patch crates.io for Rust-GPU support

    main

    Because renderling uses Rust-GPU for its shaders, you must patch the spirv-std crate in your Cargo.toml. This is a required workaround due to the current state of Rust-GPU releases. Add the following section to your Cargo.toml file:

    [patch.crates-io]
    spirv-std = { git = "https://github.com/rust-gpu/rust-gpu.git", rev = "05b34493ce661dccd6694cf58afc13e3c8f7a7e0" }
  10. Mix Image Based Lighting with analytical lights

    main

    You can combine global image-based lighting (Ibl) with analytical lights (such as point lights) to create a rich lighting environment. This allows you to capture both the subtle nuances of ambient light from the environment map and the dramatic effects of direct illumination from specific light sources.

    // Example pattern for mixing IBL and analytical lights:
    // 1. Setup Stage
    // 2. Add Ibl via stage.use_ibl(...)
    // 3. Add analytical lights (e.g., PointLight)
  11. Create a Stage using Context

    main

    The Stage is the central type in renderling, responsible for staging scene data on the GPU, linking effects, and performing the final render. You create a Stage using Context::new_stage.

    Note that Context creation is asynchronous, which is one of the two exceptions to the otherwise synchronous renderling API (the other being reading data back from the GPU). You can set the background color of the stage using a Vec4 during or after creation.

    // Stage creation via Context
    let context = Context::new_stage(background_color).await;