Sketch a point rendering pipeline

This commit is contained in:
Aaron Fenyes 2025-04-21 20:35:17 -07:00
parent 3590b1ad4e
commit 23f395331a
5 changed files with 116 additions and 37 deletions

View file

@ -27,7 +27,7 @@ fn compile_shader(
shader shader
} }
fn create_program_with_shaders( fn set_up_program(
context: &WebGl2RenderingContext, context: &WebGl2RenderingContext,
vertex_shader_source: &str, vertex_shader_source: &str,
fragment_shader_source: &str fragment_shader_source: &str
@ -131,7 +131,8 @@ fn event_dir(event: &MouseEvent) -> Vector3<f64> {
let height = rect.height(); let height = rect.height();
let shortdim = width.min(height); let shortdim = width.min(height);
// this constant should be kept synchronized with `inversive.frag` // this constant should be kept synchronized with `spheres.frag` and
// `point.vert`
const FOCAL_SLOPE: f64 = 0.3; const FOCAL_SLOPE: f64 = 0.3;
Vector3::new( Vector3::new(
@ -225,13 +226,22 @@ pub fn Display() -> View {
.dyn_into::<WebGl2RenderingContext>() .dyn_into::<WebGl2RenderingContext>()
.unwrap(); .unwrap();
// create and use the rendering program // disable depth testing
let program = create_program_with_shaders( ctx.disable(WebGl2RenderingContext::DEPTH_TEST);
// set up the sphere rendering program
let sphere_program = set_up_program(
&ctx, &ctx,
include_str!("identity.vert"), include_str!("identity.vert"),
include_str!("inversive.frag") include_str!("spheres.frag")
);
// set up the point rendering program
let point_program = set_up_program(
&ctx,
include_str!("point.vert"),
include_str!("point.frag")
); );
ctx.use_program(Some(&program));
/* DEBUG */ /* DEBUG */
// print the maximum number of vectors that can be passed as // print the maximum number of vectors that can be passed as
@ -250,31 +260,31 @@ pub fn Display() -> View {
&JsValue::from("uniform vectors available") &JsValue::from("uniform vectors available")
); );
// find indices of vertex attributes and uniforms // find indices of sphere vertex attributes and uniforms
const SPHERE_MAX: usize = 200; const SPHERE_MAX: usize = 200;
let position_index = ctx.get_attrib_location(&program, "position") as u32; let viewport_position_index = ctx.get_attrib_location(&sphere_program, "position") as u32;
let sphere_cnt_loc = ctx.get_uniform_location(&program, "sphere_cnt"); let sphere_cnt_loc = ctx.get_uniform_location(&sphere_program, "sphere_cnt");
let sphere_sp_locs = get_uniform_array_locations::<SPHERE_MAX>( let sphere_sp_locs = get_uniform_array_locations::<SPHERE_MAX>(
&ctx, &program, "sphere_list", Some("sp") &ctx, &sphere_program, "sphere_list", Some("sp")
); );
let sphere_lt_locs = get_uniform_array_locations::<SPHERE_MAX>( let sphere_lt_locs = get_uniform_array_locations::<SPHERE_MAX>(
&ctx, &program, "sphere_list", Some("lt") &ctx, &sphere_program, "sphere_list", Some("lt")
); );
let color_locs = get_uniform_array_locations::<SPHERE_MAX>( let sphere_color_locs = get_uniform_array_locations::<SPHERE_MAX>(
&ctx, &program, "color_list", None &ctx, &sphere_program, "color_list", None
); );
let highlight_locs = get_uniform_array_locations::<SPHERE_MAX>( let sphere_highlight_locs = get_uniform_array_locations::<SPHERE_MAX>(
&ctx, &program, "highlight_list", None &ctx, &sphere_program, "highlight_list", None
); );
let resolution_loc = ctx.get_uniform_location(&program, "resolution"); let resolution_loc = ctx.get_uniform_location(&sphere_program, "resolution");
let shortdim_loc = ctx.get_uniform_location(&program, "shortdim"); let shortdim_loc = ctx.get_uniform_location(&sphere_program, "shortdim");
let opacity_loc = ctx.get_uniform_location(&program, "opacity"); let opacity_loc = ctx.get_uniform_location(&sphere_program, "opacity");
let layer_threshold_loc = ctx.get_uniform_location(&program, "layer_threshold"); let layer_threshold_loc = ctx.get_uniform_location(&sphere_program, "layer_threshold");
let debug_mode_loc = ctx.get_uniform_location(&program, "debug_mode"); let debug_mode_loc = ctx.get_uniform_location(&sphere_program, "debug_mode");
// set the vertex positions // set the viewport vertex positions
const VERTEX_CNT: usize = 6; const VERTEX_CNT: usize = 6;
let positions: [f32; 3*VERTEX_CNT] = [ let viewport_positions: [f32; 3*VERTEX_CNT] = [
// northwest triangle // northwest triangle
-1.0, -1.0, 0.0, -1.0, -1.0, 0.0,
-1.0, 1.0, 0.0, -1.0, 1.0, 0.0,
@ -284,7 +294,9 @@ pub fn Display() -> View {
1.0, 1.0, 0.0, 1.0, 1.0, 0.0,
1.0, -1.0, 0.0 1.0, -1.0, 0.0
]; ];
bind_vertex_attrib(&ctx, position_index, 3, &positions);
// find indices of point vertex attributes and uniforms
let point_position_index = ctx.get_attrib_location(&point_program, "position") as u32;
// set up a repainting routine // set up a repainting routine
let (_, start_animation_loop, _) = create_raf(move || { let (_, start_animation_loop, _) = create_raf(move || {
@ -387,6 +399,8 @@ pub fn Display() -> View {
frames_since_last_sample = 0; frames_since_last_sample = 0;
} }
// --- get the assembly ---
// find the map from assembly space to world space // find the map from assembly space to world space
let location = { let location = {
let u = -location_z; let u = -location_z;
@ -400,12 +414,12 @@ pub fn Display() -> View {
}; };
let asm_to_world = &location * &orientation; let asm_to_world = &location * &orientation;
// get the assembly // get the spheres
let ( let (
elt_cnt, sphere_cnt,
reps_world, sphere_reps_world,
colors, sphere_colors,
highlights sphere_highlights
) = state.assembly.elements.with(|elts| { ) = state.assembly.elements.with(|elts| {
( (
// number of elements // number of elements
@ -436,16 +450,45 @@ pub fn Display() -> View {
) )
}); });
/* SCAFFOLDING */
// get the points
let point_positions = {
use crate::engine::point;
/* DEBUG */
// hard-code the origin and the centers of the spheres in
// the general test assembly
let point_reps = [
point(0.0, 0.0, 0.0),
point(0.5, 0.5, 0.0),
point(-0.5, -0.5, 0.0),
point(-0.5, 0.5, 0.0),
point(0.5, -0.5, 0.0),
point(0.0, 0.15, 1.0),
point(0.0, -0.15, -1.0)
];
const SPACE_DIM: usize = 3;
let asm_to_world_sp = asm_to_world.rows(0, SPACE_DIM);
let point_reps_world_sp = point_reps.map(|rep| &asm_to_world_sp * rep);
DMatrix::from_columns(&point_reps_world_sp).cast::<f32>()
};
// --- draw the spheres ---
// use the sphere rendering program
ctx.use_program(Some(&sphere_program));
// set the resolution // set the resolution
let width = canvas.width() as f32; let width = canvas.width() as f32;
let height = canvas.height() as f32; let height = canvas.height() as f32;
ctx.uniform2f(resolution_loc.as_ref(), width, height); ctx.uniform2f(resolution_loc.as_ref(), width, height);
ctx.uniform1f(shortdim_loc.as_ref(), width.min(height)); ctx.uniform1f(shortdim_loc.as_ref(), width.min(height));
// pass the assembly // pass the assembly data
ctx.uniform1i(sphere_cnt_loc.as_ref(), elt_cnt); ctx.uniform1i(sphere_cnt_loc.as_ref(), sphere_cnt);
for n in 0..reps_world.len() { for n in 0..sphere_reps_world.len() {
let v = &reps_world[n]; let v = &sphere_reps_world[n];
ctx.uniform3f( ctx.uniform3f(
sphere_sp_locs[n].as_ref(), sphere_sp_locs[n].as_ref(),
v[0] as f32, v[1] as f32, v[2] as f32 v[0] as f32, v[1] as f32, v[2] as f32
@ -455,12 +498,12 @@ pub fn Display() -> View {
v[3] as f32, v[4] as f32 v[3] as f32, v[4] as f32
); );
ctx.uniform3fv_with_f32_array( ctx.uniform3fv_with_f32_array(
color_locs[n].as_ref(), sphere_color_locs[n].as_ref(),
&colors[n] &sphere_colors[n]
); );
ctx.uniform1f( ctx.uniform1f(
highlight_locs[n].as_ref(), sphere_highlight_locs[n].as_ref(),
highlights[n] sphere_highlights[n]
); );
} }
@ -469,9 +512,25 @@ pub fn Display() -> View {
ctx.uniform1i(layer_threshold_loc.as_ref(), LAYER_THRESHOLD); ctx.uniform1i(layer_threshold_loc.as_ref(), LAYER_THRESHOLD);
ctx.uniform1i(debug_mode_loc.as_ref(), DEBUG_MODE); ctx.uniform1i(debug_mode_loc.as_ref(), DEBUG_MODE);
// pass the viewport vertex positions
bind_vertex_attrib(&ctx, viewport_position_index, 3, &viewport_positions);
// draw the scene // draw the scene
ctx.draw_arrays(WebGl2RenderingContext::TRIANGLES, 0, VERTEX_CNT as i32); ctx.draw_arrays(WebGl2RenderingContext::TRIANGLES, 0, VERTEX_CNT as i32);
// --- draw the points ---
// use the point rendering program
ctx.use_program(Some(&point_program));
// pass the point vertex positions
bind_vertex_attrib(&ctx, point_position_index, 3, point_positions.as_slice());
// draw the scene
ctx.draw_arrays(WebGl2RenderingContext::POINTS, 0, point_positions.ncols() as i32);
// --- update the display state ---
// update the viewpoint // update the viewpoint
assembly_to_world.set(asm_to_world); assembly_to_world.set(asm_to_world);

View file

@ -4,7 +4,6 @@ use web_sys::{console, wasm_bindgen::JsValue}; /* DEBUG */
// --- elements --- // --- elements ---
#[cfg(feature = "dev")]
pub fn point(x: f64, y: f64, z: f64) -> DVector<f64> { pub fn point(x: f64, y: f64, z: f64) -> DVector<f64> {
DVector::from_column_slice(&[x, y, z, 0.5, 0.5*(x*x + y*y + z*z)]) DVector::from_column_slice(&[x, y, z, 0.5, 0.5*(x*x + y*y + z*z)])
} }

9
app-proto/src/point.frag Normal file
View file

@ -0,0 +1,9 @@
#version 300 es
precision highp float;
out vec4 outColor;
void main() {
outColor = vec4(vec3(1.), 1.);
}

12
app-proto/src/point.vert Normal file
View file

@ -0,0 +1,12 @@
#version 300 es
in vec4 position;
// camera
const float focal_slope = 0.3;
void main() {
float depth = -focal_slope * position.z;
gl_Position = vec4(position.xy / depth, 0., 1.);
gl_PointSize = 5.;
}