目标:
- 在canvas中绘制基本图形以及js向shader一次传入多个(点)坐标位置值
基本概念
-
构成三维模型的基本单位是三角形,不论其形状多么复杂。通过创建更细小和更大量的三角形,就可以创建更复杂和更逼真的三维模型。
-
缓冲区对象:WebGL系统中的一块内存区域,我们可以一次性向缓冲区对象中填充大量的顶点数据,然后将这些数据保存在其中,以供顶点着色器使用。
使用缓冲区对象向顶点着色器传入多个顶点数据的五个步骤:
(创建缓冲区对象前WebGL里的状态)-
创建缓冲区对象(gl.createBuffer())
-
绑定缓冲区对象(gl.bindBuffer());【就是将缓冲区对象绑定到WebGL系统中已经存在的目标(target)上,这个目标表示缓冲区对象的用途(如:向顶点着色器提供传给attribute变量的数据),这样WebGL才能正确处理其中的内容。】
-
将数据写入缓冲区对象(gl.bufferData());【我们不能直接向缓冲区写入数据,只能向目标(target)写入数据,所以要向缓冲区写入数据,必须先绑定。】
-
将缓冲区对象分配给一个attribute变量(gl.vertexAttribPointer())【gl.vertexAttrib[1234]f系列函数一次只能向attribute变量分配一个值,vertexAttribPointer可以将整个缓冲区对象(的指针)分配给attribute变量】
-
开启attribute变量(gl.enableVertexAttribArray())【为了使顶点着色器能够访问缓冲区内的数据,虽然函数名称似乎表示该函数是处理顶点数组的,但实际上它处理的对象是缓冲区,这是历史原因造成的】
-
类型化数组
为了绘制三维图形,WebGL通常需要同时处理大量相同类型的数据,如顶点的坐标和颜色数据。为了优化性能(普通Array既可以存数字也可存字符串,并没有对“大量元素都是同一种类型”这种情况进行优化),WebGL为每种基本数据类型引入了一种特殊的数组(类型化数组),浏览器事先知道数组中的数据类型,所有处理起来更加有效率。WebGL中很多操作都要用到类型化数组
必须掌握的方法(js向shader一次传入多个(点)的坐标位置值和多个点的尺寸值)
-
gl.createBuffer()
; 创建缓冲区对象;
参数:无;
返回值:非null 新创建的缓冲区对象; null 创建缓冲区对象失败; -
gl.deleteBuffer(buffer)
; 删除参数buffer表示的缓冲区对象
参数:buffer 待删除的缓冲区对象
返回值:无 -
gl.bindBuffer(target,buffer)
允许使用buffer表示的缓冲区对象并将其绑定到target表示的目标上
参数:
target
表示缓冲区对象的用途,这样WebGL才能够正确处理其中的内容,可选值有gl.ARRAY_BUFFER
(表示缓冲区对象中包含了顶点的数据);gl.ELEMENT_ARRAY_BUFFER
(表示缓冲区对象中包含了顶点的索引值);
buffer
(指定之前由gl.createBuffer()
返回的待绑定的缓冲区对象),如果指定为null,则禁用对target的绑定。
返回值:无 -
gl.bufferData(target,data,usage)
开辟存储空间,向绑定在target上的缓冲区对象中写入数据data
参数:
target
同上,可选值gl.ARRAY_BUFFER
或gl.ELEMENT_ARRAY_BUFFER
;
data
写入缓冲区对象的数据(类型化数组);
usage
表示程序将如何使用存储在缓存区对象中的数据,可选值gl.STATIC_DRAW
(只会向缓冲区对象中写入一次数据,但需要绘制很多次),gl.STREAM_DRAW
(只会向缓冲区对象写入一次数据,然后绘制若干次),gl.DYNAMIC_DRAW
(会向缓冲区对象中多次写入数据,并绘制很多次)
返回值:无 -
gl.vertexAttribPointer(location,size,type,normalized,stride,offset)
将绑定到gl.ARRAY_BUFFER
的缓冲区对象分配给由location指定的attribute变量;
参数:
location
待分配的attribute变量的存储位置;
size
指定缓冲区中每个顶点的分量个数(1到4),若size比attribute变量需要的分量数小,缺失分量将按照与gl.vertexAttrib[1234]f()相同的规则自动补全,如:如果size为1,那么第2 3分量自动设为0,第四分量为1;
type
指定数据格式,可选值:gl.UNSIGEND_BYTE
,gl.SHORT
,gl.UNSIGNED_SHORT
,gl.INT
,gl.UNSIGEND_INT
,gl.FLOAT
;
normalize
传入true或false,表明是否将非浮点型的数据归一化到[0,1]或[-1,1]区间;
stride
指定相邻两个顶点间的字节数,默认为0(也可解释为在缓冲区对象中,单个顶点的所有数据【如顶点坐标,尺寸,颜色】总的字节数。也就是相邻两个顶点间的距离,即步进参数);
offset
指定缓冲区对象中的偏移量(以字节为单位),即attribute变量从缓冲区中的何处开始存储。
返回值:无 -
gl.enableVertexArray(location)
开启location指定的attribute变量;
参数: location attribute变量的存储位置;
返回值:无 -
gl.disableVertexArray(location)
关闭location指定的attribute变量;
返回值:无 -
gl.drawingBufferWidth
获取颜色缓冲区的宽度(了解) -
gl.drawingBufferHeight
获取颜色缓冲区的高度(了解)
示例:
var VSHADER_SOURCE = `
attribute vec4 a_Position;\n
attribute float a_PointSize;\n
void main(){\n
gl_Position = a_Position;\n
gl_PointSize = a_PointSize;\n
}\n
`
var FSHADER_SOURCE = `
void main(){\n
gl_FragColor = vec4(1.0,0.0,0.0,1.0);\n
}\n
`
function main() {
var canvas = document.getElementById('webgl');
var gl = getWebGLContext(canvas);
gl.clearColor(0.0,0.0,0.0,1.0);
if (!initShaders(gl,VSHADER_SOURCE,FSHADER_SOURCE)) {
return;
}
var n = initVertexBuffers(gl);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.POINTS,0,n);
}
main();
function initVertexBuffers(gl) {
// 顶点的坐标和尺寸
var verticesSizes = new Float32Array([
0.0, 0.5, 10.0,
-0.5, -0.5, 20.0,
0.5, -0.5, 30.0
])
var n = 3;
// 创建缓冲区对象
var vertexSizeBuffer = gl.createBuffer();
// 将缓冲区对象绑定到目标
gl.bindBuffer(gl.ARRAY_BUFFER,vertexSizeBuffer);
// 给目标赋值
/* @param
*target(gl_ARRAY_BUFFER或gl.ELEMENT_ARRAY_BUFFER);
*data(写入缓冲区对象的数据----类型化数组)
*usage(表示程序将如何使用存储在缓冲区对象中的数据,帮助WebGL优化操作,就算传入错误的值也不会终止程序)
*/
gl.bufferData(gl.ARRAY_BUFFER,verticesSizes,gl.STATIC_DRAW);
// 将verticeSize数组中每个元素的大小(字节数)存储到FSIZE中。
// 类型化数组具有BYTES_PER_ELEMENT属性,可以从中获知数组中每个元素所占的字节数
var FSIZE = verticesSizes.BYTES_PER_ELEMENT;
var a_Position = gl.getAttribLocation(gl.program,'a_Position');
// vertexAttribPointer 将缓冲区对象分配给a_Position变量
/* @param:
*location(变量地址),
*size(指定缓冲区中每个顶点的分量个数,比如本例中顶点只给了x,y,所以分量为2),
*type(指定数据格式),
*normalized(是否将非浮点型的数据归一化到[0,1]或[-1,1]区间),
*stride(指定相邻两个顶点间的字节数,默认为0,(也可解释为在缓冲区对象中,单个顶点的所有数据【如顶点坐标,尺寸,颜色】总的字节数。也就是相邻两个顶点间的距离,即步进参数)),
*offset(缓冲区对象中的偏移量,以字节为单位,即attribute变量从缓存区中的何处开始存储)
*/
gl.vertexAttribPointer(a_Position,2,gl.FLOAT,false,FSIZE*3,0);
gl.enableVertexAttribArray(a_Position);
var a_PointSize = gl.getAttribLocation(gl.program,'a_PointSize');
gl.vertexAttribPointer(a_PointSize,1,gl.FLOAT,false,FSIZE*3,FSIZE*2);
gl.enableVertexAttribArray(a_PointSize);
return n;
}
绘制结果: