THREE.JS入门教程(1)THREE.JS使用前了解


Posted in Javascript onJanuary 24, 2013

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

国外网站 aerotwist.com 有六篇较为简单的入门教程,我尝试着将其翻译过来,与大家分享。
我在一些实验项目中使用了Three.js,我发现它对快速上手浏览器3D编程确实很有帮助。通过Three.js,你不仅可以创建相机、物体、光线、材质等等,还可以选择着色器,可以决定使用何种技术(WebGL、Canvas或SVG)在网页上渲染你的3D图形。Three.js是开源的,你甚至可以参与到这个项目中来。但现在,我将把重点放在基础的介绍上,我将向你展示如何使用这个引擎上。

尽管Three.js如此奇妙,但有时候它也会令人抓狂。比如,你将花费大量时间阅读例程,做一些逆向工程(在我的情形下)来确定某个函数的作用,有时还要去GitHub上提问。如果你需要提问,Mr. doob和AlteredQualia是极好的选择。

1.基础
我假定你的三维图形学知识过关,而且也在一定程度上掌握了JavaScript。如果不是这样,那先去学一点吧,否则直接看这篇教程,也许会感到困惑。

在我们的三维世界里,我们有以下这些东西。我会带你一步一步创建它们。
1.场景
2.渲染器
3.相机
4.物体(带有材质的)
当然,你也可以创造些其他的什么东西,我也希望你如此做。
2.浏览器支持
简单地看一下浏览器的支持情况吧。Google家的Chrome浏览器支持Three.js,在我的实验里,无论是对渲染器的支持程度还是JavaScript解释器的运行速度,Chrome都是做得最好的:它支持Canvas、WebGL和SVG,而且运行得非常快。FireFox浏览器排在第二位,它的JavaScript引擎的速度比Chrome慢了半拍,但是对渲染器的支持也很棒,而且FireFox的速度,随着版本更新也越来越快。Opera浏览器正在逐渐增加对WebGL的支持,Mac上的Safari浏览器有一个开启WebGL的选项。总体上,这两个浏览器仅仅支持Canvas渲染。微软家的IE9现在只支持Canvas渲染,而且微软似乎并不乐意支持WebGL这个新特性,所以我们现在肯定不会用IE9来做实验。
3.设置场景
假定你已经选择了一个支持所有渲染技术的浏览器,而且你准备通过Canvas或WebGL来渲染场景(这是更标准化的选择)。Canvas比WebGL有着更广泛地支持,但是WebGL可以直接在GPU上操作,这意味着你的CPU可以专注地处理非渲染类的工作,比如物理引擎或与用户交互等。

无论你选择何种渲染器,你都必须牢记在心的是:JavaScript代码需要优化。三维显示对浏览器来说不是一项轻松的工作(现在能够这样做就很伟大了),所以如果你的渲染太慢了,你需要知道你代码的瓶颈在何处,如果可能,改善它。

说了这么多,我想你已经下载好Three.js源代码,而且将它引入了你的html文档了。那么如何开始创建一个场景呢?就像这样:

// 设置场景大小 
var WIDTH = 400, 
HEIGHT = 300; 
// 设置一些相机参数 
var VIEW_ANGLE = 45, 
ASPECT = WIDTH / HEIGHT, 
NEAR = 0.1, 
FAR = 10000; 
// 获取DOM结构中的元素 
// - 假设我们使用了JQuery 
var $container = $('#container'); 
// 创建渲染器、相机和场景 
var renderer = new THREE.WebGLRenderer(); 
var camera = 
new THREE.PerspectiveCamera( 
VIEW_ANGLE, 
ASPECT, 
NEAR, 
FAR); 
var scene = new THREE.Scene(); 
// 将相机加入场景 
scene.add(camera); 
// 相机的初始位置为原点 
// 将相机拉回来一些(译者注:这样才能看到原点) 
camera.position.z = 300; 
// 启动渲染器 
renderer.setSize(WIDTH, HEIGHT); 
// 将渲染器加到DOM结构中 
$container.append(renderer.domElement);

你看,简单吧!
4.构建网格表面
现在我们有了一个场景,一个相机和一个渲染器(在我的例子里,当然是一个WebGL渲染器),但我们事实上什么还没画呢。事实上,Three.js提供了载入某几种标准格式3D文件的支持,如果你在Blender,Maya,Cinema4D或是什么其他工具中建模,这简直太棒了。为了简单(毕竟这才刚开始呢!)我们先来考虑基元。基元就是基本的几何表面,比如最基本的球体、平面、立方体、圆柱体。利用Three.js可以很方便地创建这些基元:
// 设置球体参数(译者注:球体被划分为16×16的网格,如果后两个参数取4、2,则生成一个八面体,请想象) 
var radius = 50, 
segments = 16, 
rings = 16; 
// material覆盖在geometry上,生成mesh 
var sphere = new THREE.Mesh( 
new THREE.SphereGeometry( 
radius, 
segments, 
rings), 
sphereMaterial); 
// 将mesh加入到场景中 
scene.add(sphere);

