webgl - 无法使用 regl 在 Z 方向上绘制点
问题描述
我从 regl 开始,我正在尝试制作一个小演示,用于在所有三个轴上绘制点。我已经使用此链接开始。
在上面的例子中,点被初始化为
const points = d3.range(numPoints).map(i => ({
x: //Code,
y: //Code,
color: [1, 0, 0],
}));
我将它修改为下面的,以获得一个进入无穷大的螺旋
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],
}));
我修改了顶点着色器以考虑附加轴。以下是绘制点的代码
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();
}
});
但是这样做的结果是在同一平面上绘制了一个圆圈。该位置的第三个输入似乎没有任何效果。我尝试交换位置中的y和z值,并获得了正弦曲线。所以z的值被正确分配。我注意到的另一件事是,如果z的值为零,则不会绘制任何内容。z的任何其他值似乎都不会产生任何影响。
解决方案
添加z
坐标无效的原因是因为您目前在渲染管道中没有“深度投影”的概念。
z
通常,在将这些 3D 顶点位置映射到 2D 屏幕时,您需要将“投影矩阵”添加到渲染管道中,以考虑顶点坐标。
您应该能够通过使用类似canvas-orbit-camera
模块的东西相当简单地添加这个投影。将该模块添加到项目后,请考虑对代码进行以下调整(请参阅标有 [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();
}
});
希望这可以帮助!
推荐阅读
- javascript - axios 在我的字符串中间添加 52
- excel - 复制具有匹配工作表名称的数据
- python - 仅当有任何新可用时才下载 sonarqube 包的 Python 脚本
- spring - 为两个不同的入口点创建 bean
- gitlab - 检索 Jenkins 文件和 Git 存储库
- sql-server - 如何在 ASP.NET Core 中使用 Serilog 禁用自动日志记录
- javascript - 检查文本输入字段是否为空或包含数字
- python - 如何重新排列数据在多列之间拆分的熊猫表
- r - 如何在谷歌 colab R 上使用 gpu?
- reactjs - 反应:备忘录不起作用 - OnClick 按钮导致重新渲染