第六章高级几何

在第5章学习使用几何中,我们展示了Three.js提供的所有基本几何。除了这些基本的几何图形之外,Three.js还提供了一组更高级和专门化的对象。

在本章中,我们将向您展示这些高级几何图形:

  • 如何使用高级几何体,如 THREE.ConxGeometry、THREE.LatheGeometry,THREE.BoxLineGeometry 和 THREE.RoundeBoxGeometry,THRE.TeapotGeometry 和 THRE.TubeGeometry。

  • 如何使用 THREE.ExtrudeGeometry 从2D形状创建3D形状。我们将从2D SVG图像创建3D形状,并从2D THREE.js形状中挤出以创建新颖的3D形状。

  • 如果你想自己创建自定义形状,你可以继续使用我们在前几章中讨论过的形状。然而,Three.js也提供了一个THREE.ParametricGeometry 对象。使用参数化几何图元,可以使用可以更改的参数创建几何图元,以影响几何图元的形状。

  • 我们还将展示如何使用THRE.TextGeometry创建3D文本效果,并展示如何在需要将2D文本标签添加到场景中时使用Troika库。

  • 此外,我们将向您展示如何使用两种辅助几何体,THREE.WireframeGeometry 和 THREE.EdgesGeometry。这些辅助体允许您查看有关其他几何体的更多详细信息。

我们将从列表中的第一个开始: THREE.ConvexGeometry

学习高级几何图形

在本节中,我们将了解一些高级的Three.js几何图形。我们将从THREE.ConvexGeometry开始,您可以使用它来创建凸面外壳。

THREE.ConvexGeometry

使用 THREE.ConvexGeometry,我们可以从一组点创建凸包。凸包是包含所有这些点的最小形状。理解这一点最简单的方法是看一个例子。如果打开convex-geometry.html示例,您将看到一组点的凸包。以下屏幕截图显示了此几何图形:

image-20230522100702950

图6.1:包含所有点的凸包

在这个例子中,我们生成了一组随机的点,并基于这些点创建了 THREE.ConvexGeometry 。在这个例子里,你可以使用右侧菜单中的重绘按钮,它将生成20个新点并绘制凸包。如果你自己尝试,请启用材料透明度,并将不透明度设置为低于1的级别,以查看用于创建此几何体的点。在本例中,这些点被创建为小型 THREE.SphereGeometry 对象

要创建THREE.ConvexGeometry,我们需要一组点。下面的代码片段显示了我们是如何做到这一点的:

const generatePoints = () => {
 const spGroup = new THREE.Object3D()
 spGroup.name = 'spGroup'
 const points = []
 for (let i = 0; i < 20; i++) {
 const randomX = -5 + Math.round(Math.random() * 10)
 const randomY = -5 + Math.round(Math.random() * 10)
 const randomZ = -5 + Math.round(Math.random() * 10)
 points.push(new THREE.Vector3(randomX, randomY, randomZ))
 }
 const material = new THREE.MeshBasicMaterial({ color:
 0xff0000, transparent: false })
 points.forEach(function (point) {
 const spGeom = new THREE.SphereGeometry(0.04)
 const spMesh = new THREE.Mesh(spGeom, material)
 spMesh.position.copy(point)
 spGroup.add(spMesh)
 })
 return {
 spGroup,
 points
 }
}

正如您在这段代码中所看到的,我们创建了20个随机点(THREE.Vector3),并将其推入一个数组。接下来,我们迭代这个数组并创建THREE.SphereGeometry,我们将其位置设置为其中一个点(position.copy(point))。所有点都添加到一个组中,因此我们可以在重新绘制后轻松替换它们。一旦您有了这组点,就可以很容易地从它们创建一个THREE.ConverxGeometry,如以下代码片段所示:

const convexGeometry = new THREE.ConvexGeometry(points);

包含顶点的数组(THREE.VVector3类型)是THREE.ConverxGeometry 唯一的参数。请注意,如果你想渲染平滑的THREE.ConverxGeometry,你应该调用computeVertexNormals,正如我们在第2章“组成THREE.js应用程序的基本组件”中所解释的那样。下一个复杂的几何体是THREE.LatheGeometry。例如,它可以用来创建花瓶状的形状。

THREE.LatheGeometry

