Crate renderling

source ·
Expand description

A “GPU driven” renderer with a focus on simplicity and ease of use. Backed by WebGPU.

Shaders are written in Rust using rust-gpu.

All data is staged on the GPU using a slab allocator.

§Hello triangle

First you must create a crate::context::Context.

use renderling::Context;

// create a headless context with dimensions 100, 100.
let ctx = Context::headless(100, 100);

Then create a stage to place your camera, geometry, materials and lights.

use renderling::stage::Stage;
let mut stage: Stage = ctx.new_stage();

The stage is neat in that it allows you to place values and arrays of values directly onto the GPU. Those values can be modified on the CPU and synchronization will happen during Stage::render. These values are called Hybrids and HybridArrays.

use renderling::slab::{Hybrid, HybridArray};

let an_f32: Hybrid<f32> = stage.new_value(1337.0);

let an_array_of_tuples: HybridArray<(f32, u32, bool)> =
    stage.new_array([(0.0, 0, false), (1.0, 1, true)]);

In order to render, we need to “stage” a Renderlet, which is a bundle of rendering resources. We do this in the same way we “staged” an_f32 above.

But first we’ll need a Camera and some vertices of Vertex organized as triangles with counter-clockwise winding.

use renderling::{
    camera::Camera,
    stage::{Renderlet, Vertex},
};
let camera = stage.new_value(Camera::default_ortho2d(100.0, 100.0));
let vertices = stage.new_array([
    Vertex::default()
        .with_position([0.0, 0.0, 0.0])
        .with_color([0.0, 1.0, 1.0, 1.0]),
    Vertex::default()
        .with_position([0.0, 100.0, 0.0])
        .with_color([1.0, 1.0, 0.0, 1.0]),
    Vertex::default()
        .with_position([100.0, 0.0, 0.0])
        .with_color([1.0, 0.0, 1.0, 1.0]),
]);
let triangle = stage.new_value(Renderlet {
    camera_id: camera.id(),
    vertices_array: vertices.array(),
    ..Default::default()
});

This gives us triangle, which is a Hybrid<Renderlet>. We can now pass triangle to the stage to draw each frame using Stage::add_renderlet.

Finally, we get the next frame from the context with Context::get_next_frame, render to it using Stage::render and then present the frame with Frame::present.

stage.add_renderlet(&triangle);

let frame = ctx.get_next_frame().unwrap();
stage.render(&frame.view());
let img = frame.read_image().unwrap();
frame.present();

Saving img should give us this:

renderling hello triangle

§WARNING

This is very much a work in progress.

Your mileage may vary, but I hope you get good use out of this library.

PRs, criticisms and ideas are all very much welcomed at the repo.

😀☕

Modules§

  • Texture atlas.
  • Helpers for bitwise operations.
  • Physically based bloom.
  • Camera projection, view and utilities.
  • Color utils.
  • Convolution shaders.
  • Render pipelines and layouts for creating cubemaps.
  • Resources for image based lighting.
  • Mathematical helper types and functions.
  • “Physically based” types and functions.
  • Skybox shaders and CPU code.
  • GPU and CPU slab allocation.
  • GPU staging area.
  • Wrapper around wgpu::Texture.
  • Tonemapping from an HDR texture to SDR.
  • Decomposed 3d transform.
  • A tutorial module for the renderling crate.

Macros§

  • A wrapper around std::println that is a noop on the GPU.

Structs§

Enums§