Public
Edited
Aug 25, 2023
8 forks
89 stars
Line-Sweep Ambient Occlusion with WebGPUSpring TrainingLine Sweep Ambient Occlusion in JavaScriptLine Sweep Terrain LightingSpeed Climbing World Record ProgressionWebGPU ShaderHydraulic Erosion SimulationHow Does Mapbox Raster Colorization Work?Arc Length of a Quadratic Bézier SplineMagnetic PendulumTracing Lamb Wave Modes in the Complex PlaneMissing Fundamental IllusionSliced Optimal TransportLine Integral ConvolutionShanks TransformationUeda's AttractorCubic basis vs. Hermite interpolationBicubic Texture Interpolation using Linear FilteringFactor-of-Two Lanczos Image ResamplingRendering the Aperiodic Monotileeqn [WIP]SDF Points with reglKnocking Down the Gates with our Friend JacobiFast Generalized Winding Numbers in 2DHTML+CSS Periodic Three-Body OrbitsClifford and de Jong AttractorsStrange Attractors on the GPU, Part 1: ImplementationStrange Attractors on the GPU, Part 2: Fun!Lawson's Klein BottleInteractive Multi-scale Turing PatternsComputing π with the Bailey-Borwein-Plouffe FormulaThe Double Pendulum MapMalkus WaterwheelRegister Allocation and the k-Coloring ProblemMultiscale Turing Patterns in WebGLSelecting the Right Opacity for 2D Point CloudsKuramoto-Sivashinsky Equation in 2DAdaptive Contouring in Fragment ShadersComplex function plotterGPU Voronoi Diagrams using the Jump Flooding AlgorithmBaker's MapHello, g9Dispersion in Water Surface WavesFake Transparency for 3D SurfacesUniformly Distributed Points on a SphereGPU BoidsGrouping Points with Principal Component AnalysisDomain Coloring for Complex FunctionsDrawing indexed mesh data as screen-space normals without duplicating dataFinding Roots in the Complex PlanePeriodic Planar Three-Body Orbits2D (Non-physical) N-body Gravity with Poisson's EquationHalf-Precision Floating-Point, VisualizedIntegers in Single-Precision Floating-PointDomain Coloring with Adaptive Contouring
Instanced WebGL Circles
Double Compound Pendulums3D Reaction-DiffusionMathematical Easter Egg ColoringToiletpaperfullerenes and Charmin Nanotubes
Insert cell
Insert cell
Insert cell
viewof regl = reglCanvas(this, {
width,
height: Math.max(600, width * 0.6),
extensions: ["ANGLE_instanced_arrays"],
attributes: { antialias: false, depth: false }
})
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
loop = {
while (true) {
regl.poll();
regl.clear({ color: [0.05, 0.05, 0.05, 1] });
draw();
yield;
}
}
Insert cell
Insert cell
circleInstanceGeometry = Array.from(Array(numCircleDivisions + 1).keys()).map(i => {
var theta = Math.PI * 2 * i / numCircleDivisions;
return [Math.cos(theta), Math.sin(theta)];
});
Insert cell
Insert cell
instanceTheta = Array.from(Array(numCircleInstances).keys()).map(i =>
i / numCircleInstances * 2 * Math.PI
);
Insert cell
Insert cell
draw = regl({
vert: `
precision highp float;
attribute float theta;
attribute vec2 circlePoint;
varying vec3 vColor;
uniform vec2 aspectRatio;
uniform float time;
const float PI = 3.1415926535;
void main () {
// Use lots of sines and cosines to place the circles
vec2 circleCenter = vec2(cos(theta), sin(theta))
* (0.6 + 0.2 * cos(theta * 6.0 + cos(theta * 8.0 + time)));

// Modulate the circle sizes around the circle and in time
float circleSize = 0.2 + 0.12 * cos(theta * 9.0 - time * 2.0);

vec2 xy = circleCenter + circlePoint * circleSize;

// Define some pretty colors
float th = 8.0 * theta + time * 2.0;
vColor = 0.6 + 0.4 * vec3(
cos(th),
cos(th - PI / 3.0),
cos(th - PI * 2.0 / 3.0)
);

gl_Position = vec4(xy / aspectRatio, 0, 1);
}`,
frag: `
precision highp float;
varying vec3 vColor;
uniform float alpha;
void main () {
gl_FragColor = vec4(vColor, alpha);
}`,
attributes: {
// This attribute defines what we draw; we fundamentally draw circle vertices
circlePoint: circleInstanceGeometry,
// This attribute allows us to compute where we draw each circle. the divisor
// means we step through one value *per circle*.
theta: {buffer: instanceTheta, divisor: 1},
},
uniforms: {
// Scale so that it fits in the view whether it's portrait or landscape:
aspectRatio: ctx => ctx.framebufferWidth > ctx.framebufferHeight ?
[ctx.framebufferWidth / ctx.framebufferHeight, 1] :
[1, ctx.framebufferHeight / ctx.framebufferWidth],
time: regl.context('time'),
// Decrease opacity when there are more circles
alpha: Math.max(0, Math.min(1, 0.15 * 2000 / numCircleInstances)),
},
blend: {
// Additive blending
enable: true,
func: {srcRGB: 'src alpha', srcAlpha: 1, dstRGB: 1, dstAlpha: 1},
equation: {rgb: 'add', alpha: 'add'}
},
// GL_LINES are in general *pretty bad*, but they're good for some things
primitive: 'line strip',
depth: {enable: false},
count: numCircleDivisions + 1,
instances: numCircleInstances,
})
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