译文Threejs教程如何用3D

哪里治疗白癜风好 https://yyk.familydoctor.com.cn/2831/newslist_8_1.html

在浏览器中用The.js拼凑一个3D场景就像在玩乐高积木一样。我们将一些盒子放在一起,添加灯光,定义相机,The.js渲染3D图像。

在本教程中,我们将用盒子组装一辆简约的汽车,并学习如何将纹理映射到它上面。

首先,我们将进行设置——我们将定义灯光、相机和渲染器。然后我们将学习如何定义几何和材料来创建3D对象。最后,我们将使用JavaScript和HTMLCanvas对纹理进行编码。

如何设置The.js项目

The.js是一个外部库,所以首先我们需要将它添加到我们的项目中。我使用NPM将它安装到我的项目中,然后在JavaScript文件的开头导入它。

import*asTHREEfrom"the";constscene=newTHREE.Scene();...

首先,我们需要定义场景。场景是一个容器,其中包含我们想要与灯光一起显示的所有3D对象。我们即将在这个场景中添加一辆汽车,但首先让我们设置灯光、相机和渲染器。

如何设置灯光

我们将在场景中添加两盏灯:一个环境光和一个定向光。我们通过设置颜色和强度来定义两者。

颜色定义为十六进制值。在这种情况下,我们将其设置为白色。强度是一个介于0和1之间的数字,由于它们同时发光,我们希望这些值在0.5左右。

...constambientLight=newTHREE.AmbientLight(0xffffff,0.6);scene.add(ambientLight);constdictionalLight=newTHREE.DictionalLight(0xffffff,0.8);dictionalLight.position.set(,,);scene.add(dictionalLight);...

环境光从各个方向照射,为我们的几何体提供基本颜色,而定向光模拟太阳。

定向光从很远的地方发出平行光线。我们为此灯设置了一个位置,该位置定义了这些光线的方向。

这个位置可能有点混乱,所以让我解释一下。在所有平行光线中,我们特别定义了一条。这个特定的光线将从我们定义的位置(,,)照射到0,0,0坐标。其余的将与之并行。

image.png

由于光线是平行的,并且它们从很远的地方发光,所以精确地坐标在这里并不重要——相反,它们的比例很重要。

三个位置参数是X、Y和Z坐标。默认情况下,Y轴指向上方,因为它具有最高值(),这意味着我们的汽车顶部接收到的光线最多。所以它会是最亮的。

其他两个值定义了光线沿X轴和Z轴弯曲的程度,即汽车前部和侧面将接收到的光量。

如何设置相机

接下来,让我们设置定义我们如何看待这个场景的相机。

这里有两种选择——透视相机和正交相机。电子游戏大多使用透视相机,但我们将使用正交相机以获得更简约的几何外观。

在本文中,我们将只讨论如何设置正交相机。

对于相机,我们需要定义一个视锥体。这是3D空间中将被投影到屏幕上的区域。

在正交相机的情况下,这是一个盒子。相机将这个盒子内的3D对象投射到它的一侧。因为每条投影线都是平行的,所以正交相机不会扭曲几何形状。

...//SettingupcameraconstaspectRatio=window.innerWidth/window.innerHeight;constcameraWidth=;constcameraHeight=cameraWidth/aspectRatio;constcamera=newTHREE.OrthographicCamera(cameraWidth/-2,//leftcameraWidth/2,//rightcameraHeight/2,//topcameraHeight/-2,//bottom0,//nearplane//farplane);camera.position.set(,,);camera.lookAt(0,10,0);...

要设置正交相机,我们必须定义平截头体的每一侧与视点的距离。我们定义左侧距左侧75个单位,右侧平面距右侧75个单位,依此类推。

这里这些单位不代表屏幕像素。渲染图像的大小将在渲染器中定义。在这里,这些值具有我们在3D空间中使用的任意单位。稍后,当在3D空间中定义3D对象时,我们将使用相同的单位来设置它们的大小和位置。

一旦我们定义了一个相机,我们还需要定位它并朝一个方向转动。我们将相机在每个维度上移动个单位,然后我们将其设置为向后看0,10,0坐标。这几乎是原点。我们看向略高于地面的一点,我们的汽车的中心将在那里。

如何设置渲染器

我们需要设置的最后一块是渲染器,它根据我们的相机将场景渲染到浏览器中。我们像这样定义一个WebGLRender:

...//Setupnderconstnder=newTHREE.WebGLRender({antialias:true});nder.setSize(window.innerWidth,window.innerHeight);nder.nder(scene,camera);document.body.appendChild(nder.domElement);

这里我们还设置了画布的大小。这是我们以像素为单位设置大小的唯一地方,因为我们正在设置它在浏览器中的显示方式。如果我们想填满整个浏览器窗口,我们传递窗口的大小。

最后,最后一行将这个渲染的图像添加到我们的HTML文档中。它创建一个HTMLCanvas元素来显示渲染的图像并将其添加到DOM。

