简介
我在一些实验中使用了 Three.js,它非常出色地抽象化了在浏览器中开始使用 3D 的繁琐过程。借助它,您可以创建摄像头、对象、光源、材质等,还可以选择渲染程序,也就是说,您可以决定是使用 HTML 5 的画布、WebGL 还是 SVG 来绘制场景。由于它是开源的,您甚至可以参与该项目。不过,现在我将重点介绍在将其用作引擎时学到的东西,并向您介绍一些基本知识。
尽管 Three.js 非常强大,但有时您可能还是会遇到困难。通常,您需要花费大量时间研究示例、进行逆向工程,以及(在我看来肯定如此)追踪特定功能,偶尔还需要通过 GitHub 提问。顺便提一下,如果您有任何问题,我发现 Mr. doob 和 AlteredQualia 非常乐意提供帮助!
1. 基础知识
我假定您至少对 3D 有粗略的了解,并且对 JavaScript 有相当的熟练程度。如果您不熟悉这些内容,不妨先了解一下,然后再尝试使用这些内容,因为它们可能会让人感到困惑。
在我们的 3D 世界中,我们将拥有以下一些内容,我将引导您完成创建过程:
- 场景
- 渲染程序
- 摄像头
- 一个或两个对象(含材质)
当然,您可以做出一些很酷的效果,我希望您能继续尝试,并开始在浏览器中进行 3D 实验。
2. 支持
我只想简要说明一下浏览器的支持情况。根据我的经验,从支持的渲染程序和底层 JavaScript 引擎的速度来看,Google 的 Chrome 浏览器是最佳选择。Chrome 支持 Canvas、WebGL 和 SVG,并且速度极快。随着版本 4 的推出,Firefox 紧随其后。它的 JavaScript 引擎确实似乎比 Chrome 的 JavaScript 引擎慢一点,但它对渲染技术的支持非常出色。Opera 和 Safari 正在添加 WebGL 支持,但其当前版本仅支持画布。Internet Explorer(版本 9 及更高版本)仅支持画布渲染,我还没有听说过 Microsoft 计划添加 WebGL 功能。
3. 设置场景
假设您选择的浏览器支持所有渲染技术,并且您希望使用画布或 WebGL 进行渲染,因为它们是更标准的选择。Canvas 的受支持范围比 WebGL 更广,但值得注意的是,WebGL 在显卡的 GPU 上运行,这意味着 CPU 可以专注于其他非渲染任务,例如您尝试执行的任何物理或用户互动。
无论您选择哪种渲染程序,请务必注意,JavaScript 都需要进行性能优化。3D 对浏览器来说并非轻量级任务(能够实现 3D 效果本身就是一件了不起的事情),因此请务必仔细了解代码中存在的任何瓶颈,并尽可能将其移除!
假设您已下载并在 HTML 文件中添加了 three.js,那么您如何设置场景?示例如下:
// set the scene size
var WIDTH = 400,
HEIGHT = 300;
// set some camera attributes
var VIEW_ANGLE = 45,
ASPECT = WIDTH / HEIGHT,
NEAR = 0.1,
FAR = 10000;
// get the DOM element to attach to
// - assume we've got jQuery to hand
var $container = $('#container');
// create a WebGL renderer, camera
// and a scene
var renderer = new THREE.WebGLRenderer();
var camera = new THREE.PerspectiveCamera(
VIEW_ANGLE,
ASPECT,
NEAR,
FAR );
var scene = new THREE.Scene();
// the camera starts at 0,0,0 so pull it back
camera.position.z = 300;
// start the renderer
renderer.setSize(WIDTH, HEIGHT);
// attach the render-supplied DOM element
$container.append(renderer.domElement);
其实并不难!
4. 制作网格
现在,我们已经有了场景、摄像头和渲染器(我在示例代码中选择了 WebGL 渲染器),但实际上还没有任何可绘制的内容。Three.js 实际上支持加载几种不同的标准文件类型,这对于从 Blender、Maya、Cinema4D 或任何其他软件输出模型非常有用。为简单起见(毕竟,这只是介绍如何开始使用!)我将介绍基元。基元是几何网格,相对较为基础,例如球体、平面、立方体和圆柱。借助 Three.js,您可以轻松创建以下类型的基本图形:
// set up the sphere vars
var radius = 50, segments = 16, rings = 16;
// create a new mesh with sphere geometry -
// we will cover the sphereMaterial next!
var sphere = new THREE.Mesh(
new THREE.SphereGeometry(radius,
segments,
rings),
sphereMaterial);
// add the sphere to the scene
scene.add(sphere);
一切顺利,但球体的材质如何?在代码中,我们使用了变量 sphereMaterial,但尚未对其进行定义。首先,我们需要更详细地讨论一下材料。
5. 材料
毫无疑问,这是 Three.js 中最实用的部分之一。它提供了一些常见(且非常实用)的材质,可应用于网格:
- “基本”- 仅表示其渲染为“未点亮”
- Lambert
- Phong
还有更多,但为了简单起见,我会让您自己去发现。在 WebGL 的情况下,这些资料尤其有用。为什么呢?因为在 WebGL 中,您必须为要渲染的所有内容编写着色器。着色器本身就是一个庞大的主题,但简而言之,它们是用 GLSL(OpenGL 着色器语言)编写的,用于告知 GPU 内容应如何呈现。这意味着,您需要模拟光照、反射等的数学原理。这可能会很快变得非常复杂。得益于 Three.js,您无需执行此操作,因为它会为您进行抽象化处理。不过,如果您想编写着色器,也可以使用 MeshShaderMaterial 来实现,因此它是一种灵活的设置。
不过,现在我们先将 Lambert 材质应用于球体:
// create the sphere's material
var sphereMaterial = new THREE.MeshLambertMaterial(
{
// a gorgeous red.
color: 0xCC0000
});
值得注意的是,在创建材质时,除了颜色之外,您还可以指定其他属性,例如平滑度或环境贴图。您应查看 Wiki 页面,了解您可以在材质上设置的各种属性,事实上,您还可以设置引擎为您提供的任何对象的属性。此外,最近还推出了 threejs.org,它提供了对该 API 更具吸引力的视图。
6. 灯光!
如果您现在渲染场景,会看到一个红色圆圈。尽管我们应用了 Lambert 材质,但场景中没有光线,因此默认情况下,Three.js 会恢复为全环境光,这与平面着色相同。我们可以使用一个简单的光点来解决这个问题:
// create a point light
var pointLight = new THREE.PointLight( 0xFFFFFF );
// set its position
pointLight.position.x = 10;
pointLight.position.y = 50;
pointLight.position.z = 130;
// add to the scene
scene.add(pointLight);
7. 渲染
现在,我们已经完成了所有设置,可以进行渲染了。但实际上,我们需要继续执行以下操作:
// draw!
renderer.render(scene, camera);
不过,您可能需要多次渲染,因此如果要循环,您应该使用 requestAnimationFrame;它是目前在浏览器中处理动画的最明智方式。它尚未完全受支持,因此我强烈建议您查看 Paul Irish 的 shim。
8. 常见对象属性
如果您花些时间仔细查看 Three.js 的代码,就会发现许多对象都“继承”了 Object3D。这是一个基本对象,包含一些非常实用的属性,例如位置、旋转和缩放信息。具体而言,我们的 Sphere 是一个继承自 Object3D 的 Mesh,它会向 Object3D 添加自己的属性:几何图形和材质。为什么我要提及这些?您不太可能只想在屏幕上显示一个什么也不做的球体,因此这些属性值得您深入研究,因为它们可让您动态操控网格和材质的底层细节。
// sphere geometry
sphere.geometry
// which contains the vertices and faces
sphere.geometry.vertices // an array
sphere.geometry.faces // also an array
// its position
sphere.position // has x, y and z properties
sphere.rotation // same
sphere.scale // ... same
9. Dirty Little Secrets
我只想快速指出一个 Three.js 的注意事项,即如果您修改网格的顶点,您会发现渲染循环中没有任何变化。为什么呢?因为 Three.js(据我所知)会将网格的缓存数据作为一种优化措施。您实际上需要做的是向 Three.js 标记某些内容已发生变化,以便它重新计算所需的所有内容。您可以通过以下方式执行此操作:
// changes to the vertices
sphere.geometry.__dirtyVertices = true;
// changes to the normals
sphere.geometry.__dirtyNormals = true;
当然,还有其他方法,但我发现这两种方法最实用。显然,您应仅标记已更改的内容,以免进行不必要的计算。
总结
希望本简短的 Three.js 简介对您有所帮助。没有什么比亲自动手尝试更有帮助了,我强烈建议您这样做。在浏览器中原生运行 3D 非常有趣,使用 Three.js 等引擎可以为您省去很多麻烦,让您可以制作一些非常酷的东西。为方便您操作,我在本实验文章中封装了源代码,以便您将其用作参考。如果您喜欢这篇文章,欢迎通过 Twitter 告诉我,我很乐意与您交流!