Public
Edited
Dec 20, 2023
Fork of Regl
1 fork
1 star
Insert cell
Insert cell
Insert cell
canvas = DOM.canvas(width, 500)
Insert cell
// Continuously updates
regl.frame(() => {
camera(function () {
regl.clear({ color: [0, 0.1, 0.26, 1] });
drawBunny({ offset: [3, 0, 0], drawSphere: true, useR: true });
drawBunny({ offset: [-3, 0, 0], drawSphere: true, useR: false });
drawBunny({ offset: [0, 0, 0], drawSphere: false, useR: false });
});
})
Insert cell
camera = reglCamera(regl, {
element: regl._gl.canvas,
center: [0, 0, 0],
theta: (3.0 * Math.PI) / 4.0,
phi: Math.PI / 6.0,
distance: 20.0,
damping: 0,
noScroll: true,
renderOnDirty: true
})
Insert cell
drawBunny = regl({
frag: await glsl`
precision mediump float;
${reglTools}
#pragma glslify: colormap = require('glsl-colormap/${colorMapName}')
varying vec3 vnormal, vpolars;
uniform bool useR;
void main () {
if (useR) {
gl_FragColor = colormap(vpolars.y);
if (vpolars.y < 0.001) {
gl_FragColor = vec4(vec3(0.0), 1.0);
}
// if (vpolars.y > 0.5) {
// gl_FragColor = vec4(vpolars.y-0.5, 0.0, 0.0, 1.0);
// } else {
// gl_FragColor = vec4(0.0, 0.0, 0.5-vpolars.y, 1.0);
// }
} else {
gl_FragColor = vec4(hsl2rgb(vec3(vpolars.x, 1.0, (vpolars.z-0.5)*0.6+0.5)), 1.0);
}
}`,
vert: `
precision mediump float;
uniform mat4 projection, view;
uniform vec3 offset;
uniform bool drawSphere;
attribute vec3 spherePosition, shPosition, normal, polars;
varying vec3 vnormal, vpolars;
void main () {
vec3 position;

if (drawSphere) {
position = spherePosition;
} else {
position = shPosition;
}

vnormal = normal;
vpolars = polars;

gl_Position = projection * view * vec4(position+offset, 1.0);
}`,
attributes: {
shPosition: data.shPositions,
spherePosition: data.spherePositions,
normal: normals(data.cells, data.shPositions),
polars: data.polars
},
uniforms: {
offset: regl.prop("offset"),
drawSphere: regl.prop("drawSphere"),
useR: regl.prop("useR")
},
elements: data.cells
})
Insert cell
data = sphere // bunny
Insert cell
sphere = {
let shPositions = [],
spherePositions = [],
cells = [],
polars = [],
theta,
phi,
xyz,
n = 100,
m = 100,
nm = n * m,
a,
b,
c,
d;

for (let i = 0; i < n; ++i) {
for (let j = 0; j < m; ++j) {
phi = (i / (n - 1)) * Math.PI * 2;
theta = (j / (m - 1)) * Math.PI;

xyz = polar2xyz(theta, phi);
spherePositions.push([xyz.x, xyz.y, xyz.z]);

xyz = polar2sh(theta, phi);
shPositions.push([xyz.x, xyz.y, xyz.z]);

polars.push([phi / Math.PI / 2, xyz.r, theta / Math.PI]); // HSL
}
}

// Re-scale the sh function into 1 size
{
let k = d3.max(polars, (d) => Math.abs(d[1]));
shPositions.map((d) => {
for (let i = 0; i < 3; ++i) {
d[i] /= k;
}
});
}

let scale = d3
.scaleLinear()
.domain(d3.extent(polars, (d) => d[1]))
.range([0, 1]);
polars.map((d) => (d[1] = scale(d[1])));

for (let i = 0; i < n; ++i) {
for (let j = 0; j < m; ++j) {
a = i * m + j;
b = i * m + j + m;
c = a + 1;
d = b + 1;
cells.push([a, b, c].map((e) => e % nm));
cells.push([d, c, b].map((e) => e % nm));
}
}

return { shPositions, spherePositions, cells, polars };
}
Insert cell
polar2sh = (theta, phi) => {
let r, real, imag;

r = Math.cos(theta);

real = 5 * Math.cos(theta) ** 3 - 3 * Math.cos(theta);
imag = 0;

// real = 3 * Math.cos(theta) ** 2 - 1;
// imag = 0;

real = Math.sin(theta) ** 2 * Math.cos(theta) * Math.cos(2 * phi);
imag = Math.sin(theta) ** 2 * Math.cos(theta) * Math.sin(2 * phi);

r = real ** 2 - imag ** 2;

return Object.assign({ r }, polar2xyz(theta, phi, r));
}
Insert cell
polar2xyz = (theta, phi, r = 1) => {
let x, y, z;
z = r * Math.cos(theta);
x = r * Math.sin(theta) * Math.cos(phi);
y = r * Math.sin(theta) * Math.sin(phi);
return { x, y, z };
}
Insert cell
d3 = require("d3")
Insert cell
bunny = (await import("https://cdn.skypack.dev/bunny@1.0.1")).default
Insert cell
normals = (await import("https://cdn.skypack.dev/angle-normals@1.0.0")).default
Insert cell
regl = (await import("https://cdn.skypack.dev/regl@2")).default({canvas})
Insert cell
reglCamera = (await import("https://cdn.skypack.dev/regl-camera@2.1.1")).default
Insert cell
import { glsl, glslify } from "@listenzcc/glslify"
Insert cell
reglTools = `
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);
}

vec3 hsl2rgb( in vec3 c )
{
vec3 rgb = clamp( abs(mod(c.x*6.0+vec3(0.0,4.0,2.0),6.0)-3.0)-1.0, 0.0, 1.0 );

return c.z + c.y * (rgb-0.5)*(1.0-abs(2.0*c.z-1.0));
}
`
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