[WebGL入门]十六,绘制多个模型
注意:文章翻译http://wgld.org/。原作者杉本雅広(doxas),文章中假设有我的额外说明,我会加上[lufy:],另外。鄙人webgl研究还不够深入。一些专业词语。假设翻译有误。欢迎大家指正。
本次的demo的执行结果
顶点缓存的反复利用
上一篇文章中,向多边形的三个顶点中加入了颜色这个新的顶点属性,给多边形涂抹了颜色。并且知道。使用新的VBO能够给对顶点属性进行自由的扩张。
那么。这次来挑战一下同一时候绘制多个模型。可是,不准备新的VBO。还利用上次的VBO。就是说,反复利用VBO,仅仅操作坐标变换矩阵,来绘制多个模型。
所以,这次着色器相关的内容全然不变。全然使用上次的顶点着色器和片段着色器,javascript代码变更的地方也不多,下面重点说一下变更的部分。
坐标变换矩阵的反复利用
这次绘制多个模型。坐标变换矩阵相关也是反复利用。
也就是说。在实际中。将多个模型绘制到不同的位置的时候,必须要操作的坐标变换矩阵仅仅有模型变换矩阵,而决定镜头的位置的视图变换矩阵和决定屏幕范围的投影变换矩阵这两个坐标变换矩阵,都能够使用同一个。
过程例如以下,依照下面这样操作矩阵的话就能够了。
・准备好视图和投影两个坐标变换矩阵
・提前将两个矩阵相乘并保存起来(下面、pv)
・准备第一个模型坐标变换矩阵(下面、m1)
・m1和pv相乘,传给uniform
・绘制第一个模型
・准备第二个模型坐标变换矩阵(下面、m2)
・m2和pv相乘,传给uniform
・绘制第二个模型
・刷新context
主要是。视图坐标变换矩阵和投影坐标变换矩阵提前相乘并保存起来。然后等模型坐标变换矩阵准备好之后。再与之前的结果相乘,传给uniform,然后画图。
那么。来看一下实际的代码吧。
>script.js中的部分代码
//各种矩阵的生成和初始化
var mMatrix = m.identity(m.create());
var vMatrix = m.identity(m.create());
var pMatrix = m.identity(m.create());
var tmpMatrix = m.identity(m.create());
var mvpMatrix = m.identity(m.create()); //视图x投影坐标变换矩阵
m.lookAt([0.0, 0.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, tmpMatrix); //移动第一个模型的模型坐标变换矩阵
m.translate(mMatrix, [1.5, 0.0, 0.0], mMatrix); //模型x视图x投影(第一个模型)
m.multiply(tmpMatrix, mMatrix, mvpMatrix); //将坐标变换矩阵传入uniformLocation,并画图(第一个模型)
gl.uniformMatrix4fv(uniLocation, false, mvpMatrix);
gl.drawArrays(gl.TRIANGLES, 0, 3); //移动第二个模型的模型坐标变换矩阵
m.identity(mMatrix);
m.translate(mMatrix, [-1.5, 0.0, 0.0], mMatrix); //模型x视图x投影(第二个模型)
m.multiply(tmpMatrix, mMatrix, mvpMatrix); //将坐标变换矩阵传入uniformLocation,并画图(第二个模型)
gl.uniformMatrix4fv(uniLocation, false, mvpMatrix);
gl.drawArrays(gl.TRIANGLES, 0, 3); //刷新context
gl.flush();
重点是,为了临时保存视图和投影坐标变换矩阵,新声明了一个tmpMatrix这种用法。使用matIV.multiply将视图坐标变换矩阵和投影坐标变换矩阵相乘,然后结果保存到tmpMatrix中。
然后,使用matIV.translate来操作模型坐标变换矩阵,将第一个模型向X方向移动1.5,然后将这个模型坐标变换矩阵和tmpMatrix相乘。传给uniform并进行画图。
第二个模型的坐标矩阵,和之前相反,向X方向上移动-1.5,然后和第一个一样,和tmpMatrix相乘。传给uniform并进行画图。
最后,刷新context,在canvas上绘制两个多边形。
这样。利用VBO和一部分坐标变换矩阵。省去了不必要的代码,绘制了两个多边形。
须要注意的是。对第二个模型准备模型坐标变换矩阵的时候,首先在最初的时候使用matIV.identity对矩阵进行初始化。
假设,不进行初始化直接使用matIV.translate的话。会受前一回移动的影响,导致结果改变。
进行完初始化之后再进行操作,是为了避免相似这种发生错误。
附加:attribute属性加入的函数化
上次的文章中也涉及到了,添加顶点属性的时候,假设将对应的处理函数化的话能够提高效率,尽管和这次的主题(绘制多个模型)没有关系,可是由于demo中进行了函数化。所以简单的讲解一下。
>VBO的绑定相关
// 绑定VBO相关的函数
function set_attribute(vbo, attL, attS){
// 处理从參数中得到的数组
for(var i in vbo){
// 绑定缓存
gl.bindBuffer(gl.ARRAY_BUFFER, vbo[i]); // 将attributeLocation设置为有效
gl.enableVertexAttribArray(attL[i]); //通知并加入attributeLocation
gl.vertexAttribPointer(attL[i], attS[i], gl.FLOAT, false, 0, 0);
}
}
这个函数有三个參数。三个參数都是数组。使用for ~ in来循环VBO中的属性,并进行绑定和加入。
一般,须要准备非常多个VBO,所以将这里函数化,以后能够省略非常多代码了吧。
总结
这次操作的是模型坐标变换矩阵,介绍了反复利用VBO。视图和投影坐标变换矩阵。进行多个模型的绘制的方法。
绘制非常多个简单的模型,图形的时候,像这次的做法一样。能够使处理变的简洁一些。避免写非常多多余的代码。
这次的demo,HTML的代码和上一次是全然一样的,就是说。顶点着色器和片段着色器没有做不论什么调整。
javascript代码有了一些变化,所以贴出所有代码。另外,在文章的最后面,加入了demo的链接。有支持WebGL的浏览器的话。能够直接打开链接看一下效果。
下次,进一步操作模型坐标变换矩阵,对绘制的模型进行各种各样的处理。
>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 = new Array(2);
attLocation[0] = gl.getAttribLocation(prg, 'position');
attLocation[1] = gl.getAttribLocation(prg, 'color'); // 将元素数attribute保存到数组中
var attStride = new Array(2);
attStride[0] = 3;
attStride[1] = 4; // 保存顶点的位置情报的数组
var vertex_position = [
0.0, 1.0, 0.0,
1.0, 0.0, 0.0,
-1.0, 0.0, 0.0
]; // 保存顶点的颜色情报的数组
var vertex_color = [
1.0, 0.0, 0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
0.0, 0.0, 1.0, 1.0
]; // 生成VBO
var pos_vbo = create_vbo(position);
var col_vbo = create_vbo(color); // 将VBO进行绑定并加入
set_attribute([pos_vbo, col_vbo], attLocation, attStride); // 获取uniformLocation
var uniLocation = gl.getUniformLocation(prg, 'mvpMatrix'); // 使用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 tmpMatrix = m.identity(m.create());
var mvpMatrix = m.identity(m.create()); //视图x投影坐标变换矩阵
m.lookAt([0.0, 0.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, tmpMatrix); //移动第一个模型的模型坐标变换矩阵
m.translate(mMatrix, [1.5, 0.0, 0.0], mMatrix); //模型x视图x投影(第一个模型)
m.multiply(tmpMatrix, mMatrix, mvpMatrix); //将坐标变换矩阵传入uniformLocation,并画图(第一个模型)
gl.uniformMatrix4fv(uniLocation, false, mvpMatrix);
gl.drawArrays(gl.TRIANGLES, 0, 3); //移动第二个模型的模型坐标变换矩阵
m.identity(mMatrix);
m.translate(mMatrix, [-1.5, 0.0, 0.0], mMatrix); //模型x视图x投影(第二个模型)
m.multiply(tmpMatrix, mMatrix, 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;
} // 绑定VBO相关的函数
function set_attribute(vbo, attL, attS){
// 处理从參数中得到的数组
for(var i in vbo){
// 绑定缓存
gl.bindBuffer(gl.ARRAY_BUFFER, vbo[i]); // 将attributeLocation设置为有效
gl.enableVertexAttribArray(attL[i]); //通知并加入attributeLocation
gl.vertexAttribPointer(attL[i], attS[i], gl.FLOAT, false, 0, 0);
}
} };
绘制多个模型的demo
[WebGL入门]十六,绘制多个模型的更多相关文章
- [WebGL入门]十五,为多边形涂抹颜色(顶点颜色的指定)
注:文章译自http://wgld.org/.原作者杉本雅広(doxas),文章中假设有我的额外说明,我会加上[lufy:].另外.鄙人webgl研究还不够深入.一些专业词语.假设翻译有误.欢迎大家指 ...
- [WebGL入门]十四,绘制多边形
注意:文章翻译http://wgld.org/.原作者杉本雅広(doxas),文章中假设有我的额外说明,我会加上[lufy:].另外,鄙人webgl研究还不够深入.一些专业词语,假设翻译有误,欢迎大家 ...
- [WebGL入门]十二,模型数据和顶点属性
注:文章译自http://wgld.org/,原作者杉本雅広(doxas),文章中假设有我的额外说明,我会加上[lufy:].另外.鄙人webgl研究还不够深入,一些专业词语.假设翻译有误.欢迎大家指 ...
- [WebGL入门]十九,遮挡剔除和深度測试
注:文章译自http://wgld.org/,原作者杉本雅広(doxas),文章中假设有我的额外说明,我会加上[lufy:],另外.鄙人webgl研究还不够深入,一些专业词语,假设翻译有误.欢迎大家指 ...
- [WebGL入门]十八,利用索引缓存来画图
注:文章译自http://wgld.org/.原作者杉本雅広(doxas),文章中假设有我的额外说明.我会加上[lufy:].另外,鄙人webgl研究还不够深入,一些专业词语,假设翻译有误,欢迎大家指 ...
- 《Java并发编程实战》第十六章 Java内存模型 读书笔记
Java内存模型是保障多线程安全的根基,这里不过认识型的理解总结并未深入研究. 一.什么是内存模型,为什么须要它 Java内存模型(Java Memory Model)并发相关的安全公布,同步策略的规 ...
- [WebGL入门]十,矩阵计算和外部库
注:文章译自http://wgld.org/,原作者杉本雅広(doxas),文章中假设有我的额外说明,我会加上[lufy:],另外,鄙人webgl研究还不够深入,一些专业词语,假设翻译有误,欢迎大家指 ...
- java并发编程实战:第十六章----Java内存模型
一.什么是内存模型,为什么要使用它 如果缺少同步,那么将会有许多因素使得线程无法立即甚至永远看到一个线程的操作结果 编译器把变量保存在本地寄存器而不是内存中 编译器中生成的指令顺序,可以与源代码中的顺 ...
- 前端(十六)—— JavaScript盒子模型、JS动画、DOM、BOM
JS盒子模型.JS动画.DOM.BOM 一.JS盒模型 1.width | height parseInt(getComputedStyle(ele, null).getPropertyValue(' ...
随机推荐
- http报错之return error code:401 unauthorized
http报错之return error code:401 unauthorized 依据HTTP返回码所表示的意思应该是未授权,没有输入账号和password,因此解决方法就直接在HTTP包里面 ...
- JDK的dt.jar和Java BeanInfo接口
在JAVA_HOME/lib以下有两个比較重要的jar文件.tools.jar和dt.jar. tools.jar在上篇文章中做了简单的介绍.这里来介绍下dt.jar. 在Oracle官方站点搜dt. ...
- DFT 展开式和 FFT推导
C语言的FFT //---------------------------------------------------------------------------------- //----- ...
- Web 前端开发环境
创建 Web 前端开发环境 Web 前端开发涉及多种工具,这里将常用工具的安装和配置进行说明,提供了详细的说明,为后继的开发创建一个坚实的基础. 本文介绍的工具有:NodeJS, NPM, Bower ...
- Redis源代码分析(十)--- testhelp.h小测试框架和redis-check-aof.c
日志检测
周期分析struct结构体redis代码.最后,越多越发现很多的代码其实大同小异.于struct有袋1,2不分析文件,关于set集合的一些东西,就放在下次分析好了,在选择下个分析的对象时,我考虑了一下 ...
- Unity模拟龙之谷人物行走简单控制
我个人挺喜欢龙之谷(DN)的人物控制的(不是广告哈....),就是人物太萌了一点,动作.打击感都挺好的. 今天用Unity简单模仿了一下DN的人物控制,当然,游戏里面动作非常多,我这里仅仅做了简单的w ...
- quick-cocos2d-x游戏开发【6】——制作您自己的自定义效果button菜单
前面提到的主菜单使用,还是很easy的,但我们在商业产品.经常看到button他们人很好,照片不仅就好了,和动画也很不错.Candy Crash都玩过吧,他们看到,button.真的像果冻,效果确实非 ...
- MVC基本概念和流程
MVC基本概念和流程 MVC的概念 Model(模型):包含数据和行为.不过现在一般都分离开来:Value Object(数据) 和 服务层(行为). View(视图):负责进行模型的展示,一般就是展 ...
- NYoj 素数环(深搜入门)
题目链接: http://acm.nyist.edu.cn/JudgeOnline/problem.php?pid=488 深搜模板: void dfs(int 当前状态) { if(当前状态为边界状 ...
- VS解决方案创建
示例VS解决方案的创建(一) 进行项目开发的第一步,是创建出适合自己团队习惯的VS解决方案,虽然我已经提供了项目示例,但毕竟是我创建的,你直接使用可能并不合适,另外你如果尝试模仿重新创建该示例,中 ...