Three.js游戏开发入门

JavaScript010

Three.js游戏开发入门,第1张

就在不久前,创建和部署 游戏 的唯一方法是选择像 Unity 或 Unreal 这样的 游戏 引擎,学习语言,然后打包 游戏 并将其部署到你选择的平台上。

试图通过浏览器向用户提供 游戏 的想法似乎是一项不可能完成的任务。

幸运的是,由于浏览器技术的进步和硬件加速在所有流行的浏览器中都可用,JavaScript 性能的改进以及可用处理能力的稳步提高,为浏览器创建交互式 游戏 体验变得越来越普遍。

在本文中,我们将了解如何使用 Three.js 创建 游戏 。但首先,让我们回顾一下 Three.js 是什么以及为什么它是 游戏 开发的好选择。

Three.js 在 GitHub 上的项目描述恰当地将 Three.js 描述为“......一个易于使用、轻量级、跨浏览器的通用 3D 库”。

Three.js 让我们作为开发人员可以相对简单地在屏幕上绘制 3D 对象和模型。如果没有它,我们将需要直接与 WebGL 交互,虽然这并非不可能,但即使是最小的 游戏 开发项目也会花费大量时间。

传统上,“ 游戏 引擎”由多个部分组成。例如,Unity 和 Unreal 提供了一种将对象渲染到屏幕上的方法,但也提供了大量其他功能,如网络、物理等等。

然而,Three.js 的方法更受限制,不包括物理或网络之类的东西。但是,这种更简单的方法意味着它更容易学习和更优化以做它最擅长的事情:将对象绘制到屏幕上。

它还有一组很棒的示例,我们可以使用它们来了解如何在屏幕上绘制各种对象。最后,它提供了一种简单且原生的方式将我们的模型加载到我们的场景中。

如果不希望用户需要通过应用商店下载应用或进行任何设置来玩你的 游戏 ,那么Three.js 作为 游戏 开发引擎可能是一个有吸引力的选择。如果你的 游戏 在浏览器中运行,那么进入门槛最低,这只能是一件好事。

今天,我们将通过制作一个使用着色器、模型、动画和 游戏 逻辑的 游戏 来浏览 Three.js。我们将创建的内容如下所示:

这个概念很简单。我们控制着一艘火箭飞船,穿越一个星球,我们的目标是拾取能量晶体。我们还需要通过增加护盾来管理飞船的 健康 状况,并尽量不要因为撞击场景中的岩石而严重损坏我们的船。

在我们的运行结束时,火箭飞船返回天空中的母舰,如果用户点击 NEXT LEVEL ,他们会再次尝试,这一次火箭要经过更长的路径。

随着用户玩 游戏 ,火箭飞船的速度会增加,因此他们必须更快地躲避岩石并收集能量晶体。

要创建这样的 游戏 ,我们必须回答以下问题:

到我们制作这款 游戏 时,我们将克服这些挑战。

不过,在我们开始编码之前,我们必须回顾一些简短的理论,特别是与我们将如何在 游戏 中创造运动感有关。

想象一下,你在现实生活中控制着一架直升机,并且正在跟踪地面上的一个物体。物体以逐渐增加的速度继续前进。为了跟上,你必须逐渐提高你所在直升机的速度。

如果对直升机或地面上的物体的速度没有限制,只要你想跟上地面上的物体,这种情况就会持续下去。

当创建一个跟随对象的 游戏 时,正如我们在本例中所做的那样,应用相同的逻辑可能很诱人。也就是说,在世界空间中随着物体的加速移动物体,并更新后面跟随的相机的速度。然而,这提出了一个直接的问题。

基本上,每个玩这个 游戏 的人都会在他们的手机或台式电脑上玩它。这些设备资源有限。如果我们尝试在相机移动时生成可能无限数量的对象,然后移动该相机,最终我们将耗尽所有可用资源,并且浏览器选项卡将变得无响应或崩溃。

我们还需要创建一个代表海洋的平面(一个平面 2D 对象)。当我们这样做时,我们必须给出海洋的尺寸。

然而,我们不能创建一个无限大的平面,我们也不能创建一个巨大的平面,只是希望用户永远不会在我们的关卡中前进到足以让他们离开平面的程度。

那是糟糕的设计,并且希望人们玩我们的 游戏 不足以体验错误似乎违反直觉。

我们不是在一个方向上无限期地移动我们的相机,而是让相机保持静止并移动它周围的环境。这有几个好处。