THREE.LatheGeometry 允许您从一组点创建形状,这些点一起形成曲线。如果你看一下图6.2,你可以看到我们创建了许多点(红点),Three.js用这些点来创建THREE.LatheGeometry。再一次,理解THREE.LateGeometry是什么样子的最简单方法是看一个例子。该几何图形显示在车床geometry.html中。以下截图来自示例,显示了该几何图形:

image-20230522101630852

图6.2:花瓶状网格的车床

在前面的屏幕截图中,您可以看到用于创建此几何体的点,这些点是一组红色的小球体。这些点的位置与定义几何图形形状的参数一起传递到THRE.LatheGeometry中。在我们研究所有论点之前,让我们先看看用于创建单个点的代码,以及THRE.LatheGeometry如何使用这些点:

const generatePoints = () => {
 ...
 const points = []
 const height = 0.4
 const count = 25
 for (let i = 0; i < count; i++) {
 points.push(new THREE.Vector3((Math.sin(i * 0.4) +
 Math.cos(i * 0.4)) * height + 3, i / 6, 0))
 }
 ...
}
// 使用相同的点来创建一个实验室几何图形
const latheGeometry = new THREE.LatheGeometry (points,
 segments, phiStart, phiLength);
latheMesh = createMesh(latheGeometry);
scene.add(latheMesh);
}

在这段JavaScript中,我们可以看到,我们生成了25个点,其x坐标基于正弦和余弦函数的组合,而y坐标基于i和count变量。这将创建一个由前面屏幕截图中的红点可视化的样条线。基于这些点,我们可以创建THRE.LatheGeometry。除了顶点数组,THRE.LateGeometry还需要一些其他参数。以下列表说明了这些属性:

  • points:这些点构成了用于生成钟/花瓶形状的样条曲线。
  • segments:这些是创建形状时使用的段数。这个数字越高,所得到的形状就会越圆、越平滑。其默认值为12。
  • phiStart:这决定了在生成形状时对圆的位置开始。其范围可以从0到2*PI。默认值为0
  • phiLength:这就定义了形状的完全生成程度。例如,一个四分之一的形状将是0.5*PI。默认值是完整的360度或2*PI。此形状将从phiStart属性的位置开始。

在第5章中,我们已经看到了BoxGeometry。Three.js还提供了另外两种类似长方体的几何图形,我们将在下面讨论。

BoxLineGeometry

如果你只想显示轮廓,你可以使用THRE.BoxLineGeometry。这个几何体的工作原理与THRE.box geometry完全相同,但它不是渲染实体对象,而是使用这样的线(来自box-line geometry.html)渲染长方体:

image-20230522102939956

图6.3-使用线条进行渲染的一个方框

您使用此几何体的方式与 THRE.BoxGeometry 相同,但我们需要使用一种可用的特定于线的材料来创建THRE.LineSegments,而不是创建THRE.Mesh:

import { BoxLineGeometry } from 'three/examples/jsm/
 geometries/BoxLineGeometry'
const material = new THREE.LineBasicMaterial({ color:
 0x000000 }),
const geometry = new BoxLineGeometry(width, height, depth,
 widthSegments, heightSegments, depthSegments)
const lines = new THREE.LineSegments(geometry, material)
scene.add(lines)

有关可以传递到此几何体的属性的说明,请参阅第5章的THRE.BoxGeometry部分。

Three.js还提供了一个稍微高级一点的Three.BoxGeometry,在那里你可以有很好的圆角。可以使用RoundedBoxGeometry进行此操作。

THREE.RoundedBoxGeometry

此几何体使用与 THRE.BoxGeometry 相同的属性,但它也允许您指定圆角的圆角程度。在圆角框几何体示例中,您可以看到它的外观:

image-20230522103300784

图6.4:一个带有圆角的盒子

对于此几何体,我们可以通过指定宽度、高度和深度来指定长方体的尺寸。除了这些特性外,此几何图形还提供了两个附加特性:

  • radius:这是圆角的大小。这个值越高,拐角就越圆。
  • segments:此属性定义了边角的详细程度。如果将其设置为一个低值,则Three.js将使用更少的顶点来定义圆角。

在我们继续展示如何从2D对象创建3D几何体之前,我们将看看Three.js TeapotGeometry提供的最终几何体。

TeapotGeometry

