Color points

In the process, find and correct a misunderstanding about vertex
attributes. Here's my current understanding. Vertex attributes are
program-independent. When you make a draw call, every enabled attribute
has to have a vertex buffer object bound to it. A simple way to make
sure this happens is to enable only the attributes used by the active
program.
This commit is contained in:
Aaron Fenyes 2025-04-25 12:06:21 -07:00
parent 1945086586
commit 0fbb071506
5 changed files with 60 additions and 24 deletions

View file

@ -48,15 +48,22 @@ impl SceneSpheres {
}
struct ScenePoints {
representations: Vec<DVector<f64>>
representations: Vec<DVector<f64>>,
colors: Vec<ElementColor>,
}
impl ScenePoints {
fn new() -> ScenePoints {
ScenePoints {
representations: Vec::new()
representations: Vec::new(),
colors: Vec::new()
}
}
fn push(&mut self, representation: DVector<f64>, color: ElementColor) {
self.representations.push(representation);
self.colors.push(color);
}
}
pub struct Scene {
@ -135,7 +142,7 @@ impl DisplayItem for Sphere {
impl DisplayItem for Point {
fn show(&self, scene: &mut Scene, _selected: bool) {
let representation = self.representation.get_clone_untracked();
scene.points.representations.push(representation);
scene.points.push(representation, self.color);
}
/* SCAFFOLDING */
@ -211,18 +218,6 @@ fn get_uniform_array_locations<const N: usize>(
})
}
// find the vertex attribute called `attr_name` in the given program. enable it
// and return its index
fn find_and_enable_attribute(
context: &WebGl2RenderingContext,
program: &WebGlProgram,
attr_name: &str
) -> u32 {
let attr_index = context.get_attrib_location(program, attr_name) as u32;
context.enable_vertex_attrib_array(attr_index);
attr_index
}
// bind the given vertex buffer object to the given vertex attribute
fn bind_to_attribute(
context: &WebGl2RenderingContext,
@ -267,6 +262,16 @@ fn load_new_buffer(
buffer
}
fn bind_new_buffer_to_attribute(
context: &WebGl2RenderingContext,
attr_index: u32,
attr_size: i32,
data: &[f32]
) {
let buffer = load_new_buffer(context, data);
bind_to_attribute(context, attr_index, attr_size, &buffer);
}
// the direction in camera space that a mouse event is pointing along
fn event_dir(event: &MouseEvent) -> Vector3<f64> {
let target: web_sys::Element = event.target().unwrap().unchecked_into();
@ -405,8 +410,8 @@ pub fn Display() -> View {
&JsValue::from("uniform vectors available")
);
// find and enable the sphere program's sole vertex attribute
let viewport_position_attr = find_and_enable_attribute(&ctx, &sphere_program, "position");
// find the sphere program's vertex attribute
let viewport_position_attr = ctx.get_attrib_location(&sphere_program, "position") as u32;
// find the sphere program's uniforms
const SPHERE_MAX: usize = 200;
@ -443,8 +448,9 @@ pub fn Display() -> View {
];
let viewport_position_buffer = load_new_buffer(&ctx, &viewport_positions);
// find and enable the point program's sole vertex attribute
let point_position_attr = find_and_enable_attribute(&ctx, &point_program, "position");
// find the point program's vertex attributes
let point_position_attr = ctx.get_attrib_location(&point_program, "position") as u32;
let point_color_attr = ctx.get_attrib_location(&point_program, "color") as u32;
// set up a repainting routine
let (_, start_animation_loop, _) = create_raf(move || {
@ -539,6 +545,7 @@ pub fn Display() -> View {
if scene_changed.get() {
const SPACE_DIM: usize = 3;
const COLOR_SIZE: usize = 3;
/* INSTRUMENTS */
// measure mean frame interval
@ -580,6 +587,9 @@ pub fn Display() -> View {
// use the sphere rendering program
ctx.use_program(Some(&sphere_program));
// enable the sphere program's vertex attribute
ctx.enable_vertex_attrib_array(viewport_position_attr);
// write the spheres in world coordinates
let sphere_reps_world: Vec<_> = scene.spheres.representations.into_iter().map(
|rep| (&asm_to_world * rep).cast::<f32>()
@ -625,12 +635,19 @@ pub fn Display() -> View {
// draw the scene
ctx.draw_arrays(WebGl2RenderingContext::TRIANGLES, 0, VERTEX_CNT as i32);
// disable the sphere program's vertex attribute
ctx.disable_vertex_attrib_array(viewport_position_attr);
// --- draw the points ---
if !scene.points.representations.is_empty() {
// use the point rendering program
ctx.use_program(Some(&point_program));
// enable the point program's vertex attributes
ctx.enable_vertex_attrib_array(point_position_attr);
ctx.enable_vertex_attrib_array(point_color_attr);
// write the points in world coordinates
let asm_to_world_sp = asm_to_world.rows(0, SPACE_DIM);
let point_positions = DMatrix::from_columns(
@ -639,13 +656,18 @@ pub fn Display() -> View {
).collect::<Vec<_>>().as_slice()
).cast::<f32>();
// load the point positions into a new buffer and bind it to the
// position attribute in the vertex shader
let point_position_buffer = load_new_buffer(&ctx, point_positions.as_slice());
bind_to_attribute(&ctx, point_position_attr, SPACE_DIM as i32, &point_position_buffer);
// load the point positions and colors into new buffers and
// bind them to the corresponding attributes in the vertex
// shader
bind_new_buffer_to_attribute(&ctx, point_position_attr, SPACE_DIM as i32, point_positions.as_slice());
bind_new_buffer_to_attribute(&ctx, point_color_attr, COLOR_SIZE as i32, scene.points.colors.concat().as_slice());
// draw the scene
ctx.draw_arrays(WebGl2RenderingContext::POINTS, 0, point_positions.ncols() as i32);
// disable the point program's vertex attributes
ctx.disable_vertex_attrib_array(point_position_attr);
ctx.disable_vertex_attrib_array(point_color_attr);
}
// --- update the display state ---