gknpezgssb/blog

我的世界:一个村落(其二)

gknpezgssb opened this issue · 0 comments

village

现在我们对three.js的基本元素与如何用three.js搭建场景有了一定的了解后,本篇我们开始搭建村落中山坡,房屋等对象。

ps:如果没看过第一篇的请移步这里

山坡与草皮

ground

思路

从图中可以看出山坡mesh的geometry在three.js中并未直接提供,demo的思路是由基本几何体BoxGeometry变形而来。
这里说明一下,three.js构建的图形都有点(vertex),线(edge),面(face)三个属性:

vectex

如图所示移动box中对应点,可将box变形成最终所需的geometry:
construct

代码

var geom = new THREE.BoxGeometry(basicWidth, groundDeep, basicHeight, 4, 1, 1)
// 改变矩形形状
geom.vertices[0].y += hillHeight
geom.vertices[1].y += hillHeight
geom.vertices[10].y += hillHeight
geom.vertices[13].y += hillHeight
geom.vertices[4].x += groundDeep
geom.vertices[5].x += groundDeep
var mat = new THREE.MeshStandardMaterial({
    color: color.ground,
    shading: THREE.FlatShading,
    roughness: 1,
    metalness: 0
})
this.mesh = new THREE.Mesh(geom, mat)
this.add(this.mesh)

使用相同的逻辑我们可以创建草皮元素

房屋

思路

房屋可以拆分成屋顶,窗户,门,墙,烟囱等部件
其中屋顶,和墙也是对基本几何体的变形,可以参考上一节的方法,这里就不再赘述。
下面我们说一说Group与ThreeBSP

Group与Merge

THREE.Group.apply(this, arguments)

查看源码可以发现一个经常被使用到的对象THREE.Group。
Group是一个组,其中可以容纳多个Mesh对象,并且如果我们对该group进行旋转,平移,缩放操作时,Group会相当于一个整体进行旋转,平移,缩放。
与之相似,Geometry对象提供了一个Merge方法,可以合并geometry。
它们之间的差异在于:

  • Group添加的是Mesh,而Merge作用的对象是Geometry;
  • 即便添加到Group中,Group内的各个Mesh还可以被单独操作,使用Merge相当与合成了一个大的geometry对象,你无法在单独操作其中的geometry,对于创建后不需要再单独操作的对象使用Merge可以提升性能

ThreeBSP

ThreeBSP是一个用来创建geometry的Three.js的扩展库
用图来表示一下:

bsp

  • union方式用来得到geometry的合体(类似并集)
  • intersect方式用来得到交集
  • substract用来从Mesh中挖去另一个Mesh

用将大Box中挖去小box的思路,我们就可以穿件一个窗户的外框

镂空函数

// 镂空

function substractMesh(basic, substract, mat) {
    var material = new THREE.MeshBasicMaterial()
    var mesh1 = new THREE.Mesh(basic, material)
    var mesh2 = new THREE.Mesh(substract, material)
    var basicBSP = new ThreeBSP(mesh1)
    var substractBSP = new ThreeBSP(mesh2)
    var res = basicBSP.subtract(substractBSP)
    res = res.toMesh()
    res.geometry.computeFaceNormals()
    res.geometry.computeVertexNormals()
    res.material = mat
    return res
}

如上,可以抽象出一个镂空函数来帮我们处理mesh
substractMesh函数将接收三个参数(被挖的Mesh,从中挖去的Mesh,最终Mesh的材质)
返回一个镂空后的Mesh

后记

这篇并没有像前篇一样全程代码,因为静态元素的构建过程真的大同小异全写出来不免枯燥,二来这也仅仅是个人的思路,而且条条大路通罗马,不应该束缚自己的想象力。
以上就是构建村庄中静态部件的思路,在下一章节我们会介绍复杂部件如云,森林是如何构建的