好了,但是球体上的材质呢?在代码中我们使用了一个sphereMaterial变量,我们还没定义它呢。那我们就先来看看怎么创建材质吧。
5.材质
毫无疑问,这是Three.js最有用的部分了。这部分提供了几个非常易用的通用材质模型:
1.Basic材质:表示一种不考虑光照的材质,现在只能这么说了。
2.Lambert材质:(译者注:朗伯面,各向同性反射)。
3.Phong材质:(译者注:冯氏面,有光泽的表面,介于镜面反射和朗伯反射之间的反射,描述真实世界的反射)。

除此之外,还有一些其他类型材质,简单起见,就留给你自己探索。事实上,在使用WebGL类型的渲染器时,材质实在太好用了。为什么呢?因为在原生WebGL种你必须亲自为每个渲染编写着色器,而着色器本身就是个巨大的工程:简单地说着色器是使用GLSL语言(OpenGL的着色器语言)写的,用来操作GPU的程序,这意味着你要在数学上模拟光照,反射等等,这很快就变成一项极为复杂的工作。多亏有了Three.js你才可以不必去自己编写着色器,当然,如果你想亲自编写的话,你可以使用MeshShaderMaterial,可见这是很灵活的设定。

现在,让我们用朗伯面材质覆盖球体:

// 创建球体表面的材质 
var sphereMaterial = 
new THREE.MeshLambertMaterial( 
{ 
color: 0xCC0000 
});

值得指出的是,创建材质的时候,除了颜色还有很多其他参数可以指定,比如光滑度和环境贴图。你可以需要检索这个Wiki页面来确认哪些是哪些属性可以设置在材质上,或Three.js引擎提供的任何对象上。
6.光
如果你现在就想渲染场景,你会看到一个红色的圆。虽然我们在球体上覆盖了朗伯面材质,但场景里没有光。所以按照默认设定,Three.js会恢复到满环境光,物体的看上去的颜色就是物体表面的颜色。让我们添加一个简单的点光源:
// 创建一个点光源 
var pointLight = 
new THREE.PointLight(0xFFFFFF); 
// 设置点光源的位置 
pointLight.position.x = 10; 
pointLight.position.y = 50; 
pointLight.position.z = 130; 
// 将点光源加入场景 
scene.add(pointLight);

7.渲染循环
显然,关于渲染器的一切都设置好了。万事俱备,我们现在只需要:
// 画! 
renderer.render(scene, camera);

你很可能像多次渲染,而不是只渲染一次,所以如果你要去做一个循环,你应该使用requestAnimationFrame。这是目前最好的,在浏览器中处理动画的方法,虽然还没有得到最全面的支持,但我强烈建议你去看一看Paul Irish的博客。
8.通用的对象属性
如果你花点时间去浏览一遍Three.js的源代码,你会发现很多对象都继承自Object3D。这个基类包含了很多有用的属性,比如位置、旋转和缩放的信息。特别的,我们的球体是一个Mesh对象,而Mesh对象继承自Object3D对象,但是又增加了些自己的属性:geometry和material。为什么要说这些?因为你一定不会只满足于屏幕中一个什么都不做的圆球,而这些(译者注:基类中的)属性允许你操作Mesh对象更底层的细节和各种各样的材质。
// sphere是一个mesh对象 
sphere.geometry 
// sphere包含了一些点和面的信息 
sphere.geometry.vertices // 一个数组 
sphere.geometry.faces // 另一个数组 
// mesh对象继承自object3d对象 
sphere.position // 包含x,y,z 
sphere.rotation // 同上 
sphere.scale // ... 同上

9.讨厌的秘密
我希望这样说你能很快弄明白:就是如果你修改了,比如说,一个mesh对象的顶点属性vertices,你会发现在渲染循环中,什么都没变。为什么?因为Three.js将mesh对象的信息缓存为某种优化结构了。你真正要做的是给Three.js一个标识,告诉它如果什么东西改变了,需要重新计算缓存中的结构:
// 设置geometry为动态的,这样才允许改变其中的顶点 
sphere.geometry.dynamic = true; 
// 告诉Three.js,需要重新计算顶点 
sphere.geometry.__dirtyVertices = true; 
// 告诉Three.js,需要重新计算顶点 
sphere.geometry.__dirtyNormals = true;

