02-WebGL缓冲区对象

WebGL提供了一种很方便的机制,即缓冲区对象(buffer object),它可以一次性地向着色器传入多个顶点的数据。

缓冲区对象是WebGL系统中的一块内存区域,我们可以一次性地向缓冲区对象中填充大量的顶点数据,然后将这些数据保存在其中,供顶点着色器使用。

使用缓冲区对象向顶点着色器传入多个顶点的数据,需要遵循以下5个步骤:

  1. 创建缓冲区对象gl.createBuffer()
  2. 绑定缓冲区对象gl.bindBuffer()
  3. 将数据写入缓冲区对象gl.bufferData()
  4. 将缓冲区对象分配给一个attribute变量gl.vertexAttribPointer()
  5. 开始attribute变量gl.enableVertexAttribArray()
  • 绘制三角形的3个顶点
// Vertex shader program
var VSHADER_SOURCE =
  'attribute vec4 a_Position;\n' +
  'void main() {\n' +
  '  gl_Position = a_Position;\n' +
  '  gl_PointSize = 10.0;\n' +
  '}\n';

// Fragment shader program
var FSHADER_SOURCE =
  'void main() {\n' +
  '  gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n' +
  '}\n';

function main() {
  // Retrieve <canvas> element
  var canvas = document.getElementById('webgl');

  // Get the rendering context for WebGL
  var gl = getWebGLContext(canvas);
  if (!gl) {
    console.log('Failed to get the rendering context for WebGL');
    return;
  }

  // Initialize shaders
  if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
    console.log('Failed to intialize shaders.');
    return;
  }

  // Write the positions of vertices to a vertex shader
  var n = initVertexBuffers(gl);
  if (n < 0) {
    console.log('Failed to set the positions of the vertices');
    return;
  }

  // Specify the color for clearing <canvas>
  gl.clearColor(0, 0, 0, 1);

  // Clear <canvas>
  gl.clear(gl.COLOR_BUFFER_BIT);

  // Draw three points
  gl.drawArrays(gl.POINTS, 0, n);
}

function initVertexBuffers(gl) {
  var vertices = new Float32Array([
    0.0, 0.5,   -0.5, -0.5,   0.5, -0.5
  ]);
  var n = 3; // The number of vertices

  // 创建缓冲区对象
  var vertexBuffer = gl.createBuffer();
  if (!vertexBuffer) {
    console.log('Failed to create the buffer object');
    return -1;
  }

  // 将缓冲区对象绑定到目标
  gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
  // 向缓冲区对象中写入数据
  gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);

  var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
  if (a_Position < 0) {
    console.log('Failed to get the storage location of a_Position');
    return -1;
  }
  // 将缓冲区对象分配给a_Position变量
  gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);

  // 连接a_Position变量与分配给它的缓冲区对象
  gl.enableVertexAttribArray(a_Position);

  return n;
}
  1. 创建缓冲区对象gl.createBuffer()

执行该方法的结果就是,WebGL系统中多了一个新创建出来的缓冲区对象。返回值为null表示创建失败。

相应地,gl.deleteBuffer(buffer)函数可以用来删除被gl.createBuffer()创建出来的缓冲区对象

  1. 绑定缓冲区gl.bindBuffer(target,buffer)

创建缓冲区的第二步就是将缓冲区对象绑定到WebGL系统中已经存在的“目标”上。这个“目标”表示缓冲区对象的用途。允许使用buffer表示的缓冲区对象绑定到target表示的目标上。

gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer)

其中,gl.ARRAY_BUFFER表示缓冲区对象中包含了顶点的数据

  1. 向缓冲区对象中写入数据gl.bufferData(target,data,usage)

第三步,开辟空间并向缓冲区中写入数据。

var vertices = new Float32Array([
    0.0,0.5,-0.5,-0.5,0.5,0.5
])
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW)

该方法的效果是,将第2个参数vertices中的数据写入绑定到第1个参数gl.ARRAY_BUFFER上的缓冲区对象。我们不能直接向缓冲区写入数据,而只能向"目标"写入数据,所以要向缓冲区写数据,必须先绑定。

