转载自自己的独立博客,
请使用支持webgl的浏览器,猛点这里看效果。
three.js是一款轻量级的3d库,能帮我等屌丝轻松的在浏览器上过一把3d瘾。最早被吸引到是因为这个范例(见下图)
好吧。。。无话可说了。。。
我昨晚学习的时候参照的教程在这里,当然也改动扩展了不少地方。这里权当作个翻译加解说,能力有限,有错随便揪。
1、基础
原文中假设读者对3d有一定了解。但是很明显由我的实践证明这并不是必须的。。。不过你最起码得知道xyz三个坐标之类的神马的吧。。
这个教程将会带领着你来一起创建:
- 一个scene(场景)
- 一个renderer(渲染器)
- 一个camera(摄像机)
- 一或两个object(带material(材质))
2、浏览器支持
原教程建议使用chrome浏览器,我也是chrome控,哈哈。今天注意到ipad版的uc浏览器也支持WebGL,无奈事件模型不一样,没办法在ipad上看自己的成果了。。
3、布置scene
这里简要说一下,canvas渲染方式应用范围相对更加广,但这优势相对于WebGL能够用到硬件加速的能力来说弱爆了。
无论如何,3D的工作对浏览器来说可跟“轻量”一点边都沾不上,单单能在浏览器中运行这一点就已经够碉堡了。所以最好注意你代码中的性能瓶颈,能把它们排除掉的话就更好。
一些准备工作:下载好three.js,下载好jquery。
这里的three.js足有70多mb,因为里面包含了很多的范例、文档和一大堆东西。
创建index.html:
- <!doctype html>
- <html>
- <head>
- <meta charset=“utf-8″ />
- <title>Alan的实验室</title>
- <style type=“text/css”>
- body {
- padding: 0;
- margin: 0;
- overflow: hidden;
- }
- </style>
- </head>
- <body>
- <div id=“container”></div>
- </body>
- <script src=“./js/jquery.min.js”></script>
- <script src=“./js/three/three.min.js”></script>
- <script src=“./js/three/fonts/helvetiker_bold.typeface.js”></script>
- <script src=“./js/lalalalademaxiya.js”></script>
- <script type=“text/javascript”>
- var ua = navigator.userAgent.toLowerCase();
- if(!ua.match(“chrome”)) {
- alert(“本页需要使用支持webgl的浏览器浏览,你可以继续尝试,但建议使用chrome。\r某些浏览器可能需要自行开启webgl支持,自行搜索即可。”);
- }
- </script>
- </html>
按你的安排修改好js的路径。注意到lalalalademaxiya.js没?还要新建这个文件(实在接受不了的自行修名。。。),后文的js代码都要按顺序放进这里。
布置scene:
- // 设置场景尺寸
- var WIDTH = 400,
- HEIGHT = 300;
- // 设置一些摄像机的参数
- var VIEW_ANGLE = 45,
- ASPECT = WIDTH / HEIGHT,
- NEAR = 0.1,
- FAR = 10000;
- // 获取作为容器的DOM元素
- // - 假设这次用jquery来处理
- var $container = $(‘#container’);
- // 创建一个WebGL渲染器,摄像机
- // 和一个场景
- var renderer = new THREE.WebGLRenderer();
- var camera =
- new THREE.PerspectiveCamera(
- VIEW_ANGLE,
- ASPECT,
- NEAR,
- FAR);
- var scene = new THREE.Scene();
- // 把摄像机加入场景
- scene.add(camera);
- // 摄像机开始时位于坐标(0,0,0)
- // 所以把它往后拉
- camera.position.z = 300;
- // 开始做渲染器的工作
- renderer.setSize(WIDTH, HEIGHT);
- // 加入供渲染的DOM元素
- $container.append(renderer.domElement);
别急着运行,现在什么都没有。
4、制作一个mesh
mesh的翻译是网格,但是这和这个概念实在难以联想到一块,所以继续用原文。没有蒙上材质的mesh看着就像用网格线表现的物体。
现在我们有了场景、摄像机和渲染器,但是我们还没有任何东西可以绘制。这一点上,Three.js其实原生支持几种标准的文件类型,如果你要从其他的3d软件中导出模型,这就帮得上忙了。但是为了简单起见(这只是个入门教程),我们这里就用primitives。Primitives是一些基本的几何体meshes,创建起来很容易:
- // 设置球体的一些参数
- var radius = 50,
- segments = 16,
- rings = 16;
- // 创建一个球体,这里用到了
- // sphereMaterial这个材质,
- // 后面再讲。
- var sphere = new THREE.Mesh(
- new THREE.SphereGeometry(
- radius,
- segments,
- rings),
- sphereMaterial);
- // 把球体加入到场景中
- scene.add(sphere);
好了,现在浏览你的网页,应该能看到一个网格构成的球体,如果你用浏览器的开发者工具看js代码,还会看到一个(至少)错误,这是因为我们这里用了一个没有定义的变量sphereMaterial,这是球体的材质,下面就讲解,记得把下面这段插入到var sphere = new THREE.Mesh(这行之前。
5、材质
毫无疑问这是Three.js中最有用的部分。(为什么。。。)它提供了不少常用(而且好用)的材质可以应用在你的mesh上:
- “Basic” – 就我所知,这只是表示它们不会发光。(Which just means it renders “unlit”, as far as I can tell.)
- Lambert
- Phong
上面这个列表和这一块内容完全晕头转向,有需要看原文。大意是指Three.js帮了个大忙,减少了很多处理阴影的工作量。
总之,先上代码,把材质应用到球体上(还记得插入到哪吧?这段不是复制到最后)
- // 创建给球体用的质材
- var sphereMaterial =
- new THREE.MeshLambertMaterial(
- {
- color: 0xCC0000
- });
a这里要说的是在创建材质时你还可以设置很多其他的属性,比如smoothing或environment maps。可以查看文档以了解更多。
6、光源!
你现在如果浏览的话会看到一个红色的圆,即使我们已经应用了lambert材质,但这里没有光的话Three.js就会默认使用最大的全局光(full ambient light),我们只要再创建一个点光源就可以看效果了。
- // 创建一个点光源
- var pointLight =
- new THREE.PointLight(0xFFFFFF);
- // 设置它的位置
- pointLight.position.x = 10;
- pointLight.position.y = 50;
- pointLight.position.z = 130;
- // 加入到场景中
- scene.add(pointLight);
7、渲染循环(类似游戏的主循环,求靠谱的翻译法。。。)
所有渲染需要的东西都齐了,动手:
- // draw!
- renderer.render(scene, camera);
恭喜,到这里Three.js的这部分教程就已经基本完了,还有一些东西,但是似乎是扩展练习之类的,讲解也不如前面那么清楚了,所以先庆祝一下。接下来的我就自己扯了。
现在的情况就像是个静态图片一样。要像那些帅呆了的作品那样动起来,还要做一些工作才行。
实现这个需求,最聪明的办法就是使用requestAnimationFrame,原教程里也提供了一个链接以供读者进一步了解它。
不好意思。。你刚才完成的工作现在又要被我糟蹋了。。。
把刚才加上的最后一句替换成:
- // 处理窗体大小改变事件
- window.addEventListener( ‘resize’, onWindowResize, false );
- function onWindowResize() {
- var windowHalfX = window.innerWidth / 2;
- var windowHalfY = window.innerHeight / 2;
- camera.aspect = window.innerWidth / window.innerHeight;
- camera.updateProjectionMatrix();
- renderer.setSize( window.innerWidth, window.innerHeight );
- }
- // 动画,这里是重点
- function animate() {
- requestAnimationFrame( animate );
- render()
- }
- animate();
- function render() {
- // 根据鼠标位置改变摄像机位置
- camera.position.x += ( mouseX - camera.position.x ) * .05;
- camera.position.y += ( - mouseY - camera.position.y ) * .05;
- // 始终看向场景原点
- camera.lookAt( scene.position );
- renderer.render( scene, camera );
- }
- document.addEventListener(‘click’, function() {
- window.open(“http://blog.alanslab.cn/”);
- }, false);
- document.addEventListener( ‘mousemove’, onDocumentMouseMove, false );
- function onDocumentMouseMove(event) {
- // 从范例中抄来的缓动效果,想到了flash,瞬间感觉好亲切。。
- mouseX = ( event.clientX - windowHalfX ) * 10;
- mouseY = ( event.clientY - windowHalfY ) * 10;
- }
然后在最前面加入:
- var windowHalfX = window.innerWidth / 2;
- var windowHalfY = window.innerHeight / 2;
- var mouseX = 0, mouseY = 0;
之前的场景尺寸是固定的,为了铺满整个浏览器窗口,还要修改一些语句:
把var WIDTH = 400, HEIGHT = 300;这句修改为
var WIDTH = window.innerWidth, HEIGHT = window.innerHeight;
现在移动鼠标,应该就能看到效果了!