还有更多的标识,但我发现这两个是最有用的。你应该仅仅标识那些确实需要实时计算的属性来避免无谓的运算开销。
10.小结
我希望这篇简单的介绍对你有所帮助。没什么能比得上卷起袖子亲手实践了,我强烈建议你这样做。在浏览器里面运行3D程序很有意思,而且使用像Three.js这样一个引擎免去了很多麻烦,让你一开始就能专注于那些真正cool的事情。

我将这篇教程的源码打包了,你可以下载下来作为一份参考。

Javascript 相关文章推荐
Javascript 网页黑白效果实现代码(兼容IE/FF等)
Apr 23 Javascript
用JS实现3D球状标签云示例代码
Dec 01 Javascript
node.js中的console.assert方法使用说明
Dec 10 Javascript
jQuery实现表单提交时判断的方法
Dec 13 Javascript
JQuery实现鼠标移动图片显示描述层的方法
Jun 25 Javascript
基于jquery实现省市区三级联动效果
Dec 25 Javascript
Backbone.js框架中Model与Collection的使用实例
May 07 Javascript
使用svg实现动态时钟效果
Jul 17 Javascript
JavaScript捕捉事件和阻止冒泡事件实例分析
Aug 03 Javascript
详解TypeScript+Vue 插件 vue-class-component的使用总结
Feb 18 Javascript
解决ant Design中Select设置initialValue时的大坑
Oct 29 Javascript
解决Mint-ui 框架Popup和Datetime Picker组件滚动穿透的问题
Nov 04 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
javascript游戏开发之《三国志曹操传》零部件开发(一)让静态人物动起来
Jan 23 #Javascript
You might like
全国FM电台频率大全 - 12 安徽省
2020/03/11 无线电
Cygwin中安装PHP方法步骤
2015/07/04 PHP
PHP基于自定义函数实现的汉字转拼音功能实例
2017/09/30 PHP
PHP实现基于图的深度优先遍历输出1,2,3...n的全排列功能
2017/11/10 PHP
jquery tools系列 expose 学习
2009/09/06 Javascript
jQuery示例收集
2010/11/05 Javascript
浅谈jQuery异步对象(XMLHttpRequest)
2014/11/17 Javascript
js中取得变量绝对值的方法
2015/01/03 Javascript
jquery实现移动端点击图片查看大图特效
2020/09/11 Javascript
javascript实现数组去重的多种方法
2016/03/14 Javascript
js关于getImageData跨域问题的解决方法
2016/10/14 Javascript
javascript判断firebug是否开启的方法
2016/11/23 Javascript
Bootstrap select下拉联动(jQuery cxselect)
2017/01/04 Javascript
node.js实现复制文本到剪切板的功能
2017/01/23 Javascript
JavaScript使用math.js进行精确计算操作示例
2018/06/19 Javascript
node app 打包工具pkg的具体使用
2019/01/17 Javascript
JS把字符串格式的时间转换成几秒前、几分钟前、几小时前、几天前等格式
2019/07/10 Javascript
jQuery实现可编辑的表格
2019/12/11 jQuery
[02:27]2018DOTA2亚洲邀请赛趣味视频之钓鱼大赛 谁是垂钓冠军?
2018/04/05 DOTA
Python 将RGB图像转换为Pytho灰度图像的实例
2017/11/14 Python
python通过Windows下远程控制Linux系统
2018/06/20 Python
python感知机实现代码
2019/01/18 Python
Python3列表内置方法大全及示例代码小结
2019/05/10 Python
Python random模块制作简易的四位数验证码
2020/02/01 Python
关于多元线性回归分析——Python&SPSS
2020/02/24 Python
Python matplotlib模块及柱状图用法解析
2020/08/10 Python
python 爬取B站原视频的实例代码
2020/09/09 Python
Myprotein法国官网:欧洲第一运动营养品牌
2019/03/26 全球购物
应届毕业生求职信范文
2013/12/18 职场文书
社团文化节邀请函
2014/01/10 职场文书
2015年行政助理工作总结
2015/04/30 职场文书
出纳试用期工作总结2015
2015/05/28 职场文书
首席执行官观后感
2015/06/03 职场文书
外科护士长工作总结
2015/08/12 职场文书
spring boot项目application.properties文件存放及使用介绍
2021/06/30 Java/Android
Python OpenCV之常用滤波器使用详解
2022/04/07 Python