Public
Edited
Nov 6, 2023
2 forks
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
image.reglDrawer.canvas
Insert cell
<div style='max-height: ${height+20}px; overflow-y: scroll; display: flex; flex-flow: wrap'>
<div id='vertDivForREGL' style='padding: 5px'>
[Vert div for regl...]
</div>
<div id='fragDivForREGL' style='padding: 5px'>
[Frag div for regl...]
</div>
</div>
Insert cell
/**
* Draw the triangle using regl
*/
{
redrawBtnClick;

const { regl, blend } = image.reglDrawer,
{ texture, framebuffer, buffer, width, height } = image;

function drawImageByTriangle() {
const { vert, frag } = shaderSourceTriangle,
position = [
[-4, -1],
[1, -1],
[1, 4]
],
draw = regl({
vert,
frag,
attributes: { position },
uniforms: {
uSampler: texture,
alpha1: 1.0
},
blend,
count: position.length,
depth: { enable: false }
});

regl.clear({ color: [0, 0, 1, 0.1] });
draw();
statsMonitor.update();
}

function drawImageByGrid(secs = 0) {
const { vert, frag } = shaderSourceGrid,
draw = regl({
vert,
frag,
attributes: {
position: new Int8Array([-1, 0, 1, 0, -1, 1, 1, 1]),
bo: { buffer: buffer, divisor: 1 }
},
uniforms: {
uSampler: texture,
alpha: 0.9,
absorbRate: 0.2,
secs
},
blend,
primitive: "points",
count: 1,
// primitive: "triangle strip",
// count: 4,
depth: { enable: false },
instances: () => width * height
});

regl.clear({ color: [0, 0, 1, 0.1] });
draw();
statsMonitor.update();
}

function draw(sec) {
if (drawingMethod === "Triangle") {
drawImageByTriangle();
}

if (drawingMethod === "Grid") {
drawImageByGrid(sec);
}
}

draw();

var sec;
for (;;) {
sec = parseFloat((performance.now() / 1000) % 10000);
draw(sec);
yield sec;
}
}
Insert cell
shaderSourceGrid = {
const vert = await glsl`
${customGlsl.precision}

#pragma glslify: snoise = require('glsl-noise/simplex/3d')

uniform sampler2D uSampler;
uniform float absorbRate;
uniform float secs;

attribute vec2 position;
attribute vec4 bo; // Buffer object

varying vec2 v_position;
varying vec4 v_color4;
varying vec4 v_bo;

void main () {
v_position = position;
v_bo = bo;

${
useSimplex
? "v_color4 = texture2D(uSampler, vec2(bo) + absorbRate * 0.4 * vec2(snoise(vec3(bo.xy, secs)), snoise(vec3(bo.xy, secs * 2.0))));"
: "v_color4 = texture2D(uSampler, vec2(bo) + absorbRate * 0.4 * vec2(snoise(vec3(bo.zw, secs)), snoise(vec3(bo.zw, secs * 2.0))));"
}

// Translate and scale from (0, 1) to (-1, 1) linearly
v_bo -= 0.5;
v_bo.y *= -2.0;
v_bo.x *= 2.0;

gl_Position = vec4(vec2(v_bo), 0.0, 1.0);

gl_PointSize = 2.0;
}
`,
frag = await glsl`
${customGlsl.useStandardDerivatives}
${customGlsl.precision}

varying vec4 v_color4;
uniform float alpha;

void main () {
gl_FragColor = vec4(vec3(v_color4), alpha);
}
`;

return { vert, frag };
}
Insert cell
shaderSourceTriangle = {
const vert = `
${customGlsl.precision}

attribute vec2 position;

varying vec2 v_position;

void main () {
v_position = position * 0.5 + 0.5;
v_position.y = (1.0 - v_position.y);

gl_Position = vec4(position, 0.0, 1.0);
}
`,
frag = await glsl`
${customGlsl.useStandardDerivatives}
${customGlsl.precision}

uniform sampler2D uSampler;

varying vec2 v_position;
uniform float alpha1;

void main () {
vec4 tex = texture2D(uSampler, v_position);
gl_FragColor = vec4(vec3(tex), alpha1);
}
`;

return { vert, frag };
}
Insert cell
{
if (drawingMethod === "Triangle") {
updateDivForREGL(shaderSourceTriangle);
}

if (drawingMethod === "Grid") {
updateDivForREGL(shaderSourceGrid);
}
}
Insert cell
Insert cell
Insert cell
maxSize = 600
Insert cell
image.reglDrawer
Insert cell
image = {
changeImageBtnClick;

const image = await randomImage();

return image;
}
Insert cell
randomImage = () => {
const src =
"https://source.unsplash.com/random" +
`?sport,city,flower&seed=${performance.now()}`;

return new Promise((resolve) => {
const image = new Image();
image.src = src;

// Change the cross-origin permission into anonymous (from same origin or restrict),
// it allows this page to use it.
image.crossOrigin = "anonymous";

image.onload = () => {
// Limit the size of the image, no more than the maxSize,
// and the aspect ratio is kept.
{
const r = image.width / image.height;

if (r > 1.0) {
image.width = maxSize;
image.height = image.width / r;
} else {
image.height = maxSize;
image.width = image.height * r;
}
}

// Make reglDrawer for the image
{
const reglDrawer = mkReglDrawer(image.width, image.height),
texture = reglDrawer.regl.texture(image),
framebuffer = reglDrawer.regl.framebuffer({ color: texture }),
buffer = reglDrawer.regl.buffer(
createTextureArray(image.width, image.height, 4)
);

Object.assign(image, { texture, reglDrawer, framebuffer, buffer });
}

// Resolve the promise
resolve(image);
};
});
}
Insert cell
/**
* Create w x h x stride sized texture array, stride usually equals to 4.
*/
createTextureArray = (w, h, stride) => {
stride = stride || 2;

const rnd = d3.randomUniform(),
n = w * h * stride,
out = new Float32Array(n);

for (var i = 0; i < n; i += stride) {
out[i] = (i % (w * stride)) / (w * stride);
out[i + 1] = (i - (i % (w * stride)) + 0.5) / n;
out[i + 2] = rnd();
out[i + 3] = rnd();
}

return out;
}
Insert cell
Insert cell
width = 600
Insert cell
height = 600
Insert cell
reglDrawer = mkReglDrawer(width, height)
Insert cell
/**
* Make canvas, regl and blend for WebGL
*/
mkReglDrawer = (width, height) => {
const canvas = DOM.canvas(width || maxSize, height || maxSize),
pixelRatio = 2.0,
extensions = [
"oes_standard_derivatives",
"oes_texture_float",
"angle_instanced_arrays"
],
regl = wrapREGL({
canvas,
pixelRatio,
extensions
}),
blend = {
enable: true,
func: {
srcRGB: "src alpha",
srcAlpha: 1,
dstRGB: "one minus src alpha",
dstAlpha: 1
},
equation: {
rgb: "add",
alpha: "add"
}
};

return { canvas, regl, blend };
}
Insert cell
Insert cell
PR = require("https://cdn.jsdelivr.net/gh/google/code-prettify@master/loader/run_prettify.js")
Insert cell
statsMonitor = {
const stats = new Stats(),
{ dom } = stats;
dom.style.position = "relative";

return stats;
}
Insert cell
Stats = require("https://cdn.jsdelivr.net/npm/stats-js@1.0.1/build/stats.min.js")
Insert cell
wrapREGL = require("regl")
Insert cell
import { glsl, glslify } from "@listenzcc/glslify"
Insert cell
d3 = require("d3")
Insert cell
customGlsl = ({
useStandardDerivatives: `
#extension GL_OES_standard_derivatives : enable
`,
constants: `
#define PI 3.141592653589793238
#define HALF_PI 1.57079632679
#define HALF_PI_INV 0.15915494309
#define LOG_2 0.69314718056
#define C_ONE (vec2(1.0, 0.0))
#define C_I (vec2(0.0, 1.0))
#define TO_RADIANS 0.01745329251
`,
precision: `
precision lowp float;
`,
dist: `
float dist(vec2 d) {
return sqrt(pow(d.x, 2.0) + pow(d.y, 2.0));
}

float dist(vec2 a, vec2 b) {
vec2 d = a - b;
return dist(d);
}
`,
hsv2rgb: `
vec3 hsv2rgb(vec3 c) {
vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
}
`,
wireframe: `
float wireframe (vec3 parameter, float width, float feather) {
float w1 = width - feather * 0.5;
vec3 d = fwidth(parameter);
vec3 looped = 0.5 - abs(mod(parameter, 1.0) - 0.5);
vec3 a3 = smoothstep(d * w1, d * (w1 + feather), looped);
return min(min(a3.x, a3.y), a3.z);
}
`
})
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more