Published
Edited
Aug 4, 2020
1 fork
4 stars
Insert cell
Insert cell
Insert cell
Insert cell
function draw(t) {
const view = camera.view();
drawGrid({ view });

const bPoints = [];
for (let points of curvePoints) {
drawCurve({
view,
count: points.length,
point: points,
color: [0.5, 0.5, 0.5, 0.8]
});
drawPoint({
view,
count: points.length,
point: points,
pointSize: 5.0
});
const [lastPoint] = drawBezier(points, n - 1, view, t);
bPoints.push(lastPoint);
}

const surface = [];
const num = 20;
const step = 1 / num;
for (let u = 0; u < 1; u += step) {
for (let v = 0; v < 1; v += step) {
const c = bezier_surface(curvePoints, [u, v]);
surface.push(c);
}
}

for (let i = 0; i < num; ++i) {
const color = [0.2, 0.2, 1, 0.8];
drawCurve({
view,
count: num,
point: surface.slice(i * num, i * num + num + 1),
color
});
drawCurve({
view,
count: num,
point: surface.filter((v, j) => j % num === i),
color
});
}

return bPoints;
}
Insert cell
function bezier_surface(controlPoints, [u, v]) {
const n = controlPoints.length;
const m = controlPoints[0].length;

let res = [];
for (let i = 0; i < n; ++i) {
const i_poly = bernstein_poly(i, n - 1, u);
for (let j = 0; j < m; ++j) {
const [x, y, z] = controlPoints[i][j];
const j_Poly = bernstein_poly(j, m - 1, v);
res.push([i_poly * j_Poly * x, i_poly * j_Poly * y, i_poly * j_Poly * z]);
}
}

return res.reduce(([x1, y1, z1], [x2, y2, z2]) => [
x1 + x2,
y1 + y2,
z1 + z2
]);
}
Insert cell
function bezier_curve(controlPoints, t) {
const n = controlPoints.length;

let res = [];
for (let i = 0; i < controlPoints.length; ++i) {
const [x, y, z] = controlPoints[i];
const b_poly = bernstein_poly(i, n - 1, t);
res.push([b_poly * x, b_poly * y, b_poly * z]);
}

return res.reduce(([x1, y1, z1], [x2, y2, z2]) => [
x1 + x2,
y1 + y2,
z1 + z2
]);
}
Insert cell
function drawBezier(old, n, view, t) {
const current = [];
for (let i = 0; i < n; ++i) {
current.push(lerp3D(old[i], old[i + 1], t / 100));
}

if (n === 1) {
drawPoint({
view,
count: n,
point: current,
highlight: true,
pointSize: 5.0
});
return current;
}

drawPoint({
view,
count: current.length,
point: current,
pointSize: 5.0
});
drawCurve({
view,
count: current.length,
point: current,
color: [0.5, 0.5, 0.5, 0.8]
});

return drawBezier(current, n - 1, view, t);
}
Insert cell
{
gl.regl.frame(({ tick }) => {
camera.tick();
const time = (tick / 2) % 100;
const lastBPoints = draw(time);

const path = [];
for (let t = 0; t < 1; t += 0.05) {
const c = bezier_curve(lastBPoints, t);
path.push(c);
}
});
}
Insert cell
gl = createGL();
Insert cell
function positions(points) {
const startPos = [];
for (let i = 0; i < points.length; ++i) {
for (let j = 0; j < points[i].length - 1; ++j) {
startPos.push(points[i][j]);
}
}

const endPos = [];
for (let i = 0; i < points.length; ++i) {
for (let j = 1; j < points[i].length; ++j) {
endPos.push(points[i][j]);
}
}

return [startPos, endPos];
}
Insert cell
curvePoints = {
const res = [];

for (let i = 0; i < n; ++i) {
const curve = [];
for (let j = 0; j < n; ++j) {
const p = [
-w + i * ((2 * w) / (n - 1)),
Math.floor(Math.random() * randh),
-d + j * ((2 * d) / (n - 1))
];
curve.push(p);
}
res.push(curve);
}

return res;
}
Insert cell
drawPoint = gl.regl({
vert: `
precision mediump float;

attribute vec3 point;
uniform mat4 proj;
uniform mat4 view;
uniform float pointSize;
void main () {
gl_PointSize = pointSize;
gl_Position = proj * view * vec4(point, 1.0);
}
`,
frag: `
precision mediump float;

uniform bool highlight;

void main () {
vec4 color;
if(highlight) {
color = vec4(1, 0, 0, 1);
} else {
color = vec4(0.4, 0.4, 0.4, 0.7);
}
gl_FragColor = color;
}
`,
attributes: {
point: gl.regl.prop('point')
},
uniforms: {
view: gl.regl.prop('view'),
proj: mat4.perspective([], Math.PI / 4, width / height, 0.001, 10000),
highlight: gl.regl.prop('highlight'),
pointSize: gl.regl.prop('pointSize') || 5.0
},
count: gl.regl.prop('count'),
primitive: 'points'
})
Insert cell
drawCurve = gl.regl({
vert: `
precision mediump float;
attribute vec3 point;
uniform mat4 proj;
uniform mat4 view;
void main () {
gl_Position = proj * view * vec4(point, 1.0);
}
`,
frag: `
precision mediump float;

uniform bool highlight;
uniform vec4 color;

void main () {
gl_FragColor = color;
}
`,
attributes: {
point: gl.regl.prop('point')
},
uniforms: {
view: gl.regl.prop('view'),
proj: mat4.perspective([], Math.PI / 4, width / height, 0.001, 10000),
highlight: gl.regl.prop('highlight'),
color: gl.regl.prop('color')
},
count: gl.regl.prop('count'),
primitive: 'line strip'
})
Insert cell
drawGrid = gl.regl({
vert: `
precision mediump float;
attribute vec3 point;
uniform mat4 proj;
uniform mat4 view;
void main () {
gl_Position = proj * view * vec4(point, 1.0);
}
`,
frag: `
precision mediump float;
void main () {
gl_FragColor = vec4(0, 0, 0, 0.5);
}
`,
attributes: {
point: groundPoints
},
uniforms: {
view: gl.regl.prop('view'),
proj: mat4.perspective([], Math.PI / 4, width / height, 0.001, 10000)
},
count: groundPoints.length,
primitive: 'lines'
})
Insert cell
function lerp3D([x1, y1, z1], [x2, y2, z2], t) {
const v = [x2 - x1, y2 - y1, z2 - z1];
const d = Math.hypot(...v);
return [x1 + t * v[0], y1 + t * v[1], z1 + t * v[2]];
}
Insert cell
groundPoints = [
[-w, h, -d],
[-w, h, d],
[w, h, -d],
[w, h, d],
[w, h, d],
[-w, h, d],
[w, h, -d],
[-w, h, -d]
]
Insert cell
camera = {
const camera = createCamera(gl.canvas);
camera.lookAt([0, 800, -900], [0, 0, 0], [0, 1, 0]);
return camera;
}
Insert cell
function createGL(opts) {
var canvas = DOM.canvas(width, height)
var regl = createREGL(Object.assign({ canvas: canvas }, opts || {}));
return { canvas, regl };
}
Insert cell
n = 5
Insert cell
d = 250
Insert cell
w = 250
Insert cell
h = -10
Insert cell
randh = 350
Insert cell
height = width
Insert cell
import { bernstein_poly } from '@timhau/bernstein-poylnomial'
Insert cell
createREGL = require('https://unpkg.com/regl@1.3.1/dist/regl.min.js')
Insert cell
createCamera = require("https://bundle.run/canvas-orbit-camera@1.0.2")
Insert cell
mat4 = require('https://bundle.run/gl-mat4@1.0.0')
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