Public
Edited
Apr 18, 2023
Insert cell
Insert cell
{
const renderer = new THREE.WebGLRenderer({antialias: true});
invalidation.then(() => renderer.dispose());
renderer.setSize(width, height);
renderer.setPixelRatio(devicePixelRatio);
document.addEventListener('mousemove', (event) => {
event.preventDefault();
const mouseX = (event.offsetX) * 2 - 1,
mouseY = (event.offsetY) * 2 + 1,
object = scene.children[ 0 ];
object.material.uniforms.u_mouse.value.x = mouseX;
object.material.uniforms.u_mouse.value.y = mouseY;
}, false);
while (true) {
const object = scene.children[ 0 ];
object.material.uniforms.u_resolution.value.x = width;
object.material.uniforms.u_resolution.value.y = height;
renderer.render(scene,camera);
yield renderer.domElement;

}
}
Insert cell
Insert cell
scene = {
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x000000);
scene.add(plane);
return scene;
}
Insert cell
Insert cell
camera = {
const aspect = width / height;
const near = 1;
const far = 1000;
const camera = new THREE.OrthographicCamera( width / - 2, width / 2, height / 2, height / - 2, near, far );
camera.position.z = 1;
return camera;
}
Insert cell
Insert cell
plane = {
const material = new THREE.ShaderMaterial( {

uniforms: {
u_resolution: new THREE.Uniform( new THREE.Vector2() ),
u_mouse: new THREE.Uniform( new THREE.Vector2() )
},
fragmentShader: fragmentShader,
transparent: true,

} );
const geometry = new THREE.PlaneGeometry(width,height);
return new THREE.Mesh(geometry, material);
}
Insert cell
Insert cell
Insert cell
fragmentShader = `precision mediump float;
precision mediump int;
#define PI 3.14159265359
#define TWO_PI 6.28318530718


uniform vec2 u_resolution;
uniform vec2 u_mouse;



void main(){
vec3 color = vec3(0.0);
float numCells = 5.0;
//normalizing current pixel
vec2 st = gl_FragCoord.xy/u_resolution.xy;
st.x *= u_resolution.x/u_resolution.y;

//lining up mouse coordinates with the normalized st coordinates
float y_norm = 2.-u_mouse.y/u_resolution.y;
vec2 mouse = vec2(u_mouse.x/u_resolution.x, y_norm);
mouse.x *= u_resolution.x/u_resolution.y;

//tile the cells - creating the grid
st *= numCells;
// indent every other line slightly
st.x += step(1., mod(st.y,2.0)) * 0.5;
vec2 i_st = floor(st);
vec2 f_st = fract(st);
//center of tiles currently normalized to 0->1, so the center point is (0.5,0.5)
vec2 cellCenter = vec2(0.5);

//convert center back to coordinates relative to mouse/st
vec2 center = (cellCenter + i_st) / vec2(numCells);
vec2 normal = normalize(mouse-center);

//rotation matrix based on unit vector direction between mouse and center of the tile
mat2 rotation = mat2(normal.x, normal.y,
-normal.y, normal.x);

//translate, rotate, then translate back
f_st -= 0.5;
f_st = f_st * rotation;
f_st += 0.5;

//normalize cells from -1,1 for distance field(triangle)
f_st = f_st * 2.0 - 1.;

//draw triangles (from the source links above)
int N = 3;
float d = 0.0;
// Angle and radius from the current pixel
float a = atan(f_st.x,f_st.y)+PI;
float r = TWO_PI/float(N);
// Shaping function that modulate the distance
d = cos(floor(.5+a/r)*r-a)*length(f_st);
color = vec3(1.0-smoothstep(.4,.41,d));
gl_FragColor = vec4(color,0.7);
}`;
Insert cell
height = 500
Insert cell
width = 700
Insert cell
THREE = require("three@0.99.0/build/three.min.js")
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