THREE.JS入门教程(2)着色器-上


Posted in Javascript onJanuary 24, 2013

译序
Three.js是一个伟大的开源WebGL库,WebGL允许JavaScript操作GPU,在浏览器端实现真正意义的3D。但是目前这项技术还处在发展阶段,资料极为匮乏,爱好者学习基本要通过Demo源码和Three.js本身的源码来学习。

0.简介
之前我已经给出了一篇《开始使用Three.js》。如果你还没有读过,你可能需要去读一下,本文的基础是在那一篇教程的基础上完成的。

我想讨论一下着色器。在Three.js帮助你免去了很多麻烦之前,原生WebGL就很优秀了。有的时候,你也许会想要完成一些特定的效果,或者想对呈现在你的屏幕上的东西钻研得更深入一些,那么着色器一定会进入你的视野。如果你像我一样,你也同样希望实现一些比上一篇教程中的基础更加有意思的东西。这篇教程中,我会讲解Three.js的基础,这些基础实际上为我们做了很多枯燥的工作。
在开始之前我还要说,这篇教程会有相当多的篇幅在解释着色器的代码,之后会有一篇教程会在着色器代码的基础上前进一点,利用着色器去做点什么。这是因为着色器shaders第一眼看上去并不易懂,需要一些解释。
1.两种着色器
WebGL没有固定的渲染管线,你无法直接使用一个黑盒子式的着色器(译者注:上个世纪的显卡基本都只支持固定渲染管线);WebGL提供的是可编程的管线,这种方式更强大但也更难理解和使用。长话短说,可编程渲染管线意味着编写程序的人要自己负责获取顶点并将它绘制在屏幕上了。着色器是渲染管线的一部分,有两种着色器:
1.顶点着色器
2.片元着色器
你应当知道的是,这两种着色器都完全运行在显卡的GPU上,我们将需要它们处理的数据从CPU上卸下,装到GPU上,减轻了CPU的复旦。现代的GPU对着色器需要的调用的运算类型都做了大幅优化,这样做很值得。
2.顶点着色器
基元形状,比如一个球体,是由顶点构成的,是吧?顶点着色器被依次传入这些顶点中的一个顶点,然后处理它。如何处理每个顶点是可以自由定制的,但顶点着色器有一个必做的事,就是为一个名为 gl_Position 的变量赋值,该变量是一个4维数组,表示该顶点最终在屏幕上的位置。这本身是个有意思的过程,因为我们实际上在谈论如何将一个三维坐标(一个具有x、y、z值得顶点)转化为,或者说投影到二维的屏幕上。谢天谢地,要是我们使用Three.js之类的工具,我们能够如此方便地访问到 gl_Position 。
3.片元着色器
现在我们有包含顶点的三维物体了,现在要将物体投影到二维屏幕上了,但颜色哪里去了?纹理和光照呢?这正是片元着色器要处理的。
和顶点着色器类似,片元着色器有一项必须完成的任务:设置或消除变量 gl_FragColor ,另一个四维浮点变量,也就是片元点最终的颜色。什么是片元?想象一个具有三个顶点的三角形,片元就是经过这三个顶点计算后的,所有在三角形内部的点。因此,片元值由顶点的值内插生成。如果一个顶点的颜色是红色,相邻顶点的颜色是蓝色,那么我们可以观测到颜色从红色顶点附近渐变,由红色变成紫色,最终在蓝色顶点附近变成蓝色。
4.着色器变量
说到着色器变量,有三种:Uniforma,Attributes和Varyings。当我第一次听到这三个词语时,我很困惑,因为它们和我之前用到的东西完全不匹配。但现在,你可以这样理解它们:
1.Uniforms变量既可以传入顶点着色器,也可以传入片元着色器,它们包含了哪些在整个渲染过程中保持不变的变量,比如,一个点光源的位置。
2.Attributes变量对应于每个顶点,它们只可以传入顶点着色器中,比如每个顶点都具有一个颜色。Attributes变量和顶点的关系是一一对应的。
3.Varyings变量是在顶点着色器中定义,并且准备传入给片元着色器的变量。为了确保这点,我们需要确保在两个着色器中变量的类型和命名完全一致。一个经典的应用是法线向量,因为在计算光照的时候需要用到法线。
在后面一篇教程中,我会使用这三种变量,你也会学习到这三种变量如何真正应用起来得。
现在,我们已经谈过了顶点着色器、片元着色器和三种着色器变量。是时候来看一个我们可以创建的最简单的着色器了。
5.Hello World(译者吐槽:能不能不要秀法语啊)
这儿有一个最简单的顶点着色器:

/** 
* 每个顶点坐标乘以模型视图矩阵在乘以投影矩阵 
* 获得在二维屏幕上的坐标 
*/ 
void main() { 
gl_Position = projectionMatrix * 
modelViewMatrix * 
vec4(position,1.0); 
}

一个最简单的片元着色器:
/** 
* 将任意一个像元色设置为粉红 
*/ 
void main() { 
gl_FragColor = vec4(1.0, // R 
0.0, // G 
1.0, // B 
1.0); // A 
}

这就是全部了。如果现在直接运行的话,你就可以在屏幕上看到一个“无光”的粉红色形体。不是很复杂,是吗?

在顶点着色器中,我们通过Three.js传入了一些uniforms变量。有两个4×4的矩阵uniforms变量:模型视图矩阵和投影矩阵。你并不需要太了解这两个矩阵是怎么工作的。简单地说,这两个矩阵描述了三维点坐标如何投影成为二维屏幕上的坐标。

事实上,我只介绍了这两段简短的代码段。Three.js在你自己的着色器代码前已经将它们加进来了,所以你不必担心。实话说,Three.js还加了很多东西在你的代码前面,比如光照数据、节点颜色和节点法向量等等。如果没有Three.js你要亲自创建并设置这些对象,真的。
6.使用着色器材质

/** 
* 假设我们可以使用JQuery 
* 将着色器的代码文本从DOM中抽取出来 
*/ 
var vShader = $('vertexshader'); 
var fShader = $('fragmentshader'); 
var shaderMaterial = 
new THREE.ShaderMaterial({ 
vertexShader: vShader.text(), 
fragmentShader: fShader.text() 
});

从这儿开始,Three.js将会编译并运行你的着色器,将其连接在你创建的材质上,材质又依附于你创建的mesh上。它并没有变得比真的更容易。也许是这样吧,但我们在考虑浏览器3D编程,我想你应该预期,这个话题是有一定复杂性的。

我们还可以像着色器材质添加另外两种属性:uniforms和attributes。他们可以是向量、整数或者浮点数,但是如我之前所说,uniforms变量在计算所有点的过程中保持不变,所以它们更加可能是单一的值,而attributes变量是对每个顶点而言的,所以他们应当是数组。在一个mesh中,attribute变量和顶点应当是一一对应的。
7.小结
这篇教程就到这里了,实际上我已经讲得很多了,但是在许多方面我都只是一掠而过。在下一篇教程中我会提供一个复杂的着色器,通过它我将传入一些attributes变量和uniforms变量来做一些模拟光照效果。
我将这篇教程的源码打包了,你可以下载下来作为参考

