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的Cookies
Jan 16 Javascript
JS实现的省份级联实例代码
Jun 24 Javascript
jquery实现多级下拉菜单的实例代码
Oct 02 Javascript
jQuery遍历对象、数组、集合实例
Nov 08 Javascript
js控制div弹出层实现方法
May 11 Javascript
JavaScript实现基于十进制的四舍五入实例
Jul 17 Javascript
不能不知道的10个angularjs英文学习网站
Mar 23 Javascript
JavaScript中数组常见操作技巧
Sep 01 Javascript
记一次webapck4 配置文件无效的解决历程
Sep 19 Javascript
vue input实现点击按钮文字增删功能示例
Jan 29 Javascript
详解vue中的父子传值双向绑定及数据更新问题
Jun 13 Javascript
VUE子组件向父组件传值详解(含传多值及添加额外参数场景)
Sep 01 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
咖啡磨器 如何选购一台适合家用的意式磨豆机
2021/03/05 新手入门
php中的PHP_EOL换行符详细解析
2013/10/26 PHP
php+js实现异步图片上传实例分享
2014/06/02 PHP
PHP针对JSON操作实例分析
2015/01/12 PHP
浅谈Coreseek、Sphinx-for-chinaese、Sphinx+Scws的区别
2016/12/15 PHP
PHP+Ajax简单get验证操作示例
2019/03/02 PHP
ThinkPHP6.0如何利用自定义验证规则规范的实现登陆
2020/12/16 PHP
可输入的下拉框
2006/06/19 Javascript
Javascript 判断客户端浏览器类型代码
2010/03/01 Javascript
JS非Alert实现网页右下角“未读信息”效果弹窗
2015/09/26 Javascript
JavaScript原型及原型链终极详解
2016/01/04 Javascript
浅谈Emergence.js 检测元素可见性的 js 插件
2017/11/18 Javascript
解决Vue2.x父组件与子组件之间的双向绑定问题
2018/03/06 Javascript
vue.js实现标签页切换效果
2018/06/07 Javascript
详解vue-cli3多页应用改造
2019/06/04 Javascript
Postman动态获取返回值过程详解
2020/06/30 Javascript
vue $mount 和 el的区别说明
2020/09/11 Javascript
跟老齐学Python之通过Python连接数据库
2014/10/28 Python
python使用mailbox打印电子邮件的方法
2015/04/30 Python
Python PyAutoGUI模块控制鼠标和键盘实现自动化任务详解
2018/09/04 Python
python如何制作缩略图
2019/04/30 Python
分享8点超级有用的Python编程建议(推荐)
2019/10/13 Python
Python使用jpype模块调用jar包过程解析
2020/07/29 Python
HTML5移动端开发中的Viewport标签及相关CSS用法解析
2016/04/15 HTML / CSS
美国面料纺织品商城:Fabric.com
2017/06/28 全球购物
SEPHORA丝芙兰德国官方购物网站:化妆品、护肤品和香水
2020/01/21 全球购物
几个常见的消息中间件(MOM)
2014/01/08 面试题
护士自我鉴定怎么写
2014/02/07 职场文书
大队委竞选演讲稿
2014/04/28 职场文书
领导班子专题民主生活会情况想汇报
2014/09/30 职场文书
商务考察邀请函模板
2015/02/02 职场文书
开除通知书范本
2015/04/25 职场文书
开票证明
2015/06/23 职场文书
2016简历自荐信优秀范文
2016/01/29 职场文书
SpringBoot整合Minio文件存储
2022/04/03 Java/Android
SQL Server2019安装的详细步骤实战记录(亲测可用)
2022/06/10 SQL Server