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

@ -138,6 +138,7 @@ fn load_pointed_assemb(assembly: &Assembly) {
Point::new( Point::new(
format!("point_front"), format!("point_front"),
format!("Front point"), format!("Front point"),
[0.875_f32, 0.875_f32, 0.875_f32],
engine::point(0.0, 0.0, FRAC_1_SQRT_2) engine::point(0.0, 0.0, FRAC_1_SQRT_2)
) )
); );
@ -145,6 +146,7 @@ fn load_pointed_assemb(assembly: &Assembly) {
Point::new( Point::new(
format!("point_back"), format!("point_back"),
format!("Back point"), format!("Back point"),
[0.875_f32, 0.875_f32, 0.875_f32],
engine::point(0.0, 0.0, -FRAC_1_SQRT_2) engine::point(0.0, 0.0, -FRAC_1_SQRT_2)
) )
); );
@ -166,6 +168,7 @@ fn load_pointed_assemb(assembly: &Assembly) {
Point::new( Point::new(
format!("point{index_x}{index_y}"), format!("point{index_x}{index_y}"),
format!("Point {index_x}{index_y}"), format!("Point {index_x}{index_y}"),
[0.4*(2.0 + x) as f32, 0.4*(2.0 + y) as f32, 0.4*(2.0 - x*y) as f32],
engine::point(x, y, 0.0) engine::point(x, y, 0.0)
) )
); );

View file

@ -202,6 +202,7 @@ impl ProblemPoser for Sphere {
pub struct Point { pub struct Point {
pub id: String, pub id: String,
pub label: String, pub label: String,
pub color: ElementColor,
pub representation: Signal<DVector<f64>>, pub representation: Signal<DVector<f64>>,
pub regulators: Signal<BTreeSet<RegulatorKey>>, pub regulators: Signal<BTreeSet<RegulatorKey>>,
pub serial: u64, pub serial: u64,
@ -214,11 +215,13 @@ impl Point {
pub fn new( pub fn new(
id: String, id: String,
label: String, label: String,
color: ElementColor,
representation: DVector<f64> representation: DVector<f64>
) -> Point { ) -> Point {
Point { Point {
id, id,
label, label,
color,
representation: create_signal(representation), representation: create_signal(representation),
regulators: create_signal(BTreeSet::default()), regulators: create_signal(BTreeSet::default()),
serial: Self::next_serial(), serial: Self::next_serial(),
@ -236,6 +239,7 @@ impl Element for Point {
Point::new( Point::new(
id, id,
format!("Point {id_num}"), format!("Point {id_num}"),
[0.875_f32, 0.875_f32, 0.875_f32],
point(0.0, 0.0, 0.0) point(0.0, 0.0, 0.0)
) )
} }

View file

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

View file

@ -2,8 +2,10 @@
precision highp float; precision highp float;
in vec3 point_color;
out vec4 outColor; out vec4 outColor;
void main() { void main() {
outColor = vec4(vec3(1.), 1.); outColor = vec4(point_color, 1.);
} }

View file

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