unity3d制作安卓小游戏(用three.js做一个类似微信)

如果您曾经想使用 JavaScript 构建游戏,那么您可能会遇到 Three.js。

Three.js 是一个我们可以用来在浏览器中渲染 3D 图形的库。整个事情都在 JavaScript 中,所以通过一些逻辑,您可以添加动画、交互,甚至将其变成游戏。

在本教程中,我们将通过一个非常简单的示例。我们将渲染一个 3D 盒子,同时我们将学习 Three.js 的基础知识。

Three.js 在后台使用 WebGL 来渲染 3D 图形。我们可以使用普通的 WebGL,但它非常复杂且级别较低。另一方面,Three.js 就像在玩乐高积木。

在本文中,我们将介绍如何在场景中放置 3D 对象、设置照明和相机,以及在画布上渲染场景。那么让我们看看我们如何做到这一切

定义场景对象

首先,我们必须定义一个场景。这将是一个放置 3D 对象和灯光的容器。场景对象也有一些属性,比如背景颜色。设置是可选的。如果我们不设置它,则默认为黑色。

import * as THREE from "three"; const scene = new THREE.Scene(); scene.background = new THREE.Color(0x000000); // Optional, black is default ...

几何 材质 = 网格

然后我们将 3D 盒子作为网格添加到场景中。网格是几何体和材料的组合。

... // Add a cube to the scene const geometry = new THREE.BoxGeometry(3, 1, 3); // width, height, depth const material = new THREE.MeshLambertMaterial({ color: 0xfb8e00 }); const mesh = new THREE.Mesh(geometry, material); mesh.position.set(0, 0, 0); // Optional, 0,0,0 is the default scene.add(mesh); ...

什么是几何?

几何图形是我们正在构建的渲染形状 - 就像一个盒子。可以从顶点构建几何图形,也可以使用预定义的几何图形。

BoxGeometry 是最基本的预定义选项。我们只需要设置盒子的宽度、高度和深度就可以了。

你可能认为我们不能通过定义盒子来走多远,但许多设计简约的游戏只使用盒子的组合。

还有其他预定义的几何形状。我们可以很容易地定义一个平面、一个圆柱体、一个球体,甚至是一个二十面体。

unity3d制作安卓小游戏(用three.js做一个类似微信)(1)

image.png

如何使用材料

然后我们定义一个材质。材质描述了物体的外观。在这里,我们可以定义诸如纹理、颜色或不透明度之类的东西。

在这个例子中,我们只设置一种颜色。材料仍然有不同的选择。它们中的大多数之间的主要区别在于它们对光的反应。

最简单的是MeshBasicMaterial。这种材料根本不关心光线,每一面都会有相同的颜色。不过,这可能不是最佳选择,因为您看不到盒子的边缘。

关心光的最简单的材料是 MeshLambertMaterial。这将计算每个顶点的颜色,实际上是每一边。但它并不止于此。

unity3d制作安卓小游戏(用three.js做一个类似微信)(2)

如果您需要更高的精度,还有更高级的材料。MeshPhongMaterial 不仅按顶点计算颜色,而且按每个像素计算颜色。颜色可以在一侧改变。这有助于提高现实主义,但也会降低性能成本。

如果它有任何实际效果,它还取决于灯光设置和几何形状。如果我们渲染盒子并使用定向光,结果不会有太大变化。但是如果我们渲染一个球体,区别就更明显了。

如何定位网格

一旦我们有了一个网格,我们还可以将它定位在场景中并设置每个轴的旋转。稍后,如果我们想在 3D 空间中为对象设置动画,我们将主要调整这些值。

对于定位,我们使用与设置大小相同的单位。无论您使用的是小数还是大数,您只需要在自己的世界中保持一致即可。

对于旋转,我们以弧度设置值。因此,如果您的值以度为单位,则必须将它们除以 180°,然后乘以 PI。

unity3d制作安卓小游戏(用three.js做一个类似微信)(3)

image.png

如何添加光

然后让我们添加灯光。具有基本材质的网格不需要任何灯光,因为无论灯光设置如何,网格都将具有设定的颜色。

但是 Lambert 材料和 Phong 材料需要光。如果没有任何光,网格将保持在黑暗中。

... // Set up lights const ambientLight = new THREE.AmbientLight(0xffffff, 0.6); scene.add(ambientLight); ...

我们将添加两盏灯——一个环境光和一个定向光。

首先,我们添加环境光。环境光从各个方向照射,为我们的几何体提供了基础颜色。

要设置环境光,我们设置颜色和强度。颜色通常为白色,但您可以设置任何颜色。强度是一个介于 0 和 1 之间的数字。我们定义的两个灯以累积的方式工作,因此在这种情况下,我们希望每个灯的强度约为 0.5。

unity3d制作安卓小游戏(用three.js做一个类似微信)(4)

定向灯具有类似的设置,但它也有一个位置。这里的位置这个词有点误导,因为它并不意味着光来自一个确切的位置。

定向光从很远的地方发出,许多平行光线都具有固定的角度。但我们不是定义角度,而是定义单个光线的方向。

在这种情况下,它从 10,20,0 位置的方向向 0,0,0 坐标照射。但当然,定向光不仅仅是一条光线,而是无限量的平行光线。

把它想象成太阳。在较小的尺度上,太阳的光线也平行下降,太阳的位置并不重要,重要的是它的方向。

这就是定向光的作用。它用来自很远的平行光线照射在一切事物上。

