分别绘制每个像素 WebGL

Draw each pixel separately WebGL

首先说一下我的目标。我正在创建另一个像素艺术在线编辑器,并决定只使用 WebGL(根本没有 Canvas2D)。我真蠢,因为我对这项技术一无所知,但我正在努力!所以......问题:如何改变唯一一个像素的颜色?我一直在与我的另一个 "misunderstand" 作斗争,并用粒子系统找到了这个答案:

我重写了它以使其看起来接近我的情况:

https://jsfiddle.net/kurz/rt2n7hmb/1/

如您所见,在canvas上绘图时,有10个像素点颜色相同。 这里主要绘制方法:

function mouseMoveEvent(e) {
    /*... detect x and y...*/
    gl.bindBuffer(gl.ARRAY_BUFFER, particleBuffer);
    var data = new Float32Array(2);
    data[0] = x;
    data[1] = y;
    gl.uniform4f(
        gl.getUniformLocation(shaderProgram, "color"),
        Math.random(),
        Math.random(),
        Math.random(),
        1.0
    );
    gl.bufferSubData(gl.ARRAY_BUFFER, particleId * particleSize * sizeOfFloat, data);
    particleId = (particleId + 1) % vertexBufferSize;
    gl.clear(gl.COLOR_BUFFER_BIT);
    gl.drawArrays(gl.POINTS, 0, vertexBufferSize);
}

那么如何将此示例更改为使用独特颜色绘制的像素?

有些人可能会说:"use canvas2d!"。 - 不!我认为未来不是 canvas2d。 "So use library!"。 - 不,再来一次!对于 "simple" 之类的绘制方块之类的东西,我不想包含大型库。

谢谢!

您问题的直接答案是 gl.uniform4f 是一个全局变量。所以你实际上是在这样做:

var color = randomColor(); // uniform4f call
for each point:
    drawPoint(p.x, p.y,color);

你需要改成这样:

for each point:
    var color = gl.uniform4f(...);
    drawPoint(p.x, p.y, color);

但是,我想指出,使用粒子系统来做像素编辑器可能不是可行的方法。想象一下,如果用户在同一区域反复移动会发生什么情况,您将拥有大量冗余数据。其次,您如何(有效地)支持擦除操作?还是填充?

最后,我认为您想继续使用纹理。纹理基本上是一组数据的奇特名称,但对其格式和可包含的内容有限制。然而,GPU 可以非常非常快地访问它们。所以你想要做的是绘制一个与屏幕大小相同的四边形,并通过纹理为其提供单独的像素数据,以告诉它要绘制什么。然后在用户做事的时候直接操作纹理数据重绘

包含如何在 webgl 中实现这一点真的太长了,所以我建议遵循网络上的一些教程。 webgl 最好的 atm 是 webgl fundamentals 系列。我建议从那里开始。

关于您发布的代码,您需要了解的是它正在将一个变量传递给片段着色器,它没有进行任何绘制。片段着色器正在绘制。

OpenGL 是一种在现代图形卡上操纵渲染过程的不同阶段的工具。它不会尝试涵盖将像素传送到屏幕缓冲区的用例。 (glDrawPixels 已弃用,在 ES 2.0 或 WebGL 中不可用)

但是,您可以通过多种方式在您的应用程序中使用它。

我建议 these two articles 了解先决条件,但您应该知道它适用于 openGL 3.2 和 C++,而不是 WebGL 和 Javascript。所以你可以忽略诸如上下文创建、纹理加载方式之类的事情,你不必创建 VertexArrays。

WebGL解决方案1:

  • 创建一个空纹理。
  • 每一帧,在显示此纹理的屏幕上绘制一个四边形。
  • 点击鼠标,调用glTexSubImage2D修改纹理内的1个像素。

WebGL解决方案2:

  • 更改gl_PointSize(顶点着色器第 8 行)
  • 只抽1分
  • 不要清除屏幕(javascript 第 45 行)
  • 保留 webGL 屏幕缓冲区(javascript 第 86 或 89 行)

See modified source

此解决方案未修改 1 个精确像素,我认为解决方案 1 是更好的方法

为什么要使用 Canvas2D:

认为Canvas2D不如WebGL是错误的,一个是螺丝刀,一个是锤子。一种适合用螺丝固定,另一种适合用钉子固定。

当您想要操作 3d 渲染管道时使用 WebGL,当您想要操作光栅图像时使用 Canvas2D。

TL;DR:

如果您使用 Canvas2D,您今天就可以开始制作您想要的具有良好性能的应用程序。如果您想使用 WebGL,您应该努力了解渲染管道的各个阶段。