茶壶几何体是一种可以用来渲染茶壶的几何体,这并不奇怪。这个茶壶是3D渲染的标准参考模型,自1975年以来一直在使用。有关此模型历史的更多信息,请点击此处:https://www.computerhistory.org/revolution/computer-graphics-music-and-art/15/206.

使用此模型的工作方式与我们迄今为止看到的所有其他模型完全相同:

import { TeapotGeometry } from 'three/examples/jsm/
 geometries/TeapotGeometry'
...
const geom = new TeapotGeometry(size, segments, bottom,
 lid, body, fitLid, blinn)

指定特定的属性,然后创建几何体,将其指定给THRE.Mesh。根据属性的不同,结果如下(在teapot-geometry.html示例中):

image-20230522111201893

图6.5:犹他茶壶

若要配置此几何图形,您可以使用以下属性:

  • size:这是茶壶的大小。
  • segments:这定义了使用多少个段来创建此茶壶的线框。你使用的片段越多,茶壶看起来就越光滑。
  • bottom:如果设置为true,则将呈现茶壶的底部。如果为false,则不会渲染底部,当茶壶位于曲面上时,您可以使用该底部,而无需渲染其底部
  • lid:如果设置为true,则将呈现茶壶盖。如果是假的,那么这个盖子就不会被渲染了。
  • body:如果设置为true,则将呈现茶壶的主体。如果为假的,身体将不会被渲染。
  • fitLid:如果设置为true,盖子将完全适合茶壶。如果为假,则在盖子和茶壶主体之间会有一个很小的空间。
  • blinn:这定义了是否使用与此茶壶所基于的原始1975年模型相同的高宽比。

在下一节中,我们将介绍通过从二维形状中提取三维几何图形来创建几何图形的另一种方法。

通过提取二维形状来创建几何图形

Three.js提供了一种将2D形状挤出为3D形状的方法。通过挤压,我们的意思是沿着z轴拉伸2D形状,将其转换为3D。例如,如果我们挤出THREE.CircleGeometry,我们会得到一个看起来像圆柱体的形状,如果我们挤压THREE.PlaneGeometry的话,我们会获得一个类似立方体的形状。挤出形状的最通用方法是使用THREE.ExtrudeGeometry。

THREE.ExtrudeGeometry

使用THREE.ExtrudeGeometry,可以从二维形状创建三维对象。在我们深入研究这个几何体的细节之前,让我们先看一个例子,extrude-geometry.html

image-20230522111815589

图6.6-从二维形状创建三维几何图形

在这个例子中,我们采用了在第5章的2D几何部分中创建的2D形状,并使用THRE.ExprudeGeometry将其转换为3D。正如您在前面的屏幕截图中所看到的,该形状是沿着z轴拉伸的,这会产生3D形状。创建THREE.ExtrudeGeometry的代码非常简单:

const geometry = new THREE.ExtrudeGeometry(drawShape(), {
 curveSegments,
 steps,
 depth,
 bevelEnabled,
 bevelThickness,
 bevelSize,
 bevelOffset,
 bevelSegments,
 amount
 })

在这段代码中,我们使用drawShape()函数创建了形状,就像我们在第5章中所做的那样。此形状与一组属性一起传递给THREE.ExprudeGeometry构造函数。使用这些特性,可以精确地定义应如何拉伸形状。以下列表说明了可以传递到THREE.ExtrudeGeometry中的选项

  • shapes:拉伸几何体需要一个或多个形状(THRE.Shape对象)。请参阅第5章,了解如何创建这样的形状。
  • depth:这就决定了形状应被挤压的距离(depth)。默认值为100。
  • bevelThickness:这就决定了斜角的深度。斜角是正面和背面和挤压之间的圆角。此值定义了斜角所在的形状的深度。默认值为6。
  • bevelSize:这就决定了斜角的高度。这将被添加到形状的正常高度中。默认值为双厚度2。
  • bevelSegments:这定义了斜角将使用的段数。使用的段数越多,斜角看起来就越平滑。默认值为3。请注意,如果您添加更多的段,您也会增加顶点计数,这可能会对性能产生不利影响。
  • bevelEnabled:如果此设置为true,则添加一个斜角。默认值为真。
  • bevelOffset:如果此设置为true,则添加一个斜角。默认值为真。
  • curveSegments:这决定了在挤压形状的曲线时将使用多少个线段。使用的段数越多,曲线看起来就越平滑。默认值为12。
  • steps:这定义了形状沿挤压深度划分的段数。默认值为1,这意味着它将沿其深度有一个段,没有不必要的额外顶点。
  • extrudePath:这是形状应该沿着的路径(THREE.CurvePath)挤出的。如果未指定此选项,则该形状将沿z轴拉伸。请注意,如果您有一条弯曲的路径,还需要确保为steps属性设置更高的值,以便它能够准确地跟随曲线
  • uvGenerator:将纹理与材质一起使用时,UV贴图将确定纹理的哪个部分用于特定的面。使用uvGenerator属性,可以传入自己的对象,这将为传入的形状创建的面创建UV设置。有关UV设置的更多信息,请参阅第10章“加载和使用纹理”。如果未指定任何内容,则使用THREE.ExtrudeGeometry.WorldUVGenerator。

