webgl之Three.js学习 day5使用高级几何体和二元操作

一、ConvexGeometry(凸面体)


通过ConvexGeometry我们可以在一组点的外面建立一个凸包。所谓凸包就是包围这组点的最小图形。下面这个例子就是一个凸面体:

我们在这个例子中随机生成了一组点,然后在这组点的基础上创建了ConvexGeometry。由生成的随机点生成一个ConvexGeometry非常简单:

var convexGeometry = new THREE.ConvexGeometry(points);
convexMesh = createMesh(convexGeometry);
scene.add(convexMesh);

保存顶点(类型是THREE.Vector3)的数组是ConvexGeometry构造函数的唯一参数。最后要注意的是我们在这里调用的createMesh()函数。

 

二、LatheGeometry(扫描体)


通过LatheGemetry你可以从一条光滑曲线开始创建图形。这条曲线是通过指定一些点(也叫节点)来定义的,而这条曲线通常也被称作样条曲线。当这条样条曲线绕一个固定点旋转时就构成了一个类似花瓶或铃铛的图形。同样,我们来看一个例子:

 你可以看到这条样条曲线是由一组红色小球来表示的。这些小球的位置连同其他一些参数一同传递给LatheGeometry的构造函数。在看那些参数之前,我们先来看看创建样条曲线的代码,以及LatheGeometry如何使用这条样条曲线:

function generatePoints(segments,phiStart,phiLength){
    var points = [];
    var heights = 5;
    var count = 30;
    for (var i = 0; i < count; i++) {
        points.push(new THREE.Vector3((Math.sin(i*0.2)+Math.cos(i*0.3))*height+12,
                                       0, (i-count)+count/2));    
    }
    ...
    var latheGeometry = new THREE.LatheGeometry(points,segments,phiStart,phiLength);
    latheMesh = createMesh(latheGeometry);
    scene.add(latheMesh);
}

下面我们来看一下它所接受的参数:

 属性

是否必须

描述

points

该属性指定构成样条曲线的点,然后基于这条样条曲线生成类似铃铛或花瓶的图形

segments

该属性指定创建图形是所用的分段数目。这个数字越高,最终的图形越光滑。默认值是12

phiStart

该属性指定创建图形时从圆的何处开始。取值范围是0到2*Pi。默认值是0

phiLength

该属性指定创建出的图形有多完整。例如四分之一图形就是0.5*Pi。默认值是完整的360度或2*Pi

 

三、通过拉伸创建几何体


Three.js提供了几个办法让我们可以把一个二维图形拉伸成三维图形。所谓拉伸指的是先画一个图形的二维轮廓,然后沿着z轴将它转换成三维图形。例如,如果我们拉伸一个THREE。CircleGeometry对象,我们就会得到一个类似圆柱体的图形;如果我们拉伸一个THREE.PlanceGeometry对象,我们就会得到一个类似方块的图形。

1.ExtrudeGeometry

 ·通过ExtrudeGeometry,二维图形沿着z轴拉伸,最终形成一个三维图形。创建ExtrudeGeometry很简单:

var options = {
    amount:10,
    bevelThickness:2,
    bevelSize:1,
    bevelSegments:3,
    bevelEnabled:true,
    curveSegments:12,
    steps:1
};
shape = createMesh(new THREE.ExtrudeGeometry(drawShape(),options));

在这段代码中,使用drawShape()函数创建图形。然后将这个图形连同options(选项)对象一起传递给THREE.ExtrudeGeometry的构造函数。下表是对可以传递THREE.ExtrudeGeometry的各个选项的解释:

属性

是否必须

描述

amount(数量)

指定图形可以拉多高。默认值是100

bevelThickness(斜角厚度)

指定斜角的深度。斜角是前后面和拉伸体之间的倒角。默认值是6

bevelSize(斜角尺寸)

指定斜角的高度。默认值是bevelThickness-2

bevelSegments(斜角分段数)

定义斜角的分段数。段数越多,斜角越光滑。默认值是3

bevelEnabled(是否用斜角)

如果设为true,就会有斜角。默认值是true

curveSegments(曲线分段数)

指定拉伸图形时曲线分成多少段。段数越多,曲线越光滑。默认值是12

steps(拉伸体段数)

定义拉伸体被分成多少段。默认值是1

extrudePath(拉伸路径)

指定图形沿着什么路径拉伸。如果没有指定,图形就会沿着z轴拉伸

material(材质)

定义前后面所用材质的索引。用函数THREE.SceneUtils.createMultiMaterialObject创建网络

extrudeMaterial(拉伸材质)

指定斜角和拉伸体所用材质的索引。用函数THREE.SceneUtils.createMultiMaterialObject创建网络

2.TubeGeometry

