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(
format!("point_front"),
format!("Front point"),
[0.875_f32, 0.875_f32, 0.875_f32],
engine::point(0.0, 0.0, FRAC_1_SQRT_2)
)
);
@ -145,6 +146,7 @@ fn load_pointed_assemb(assembly: &Assembly) {
Point::new(
format!("point_back"),
format!("Back point"),
[0.875_f32, 0.875_f32, 0.875_f32],
engine::point(0.0, 0.0, -FRAC_1_SQRT_2)
)
);
@ -166,6 +168,7 @@ fn load_pointed_assemb(assembly: &Assembly) {
Point::new(
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)
)
);

View file

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

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 ---

View file

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

View file

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