Public
Edited
Sep 10, 2023
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
/**
* Render with the REGL and WebGL,
* and the vert and frag codes.
*/
{
function wrapCanvasBlock(canvasPairs) {
const insides = canvasPairs.map(
({ title, canvas }) => htl.html`
<div style="margin: 5px">
<h2>${title}</h2>
${canvas}
</div>
`
);

return htl.html`
<div style="display: flex; flex-flow: wrap">
${insides}
</div>
`;
}

function wrapCodesBlock(codePairs) {
const insides = codePairs.map(
({ title, code }) => htl.html`
<div style="margin: 5px; minwidth: ${width}px">
<h2>${title}</h2>
<pre class='prettyprint linenums lang-c'>
<code>
${"\n" + code.trim()}
</code>
</pre>
</div>
`
);

return htl.html`
<div style="display: flex; flex-flow: wrap">
${insides}
</div>
`;
}

const canvasPairs = [
{
title: "Canvas with REGL",
canvas: reglDrawer.canvas
},
{
title: "Canvas with WebGL",
canvas: webglDrawer.canvas
}
];

const codePairs = [
{
title: "Code of vert",
code: shaderSource.vert
},
{
title: "Code of frag",
code: shaderSource.frag
}
];

document.getElementById("embedding").innerHTML = "";

document
.getElementById("embedding")
.appendChild(wrapCanvasBlock(canvasPairs));

document.getElementById("embedding").appendChild(wrapCodesBlock(codePairs));

PR.prettyPrint();
}
Insert cell
Insert cell
reglDrawer = {
const canvas = DOM.canvas(width, height),
pixelRatio = 1.0,
extensions = ["oes_standard_derivatives"],
regl = wrapREGL({
canvas,
pixelRatio,
extensions
});

Object.assign(canvas, { width, height });

return { canvas, regl };
}
Insert cell
/**
* Draw the triangle using regl
*/
{
const { regl } = reglDrawer,
drawTriangle = regl({
vert: shaderSource.vert,
frag: shaderSource.frag,
attributes,
uniforms: {
radian: regl.prop("radian")
},
count: 3
});

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

drawTriangle({ radian: radian });

return drawTriangle;
}
Insert cell
Insert cell
Insert cell
{
const { gl } = webglDrawer;

/** ========================= SHADERS =========================
* Create the SHADER_PROGRAM and compile it with the vertex and fragment
*/
function createShaderProgram() {
const SHADER_PROGRAM = gl.createProgram(),
{ vert, frag } = shaderSource;

// Compile
const shader_vertex = bindShader(vert, gl.VERTEX_SHADER, gl),
shader_fragment = bindShader(frag, gl.FRAGMENT_SHADER, gl);

// Attach
gl.attachShader(SHADER_PROGRAM, shader_vertex);
gl.attachShader(SHADER_PROGRAM, shader_fragment);

// Link
gl.linkProgram(SHADER_PROGRAM);

// Enable color and position attributes
// Enable _radian uniform
const _color = gl.getAttribLocation(SHADER_PROGRAM, "color"),
_position = gl.getAttribLocation(SHADER_PROGRAM, "position"),
_radian = gl.getUniformLocation(SHADER_PROGRAM, "radian");

gl.enableVertexAttribArray(_color);
gl.enableVertexAttribArray(_position);
gl.enableVertexAttribArray(_radian);

gl.useProgram(SHADER_PROGRAM);

return { SHADER_PROGRAM, _position, _color, _radian };
}

/** ========================= Create buffers for vertex and fragment =========================
* Create buffers for vertex and fragment
*/
function createTriangleFace(triangle_vertex, triangle_fragment) {
// Vertex:
const TRIANGLE_VERTEX = gl.createBuffer();

gl.bindBuffer(gl.ARRAY_BUFFER, TRIANGLE_VERTEX);

gl.bufferData(
gl.ARRAY_BUFFER,
new Float32Array(triangle_vertex),
gl.STATIC_DRAW
);

// Fragment:
const TRIANGLE_FRAGMENT = gl.createBuffer();

gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, TRIANGLE_FRAGMENT);

gl.bufferData(
gl.ELEMENT_ARRAY_BUFFER,
new Uint16Array(triangle_fragment),
gl.STATIC_DRAW
);

return { TRIANGLE_VERTEX, TRIANGLE_FRAGMENT };
}

/** ========================= Create buffers for vertex and fragment =========================
* Bind parameters for vertex and fragment
*/
function bindParameters(triangle_vertex, triangle_fragment) {
// Create SHADER_PROGRAM
const { SHADER_PROGRAM, _position, _color, _radian } =
createShaderProgram();

const { TRIANGLE_VERTEX, TRIANGLE_FRAGMENT } = createTriangleFace(
triangle_vertex,
triangle_fragment
);

// The 4 refers 4 bytes per number
gl.vertexAttribPointer(_position, 2, gl.FLOAT, false, 4 * (2 + 3), 0);
gl.vertexAttribPointer(_color, 3, gl.FLOAT, false, 4 * (2 + 3), 4 * 2);

return { _radian, TRIANGLE_VERTEX, TRIANGLE_FRAGMENT };
}

// Binds with triangle
const triangle_vertex = [],
triangle_fragment = [0, 1, 2];

triangle_fragment.map((i) => {
attributes.position[i].map((d) => triangle_vertex.push(d));
attributes.color[i].map((d) => triangle_vertex.push(d));
});

const { _radian, TRIANGLE_VERTEX, TRIANGLE_FRAGMENT } = bindParameters(
triangle_vertex,
triangle_fragment
);

{
// Clear the scene
gl.clearColor(0, 0.1, 0.26, 1);
gl.clear(gl.COLOR_BUFFER_BIT);

// The radian is a float
gl.uniform1f(_radian, radian);

// Real draw
gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_SHORT, 0);
gl.flush();
}

return triangle_vertex;
}
Insert cell
/**
* Create the shader,
* and bind the source with the shader,
* type is one of the following:
* type = gl.VERTEX_SHADER
* type = gl.FRAGMENT_SHADER
* gl is the WebGLRenderingContext
*/
bindShader = (source, type, gl) => {
const shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
return shader;
}
Insert cell
Insert cell
Insert cell
shaderSource = {
const vert = `
precision mediump float;

attribute vec2 position;
attribute vec3 color;

uniform float radian;

varying vec3 v_color;
varying vec2 v_pos;

vec2 rotate(vec2 src, float radian) {
vec2 dst = vec2(
src.x * cos(radian) - src.y * sin(radian),
src.x * sin(radian) + src.y * cos(radian)
);
return dst;
}

void main () {
v_color = color;

v_pos = rotate(position, radian);

${clipToggle ? "v_pos.x = min(0.1, v_pos.x)" : "// Placeholder of clip"};

gl_Position = vec4(v_pos, 0.0, 1.0);
}
`,
frag = `
precision mediump float;

varying vec3 v_color;
varying vec2 v_pos;

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);
}

void main () {

gl_FragColor = vec4(v_color, 1.0);

float d = dist(v_pos);

// Draw a ring around the (0, 0)
if (d > 0.02 - 0.01 && d < 0.02) gl_FragColor = vec4(1.0);

// Draw a ring around the (0, 0)
if (d > 0.3 - 0.005 && d < 0.3) gl_FragColor = vec4(1.0);

}
`;

return { vert, frag };
}
Insert cell
width = 400
Insert cell
height = 400
Insert cell
wrapREGL = require("regl")
Insert cell
d3 = require("d3")
Insert cell
PR = require("https://cdn.jsdelivr.net/gh/google/code-prettify@master/loader/run_prettify.js")
Insert cell
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