Module view3d

Source
Expand description

Gemini’s implementation of 3D rendering. Capable of rendering full 3D meshes as wireframes, solid colours or with lighting

§Example

Let’s write a simple example program to draw a spinning cube. This example is available in examples/spinning-cube.rs

//! An example of a spinning cube with `view3d`
use gemini_engine::{
    core::ColChar,
    fps_gameloop,
    mesh3d::{Mesh3D, Transform3D, Vec3D},
    view::View,
    view3d::{DisplayMode, Light, Viewport},
};
use std::time::Duration;

const FPS: f32 = 30.0;
const FOV: f64 = 80.0;

fn main() {
    let mut view = View::new(100, 50, ColChar::EMPTY);

    let mut viewport = Viewport::new(
        Transform3D::look_at_lh(Vec3D::new(0.0, -1.5, 4.3), Vec3D::ZERO, Vec3D::Y),
        FOV,
        view.center(),
    );
    viewport.objects.push(Mesh3D::default_cube());

    viewport.display_mode = DisplayMode::Illuminated {
        lights: vec![
            Light::new_ambient(0.3),
            Light::new_directional(0.6, Vec3D::new(0.5, 1.0, 1.0)),
        ],
    };

    fps_gameloop!(
        {
            viewport.objects[0].transform = viewport.objects[0]
                .transform
                .mul_mat4(&Transform3D::from_rotation_y(-0.05));
        },
        {
            view.clear();
            view.draw(&viewport);
            let _ = view.display_render();
        },
        FPS,
        |elapsed: Duration, frame_skip| {
            println!(
                "Elapsed: {:.2?}µs | Frame skip: {}",
                elapsed.as_micros(),
                frame_skip
            );
        }
    );
}

There is a lot of code here, but here we’ll only focus on the parts that are different from the gameloop example:

§Initialisation

let mut view = View::new(100, 50, ColChar::EMPTY);

let mut viewport = Viewport::new(
    Transform3D::look_at_lh(Vec3D::new(0.0, -1.5, 4.3), Vec3D::ZERO, Vec3D::Y),
    FOV,
    view.center(),
);
viewport.objects.push(Mesh3D::default_cube());

viewport.display_mode = DisplayMode::Illuminated {
    lights: vec![
        Light::new_ambient(0.3),
        Light::new_directional(0.6, Vec3D::new(0.5, 1.0, 1.0)),
    ],
};

main() begins with the creation of all the necessary objects to render 3D images:

  1. View to handle the canvas and printing to the screen
  2. Viewport to handle drawing 3d objects to the canvas
  3. The actual objects you intend to use in the scene, as Mesh3D

In this scenario, we create a View of width 100 and height 50 (you may have to zoom out and expand your terminal to fit the whole image), a Viewport with a camera positioned at (0,-1.5,4.3) pointing at (0,0,0), our desired FOV and origin point (the centre of the view we’re printing to) in the middle of the View. We add a single default cube, which is 2 units tall, wide and long to the Viewports list of objects, and set the Viewport’s display_mode to DisplayMode::Illuminated with a simple lighting setup

§Gameloop process logic

viewport.objects[0].transform = viewport.objects[0]
    .transform
    .mul_mat4(&Transform3D::from_rotation_y(-0.05));

This part of the code is where we would put all our physics, collisions, events etc. code, but in this case the only thing we do is rotate the cube 0.05 radians anticlockwise in the Y axis.

§Drawing/Rendering

view.clear();
view.draw(&viewport);
let _ = view.display_render();

This part of the code renders and draws all the 3d stuff to the View before rendering with display_render as usual. Viewport implements CanDraw, so when it is draw to the View, it fully renders our scene based on its stored transform, display mode, objects, etc.

Structs§

Light
A light object used to define a scene’s lighting. Used by DisplayMode::Illuminated
Viewport
The Viewport handles drawing 3D objects to a 2D Canvas, and also acts as the scene’s camera.

Enums§

DisplayMode
DisplayMode determines how the Viewport renders our 3D objects. This is the Gemini equivalent of Blender’s Viewport Shading options
LightType
Type of light, determines how the normal of a face affects its illumination

Constants§

BRIGHTNESS_CHARS
Characters for brightness. The first character is the darkest and the last character is the brightest