我对 WebGL 很陌生,但不是 Javascript 或 Canvas。本质上,我需要一种非常快速的方法来改变画布上任意坐标处像素的颜色。我觉得这可以使用 WebGL 片段着色器来完成。这可能吗,有没有更好的方法?我该怎么做呢?
3 回答
这不是一个详尽的渲染指南,因为它不包括有关着色器管理的内容。相反,它侧重于如何实际执行 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);
每次数据更改时,您都需要执行bufferData
或调用。bufferSubData
此时数据在显卡上,所以你只需要实际绘制它:
// 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 值仍然必须位于near
和之间far
才能被渲染,但是,该near
值不能设置为0
。
让我知道这是否需要澄清。
如果您只想绘制单个像素,最好使用 canvas 2d。
否则,您可能可以从本教程中找出它以像素为单位绘制矩形,因此将宽度和高度设置为 1x1,您将获得单个像素。
绘图时可以使用 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 的原始块中渲染几个点的方式。