如何在The.js中构建汽车

现在让我们看看我们怎样才能组成一辆汽车。首先,我们将创建一个没有纹理的汽车。这将是一个简约的设计——我们只需将四个盒子放在一起。

image.png

如何添加框

首先,我们创建一对轮子。我们将定义一个代表左右轮的灰色框。由于我们从未从下方看到汽车,因此我们不会注意到我们只有一个大盒子,而不是单独的左右轮。

我们将需要在汽车的前部和后部都有一对轮子,这样我们就可以创建一个可重用的功能。

...functioncateWheels(){constgeometry=newTHREE.BoxBufferGeometry(12,12,33);constmaterial=newTHREE.MeshLambertMaterial({color:0x});constwheel=newTHREE.Mesh(geometry,material);turnwheel;}...

我们将轮子定义为网格。网格是几何和材质的组合,它将代表我们的3D对象。

几何定义对象的形状。在这种情况下,我们通过将其沿X、Y和Z轴的尺寸设置为12、12和33个单位来创建一个框。

然后我们传递将定义我们的网格外观的材料。有不同的材料选择。它们之间的主要区别在于它们对光的反应。

在本教程中,我们将使用MeshLambertMaterial.计算MeshLambertMaterial每个顶点的颜色。在绘制一个盒子的情况下,基本上是每一面。

我们可以看到它是如何工作的,因为盒子的每一面都有不同的阴影。我们将定向光定义为主要从上方发光,因此盒子的顶部是最亮的。

一些其他材料计算颜色,不仅针对每一面,而且针对该面内的每个像素。它们会为更复杂的形状生成更逼真的图像。但是对于用定向光照明的盒子,它们并没有太大的区别。

如何建造汽车的其余部分

然后以类似的方式让我们创建汽车的其余部分。我们定义了cateCar返回Group的函数。这个组是另一个像场景一样的容器。它可以容纳The.js对象。这很方便,因为如果我们想在汽车周围移动,我们可以简单地在Group周围移动。

...functioncateCar(){constcar=newTHREE.Group();constbackWheel=cateWheels();backWheel.position.y=6;backWheel.position.x=-18;car.add(backWheel);constfrontWheel=cateWheels();frontWheel.position.y=6;frontWheel.position.x=18;car.add(frontWheel);constmain=newTHREE.Mesh(newTHREE.BoxBufferGeometry(60,15,30),newTHREE.MeshLambertMaterial({color:0x78b14b}));main.position.y=12;car.add(main);constcabin=newTHREE.Mesh(newTHREE.BoxBufferGeometry(33,12,24),newTHREE.MeshLambertMaterial({color:0xffffff}));cabin.position.x=-6;cabin.position.y=25.5;car.add(cabin);turncar;}constcar=cateCar();scene.add(car);nder.nder(scene,camera);...

我们用我们的函数生成两对轮子,然后定义汽车的主要部分。然后我们将添加小屋的顶部作为第四个网格。这些都只是不同尺寸和不同颜色的盒子。

默认情况下,每个几何图形都位于中间,它们的中心位于0,0,0坐标处。

首先,我们通过调整它们沿Y轴的位置来提升它们。我们将轮子提高了一半的高度——所以它们不是沉到地面的一半,而是躺在地上。然后我们还沿着X轴调整碎片以到达它们的最终位置。

我们将这些部分添加到汽车组中,然后将整个组添加到场景中。在渲染图像之前将汽车添加到场景中很重要,否则我们需要在修改场景后再次调用渲染。

如何为汽车添加纹理

现在我们有了非常基本的汽车模型,让我们为车厢添加一些纹理。我们要粉刷窗户。我们将为侧面定义一个纹理,并为机舱的前部和后部定义一个纹理。

当我们使用材质设置网格的外观时,设置颜色并不是唯一的选择。我们还可以映射纹理。我们可以为每一面提供相同的纹理,或者我们可以为数组中的每一面提供一种材质。

为纹理,我们可以使用图像。但取而代之的是,我们将使用JavaScript创建纹理。我们将使用HTMLCanvas和JavaScript对图像进行编码。

在继续之前,我们需要对The.js和HTMLCanvas做一些区分。

The.js是一个JavaScript库。它在后台使用WebGL将3D对象渲染为图像,并将最终结果显示在画布元素中。

另一方面,HTMLCanvas是一个HTML元素,就像div元素或段落标签一样。不过,它的特别之处在于我们可以使用JavaScript在这个元素上绘制形状。

这就是The.js在浏览器中渲染场景的方式,也是我们要创建纹理的方式。让我们看看它们是如何工作的。

如何在HTML画布上绘图

要在画布上绘图,首先我们需要创建一个画布元素。当我们创建一个HTML元素时,这个元素永远不会成为我们HTML结构的一部分。它本身不会显示在页面上。相反,我们将把它变成The.js纹理。