TubeGeometry沿着一条三维样条曲线拉伸出一根管子。你可以通过指定顶点来定义路径,然后TubeGeometry就可以创建这跟管子。如下图所示:

 在这个例子中,我们随机生成了一些点,然后用这些点来画管道。创建这些管道的代码很简单:

var points = [];
for (var i = 0;i<controls.numberOfPoints;i++){
    var randomX = -20+Math.round(Math.random()*50);
    var randomY = -15+Math.round(Math.random()*40);
    var randomZ = -20+Math.round(Math.random()*40);
    
    points.push(new THREE.Vector3(randomX,randomY,randomZ));
}
var tubeGeometry = new THREE.TubeGeometry(new THREE.SplineCurve3(points),
                       segments,radius,radiusSegments,closed);

var tubeMesh = createMesh(tubeGeometry);
scene.add(tubeMesh);

我们首先要做的是获取一组顶点,类型是THREE.Vector3,在使用这些点创建管道之前,我们先要把这些点转换成THREE.SplineCurve类。换言之,我们需要用这些点来定义一条光滑曲线。做法很简单,只要把顶点数组传递给THREE.SplineCurve3构造函数即可。

除了THREE.SplineCurve3对象,TubeGeometry构造函数还接受别的参数。下表列出的就是TubeGeometry的所有参数:

属性

是否必须

描述

path

用一个THREE.SplineCurve对象来指定管道应当遵循的路径

segments

指定构建这个管道所用的分段数。默认值是64。路径越长,指定的的分段数应该越多

radius

指定管道的半径。默认值是1

radiusSegments

指定管道圆周的分段数。默认值是8。分段数越多,管道看上去越光滑

closed

如果设为true,管道的头和尾会连在一起。默认值是false

debug

如果设为true,额外的调试信息会添加到管道上

3.从SVG拉伸

SVG和曲线创建图形的方式基本相同。特别是SVG有一个跟Three.js处理图形相同的方式。本节我们将来看看如何使用来自https://github.com/asutherland/d3-threeD的小型库,将SVG路径转换成Three.js图形。

SVG的含义是Scalabel Vector Graphic(可缩放矢量图)。这是个基于XML的标准,用来在网页上创建二维矢量图。该标准是一个开放的标准。

4.ParametricGeometry

通过ParametricGeometry,你可以创建基于等式的几何体。最基础的例子是一个创建平面的函数:

function plane(u,v){
    var x = u*width;
    var y = 0;
    var z = v*depth;
    return new THREE.Vector3(x,y,z);
}

ParametricGeometry会调用这个函数。u和v的取值范围是0到1,而且针对0到1之间的所有值该函数还会被调用很多次。在上面这个例子中,u值用来确定向量的x坐标,v值用来确定z坐标。当这个函数被调用的时候,你就会得到一个宽为width,深为depth的基础平面。

下表对传递给ParametricGeometry的参数做出解释:

属性

是否必须

描述

function

该参数是一个函数,以u、v值(0到1)作为参数,返回值是一个Vector3类型的对象,作为图形上点的坐标

slices

定义u值应该分成多少份

stacks

定义v值应该分成多少份

useTris

默认是false。如果设为true,那么该几何体创建时将会使用三角面片。如果设为false,使用的将是四边形

通过slices和stacks属性,我们可以指定function函数会被调用多少次。假如我们将slices设为5,stacks设为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

这两个值越大,那么生成的向量就越多,创建出来的图形看上去就越光滑。

 

四、创建三维文本


1.渲染文本

在Three.js中渲染文本很简单。你所要做的只是指定想用的字体,以及基本的拉伸属性。下面这个截图展示的就是一个在Three.js里如何渲染文本的例子:

显示这几行文本的代码如下所示:

var options = {
    size:90,
    height:90,
    weight:'normal',
    font:'helvetiker',
    style:'normal',
    bevelThickness:2,
    bevelSize:4,
    bevelSegments:3,
    bevelEnabled:true,
    curveSegments:12,
    steps:1
};

text1 = createMesh(new THREE.TextGeometry("Learning",options));
text1.position.z = -100;
text1.position.y = 100;
scene.add(text1);

text2 = createMesh(new THREE.TextGeometry("Three.js",options));
scene.add(text2);

我们来看一下可以在TextGeometry里指定的属性:

属性

是否必须

描述

size

指定文本的大小。默认是100

height

指定拉伸的长度。默认是50

weight

指定字体的权重。可选的值是normal和bold。默认是normal

font

指定要用的字体名。默认是helvetiker

style

指定字体的样式。可选值包括normal和italic。默认值是normal 

bevelThickness(斜角厚度)

指定斜角的深度。斜角是前后面和拉伸体之间的倒角。默认值是10

bevelSize(斜角尺寸)

指定斜角的高度。默认值是8

