~luyu/comp5411-rendering-project

dcab6113c5361d95a8a228f6d98cadf7453e395f — Luyu Cheng 2 months ago da0a699
feat: generate and draw many cubes
3 files changed, 67 insertions(+), 51 deletions(-)

M Cargo.toml
M src/gl.rs
M src/lib.rs
M Cargo.toml => Cargo.toml +2 -1
@@ 2,7 2,7 @@
name = "comp5411-rendering-project"
version = "0.0.1"
authors = ["The project for the rendering part of COMP5411 (advanced computer graphics)"]
edition = "2018"
edition = "2021"

[lib]
crate-type = ["cdylib"]


@@ 14,6 14,7 @@ cgmath = "0.18.0"
rand = "0.8.4"
getrandom = { version = "0.2.3", features = ["js"] }
png = "0.17.2"
ndarray = "0.15.4"

[dependencies.web-sys]
version = "0.3.4"

M src/gl.rs => src/gl.rs +1 -1
@@ 9,7 9,7 @@ macro_rules! get_attribute_location {
        .ok_or(format!(
            "Failed to get the location of attribute \"{}\"",
            $name
        ))?;
        ))?
    };
}


M src/lib.rs => src/lib.rs +64 -49
@@ 1,11 1,11 @@
use cgmath::Matrix4;
use cgmath::SquareMatrix;
use cgmath::Vector3;
use ndarray::Array2;
use rand::prelude::*;
use std::cell::Cell;
use std::cell::RefCell;
use std::rc::Rc;
use std::vec;
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsCast;
use web_sys::WebGl2RenderingContext;


@@ 24,6 24,21 @@ enum DragMode {
    Rotate,
}

struct WorldMap {
    pub tile: Array2<u32>,
}

impl WorldMap {
    pub fn new() -> WorldMap {
        let mut tile = Array2::<u32>::zeros((16, 16));
        let mut rng = rand::thread_rng();
        for x in tile.iter_mut() {
            *x = rng.gen_range(0..=16);
        }
        WorldMap { tile }
    }
}