其中,参数usage表示程序将如何使用存储在缓冲区对象中的数据。该参数将帮助WebGL优化操作,但即便传入了错误的值,也不会终止程序(仅仅是降低程序的效率)

上面,我们使用了Float32Array对象,而不是JS更常见的Array对象。这是因为,JS中的数组Array是一种通用的类型,既可以存储数字也可以存储字符串,而并没有对“大量元素都是同一种类型”优化。为了解决这个问题,WebGL引入了类型化的数组,Float32Array就是其中之一。

  • WebGL使用的各种类型化数组
数组类型 每个元素所点字节数 描述(C语言中的数据类型)
Int8Array 1 8位整型(singed char)
UInt8Array 1 8位无符号整型(unsinged char)
Int16Array 2 16位整型(singed short)
UInt16Array 2 16位无符号整型(unsinged short)
Int32Array 4 32位整型(singed int)
UInt32Array 4 32位无符号整型(unsinged int)
Float32Array 4 单精度32位浮点数(float)
Float64Array 8 双精度64位浮点数(double)

注意: 与普通的Array数组不同,类型化数组不支持push()和pop()方法;创建类型化数组的唯一方法就是使用new运算符,不能使用[]运算符。

  • 类型化数组的方法、属性和常量
方法、属性和常量 描述
get(index) 获取第index个元素值
set(index,value) 设置第index个元素的值为value
set(array,offset) 从第offset个元素开始将数组array中的值填充进去
length 数组的长度
BYTES_PER_ELEMENT 数组中每个元素所占的字节数
  1. 将缓冲区对象分配给attribute变量gl.vertexAttribPointer(location,size,type,normalized,stride,offset)

将绑定到gl.ARRAY_BUFFER的缓冲区对象分配给由location指定的attribute变量。

  gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);

参数location指定待分配attribute变量的存储位置;

size指定缓冲区中每个顶点的分量个数(1到4),若size比attribute变量需要的分量数小,缺失分量将按照与gl.vertexAttrib[1234]f()相同的规则补全。(比如:size为1,那么第2、3分量自动设为0,第4分量为1)

type为数据类型

normalize传入true或false,表明是否将非浮点型的数据归一化到[0,1]或[1,1]区间

stride指定相邻两个顶点间的字节数,默认为0

offset指定缓冲区对象中的偏移量

  1. 开启attribute变量gl.enableVertexAttribArray()
gl.enableVertexAttribArray(a_Position)

注意:虽然函数的名称似乎表示该函数是用来处理“顶点数组”的,但实际上它处理的对象是缓冲区。这是由于历史原因(从OpenGL中继承)造成的。

开启attribute变量后,就不能再用gl.vertexAttrib[1234]f()向它传数据了,除非你显示地关闭该attribute变量。实际上,你无法(也不应该)同时使用这两个函数。

gl.drawArrays(mode,first,count)

mode指定绘制的方式,可接收:gl.POINTS、gl.LINES、gl.LINES_STRIP、gl.LINE_LOOP、gl.TRIANGLES、gl.TRIANGLE_STRIP、gl.TRINGLE_FAN

first指定从哪个顶点开始绘制(整数)

count 指定绘制需要用到多少个顶点(整数)

gl.drawArrays(gl.POINTS,0,n) //n为3

实际上,顶点着色器执行了n(3)次,我们通过存储在缓冲区中的顶点坐标数据被依次传给attribute变量。

  • 连接三个顶点,填充三角形

基于上面顶点程序的改动有两处:

1.在顶点着色器中,去掉指定点的尺寸gl_PointSize = 10.0;,该语句只有在绘制单个点的时候才起作用。

2.gl.drawArrays()方法的第1个参数从gl.POINTS被改为了gl.TRINGLES,就相当于告诉WebGL,从缓冲区中的第1个顶点开始,使顶点着色器执行3次(n为3),用这3个点绘制出一个三角形。

  • WebGL可以绘制的基本图形
image.png
  • 对应效果
image.png

WebGL有点上头,暂时告一段落……

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,001评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,210评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,874评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,001评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,022评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,005评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,929评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,742评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,193评论 1 309
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,427评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,583评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,305评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,911评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,564评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,731评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,581评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,478评论 2 352

推荐阅读更多精彩内容