如何使用 WebGL 在画布上设置像素的颜色?

Posted

技术标签:

【中文标题】如何使用 WebGL 在画布上设置像素的颜色?【英文标题】:How can I set the color of a pixel on a canvas using WebGL? 【发布时间】:2012-06-19 22:38:25 【问题描述】:

我对 WebGL 很陌生,但不是 javascript 或 Canvas。本质上,我需要一种非常快速的方法来改变画布上任意坐标处像素的颜色。我觉得这可以使用 WebGL 片段着色器来完成。这可能吗,有没有更好的方法?我该怎么做呢?

【问题讨论】:

只有一个像素?还是很多像素?对于单个像素,调用开销可能比仅使用 Canvas2D 更糟糕。 很多像素。使用 imageData 是可行的,但对于 400x400 像素来说太慢了。 从哪里获取像素数据?如果你可以一次计算出shader中的所有值,WebGL会更快。如果从数组中获取数据,WebGL 可能不会比 imageData 快多少。 它们可能来自一个数组。不过感谢您的帮助! 【参考方案1】:

如果您只想绘制单个像素,最好使用 canvas 2d。

否则,您可能可以从本教程中弄清楚它以像素为单位绘制矩形,因此将宽度和高度设置为 1x1,您将获得单个像素。

http://games.greggman.com/game/webgl-fundamentals/

【讨论】:

【参考方案2】:

您可以在绘图时使用 GL_POINTS。基本上,您会将一组点连同颜色和位置一起传递给 GPU。然后使用正确的数据调用 drawArrays。

这可能与其他事情过于相关,但这可能会对您有所帮助:

https://github.com/funkaster/ChesterGL/blob/master/chesterGL/primitivesBlock.js#L126

https://github.com/funkaster/ChesterGL/blob/master/chesterGL/primitivesBlock.js#L260

这就是我在chesterGL的原始块中渲染几个点的方式。

【讨论】:

【参考方案3】:

这不是一个详尽的渲染指南,因为它不包含有关着色器管理的内容;相反,它侧重于如何实际执行 WebGL 基元的绘制,以及如何使用正交投影在屏幕上精确定位顶点。

如需了解更多信息,我强烈推荐以下来源:

Learning WebGL - tutorials The WebGL specification The Typed Arrays specification

WebGL 使用顶点缓冲区对象 (VBO) 进行所有绘图,因此您需要将所有数据编译为 3D 顶点,并以尽可能少的 VBO 将它们发送到视频卡(以最大限度地提高性能)。

可以像这样在 WebGL 中创建 VBO:

var vbo = gl.createBuffer();

然后您需要将数据向下发送到缓冲区,通常以Float32Array 的形式。如果您已经拥有常规 JavaScript 数组形式的数据,那么您可以使用 new Float32Array(jsArray)jsArray 的内容中初始化 Float32Array。尝试很少这样做。类型化数组非常快,但初始化非常慢。最好创建一次并尽可能重复使用。

一旦你有了Float32Array,你就可以像这样将数据向下传递到缓冲区:

gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
gl.bufferData(gl.ARRAY_BUFFER, float32Data, gl.DYNAMIC_DRAW);

每次数据更改时,您都需要执行bufferDatabufferSubData 调用。

此时数据在显卡上,所以你只需要实际绘制它:

// bind the VBO to be drawn if you haven't already
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
// send the vertex data to the shader program
gl.vertexAttribPointer(vertexAttributeLocation, 3, gl.FLOAT, false, 0, 0);
// draw the buffer
gl.drawArrays(gl.POINTS, 0, float32Data.length / 3);

请注意,虽然显卡可以容纳相当多的 VBO,但您应该尽可能少地使用它们,因为您必须执行的 drawArrays 调用越多,速度就越慢。事实上,如果你在给定的 VBO 中一次只渲染一个像素,运行起来会太慢。

Float32Array 的长度除以 3 的原因是因为每个单个数据元素都是一个 3D (X, Y, Z) 坐标,所以每个数据元素由 3 个浮点分量组成。注意gl.drawArrays 的第一个参数是gl.POINTS。这指示图形卡为数组中的每个项目绘制一个点(默认情况下,一个像素大小)。还有其他绘制方式,如果您需要填充一组像素,其他绘制模式之一(例如gl.TRIANGLES)可能更符合您的喜好。

至于照亮特定像素,这取决于着色器的编写方式,但很可能您正在使用模型视图矩阵和投影矩阵。模型视图矩阵表示相机相对于被绘制点的方向,投影矩阵表示相机尺寸(宽度和高度、视野、最近和最远的可见范围等)。所以如果你想照亮特定的像素,你最好的办法是应用一个宽度和高度等于画布宽度和高度的正交投影矩阵;和一个模型视图矩阵设置为身份(无转换)。在正交投影中,物体在远离相机时不会缩小,因此它们对于指定相对于屏幕的精确位置非常有帮助。此外,如果你给它们适当的尺寸,你可以非常精确地定位顶点——在特定像素处,如果你愿意的话。

不同的矩阵库以不同的方式工作,但例如,要在gl-matrix 中设置正交矩阵,您可以这样做:

var ortho = mat4.ortho(left, right, bottom, top, near, far);

具体数字取决于您的偏好;如果你想将原点 (0, 0) 放在画布的左下角,你可以这样做:

var ortho = mat4.ortho(0, canvas.width, 0, canvas.height, 0.01, 200);

请注意,每个点的 Z 值仍然必须位于 nearfar 之间才能被渲染,但是,near 值不能设置为 0

如果有任何需要澄清的地方,请告诉我。

【讨论】:

以上是关于如何使用 WebGL 在画布上设置像素的颜色?的主要内容,如果未能解决你的问题,请参考以下文章

像素和颜色 - WebGL

WebGL纹理颜色原理

在 WebGL v.s. 中模拟基于调色板的图形2D画布

波浪js背景颜色

base64如何查看像点颜色

photoshop如何改变矩形线条颜色