一是我们总是知道火箭飞船在哪里,因为火箭的位置不会移到远处;它只会左右移动。这让我们很容易判断物体是否在相机后面,并且可以从场景中移除以释放资源。

另一个好处是我们可以选择远处的一个点来创建对象。这意味着当物体接近玩家时,新的物品或物体将不断地在玩家视野之外的距离创建。

当它们从视野中消失时,无论是玩家与它们发生碰撞还是从玩家身后消失,这些物品都会从场景中移除,以降低内存使用量。

要创建这种效果,我们需要做两件事:首先,我们需要在程序上沿深度轴移动每个项目,以将对象移向相机。其次,我们必须为我们的水面提供一个可以抵消的值,并随着时间的推移增加这个偏移量。

这将产生水面移动越来越快的效果。

现在我们已经解决了如何在场景中向前移动火箭,让我们继续设置我们的项目。

让我们开始制作 游戏 吧!我们需要做的第一件事是设置构建环境。对于这个例子,我选择使用 Typescript 和 Webpack。这篇文章不是要讨论这些技术的有点,所以除了快速总结之外,我不会在这里详细介绍它们。

使用 Webpack 意味着当我们开发项目并保存文件时,Webpack 将看到我们的文件已更改,并使用保存的更改自动重新加载浏览器。

这意味着我们无需在每次进行更改时手动刷新浏览器,从而节省大量时间。这也意味着我们可以使用像three-minifier这样的插件,它可以在我们部署它时减小我们的包的大小。

在我们的示例中使用 TypeScript 意味着我们的项目将具有类型安全性。我发现这在使用 Three.js 的一些内部类型时特别有用,比如Vector3s 和Quaternions. 知道我将正确类型的值分配给变量是非常有价值的。

我们还将在 UI 中使用Materialize CSS。对于我们将用作 UI 的几个按钮和卡片,这个 CSS 框架将有很大帮助。

要开始我们的项目,请创建一个新文件夹。在文件夹中,创建一个package.json并粘贴以下内容:

然后,在命令窗口中,键入npm i以将包安装到新项目中。

我们现在需要创建三个文件,一个基本的 Webpack 配置文件,然后是我们项目的开发和生产配置文件。

在项目文件夹中创建一个webpack.common.js文件并粘贴以下配置:

然后,创建一个webpack.dev.js文件并粘贴这些详细信息。这配置了 Webpack 开发服务器的热重载功能:

最后,创建一个webpack.production.js文件并粘贴这些详细信息:

我们需要做的下一件事是配置 TypeScript 环境以允许我们使用来自 JavaScript 文件的导入。为此,请创建一个tsconfig.json文件并粘贴以下详细信息:

我们的构建环境现在已经配置好了。现在是时候开始为我们的玩家创造一个美丽而可信的场景了。

我们的场景包含以下元素:

我们将在一个名为 game.ts的文件中完成大部分工作,但我们也会将部分 游戏 拆分为单独的文件,这样我们就不会得到一个非常长的文件。我们现在可以继续创建文件game.ts。

因为我们正在处理一个非常复杂的主题,所以我还将包含指向此代码在 GitHub 上的项目中的位置的链接。这应该有望帮助你保持自己的方向,而不是在更大的项目中迷失方向。

我们需要做的第一件事是创建一个Scene,以便 Three.js 有一些东西可以渲染。在我们的game.ts中,我们将添加以下行来构建我们的并将 一个ScenePerspectiveCamera放置在场景中,这样我们就可以看到发生了什么。

最后,我们将为稍后分配的渲染器创建一个引用:

为了设置我们的场景,我们需要执行一些任务,比如创建一个新的WebGLRenderer和设置我们想要绘制的画布的大小。

为此,让我们创建一个init函数并将其也放入我们的game.ts中。此init函数将为我们的场景执行初始设置,并且只运行一次(当 游戏 首次加载时):

我们还需要为场景利用渲染和动画循环。我们需要动画循环来根据需要在屏幕上移动对象,并且我们需要渲染循环来将新帧绘制到屏幕上。

让我们继续在game.ts中创建render函数。 一开始,这个函数看起来很简单,因为它只是请求一个动画帧然后渲染场景。

我们请求动画帧的原因有很多,但其中一个主要原因是如果用户更改选项卡,我们的 游戏 将暂停,这将提高性能并减少设备上可能浪费的资源:

好了,现在我们有了一个空的场景,里面有一个相机,但没有别的了。让我们在场景中添加一些水。

幸运的是,Three.js 包含一个我们可以在场景中使用的水对象示例。它包括实时反射,看起来相当不错;你可以在这里查看。

对我们来说幸运的是,这种水将完成我们在场景中想要做的大部分事情。我们唯一需要做的就是稍微改变水的着色器,这样我们就可以在渲染循环中更新它。

我们这样做是因为如果随着时间的推移,我们越来越多地抵消我们的水纹理,那么它会给我们带来速度的感觉。

作为演示,下面就是我们 游戏 的开场场景,但我每帧都增加了偏移量。随着偏移量的增加,感觉就像我们下方海洋的速度正在增加(即使火箭实际上是静止的)。

水对象可以在 Three.js GitHub 上找到。我们唯一需要做的就是做一个小的改变,使这个偏移量可以从我们的渲染循环中控制(所以我们可以随着时间的推移更新它)。

我们要做的第一件事是在 Three.js 存储库中获取 Water.js 示例的副本。我们将把这个文件objects/water.js放在我们的项目中。如果我们打开water.js文件,大约一半,我们将开始看到如下所示的内容:

这是海洋材质的着色器。着色器本身的介绍超出了本文的范围,但基本上,它们是我们的 游戏 将向用户的计算机提供的关于如何绘制此特定对象的说明。

这里还有我们的着色器代码,它是用 OpenGraph 着色器语言 (GLSL) 编写的,并合并到一个原本是 JavaScript 的文件中。

这没有什么问题,但是如果我们将这个着色器代码单独移动到一个文件中,那么我们可以将 GLSL 支持安装到我们选择的 IDE 中,我们将获得语法着色和验证之类的东西,这有助于我们自定义 GLSL .

要将 GLSL 分解为单独的文件,让我们在当前objects目录中创建一个shader目录,选择 我们的vertexShader和 fragmentShader 的内容, 并将它们分别移动到waterFragmentShader.glsl和waterVertexShader.glsl文件中。

在我们waterFragmentShader.glsl文件的顶部,我们有一个getNoise函数。默认情况下,它看起来像这样:

为了使这个偏移量可以从我们的 游戏 代码中调整,我们想在我们的 GLSL 文件中添加一个参数,允许我们在执行期间对其进行修改。为此,我们必须将此函数替换为以下函数:

你会注意到我们在这个 GLSL 文件中包含了一个新变量:speed变量。这是我们将更新以提供速度感的变量。

在我们的game.ts中,现在需要配置水的设置。在我们文件的顶部,添加以下变量:

然后,在我们的init函数中,必须配置水平面的旋转和位置,如下所示:

这将为海洋提供正确的旋转。

Three.js 带有一个相当令人信服的天空,我们可以在项目中免费使用它。你可以在此处的 Three.js 示例页面中查看此示例。

在我们的项目中添加天空非常容易;只需要将天空添加到场景中,设置天空盒的大小,然后设置一些参数来控制天空的外观。

我们需要对初始场景初始化做的最后一件事是添加一些光照并添加我们的火箭模型和母舰模型:

现在我们有了一些漂亮的水和火箭的场景。但是,我们缺乏任何可以真正使它成为 游戏 的东西。为了解决这个问题,我们需要构建一些基本参数来控制 游戏 并允许玩家朝着某些目标前进。

在我们game.ts文件的顶部,我们将添加以下sceneConfiguration变量,这有助于我们跟踪场景中的对象:

现在,我们必须为玩家所在的当前关卡执行初始化。这个场景设置函数很重要,因为每次用户开始一个新的关卡时都会调用它。

因此,我们需要将火箭的位置设置回起点并清理所有正在使用的旧资产。我在代码行内添加了一些注释,以便你可以看到每一行在做什么:

我们预计有两种类型的设备可以玩我们的 游戏 :台式电脑和手机。为此,我们需要适应两种类型的输入选项:

现在让我们配置这些。

在我们game.ts的开始,我们将添加以下变量来跟踪键盘上是否按下了左键或右键:

然后,在我们的init函数中,我们将注册keydownandkeyup事件来分别调用onKeyDownandonKeyUp函数:

最后,对于键盘输入,我们将记录按下这些键时要执行的操作:

我们的移动用户没有键盘可以输入,因此,我们将使用nippleJS在屏幕上创建一个操纵杆,并使用操纵杆的输出来影响火箭在屏幕上的位置。

