Browse Source

Prototype: separate per-quad data using instanced rendeding and per-stroke data using a texture

ssao
A.Olokhtonov 11 months ago
parent
commit
31a0b0113a
  1. 70
      client/webgl_draw.js
  2. 80
      client/webgl_shaders.js

70
client/webgl_draw.js

@ -57,6 +57,74 @@ function draw(state, context) { @@ -57,6 +57,74 @@ function draw(state, context) {
gl.clearDepth(0.0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.bindBuffer(gl.ARRAY_BUFFER, lod.data_buffer);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, lod.index_buffer);
const quad_data = serializer_create(1024);
ser_f32(quad_data, 0);
ser_f32(quad_data, 0);
ser_f32(quad_data, 200);
ser_f32(quad_data, 100);
ser_u32(quad_data, 0);
ser_f32(quad_data, 200);
ser_f32(quad_data, 100);
ser_f32(quad_data, 255);
ser_f32(quad_data, 500);
ser_u32(quad_data, 0);
ser_f32(quad_data, 100);
ser_f32(quad_data, 300);
ser_f32(quad_data, 125);
ser_f32(quad_data, 854);
ser_u32(quad_data, 1);
gl.bufferData(gl.ARRAY_BUFFER, new Uint8Array(quad_data.buffer, 0, quad_data.offset), gl.STATIC_DRAW);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint32Array([0, 1, 2, 3, 2, 1, 4, 5, 6, 7, 6, 5, 8, 9, 10, 11, 10, 9]), gl.STATIC_DRAW);
locations = context.locations['sdf'].main;
gl.useProgram(context.programs['sdf'].main);
gl.uniform2f(locations['u_res'], context.canvas.width, context.canvas.height);
gl.uniform2f(locations['u_scale'], state.canvas.zoom, state.canvas.zoom);
gl.uniform2f(locations['u_translation'], state.canvas.offset.x, state.canvas.offset.y);
gl.uniform1i(locations['u_stroke_count'], 2);
gl.uniform1i(locations['u_debug_mode'], state.debug.red);
gl.uniform1i(locations['u_stroke_data'], 0);
gl.enableVertexAttribArray(locations['a_ab']);
gl.enableVertexAttribArray(locations['a_stroke_id']);
gl.vertexAttribPointer(locations['a_ab'], 4, gl.FLOAT, false, 5 * 4, 0);
gl.vertexAttribIPointer(locations['a_stroke_id'], 1, gl.INT, 5 * 4, 4 * 4);
gl.vertexAttribDivisor(locations['a_ab'], 1);
gl.vertexAttribDivisor(locations['a_stroke_id'], 1);
const stroke_data = serializer_create(1024);
ser_u8(stroke_data, 255);
ser_u8(stroke_data, 0);
ser_u8(stroke_data, 0);
ser_u8(stroke_data, 8);
ser_u8(stroke_data, 0);
ser_u8(stroke_data, 0);
ser_u8(stroke_data, 255);
ser_u8(stroke_data, 1);
gl.bindTexture(gl.TEXTURE_2D, context.textures['stroke_data']);
gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 2, 1, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([255, 0, 0, 16, 0, 0, 255, 2]));
gl.activeTexture(gl.TEXTURE0);
gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_INT, 0, 3);
/*
const before_clip = performance.now();
const index_count = bvh_clip(state, context, lod_level);
const after_clip = performance.now();
@ -124,7 +192,7 @@ function draw(state, context) { @@ -124,7 +192,7 @@ function draw(state, context) {
//index_buffer.reverse();
gl.drawElements(gl.TRIANGLES, index_count, gl.UNSIGNED_INT, 0);
}
*/
/*
// Dynamic data (stroke previews that are currently in progress)
const dynamic_points = context.dynamic_serializer.offset / config.bytes_per_point;

80
client/webgl_shaders.js

@ -102,18 +102,17 @@ const nop_fs_src = `#version 300 es @@ -102,18 +102,17 @@ const nop_fs_src = `#version 300 es
`;
const sdf_vs_src = `#version 300 es
in vec3 a_pos; // .z is radius
in vec4 a_line;
in vec3 a_color;
in vec4 a_ab; // original points
in float a_radius;
in int a_stroke_id;
uniform vec2 u_scale;
uniform vec2 u_res;
uniform vec2 u_translation;
uniform int u_stroke_count;
uniform highp sampler2D u_stroke_data;
out vec4 v_line;
out vec2 v_texcoord;
out vec3 v_color;
@ -121,40 +120,52 @@ const sdf_vs_src = `#version 300 es @@ -121,40 +120,52 @@ const sdf_vs_src = `#version 300 es
flat out float v_thickness;
void main() {
vec2 screen01 = (a_pos.xy * u_scale + u_translation) / u_res;
vec2 screen02 = screen01 * 2.0;
float apron = 2.0;
vec2 line_dir = normalize(a_line.zw - a_line.xy);
vec2 screen02;
float apron = 1.0; // google "futanari inflation rule 34"
vec4 stroke_data = texelFetch(u_stroke_data, ivec2(a_stroke_id, 0), 0);
float radius = stroke_data.w * 255.0;
vec2 a = a_ab.xy;
vec2 b = a_ab.zw;
vec2 line_dir = normalize(b - a);
vec2 up_dir = vec2(line_dir.y, -line_dir.x);
vec2 pixel = vec2(2.0) / u_res * apron;
float rscale = apron / u_scale.x;
int vertex_index = gl_VertexID & 0x3;
int vertex_index = gl_VertexID % 6;
vec2 outwards;
vec2 origin;
if (vertex_index == 0) {
// "top left" aka "p1"
screen02 += up_dir * pixel - line_dir * pixel;
v_texcoord = a_pos.xy + up_dir * rscale - line_dir * rscale;
} else if (vertex_index == 1) {
origin = a;
outwards = up_dir - line_dir;
} else if (vertex_index == 1 || vertex_index == 5) {
// "top right" aka "p2"
screen02 += up_dir * pixel + line_dir * pixel;
v_texcoord = a_pos.xy + up_dir * rscale + line_dir * rscale;
} else if (vertex_index == 2) {
origin = b;
outwards = up_dir + line_dir;
} else if (vertex_index == 2 || vertex_index == 4) {
// "bottom left" aka "p3"
screen02 += -up_dir * pixel - line_dir * pixel;
v_texcoord = a_pos.xy - up_dir * rscale - line_dir * rscale;
origin = a;
outwards = -up_dir - line_dir;
} else {
// "bottom right" aka "p4"
screen02 += -up_dir * pixel + line_dir * pixel;
v_texcoord = a_pos.xy - up_dir * rscale + line_dir * rscale;
origin = b;
outwards = -up_dir + line_dir;
}
vec2 pos = origin + normalize(outwards) * radius;
screen02 = (pos.xy * u_scale + u_translation) / u_res + outwards * pixel;
v_texcoord = pos.xy + outwards * rscale;
screen02.y = 2.0 - screen02.y;
v_line = a_line;
v_color = a_color;
v_thickness = a_pos.z;
v_line = vec4(a, b);
v_thickness = radius;
v_color = stroke_data.xyz;
gl_Position = vec4(screen02 - 1.0, (float(a_stroke_id) / float(u_stroke_count)) * 2.0 - 1.0, 1);
}
@ -182,8 +193,8 @@ const sdf_fs_src = `#version 300 es @@ -182,8 +193,8 @@ const sdf_fs_src = `#version 300 es
float h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0);
float dist = length(pa - ba * h) - v_thickness / 2.0;
float fade = length(fwidth(v_texcoord));
float alpha = 1.0 - smoothstep(0.0, fade, dist);
float fade = 0.5 * length(fwidth(v_texcoord));
float alpha = 1.0 - smoothstep(-fade, fade, dist);
FragColor = vec4(v_color * alpha, alpha);
} else {
@ -292,17 +303,15 @@ function init_webgl(state, context) { @@ -292,17 +303,15 @@ function init_webgl(state, context) {
},
'main': {
'a_pos': gl.getAttribLocation(context.programs['sdf'].main, 'a_pos'),
'a_line': gl.getAttribLocation(context.programs['sdf'].main, 'a_line'),
'a_color': gl.getAttribLocation(context.programs['sdf'].main, 'a_color'),
'a_ab': gl.getAttribLocation(context.programs['sdf'].main, 'a_ab'),
'a_stroke_id': gl.getAttribLocation(context.programs['sdf'].main, 'a_stroke_id'),
'u_res': gl.getUniformLocation(context.programs['sdf'].main, 'u_res'),
'u_scale': gl.getUniformLocation(context.programs['sdf'].main, 'u_scale'),
'u_translation': gl.getUniformLocation(context.programs['sdf'].main, 'u_translation'),
'u_debug_mode': gl.getUniformLocation(context.programs['sdf'].main, 'u_debug_mode'),
'u_tile_size': gl.getUniformLocation(context.programs['sdf'].main, 'u_tile_size'),
'u_stroke_count': gl.getUniformLocation(context.programs['sdf'].main, 'u_stroke_count'),
'u_stroke_data': gl.getUniformLocation(context.programs['sdf'].main, 'u_stroke_data'),
}
};
@ -321,6 +330,15 @@ function init_webgl(state, context) { @@ -321,6 +330,15 @@ function init_webgl(state, context) {
'b_packed_dynamic_index': gl.createBuffer(),
};
context.textures = {
'stroke_data': gl.createTexture(),
};
gl.bindTexture(gl.TEXTURE_2D, context.textures['stroke_data']);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 2, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
const resize_canvas = (entries) => {
// https://www.khronos.org/webgl/wiki/HandlingHighDPI
const entry = entries[0];

Loading…
Cancel
Save