bevelSegments(斜角分段数)

定义斜角的分段数。段数越多,斜角越光滑。默认值是3

bevelEnabled(是否用斜角)

如果设为true,就会有斜角。默认值是false

curveSegments(曲线分段数)

指定拉伸图形时曲线分成多少段。段数越多,曲线越光滑。默认值是4

steps(拉伸体段数)

定义拉伸体被分成多少段。默认值是1

extrudePath(拉伸路径)

指定图形沿着什么路径拉伸。如果没有指定,图形就会沿着z轴拉伸

material(材质)

定义前后面所用材质的索引。用函数THREE.SceneUtils.createMultiMaterialObject创建网格

extrudeMateria(拉伸材质)

指定斜角和拉伸体所用材质的索引。用函数THREE.SceneUtils.createMultiMaterialObject创建网格

注:如果你想渲染一组二维文字,例如用作材质的纹理,那么你不应该使用TextGeometry。TextGeometry和JavaScript字体引入了很多操作。对于简单的二维字体渲染,最好使用HTML5画布。通过context.font属性,你可以设置要用的字体,通过context.fillText属性你可以将文本输出到画布上。

2.添加自定义字体

Three.js提供了几种可以在场景中使用的字体。这些字体的基础是由typeface.js提供的字体。typeface.js是一个可以将TrueType和OpenType字体转换成JavaScript的库。转换出来的JavaScript文件可以包含在你的页面中,然后即可在Three.js中使用。

要转换已有的OpenType或TrueType字体,可以使用http://typeface.neocracy.org/fonts.html。通过这个网站,你可以把字体转换成JavaScript。要包含这个字体,只要在你的HTML页面顶部加上如下几行代码即可:

<script type="text/javascript"
    src="../assets/fonts/bitstream_vera_sans_mono_roman.typeface.js">
</script>

这样即可加载该字体,并在Three.js中使用。

 

五、使用二元操作组合网格


通过默认的属性组合,你可以创建出漂亮的模型,但是你所能做的也会受制于Three.js所提供的内容。在本节,我们将展示如何将各种标准几何体组合在一起创建出新的几何体。为此,我们将使用Three.js的扩展库THREEBSP。你可以在网上找到这个库,网址是https://github.com/skalnik/ThreeBSP。这个扩展库提供如下三个函数:

名称

描述

intersect(相交)

使用该函数可以在两个几何体的交集上创建出新的几何体。两个几何体相互交叠的地方就是新的几何体

union(联合)

union函数可以将两个几何体联合在一起创建出新的几何体。

subtract(相减)

通过这个函数你可以在第一个几何体中减去两个几何体交叠的部分,从而创建出新的几何体

使用这个库需要把它包含在我们的网页中。该库使用coffee-script(咖啡脚本)写的,这是一种对用户更加友好的JavaScript脚本的变体。要使用这个库我们有两种选择。我们可以添加coffee-script文件,并在运行时编译,或者将它预先编译成JavaScript文件,然后直接包涵编译后的文件。对于第一种方法,我们需要做的是:

<script type="text/javascript"
    src="../libs/coffee-script.js"></script>
<script type="text/coffeescript"
    src="../libs/ThreeBSP.coffee"></script>

最后一步是要保证在我们使用ThreeBSP功能之前,ThreeBSP.coffee文件已经解析完毕。为此我们要在页面文件底部添加如下代码:

<script type="text/coffeescript">
    onReady();
</script>

然后将我们原先的匿名函数改名为onReady:

function onReady(){
    //Three.js code
}

如果我们使用coffee-script的命令行工具预先将coffee-script编译成JavaScript,我们就可以在网页中直接包含编译好的JavaScript文件。要将它编译成JavaScript代码可以使用如下的命令行:

coffee --compile ThreeBSP.coffee

1.subtract函数

在讲解这个函数之前,有一个重要的步骤你需要记住。这三个函数在计算是使用的是网格的绝对位置。所以如果你在应用这些函数之前将网格组合在一起或者使用多种材质,你可能会得到一些奇怪的结果。为了得到更好的、可预测的结果,应当确保使用未经组合的网格。

在代码中我们首先要将网格包装成一个ThreeBSP对象。只有这样才能在这些对象上调用subtract、intersect、union函数。要创建该网格,我们只需调用toMesh()函数,并通过调用computeFaceNormals()和computeVertexNormals()函数确保所有的法向量可以正确计算出来。之所以要调用这两个函数,是因为在执行二元操作后,几何体中顶点和面的法向量可能会改变,Three.js在着色时会用到面法向量和顶点法向量,明确地重新计算面和顶点的法向量,可以保证新生成的对象着色光滑、渲染正确。

对于intersect和union操作,我们使用的方法基本一致。

 


版权声明:本文为chengzhaohui18原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。