WebGL 基本原理

更新时间:2016-04-25 10:56:00 点击次数:2166次

WebGL 的出现使得在浏览器上面实时显示 3D 图像成为,WebGL 本质上是基于光栅化的 API ,而不是基于 3D 的 API。

WebGL 只关注两个方面,即投影矩阵的坐标和投影矩阵的颜色。使用 WebGL 程序的任务就是实现具有投影矩阵坐标和颜色的 WebGL 对象即可。可以使用“着色器”来完成上述任务。顶点着色器可以提供投影矩阵的坐标,片段着色器可以提供投影矩阵的颜色。

无论要实现的图形尺寸有多大,其投影矩阵的坐标的范围始终是从 -1 到 1 。下面是一个关于实现 WebGL 对象的一个简单例子。

// Get A WebGL context
var canvas = document.getElementById("canvas");
var gl = canvas.getContext("experimental-webgl");
 
// setup a GLSL program
var program = createProgramFromScripts(gl, ["2d-vertex-shader", "2d-fragment-shader"]);
gl.useProgram(program);
 
// look up where the vertex data needs to go.
var positionLocation = gl.getAttribLocation(program, "a_position");
 
// Create a buffer and put a single clipspace rectangle in
// it (2 triangles)
var buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(
gl.ARRAY_BUFFER,
new Float32Array([
-1.0, -1.0,
 1.0, -1.0,
-1.0,  1.0,
-1.0,  1.0,
 1.0, -1.0,
 1.0,  1.0]),
gl.STATIC_DRAW);
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
 
// draw
gl.drawArrays(gl.TRIANGLES, 0, 6); 

下面是两个着色器。

 



它将绘出一个绿色的长方形来填充整个画板。

后面内容还会更精彩,我们继续:-P

我们再次降调一下,无论画板尺寸多大,投影矩阵坐标的范围只会在 -1 到 1 之间。从上面的例子中,我们可以看出我们只是将位置信息直接写在了程序里。 因为位置信息已经在投影矩阵中,所以并没有其他额外的工作要做。 如果想实现 3D 的效果,那么可以使用着色器来将 3D 转换为投影矩阵,这是因为 WebGL 是基于光栅的 API。

对于 2D 的图像,也许会使用像素而不是投影矩阵来表述尺寸,那么这里我们就更改这里的着色器,使得我们实现的矩形可以以像素的方式来度量,下面是新的顶点着色器。

 

下面我们将我们的数据从投影矩阵改为像素。

// set the resolution
var resolutionLocation = gl.getUniformLocation(program, "u_resolution");
gl.uniform2f(resolutionLocation, canvas.width, canvas.height);

// setup a rectangle from 10,20 to 80,30 in pixels
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
10, 20,
80, 20,
10, 30,
10, 30,
80, 20,
80, 30]), gl.STATIC_DRAW); 

上面例子矩阵位于底部边框,下面我们让它位于左上边框:

修改代码如下:

 gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);

效果如下图:

下面我们将上述关于矩阵的实现写成函数以便可以以函数调用的方式来实现不同尺寸的矩阵。 然而,这里的颜色应该是可变的。

首先,我们为片段着色器设计一个关于颜色的输入。

 

下面是实现绘画 50 个尺寸和颜色均随机的矩阵的代码。

var colorLocation = gl.getUniformLocation(program, "u_color");
  ...
  // Create a buffer
  var buffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
  gl.enableVertexAttribArray(positionLocation);
  gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);

  // draw 50 random rectangles in random colors
  for (var ii = 0; ii < 50; ++ii) { // Setup a random rectangle setRectangle( gl, randomInt(300), randomInt(300), randomInt(300), randomInt(300)); // Set a random color. gl.uniform4f(colorLocation, Math.random(), Math.random(), Math.random(), 1); // Draw the rectangle. gl.drawArrays(gl.TRIANGLES, 0, 6); } } // Returns a random integer from 0 to range - 1. function randomInt(range) { return Math.floor(Math.random() * range); } // Fills the buffer with the values that define a rectangle. function setRectangle(gl, x, y, width, height) { var x1 = x; var x2 = x + width; var y1 = y; var y2 = y + height; gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ x1, y1, x2, y1, x1, y2, x1, y2, x2, y1, x2, y2]), gl.STATIC_DRAW); } 

下面就是实现出来的效果。

到此可以看出 WebGL 实质上是一种轻量级的 API。但是,它可以实现较为复杂的 3D 效果,其复杂性由程序定制。WebGL API 本身是 2D 的且相对比较简单。

本站文章版权归原作者及原出处所有 。内容为作者个人观点, 并不代表本站赞同其观点和对其真实性负责,本站只提供参考并不构成任何投资及应用建议。本站是一个个人学习交流的平台,网站上部分文章为转载,并不用于任何商业目的,我们已经尽可能的对作者和来源进行了通告,但是能力有限或疏忽,造成漏登,请及时联系我们,我们将根据著作权人的要求,立即更正或者删除有关内容。本站拥有对此声明的最终解释权。

回到顶部
嘿,我来帮您!