Javascript 相关文章推荐
JavaScript判断DOM何时加载完毕的技巧
Nov 11 Javascript
jquery获取iframe中的dom对象(两种方法)
Jul 02 Javascript
JQuery each打印JS对象的方法
Nov 13 Javascript
Knockout visible绑定使用方法
Nov 15 Javascript
JS实现将人民币金额转换为大写的示例代码
Feb 13 Javascript
script标签属性用type还是language
Jan 21 Javascript
Javascript对象Clone实例分析
Jun 09 Javascript
JavaScript贪吃蛇小组件实例代码
Aug 20 Javascript
vue和webpack项目构建过程常用的npm命令详解
Jun 15 Javascript
layerUI下的绑定事件实例代码
Aug 17 Javascript
解决ng-repeat产生的ng-model中取不到值的问题
Oct 02 Javascript
JS实现斐波那契数列的五种方式(小结)
Sep 09 Javascript
THREE.JS入门教程(1)THREE.JS使用前了解
Jan 24 #Javascript
(跨浏览器基础事件/浏览器检测/判断浏览器)经验代码分享
Jan 24 #Javascript
jQuery ajax(复习)—Baidu ajax request分离版
Jan 24 #Javascript
javascript游戏开发之《三国志曹操传》零部件开发(五)可移动地图的实现
Jan 23 #Javascript
javascript游戏开发之《三国志曹操传》零部件开发(四)用地图块拼成大地图
Jan 23 #Javascript
javascript游戏开发之《三国志曹操传》零部件开发(三)情景对话中仿打字机输出文字
Jan 23 #Javascript
javascript游戏开发之《三国志曹操传》零部件开发(二)人物行走的实现
Jan 23 #Javascript
You might like
PHP信号量基本用法实例详解
2016/02/12 PHP
去除链接虚线全面分析总结
2006/08/15 Javascript
js确定对象类型方法
2012/03/30 Javascript
Dom 学习总结以及实例的使用介绍
2013/04/24 Javascript
原生javaScript做得动态表格(注释写的很清楚)
2013/12/29 Javascript
extjs 如何给column 加上提示
2014/07/29 Javascript
如何判断微信内置浏览器(通过User Agent实现)
2014/09/01 Javascript
jQuery中data()方法用法实例
2014/12/27 Javascript
js实现从数组里随机获取元素
2015/01/12 Javascript
jQuery实现向下滑出的平滑下拉菜单效果
2015/08/21 Javascript
基于jQuery实现美观且实用的倒计时实例代码
2015/12/30 Javascript
轻松掌握JavaScript中的Math object数学对象
2016/05/26 Javascript
AngularJs $parse、$eval和$observe、$watch详解
2016/09/21 Javascript
jQuery轻松实现无缝轮播效果
2017/03/22 jQuery
原生js封装自定义滚动条
2017/03/24 Javascript
JavaScript数据结构中栈的应用之表达式求值问题详解
2017/04/11 Javascript
详解React Native顶|底部导航使用小技巧
2017/09/14 Javascript
快速解决处理后台返回json数据格式的问题
2018/08/07 Javascript
Vue自动构建发布脚本的方法示例
2020/07/24 Javascript
python3利用smtplib通过qq邮箱发送邮件方法示例
2017/12/03 Python
python绘制简单彩虹图
2018/11/19 Python
python如何查看安装了的模块
2020/06/23 Python
解析python 类方法、对象方法、静态方法
2020/08/15 Python
python中time、datetime模块的使用
2020/12/14 Python
H5调用相机拍照并压缩图片的实例代码
2017/07/20 HTML / CSS
萨克斯第五大道精品百货店: Saks Fifth Avenue
2017/04/28 全球购物
加拿大折扣、优惠券和交易网站:WagJag
2018/02/07 全球购物
幼儿园招生广告
2014/03/19 职场文书
感恩老师演讲稿400字
2014/08/28 职场文书
标准大学生职业生涯规划书写作指南
2014/09/18 职场文书
科学育儿宣传标语
2014/10/08 职场文书
匿名信格式范文
2015/05/27 职场文书
2016年“世界环境日”校园广播稿
2015/12/18 职场文书
2016年感恩教师节校园广播稿
2015/12/18 职场文书
解决pycharm下载库时出现Failed to install package的问题
2021/09/04 Python
《游戏王:大师决斗》将推出新卡牌包4月4日上线
2022/03/31 其他游戏