drawParticles = regl({
vert: `
precision mediump float;
attribute vec4 freq, phase;
attribute vec3 color;
uniform float time; // current time
uniform mat4 view, projection; // view (camera position), projection (camera's perspective)
varying vec3 fragColor;
void main() {
// it oscillates between -8.0 and 8.0 for each of the x, y, and z coordinates
vec3 position = 8.0 * cos(freq.xyz * time + phase.xyz);
gl_PointSize = 4.2 * (1.0 + cos(freq.w * time + phase.w));
// 3D to 2D position using camera
gl_Position = projection * view * vec4(position, 1);
fragColor = color;
}`,
frag: `
precision lowp float; // this is sufficient for this color calulation
varying vec3 fragColor;
void main() {
// gl_PointCoord is built-in variable, coordinates of the current fragment within point
// xy components range from 0.0 to 1.0, where (0.5, 0.5) is the center of the point
// length(gl_PointCoord.xy - 0.5) calculates the distance from the current fragment to the center of the point.
if (length(gl_PointCoord.xy - 0.5) > 0.5) {
discard; // discard fragment, making the point circular rather than square
}
gl_FragColor = vec4(fragColor, 1);
}`,
attributes: {
freq: {
buffer: pointBuffer,
stride: VERT_SIZE,
offset: 0
},
phase: {
buffer: pointBuffer,
stride: VERT_SIZE,
offset: 16
},
color: {
buffer: pointBuffer,
stride: VERT_SIZE,
offset: 32
}
},
uniforms: {
view: ({ tick }) => {
const t = 0.004 * tick;
return mat4.lookAt(
[],
[30 * Math.cos(t), 2.5, 30 * Math.sin(t)],
[0, 0, 0],
[0, 1, 0]
);
},
projection: ({ viewportWidth, viewportHeight }) =>
mat4.perspective(
[],
Math.PI / 4,
viewportWidth / viewportHeight,
0.01,
1000
),
time: ({ tick }) => tick * 0.001
},
count: NUM_POINTS,
primitive: "points"
})