From 5885189b04ca63750ce113f2f77496734d36ff8d Mon Sep 17 00:00:00 2001 From: Aaron Fenyes Date: Wed, 21 Aug 2024 17:31:17 -0700 Subject: [PATCH] Draw a mesh in perspective, and in color --- app-proto/inversive-display/src/main.rs | 161 ++++++++++++++++-------- 1 file changed, 112 insertions(+), 49 deletions(-) diff --git a/app-proto/inversive-display/src/main.rs b/app-proto/inversive-display/src/main.rs index 6730a39..6768864 100644 --- a/app-proto/inversive-display/src/main.rs +++ b/app-proto/inversive-display/src/main.rs @@ -2,9 +2,13 @@ // // https://rustwasm.github.io/wasm-bindgen/examples/webgl.html // +// and this StackOverflow answer by wangdq +// +// https://stackoverflow.com/a/39684775 +// extern crate js_sys; -use std::f64::consts::PI as PI; +/* use std::f64::consts::PI as PI; */ use sycamore::{prelude::*, rt::{JsCast, JsValue}}; use web_sys::{console, WebGl2RenderingContext, WebGlProgram, WebGlShader}; @@ -19,6 +23,52 @@ fn compile_shader( shader } +// load the given data into the vertex input of the given name +fn bind_vertex_attrib( + context: &WebGl2RenderingContext, + program: &WebGlProgram, + name: &str, + size: i32, + data: &[f32] +) { + // create a data buffer and bind it to ARRAY_BUFFER + let buffer = context.create_buffer().unwrap(); + context.bind_buffer(WebGl2RenderingContext::ARRAY_BUFFER, Some(&buffer)); + + // load the given data into the buffer. the function `Float32Array::view` + // creates a raw view into our module's `WebAssembly.Memory` buffer. + // allocating more memory will change the buffer, invalidating the view. + // that means we have to make sure we don't allocate any memory until the + // view is dropped + unsafe { + context.buffer_data_with_array_buffer_view( + WebGl2RenderingContext::ARRAY_BUFFER, + &js_sys::Float32Array::view(&data), + WebGl2RenderingContext::STATIC_DRAW, + ); + } + + // find the target attribute in the program's attribute list + let attrib_index = context.get_attrib_location(&program, name); + + // allow the target attribute to be used + context.enable_vertex_attrib_array(attrib_index as u32); + + // take whatever's bound to ARRAY_BUFFER---here, the data buffer created + // above---and bind it to the target attribute + // + // https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/vertexAttribPointer + // + context.vertex_attrib_pointer_with_i32( + attrib_index as u32, + size, + WebGl2RenderingContext::FLOAT, + false, // don't normalize + 0, // zero stride + 0, // zero offset + ); +} + fn main() { // set up a config option that forwards panic messages to `console.error` #[cfg(feature = "console_error_panic_hook")] @@ -40,16 +90,31 @@ fn main() { .dyn_into::() .unwrap(); - // load the vertex and fragment shaders + // compile and attach the vertex and fragment shaders let vertex_shader = compile_shader( &ctx, WebGl2RenderingContext::VERTEX_SHADER, r##"#version 300 es - in vec4 position; + in vec3 position; + in vec3 color; + + out vec4 vertexColor; + + const float focal_length = 3.0; + const float near_clip = 0.1; + const float far_clip = 20.0; + const float depth_inv = 1. / (far_clip - near_clip); void main() { - gl_Position = position; + const mat4 world_to_clip = mat4( + focal_length, 0.0, 0.0, 0.0, + 0.0, focal_length, 0.0, 0.0, + 0.0, 0.0, (near_clip + far_clip) * depth_inv, -1., + 0.0, 0.0, 2. * near_clip * far_clip * depth_inv, 0.0 + ); + gl_Position = world_to_clip * vec4(position, 1.); + vertexColor = vec4(color, 1.); } "##, ); @@ -59,10 +124,13 @@ fn main() { r##"#version 300 es precision highp float; + + in vec4 vertexColor; + out vec4 outColor; void main() { - outColor = vec4(gl_FragCoord.xy / 600., 1., 1.); + outColor = vertexColor; } "##, ); @@ -82,58 +150,53 @@ fn main() { console::log_1(&JsValue::from(link_msg)); ctx.use_program(Some(&program)); + // create a vertex array and bind it to the graphics context + let vertex_array = ctx.create_vertex_array().unwrap(); + ctx.bind_vertex_array(Some(&vertex_array)); + // set up a repainting routine create_effect(move || { - // list the vertices - let vertices: [f32; 9] = [ - -0.9, 0.9, 0.0, - -0.9, -0.9, 0.0, - 0.9*(tip.get() as f32), 0.0, 0.0 + const VERTEX_CNT: usize = 9; + + // set the vertex positions + let tip_shift = 4.0/3.0 * tip.get() as f32; + let positions: [f32; 3*VERTEX_CNT] = [ + // triangle 1 + 1.0 - tip_shift, 1.0 - tip_shift, -5.0 - tip_shift, + 1.0, -1.0, -7.0, + -1.0, 1.0, -7.0, + // triangle 2 + 1.0 - tip_shift, 1.0 - tip_shift, -5.0 - tip_shift, + -1.0, 1.0, -7.0, + -1.0, -1.0, -7.0, + // triangle 3 + 1.0 - tip_shift, 1.0 - tip_shift, -5.0 - tip_shift, + -1.0, -1.0, -7.0, + 1.0, -1.0, -7.0 ]; + bind_vertex_attrib(&ctx, &program, "position", 3, &positions); - // create a vertex buffer and bind it to ARRAY_BUFFER - let position_attribute_location = ctx.get_attrib_location(&program, "position"); - let buffer = ctx.create_buffer().unwrap(); - ctx.bind_buffer(WebGl2RenderingContext::ARRAY_BUFFER, Some(&buffer)); - - // load the vertex list into the vertex buffer. the function - // `Float32Array::view` creates a raw view into our module's - // `WebAssembly.Memory` buffer. allocating more memory will - // change the buffer, invalidating the view. that means we have - // to make sure we don't allocate any memory until the view is - // dropped - unsafe { - ctx.buffer_data_with_array_buffer_view( - WebGl2RenderingContext::ARRAY_BUFFER, - &js_sys::Float32Array::view(&vertices), - WebGl2RenderingContext::STATIC_DRAW, - ); - } - - // create a vertex array and bind it to the graphics context - let vtx_array_obj = ctx.create_vertex_array().unwrap(); - ctx.bind_vertex_array(Some(&vtx_array_obj)); - - // use whatever is bound to ARRAY_BUFFER---here, the vertex - // buffer created above---as the vertex attribute array - // - // https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/vertexAttribPointer - // - ctx.vertex_attrib_pointer_with_i32( - position_attribute_location as u32, - 3, // dimension - WebGl2RenderingContext::FLOAT, // type - false, // normalized? - 0, // stride - 0, // offset - ); - ctx.enable_vertex_attrib_array(position_attribute_location as u32); + // set the vertex colors + let colors: [f32; 3*VERTEX_CNT] = [ + // triangle 1 + 1.0, 0.0, 0.5, + 1.0, 0.0, 0.5, + 1.0, 0.0, 0.5, + // triangle 2 + 0.0, 0.5, 1.0, + 0.0, 0.5, 1.0, + 0.0, 0.5, 1.0, + // triangle 3 + 0.5, 0.0, 1.0, + 0.5, 0.0, 1.0, + 0.5, 0.0, 1.0 + ]; + bind_vertex_attrib(&ctx, &program, "color", 3, &colors); // clear the screen and draw the scene - let vert_count = (vertices.len() / 3) as i32; ctx.clear_color(0.0, 0.0, 0.0, 1.0); ctx.clear(WebGl2RenderingContext::COLOR_BUFFER_BIT); - ctx.draw_arrays(WebGl2RenderingContext::TRIANGLES, 0, vert_count); + ctx.draw_arrays(WebGl2RenderingContext::TRIANGLES, 0, VERTEX_CNT as i32); }); });