简介
我在一些实验中使用了 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 慢,但同样,它对渲染技术的支持非常出色。Opera 和 Safari 正在添加 WebGL 支持,但其当前版本仅支持画布。Internet Explorer(版本 9 及更高版本)仅支持画布渲染,我还没有听说过 Microsoft 计划添加 WebGL 功能。
3. 设置场景
我假设您已选择支持所有渲染技术的浏览器,并且您希望使用画布或 WebGL 进行渲染,因为这些技术是标准选择。画布的支持范围比 WebGL 更广泛,但值得注意的是,WebGL 在显卡的 GPU 上运行,这意味着您的 CPU 可以专注于其他非渲染任务,例如您尝试执行的任何物理或用户互动。
无论您选择哪种渲染程序,请务必注意,JavaScript 都需要进行性能优化。3D 对浏览器来说并非轻量级任务(能够实现 3D 效果本身就是一件了不起的事情),因此请务必仔细了解代码中存在的瓶颈,并尽可能将其移除!
话虽如此,但假设您已经下载并将 three.js 添加到 HTML 文件中,那么,该如何设置场景呢?示例如下:
// 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 来实现,因此它是一种灵活的设置。
不过,现在我们先对球体应用兰伯材料:
// 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 Ireland's shim。
8. 常见对象属性
如果您花时间浏览一下 Three.js 代码,您会看到许多对象都是从 Object3D “继承”的。这是一个基础对象,其中包含一些非常有用的属性,例如 position、rotation 和 scale 信息。具体而言,我们的 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 告诉我,我非常乐意与您交流!