如何使用WebGL在画布上设置像素的颜色? [英] How can I set the color of a pixel on a canvas using WebGL?

查看:2063
本文介绍了如何使用WebGL在画布上设置像素的颜色?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是WebGL的新手,但不是Javascript或Canvas。基本上,我需要一个非常快的方式,以便能够在任何坐标上更改画布上的像素的颜色。我觉得这可以使用WebGL片段着色器。这是可能的,有更好的方法吗?

I am very new to WebGL, but not Javascript or Canvas. Essentially, I need a very fast way to be able to change the color of a pixel on a canvas at any coordinate. I feel like this could be done using WebGL fragment shaders. Is this possible, and is there a better way? How would I go about doing this?

推荐答案

这不是一个详尽的渲染指南,因为它不包括位关于着色器管理;而是关注如何实际执行WebGL图元的绘制,以及如何使用正投影来精确地在屏幕上定位顶点。

This isn't an exhaustive guide to rendering because it doesn't include the bits about shader management; instead it focuses on how drawing of WebGL primitives is actually performed, and how to use orthographic projection to precisely position vertices on the screen.

有关更多信息,我强烈推荐这些来源:

For more information, I highly recommend these sources:

  • Learning WebGL - tutorials
  • The WebGL specification
  • The Typed Arrays specification

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

WebGL does all of its drawing with Vertex Buffer Objects (VBOs), so you need to compile all your data into 3D vertices and send them down to the video card in as few VBOs as possible (to maximize performance).

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

A VBO can be created in WebGL like so:

var vbo = gl.createBuffer();

然后你需要将数据发送到缓冲区,通常以 Float32Array 。如果您已经以常规JavaScript数组的形式存在数据,那么您可以使用 new Float32Array(jsArray)初始化 Float32Array jsArray 的内容。尝试这样做很少,虽然。类型化数组非常快,但初始化非常缓慢。

Then you need to send the data down to the buffer, usually in the form of a Float32Array. If you already have your data in the form of a regular JavaScript array, then you can use new Float32Array(jsArray) to initialize the Float32Array from the jsArray's contents. Try to do this rarely though. Typed arrays are very fast, but initialize very slowly. It's best to create them once and reuse them whenever possible.

一旦你有一个 Float32Array ,你可以通过数据到缓冲区如下:

Once you have a Float32Array, you can pass the data down to the buffer like so:

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

您需要执行 bufferData bufferSubData 每次数据更改时调用。

You'll need to perform a bufferData or bufferSubData call every time the data changes.

此时数据位于显卡上,只需要实际绘制:

By this time the data is on the graphics card, so you only need to actually draw it:

// 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中只渲染一个像素,它的运行速度会太慢。

Note that although the graphics card can hold quite a few VBOs, you should use as few of them as possible, because the more drawArrays calls you have to perform, the slower things are going to get. Indeed, if you render only a single pixel at a time in a given VBO, it's going to be too slow to run.

$ c> Float32Array 除以3是因为每个单个数据元素是一个3D(X,Y,Z)坐标,因此每个数据元素由3个浮点数组成。注意, gl.drawArrays 的第一个参数是 gl.POINTS 。这将指示图形卡为数组中的每个项目绘制一个点(默认情况下,大小为一个像素)。还有其他绘制方式,如果您需要填充一组像素,其他绘制模式之一(例如 gl.TRIANGLES

The reason the length of the Float32Array is divided by 3 is because each single data element is a 3D (X, Y, Z) coordinate, so each data element consists of 3 float components. Note that the first argument to gl.drawArrays was gl.POINTS. This instructs the graphics card to draw a single point (by default, a single pixel in size) for each item in the array. There are other ways to draw, and if you need to fill a group of pixels, one of the other draw modes (e.g. gl.TRIANGLES) may be more to your liking.

对于点亮特定像素,这取决于着色器的写入方式,但最有可能重新利用模型视图矩阵和投影矩阵。模型视图矩阵表示相机相对于所绘制的点的取向,并且投影矩阵表示相机尺寸(宽度和高度,视场,最近和最远可见范围等)。因此,如果您想要点亮特定像素,最好的办法是应用一个宽度和高度等于画布宽度和高度的正投影矩阵;和设置为身份(无变换)的模型视图矩阵。在正交投影中,物体不会随着远离相机而收缩,因此它们非常有助于指定相对于屏幕的精确位置。此外,如果您给它们正确的尺寸,您可以非常精确地定位顶点 - 在特定像素

As for lighting up specific pixels, it depends on how the shader is written, but most likely you're making use of a modelview matrix and a projection matrix. The modelview matrix represents the orientation of the camera relative to the points being drawn, and the projection matrix represents the camera dimensions (width and height, field of view, nearest and furthest visible ranges, etc). So if you want to light specific pixels, your best bet is to apply an orthographic projection matrix with a width and height equal to the width and height of the canvas; and a modelview matrix set to the identity (no transformation). In an orthographic projection, objects don't shrink as they get further away from the camera, so they're very helpful for specifying exact positions relative to the screen. Also, if you give them the proper dimensions, you can position vertices very precisely -- at specific pixels, if you wish.

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

Different matrix libraries work in different ways, but for example, to set up an orthographic matrix in gl-matrix, you can do so like this:

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

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

The exact numbers depend on your preference; if you'd like to place the origin (0, 0) at the bottom-left of the canvas, you'd do so like this:

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

请注意,每个点的Z值仍然位于 near far 以便呈现,然而 near 值不能设置为 0

Note that the Z value of each point still has to lie between near and far in order to be rendered, however, and the near value cannot be set to 0.

让我知道是否有任何需要澄清。

Let me know if any of this needs clarifying.

这篇关于如何使用WebGL在画布上设置像素的颜色?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