前面学习了通过缓冲区对象来绘制多个点的原理,在实际的3D世界里,有好多复杂的模型,但细化分解后又是由一个个基础的几何图形构成的,掌握了基础图形的绘制才能够理解更加复杂的模型。本节将会讲解三角形,矩形以及利用三角函数绘制圆。
之前的篇章我们通过 drawArrays 这个api绘制过单个点以及多个点,然而,它的功能不仅仅如此,它也是绘制多边形的基石。先来看下面这张熟悉的图:
drawArrays 支持多种类型的基本图形,可以画点、线段、折线图,三角形,扇形等,不过要注意顶点的顺序性。
在上一小节画三个点的示例上,只要稍微把绘制方法改一下,即可绘制一个三角形。
// 第一个参数改为: context.TRIANGLES
context.drawArrays(context.TRIANGLES, 0, n);
是不是非常的简单,同时注意到,WebGL绘制出来的是填充好了的三角形,还记得我们在片元着色器中定义的顶点颜色为: gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0),也就是三个顶点都是红色,结果整个三角形都为红色的。(后续章节会解释颜色的绘制,这跟片元着色器的工作原理相关)
现在,我们已经知道了,要绘制一个几何图形,只需要按照规定定义好图形的顶点,再调用drawArrays方法便可以自行绘制出几何图形了,这便是WebGL几何图形的绘制原理,只需要指定顶点信息即可。
接着,我们再接再厉,绘制一个四边形。四边形跟三角形不一样的地方在于多了一个顶点,我们重新定义顶点的信息:
var vertices = new Float32Array([
-0.5,0.5, -0.5,-0.5, 0.5,0.5, 0.5,-0.5
]);
这一次,我们使用 context.TRIANGLE_STRIP 这种类型进行绘制,参考图示,定义的顶点顺序为:左上角(V0),左下角(V1),右上角(V2),右下角(V3)。
最后修改绘制方法即可:
// 绘制矩形
context.drawArrays(context.TRIANGLE_STRIP, 0, n);
从上面几何绘制图形来看,似乎没有办法可以直接绘制一个圆,事实上,的确没有直接的api可以绘制一个圆,但这难不倒我们,借助 context.TRIANGLE_FAN 这种类型,我们便可以绘制一个近乎圆的多边形(肉眼来看的确就是一个圆)。
我们在一个圆形上面画一个八边形和一个十六边形,所有的顶点都落在圆形上面,从以上两幅图可以看到,只要遵循顶点在圆形上,而且顶点均匀分布,那么随着顶点数越多,所有顶点连结起来就越接近一个圆。
思路有了,接下来,我们的任务就转化为怎么去求这些点的坐标。
假设p1就是我们的点V0,现在我们要求出其他点的坐标,设点p2(x’,y’)是接下去的顶点,与p1(x,y) 相隔了θ度(θ = 360/n,n为顶点数量),
由三角函数知识 ,可得
sinθ = y’/ r ; cosθ = x’/ r
也即:
p2(x’ , y’) = (r * cosθ , r * sinθ)
现在,我们使用的是角度 ,js中计算三角函数使用的是弧度,所以要转换一下,
θ = 360/n * (Math.PI/180); (n为顶点的数量)
有了这些基础,我们便可以编写画圆的程序了,初始化顶点的代码如下:
function initVertexBuffers(context) {
// 画n个点
var n = 64;
var vertices = new Float32Array(n*2);
var angle = 0; // 开始的弧度
var r = 0.5; // 圆的半径
// θ值
var stepAngle = 360/n * (Math.PI/180);
for(var i=0; i2; i+=2){
// 计算顶点x坐标
vertices[i] = r * Math.cos(angle);
// 计算顶点y坐标
vertices[i+1] = r * Math.sin(angle);
angle += stepAngle;
}
// 创建一个缓存对象,用于存放顶点数据
var vertexBuffer = context.createBuffer();
// 绑定缓存对象
context.bindBuffer(context.ARRAY_BUFFER, vertexBuffer);
// 把数据写到缓冲对象中
context.bufferData(context.ARRAY_BUFFER, vertices, context.STATIC_DRAW);
// 获取顶点着色器代码中的顶点变量
var a_Position = context.getAttribLocation(context.program, 'a_Position');
// 设置变量获取数据规则
context.vertexAttribPointer(a_Position, 2, context.FLOAT, false, 0, 0);
// 允许变量从 ARRAY_BUFFER目标上绑定的缓冲区对象获取数据
context.enableVertexAttribArray(a_Position);
return n;
}
然后,我们使用 TRIANGLE_FAN 进行绘制即可。
// 绘制扇形
context.drawArrays(context.TRIANGLE_FAN, 0, n);
多边形的绘制是非常基础的知识,但也是非常重要的,只有知道了怎么绘制基础的图形,才能够理解各种更加复杂的模型,通过一些数学知识,我们最后绘制了一个圆。大家可以凭自己的想象尝试绘制更多的图形。
点击下载(多边形绘制原理)