use of instancing and impl inside the line rasterizer. Lyon is not needed anymore for plotting lines, but still used for plotting filled paths

This commit is contained in:
Matthieu Baumann
2024-06-13 17:26:59 +02:00
parent 49061a746b
commit 776cd36969
8 changed files with 204 additions and 39 deletions

View File

@@ -14,7 +14,7 @@
A.init.then(() => {
aladin = A.aladin('#aladin-lite-div', {showReticle: true, showSurveyStackControl: true, showOverlayStackControl: false, projection: "TAN", target: '15 16 57.636 -60 55 7.49', showProjectionControl: true, realFullscreen: true, showZoomControl: true, showSimbadPointerControl: true, showShareControl: true, showContextMenu: true, showCooGridControl: true, fullScreen: true, showCooGrid: true, fov: 90});
var moc_0_99 = A.MOCFromURL("./data//gw/gw_0.9.fits",{ name: "GW 90%", color: "#ff0000", opacity: 0.0, lineWidth: 3, fill: false, perimeter: true});
var moc_0_99 = A.MOCFromURL("./data//gw/gw_0.9.fits",{ name: "GW 90%", color: "#ff0000", opacity: 0.0, lineWidth: 10, fill: false, perimeter: true});
var moc_0_95 = A.MOCFromURL("./data/gw/gw_0.6.fits",{ name: "GW 60%", color: "#00ff00", opacity: 0.5, lineWidth: 3, fill: true, perimeter: true});
var moc_0_5 = A.MOCFromURL("./data/gw/gw_0.3.fits",{ name: "GW 30%", color: "#00ffff", opacity: 0.5, lineWidth: 3, fill: true, perimeter: true});
var moc_0_2 = A.MOCFromURL("./data/gw/gw_0.1.fits",{ name: "GW 10%", color: "#ff00ff", opacity: 0.5, lineWidth: 3, fill: true, perimeter: true});

View File

@@ -23,6 +23,7 @@
reticleColor: '#ff89ff', // change reticle color
reticleSize: 64, // change reticle size
showContextMenu: true,
showCooGrid: true,
}
);
});

View File