如果要对面和边使用不同的材质,可以将一组材质传递到THRE.Mesh。传递的第一种材质将应用于面,第二种材质将用于边。您可以使用extract-geometry.html示例中的菜单来试验这些选项。在这个例子中,我们沿着它的z轴拉伸了这个形状。正如您在本节前面列出的选项中看到的那样,您也可以使用“extrudePath”选项沿着路径挤出形状。在下面的几何体THRE.TubeGeometry中,我们将做到这一点。

THREE.TubeGeometry

THREE.TubeGeometry创建一个沿三维样条线挤出的管。使用多个顶点指定路径,然后THREE.TubeGeometry将创建管状体。您可以在本章的源代码(tube-geometry.html)中找到一个可以进行实验的示例。下面的屏幕截图显示了这个示例:

image-20230522113139758

图6.7-基于随机三维顶点的管道几何图

正如您在本示例中所看到的,我们生成了许多随机点,并使用这些点来绘制管。通过菜单中的控件,我们可以定义试管的外观。创建管道所需的代码非常简单,如下所示:

const points = ... // 阵列的三个。THREE.Vector3 对象 
const tubeGeometry = new TubeGeometry(
	new THREE.CatmullRomCurve3(points),
 	tubularSegments,
 	radius,
 	radiusSegments,
 	closed
)

我们首先需要做的是获得一组THREE.Vector3类型的顶点(点变量),就像我们对THREE.ConverxGeometry和THREE.LatheGeometry所做的那样。然而,在我们可以使用这些点创建管之前,我们首先需要将这些点转换为THREE.Curve。换句话说,我们需要通过定义的点定义一条平滑的曲线。我们可以简单地通过将顶点数组传递给THREE.CatmullRomCurve3的构造函数或THREE.js提供的任何其他Curve实现来实现这一点。有了这个曲线和其他参数(我们将在本节中解释),我们可以创建管状体并将其添加到场景中。

在本例中,我们使用了THREE.CatmullRomCurve3。Three.js提供了许多其他曲线,您也可以使用这些曲线,它们采用稍微不同的参数,但它们可以用于创建不同的曲线实现。开箱即用,Three.js提供了以下曲线:ArcCurve、CatmullRomCurve3、CubicBezierCurve、CubicBezierCurve3、EllipseCurve、LineCurve、LineCurve3、QuadraticBezierCorve、QuadradicBezierCcurve3和SplineCurve。

THREE.TubeGeometry采用了除曲线之外的其他一些参数。以下列出了THREE.TubeGeometry的所有参数:

path:这是THREE.SplineCurve3,它描述了该管道应该遵循的路径

tubularSegments:这些是用于构建管道的管段。默认值为64。路径越长,应指定的线段越多

radius:这是管子的半径。默认值为1。

radiusSegments:这是沿管长度使用的段数。默认值为8。你用得越多,管子就会看起来越圆。

closed:如果设置为true,则将连接管的开始和结束。默认值为假值。

我们将在本章中展示的最后一个挤压例子并不是一个不同类型的几何图形,但我们将使用 THREE.ExtrudeGeometry 从SVG图像中创建挤压。

什么是SVG?

