diff --git a/static/brush-renderer.js b/static/brush-renderer.js index e1500a3..462012e 100644 --- a/static/brush-renderer.js +++ b/static/brush-renderer.js @@ -12,29 +12,71 @@ const linesVertexShader = `#version 300 es layout (location = 2) in vec4 a_color; layout (location = 3) in vec2 a_properties; // (thickness, hardness) + out vec2 vf_localPosition; + out vec4 vf_line; + out vec4 vf_color; + out vec2 vf_properties; + void main() { float thickness = a_properties.x; - float hardness = a_properties.y; - vec2 xAxis = a_line.zw - a_line.xy; - vec2 direction = normalize(xAxis); + vec2 from = a_line.xy; + vec2 to = a_line.zw; + vec2 direction = normalize(to - from); + if (to == from) + direction = vec2(1.0, 0.0); + + // Extrude forward for caps + from -= direction * (thickness / 2.0); + to += direction * (thickness / 2.0); + + vec2 xAxis = to - from; vec2 yAxis = vec2(-direction.y, direction.x) * thickness; - vec2 localPosition = a_line.xy + xAxis * a_position.x + yAxis * a_position.y; + vec2 localPosition = from + xAxis * a_position.x + yAxis * a_position.y; vec4 screenPosition = vec4(localPosition + u_translation, 0.0, 1.0); vec4 scenePosition = screenPosition * u_projection; gl_Position = scenePosition; + vf_localPosition = localPosition; + vf_line = a_line; + vf_color = a_color; + vf_properties = a_properties; } `; const linesFragmentShader = `#version 300 es precision highp float; + in vec2 vf_localPosition; + in vec4 vf_line; + in vec4 vf_color; + in vec2 vf_properties; + out vec4 f_color; + // https://iquilezles.org/articles/distfunctions2d/ + + float segmentSdf(vec2 uv, vec2 a, vec2 b) { + vec2 uva = uv - a; + vec2 ba = b - a; + float h = clamp(dot(uva, ba) / dot(ba, ba), 0.0, 1.0); + return length(uva - ba * h); + } + void main() { - f_color = vec4(vec3(0.0), 1.0); + float thickness = vf_properties.x; + float hardness = vf_properties.y; + float halfSoftness = (1.0 - hardness) / 2.0; + + vec2 uv = vf_localPosition; + float alpha = -(segmentSdf(uv, vf_line.xy, vf_line.zw) - thickness) / thickness; + if (hardness > 0.999) + alpha = step(0.5, alpha); + else + alpha = smoothstep(0.5 - halfSoftness, 0.5001 + halfSoftness, alpha); + + f_color = vec4(vec3(1.0), alpha) * vf_color; } `; @@ -148,6 +190,8 @@ export class BrushRenderer { ); gl.uniform2f(this.linesProgram.u_translation, this.#translation.x, this.#translation.y); + gl.enable(gl.BLEND); + let instances = this.linesInstanceData; instances[0] = x1; instances[1] = y1;