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中的prototype属性实例分析说明
Aug 09 Javascript
javascript 原型继承介绍
Aug 30 Javascript
基于JQuery实现滚动到页面底端时自动加载更多信息
Jan 31 Javascript
javascript手工制作悬浮菜单
Feb 12 Javascript
JS实现的自定义显示加载等待图片插件(loading.gif)
Jun 17 Javascript
bootstrap PrintThis打印插件使用详解
Feb 20 Javascript
详解基于 axios 的 Vue 项目 http 请求优化
Sep 04 Javascript
浅谈Vue.js 组件中的v-on绑定自定义事件理解
Nov 17 Javascript
判断jQuery是否加载完成,没完成继续判断的解决方法
Dec 06 jQuery
简单的Vue异步组件实例Demo
Dec 27 Javascript
使用JavaScript保存文本文件到本地的两种方法
Jan 22 Javascript
vue 将多个过滤器封装到一个文件中的代码详解
Sep 05 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-timeit估计php函数的执行时间
2015/09/06 PHP
php 无限级分类 获取顶级分类ID
2016/03/13 PHP
[原创]PHP字符串中插入子字符串方法总结
2016/05/06 PHP
javascript生成/解析dom的CDATA类型的字段的代码
2007/04/22 Javascript
Mootools 1.2教程 事件处理
2009/09/15 Javascript
JavaScript去掉空格的方法集合
2010/12/28 Javascript
随窗体滑动的小插件sticky源码
2013/06/21 Javascript
输入自动提示搜索提示功能的javascript:sugggestion.js
2013/09/02 Javascript
Javascript中this的用法详解
2014/09/22 Javascript
最全面的JS倒计时代码
2016/09/17 Javascript
Vue生命周期示例详解
2017/04/12 Javascript
详谈js模块化规范
2017/07/07 Javascript
react-native DatePicker日期选择组件的实现代码
2017/09/12 Javascript
详解ES6 Promise对象then方法链式调用
2018/10/20 Javascript
vue.js多页面开发环境搭建过程
2019/04/24 Javascript
解决vue无法侦听数组及对象属性的变化问题
2020/07/17 Javascript
Python实现在matplotlib中两个坐标轴之间画一条直线光标的方法
2015/05/20 Python
linux下python抓屏实现方法
2015/05/22 Python
用Python写王者荣耀刷金币脚本
2017/12/21 Python
python开启debug模式的方法
2019/06/27 Python
python实现BP神经网络回归预测模型
2019/08/09 Python
Python list运算操作代码实例解析
2020/01/20 Python
Python 生成VOC格式的标签实例
2020/03/10 Python
Python3实现英文字母转换哥特式字体实例代码
2020/09/01 Python
python 实现围棋游戏(纯tkinter gui)
2020/11/13 Python
Python3 用matplotlib绘制sigmoid函数的案例
2020/12/11 Python
工程师自我评价怎么写
2013/09/19 职场文书
教育系毕业生中文求职信范文
2013/10/06 职场文书
仓库理货员岗位职责
2013/12/18 职场文书
党员干部廉洁承诺书
2014/05/28 职场文书
关于运动会的广播稿50字
2014/10/17 职场文书
2015年反腐倡廉工作总结
2015/05/14 职场文书
2016庆祝教师节新闻稿
2015/11/25 职场文书
pytorch 预训练模型读取修改相关参数的填坑问题
2021/06/05 Python
Centos系统通过Docker安装并搭建MongoDB数据库
2022/04/12 MongoDB
Vue Element plus使用方法梳理
2022/12/24 Vue.js