标签:webgl
注:文章译自http://wgld.org/,原作者杉本雅広(doxas),文章中如果有我的额外说明,我会加上[lufy:],另外,鄙人webgl研究还不够深入,一些专业词语,如果翻译有误,欢迎大家指正。

这是本次的demo的运行结果
这次终于该绘制多边形了,之前的文章(十一,着色器的编译和连接)中介绍了HTML,顶点着色器和片段着色器,这次看一下javascript从开始到最终的全部处理。
如果前两篇文章介绍的内容完全理解的话,这次的内容也应该不难了。或许会有不容易理解的地方,不要着急。
首先,我先贴出所有代码,然后在慢慢说明。
>script.js的全部代码
onload = function(){
// canvas对象获取
var c = document.getElementById(‘canvas‘);
c.width = 300;
c.height = 300;
// webgl的context获取
var gl = c.getContext(‘webgl‘) || c.getContext(‘experimental-webgl‘);
// 设定canvas初始化的颜色
gl.clearColor(0.0, 0.0, 0.0, 1.0);
// 设定canvas初始化时候的深度
gl.clearDepth(1.0);
// canvas的初始化
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
// 顶点着色器和片段着色器的生成
var v_shader = create_shader(‘vs‘);
var f_shader = create_shader(‘fs‘);
// 程序对象的生成和连接
var prg = create_program(v_shader, f_shader);
// attributeLocation的获取
var attLocation = gl.getAttribLocation(prg, ‘position‘);
// attribute的元素数量(这次只使用 xyz ,所以是3)
var attStride = 3;
// 模型(顶点)数据
var vertex_position = [
0.0, 1.0, 0.0,
1.0, 0.0, 0.0,
-1.0, 0.0, 0.0
];
// 生成VBO
var vbo = create_vbo(vertex_position);
// 绑定VBO
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
// 设定attribute属性有効
gl.enableVertexAttribArray(attLocation);
// 添加attribute属性
gl.vertexAttribPointer(attLocation, attStride, gl.FLOAT, false, 0, 0);
// 使用minMatrix.js对矩阵的相关处理
// matIV对象生成
var m = new matIV();
// 各种矩阵的生成和初始化
var mMatrix = m.identity(m.create());
var vMatrix = m.identity(m.create());
var pMatrix = m.identity(m.create());
var mvpMatrix = m.identity(m.create());
// 视图变换坐标矩阵
m.lookAt([0.0, 1.0, 3.0], [0, 0, 0], [0, 1, 0], vMatrix);
// 投影坐标变换矩阵
m.perspective(90, c.width / c.height, 0.1, 100, pMatrix);
// 各矩阵想成,得到最终的坐标变换矩阵
m.multiply(pMatrix, vMatrix, mvpMatrix);
m.multiply(mvpMatrix, mMatrix, mvpMatrix);
// uniformLocation的获取
var uniLocation = gl.getUniformLocation(prg, ‘mvpMatrix‘);
// 向uniformLocation中传入坐标变换矩阵
gl.uniformMatrix4fv(uniLocation, false, mvpMatrix);
// 绘制模型
gl.drawArrays(gl.TRIANGLES, 0, 3);
// context的刷新
gl.flush();
// 生成着色器的函数
function create_shader(id){
// 用来保存着色器的变量
var shader;
// 根据id从HTML中获取指定的script标签
var scriptElement = document.getElementById(id);
// 如果指定的script标签不存在,则返回
if(!scriptElement){return;}
// 判断script标签的type属性
switch(scriptElement.type){
// 顶点着色器的时候
case ‘x-shader/x-vertex‘:
shader = gl.createShader(gl.VERTEX_SHADER);
break;
// 片段着色器的时候
case ‘x-shader/x-fragment‘:
shader = gl.createShader(gl.FRAGMENT_SHADER);
break;
default :
return;
}
// 将标签中的代码分配给生成的着色器
gl.shaderSource(shader, scriptElement.text);
// 编译着色器
gl.compileShader(shader);
// 判断一下着色器是否编译成功
if(gl.getShaderParameter(shader, gl.COMPILE_STATUS)){
// 编译成功,则返回着色器
return shader;
}else{
// 编译失败,弹出错误消息
alert(gl.getShaderInfoLog(shader));
}
}
// 程序对象的生成和着色器连接的函数
function create_program(vs, fs){
// 程序对象的生成
var program = gl.createProgram();
// 向程序对象里分配着色器
gl.attachShader(program, vs);
gl.attachShader(program, fs);
// 将着色器连接
gl.linkProgram(program);
// 判断着色器的连接是否成功
if(gl.getProgramParameter(program, gl.LINK_STATUS)){
// 成功的话,将程序对象设置为有效
gl.useProgram(program);
// 返回程序对象
return program;
}else{
// 如果失败,弹出错误信息
alert(gl.getProgramInfoLog(program));
}
}
// 生成VBO的函数
function create_vbo(data){
// 生成缓存对象
var vbo = gl.createBuffer();
// 绑定缓存
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
// 向缓存中写入数据
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(data), gl.STATIC_DRAW);
// 将绑定的缓存设为无效
gl.bindBuffer(gl.ARRAY_BUFFER, null);
// 返回生成的VBO
return vbo;
}
};那么,从上到下按顺序来看一下吧。
首先,前提是在页面加载的同时执行script.js中的所有代码,所以,将代码全都写进了onload函数中。之后,获取canvas对象开始处理。
>canvas的获取和初始化如下
// canvas对象获取
var c = document.getElementById(‘canvas‘);
c.width = 300;
c.height = 300;
// webgl的context获取
var gl = c.getContext(‘webgl‘) || c.getContext(‘experimental-webgl‘);
// 设定canvas初始化的颜色
gl.clearColor(0.0, 0.0, 0.0, 1.0);
// 设定canvas初始化时候的深度
gl.clearDepth(1.0);
// canvas的初始化
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);最先开始做的是获取canvas对象,并设定canvas的大小为宽300px,高300px。然后获取WebGL的context,以及设定清除画面所使用的颜色。生成顶点着色器和片段着色器,并使用程序对象进行连接。在以前的文章(着色器的编译和连接)中进行过详细的说明,可以参考一下。
>着色器和程序对象相关的处理
// 顶点着色器和片段着色器的生成
var v_shader = create_shader(‘vs‘);
var f_shader = create_shader(‘fs‘);
// 程序对象的生成和连接
var prg = create_program(v_shader, f_shader);
// attributeLocation的获取
var attLocation = gl.getAttribLocation(prg, ‘position‘);
// attribute的元素数量(这次只使用 xyz ,所以是3)
var attStride = 3;注意这里出现的函数,并不是WebGL中内置的函数,而是自己写的。具体点就是说create_shader和create_program都是自己写的函数。>使用顶点着色器的代码
attribute vec3 position;
uniform mat4 mvpMatrix;
void main(void){
gl_Position = mvpMatrix * vec4(position, 1.0);
}这次使用着色器的时候,只使用了一个attribute变量,当然就是position了,这个position变量定义成了vec3,说明是拥有3各元素的向量。继续吧,接着是定义模型数据,并生成VBO,然后为了将VBO传给顶点着色器,进行绑定并传入数据。
>VBO生成的相关处理
// 模型(顶点)数据
var vertex_position = [
0.0, 1.0, 0.0,
1.0, 0.0, 0.0,
-1.0, 0.0, 0.0
];
// 生成VBO
var vbo = create_vbo(vertex_position);
// 绑定VBO
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
// 设定attribute属性有効
gl.enableVertexAttribArray(attLocation);
// 添加attribute属性
gl.vertexAttribPointer(attLocation, attStride, gl.FLOAT, false, 0, 0);以前的文章(十二,模型数据和顶点属性)中也有过详细说明,将顶点数据定义为简单的数组,然后根据这个数组数据,用自定义函数create_vbo来生成顶点缓存(VBO)。接着,是准备渲染用的坐标变换矩阵。这里使用了本网站制作的矩阵计算的库minMatrix.js,minMatrix.js的基本的使用方法在上一篇文章中(minMatrix.js和坐标变换矩阵)已经介绍过了。
>坐标变换矩阵的生成以及相关的处理
// 使用minMatrix.js对矩阵的相关处理
// matIV对象生成
var m = new matIV();
// 各种矩阵的生成和初始化
var mMatrix = m.identity(m.create());
var vMatrix = m.identity(m.create());
var pMatrix = m.identity(m.create());
var mvpMatrix = m.identity(m.create());
// 视图变换坐标矩阵
m.lookAt([0.0, 1.0, 3.0], [0, 0, 0], [0, 1, 0], vMatrix);
// 投影坐标变换矩阵
m.perspective(90, c.width / c.height, 0.1, 100, pMatrix);
// 各矩阵想成,得到最终的坐标变换矩阵
m.multiply(pMatrix, vMatrix, mvpMatrix);
m.multiply(mvpMatrix, mMatrix, mvpMatrix);
// uniformLocation的获取
var uniLocation = gl.getUniformLocation(prg, ‘mvpMatrix‘);
// 向uniformLocation中传入坐标变换矩阵
gl.uniformMatrix4fv(uniLocation, false, mvpMatrix);这次,模型变换矩阵初始化之后没有做任何处理就直接使用了,当然,并不是说不能操作模型变换矩阵,现在就先这么使用了。>>uniform系列函数相关
这次出现的uniformMatrix4fv只是uniform系列函数的一个,uniform系列函数有很多种,主要分为以下几大类。
uniform 系列
uniform系列有uniform1 ~ uniform4,分别在向顶点着色器中传入一个到四各元素时使用。根据传给顶点着色器的数据的类型为整型或者浮点型,数字的后面会加上i(int)或者f(float)等小写字母。比如,传给着色器的数据是有两个元素的浮点型数据的时候,使用uniform2f。
示例 : gl.uniform2f(uniformLocation, date1, data2);
uniform v 系列
这一系列,基本上和上面的uniform系列没有太大差别,传入的数据是数组的时候使用。和uniform系列一样,有1 ~ 4、数据类型也是在后面添加i或者f。
示例 : gl.uniform3iv(uniformLocation, Array);
uniformMatrix 系列
看名字就应该知道了,这个系列是在矩阵的时候使用。当然,矩阵不可能出现1,所以只有2 ~ 4。而且,矩阵中基本上只使用浮点型小数、所以,数据类型也不存在i,数据就是以使用数组为前提的,所以后面加不加v都是没有区别的。
示例 : gl.uniformMatrix4fv(uniformLocation, false, Matrix);
着色器,顶点数据,坐标变换矩阵等,各种准备工作都完工了,终于该写绘制命令了。
>绘制命令和刷新
// 绘制模型 gl.drawArrays(gl.TRIANGLES, 0, 3); // context的刷新 gl.flush();执行WebGL的drawArrays函数的话,模型就被绘制到了缓存中了,这里之所以说是[缓存中],是因为当执行drawArrays函数的时候,还没有把多边形绘制到画面上。
这里出现的drawArrays函数,第一个参数是指定如何使用顶点进行绘图的一个常量,第二个参数是从第几个顶点开始使用,第三个参数是绘制几个顶点。
这一次,使用的是gl.TRAIANGLES,所以顶点被当成了纯粹的三角形多边形,利用三个顶点进行了绘制。
这次的文章有点太长了,贴出的代码量有点多,可能有人会吃了一惊吧。
其实这次的代码绘制的只是一个简单的三角形。只是这样,却写了这么长的代码,所以才说3D开发是比较难的。
但是,个人认为,即使这样,和DirectX相比较的话,已经相当简单,简练了。
单从开发环境上来说,不需要特别的开发环境,WebGL这一点已经很轻松了吧。理解了本次的内容的话,只需要稍微慢慢的调整一下,就可以实现很多效果。这以后的内容,都是以这次的内容为基础的,所以必须要好好的理解一下。
本文章最后,给出本文demo的链接,如果浏览器支持的话,直接看demo比较直观吧。
那么,下次给多边形进行着色,敬请期待。
渲染三角形的demo
转载请注明:转自lufy_legend的博客http://blog.csdn.net/lufy_legend
[WebGL入门]十四,绘制多边形,布布扣,bubuko.com
标签:webgl
原文地址:http://blog.csdn.net/lufy_legend/article/details/38446243