SVG是一种基于XML的标准,可用于为网络创建基于矢量的2D图像。这是一个所有现代浏览器都支持的开放标准。然而,直接使用SVG并从JavaScript操作它并不是很简单。幸运的是,有几个开源JavaScript库使使用SVG变得更加容易。Paper.js、Snap.js、D3.js和Raphael.js都是最好的。如果你想要一个图形编辑器,你也可以使用开源的Inkscape产品。

从SVG元素中挤出三维形状

当我们在第5章中讨论THREE.ShapeGeometry时,我们提到SVG在绘制形状时采用了几乎相同的方法。在本节中,我们将研究如何将SVG图像与THREE.SVGLoader一起使用来挤出SVG图像。我们将以蝙蝠侠标志为例:

image-20230522114243470

图6.8-蝙蝠侠SVG的基本图像

首先,让我们看看原始的SVG代码是什么样子的(在查看assets/SVG/batman.SVG文件的源代码时,您也可以自己看到这一点):

<svg version="1.0" xmlns="http://www.w3.org/2000/
svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" 
y="0px" width="1152px" height="1152px" xml:space="preserve">
 <g>
 <path id="batman-path" style="fill:rgb(0,0,0);" d="M 
261.135 114.535 C 254.906 116.662 247.491 118.825 244.659 
119.344 C
 229.433 122.131 177.907 142.565 151.973 156.101 C 111.417
 177.269 78.9808 203.399 49.2992 238.815 C 41.0479 248.66
 26.5057 277.248 21.0148 294.418 C 14.873 313.624 15.3588
 357.341 21.9304 376.806 C 29.244 398.469 39.6107 416.935
 52.0865 430.524 C 58.2431 437.23 63.3085 443.321 63.3431
 444.06 ... 261.135 114.535 "/>
 </g>
</svg>

除非你是SVG大师,否则这对你来说可能意义不大。不过,基本上,你在这里看到的是一组绘图说明。例如,C 277.987 119.348 279.673 116.786 279.679 115.867告诉浏览器绘制三次贝塞尔曲线,L 489.242 111.787告诉我们应该绘制一条到该特定位置的线。幸运的是,我们不必自己编写代码来解释这一点,而是可以使用 THREE.SVGLoader ,正如您在以下代码中看到的那样:

