首页 > 解决方案 > 无法使用 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();
        }
    });

但是这样做的结果是在同一平面上绘制了一个圆圈。该位置的第三个输入似乎没有任何效果。我尝试交换位置中的yz值,并获得了正弦曲线。所以z的值被正确分配。我注意到的另一件事是,如果z的值为零,则不会绘制任何内容。z的任何其他值似乎都不会产生任何影响。

标签: webglregl

解决方案


添加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();
    }
});

希望这可以帮助!


推荐阅读