简介
我在一些实验中使用了 Three.js,它在消除浏览器中 3D 体验的烦恼方面做得非常出色。借助它,您可以创建相机、对象、灯光、材质等,还可以选择渲染器,这意味着您可以决定是使用 HTML 5 的画布、WebGL 还是 SVG 来绘制场景。由于它是开源的,您甚至可以参与该项目。但现在,我将重点介绍我通过将其作为引擎进行实验所学到的知识,并向您介绍一些基础知识。
尽管 Three.js 具有诸多优势,但有时您可能会遇到困难。通常,您需要花费大量时间来研究示例、进行逆向工程,以及(在我的情况下)寻找特定功能,有时还需要通过 GitHub 提问。顺便说一下,如果您有任何问题,可以向 Mr. doob 和 AlteredQualia 寻求帮助,他们非常乐于助人!
1. 基础知识
我假设您至少对 3D 有所了解,并且对 JavaScript 有一定的熟练度。如果您不了解,那么在尝试使用这些内容之前,最好先了解一下,因为这些内容可能会让人感到有些困惑。
在我们的 3D 世界中,我们将拥有以下一些内容,我将引导您完成创建过程:
- 场景
- 渲染器
- 摄像头
- 一两个对象(带材质)
当然,您可以做一些很酷的事情,我希望您能继续这样做,并开始在浏览器中尝试 3D。
2. 支持
下面简要说明一下浏览器支持情况。根据我的经验,Google Chrome 浏览器是最好的浏览器,因为它支持各种渲染器,并且底层 JavaScript 引擎的速度很快。Chrome 支持 Canvas、WebGL 和 SVG,而且速度极快。Firefox 紧随其后,推出了第 4 版。其 JavaScript 引擎似乎比 Chrome 稍慢,但它对渲染技术的支持同样出色。Opera 和 Safari 正在添加 WebGL 支持,但其当前版本仅支持画布。 Internet Explorer(版本 9 及更高版本)仅支持画布渲染,而且我没有听说过 Microsoft 计划添加 WebGL 功能。
3. 阐明背景
我假设您选择的浏览器支持所有渲染技术,并且您希望使用 Canvas 或 WebGL 进行渲染,因为它们是更标准的选择。Canvas 比 WebGL 得到更广泛的支持,但值得注意的是,WebGL 在显卡的 GPU 上运行,这意味着您的 CPU 可以专注于其他非渲染任务,例如您尝试执行的任何物理或用户交互。
无论您选择哪种渲染器,都应注意,JavaScript 需要进行性能优化。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 中最实用的部分之一。它为您提供了许多常见(且非常方便)的材质,可应用于网格:
- “Basic”(基本)- 仅表示它呈现“无光照”
- 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。这是一个基础对象,包含一些非常实用的属性,例如 position、rotation 和 scale 信息。具体而言,我们的 Sphere 是一个继承自 Object3D 的 Mesh,它会向 Object3D 添加自己的属性:geometry 和 materials。我为什么要提到这些?您不太可能只想在屏幕上显示一个什么都不做的球体,这些属性值得研究,因为它们允许您实时操作网格和材质的底层细节。
// 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. 不可告人的小秘密
我只想快速指出 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 告诉我,欢迎随时与我交流!