让我们看看如何在这个画布上绘图。首先,我们定义画布的宽度和高度。这里的大小并没有定义画布会出现多大,它更像是画布的分辨率。纹理将被拉伸到盒子的一侧,不管它的大小。

functiongetCarFrontTextu(){constcanvas=document.cateElement("canvas");canvas.width=64;canvas.height=32;constcontext=canvas.getContext("2d");context.fillStyle="#ffffff";context.fillRect(0,0,64,32);context.fillStyle="#";context.fillRect(8,8,48,24);turnnewTHREE.CanvasTextu(canvas);}

然后我们得到2D绘图上下文。我们可以使用这个上下文来执行绘图命令。

首先,我们要用一个白色矩形填充整个画布。为此,首先我们将填充样式设置为while。然后通过设置矩形的左上角位置和大小来填充矩形。在画布上绘图时,默认情况下0,0坐标将位于左上角。

然后我们用灰色填充另一个矩形。这个从8,8坐标开始,它不填充画布,它只绘制窗口。

就是这样——最后一行将画布元素转换为纹理并将其返回,因此我们可以将它用于我们的汽车。

functiongetCarSideTextu(){constcanvas=document.cateElement("canvas");canvas.width=;canvas.height=32;constcontext=canvas.getContext("2d");context.fillStyle="#ffffff";context.fillRect(0,0,,32);context.fillStyle="#";context.fillRect(10,8,38,24);context.fillRect(58,8,60,24);turnnewTHREE.CanvasTextu(canvas);}

以类似的方式,我们可以定义侧面纹理。我们再次创建一个画布元素,获取它的上下文,然后首先填充整个画布以具有基色,然后将窗口绘制为矩形。

如何将纹理映射到盒子

现在让我们看看如何将这些纹理用于我们的汽车。当我们为舱室顶部定义网格时,我们不是只设置一种材质,而是为每一侧设置一种材质。我们定义了一个包含六种材料的数组。我们将纹理映射到机舱的侧面,而顶部和底部仍将具有纯色。

...functioncateCar(){constcar=newTHREE.Group();constbackWheel=cateWheels();backWheel.position.y=6;backWheel.position.x=-18;car.add(backWheel);constfrontWheel=cateWheels();frontWheel.position.y=6;frontWheel.position.x=18;car.add(frontWheel);constmain=newTHREE.Mesh(newTHREE.BoxBufferGeometry(60,15,30),newTHREE.MeshLambertMaterial({color:0xa}));main.position.y=12;car.add(main);constcarFrontTextu=getCarFrontTextu();constcarBackTextu=getCarFrontTextu();constcarRightSideTextu=getCarSideTextu();constcarLeftSideTextu=getCarSideTextu();carLeftSideTextu.center=newTHREE.Vector2(0.5,0.5);carLeftSideTextu.rotation=Math.PI;carLeftSideTextu.flipY=false;constcabin=newTHREE.Mesh(newTHREE.BoxBufferGeometry(33,12,24),[newTHREE.MeshLambertMaterial({map:carFrontTextu}),newTHREE.MeshLambertMaterial({map:carBackTextu}),newTHREE.MeshLambertMaterial({color:0xffffff}),//topnewTHREE.MeshLambertMaterial({color:0xffffff}),//bottomnewTHREE.MeshLambertMaterial({map:carRightSideTextu}),newTHREE.MeshLambertMaterial({map:carLeftSideTextu}),]);cabin.position.x=-6;cabin.position.y=25.5;car.add(cabin);turncar;}...

大多数这些纹理将被正确映射而无需任何调整。但是如果我们把车掉头,我们可以看到左侧的窗户以错误的顺序出现。

这是预期的,因为我们在这里也使用右侧的纹理。我们可以为左侧定义一个单独的纹理,或者我们可以镜像右侧。

不幸的是,我们不能水平翻转纹理。我们只能垂直翻转纹理。我们可以通过3个步骤解决此问题。

首先,我们将纹理旋转度,这等于PI的弧度。不过,在转动它之前,我们必须确保纹理围绕其中心旋转。这不是默认设置——我们必须将旋转中心设置为中途。我们在两个轴上都设置了0.5,这基本上意味着50%。最后我们将纹理倒置以使其处于正确的位置。

包起来

那么我们在这里做了什么?我们创建了一个包含汽车和灯光的场景。我们用简单的盒子制造了这辆车。

你可能觉得这太基础了,但仔细想想,很多外观时尚的手游其实都是用盒子制作的。或者只是想一想Minecraft,看看你能把盒子放在一起能走多远。

然后我们使用HTML画布创建纹理。HTML画布的功能远比我们在这里使用的要多。我们可以用曲线和弧线绘制不同的形状,但有时我们只需要一个最小的设计。

最后,我们定义了一个摄像机来确定我们如何看待这个场景,以及一个将最终图像渲染到浏览器中的渲染器。




转载请注明:http://www.aierlanlan.com/rzgz/4163.html