// returns a promise
const batmanShapesPromise = new SVGLoader().loadAsync('/assets/
svg/batman.svg')
// when promise resolves the svg will contain the shapes
batmanShapes.then((svg) => {
 const shapes = SVGLoader.createShapes(svg.paths[0])
 // 基于这些形状,我们可以创建一个挤压几何图形,正如我们之前所看到的
 const geometry = new THREE.ExtrudeGeometry(shapes, {
 curveSegments,
 steps,
 depth,
 bevelEnabled,
 bevelThickness,
 bevelSize,
 bevelOffset,
 bevelSegments,
 amount
 })
 ...
}

在这个代码片段中,您可以看到我们使用SVGLoader来加载SVG文件。我们在这里使用loadAsync,它将返回一个JavaScript Promise。当Promise解析后,我们可以访问加载的svg数据。该数据可以包含一个路径元素列表,每个路径元素表示原始SVG的路径元素。在我们的例子中,我们只有一个,所以我们使用svg.paths[0]并将其传递到SVGLoader.createShapes中,以将其转换为THREE.Shape对象的数组。 现在我们已经有了形状,我们可以使用与之前相同的方法,即挤出自定义创建的2D几何体,并使用THREE.ExtrudGeometry从2D加载的SVG形状创建3D模型。

当您在浏览器中打开extrude-svg.html示例时,可以看到最终的结果:

image-20230522114832252

图6.9-从2D SVG图像中挤出的3D创建的蝙蝠侠标志

我们将在本节中讨论的最后一个几何体是THREE.ParametricGeometry。使用此几何体,您可以指定用于以编程方式创建几何体的两个函数。

THREE.ParametricGeometry

使用THREE.ParametricGeometry,可以基于方程式创建几何体。在我们深入研究自己的例子之前,一个好的开始是看看Three.js已经提供的例子。当你下载Three.jss发行版时,你会得到examples/js/ParametricGeometrys.js文件。在这个文件中,您可以找到几个可以与THREE.ParametricGeometry一起使用的方程示例。

最基本的例子是创建一个平面的函数:

plane: function ( width, height ) {
 return function ( u, v, target ) {
 const x = u * width;
 const y = 0;
 const z = v * height;
 target.set( x, y, z );
 };
}

此函数由THREE.ParametricGeometry调用。u和v值的范围从0到1,对于0到1的所有值,都会被调用多次。在本例中,u值用于确定矢量的x坐标,v值用于确定z坐标。运行此操作时,将有一个宽度为宽度、深度为深度的基本平面。

在我们的例子中,我们做了类似的事情。然而,我们不是创建一个平面,而是创建一个波浪状图案,正如您在parameteric-geometry.html示例中看到的那样。以下屏幕截图显示了此示例:

image-20230522115447097

图6.10-使用参数化几何图形的波状平面

为了创建此形状,我们将以下函数传递给THREE.ParametricGeometry:

const radialWave = (u, v, optionalTarget) => {
 var result = optionalTarget || new THREE.Vector3()
 var r = 20
 var x = Math.sin(u) * r
 var z = Math.sin(v / 2) * 2 * r + -10
 var y = Math.sin(u * 4 * Math.PI) + Math.cos(v * 2 *
 Math.PI)
 return result.set(x, y, z)
}
const geom = new THREE.ParametricGeometry(radialWave, 120,120);

正如您在这个例子中看到的,通过几行代码,我们可以创建一些非常有趣的几何图形。在本例中,您还可以看到我们可以传递给THREE.ParametricGeometry的参数:

  • function:这一函数根据所提供的u和v值来定义每个顶点的位置
  • slices:这定义了u值应该划分的部分数
  • stacks:这定义了v值应该划分的部分数

通过更改函数,我们可以很容易地使用完全相同的方法来渲染一个完全不同的对象:

image-20230522134027590

图6.11-使用参数化几何图形渲染的克莱因瓶

在进入本章的下一部分之前,这里是关于如何使用切片和堆栈属性的最后一个注释。我们提到,u和v属性被传递到提供的函数参数中,这两个属性的值范围从0到1。用切片和堆叠属性,我们可以定义传入函数的调用频率。例如,如果我们将切片设置为5,将堆栈设置为4,则将使用以下值调用该函数:

u:0/5, v:0/4
u:1/5, v:0/4
u:2/5, v:0/4
u:3/5, v:0/4
u:4/5, v:0/4
u:5/5, v:0/4
u:0/5, v:1/4
u:1/5, v:1/4
...
u:5/5, v:3/4
u:5/5, v:4/4

因此,这些值越高,指定的顶点越多,创建的几何体就越平滑。您可以使用parameteric-geometry.html示例右侧的菜单来查看此效果。

有关更多示例,您可以查看Three.js发行版中的examples/js/ParametricGeometries.js文件。该文件包含用于创建以下几何图形的函数:

  • Klein bottle
  • Plane
  • Flat Mobius strip
  • 3D Mobius strip
  • Tube
  • Torus knot
  • Sphere
  • Plane

有时,您需要查看有关几何体的更多细节,并且不太关心材质和网格的渲染方式。如果您想查看顶点和面,甚至只查看轮廓,Three.js提供了一些几何图形,可以帮助您实现这一点(除了启用用于网格的材质的线框属性外)。我们将在以下部分。

您可以用于调试的几何图形

Three.js附带了两个辅助几何图形,可以更容易地看到几何图形的细节或只是几何图形的轮廓

  • THREE.EdgesGeometry 提供仅渲染几何体边缘的几何体
  • THREE.WireFrameGeometry,它只渲染几何图形而不显示任何面

首先,让我们看 THREE.EdgesGeometry

THREE.EdgesGeometry

使用THREE.EdgesGeometry,可以包裹现有的几何体,然后只显示边而不显示单个顶点和面来渲染该几何体。edges-geometry.html示例中显示了一个示例:

image-20230522134853473

图6.12-边缘几何图形只显示边缘,而不是单个面

在前面的屏幕截图中,您可以看到RoundedBoxGeometry的轮廓,我们只看到了边缘。由于RoundedBoxGeometry具有平滑的角,因此当 使用THREE.EdgesGeometry。

要使用此几何图形,只需像这样包装现有的几何图形:

const baseGeometry = new RoundedBoxGeometry(3, 3, 3, 10, 0.4)
const edgesGeometry = THREE.EdgesGeometry(baseGeometry, 1.5)
}

THREE.EdgesGeometry唯一的属性是thresholdAngle。使用此特性,可以确定此几何图形何时绘制边。在edges-geometry.html中,可以控制此属性以查看效果。

如果您有一个现有的几何图形,并希望查看线框,则可以配置一个材质来显示此线框:

const material = new THREE.MeshBasicMaterial({ color: 0xffff00, wireframe: true })

Three.js还提供了一种不同的使用THRE.WireFrameGeometry的方法

THREE.WireFrameGeometry

此几何图形模拟在将材质的线框属性设置为true时看到的行为:

image-20230522135258584

图6.13-线框几何图形,显示所有几何图形的各个面

使用此材质的方式与使用THREE.EdgesGeometry的方式相同:

const baseGeometry = new THREE.TorusKnotBufferGeometry(3, 1, 
100, 20, 6, 9)
const wireframeGeometry = new THREE.
WireframeGeometry(baseGeometry)

此几何图形不具有任何附加属性。

本章的最后一部分涉及创建三维文本对象。我们将向您展示两种不同的方法,一种使用THREE.Text对象,另一种使用外部库

创建一个三维文本网格

在本节中,我们将快速了解如何创建三维文本。首先,我们将了解如何使用Three.js提供的字体渲染文本,以及如何使用自己的字体。然后,我们将展示一个使用名为Troika的外部库的快速示例(https://github.com/protectwise/troika)这使得创建标签和2D文本元素并将它们添加到场景中变得非常容易。

渲染文本

在Three.js中渲染文本非常容易。您所要做的就是定义要使用的字体,并使用我们在讨论THREE.ExtrudeGeometry时看到的相同挤出属性。下面的屏幕截图显示了如何在THREE.js中渲染文本的text-geometry.html示例:

image-20230522135956821

图6.14-在Three.js中渲染文本

创建此3D文本所需的代码如下:

import { FontLoader } from 'three/examples/jsm/
 loaders/FontLoader'
import { TextGeometry } from 'three/examples/jsm/
 geometries/TextGeometry'
...
new FontLoader()
 .loadAsync('/assets/fonts/helvetiker_regular.typeface.json')
 .then((font) => {
 const textGeom = new TextGeometry('Some Text', {
 font,
 size,
 height,
 curveSegments,
 bevelEnabled,
 bevelThickness,
 bevelSize,
 bevelOffset,
 bevelSegments,
 amount
 })
 ...
 )

在这个代码片段中,您可以看到我们首先必须加载字体。为此,Three.js提供了FontLoader(),我们在其中提供要加载的字体的名称,就像我们在SVGLoader中所做的那样,在那里我们可以获得JavaScript Promise。一旦Promise解析,我们就使用加载的字体来创建TextGeometry。

我们可以传递到THREE.TextGeometry中的选项与我们可以传递给THREE.ExtrudeGeometry的选项相匹配:

  • font:要用于文本的已加载的字体。
  • size:这是文本的大小。默认值为100。
  • height:这是挤压物的长度(深度)。默认值为50
  • curveSegments:这定义了在挤压形状曲线时使用的段数。分段数越多,曲线看起来就会越平滑。默认值为4
  • bevelEnabled:如果此设置为true,则添加一个斜角。默认值为假值。
  • bevelThickness:这是斜角的深度。斜角是正面和背面和挤压之间的圆角。默认值为10。
  • bevelSize:这是斜角的高度。默认值为8
  • bevelSegments:这定义了斜角将使用的段数。分段越多,斜面看起来就越平滑。默认值为3。
  • bevelOffset:这是从斜角开始的形状的轮廓之间的距离。默认值为0。

由于THRE.TextGeometry也是THRE.ExprudeGeometry,因此如果要在材质的正面和侧面使用不同的材质,也可以使用相同的方法。如果你传入一个数组

在创建THREE.Mesh时,THREE.js将第一种材质应用于文本的正面和背面,第二种材质应用到侧面。

也可以将其他字体与此几何体一起使用,但您首先需要将它们转换为JSON——如何做到这一点将在下一节中介绍。

添加自定义字体

Three.js提供了几种字体,您可以在场景中使用。这些字体基于TypeFace.js库提供的字体。TypeFace.js是一个可以将TrueType和OpenType字体转换为JavaScript的库。可以包含生成的JavaScript文件或JSON文件在您的页面中,然后可以在Three.js中使用字体。在旧版本中,使用JavaScript文件,但在后来的Three.js版本中,Three.js改用JSON文件

要转换现有的开放类型或TrueType字体,您可以使用 https://gero3.github.io/facetype.js/ 的网页

image-20230522140811527

图6.15-将字体转换为字体支持的格式

在这个页面上,您可以上传一个字体,它将为您转换为JSON。请注意,这并不能很好地适用于所有类型的字体。字体越简单(直线越多),在Three.js中使用时正确渲染的机会就越大。生成的文件如下所示,其中描述了每个字符(或字形):

{"glyphs":{"¦":{"x_min":359,"x_max":474,"ha":836,"o":"m 474 971 
l 474 457 l
359 457 l 359 971 l 474 971 m 474 277 l 474 -237 l 359 -237 l 
359 277 l 474
277 "},"Ž":{"x_min":106,"x_max":793,"ha":836,"o":"m 121 1013 l 
778 1013 l
778 908 l 249 115 l 793 115 l 793 0 l 106 0 l 106 104 l 620 898 
l 121 898 l
121 1013 m 353 1109 l 211 1289 l 305 1289 l 417 1168 l 530 1289 
l 625 1289
l 482 1109 l 353 1109 "},"Á":{"x_min":25,"x_
max":811,"ha":836,"o":"m 417
892 l 27 ....

一旦您获得了JSON文件,您就可以使用FontLoader(正如我们之前在渲染文本部分中所展示的那样)来加载此字体,并将其分配给可以传递到TextGeometry中的选项的字体属性。

对于本章的最后一个例子,我们将研究使用Three.js创建文本的不同方法。

使用Troika库创建文本

如果要为场景的某些部分创建标签或二维文本标记,还可以使用这三个选项。文本几何图形。您也可以使用一个叫做Troika的外部库: https://github.com/protectwise/troika的库

这是一个相当大的库,它提供了许多功能来为场景添加交互性。对于本例,我们将只查看该库的文本模块。我们将要创建的一个例子是troika-text.html的例子:

image-20230522141443344

图6.16-2D标签的 Troika 文本

要使用这个库,我们首先必须安装它(如果你按照第1章“用Three.js创建你的第一个3D场景”中的说明,你已经可以使用这个库了):

$ yarn add troika-three-text。安装后,我们可以导入并使用它,就像我们使用Three.js提供的其他模块一样:

import { Text } from 'troika-three-text'
const troikaText = new Text()
troikaText.text = 'Text rendering with Troika!\nGreat for
 2D labels'
troikaText.fontSize = 2
troikaText.position.x = -3
troikaText.color = 0xff00ff
troikaText.sync()
scene.add(troikaText)

在前面的代码片段中,我们展示了如何使用Troika创建一个简单的文本元素。您只需要调用Text()构造函数并设置属性。然而,需要记住的一点是,无论何时更改Text()对象中的属性,都必须调用troikaText.sync()。这将确保更改也应用于屏幕上呈现的模型。

总结

我们在这一章中看到了很多。我们介绍了一些高级几何图形,并向您展示了如何使用Three.js创建和渲染文本元素,以及THREE.LatheGeometry,以及如何对这些几何图形进行实验以获得您想要的结果。一个非常好的功能是,我们还可以使用Three.ExtrudeGeometry将现有的SVG路径转换为Three.js

我们还快速研究了一些对调试非常有用的几何图形。THREE.EdgesGeometry仅显示另一个几何体的边,而THREE.WireframeGeometry可用于显示某些其他几何体的线框

最后,如果你想创建3D文本,Three.js提供了TextGeometry,你可以在这里输入你想要使用的字体。Three.js提供了几种字体,但您也可以创建自己的字体。但是,请记住,复杂的字体通常无法正确转换。使用的替代方案TextGeometry使用了Troika 库,这使得创建2D文本标签并将其放置在场景中的任何位置都非常容易。

到目前为止,我们研究的是实体(或线框)几何体,其中顶点相互连接以形成面。在下一章中,我们将研究一种使用粒子或点来可视化几何图形的替代方法。使用粒子,我们不会渲染完整的几何体——我们只是将单个顶点渲染为空间中的点。这使您能够创建出色的3D效果。