I am starting with regl and I am trying to make a small demo for plotting points in all three axis. I have used this link to start with.
In the example above the points were initialized as
const points = d3.range(numPoints).map(i => ({
x: //Code,
y: //Code,
color: [1, 0, 0],
}));
I modified it to the one below to get a spiral that goes into infinity
const points = d3.range(numPoints).map(i => ({
x: 200+radius*Math.cos(i*Math.PI/180),
y: 200+radius*Math.sin(i*Math.PI/180),
z: i,
color: [1, 0, 0],
}));
I modified the vertex shader to account for the additional axis. The following is the code which draws the points
const drawPoints = regl({
frag:`
precision highp float;
varying vec3 fragColor;
void main()
{
gl_FragColor = vec4(fragColor, 1);
}
`,
vert:`
attribute vec3 position;
attribute vec3 color;
varying vec3 fragColor;
uniform float pointWidth;
uniform float stageWidth;
uniform float stageHeight;
uniform float stageDepth;
vec3 normalizeCoords(vec3 position)
{
float x = position[0];
float y = position[1];
float z = position[2];
return vec3(2.0 * ((x / stageWidth) - 0.5),-(2.0 * ((y / stageHeight) - 0.5)),1.0 * ((z / stageDepth) - 0.0));
}
void main()
{
gl_PointSize = pointWidth;
fragColor = color;
gl_Position = vec4(normalizeCoords(position), 1.0);
}
`,
attributes:
{
position: points.map(d => [d.x, d.y, d.z]),
color: points.map(d => d.color),
},
uniforms:
{
pointWidth: regl.prop('pointWidth'),
stageWidth: regl.prop('stageWidth'),
stageHeight: regl.prop('stageHeight'),
stageDepth: regl.prop('stageDepth'),
},
count: points.length,
depth:
{
enable: true,
mask: true,
func: 'less',
range: [0, 1]
},
primitive: 'points',
});
frameLoop = regl.frame(() => {
// clear the buffer
regl.clear({
// background color (black)
color: [0, 0, 0, 1],
depth: 1,
});
drawPoints({
pointWidth,
stageWidth: width,
stageHeight: height,
});
if (frameLoop) {
frameLoop.cancel();
}
});
But the result of this is a circle which is plotted on the same plane. The third input to the position doesn't seem to have any effect. I tried interchanging the y and z values in the position and I obtained a sine curve. So the value of z is getting assigned properly. Another thing I noted is that if the value of z is zero, nothing is plotted. Any other value of z doesn't seem to produce any effect.
The reason the added z
coordinate has no effect is because you currently have no concept of "depth projection" in your rendering pipeline.
Typically, you'll need to add a "projection matrix" to your rendering pipeline which will account for the z
coordinate in vertices, when mapping those 3D vertex positions to your 2D screen.
You should be able to add this projection fairly simply by using something like the canvas-orbit-camera
module. Once you'd added that module to your project, consider making the following adjustments to your code (see comments tagged with [Add]):
// Your init code ..
// [Add] Register camera middleware with canvas
const camera = require('canvas-orbit-camera')(canvas)
// Your init code ..
const drawPoints = regl({
frag:`
precision highp float;
varying vec3 fragColor;
void main()
{
gl_FragColor = vec4(fragColor, 1);
}
`,
vert:`
attribute vec3 position;
attribute vec3 color;
varying vec3 fragColor;
uniform float pointWidth;
uniform float stageWidth;
uniform float stageHeight;
uniform float stageDepth;
uniform mat4 proj; // [Add] Projection matrix uniform
vec3 normalizeCoords(vec3 position)
{
float x = position[0];
float y = position[1];
float z = position[2];
return vec3(2.0 * ((x / stageWidth) - 0.5),-(2.0 * ((y / stageHeight) - 0.5)),1.0 * ((z / stageDepth) - 0.0));
}
void main()
{
gl_PointSize = pointWidth;
fragColor = color;
gl_Position = proj * vec4(normalizeCoords(position), 1.0); // [Add] Multiply vertex by projection matrix
}
`,
attributes:
{
position: points.map(d => [d.x, d.y, d.z]),
color: points.map(d => d.color),
},
uniforms:
{
pointWidth: regl.prop('pointWidth'),
stageWidth: regl.prop('stageWidth'),
stageHeight: regl.prop('stageHeight'),
stageDepth: regl.prop('stageDepth'),
// [Add] Projection matrix calculation
proj: ({viewportWidth, viewportHeight}) =>
mat4.perspective([],
Math.PI / 2,
viewportWidth / viewportHeight,
0.01,
1000),
},
count: points.length,
depth:
{
enable: true,
mask: true,
func: 'less',
range: [0, 1]
},
primitive: 'points',
});
frameLoop = regl.frame(() => {
// clear the buffer
regl.clear({
// background color (black)
color: [0, 0, 0, 1],
depth: 1,
});
// [Add] Camera re computation
camera.tick()
drawPoints({
pointWidth,
stageWidth: width,
stageHeight: height,
});
if (frameLoop) {
frameLoop.cancel();
}
});
Hope this helps!