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

时间:2012-06-17 20:55:26

标签: javascript html canvas webgl

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

3 个答案:

答案 0 :(得分:10)

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

有关详细信息,我强烈推荐这些来源:

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

可以在WebGL中创建VBO,如下所示:

var vbo = gl.createBuffer();

然后,您需要将数据发送到缓冲区,通常采用Float32Array的形式。如果您已经以常规JavaScript数组的形式获得数据,则可以使用new Float32Array(jsArray)Float32Array的内容初始化jsArray。尽量少尝试这样做。类型化数组非常快,但初始化速度非常慢。最好一次创建它们并尽可能重复使用它们。

获得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值不能设置为{{1 }}

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

答案 1 :(得分:3)

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

否则你可以从本教程中找出它以像素为单位绘制矩形,所以将宽度和高度设置为1x1,你就会得到单个像素。

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

答案 2 :(得分: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的原始块中渲染几个点的方法。