Public
Edited
Nov 18, 2023
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
reglDrawer.canvas
Insert cell
shaderDrawField = {
const vert = `
${customGlsl.precision}
attribute vec2 position;
varying vec2 v_position;
void main () {
v_position = position*0.5+0.5;
gl_Position = vec4(position, 0.0, 1.0);
}
`,
frag = await glsl`
${customGlsl.useStandardDerivatives}
${customGlsl.precision}

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

varying vec2 v_position;
uniform float secs, spatialZoom, speedUp;

void main () {
float v = 0.5 + 0.5 * snoise(vec3(v_position * spatialZoom, secs * speedUp));
gl_FragColor = vec4(v, 0.0, 0.0, 1.0);
}
`;

return { vert, frag };
}
Insert cell
shaderDrawScatter = {
const vert = `
${customGlsl.precision}
attribute vec2 position;
varying vec2 v_position;
void main () {
v_position = position * 0.5 + 0.5;
gl_Position = vec4(position, 0.0, 1.0);
}
`,
frag = await glsl`
${customGlsl.useStandardDerivatives}
${customGlsl.precision}
#pragma glslify: snoise = require('glsl-noise/simplex/3d')
#pragma glslify: random = require('glsl-random')
varying vec2 v_position;
uniform float densityLic;
uniform sampler2D src, field;

void main () {
float v = random(gl_FragCoord.xy * 100.0);
float k = 0.0;
if (v < densityLic) {
k = v; //0.1;
}

if (false && v < densityLic) {
gl_FragColor = vec4(0.1, 0.0, 0.0, 1.0);
} else {
vec4 f = texture2D(field, v_position);
float dx = dFdx(f.x) * 0.5;
float dy = dFdy(f.x) * 0.5;
float df = texture2D(src, v_position + vec2(dx, dy)).x;
float speed = sqrt(dx*dx +dy*dy) * 100.0;

gl_FragColor = vec4(df * 0.8 * (0.8 + speed) + k, speed, 0.0, 1.0);
}
}
`;

return { vert, frag };
}
Insert cell
shaderDrawScreen = {
const vert = `
${customGlsl.precision}
attribute vec2 position;
varying vec2 v_position;
void main () {
v_position = position * 0.5 + 0.5;
gl_Position = vec4(position, 0.0, 1.0);
}
`,
frag = await glsl`
${customGlsl.useStandardDerivatives}
${customGlsl.precision}
#pragma glslify: colormap = require('glsl-colormap/${colorMapName}')
varying vec2 v_position;
uniform sampler2D field;

void main () {
vec4 v1 = texture2D(field, v_position);
gl_FragColor = colormap(v1.x);
}
`;

return { vert, frag };
}
Insert cell
shaderDrawScreenOverlap = {
const vert = `
${customGlsl.precision}
attribute vec2 position;
varying vec2 v_position;
void main () {
v_position = position * 0.5 + 0.5;
gl_Position = vec4(position, 0.0, 1.0);
}
`,
frag = await glsl`
${customGlsl.useStandardDerivatives}
${customGlsl.precision}
#pragma glslify: colormap = require('glsl-colormap/${colorMapNameLic}')
varying vec2 v_position;
uniform sampler2D scatter;

void main () {
vec4 v2 = texture2D(scatter, v_position);
vec4 c = colormap(v2.x);

c.w = v2.y;

gl_FragColor = c;
}
`;

return { vert, frag };
}
Insert cell
/**
* Draw the triangle using regl
*/
{
const { regl, blend } = reglDrawer;

const position = [
[-1, -1],
[3, -1],
[-1, 3]
];

function drawField(secs = 0) {
const { vert, frag } = shaderDrawField,
draw = regl({
vert,
frag,
attributes: { position },
count: position.length,
depth: { enable: false },
blend,
uniforms: {
secs,
spatialZoom,
speedUp
}
});
draw();
}

function drawScatter(secs = 0, src, field) {
const { vert, frag } = shaderDrawScatter,
draw = regl({
vert,
frag,
attributes: { position },
count: position.length,
depth: { enable: false },
blend,
uniforms: {
densityLic,
src,
field
}
});
draw();
}

function drawScreen(secs = 0, field) {
const { vert, frag } = shaderDrawScreen,
draw = regl({
vert,
frag,
attributes: { position },
count: position.length,
depth: { enable: false },
blend,
uniforms: {
field
}
});
draw();
}

function drawScreenOverlap(secs = 0, scatter) {
const { vert, frag } = shaderDrawScreenOverlap,
draw = regl({
vert,
frag,
attributes: { position },
count: position.length,
depth: { enable: false },
blend,
uniforms: {
scatter
}
});
draw();
}

var secs = 0,
secsNext = 0,
bellFlag,
even = false,
srcFbo,
dstFbo;

function draw(secs) {
bellFlag = secs > secsNext;
if (bellFlag) secsNext = secs + 100;
even = !even;

fieldFbo.fbo.use(() => {
regl.clear({ color: [0, 0, 0, 1] });
drawField(secs);
});

if (bellFlag) {
scatterFbo.fbo.use(() => {
regl.clear({ color: [0, 0, 0, 0] });
});
scatterFbo2.fbo.use(() => {
regl.clear({ color: [0, 0, 0, 0] });
});
}

if (even) {
srcFbo = scatterFbo.fbo;
dstFbo = scatterFbo2.fbo;
} else {
srcFbo = scatterFbo2.fbo;
dstFbo = scatterFbo.fbo;
}

dstFbo.use(() => {
drawScatter(secs, srcFbo, fieldFbo.fbo);
});

srcFbo.use(() => {
regl.clear({ color: [0, 0, 0, 0] });
});

regl.clear({ color: [1, 0, 1, 0.1] });
if (toggleField) drawScreen(secs, fieldFbo.fbo);
else regl.clear({ color: [0, 0, 0, 1] });
if (toggleOverlay) drawScreenOverlap(secs, dstFbo);

statsMonitor.update();
}

draw(secs);

for (;;) {
secs = parseFloat((performance.now() / 1000) % 10000);
draw(secs);
yield secs;
}
}
Insert cell
scatterFbo = {
const { regl } = reglDrawer,
color = regl.texture({
type: "float",
width,
height
});
return {
color,
fbo: regl.framebuffer({ color })
};
}
Insert cell
scatterFbo2 = {
const { regl } = reglDrawer,
color = regl.texture({
type: "float",
width,
height
});
return {
color,
fbo: regl.framebuffer({ color })
};
}
Insert cell
fieldFbo = {
const { regl } = reglDrawer,
color = regl.texture({
type: "float",
width,
height
});
return {
color,
fbo: regl.framebuffer({ color })
};
}
Insert cell
textureBuffer = reglDrawer.regl.buffer({ data: texture })
Insert cell
texture = createTexture(width, height, 4)
Insert cell
Insert cell
Insert cell
/**
* Create w x h x stride sized texture array
*/
createTexture = (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] = 1.0; // rnd() > 0.9 ? 1.0 : 0.0;
}

return out;
}
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, height),
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
colorMapNames = [
"jet",
"hsv",
"hot",
"cool",
"spring",
"summer",
"autumn",
"winter",
"bone",
"copper",
"greys",
"yignbu",
"greens",
"yiorrd",
"bluered",
"rdbu",
"picnic",
"rainbow",
"portland",
"blackbody",
"earth",
"electric",
"alpha",
"viridis",
"inferno",
"magma",
"plasma",
"warm",
"rainbow-soft",
"bathymetry",
"cdom",
"chlorophyll",
"density",
"freesurface-blue",
"freesurface-red",
"oxygen",
"par",
"phase",
"salinity",
"temperature",
"turbidity",
"velocity-blue",
"velocity-green",
"cubehelix"
]
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