在我们的init函数中,我们将通过检查它在屏幕上是否有非零数量的触摸点来检查设备是否是触摸设备。如果是,我们将创建操纵杆,但一旦玩家释放操纵杆的控制,我们还将将火箭的运动设置回零:

在我们的animate函数中,我们会跟踪此时按下左键或右键或操纵杆是否正在使用中的操作。我们还将火箭的位置夹在可接受的左右位置,这样火箭就不能完全移出屏幕:

正如我们已经讨论过的,火箭飞船在我们的场景中保持静止,并且物体朝它移动。这些物体移动的速度随着用户继续玩而逐渐增加,随着时间的推移增加了关卡的难度。

仍然在我们的动画循环中,我们希望逐步将这些对象移向玩家。当对象离开玩家的视野时,我们希望将它们从场景中移除,这样我们就不会占用玩家计算机上不必要的资源。

在我们的渲染循环中,我们可以像这样设置这个功能:

我们可以看到有几个函数是这个调用的一部分:

让我们 探索 一下这些函数在我们的 游戏 中完成了什么。

碰撞检测是我们 游戏 的重要途径。没有它,我们将不知道我们的火箭飞船是否达到了任何目标,或者它是否撞到了岩石并应该减速。这就是我们想要在 游戏 中使用碰撞检测的原因。

通常,我们可以使用物理引擎来检测场景中对象之间的碰撞,但是 Three.js 没有包含物理引擎。

不过,这并不是说 Three.js 不存在物理引擎。他们当然可以,但是为了我们的需要,我们不需要添加物理引擎来检查我们的火箭是否击中了另一个物体。

本质上,我们想回答这个问题,“我的火箭模型目前是否与屏幕上的任何其他模型相交?” 我们还需要根据受到的打击以某些方式做出反应。

例如,如果我们的玩家不断将火箭撞到岩石上,我们需要在受到一定程度的伤害后结束关卡。

为了实现这一点,让我们创建一个函数来检查我们的火箭和场景中的对象的交集。根据玩家击中的内容,我们会做出相应的反应。

我们将把这段代码放在我们的game目录中的一个collisionDetection.ts文件中:

对于碰撞检测,我们唯一需要做的另一件事是添加一个短动画,当用户与对象碰撞时播放该动画。此函数将获取发生碰撞的位置并从该原点生成一些框。

完成的结果将如下所示。

为了实现这一点,我们必须在碰撞发生的地方创建一个圆圈中的盒子,并将它们向外设置动画,这样看起来它们就像从碰撞中爆炸一样。为此,让我们在collisionDetection.ts文件中添加此功能:

这就是我们整理出来的碰撞检测,当物体被破坏时会有一个漂亮的动画。

随着场景的进行,我们希望在玩家的两侧添加一些悬崖,这样感觉就像他们的运动在某个空间内得到了适当的限制。我们使用模运算符在程序上将岩石添加到用户的右侧或左侧:

随着场景的进行,我们还希望将“挑战行”添加到场景中。这些是包含岩石、水晶或盾牌物品的物体。每次创建这些新行中的一个时,我们都会为每一行随机分配岩石、水晶和盾牌。

因此,在上面的示例中,单元格 1、2 和 4 没有添加任何内容,而单元格 3 和 5 分别添加了水晶和盾牌项目。

为了实现这一点,我们将这些挑战行分为五个不同的单元格。我们根据随机函数的输出在每个单元格中生成某个项目,如下所示:

可以在这些链接中的任何一个查看岩石、水晶和盾牌创建功能。

我们需要在渲染循环中完成的最后一件事是:

在我们的渲染函数结束时,我们可以添加以下代码来适应这个功能:

这就是我们的渲染循环完成了。

当人们加载我们的 游戏 时,他们会看到一些让他们能够开始玩的按钮。

这些只是简单的 HTML 元素,我们根据 游戏 中发生的情况以编程方式显示或隐藏它们。问题图标让玩家对 游戏 的内容有所了解,并包含有关如何玩 游戏 的说明。它还包括我们模型的(非常重要的!)许可证。

并且,按下红色按钮开始 游戏 。请注意,当我们点击红色的“播放”按钮时,摄像机会移动并旋转到火箭后面,让玩家准备好开始场景。

在我们的场景init函数中,我们将要执行此操作的事件注册到此按钮的onClick处理程序。要创建旋转和移动功能,我们需要执行以下操作:

