From 9892ebf33add54fa23051ec027a99ebfa266e695 Mon Sep 17 00:00:00 2001 From: "A.Olokhtonov" Date: Sun, 14 Jul 2024 14:32:53 +0300 Subject: [PATCH] SSAO experiments (unfinihsed) --- client/aux.js | 8 ++++++++ client/bvh.js | 4 +++- client/index.js | 1 + client/webgl_draw.js | 31 ++++++++++++++++++------------- client/webgl_shaders.js | 29 +++++++++++++++++++++-------- 5 files changed, 51 insertions(+), 22 deletions(-) diff --git a/client/aux.js b/client/aux.js index 8b1f784..3368084 100644 --- a/client/aux.js +++ b/client/aux.js @@ -265,3 +265,11 @@ function grid_snap_step(state) { return 32 / zoom_next; } } + +function canvas_css_rect(context) { + const el = context.canvas; + return { + 'width': el.clientWidth, + 'height': el.clientHeight + }; +} diff --git a/client/bvh.js b/client/bvh.js index 04bee14..e492eda 100644 --- a/client/bvh.js +++ b/client/bvh.js @@ -220,8 +220,10 @@ function bvh_clip(state, context) { tv_clear(context.clipped_indices); + const canvas = canvas_css_rect(context); + const screen_topleft = screen_to_canvas(state, {'x': 0, 'y': 0}); - const screen_bottomright = screen_to_canvas(state, {'x': context.canvas.width, 'y': context.canvas.height}); + const screen_bottomright = screen_to_canvas(state, {'x': canvas.width, 'y': canvas.height}); const screen_topright = { 'x': screen_bottomright.x, 'y': screen_topleft.y }; const screen_bottomleft = { 'x': screen_topleft.x, 'y': screen_bottomright.y }; diff --git a/client/index.js b/client/index.js index 68c0181..25ff6c9 100644 --- a/client/index.js +++ b/client/index.js @@ -31,6 +31,7 @@ const config = { pattern_fadeout_min: 0.3, pattern_fadeout_max: 0.75, min_pressure: 50, + ssao: 0.5, benchmark: { zoom_level: -75, offset: { x: 425, y: -1195 }, diff --git a/client/webgl_draw.js b/client/webgl_draw.js index b7dafd4..bef3a28 100644 --- a/client/webgl_draw.js +++ b/client/webgl_draw.js @@ -86,6 +86,8 @@ async function draw(state, context, animate, ts) { const width = window.innerWidth; const height = window.innerHeight; + const canvas = canvas_css_rect(context); + bvh_clip(state, context); const segment_count = await geometry_write_instances(state, context); @@ -100,10 +102,10 @@ async function draw(state, context, animate, ts) { } // Only clear once we have the data, this might not always be on the same frame? - gl.viewport(0, 0, context.canvas.width, context.canvas.height); + gl.viewport(0, 0, canvas.width, canvas.height); gl.clearColor(context.bgcolor.r, context.bgcolor.g, context.bgcolor.b, 1); gl.clearDepth(0.0); - gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT); // Draw the background pattern if (state.background_pattern === 'dots') { @@ -116,7 +118,7 @@ async function draw(state, context, animate, ts) { gl.vertexAttribPointer(locations['a_center'], 2, gl.FLOAT, false, 2 * 4, 0); gl.vertexAttribDivisor(locations['a_center'], 1); - gl.uniform2f(locations['u_res'], context.canvas.width, context.canvas.height); + gl.uniform2f(locations['u_res'], canvas.width, 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); @@ -124,11 +126,12 @@ async function draw(state, context, animate, ts) { const zoom_log2 = Math.log2(zoom); const zoom_previous = Math.pow(2, Math.floor(zoom_log2)); const zoom_next = Math.pow(2, Math.ceil(zoom_log2)); + const grid_step = 32; // Previous level { const one_dot = new Float32Array(geometry_gen_quad(0, 0, 1 / zoom_previous)); - const dot_instances = new Float32Array(geometry_gen_fullscreen_grid(state, context, 32 / zoom_previous, 32 / zoom_previous)); + const dot_instances = new Float32Array(geometry_gen_fullscreen_grid(state, context, grid_step / zoom_previous, grid_step / zoom_previous)); const t = Math.min(1.0, 1.0 - (zoom / zoom_previous) / 2.0); gl.uniform1f(locations['u_fadeout'], t); @@ -141,7 +144,7 @@ async function draw(state, context, animate, ts) { // Next level if (zoom_previous != zoom_next) { - const dot_instances = new Float32Array(geometry_gen_fullscreen_grid(state, context, 32 / zoom_next, 32 / zoom_next)); + const dot_instances = new Float32Array(geometry_gen_fullscreen_grid(state, context, grid_step / zoom_next, grid_step / zoom_next)); const t = Math.min(1.0, 1.0 - (zoom_next / zoom) / 2.0); gl.uniform1f(locations['u_fadeout'], t); @@ -155,7 +158,7 @@ async function draw(state, context, animate, ts) { const zoom = state.canvas.zoom; let zoom_log8 = Math.log(zoom) / Math.log(8); - //if (zoom_log2 === Math.floor(zoom_log2)) { + //if (zoom_log2 === Math.floor(zoom_log2)) // zoom_log2 -= 0.001; //} @@ -175,14 +178,14 @@ async function draw(state, context, animate, ts) { gl.vertexAttribPointer(locations['a_data'], 2, gl.FLOAT, false, 2 * 4, 0); gl.vertexAttribDivisor(locations['a_data'], 1); - gl.uniform2f(locations['u_res'], context.canvas.width, context.canvas.height); + gl.uniform2f(locations['u_res'], canvas.width, 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.uniform1f(locations['u_fadeout'], 1.0); // Previous level (major lines) { - const grid_instances = new Float32Array(geometry_gen_fullscreen_grid_1d(state, context, 32 / zoom_previous, 32 / zoom_previous)); + const grid_instances = new Float32Array(geometry_gen_fullscreen_grid_1d(state, context, grid_step / zoom_previous, grid_step / zoom_previous)); let t = (zoom / zoom_previous - 1) / -7 + 1; t = 0.25; @@ -196,7 +199,7 @@ async function draw(state, context, animate, ts) { // Next level (minor lines) { - const grid_instances = new Float32Array(geometry_gen_fullscreen_grid_1d(state, context, 32 / zoom_next, 32 / zoom_next)); + const grid_instances = new Float32Array(geometry_gen_fullscreen_grid_1d(state, context, grid_step / zoom_next, grid_step / zoom_next)); let t = (zoom_next / zoom - 1) / 7; t = Math.min(0.1, -t + 1); // slight fade-in @@ -226,7 +229,7 @@ async function draw(state, context, animate, ts) { gl.vertexAttribPointer(locations['a_pos'], 2, gl.FLOAT, false, 2 * 4, 0); for (const entry of context.images) { - gl.uniform2f(locations['u_res'], context.canvas.width, context.canvas.height); + gl.uniform2f(locations['u_res'], canvas.width, 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_texture'], 0); // Only 1 active texture for each drawcall @@ -266,7 +269,7 @@ async function draw(state, context, animate, ts) { gl.bindTexture(gl.TEXTURE_2D, context.textures['stroke_data']); upload_square_rgba16ui_texture(gl, context.stroke_data, config.stroke_texture_size); - gl.uniform2f(locations['u_res'], context.canvas.width, context.canvas.height); + gl.uniform2f(locations['u_res'], canvas.width, 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'], state.events.length); @@ -274,6 +277,7 @@ async function draw(state, context, animate, ts) { gl.uniform1i(locations['u_stroke_data'], 0); gl.uniform1i(locations['u_stroke_texture_size'], config.stroke_texture_size); gl.uniform1f(locations['u_fixed_pixel_width'], 0); + gl.uniform2f(locations['u_ssao'], config.ssao, config.ssao); gl.enableVertexAttribArray(locations['a_a']); gl.enableVertexAttribArray(locations['a_b']); @@ -326,7 +330,7 @@ async function draw(state, context, animate, ts) { gl.bindTexture(gl.TEXTURE_2D, context.textures['dynamic_stroke_data']); upload_square_rgba16ui_texture(gl, context.dynamic_stroke_data, config.dynamic_stroke_texture_size); - gl.uniform2f(locations['u_res'], context.canvas.width, context.canvas.height); + gl.uniform2f(locations['u_res'], canvas.width, 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); @@ -335,6 +339,7 @@ async function draw(state, context, animate, ts) { gl.uniform1i(locations['u_stroke_data'], 0); gl.uniform1i(locations['u_stroke_texture_size'], config.dynamic_stroke_texture_size); gl.uniform1f(locations['u_fixed_pixel_width'], 0); + gl.uniform2f(locations['u_ssao'], config.ssao, config.ssao); gl.enableVertexAttribArray(locations['a_a']); gl.enableVertexAttribArray(locations['a_b']); @@ -374,7 +379,7 @@ async function draw(state, context, animate, ts) { gl.bindTexture(gl.TEXTURE_2D, context.textures['ui']); upload_square_rgba16ui_texture(gl, handles.stroke_data, config.ui_texture_size); - gl.uniform2f(locations['u_res'], context.canvas.width, context.canvas.height); + gl.uniform2f(locations['u_res'], canvas.width, 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'], 8); diff --git a/client/webgl_shaders.js b/client/webgl_shaders.js index 1ea5bef..14535a0 100644 --- a/client/webgl_shaders.js +++ b/client/webgl_shaders.js @@ -12,6 +12,7 @@ const sdf_vs_src = `#version 300 es uniform int u_stroke_texture_size; uniform highp usampler2D u_stroke_data; uniform float u_fixed_pixel_width; + uniform vec2 u_ssao; out vec4 v_line; out vec2 v_texcoord; @@ -62,8 +63,9 @@ const sdf_vs_src = `#version 300 es } vec2 pos = origin + normalize(outwards) * radius * 2.0 * max(a_pressure.x, a_pressure.y); // doubling is to account for max possible pressure - screen02 = (pos.xy * u_scale + u_translation) / u_res * 2.0 + outwards * pixel * apron; - v_texcoord = pos.xy + outwards * rscale; + screen02 = (pos.xy * u_scale + u_translation) / u_res * u_ssao * 2.0 + outwards * pixel * apron; + v_texcoord = pos.xy; + // v_texcoord = pos.xy + outwards * rscale; screen02.y = 2.0 - screen02.y; v_line = vec4(a_a, a_b); v_thickness = radius * a_pressure; // pressure 0.5 is the "neutral" pressure @@ -97,10 +99,20 @@ const sdf_fs_src = `#version 300 es float h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0); float dist = length(v_texcoord - (a + ba * h)) - mix(v_thickness.x, v_thickness.y, h); +/* float fade = 0.5 * length(fwidth(v_texcoord)); float alpha = 1.0 - smoothstep(-fade, fade, dist); +*/ - FragColor = vec4(v_color * alpha, alpha); + float alpha = 1.0 - step(0.0, dist); + alpha = clamp(0.0, 1.0, alpha); + + if (alpha == 0.0) { + discard; + } else { + alpha = 0.5; + FragColor = vec4(v_color * alpha, alpha); + } } else { FragColor = vec4(0.2, 0.0, 0.0, 0.2); } @@ -273,7 +285,7 @@ function init_webgl(state, context) { context.gl = context.canvas.getContext('webgl2', { 'preserveDrawingBuffer': true, 'desynchronized': true, - 'antialias': false, + 'antialias': true, }); const gl = context.gl; @@ -282,7 +294,7 @@ function init_webgl(state, context) { gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); gl.enable(gl.DEPTH_TEST); - gl.depthFunc(gl.GEQUAL); + gl.depthFunc(gl.NOTEQUAL); context.gpu_timer_ext = gl.getExtension('EXT_disjoint_timer_query_webgl2'); if (context.gpu_timer_ext === null) { @@ -334,7 +346,8 @@ function init_webgl(state, context) { 'u_stroke_count': gl.getUniformLocation(context.programs['sdf'].main, 'u_stroke_count'), 'u_stroke_data': gl.getUniformLocation(context.programs['sdf'].main, 'u_stroke_data'), 'u_stroke_texture_size': gl.getUniformLocation(context.programs['sdf'].main, 'u_stroke_texture_size'), - 'u_fixed_pixel_width': gl.getUniformLocation(context.programs['sdf'].main, 'u_fixed_pixel_width'), + 'u_fixed_pixel_width': gl.getUniformLocation(context.programs['sdf'].main, 'u_fixed_pixel_width'), + 'u_ssao': gl.getUniformLocation(context.programs['sdf'].main, 'u_ssao'), } }; @@ -411,8 +424,8 @@ function init_webgl(state, context) { height = Math.round(entry.contentBoxSize[0].blockSize * devicePixelRatio); } - context.canvas.width = width; - context.canvas.height = height; + context.canvas.width = width * config.ssao; + context.canvas.height = height * config.ssao; schedule_draw(state, context); }