Public
Edited
Jan 23, 2024
2 forks
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
frame = () => {
return regl.frame(({ tick }) => {
drawField({ sun: mkSun() }, () => {
regl.draw();
let triangle = triangles[tick % triangles.length];
updateField({ triangle });
statsMonitor.update();
});
});
}
Insert cell
noiseGen.noise3D(1, 2, performance.now())
Insert cell
sun = {
button;
const rnd = d3.randomUniform();
return [rnd(), rnd(), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
}
Insert cell
mkSun()
Insert cell
mkSun = () => {
let t = (performance.now() / 1000) * 0.1,
x = noiseGen.noise2D(10, t) * 0.5 + 0.5,
y = noiseGen.noise2D(20, t) * 0.5 + 0.5;
return [x, y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
}
Insert cell
triangles = {
button;
const rnd = d3.randomUniform();
return Array(5)
.fill(0)
.map((d) => [rnd(), rnd(), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
}
Insert cell
updateField = regl({
frag: `
${customGlsl.precision}
${myREGL}
varying vec2 uv;
uniform mat4 triangle;
uniform sampler2D prevState;

void main() {
gl_FragColor = vec4(uv, 1.0, 1.0);
float d = dist(uv, triangle[0].xy);
float e = texture2D(prevState, uv).x;
gl_FragColor = vec4(vec3(min(e, d)), 1.0);
}`,
depth: false,
uniforms: {
triangle: regl.prop("triangle")
},
framebuffer: ({ tick }) => state[(tick + 1) % 2]
})
Insert cell
drawField = regl({
vert: `
${customGlsl.precision}
attribute vec2 position;
varying vec2 uv;
void main() {
// Convert (-1, 1) to (0, 1)
uv = 0.5 * position + 0.5;
gl_Position = vec4(position, 0.0, 1.0);
}`,

frag: `
${customGlsl.precision}
${myREGL}
varying vec2 uv;
uniform sampler2D prevState;
uniform mat4 sun;
void main() {
vec4 sdf = texture2D(prevState, uv);
gl_FragColor = vec4(sdf.xyz, 1.0);

vec3 d;

// Draw the ray trace shadow
${
drawShadow
? `
d = dist(prevState, uv, sun[0].xy);
gl_FragColor = vec4(vec3(d.x), 1.0);
`
: ``
}

// Draw the colorful ray trace shadow
${
drawColorfulShadow
? `
d = dist(prevState, uv, sun[0].xy);
gl_FragColor = vec4(vec3(d), 1.0);
`
: ``
}


// Draw the sun in a small red circle
if (dist(uv, sun[0].xy) < 0.01) {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}

}`,
attributes: {
position: [-4, -4, 4, -4, 0, 4]
},
count: 3,
depth: false,
uniforms: {
prevState: ({ tick }) => state[tick % 2],
tick: ({ tick }) => tick,
sun: regl.prop("sun")
}
})
Insert cell
myREGL = `
#define MAXSDF 5.0

/**
* Compute norm2 between src and dst.
**/
float norm2(vec2 src, vec2 dst) {
return dot(src-dst, src-dst);
}

/**
* Compute distance between src and dst.
**/
float dist(vec2 src, vec2 dst) {
return sqrt(norm2(src, dst));
}

/**
* Compute the dist value among the signed distance field
**/
vec3 dist(sampler2D sdf, vec2 src, vec2 dst) {
float minsdf = MAXSDF;
float d0 = dist(src, dst), d, remain;
for (int i=0; i<1000; ++i) {
d = texture2D(sdf, src).x;

// Record the min sdf value during the trace
minsdf = min(minsdf, d);

// It is blocked, thus it will not reach dst
if (d <= 0.03) {
return vec3(sqrt(abs(d)*10.0), 0.3, 0.3);
}

// It sees the dst directly, without being blocked at all
remain = dist(src, dst);
if (remain < d) {
return vec3(1.0-d0, 0.5, 0.0);
}

src = mix(src, dst, d/remain);
}

return vec3(minsdf, 0.0, 0.0);
}
`
Insert cell
paintBackground = () => {
regl.clear({ color: [0, 0.1, 0.26, 1] });
}
Insert cell
state = {
button;
const { width, height } = canvas,
data = Array(width * height * 4)
.fill(0)
.map(() => initValue);

return Array(2)
.fill(0)
.map((d) => {
let texture = regl.texture({
type: "float",
width,
height,
data
});
return regl.framebuffer({ color: texture, depthStencil: false });
});
}
Insert cell
Insert cell
blend = ({
enable: true,
func: {
srcRGB: "src alpha",
srcAlpha: 1,
dstRGB: "one minus src alpha",
dstAlpha: 1
},
equation: {
rgb: "add",
alpha: "add"
}
})
Insert cell
customGlsl = ({
useStandardDerivatives: `
#extension GL_OES_standard_derivatives : enable
`,
precision: `
precision lowp float;
`
})
Insert cell
Insert cell
noiseGen.noise3D(1, 2, performance.now())
Insert cell
noiseGen = new simplexNoise(performance.now())
Insert cell
simplexNoise = require("simplex-noise@2.4.0")
Insert cell
d3 = require("d3")
Insert cell
regl = (await import("https://cdn.skypack.dev/regl@2")).default({
canvas,
pixelRatio: 1.0,
extensions: ["oes_standard_derivatives", "oes_texture_float"],
attributes: { antialias: true }
})
Insert cell
wrapREGL = require("regl")
Insert cell
import { glsl, glslify } from "@listenzcc/glslify"
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
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