为此,我们将在init函数中添加以下代码,如下所示:

当我们的关卡结束时,我们还必须连接我们的逻辑,并且可以在此处查看执行此操作的代码。

在 Three.js 中创建 游戏 可以让你接触到数量惊人的潜在客户。由于人们可以在浏览器中玩 游戏 而无需下载或安装到他们的设备上,因此它成为开发和分发 游戏 的一种非常有吸引力的方式。

正如我们所见,为广泛的用户创造一种引人入胜且有趣的体验是非常有可能的。所以,唯一需要解决的是,你将在 Three.js 中创建什么?

原文链接:http://www.bimant.com/blog/threejs-game-dev-tutorial/

近年来web得到了快速的发展。随着HTML5的普及,网页的表现能力越来越强大。网页上已经可以做出很多复杂的动画,精美的效果。 但是,人总是贪的。那么,在此之上还能做什么呢?其中一种就是通过WebGL在网页中绘制高性能的3D图形。

OpenGL 它是最常用的跨平台图形库。

WebGL 是基于 OpenGL 设计的面向web的图形标准,提供了一系列JavaScript API,通过这些API进行图形渲染将得以利用图形硬件从而获得较高性能。

Three.js 是通过对 WebGL 接口的封装与简化而形成的一个易用的图形库。

简单点的说法 threejs=three + js ,three表示3D的意思,js表示javascript的意思。那么合起来,three.js就是使用javascript 来写3D程序的意思。而javascript的计算能力因为google的V8引 擎得到了迅猛的增强,做3D程序,做服务器都没有问题。

WebGL 门槛相对较高,需要相对较多的数学知识(线性代数、解析几何)。因此,想要短时间上手 WebGL 还是挺有难度的。 Three.js WebGL 提供的接口进行了非常好的封装,简化了很多细节,大大降低了学习成本。并且,几乎没有损失 WebGL 的灵活性。

因此,从 Three.js入 手是值得推荐的,这可以让你在较短的学习后就能面对大部分需求场景。

Three.js 的入门是相对简单的,但是当我们真的去学的时候,会发现一个很尴尬的问题:相关的学习资料很少。

通常这种流行的库都有很完善的文档,很多时候跟着官方的文档或官方的入门教程学习就是最好的路线。但Three不是的,它的文档对初学者来说太过简明扼要。

不过官方提供了非常丰富的examples,几乎所有你需要的用法都在某个example中有所体现。但这些example不太适合用来入门,倒是适合入门之后的进一步学习。

这里推荐一些相对较好的教程:

当然,实际的学习过程中这些资料肯定是不太够的,遇到问题还是要自己去查资料。不过这里要提醒一下,Three.js的更新是相当频繁的,现在是r80版本,自2010年4月发布r1以来,这已经是第72个版本了(中间有的版本号跳过了)。因此,在网上找到的资料有些可能是不适合当前版本的,需要注意甄别(前面推荐的资料也都或多或少存在这样的问题)。

要在屏幕上展示3D图形,思路大体上都是这样的:

1、构建一个三维空间

Three中称之为场景(Scene)

2、选择一个观察点,并确定观察方向/角度等

Three中称之为相机(Camera)

3、在场景中添加供观察的物体

Three中的物体有很多种,包括Mesh,Line,Points等,它们都继承自Object3D类

4、将观察到的场景渲染到屏幕上的指定区域

Three中使用Renderer完成这一工作

场景是所有物体的容器,也对应着我们创建的三维世界。

Camera是三维世界中的观察者,为了观察这个世界,首先我们要描述空间中的位置。 Three中使用采用常见的右手坐标系定位。

Three中的相机有两种,分别是正投影相机THREE.OrthographicCamera和透视投影相机THREE.PerspectiveCamera。

这里补充一个视景体的概念:视景体是一个几何体,只有视景体内的物体才会被我们看到,视景体之外的物体将被裁剪掉。这是为了去除不必要的运算。

正交投影相机的视景体是一个长方体,OrthographicCamera的构造函数是这样的:

Camera本身可以看作是一个点,left则表示左平面在左右方向上与Camera的距离。另外几个参数同理。于是六个参数分别定义了视景体六个面的位置。

可以近似地认为,视景体里的物体平行投影到近平面上,然后近平面上的图像被渲染到屏幕上。

2)透视投影相机

fov对应着图中的视角,是上下两面的夹角。aspect是近平面的宽高比。在加上近平面距离near,远平面距离far,就可以唯一确定这个视景体了。

