分别绘制每个像素 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 行)
此解决方案未修改 1 个精确像素,我认为解决方案 1 是更好的方法
为什么要使用 Canvas2D:
认为Canvas2D不如WebGL是错误的,一个是螺丝刀,一个是锤子。一种适合用螺丝固定,另一种适合用钉子固定。
当您想要操作 3d 渲染管道时使用 WebGL,当您想要操作光栅图像时使用 Canvas2D。
TL;DR:
如果您使用 Canvas2D,您今天就可以开始制作您想要的具有良好性能的应用程序。如果您想使用 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 行)
此解决方案未修改 1 个精确像素,我认为解决方案 1 是更好的方法
为什么要使用 Canvas2D:
认为Canvas2D不如WebGL是错误的,一个是螺丝刀,一个是锤子。一种适合用螺丝固定,另一种适合用钉子固定。
当您想要操作 3d 渲染管道时使用 WebGL,当您想要操作光栅图像时使用 Canvas2D。
TL;DR:
如果您使用 Canvas2D,您今天就可以开始制作您想要的具有良好性能的应用程序。如果您想使用 WebGL,您应该努力了解渲染管道的各个阶段。