... const dirLight = new THREE.DirectionalLight(0xffffff, 0.6); dirLight.position.set(10, 20, 0); // x, y, z scene.add(dirLight); ...

在这里,我们将光的位置设置为从上方(使用 Y 值)并沿 X 轴移动一点。Y 轴具有最高值。这意味着盒子的顶部接收到的光线最多,它将是盒子最闪亮的一面。

unity3d制作安卓小游戏(用three.js做一个类似微信)(5)

光线也沿着 X 轴移动了一点,所以盒子的右侧也会收到一些光线,但会少一些。

并且因为我们没有沿 Z 轴移动光源位置,所以盒子的正面将不会接收到任何来自该光源的光线。如果没有环境光,正面将保持黑暗。

还有其他的灯类型。例如,PointLight 可用于模拟灯泡。它有一个固定的位置,它向各个方向发光。SpotLight 可以用来模拟汽车的聚光灯。它从一个点向沿着圆锥的方向发射光。

如何设置相机

到目前为止,我们已经创建了一个包含几何体和材质的网格。我们还设置了灯光并添加到场景中。我们仍然需要一个相机来定义我们如何看待这个场景。

这里有两种选择:透视相机和正交相机。

unity3d制作安卓小游戏(用three.js做一个类似微信)(6)

电子游戏大多使用透视相机,因为它们的工作方式与您在现实生活中的观察方式相似。更远的东西看起来更小,而你面前的东西看起来更大。

使用正交投影,无论物体离相机多远,它们都将具有相同的大小。正交相机具有更简约的几何外观。它们不会扭曲几何图形 - 平行线将平行出现。

对于这两个相机,我们必须定义一个视锥体。这是 3D 空间中将被投影到屏幕上的区域。此区域之外的任何内容都不会出现在屏幕上。这是因为它要么太近要么太远,或者因为相机没有指向它。

unity3d制作安卓小游戏(用three.js做一个类似微信)(7)

使用透视投影,视锥体中的所有内容都以直线投影到视点。距离相机较远的东西在屏幕上显得更小,因为从视点看,您可以在更小的角度看到它们。

... // Perspective camera const aspect = window.innerWidth / window.innerHeight; const camera = new THREE.PerspectiveCamera( 45, // field of view in degrees aspect, // aspect ratio 1, // near plane 100 // far plane ); ...

要定义透视相机,您需要设置一个视野,即与视点的垂直角度。然后定义框架的宽度和高度的纵横比。如果您填满整个浏览器窗口并希望保持其纵横比,那么您可以这样做。

然后最后两个参数定义近平面和远平面离视点的距离。离相机太近的东西会被忽略,离相机太远的东西也会被忽略。

... // Orthographic camera const width = 10; const height = width * (window.innerHeight / window.innerWidth); const camera = new THREE.OrthographicCamera( width / -2, // left width / 2, // right height / 2, // top height / -2, // bottom 1, // near 100 // far ); ...

然后是正交相机。在这里,我们不是将事物投射到一个点上,而是投射到一个表面上。每条投影线是平行的。这就是为什么物体离相机有多远并不重要,这就是它不会扭曲几何形状的原因。

对于正交相机,我们必须定义每个平面与视点的距离。左平面因此向左五个单位,右平面向右五个单位,依此类推。

... camera.position.set(4, 4, 4); camera.lookAt(0, 0, 0); ...

无论我们使用哪个相机,我们还需要定位它并设置它的方向。如果我们使用的是正交相机,那么这里的实际数字并不重要。无论对象离相机多远,它们都将显示相同的大小。不过,重要的是它们的比例。

通过整个教程,我们通过同一个摄像头看到了所有示例。该相机沿每个轴移动相同的单位,并朝向 0,0,0 坐标。定位正交相机就像定位定向光。重要的不是实际位置,而是方向。

如何渲染场景

所以我们设法把场景和相机放在一起。现在只缺少将图像渲染到我们的浏览器中的最后一块。

我们需要定义一个 WebGLRenderer。当我们提供场景和相机时,它能够将实际图像渲染到 HTML 画布中。这也是我们可以设置此画布的实际大小的地方 - 画布的宽度和高度(以像素为单位),因为它应该出现在浏览器中。

import * as THREE from "three"; // Scene const scene = new THREE.Scene(); // Add a cube to the scene const geometry = new THREE.BoxGeometry(3, 1, 3); // width, height, depth const material = new THREE.MeshLambertMaterial({ color: 0xfb8e00 }); const mesh = new THREE.Mesh(geometry, material); mesh.position.set(0, 0, 0); scene.add(mesh); // Set up lights const ambientLight = new THREE.AmbientLight(0xffffff, 0.6); scene.add(ambientLight); const directionalLight = new THREE.DirectionalLight(0xffffff, 0.6); directionalLight.position.set(10, 20, 0); // x, y, z scene.add(directionalLight); // Camera const width = 10; const height = width * (window.innerHeight / window.innerWidth); const camera = new THREE.OrthographicCamera( width / -2, // left width / 2, // right height / 2, // top height / -2, // bottom 1, // near 100 // far ); camera.position.set(4, 4, 4); camera.lookAt(0, 0, 0); // Renderer const renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setSize(window.innerWidth, window.innerHeight); renderer.render(scene, camera); // Add it to HTML document.body.appendChild(renderer.domElement);

最后,这里的最后一行将这个渲染的画布添加到我们的 HTML 文档中。这就是渲染盒子所需的全部内容。仅仅一个盒子可能看起来有点太多了,但大多数这些东西我们只需要设置一次。

,

免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com

    分享
    投诉
    首页