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 相关文章推荐
Track Image Loading效果代码分析
Aug 13 Javascript
Javascript 继承机制的实现
Aug 12 Javascript
用户注册常用javascript代码
Aug 29 Javascript
Javascript 判断是否存在函数的方法
Jan 03 Javascript
JavaScript编写简单的计算器
Nov 25 Javascript
JSON格式的时间/Date(2367828670431)/格式转为正常的年-月-日 格式的代码
Jul 27 Javascript
Vue.js第三天学习笔记(计算属性computed)
Dec 01 Javascript
深入理解Angularjs向指令传递数据双向绑定机制
Dec 31 Javascript
Form表单上传文件(type="file")的使用
Aug 03 Javascript
微信小程序实现的点击按钮 弹出底部上拉菜单功能示例
Dec 20 Javascript
深入理解Vue keep-alive及实践总结
Aug 21 Javascript
JavaScript中arguments的使用方法详解
Dec 20 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中使用FFMPEG获取视频缩略图和视频总时长实例
2014/05/04 PHP
PHP使用CURL实现多线程抓取网页
2015/04/30 PHP
php获取数据库中数据的实现方法
2017/06/01 PHP
[原创]PHP global全局变量经典应用与注意事项分析【附$GLOBALS用法对比】
2019/07/12 PHP
解决extjs在firefox中关闭窗口再打开后iframe中js函数访问不到的问题
2008/11/06 Javascript
NodeJS框架Express的模板视图机制分析
2011/07/19 NodeJs
动态创建样式表在各浏览器中的差异测试代码
2011/09/13 Javascript
js禁止页面刷新与后退的方法
2015/06/08 Javascript
AngularJS基础 ng-csp 指令详解
2016/08/01 Javascript
Javascript 正则表达式校验数字的简单实例
2016/11/02 Javascript
Bootstrap源码解读网格系统(3)
2016/12/22 Javascript
原生JS实现幻灯片
2017/02/22 Javascript
js实现时间轴自动排列效果
2017/03/09 Javascript
基于BootStrap实现简洁注册界面
2017/07/20 Javascript
Angular使用Md5加密的解决方法
2017/09/16 Javascript
微信小程序自定义组件之可清除的input组件
2018/07/17 Javascript
JS+CSS+HTML实现“代码雨”类似黑客帝国文字下落效果
2020/03/17 Javascript
使用React-Router实现前端路由鉴权的示例代码
2020/07/26 Javascript
vue和H5 draggable实现拖拽并替换效果
2020/07/29 Javascript
JavaScript Dom实现轮播图原理和实例
2021/02/19 Javascript
[01:19:35]DOTA2上海特级锦标赛主赛事日 - 3 败者组第三轮#2Fnatic VS OG第二局
2016/03/05 DOTA
[01:07:19]2018DOTA2亚洲邀请赛 4.5 淘汰赛 Mineski vs VG 第一场
2018/04/06 DOTA
Python中捕捉详细异常信息的代码示例
2014/09/18 Python
利用python发送和接收邮件
2016/09/27 Python
python解决pandas处理缺失值为空字符串的问题
2018/04/08 Python
python 返回一个列表中第二大的数方法
2019/07/09 Python
python编写俄罗斯方块
2020/03/13 Python
scrapy在python爬虫中搭建出错的解决方法
2020/11/22 Python
浅析canvas元素的html尺寸和css尺寸对元素视觉的影响
2019/07/22 HTML / CSS
素质拓展感言
2014/01/29 职场文书
社会实践活动总结范文
2014/07/03 职场文书
银行授权委托书范本
2014/10/04 职场文书
小学班主任事迹材料
2014/12/17 职场文书
立项申请报告范本
2015/05/15 职场文书
2016年主题党日活动总结
2016/04/05 职场文书
Oracle 区块链表创建过程详解
2021/05/15 Oracle