透视投影相机很符合我们通常的看东西的感觉,因此大多数情况下我们都是用透视投影相机展示3D效果。

有了相机,总要看点什么吧?在场景中添加一些物体吧。

Three中供显示的物体有很多,它们都继承自Object3D类,这里我们主要看一下Mesh和Points两种。

1)Mesh

我们都知道,计算机的世界里,一条弧线是由有限个点构成的有限条线段连接得到的。线段很多时,看起来就是一条平滑的弧线了。

计算机中的三维模型也是类似的,普遍的做法是用三角形组成的网格来描述,我们把这种模型称之为Mesh模型。

geometry是它的形状,material是它的材质。

不止是Mesh,创建很多物体都要用到这两个属性。下面我们来看看这两个重要的属性。

2)Geometry

Geometry,形状,相当直观。Geometry通过存储模型用到的点集和点间关系(哪些点构成一个三角形)来达到描述物体形状的目的。

Three提供了立方体(其实是长方体)、平面(其实是长方形)、球体、圆形、圆柱、圆台等许多基本形状;

你也可以通过自己定义每个点的位置来构造形状;

对于比较复杂的形状,我们还可以通过外部的模型文件导入。

3)Material

Material,材质,这就没有形状那么直观了。

材质其实是物体表面除了形状以为所有可视属性的集合,例如色彩、纹理、光滑度、透明度、反射率、折射率、发光度。

这里讲一下材质(Material)、贴图(Map)和纹理(Texture)的关系。

材质上面已经提到了,它包括了贴图以及其它。

贴图其实是‘贴’和‘图’,它包括了图片和图片应当贴到什么位置。

纹理嘛,其实就是‘图’了。

Three提供了多种材质可供选择,能够自由地选择漫反射/镜面反射等材质。

4)Points

讲完了Mesh,我们来看看另一种Object——Points。

Points其实就是一堆点的集合,它在之前很长时间都被称为ParticleSystem(粒子系统),r68版本时更名为PointCloud,r72版本时才更名为Points。更名主要是因为,Mr.doob认为,粒子系统应当是包括粒子和相关的物理特性的处理的一套完整体系,而Three中的Points简单得多。因此最终这个类被命名为Points。

5)Light

神说:要有光!

光影效果是让画面丰富的重要因素。

Three提供了包括环境光AmbientLight、点光源PointLight、 聚光灯SpotLight、方向光DirectionalLight、半球光HemisphereLight等多种光源。

只要在场景中添加需要的光源就好了。

6)Renderer

在场景中建立了各种物体,也有了光,还有观察物体的相机,是时候把看到的东西渲染到屏幕上了。这就是Render做的事情了。

Renderer绑定一个canvas对象,并可以设置大小,默认背景颜色等属性。

调用Renderer的render函数,传入scene和camera,就可以把图像渲染到canvas中了。

现在,一个静态的画面已经可以得到了,怎么才能让它动起来?

很简单的想法,改变场景中object的位置啊角度啊各种属性,然后重新调用render函数渲染就好了。

那么重新渲染的时机怎么确定?

HTML5为我们提供了requestAnimFrame,它会自动在每次页面重绘前调用传入的函数。

如果我们一开始这样渲染:

只需要改成这样:

object就可以动起来了!

下面我们用一个简单的例子来梳理一下这个过程。

首先写一个有Canvas元素的页面吧。

下面来做Javascript的部分

首先初始化Renderer

初始化场景:

初始化相机:

要唯一确定一个相机的位置与方向,position、up、lookAt三个属性是缺一不可的。

这里我们创建了一个正交投影相机,这里我将视景体大小与屏幕分辨率保持一致只是为了方便,这样坐标系中的一个单位长度就对应屏幕的一个像素了。

我们将相机放在Z轴上,面向坐标原点,相机的上方向为Y轴方向,注意up的方向和lookAt的方向必然是垂直的(类比自己的头就知道了)。

下面添加一个立方体到场景中:

注意我们使用了法向材质 MeshNormalMaterial ,这样立方体每个面的颜色与这个面对着的方向是相关的,更便于观察/调试。

在这个简单的demo里我不打算添加光影效果,而法向材质对光也是没有反应的。 最后来创建一个动画循环吧

每次重绘都让这个立方体转动一点点。 当页面加载好时,调用前面这些函数就好了。

WebGL中文网 强烈推荐!!

WebGL中文教程网