#[wasm_bindgen(start)]
pub fn start() -> Result<(), JsValue> {
    let window = web_sys::window().ok_or("no global `window` exists")?;


@@ 66,6 81,7 @@ pub fn start() -> Result<(), JsValue> {
    let program = gl::link_program(&context, &vert_shader, &frag_shader)?;
    context.use_program(Some(&program));

    let world = WorldMap::new();
    let cube = model::Model::cube();

    if cfg!(debug_assertions) {


@@ 76,7 92,8 @@ pub fn start() -> Result<(), JsValue> {
    let model_uniform_location = gl::get_uniform_location!(context, program, "model")?;
    let view_uniform_location = gl::get_uniform_location!(context, program, "view")?;
    let projection_uniform_location = gl::get_uniform_location!(context, program, "projection")?;
    let normal_matrix_uniform_location = gl::get_uniform_location!(context, program, "normalMatrix")?;
    let normal_matrix_uniform_location =
        gl::get_uniform_location!(context, program, "normalMatrix")?;
    let sampler_uniform_location = gl::get_uniform_location!(context, program, "textureSampler")?;

    let texture = texture::load_texture(&context).ok_or("Failed to load the texture.")?;


@@ 166,9 183,10 @@ pub fn start() -> Result<(), JsValue> {
    context.uniform1i(Some(&sampler_uniform_location), 0);

    let drag_mode = Rc::new(Cell::new(DragMode::None));
    // The camera setup.
    let model = Rc::new(Cell::new(cgmath::Matrix4::identity()));
    let view = Rc::new(Cell::new(Matrix4::from_translation(cgmath::Vector3::new(
        0.0, 0.0, -15.0,
        0.0, -8.0, -48.0,
    ))));
    {
        let drag_mode = drag_mode.clone();


@@ 258,24 276,9 @@ pub fn start() -> Result<(), JsValue> {
        )?;
        closure.forget();
    }
    let mut rng = rand::thread_rng();
    let mut replicas = vec![];
    for _ in 0..10 {
        let translation = cgmath::Vector3::<f32>::new(
            rng.gen_range(-2.0..2.0),
            rng.gen_range(-2.0..2.0),
            rng.gen_range(-2.0..2.0),
        );
        replicas.push((
            cgmath::Matrix4::from_translation(translation),
            rng.gen_range(10.0..20.0),
        ));
    }
    let replicas = Rc::new(replicas);
    {
        let model = model.clone();
        let view = view.clone();
        let replicas = replicas.clone();
        // From https://rustwasm.github.io/wasm-bindgen/examples/request-animation-frame.html
        let f: Rc<RefCell<Option<Closure<FrameRequestCallback>>>> = Rc::new(RefCell::new(None));
        let g: Rc<RefCell<Option<Closure<FrameRequestCallback>>>> = f.clone();


@@ 283,7 286,10 @@ pub fn start() -> Result<(), JsValue> {
        *g.borrow_mut() = Some(Closure::wrap(Box::new(move |time_stamp: f64| {
            let projection =
                cgmath::perspective(cgmath::Deg(45.0), width as f32 / height as f32, 0.1, 100.0);
            let view = view.get();
            let rotation_speed = 100.0;
            let rotation =
                cgmath::Matrix4::from_angle_y(cgmath::Deg(time_stamp as f32 / rotation_speed));
            let view = view.get() * rotation;
            let view_slice: &[f32; 16] = view.as_ref();
            let projection_slice: &[f32; 16] = projection.as_ref();
            context.uniform_matrix4fv_with_f32_array(


@@ 302,37 308,46 @@ pub fn start() -> Result<(), JsValue> {
                WebGl2RenderingContext::COLOR_BUFFER_BIT | WebGl2RenderingContext::DEPTH_BUFFER_BIT,
            );

            for (transformation, rotation_speed) in replicas.iter() {
                let model = transformation
                    * model.get()
                    * cgmath::Matrix4::from_angle_y(cgmath::Deg(
                        time_stamp as f32 / rotation_speed,
                    ))
                    * cgmath::Matrix4::from_angle_z(cgmath::Deg(
                        time_stamp as f32 / rotation_speed,
            let half_width = world.tile.len_of(ndarray::Axis(0)) as f32 / 2.0;
            let half_height = world.tile.len_of(ndarray::Axis(1)) as f32 / 2.0;
            for ((i, j), num_cubes) in world.tile.indexed_iter() {
                if *num_cubes == 0 {
                    continue;
                }
                // We will scale the cube to half its size.
                let scale = Matrix4::from_scale(0.5);
                for k in 0..*num_cubes {
                    // Then we will translate it to the right position.
                    let translation = Matrix4::from_translation(Vector3::new(
                        i as f32 - half_width,
                        k as f32,
                        j as f32 - half_height,
                    ));
                let model_slice: &[f32; 16] = model.as_ref();
                context.uniform_matrix4fv_with_f32_array(
                    Some(&model_uniform_location),
                    false,
                    model_slice,
                );
                // Prepare the model matrix.
                let mut normal_matrix = Matrix4::identity() * (model * view).invert().unwrap();
                normal_matrix.transpose_self();
                let normal_matrix_slice: &[f32; 16] = normal_matrix.as_ref();
                context.uniform_matrix4fv_with_f32_array(
                    Some(&normal_matrix_uniform_location),
                    false,
                    normal_matrix_slice,
                );
                // Draw the cube.
                context.draw_elements_with_i32(
                    WebGl2RenderingContext::TRIANGLES,
                    cube.indices.len() as i32,
                    WebGl2RenderingContext::UNSIGNED_SHORT,
                    0,
                );
                    let model: Matrix4<_> = model.get() * translation * scale;
                    // Set the uniform to the multiplied matrix.
                    let model_slice: &[f32; 16] = model.as_ref();
                    context.uniform_matrix4fv_with_f32_array(
                        Some(&model_uniform_location),
                        false,
                        model_slice,
                    );
                    // Prepare the model matrix.
                    let mut normal_matrix = Matrix4::identity() * (model * view).invert().unwrap();
                    normal_matrix.transpose_self();
                    let normal_matrix_slice: &[f32; 16] = normal_matrix.as_ref();
                    context.uniform_matrix4fv_with_f32_array(
                        Some(&normal_matrix_uniform_location),
                        false,
                        normal_matrix_slice,
                    );
                    // Draw the cube.
                    context.draw_elements_with_i32(
                        WebGl2RenderingContext::TRIANGLES,
                        cube.indices.len() as i32,
                        WebGl2RenderingContext::UNSIGNED_SHORT,
                        0,
                    );
                }
            }
            request_animation_frame(f.borrow().as_ref().unwrap());
        }) as Box<FrameRequestCallback>));