@@ -6,6 +6,7 @@ use crate::webgl_ctx::WebGlContext;
pub struct ArrayBufferInstanced {
buffer: WebGlBuffer,
len: usize,
num_packed_data: usize,
offset_idx: u32,
@@ -39,7 +40,7 @@ impl ArrayBufferInstanced {
offset_idx: u32,
stride: usize,
sizes: &[usize],
_offsets: &[usize],
offsets: &[usize],
usage: u32,
data: B,
) -> ArrayBufferInstanced {
@@ -49,29 +50,43 @@ impl ArrayBufferInstanced {
let num_f32_in_buf = data.len() as i32;
let num_instances = num_f32_in_buf / (num_f32_per_instance as i32);
let len = data.len();
let buffer = gl.create_buffer().ok_or("failed to create buffer").unwrap_abort();
let buffer = gl
.create_buffer()
.ok_or("failed to create buffer")
.unwrap_abort();
// Bind the buffer
gl.bind_buffer(WebGlRenderingCtx::ARRAY_BUFFER, Some(buffer.as_ref()));
// Pass the vertices data to the buffer
f32::buffer_data_with_array_buffer_view(gl, data, WebGlRenderingCtx::ARRAY_BUFFER, usage);
// Link to the shader
let idx = offset_idx;
for (idx, (size, offset)) in sizes.iter().zip(offsets.iter()).enumerate() {
let idx = (idx as u32) + offset_idx;
f32::vertex_attrib_pointer_with_i32(gl, idx, *sizes.first().unwrap_abort() as i32, 0, 0);
gl.enable_vertex_attrib_array(idx);
f32::vertex_attrib_pointer_with_i32(
gl,
idx,
*size as i32,
stride as i32,
*offset as i32,
);
#[cfg(feature = "webgl2")]
gl.vertex_attrib_divisor(idx, 1);
#[cfg(feature = "webgl1")]
gl.ext.angles.vertex_attrib_divisor_angle(idx, 1);
gl.enable_vertex_attrib_array(idx);
#[cfg(feature = "webgl2")]
gl.vertex_attrib_divisor(idx, 1);
#[cfg(feature = "webgl1")]
gl.ext.angles.vertex_attrib_divisor_angle(idx, 1);
}
let num_packed_data = sizes.len();
let gl = gl.clone();
// Returns an instance that keeps only the buffer
ArrayBufferInstanced {
buffer,
len,
num_packed_data,
offset_idx,
@@ -119,13 +134,30 @@ impl ArrayBufferInstanced {
self.gl.disable_vertex_attrib_array(loc as u32);
}
pub fn update<'a, B: BufferDataStorage<'a, f32>>(&self, buffer: B) {
pub fn update<'a, B: BufferDataStorage<'a, f32>>(&mut self, usage: u32, data: B) {
self.bind();
f32::buffer_sub_data_with_i32_and_array_buffer_view(
if self.len >= data.len() {
f32::buffer_sub_data_with_i32_and_array_buffer_view(
&self.gl,
data,
WebGlRenderingCtx::ARRAY_BUFFER,
);
} else {
self.len = data.len();
f32::buffer_data_with_array_buffer_view(
&self.gl,
data,
WebGlRenderingCtx::ARRAY_BUFFER,
usage,
);
}
/*f32::buffer_sub_data_with_i32_and_array_buffer_view(
&self.gl,
buffer,
WebGlRenderingCtx::ARRAY_BUFFER,
);
);*/
/*self.gl.buffer_sub_data_with_i32_and_array_buffer_view(
WebGlRenderingCtx::ARRAY_BUFFER,
0,

View File

@@ -9,8 +9,8 @@ pub mod vao {
use crate::object::element_array_buffer::ElementArrayBuffer;
use crate::webgl_ctx::WebGlContext;
use std::collections::HashMap;
use crate::Abort;
use std::collections::HashMap;
pub struct VertexArrayObject {
array_buffer: HashMap<&'static str, ArrayBuffer>,
@@ -88,7 +88,10 @@ pub mod vao {
}*/
pub fn num_elements(&self) -> usize {
self.element_array_buffer.as_ref().unwrap_abort().num_elements()
self.element_array_buffer
.as_ref()
.unwrap_abort()
.num_elements()
}
pub fn num_instances(&self) -> i32 {
@@ -143,13 +146,14 @@ pub mod vao {
pub fn update_instanced_array<B: BufferDataStorage<'a, f32>>(
&mut self,
attr: &'static str,
usage: u32,
array_data: B,
) -> &mut Self {
self.vao
.array_buffer_instanced
.get_mut(attr)
.unwrap_abort()
.update(array_data);
.update(usage, array_data);
self
}
@@ -333,13 +337,14 @@ pub mod vao {
pub fn update_instanced_array<B: BufferDataStorage<'a, f32>>(
&mut self,
attr: &'static str,
usage: u32,
array_data: B,
) -> &mut Self {
self.vao
.array_buffer_instanced
.get_mut(attr)
.unwrap_abort()
.update(array_data);
.update(usage, array_data);
self
}
@@ -444,7 +449,10 @@ pub mod vao {
}*/
pub fn num_elements(&self) -> usize {
self.element_array_buffer.as_ref().unwrap_abort().num_elements()
self.element_array_buffer
.as_ref()
.unwrap_abort()
.num_elements()
}
pub fn num_instances(&self) -> i32 {
@@ -694,13 +702,14 @@ pub mod vao {
pub fn update_instanced_array<B: BufferDataStorage<'a, f32>>(
&mut self,
attr: &'static str,
usage: u32,
array_data: B,
) -> &mut Self {
self.vao
.array_buffer_instanced
.get_mut(attr)
.expect("cannot get attribute from the array buffer")
.update(array_data);
.update(usage, array_data);
self
}

View File

@@ -26,6 +26,7 @@ impl From<Error> for JsValue {
}
}
// Num of shapes
const _NUM_SHAPES: usize = 5;
pub struct Manager {
gl: WebGlContext,
@@ -457,7 +458,11 @@ impl Catalog {
#[cfg(feature = "webgl2")]
self.vertex_array_object_catalog
.bind_for_update()
.update_instanced_array("center", VecData(&sources));
.update_instanced_array(
"center",
WebGl2RenderingContext::DYNAMIC_DRAW,
VecData(&sources),
);
}
fn draw(

View File

@@ -11,14 +11,11 @@ use super::Renderer;
use al_api::color::ColorRGBA;
use al_core::SliceData;
use lyon::algorithms::{
math::point,
measure::{PathMeasurements, SampleType},
path::Path,
};
use lyon::algorithms::{math::point, path::Path};
struct Meta {
color: ColorRGBA,
thickness: f32,
off_indices: usize,
num_indices: usize,
}
@@ -35,9 +32,16 @@ pub struct RasterizedLineRenderer {
shader: Shader,
vao: VertexArrayObject,
shader_line_instanced: Shader,
vao_idx: usize,
vertices: Vec<f32>,
indices: Vec<u32>,
meta: Vec<Meta>,
instanced_line_vaos: Vec<VertexArrayObject>,
meta_instanced: Vec<Meta>,
}
use wasm_bindgen::JsValue;
@@ -68,6 +72,38 @@ impl RasterizedLineRenderer {
include_str!("../../../../glsl/webgl2/line/line_vertex.glsl"),
include_str!("../../../../glsl/webgl2/line/line_frag.glsl"),
)?;
let shader_line_instanced = Shader::new(
&gl,
r#"#version 300 es
precision lowp float;
layout (location = 0) in vec2 p_a;
layout (location = 1) in vec2 p_b;
layout (location = 2) in vec2 vertex;
out vec2 out_uv;
out vec3 out_p;
uniform float u_width;
void main() {
vec2 x_b = p_b - p_a;
vec2 y_b = normalize(vec2(-x_b.y, x_b.x));
vec2 p = p_a + x_b * vertex.x + y_b * u_width * 0.001 * vertex.y;
gl_Position = vec4(p, 0.f, 1.f);
}"#,
r#"#version 300 es
precision lowp float;
out vec4 color;
uniform vec4 u_color;
void main() {
// Multiply vertex color with texture color (in linear space).
// Linear color is written and blended in Framebuffer and converted to sRGB later
color = u_color;
}"#,
)?;
let mut vao = VertexArrayObject::new(&gl);
vao.bind_for_update()
@@ -87,10 +123,17 @@ impl RasterizedLineRenderer {
.unbind();
let meta = vec![];
let meta_instanced = vec![];
let gl = gl.clone();
let instanced_line_vaos = vec![];
Ok(Self {
gl,
shader,
shader_line_instanced,
vao_idx: 0,
instanced_line_vaos,
meta_instanced,
vao,
meta,
vertices,
@@ -167,22 +210,57 @@ impl RasterizedLineRenderer {
self.meta.push(Meta {
off_indices,
num_indices,
thickness: 1.0,
color: color.clone(),
});
}
fn create_instanced_vao(&mut self) {
let mut vao = VertexArrayObject::new(&self.gl);
vao.bind_for_update()
// Store the cartesian position of the center of the source in the a instanced VBO
.add_instanced_array_buffer(
"ndc_pos",
4 * std::mem::size_of::<f32>(),
&[2, 2],
&[0, 2 * std::mem::size_of::<f32>()],
WebGl2RenderingContext::DYNAMIC_DRAW,
SliceData(&[]),
)
.add_array_buffer(
"vertices",
2 * std::mem::size_of::<f32>(),
&[2],
&[0],
WebGl2RenderingContext::STATIC_DRAW,
SliceData(&[
0_f32, -0.5_f32, 1_f32, -0.5_f32, 1_f32, 0.5_f32, 0_f32, 0.5_f32,
]),
)
// Set the element buffer
.add_element_buffer(
WebGl2RenderingContext::STATIC_DRAW,
SliceData(&[0_u16, 1_u16, 2_u16, 0_u16, 2_u16, 3_u16]),
)
// Unbind the buffer
.unbind();
self.instanced_line_vaos.push(vao);
}
pub fn add_stroke_paths<T>(
&mut self,
paths: impl Iterator<Item = PathVertices<T>>,
thickness: f32,
color: &ColorRGBA,
style: &Style,
_style: &Style,
) where
T: AsRef<[[f32; 2]]>,
{
let num_vertices = (self.vertices.len() / 2) as u32;
//let num_vertices = (self.vertices.len() / 2) as u32;
let mut path_builder = Path::builder();
/*let mut path_builder = Path::builder();
match &style {
Style::None => {
@@ -268,17 +346,40 @@ impl RasterizedLineRenderer {
.unwrap_abort();
}
let VertexBuffers { vertices, indices } = geometry;
let VertexBuffers { vertices, indices } = geometry;*/
if self.vao_idx == self.instanced_line_vaos.len() {
// create a vao
self.create_instanced_vao();
}
let num_indices = indices.len();
let off_indices = self.indices.len();
let vao = &mut self.instanced_line_vaos[self.vao_idx];
self.vao_idx += 1;
self.vertices.extend(vertices.iter().flatten());
self.indices.extend(indices.iter());
let mut buf: Vec<f32> = vec![];
self.meta.push(Meta {
off_indices,
num_indices,
for PathVertices { vertices } in paths {
let vertices = vertices.as_ref();
let path_vertices_buf_iter = vertices
.iter()
.zip(vertices.iter().skip(1))
.map(|(a, b)| [a[0], a[1], b[0], b[1]])
.flatten();
buf.extend(path_vertices_buf_iter);
}
vao.bind_for_update().update_instanced_array(
"ndc_pos",
WebGl2RenderingContext::DYNAMIC_DRAW,
VecData(&buf),
);
let num_instances = buf.len() / 4;
self.meta_instanced.push(Meta {
off_indices: 0,
thickness,
num_indices: num_instances,
color: color.clone(),
});
}
@@ -308,6 +409,21 @@ impl RasterizedLineRenderer {
}
//self.gl.enable(WebGl2RenderingContext::CULL_FACE);
// draw the lines
let shader_bound = self.shader_line_instanced.bind(&self.gl);
for (idx, meta) in self.meta_instanced.iter().enumerate() {
let vao_bound = shader_bound
.attach_uniform("u_color", &meta.color)
.attach_uniform("u_width", &meta.thickness)
.bind_vertex_array_object_ref(&self.instanced_line_vaos[idx]);
vao_bound.draw_elements_instanced_with_i32(
WebGl2RenderingContext::TRIANGLES,
0,
meta.num_indices as i32,
);
}
self.gl.disable(WebGl2RenderingContext::BLEND);
Ok(())
@@ -318,8 +434,10 @@ impl Renderer for RasterizedLineRenderer {
fn begin(&mut self) {
self.vertices.clear();
self.indices.clear();
self.meta.clear();
self.meta_instanced.clear();
self.vao_idx = 0;
}
fn end(&mut self) {

View File

@@ -164,7 +164,7 @@ export let DefaultActionsForContextMenu = (function () {
files.forEach(file => {
const url = URL.createObjectURL(file);
let moc = A.MOCFromURL(url, { name: file.name, fill: true, opacity: 0.4 });
let moc = A.MOCFromURL(url, { name: file.name, edge: true });
a.addMOC(moc);
});
};

View File

@@ -36,7 +36,7 @@ export let MOC = (function() {
*
* @class
* @constructs MOC
* @param {MOCOptions} options - Configuration options for the MOC.
* @param {MOCOptions} options - Configuration options for the MOC
*/
let MOC = function(options) {
//this.order = undefined;