当前位置: 代码迷 >> JavaScript >> 分别绘制每个像素WebGL
  详细解决方案

分别绘制每个像素WebGL

热度:116   发布时间:2023-06-07 11:47:42.0

首先,让我谈谈我的目标。 我正在创建另一个像素艺术在线编辑器,并决定只使用WebGL(根本没有Canvas2D)。 我很愚蠢,因为我对这项技术一无所知,但我正在努力! 那么......问题:如何改变唯一一个像素的颜色? 我一直在努力解决另一个“误解”,并用粒子系统找到了这个答案:

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

如您所见,在画布上绘制时,有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);
}

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

有些人可能会说:“使用canvas2d!”。 - 不! 我认为未来不是canvas2d。 “所以使用库!”。 - 不,再次! 对于那种“简单”的东西,比如绘制正方形,我不想要包含大型库。

谢谢!

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

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

但是,有一些方法可以在您的应用程序中使用它。

我推荐两篇来理解先决条件,尽管你应该知道它适用于openGL 3.2和C ++,而不是WebGL和Javascript。 因此,您可以忽略诸如上下文创建,加载纹理的方式以及您不必创建VertexArrays等内容。

WebGL解决方案1:

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

WebGL解决方案2:

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

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

为什么你应该使用Canvas2D:

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

如果要操作3d渲染管道,请使用WebGL,在想要操作光栅图像时使用Canvas2D。

TL; DR:

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

你的问题的直接答案是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是系列。 我建议从那里开始。

  相关解决方案