ThreeJs 3D编程

新版本的主流浏览器都已支持WebGL,这样不需要插件就能在浏览器中创建三维图形。但WebGL提供的接口过于复杂,直接使用来创建三维图形和动画非常繁琐。Three.js函数库将强大的功能融汇其中,方便使用,即使对其中的原理不是很了解,也能借助ThreeJS创建出炫目的三角场景和动画。

一、ThreeJS的场景的基本组件:

1. 场景Scene: 
THREE.Scene是ThreeJS中所有不同对象的容器,也被称为场景图,用来保存物体、光源和渲染所需的其他对象。 
1)创建一个场景对象: 
要在浏览器中显示物体,首先要创建一个场景。创建一个场景对象方法: 
var scene=new THREE.Scene(); 
2)场景对象常用的方法:

方法

描述

Scene.add(object)

用于向创建中添加对象,也可以创建对象组

Scene.remove(object)

用于移除场景中的对象,object为要移除对象的引用

Scene.children

用于获取场景中所有的子对象列表

Scene.getObjectByName(name, recursive)

用name属性获取指定的对象,recursive设为false只在调用者子元素上查找,为true则在所有后代上查找

Scene.traverse(function)

将一个方法作为参数传递给每一个子对象上执行

示例: 
可以使用如下方法在浏览器控制台输出场景中包含的所有对象: 
console.log(scene.children); 
如果知道其中一个对象的名字,也可以使用: 
console.log(scene.getObjectByName(name)); 
2)场景的雾化属性: 
·Scene.fog:为场景添加雾化效果 
为场景添加雾化效果的代码: 
scene.fog=new THREE.Fog(0xffffff, 0.015, 100); 
代码定义了一个白色(0xffffff)雾化效果,后面两个参数分别为近处near和远处far属性的值,通过这两个值决定雾化开始和结束的地方。这种方法创建的雾的浓度是线性增加的,还可以使用一种指数变化的雾化效果: 
scene.fog=new THREE.FogExp2(0xffffff, 0.01); 
此方法中只需要设置雾的颜色和浓度即可,雾的浓度随距离呈指数增长。 
3)场景的材质覆盖属性: 
·Scene.overrideMaterial:为场景添加材质覆盖 
当设置了此属性后,场景中所有物体都会使用该属性指向的材质,即使物体本身也设置了材质。使用方法为: 
scene.overrideMaterial=new THREE.MeshLambertMaterial({color:0xffffff}); 
使用MeshLambertMaterial材质可以创建不发光但可以对场景中的光源产生反应的物体。

2. 几何体Geometry:

ThreeJS提供了很多可以在三维场景中使用的几何体,这些几何体基本都是三维空间的点集和将这些点连接起来的面。当使用ThreeJS中的几何体时,不需要定义所有顶点和面,比如立方体只需要定义长、宽、高几个参数即可。 
1)ThreeJS提供的几何体: 
ThreeJS提供的基础几何体:

THREE.CircleGeometry

圆形

THREE.TorusGeometry

圆环

THREE.RingGeometry

环形

THREE.TorusKnotGeometry

环状纽结

THREE.PlaneGeometry

平面

THREE.PolyhedronGeometry

多面体

THREE.ShapeGeometry

任意图形

THREE.IcosahedronGeometry

二十面体

THREE.BoxGeometry

长方体

THREE.OctahedronGeometry

八面体

THREE.SphereGeometry

球体

THREE.TetraHedronGeometry

四面体

THREE.CylinderGeometry

圆柱体

THREE.DodecahedronGeometry

十二面体

还有复杂几何体:

THREE.ConvexGeometry

凸面体

THREE.ExtrudeGeometry

拉伸几何体

THREE.LatheGeometry

扫描面

THREE.ParametricGeometry

参数几何体

THREE.TubeGeometry

管状体

THREE.TexteGeometry

文本几何体

2)自定义几何体: 
ThreeJS中也可以通过顶点和面来自定义几何体: 
var vertices=[ 
new THREE.Vector3(1, 3, 1), 
new THREE.Vector3(1, 3, -1), 
new THREE.Vector3(1, -1, 1), 
new THREE.Vector3(1, -1, -1), 
new THREE.Vector3(-1, 3, -1), 
new THREE.Vector3(-1, 3, 1), 
new THREE.Vector3(-1, -1, -1), 
new THREE.Vector3(-1, -1, 1) 
]; 
var faces=[ 
new THREE.Face3(0, 2, 1), 
new THREE.Face3(2, 3, 1), 
new THREE.Face3(4, 6, 5), 
new THREE.Face3(6, 7, 5), 
new THREE.Face3(4, 5, 1), 
new THREE.Face3(5, 0, 1), 
new THREE.Face3(7, 6, 2), 
new THREE.Face3(6, 3, 2), 
new THREE.Face3(5, 7, 0), 
new THREE.Face3(7, 2, 0), 
new THREE.Face3(1, 3, 4), 
new THREE.Face3(3, 6, 4) 
]; 
var geom=new THREE.Geometry(); 
geom.vertices=vertices; 
geom.faces=faces; 
geom.computeFaceNormals(); 
其中, vertices数组中保存了构成几何体的顶点, faces数组中保存了由这些顶点连接起来创建的三角形面,里面的数字为顶点中的序号,创建面时注意顶点的顺序,顶点顺序决定了是面向摄像机或背向摄像机,面向摄像机的三角形顶点顺序是顺时针的。 
有了顶点和面,就可以创建THREE.Geometry的实例对象geom,然后将顶点数组和面数组赋值给geom的vertices属性和faces属性,在geom对象上执行computeFaceNormals()方法来得到每个面的方向矢量。法向矢量用于计算得到光源下的颜色。 
2)几何体geometry的方法: 
·clone():创建几何体对象的拷贝。 
3)几何体的属性: 
·verticesNeedUpdate:顶点需要更新

3. 网格Mesh:

创建一个网格需要一个几何体,以及一个或多个材质。当网格创建好后,就可以将它添加到场景中并进行渲染。 
1)网格对象的方法:

方法

描述

translateX(amount)

沿x轴将对象平移amount距离

translateY(amount)

沿y轴将对象平移amount距离

translateZ(amount)

沿z轴将对象平移amount距离

rotateX(degree)

设置沿x轴旋转的弧度

rotateY(degree)

设置沿y轴旋转的弧度

rotateZ(degree)

设置沿z轴旋转的弧度

2)网格对象的属性:

属性

描述

position

该对象相对于父对象的位置

rotation

设置绕每个轴的旋转弧度

scale

通过该属性可以沿x、y、z轴缩放对象

visible

该属性为false时将不会被渲染到场景中

3)为几何体添加线框: 
THREE.WireframeHelper():为几何体添加线框 
var helper=new THREE.WireframeHelper(mesh, 0x000000); 
其中,参数mesh为需要添加线框的网格,另一个参数是线框颜色 
使用scene.add(helper)就可以将helper线框对象添加到场景中。然后可以通过设置线框属性来改变线框显示,如helper.material.linewidth=2来指定线框的宽度。

4. 摄像机:

ThreeJS提供了两种摄像机,正交摄像机和透视摄像机。 
1)正交摄像机: 
使用正交摄像机,物体相对于摄像机对象的距离对渲染效果没有影响,通常用于二维游戏中。 
创建正交摄像机: 
var camera=new THREE.OrthographicCamera(left, right, top, bottom, near, far, zoom); 
其中的参数含义为:

参数

描述

left

左边界,可视范围的左平面

right

右边界,可视范围的右平面

top

上边界,可视范围的上平面

bottom

下边界,可视范围的下平面

near

定义从距离摄像机多近开始渲染

far

定义从距离摄像机多远还可以看见

zoom

放大和缩小场景,大于1放大场景,小于1缩小场景,负值上下颠倒场景

2)透视摄像机: 
大部分情况下使用透视摄像机,物体的大小与距离摄像机的远近有关,更贴近人眼中的世界。 
创建透视摄像机: 
var camera=new THREE.PerspectiveCamera(fov, aspect, near, far, zoom); 
其中的参数含义为:

参数

描述

fov

视场,即摄像机中能够看到的场景,用角度表示,一般为60~90度,推荐50

aspect

长宽比,渲染结果的横向尺寸和纵向尺寸的比值,一般使用界面长宽比

near

定义从距离摄像机多近开始渲染,推荐0.1

far

定义从距离摄像机多远还可以看见,推荐1000

zoom

放大和缩小场景,大于1放大场景,小于1缩小场景,负值上下颠倒场景

3)指定摄像机的指向位置: 
一般情况下摄像机会指向场景的中心,即position(0,0,0)。也可以改变摄像机所指向的位置: 
camera.lookAt(new THREE.Vector3(x, y, z)); 
4)摄像机控件: 
ThreeJS提供了摄像机控件,控件在ThreeJS发布包的examples/js/controls目录中。

控件

描述

FirstPersonControls

第一视角控制器,类似这类游戏中的摄像机,使用键盘鼠标

FlyControls

飞行模拟控制器,用键盘和鼠标控制摄像机的移动

RollControls

翻滚控制器,是飞行模拟控制器的简化版,允许绕z轴旋转

TrackBallControls

轨迹球控制器,最常用,可使用鼠标来轻松移动、平移、缩放

OribitControls

轨道控制器,可以在特定场景中模拟轨道中的卫星

还有其他一些控件:

控件

描述

DeviceOrientationControls

设备朝向控制器,使得摄像机依据设备朝向来调整

EditorControls

编辑控制器,为在线三维编辑器而创建

OculusControls

眼睛控制器,允许使用Oculus Rift设备来环顾场景

OrthographicTrackballControls

正交轨迹控制器,与轨迹球控制器类似

PointerLockControls

鼠标锁定控制器,用场景中渲染的DOM元素锁定鼠标

TransformControls

变换控制器,是ThreeJS内部使用的控制器

VRControls

VR控制器,使用PositionSensorVRDevice API控制场景

除了使用控制器,还可以通过修改position属性来移动相机,通过lookAt90方法来改变摄像机的朝向。 
如果要使用TrackBallControls,需要引入TrackBallControls.js脚本文件,然后可以创建控制器: 
var trackballControls=new THREE.TrackballControls(camera); 
然后为这个对象设置属性值,包括rotateSpeed、zoomSpeed、panSpeed等。使用轨迹球控件时,鼠标左键按住拖动可在场景中旋转和翻滚,移动鼠标滚轮实现放大缩小,按住鼠标右键拖动可以在场景中平移。如果有鼠标中键,按住拖动可以放大缩小,类似滚轮。 
飞行控制器FlyControls可以模拟飞行,使用鼠标和w、s、a、d、r、f、g、e及方向键。其他一些控制器或者会使用其他一些按键,如q键。

5. 使用THREE.MorphAnimMesh实现动画:

动画一般有变形动画和骨骼动画两种,使用变形动画需要定义网格变形之后的状态,也即关键位置。对于变形目标,所有顶点位置都会被存储下来,需要做的是将所有顶点从一个位置移动到另外一个定义好的关键位置,并重复该过程。 
骨骼动画则是需要定义骨骼,并将顶点绑定到特定的骨头上,然后移动一块骨头时,任何与其相连的骨头都会做相应的移动,同时骨头上绑定的顶点也会随之移动。网格的变化也是基于骨头的位置、移动和缩放实现的。 
ThreeJS对两种模式都支持,使用变形动画能得到更好的效果。骨骼动画的主要问题是怎样从三维模型软件的数据导出,从而使用ThreeJS制作动画。 
变形目标是实现目标的最直接方式,可以为所有顶点定义一系列关键位置,即关键帧,然后用ThreeJS将这些顶点从一个位置移动到另一个位置。这种方法也会使模型文件非常大。 
ThreeJS提供了THREE.MorphAnimMesh对象来实现变形动画,这是从带有变形目标的模型中创建动画的最简单方式。使用时要把材质中THREE.morphTargets属性设置为true,否则网格不会移动,使用之前还需要调用computeMorphNormals来计算出变形目标的所有法向矢量,以便创建出合适的光照和阴影效果。使用morphColors属性可以为变形目标的特定某个面指定颜色。变形动画还可以使用morphTargetInfluences属性。 
ThreeJS使用带有蒙皮的网格对象THREE.SkinnedMesh实现骨骼动画,要加载创建骨骼动画的模型,模型文件中包含了顶点、面、骨骼的定义,还有创建网格采用的几何体。需要将模型所使用的材质的skinning属性设置为true,否则骨头不会运动。其中可以使用TWEEN。

6. 使用Tween实现动画:

Tween.js是一个轻量级的JavaScript库,通过这个库可以很容易地实现某个属性在两个值之间进行过渡,而且起始值和结束值之间的所有中间值都会自动计算出来,这个过程称为tweening补间。例如: 
var tween=new TWEEN.Tween({x: 10}).to({x: 3}), 10000) 
 .easing(TWEEN.Easing.ElasticInOut).onUpdate(function(){ 
  //update the mesh 
}) 
代码中将网格的x轴坐标值在10秒内从10递减到3。通过TweenJS可以指定属性值是如何变化的,线性的、指数的,或者其他形式。属性值在指定时间内的变化被称为easing。

7. 加载外部动画模型:

有些外部模型软件,如Blender、Collada、MD2、glTF等,可以创建动画模型。Blender中创建的动画以骨骼动画方式导出,ThreeJS可以加载导出的JSON文件,使用THREE.Animation对象的play()方法,在render循环中调用THREE.AnimationHandler.update()方法来更新动画。

二、ThreeJS中的光源:

没有光源,渲染场景将不可见。ThreeJS中包含大量的光源:

光源

描述

THREE.AmbientLight

基本光源,该光源的颜色会叠加到场景现有物体的颜色上

THREE.PointLight

点光源,从空间一点向所有方向发射光线,不能创建阴影

THREE.SpotLight

聚光源,这种光源可以投射阴影

THREE.DirectionalLight

平行光,光源发出的光线看作平行的,可用来创建阴影

THREE.HemisphereLight

可以通过模拟反光面和光线微弱的天空来创建更加自然的室外光线,也不提供阴影功能

THREE.AreaLight

指定散发光线的平面,也不投射阴影

THREE.LensFlare

可以为场景中的光源添加镜头光晕效果

前面4种是简单光源,只需要一些简单的配置,可用于创建大多数场景的光源。

1. THREE.AmbientLight:环境光

AmbientLight没有特别的来源方向,也不会生成阴影,通常不能作为场景中的唯一光源。AmbientLight创建时,颜色会应用到全局,是在使用其他光源的同时使用,目的是弱化阴影或给场景添加一些额外的颜色。 
1)AmbientLight创建: 
var ambiColor="#0c0c0c"; 
var ambientLight=new THREE.AmbientLight(ambiColor); 
scene.add(ambientLight); 
2)THREE.Color: 
AmbientLight只有颜色属性,使用THREE.Color对象表示颜色,通常情况下可以使用十六进制字符串,如"#0c0c0c";或使用十六进制值,如0x0c0c0c;也可以使用RGB颜色值,如(0.3, 0.5, 0.6),数值范围0~1。 
THREE.Color对象的方法:

方法

描述

set(value)

将当前颜色设置为指定的十六进制值、数值或Color实例

setHex(value)

将当前颜色设置为指定的十六进制数字值

setRGB(r, g, b)

根据提供的RGB值设置颜色,数值范围0~1

setHSL(h, s, l)

根据提供的HSL值设置颜色,数值范围0~1

setStyle(style)

根据CSS设置颜色的方式来设置颜色,如red、#f00等

copy(color)

从提供的颜色对象复制颜色到当前对象

copyGammaToLinear(color)

根据颜色实例设置,由伽马彩色空间转换到线性彩色空间

copyLinearToGamma(color)

根据颜色实例设置,由线性彩色空间转换到伽马彩色空间

convertGammaToLinear()

将当前颜色由伽马彩色空间转换到线性彩色空间

convertLinearToGamma()

将当前颜色由线性彩色空间转换到伽马彩色空间

getHex()

以十六进制值形式从颜色对象中获取颜色值

setHexString()

以十六进制字符串形式从颜色对象中获取颜色值

getStyle()

以CSS值的形式从颜色对象中获取颜色值

getHSL(optionalTarget)

以HSL值的形式从颜色对象中获取颜色值

offsetHSL(h, s, l)

将提供的h、s、l添加到当前颜色的h、s、l值上

add(color)

将r、g、b值添加到当前颜色

addColors(color1, color2)

将color1和color2相加,将得到的值设置到当前颜色

addScalar(s)

在当前颜色的RGB分量上添加值,参数范围0~1

multiply(color)

在当前颜色的RGB分量与color对象的RGB值相乘

multiplyScalar(s)

在当前颜色的RGB分量与提供的RGB值相乘

lerp(color, alpha)

找出介于对象的颜色和提供的颜色之间的颜色,alpha属性定义了当前颜色与提供的颜色的差距

equals(color)

如果Color对象实例的颜色与当前颜色相等,返回true

fromArray(array)

与setRGB方法具有相同功能,RGB值通过数组方式传入

toArray

返回三元数组[r, g, b]

clone()

复制当前颜色

其中一些方法是three.js内部使用的,包括copyGammaToLinear()、copyLinearToGamma()、addColors()、addScalar()、multiply()、multiplyScalar()、lerp()等。

2. THREE.PointLight:点光源

PointLight是一种单点发光照射所有方向的光源。因为点光源会朝所有方向发射光线,计算阴影负担太重,不提供阴影功能。 
1)创建点光源: 
var pointColor="#ccffcc"; 
var pointLight=new THREE.PointLight(pointColor); 
pointLight.position.set(10, 10, 10); 
scene.add(pointPoint); 
2)PointLight的属性: 
点光源PointLight可以设置多个属性。包括:

属性

描述

color

光源颜色

distance

光源照射的距离,默认为0,意味着光的强度不会随距离增加而减弱

intensity

光源照射的强度,默认值为1

position

光源在场景中的位置

visible

设为true,光源就会打开;设为false,光源就会关闭。默认true。

示例: 
pointLight.intensity=2.4; 
pointLight.distance=14;

3. THREE.SpotLight:聚光源

SpotLight是具有锥形效果的光源,最常用的光源之一,特别是在需要阴影时。 
1)创建聚光源: 
var spotColor="#ccffcc"; 
var spotLight=new THREE.SpotLight(spotColor); 
spotLight.position.set(-40, 60, -10); 
spotLight.castShadow=true; 
spotLight.target=plane; 
scene.add(spotPoint); 
2)SpotLight的属性: 
SpotLight具有产生光的方向和角度等属性:

属性

描述

angle

光源发出的光束的宽度,单位是弧度,默认值Math.PI/3

castShadow

如果设置为true,这个光源就会生成阴影

color

光源颜色

distance

光源照射的距离,默认为0,意味着光的强度不会随距离增加而减弱

exponent

光强衰减系数,值小时光线可以到达远处,值大时光线仅能到达近处

intensity

光源照射的强度,默认值为1

onlyShadow

如果设置为true,则该光源只生成阴影,而不产生光照

position

光源在场景中的位置

shadowBias

阴影偏移的位置,当使用非常薄的物体时设为非常小的值,如0.01,可以消除奇怪效果的阴影。默认值为0

shadowCameraFar

投影远场,设置距离光源的哪个位置可以生成阴影,默认5000

shadowCameraFov

投影视场,设置生成阴影的视场大小,默认50

shadowCameraNear

投影近场,设置从距离光源的哪个位置开始生成阴影,默认50

shadowCameraVisible

投影方式可见,设置为true可以看到在哪里以及怎样生成阴影,默认false

shadowDarkness

阴影暗度,定义阴影渲染的暗度,场景渲染后无法修改,默认0.5

shadowMapWidth

阴影映射宽度和高度,决定有多少像素用来生成阴影,当阴影看起来不光滑时可以增加此值。场景渲染后无法修改,默认为512

shadowMapHeight

target

使用此属性,可以将光源指向场景中的特定对象或位置

visible

设为true,光源就会打开;设为false,光源就会关闭。默认true。

target属性需要一个THREE.Object3D对象,如THREE.Mesh。设置阴影时,也可以几何体的castShadow和receiveShadow属性告知几何体是否接收或投射阴影。

4. THREE.DirectionalLight:平行光

平行光可以看作距离非常远的光,它发出的光线都是相互平行的,被平行光照亮的整个区域接收到的光强是一样的。 
1)创建平行光: 
var directionalColor="#ccffcc"; 
var directionalLight=new THREE.DirectionalLight(directionalColor); 
directionalLight.castShadow=true; 
scene.add(directionalLight); 
2)DirectionalLight的属性: 
平行光只有方向、颜色、强度和阴影。与聚光源SpotLight相比,相同的属性有position、target、intensity、distance、castShadow、onlyShadow、shadowCameraNear、shadowCameraFar、shadowDarkness、shadowCameraVisible、shadowMapWidth、shadowMapHeight和shadowBias。 
由于平行光的光线是平行的,照射区域是一个立方体区域,这个立方体范围内的所有物体都可以投射阴影和接收阴影。所以一般使用下面属性来设置立方体范围: 
directionalLight.shadowCameraNear=2; 
directionalLight.shadowCameraFar=200; 
directionalLight.shadowCameraLeft=-50; 
directionalLight.shadowCameraRight=50; 
directionalLight.shadowCameraTop=50; 
directionalLight.shadowCameraBottom=-50; 
当需要在一个很大的区域内设置阴影时,可以使用shadowCascade属性。属性设为true,阴影生成分裂为由shadowCascadeCount指定的值,使靠近摄像机视点处产生更多细节的阴影,而远离摄像机视点处阴影细节少。配合这个属性,还需要设置shadowCascadeCount、shadowCascadeBias、shadowCascadeWidth、shadowCascadeHeight、shadowCascadeNearZ和shadowCascadeFarZ属性。

5. THREE.HemisphereLight:半球光光源

在户外,并不是所有的光都来自上方,很多是来自大气的散射和地面以及其他物体的反射,半球光光源可以为户外场景场景更加自然的光照效果。使用这种光源会需要加载额外的资源。 
1)创建HemisphereLight: 
var hemLight=new THREE.HemisphereLight(0X0000ff, 0x00ff00, 0.6); 
hemLight.position.set(0, 500, 0); 
scene.add(hemLight); 
2)HemisphereLight光源的属性: 
使用HemisphereLight只需要指定接收自天空的颜色,接收自地面的颜色,以及这些光线的光照强度:

属性

描述

groundColor

从地面发出的光线颜色

color

从天空发出的光线的颜色

intensity

光线照射的强度

6. THREE.AreaLight:区域光

使用AreatLight可以定义一个长方形的发光区域,也是处于扩展库中。使用AreaLight需要使用THREE.WebGLDeferredRenderer进行渲染,这种方法可以更好地处理复杂的光照,或大量光源下的光照效果。这同样也需要加入额外的js脚本文件。 
创建AreaLight光源的方法为: 
var areaLight=new THREE.AreaLight(0xff0000, 3); 
areaLight.position.set(-10, 10, -35); 
areaLight.rotation.set(-Math.PI/2, 0, 0); 
areaLight.width=4; 
areaLight.height=9.9; 
scene.add(areaLight);

7. THREE.LensFlare:镜头光晕

Three.js支持镜头光晕,场景中添加非常简单。创建光晕使用的方法为: 
flare=new THREE.LensFlare(texture, size, distance, blending, color, opacity); 
其中的参数含义为:

参数

描述

texture

纹理图片,用来决定光晕的形状

size

指定光晕的大小,以像素为单位,如果指定为-1将使用纹理尺寸

distance

从光源到摄像机的距离,使用这个参数将镜头光晕放在正确位置

blending

可以为光晕提供多种材质,混合模式指定混合的方式,默认使用THREE.AdditiveBlending

color

光晕的颜色

opacity

不透明度

创建的代码为: 
var flareColor=new THREE.Color(0xffaacc); 
var lensFlare=new THREE.LensFlare(texture, 350, 0.0, THREE.AdditiveBlending, flareColor); 
lensFlare.position=spotLight.position; 
scene.add(lensFlare); 
首先要加载纹理,然后再创建光晕。还可以使用add方法为创建的光晕加入一些效果: 
lensFlare.add(texture1, 60, 0.6, THREE.AdditiveBlending); 
lensFlare.add(texture1, 120, 0.9, THREE.AdditiveBlending);

三、ThreeJS的材质:

材质决定了物体的外表,ThreeJS中的材质有:

材质

名称

描述

MeshBasicMaterial

网格基础材质

用于给几何体赋予一种简单的颜色,可显示几何体线框

MeshDepthMaterial

网格深度材质

使用从摄像机到网格的距离来决定如何给网格上色

MeshNormalMaterial

网格法向材质

一种简单材质,根据法向矢量计算物体表面的颜色

MeshFaceMaterial

网格面材质

这是一个容器,可以为几何体的各个表面指定不同材质

MeshLambertMaterial

网格Lambert材质

这是一种考虑光照影响的材质,用于创建不光亮的物体

MeshPhongMaterial

网格Phong材质

这种一种考虑光照的材质,用于创建光亮的物体

ShaderMaterial

着色器材质

这种材质允许使用自定义的着色器程序,直接控制顶点的放置方式以及像素的着色方式

RawShaderMaterial

原始着色器材质

只能与THREE.BufferedGeometry一起使用的特殊材质

LineBasicMaterial

直线基础材质

这种材质可以用于THREE.Line几何体,创建着色的直线

LineDashMaterial

虚线材质

这种材质与LineBasicMaterial一样,允许创建虚线效果

还有THREE.SpriteCanvasMaterial、THREE.SpriteMaterial和THREE.PointCliudMaterial材质,用来给单点设置样式。

1. 材质的共有属性:

ThreeJS提供了THREE.Material基类,列出了所有材质的共有属性,包括基础属性、融合属性和高级属性三类。大多数材质允许使用图片作为纹理,有些材质有与动画相关的属性。 
1)基础属性:

属性

描述

id

标识符,用来识别材质,并在材质创建时被赋值,第一个材质为0

uuid

通用唯一识别码,内部使用

name

名称,通过这个属性赋予材质名称,用于调试

opacity

不透明度,定义物体的透明度,与transparent一起使用,范围0~1

transparent

如果该值设为true,会使用指定的不透明度渲染物体;设为false就不透明,着色更明亮些。如果使用alpha通道纹理,该属性要设为true

overdraw

当使用THREE.CanvasRender时,多边形会被渲染得稍大一些,补间隙

visible

定义材质是否可见,设为false就看不到该物体

side

侧面,定义几何体某个面应用材质,默认THREE.FrontSide前面

needsUpdate

对于材质的某些修改,如果该属性设为true,ThreeJS会更新缓存

side侧面可以使用THREE.FrontSide、THREE.BackSide后面、THREE.DoubleSide双侧等。 
2)融合属性:
融合决定了渲染颜色如何与它们后面的颜色交互。

属性

描述

blending

决定物体上的材质如何与背景融合,一般为THREE.NormalBlending,这种模式下只显示材质的上层

blendsrc

定义了物体如何与背景融合,默认值THREE.SrcAlphaFactor,即使用alpha通道进行融合

blenddst

定义了如何使用背景,默认值为THREE.OneMinusSrcAlphaFactor,含义是目标也使用源的alpha通道进行融合,只是使用的值为1

blendequation

定义了如何使用blendsrc和blenddst的值,默认为使它们相加

blendequation属性大多在内部使用,用来控制WebGL渲染场景时的细节。 
3)高级属性:

属性

描述

depthTest

使用这个属性可以打开或关闭GL_DEPTH_TEST参数,此参数控制是否使用像素深度来计算新像素的值,通常不需要修改

depthWrite

用来决定这个材质是否影响WebGL的深度缓存,如果将一个物体用作二维贴图要将这个属性设为false。通常不需要修改

polygonOffset 
polygonOffsetFactor 
polygonOffsetUnits

这些属性可以控制WebGL的POLYGON_OFFSET_FILL特性,一般不需要使用

alphatest

可以指定一个从0到1的值,如果某个像素的alpha小于此值就不会显示出来。可以用来移除一些与透明度相关的毛边

4)传入属性配置材质的方法:
①构造函数中通过参数对象传入参数: 
var material=new THREE.MeshBasicMaterial({ 
color: 0xff0000, name: 'material-1', opacity: 0.5, transparency: true, ... 
}); 
②创建一个实例并分别设置属性: 
var material=new THREE.MeshBasicMaterial(); 
material.color=new THREE.Color(0xff0000); 
material.name='material-1'; 
material.opacity=0.5; 
material.transparency=true; 
一般来说,如果知道所有属性的值,最好的方式是在创建材质对象时使用构造方法传入参数。

2. THREE.MeshBasicMaterial:网格基础材质

MeshBasicMaterial是一种简单的材质,不考虑场景中光照的影响,使用这种材质的网格会被渲染成简单的平面多边形,而且也可以显示几何体的线框。 
MeshBasicMaterial还有的一些属性:

属性

描述

color

设置材质的颜色

wireframe

设置这个属性可以将材质渲染成线框,适用于调试

wireframeLinewidth

如果打开了wireframe,定义线框中线的宽度

wireframeLinecap

定义线框模式顶点间线段的端点如何显示,可选值有butt、round、square模式,默认round。WebGLRenderer不支持该属性

wireframeLinejoin

定义线框模式线段的连接点如何显示,可选值有round、bevel、miter,默认round。WebGLRenderer不支持该属性

shading

定义如何着色,可选值SmoothShading、NoShading、FlatShading,默认SmoothShading,将产生一个平滑对象,看不到单个面

vertexColors

给每个顶点定义不同颜色,默认NoColors。该属性对CanvasRenderer不起作用,对WebGLRender起作用

fog

指定当前材质是否受全局雾化效果设置的影响

3. THREE.MeshDepthMaterial:网格深度材质

使用这种材质,其外观不是由光照或某个材质属性决定,而是由物体到摄像机的距离决定。将这种材质与其他材质结合使用,容易创建逐渐消失的效果。 
这种材质只有两个控制线框显示的属性:

属性

描述

wireframe

设置这个属性可以将材质渲染成线框,适用于调试

wireframeLinewidth

如果打开了wireframe,定义线框中线的宽度

这种材质可以控制物体颜色消失的速度。摄像机的near和far属性之间的距离决定了场景的亮度和物体消失的速度,如果这个距离非常大,那么当物体远离摄像机时只会消失一点;如果这个距离非常小,那么物体消失的效果会非常明显。 
创建MeshDepthMaterial材质很简单,并可以使用scene.overrideMaterial属性以保证场景中的所有物体都会使用该材质: 
var scene.=new THREE.Scene(); 
scene.overrideMaterial=new THREE.MeshDepthMaterial();

4. 联合材质:

MeshDepthMaterial材质没法设置颜色,可以通过联合材质创建出新效果,使用材质融合。 
var cubeMaterial=new THREE.MeshDepthMaterial(); 
var colorMaterial=new THREE.MeshBasicMaterial({color: 0x00ff00, transparent: true, 
 blending: THREE.MultiplyBlending}); 
var cube=new THREE.SceneUtils.createMultiMaterialObject(cubeGeometry, 
 [colorMaterial, cubeMaterial]); 
cube.children[1].scale.set(0.99, 0.99, 0.99); 
使用联合材质的cube物体,从MeshDepthMaterial获得亮度,从MeshBasicMaterial获得颜色。

5. THREE.MeshNormalMaterial:网格法向材质

法向矢量所指的方向决定了在使用MeshNormalMaterial材质时,每个面获取的颜色。 
MeshNormalMaterial材质的属性有:

属性

描述

wireframe

设置这个属性可以将材质渲染成线框,适用于调试

wireframeLinewidth

如果打开了wireframe,定义线框中线的宽度

shading

定义如何着色,可选值SmoothShading、NoShading、FlatShading,默认SmoothShading,将产生一个平滑对象,看不到单个面

6. THREE.MeshFaceMaterial:网格面材质

网格面材质并不是一种真正的材质,而像是一种材质容器,它允许给几何体的每个面指定不同的材质。比如给一个立方体的每个面指定一种材质: 
var matArray=[]; 
matArray.push(new THREE.MeshBasicMaterial({color: 0x009e60})); 
matArray.push(new THREE.MeshBasicMaterial({color: 0x009e60})); 
matArray.push(new THREE.MeshBasicMaterial({color: 0x0051ba})); 
matArray.push(new THREE.MeshBasicMaterial({color: 0x0051ba})); 
matArray.push(new THREE.MeshBasicMaterial({color: 0xffd500})); 
matArray.push(new THREE.MeshBasicMaterial({color: 0xffd500})); 
matArray.push(new THREE.MeshBasicMaterial({color: 0xff5800})); 
matArray.push(new THREE.MeshBasicMaterial({color: 0xff5800})); 
matArray.push(new THREE.MeshBasicMaterial({color: 0xc41e3a})); 
matArray.push(new THREE.MeshBasicMaterial({color: 0xc41e3a})); 
matArray.push(new THREE.MeshBasicMaterial({color: 0xffffff})); 
matArray.push(new THREE.MeshBasicMaterial({color: 0xffffff}));

var faceMaterial=new THREE.MeshFaceMatetial(matArray); 
var cubeGeom=new THREE.BoxGeometry(3, 3, 3); 
var cube=new THREE.Mesh(cubeGeom, faceMaterial); 
代码中创建了一个数组用来保存所有的材质,然后为每个面创建了不同颜色的材质。然后用这个数组实例化材质,再结合几何体构建一个网格。

7. THREE.MeshLambertMaterial:网格Lambert材质

这种材质可以用来创建暗淡不光亮的表面,而且会对场景中的光源产生反应。这个材质可以配置与其他材质相同的一些属性,包括:color、opacity、shading、blending、depthTest、depthWrite、wireframe、wireframeLinewidth、wireframeLinecap、wireframeLineJoin、vertexColors、fog等。这种材质还有一些独有的属性:

属性

描述

ambient

这是材质的环境色,与环境光源一起使用,颜色相乘。默认白色

emissive

材质发射的颜色,只是一种不受其他光照影响的颜色,默认黑色

wrapAround

设为true则启动半lambert光照技术,如果网格有粗糙暗区,会更柔和

wrapRGB

当wrapAround设为true时,可使用Vector3来控制光下降的速度

创建材质的方法: 
var meshMaterial=new THREE.MeshLambertMaterial({color:0x7777ff});

8. THREE.MeshPhongMaterial:网格Phong材质

这种材质可以创建一种光亮的材质,可使用的属性与MeshLambertMaterial基本一样,如color、opacity、shading、blending、depthTest、depthWrite、wireframe、wireframeLinewidth、wireframeLinecap、wireframeLineJoin、vertexColors等。有特色的属性有:

属性

描述

ambient

这是材质的环境色,与环境光源一起使用,颜色相乘。默认白色

emissive

材质发射的颜色,只是一种不受其他光照影响的颜色,默认黑色

specular

指定光亮部分及高光部分的颜色,设为与color属性相同色会得到类似金属材质;设为灰色会像塑料

shininess

指定镜面高光部分的亮度,默认值30

metal

设为true,会使用略微不同的方法计算像素颜色,使物体更像金属

wrapAround

设为true则启动半lambert光照技术,如果网格有粗糙暗区,会更柔和

wrapRGB

当wrapAround设为true时,可使用Vector3来控制光下降的速度

创建材质的方法: 
var meshMaterial=new THREE.MeshPhongMaterial({color:0x7777ff});

9. THREE.ShaderMaterial:创建着色器材质

ShaderMaterial材质是通用的也是最复杂的材质,使用此材质可以定制着色器。其有特色的属性有:

属性

描述

wireframe

设置这个属性可以将材质渲染成线框,适合调试

wireframeLinewidth

如果打开了wireframe,用来定义线框中的线宽

linewidth

定义要绘制的线宽

shading

定义如何着色,可选值SmoothShading和FlatShading

vertexColors

可以通过此属性为每个顶点定义不同的颜色,对CanvasRenderer不起作用,对WebGLRender起作用

fog

指定当前材质是否受全局雾化效果设置的影响

ShaderMaterial还有一些特别属性,可用来定制着色器传入信息:

属性

描述

frameShader

通过此属性传入片元着色器程序的字符串值

vertexShader

通过此属性传入顶点着色器程序的字符串值

uniforms

通过这个属性向着色器发uniform变量信息

defines

转换成#define代码片段,用来设置着色器程序中的一些全局变量

attributes

通过此属性来传递位置数据和与法向矢量相关的数据

lights

该属性定义光照数据是否传递给着色器,默认false

创建ShaderMaterial的方法为: 
function createMaterial(vertexShader, fragmentShader) { 
 var vertShader=document.getElementById(vertexShader).innerHTML; 
 var fragShader=document.getElementById(fragmentShader).innerHTML; 
 var attributes={}; 
 vat uniforms={ 
  time:{type: 'f', value: 0.2}, 
  scale:{type: 'f', value: 0.2}, 
  alpha:{type: 'f', value: 0.6}, 
  resolution:{type: 'v2', value: new THREE.Vector2()} 
 }; 
 uniforms.resolution.value.x=window.innerWidth; 
 uniforms.resolution.value.x=window.innerHeight; 
 var meshMaterial=new THREE.ShaderMaterial({ 
  uniforms: uniforms, 
  attributes: attributes, 
  vertexShader: vertShader, 
  fragmentShader: fragShader, 
  transparent: true 
 }); 
 return meshMaterial; 
}

10. THREE.LineBasicMaterial和THREE.LineDashedMaterial:线性几何体材质

这种材质只能用于THREE.Line线段。线段只是一条线,不包含任何面,包括两种材质。 
1)THREE.LineBasicMaterial: 
这种几何体有几种可用属性:

属性

描述

color

定义线的颜色,如果指定了vertexColors,这个属性就会忽略

linewidth

定义线的宽度

linecap

定义线框模式下顶点间线段的端点怎样显示,有butt、round、square可选,默认round。WebGLRenderer不支持该属性

linejoin

定义线段的连接点如何显示,有round、bevel、miter可选,默认round。WebGLRenderer不支持该属性

vertexColors

将此属性设为THREE.VertexColors值就可以给每个顶点指定一种颜色

fog

指定当前材质是否受全局雾化效果设置的影响

2)THREE.LineDashedMaterial: 
此材质有与LineBasicMaterial一样的属性,还有几个额外属性,用来定义虚线的宽度和虚线之间间隙的宽度:

属性

描述

scale

缩放dashSize和gapSize。如果scale小于1,就会增大;大于1,就会减小

dashSize

虚线段的长度

gapSize

虚线间隔的宽度

创建方法: 
lines.computeLineDistances(); 
var material=new THREE.LineDashedMaterial({vertexColors: true, color: 0xffffff, 
 dashSize: 10, gapSize: 1, scale: 0.1}); 
创建前要先使用lines.computeLineDistances()来计算线段顶点之间的距离,不然间隔不会正确显示。

四、ThreeJS几何体:

ThreeJS提供的几何体中包括基础几何体和复杂几何体,基础几何体中还分为二维几何体和三维几何体。

1. 二维几何体:

1)THREE.PlaneGeometry:平面 
PlaneGeometry用来创建一个简单的二维矩形。创建平面的方法: 
new THREE.PlaneGeometry(width, height, widthSegments, heightSegments); 
其中的参数为:

参数

是否必需

描述

width

指定矩形的宽度

height

指定矩形的高度

widthSegments

指定矩形的宽度应该划分为几段,默认为1

heightSegments

指定矩形的高度应该划分为几段,默认为1

如果想创建一个有多个方格的样式,可以使用widthSegments和heightSegments参数,将几何体分成多个小面。如果要使用几何体属性,要使用parameters属性,比如获取width属性,要使用plane.parameters.width。 
创建基于几何体的网格: 
function createMesh(geometry) { 
 var meshMaterial=new THREE.MeshNormalMaterial(); 
 meshMaterial.side=THREE.DoubleSide; 
 var wireframeMaterial=new THREE.MeshBasicMaterial(); 
 wireFrameMaterial.wireframe=true; 
 var mesh=THREE.SceneUtils.createMultiMaterialObject( 
 geometry, [meshMaterial, wireframeMaterial]); 
 return mesh; 

创建出的二维图形位于x-y平面,一般来说希望PlaneGeometry位于x-z平面以形成地面,以便把其他物体放在上面,简单的办法是沿x轴向后旋转1/4圈,即-PI/2。代码为: 
mesh.rotation.x=-Mash.PI/2; 
2)THREE.CircleGeometry:圆形 
CircleGeometry用来创建一个二维圆或部分圆。创建圆的方法: 
new THREE.CircleGeometry(radius, segments, thetaStart, thetaLength); 
其中的参数为:

参数

是否必需

描述

radius

指定圆形的半径,默认为50

segments

指定圆形所用面的数量,最小值为3,默认值为6

thetaStart

定义开始画圆的角度,值的范围0到2*PI,默认值为0

thetaLength

定义画圆的占用角度,默认值为2*PI,即整圆

3)THREE.RingGeometry:环形 
RingGeometry用来创建一个中心有孔的二维圆。创建环的方法: 
new THREE.RingGeometry(innerRadius, outerRadius,thetaSegments, phiSegments, thetaStart, thetaLength); 
其中的参数为:

参数

是否必需

描述

innerRadius

圆环的内半径,定义中心圆孔的尺寸,默认0,没有孔

outerRadius

圆环的外半径,定义圆环的尺寸,默认50

thetaSegments

定义圆环对角线段的数量,值大时更平滑,默认8

phiSegments

定义沿圆环的长度所用的线段数量,默认8

thetaStart

定义开始画圆的角度,值的范围0到2*PI,默认值为0

thetaLength

定义环占用的角度,默认值为2*PI,即整圆

4)THREE.ShapeGeometry:任意二维图形 
ShapeGeometry可用来创建自定义二维图形。创建的方法: 
new THREE.ShapeGeometry(shapes, options); 
其中的参数为:

参数

是否必需

描述

shapes

用来创建图形的一个或多个THREE.Shape对象

options

一些选项

参数options的选项有: 
·curveSegments:此属性确定从图形创建的曲线的平滑程度,默认为12 
·material:用于为指定图形创建的面的materialIndex属性,当与THREE.MeshFaceMaterial使用时,materialIndex属性决定传入的材质中的哪些材质用于传入的图形的面 
·UVGenerator:当对材质使用纹理时,UV映射决定纹理的哪个部分用于特定的面。 
5)THREE.Shape:绘图函数 
用ShapeGeometry创建自定义二维图形时,需要使用THREE.Shape绘图函数绘制图形,这些函数是从THREE.Path类继承来的。 
⑴moveTo(x, y):将绘图点移动到指定点(x, y) 
⑵lineTo(x, y):从当前位置绘制一条线到指定点(x, y) 
⑶fromPoints(vectors):沿着提供的矢量对象数组绘制直线路径,参数为THREE.Vector2或THREE.Vector3对象数组。 
⑷splineThru(pts):沿着提供的坐标集pts绘制一条光滑曲线,参数为THREE.Vector2对象数组,起始点是路径的当前位置 
⑸quadraticCurveTo(aCPx, aCPy, x, y):使用额外点(aCPx, aCPy)绘制曲线到指定点(x, y) 
⑹bezierCurveTo(aCpx1, aCPy1, aCpx2, aCPy2,x, y):使用两个额外点(aCPx1, aCPy1)和(aCPx2, aCPy2)绘制曲线到指定点(x, y) 
⑺arc(aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise):用来画圆弧,圆弧起始于当前位置,aX、aY用来指定与当前位置的偏移量,aRadius设置圆的大小,aStartAngle、aEndAngle指定起始和结束的角度,布尔值aClockwise指定顺时针或逆时针。 
⑻absArc(aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise):位置是绝对位置,而不是相对于当前位置,其中参数类似arc()。 
⑼ellipse(aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise):通过x轴半径及y轴半径,绘制椭圆弧。 
⑽absEllipse(aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise):位置是绝对位置,而不是相对于当前位置,其中参数类似ellipse()。 
⑾holes:包含一个THREE.Shape对象数组,其中每个对象会渲染为一个孔 
使用THREE.Shape创建ShapeGeometry几何体的实例: 
function drawShape() { 
 var shape=new THREE.Shape(); 
 shape.moveTo(10, 10); 
 shape.lineTo(10, 40); 
 shape.bezierCurveTo(15, 25, 25, 25, 25, 30, 40); 
 shape.splineThru([ 
  new THREE.Vector2(32, 30), 
  new THREE.Vector2(28, 20), 
  new THREE.Vector2(30, 10) 
 ]) 
 shape.quadraticCurveTo(20, 15, 10, 10);

 var hole1=new THREE.Path(); 
 hole1.absellipse(16, 24, 2, 3, 0, Math.PI*2, true); 
 shape.holes.push(hole1); 
 var hole2=new THREE.Path(); 
 hole2.absellipse(23, 24, 2, 3, 0, Math.PI*2, true); 
 shape.holes.push(hole2); 
 var hole3=new THREE.Path(); 
 hole3.absellipse(20, 16, 2, 3, 0, Math.PI*2, true); 
 shape.holes.push(hole3);

 return shape; 

代码中使用line、curve和spline创建了图形轮廓,然后使用THREE.Shape对象的holes属性给图形打孔。THREE.Shape创建好后,就可以使用来创建几何体: 
new THREE.ShapeGeometry(drawShape()); 
THREE.Shape还有一些函数: 
·makeGeometry(options):该函数从THREE.Shape返回一个THREE.ShapeGeometry对象。 
·createPointsGeometry(divisions):该函数将图形转换成一个点集,divisions属性定义返回点的数量,这个值越高最终的曲线越平滑。divisions会分别应用到路径的每一部分。 
·createSpacedPointsGeometry(divisions):该函数也将图形转换成一个点集,这里的divisions是一次性地应用到整个路径。 
使用示例: 
new THREE.Line(shape.createPointsGeometry(10), new THREE.LineBasicMaterial({color: 0xff3333, linewidh: 2}));

2. 三维几何体:

1)THREE.BoxGeometry:长方体 
使用BoxGeometry只需要指定宽度、高度、深度就可以创建长方体。创建方法: 
new THREE.BoxGeometry(10, 10, 10); 
创建BoxGeometry的参数有:

参数

是否必需

描述

width

定义长方体的宽度,即沿x轴方向的长度

height

定义长方体的高度,即沿y轴方向的长度

depth

定义长方体的深度,即沿z轴方向的长度

widthSegments

定义沿x轴方向将面分成多少份,默认为1

heightSegments

定义沿y轴方向将面分成多少份,默认为1

depthSegments

定义沿z轴方向将面分成多少份,默认为1

通过增加多个分段segment属性,可以将长方体的6个面分成很多小面。 
2)THREE.SphereGeometry:球体 
使用SphereGeometry可以创建一个三维球体,可以不用任何参数。 
创建SphereGeometry的参数有:

参数

是否必需

描述

radius

设置球体的半径,默认为50

widthSegments

指定竖直方向上的分段数,段多则光滑,默认8,最小3

heightSegments

指定水平方向上的分段数,段多则光滑,默认6,最小2

phiStart

指定开始绘制球体的x轴的位置,范围0到2*PI,默认0

phiLength

指定从phiStart开始绘制的范围,默认2*PI,完整球体

thetaStart

指定开始绘制球体的y轴的位置,范围0到PI,默认0

thetaLength

指定从thetaiStart开始绘制的范围,默认PI,完整球体

可以使用SphereGeometry创建球体的部分曲面。 
3)THREE.CylinderGeometry:圆柱体 
使用CylinderGeometry可以创建一个圆柱体,可以不用任何参数。 
创建CylinderGeometry的参数有:

参数

是否必需

描述

radiusTop

设置圆柱顶部的尺寸,默认为20

height

设置圆柱底部的尺寸,默认为20

radiusTop

设置圆柱的高度,默认值100

radialSegments

指定圆柱半径的分段数,段多则光滑,默认8

heightSegments

指定圆柱高度的分段数,段多则面多,默认1

openEnded

网格的顶部和底部是否封闭,默认false

使用CylinderGeometry时,顶部或底部使用负数半径时,可以创建类似沙漏的形状,但半个柱体是内外翻转的,需要材质设为THREE.DoubleSide,否则看不到内外翻转的部分。 
4)THREE.TorusGeometry:圆环体 
使用TorusGeometry可以创建一个类似甜甜圈的环状体,可以不用任何参数。 
创建TorusGeometry的参数有:

参数

是否必需

描述

radius

设置圆环的尺寸,默认为100

tube

设置圆环中管的半径,默认40

radiusSegments

设置沿圆环长度方向分成的段数,默认8

tubularSegments

设置沿圆环宽度方向分成的段数,默认6

arc

控制是否绘制一个完整的圆环,默认2*PI

使用TorusGeometry的arc参数可以绘制圆环的一部分。 
5)THREE.TorusKnotGeometry:环状纽结 
使用TorusKnotGeometry可以创建一个环状纽结,像一个管子绕了几圈。 
创建TorusKnotGeometry的参数有:

参数

是否必需

描述

radius

设置圆环的尺寸,默认为100

tube

设置圆环中管的半径,默认40

radiusSegments

设置沿环状纽结长度分成的段数,默认64

tubularSegments

设置沿环状纽结宽度方向分成的段数,默认8

p

定义环状纽结的形状,默认值2

q

定义环状纽结的形状,默认值3

heightScale

通过这个属性可以拉伸这个环状纽结,默认值为1

使用TorusKnotGeometry的参数p和q可以创建各种各样的管状几何体,p定义纽结绕其轴线旋转的频率,q定义纽结绕其内部缠绕多少次。 
6)THREE.PolyhedronGeometry:多面体 
多面体是只有平面和直边的几何体,但多数情况下不会直接使用这种几何体,ThreeJS提供了几种特定的多面体,可以直接使用。如果使用PolyhedronGeometry必须指定顶点和面。 
var vertices=[1, 1, 1, -1, -1, 1, -1, 1, -1, 1, -1, -1]; 
var indices=[2, 1, 0, 0, 3, 2, 1, 3, 0, 2, 3, 1]; 
polyhedron = createMesh ( new THERE.PolyhedronGeometry ( vertices, indices, controls.radius, controls.detail)); 
为了创建一个PolyhedronGeometry对象,需要传入vertices、indices、radius和detail参数。创建多面体的参数有:

参数

是否必需

描述

vertices

设置构成多面体的顶点

indices

设置由vertices创建出的面

radius

指定多面体的大小,默认为1

detail

为多面体添加额外细节。设为1,多面体上的每个三角形都会分成4个三角形;设为2,那4个三角形中的每一个将会继续分成4个小三角形;以此类推。

7)THREE.IcosahedronGeometry:二十面体 
使用IcosahedronGeometry可以创建一个有20个三角形面的多面体,这些三角形面是从12个顶点创建出来的。创建这个多面体时,只需要指定radius和detail的值。 
8)THREE.TetrahedronGeometry:四面体 
使用TetrahedronGeometry可以创建一个只包含4个顶点和4个三角形面的最简单的多面体,只需要指定radius和detail的值。 
9)THREE.OctahedronGeometry:八面体 
使用OctahedronGeometry可以创建一个八面体,8个面是从6个顶点创建出来的,只需要指定radius和detail的值。 
10)THREE.DodecahedronGeometry:十二面体 
使用DodecahedronGeometry可以创建一个十二面体,只需要指定radius和detail的值。

3. 高级几何体:

1)THREE.ConvexGeometry:凸面体 
通过ConvexGeometry可以围绕一组点创建一个凸包,就是包围这组点的最小图形。使用ConvexGeometry需要引入ConvexGeometry.js脚本文件。如果创建了一组点points就可以创建一个ConvexGeometry对象: 
var convexGeometry=new THREE.ConvexGeometry(points); 
convexMesh=createMesh(convexGeometry); 
scene.add(convexMesh); 
保存顶点的数组是创建ConvexGeometry的唯一参数。 
2)THREE.LatheGeometry:旋转体 
LatheGeometry允许从一条光滑曲线经旋转创建图形。此曲线是由多个点定义的,通常称为样条曲线。这条样条曲线绕物体的中心z轴旋转,就得到了类似花瓶的图形。 
创建LatheGeometry,除了顶点数组,还接受其他几个参数:

参数

是否必需

描述

points

指定构成样条曲线的点

segments

指定创建图形时所用的分段数目,数值越大就越圆,默认12

phiStart

指定创建图形时的起始角度,取值0到2*PI,默认0

phiLength

指定创建图形时的角度范围,默认值2*PI,完整图形

3)THREE.ExtrudeGeometry:拉伸体 
使用ExtrudeGeometry可以用二维图形沿z轴拉伸成三维图形。创建的方法为: 
var options={amount: 10, bevelThickness: 2, bevelSize: 1, bevelSegments: 3, bevelEnables: true, curveSegments: 12, steps: 1}; 
shape=createMesh(new THREE.ExtrudeGeometry(drawShape(), options)); 
其中,使用drawShape()函数创建了一个图形,然后将这个图形连同options对象一起传递给ExtrudeGeometry的构造函数。通过options可以定义图形怎样拉伸,其中的选项有:

参数

是否必需

描述

shapes

拉伸几何体需要提供的一个或多个图形

amount

指定图形拉伸的深度,默认100

bevelThickness

指定斜角的深度,斜角是前后面和拉伸体之间的倒角,定义斜角进入图形的深度,默认为6

bevelSize

指定斜角的高度,这个高度被加到图形正常的高度上,默认为bevelThickness-2

bevelSegments

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

bevelEnables

这个属性设为true就会有斜角,默认为true

curveSegments

指定拉伸图形时曲线分成的段,段数多则平滑,默认12

steps

指定拉伸体沿深度方向分的段数,默认1,值大则面多

extrudePath

指定图形拉伸路径THREE.CurvePath,不指定则沿z轴

material

指定前后面用的材质的索引

extrudeMaterial

指定斜角和拉伸体的材质

uvGenerator

材质使用纹理时,UV映射确定纹理哪部分用于特定的面

frames

用于计算样条曲线的切线、法线和副法线,不需要指定

SVG与ThreeJS处理图形的方式一致,使用d3-threeD小型库可将SVG路径转换成ThreeJS图形: 
function drawShape() { 
 var svgString=document.querySelector("#batman-path").getAttribute("d"); 
 var shape=transformSVGPathExposed(svgString); 
 return shape; 

然后就可以使用ExtrudeGeometry进行转换,变成三维几何体: 
shape=createMesh(new THREE.ExtrudeGeometry(drawShape(), options)); 
4)THREE.TubeGeometry:管状体 
TubeGeometry允许沿一条三维的样条曲线拉伸出一根管,通过指定一些顶点来定义路径,然后创建这根管。如果已经定义了点数组points,创建TubeGeometry的方法为: 
var tubeGeometry = new THREE.TubeGeometry ( new THREE.SplineCurve3 (points), segments, radius, radiusSegments, closed); 
var tubeMesh=createMesh(tubeGeometry); 
scene.add(tubeMesh); 
定义的顶点需要转换成THREE.SplineCurve3对象,也就是用来定义一条平滑的曲线,然后创建TubeGeometry管状体。创建时还接受其他一些参数:

参数

是否必需

描述

path

用一个THREE.SplineCurve3对象来指定管循的路径

segments

指定构建管所用的分段数,默认64.,路径长分段就要多

radius

指定管的半径,默认为1

radiusSegments

指定管道圆周的分段数,默认8。分段越多管道越圆

closed

设为true,管的头尾会连起来,默认false

5)THREE.ParametricGeometry:参数几何体 
通过ParametricGeometry可以创建基于等式的几何体,这需要使用ParametricGeometry.js脚本文件,这个文件中可以找到几个公式的示例,可以与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,u值用来确定向量的x坐标,v值用于确定z坐标,调用时就会得到宽为width深为depth的基础平面。示例的几何体: 
radialWave=function(u, v) { 
 var r=50; 
 var x=Math.sin(u)*r; 
 var z=Math.sin(v/2)*2*r; 
 var y=(Math.sin(u*4*Math.PI)+Math.cos(v*2*Math.PI))*2.8; 
 return new THREE.Vectors(x, y, z); 

var mesh=createMesh(new THREE.ParametricGeometry(radialWave, 120, 120, false)): 
创建ParametricGeometry的参数有:

参数

是否必需

描述

function

函数以u、v值作为参数定义每一个顶点的位置

slices

定义u值应该分成多少份

stacks

定义v值应该分成多少份

u、v属性会传递给由function指定的函数,并且这两个参数的取值范围是0~1。通过slices和stacks可以指定传入function的调用频率。值越大,生成的向量越多,创建出的几何体越平滑。ParametricGeometry.js文件中有克莱因瓶、二维莫比乌斯带、三维莫比乌斯带、管、环状纽结、球体等几何体的函数。

4. 三维文本:

1)THREE.TextGeometry:文本几何体 
使用TextGeometry可以使用三维文本,只需要指定要用的字体。 
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中的选项options中的参数有:

参数

是否必需

描述

size

指定文本的大小,默认100

height

指定拉伸的深度,默认50

weight

指定字体的粗细,可选值有normal和bold,默认normal

font

指定要用的字体名,默认helvetiker

style

指定字体的样式,可选值有normal和italic,默认normal

bevelThickness

指定斜角的深度,斜角是前后面和拉伸体之间的倒角,定义斜角进入图形的深度,默认为10

bevelSize

指定斜角的高度,默认为8

bevelSegments

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

bevelEnables

这个属性设为true就会有斜角,默认为false

curveSegments

指定拉伸图形时曲线分成的段,段数多则平滑,默认4

steps

指定拉伸体沿分的段数,默认1,值大则面多

extrudePath

指定图形拉伸路径THREE.CurvePath,不指定则沿z轴

material

指定前后面用的材质的索引

extrudeMaterial

指定斜角和拉伸体的材质

uvGenerator

材质使用纹理时,UV映射确定纹理哪部分用于特定的面

frames

用于计算样条曲线的切线、法线和副法线,不需要指定

TextGeometry在内部使用ExtrudeGeometry构建三维文本,并且JavaScript字体引入大量开销。渲染二维文字使用canvas更简单,也可以将canvas输出作为纹理输入WebGL。 
2)添加自定义字体: 
ThreeJS提供了几种可以在场景中使用的字体,这些字体基于typeface.js提供的字体,这个函数库可以将TrueType和OpenType字体转换为JavaScript的库,转换出来的JavaScript文件可以包含在文件页面中,然后就可以在ThreeJS中使用。 
要转换已有的TrueType和OpenType字体,可以在typeface提供的页面长传字体,然后生成JavaScript。直线多的字体容易被正确渲染。要包含这个字体,只需要在HTML中添加代码: 
 
这样就可以加载字体,并在ThreeJS中使用。

5. 使用二元操作组合网络:

将各种标准几何体组合在一起可以创建出相交、相减、联合等新的几何体,为此需要引入扩展库ThreeBSP。ThreeBSP提供了三个函数:

函数名

描述

intersect

相交,可以基于两个现有几何体的交集创建出新的几何体

union

联合,可以将两个几何体联合起来创建出一个新的几何体

substract

相减,与union相反,在第1个几何体中移除两个几何体重叠的部分

这个库是使用CoffeeScript写的,可以添加这个文件并在运行时编译,或者预先编译成JavaScript文件。这三个函数使用的是网格的绝对位置,为了得到正确的结果要确保使用的是未经组合的网格。 
其中的union联合其实一般不会使用,而是使用THREE.Geometry.merge()方法来组合几何体。

五、粒子和点云:

使用粒子particle可以很容易地创建细小的物体,可以模拟雨滴、雪花、烟等效果。

1. THREE.PointCloud:点云

点云有几何体和材质两个属性,其中材质用来给粒子着色和添加纹理,而几何体则用来指定单个粒子的位置,每个顶点和每个用来定义几何体的点将会以粒子的形态展示出来。可以基于Geometry对象创建PointCloud对象,一般来说则是手工将顶点添加到几何体上,或者使用一个外部加载的模型。示例: 
function createParticles(size, transparent, opacity, vertexColors, sizeAttenuation, color) { 
 var geom=new THREE.Geometry(); 
 var material=new THREE.PointCloudMaterial({ size: size, transparent: transparent, opacity: opacity, vertexColors:  vertexColors, sizeAttenuation: sizeAttenuation, color: color}); 
 var range=500; 
 for(var i=0; i<15000; i++) { 
  var particle=new THREE.Vector3(Math.random()*range-range/2, Math.random() *range -range/2, Math.random()*range-range/2); 
  geom.vertices.push(particle); 
  var color=new THREE.Color(0x00ff00); 
  color.setHSL(color.getHSL().h, color.getHSL().s, Math.random()*color.getHSL().l); 
  geom.colors.push(color); 
 } 
 cloud=new THREE.PointCloud(geom, material); 
 scene.add(cloud); 
}

2. THREE.PointCloudMaterial:点云材质

点云材质对象可设置的属性有:

属性

描述

color

ParticleSystem中所有粒子的颜色,将vertexColors属性设为true,并且通过颜色属性指定几何体颜色就与此值相乘确定颜色,默认0xffffff

map

通过此属性可以在粒子上应用某种材质,如看起来像雪花

size

指定粒子的大小,默认为1

sizeAnnutation

如果该属性设为false,那么所有粒子都将有相同尺寸;设为true,粒子大小取决于距离摄像机的远近。默认true

vertexColors

属性设为THREE.VertexColors,且几何体颜色数组有值,就会用颜色数组中的值;默认THREE.NoColors,所有粒子都有相同颜色

opacity

与transparent属性一起使用,设置粒子不透明度,默认1

transparent

设为true,粒子在渲染时根据opacity来确定透明度,默认false

blending

指定渲染粒子时的融合模式

fog

决定粒子是否受场景中雾化效果影响,默认true

粒子默认渲染为小方块,可以使用其他方法来样式化粒子。

3. 使用HTML5画布样式化粒子:

有CanvasRenderer和WebGLRenderer两种方式。 
1)THREE.CanvasRenderer中使用HTML5画布:
通过THREE.SpriteCanvasMaterial可以将HTML5画布的输出作为粒子的纹理,这种材质是专为THREE.CanvasRenderer创建的,而且只能在使用这种渲染器时才有效。 
THREE.SpriteCanvasMaterial的属性有:

属性

描述

color

指定粒子的颜色,根据指定的混合模式,影响画布图片的颜色

program

指定一个以canvas上下文为参数的函数,粒子渲染时被调用来显示粒子

opacity

决定粒子的不透明度,默认为1,表示完全不透明

transparent

决定粒子是否透明显示,与opacity一起使用

blending

指定粒子的融合模式

rotation

允许旋转画布内容,通常此属性设为PI以正确对齐画布内容

2)THREE.WebGLRenderer中使用HTML5画布:
如果要在WebGLRenderer中使用HTML5画布,有两种方法,可以使用PointCloudMaterial并创建PointCloud,或者使用THREE.Sprite和THREE.SpriteMaterial的map属性。 
PointCloudMaterial有map属性,用于为粒子加载纹理,该纹理可以是HTML5画布的输出。PointCloud有一个FrustumCulled属性,设为true时意味着在摄像机可见范围外的粒子不会被渲染,这样可以提高性能。 
使用THREE.Sprite可以更好地控制单个粒子,但当粒子数量大时性能会降低,也会更复杂;使用PointCloud可以轻松管理大量粒子,但对单个粒子的控制能力会减弱。

4. 使用纹理化粒子:

使用图像样式化粒子有更直接的方法,可以使用THREE.ImageUtils.loadTexture()函数将图像加载为THREE.Texture,然后就可以分配给材质的map属性。 
加载纹理图像后,使用PointCloudMaterial的map属性指向加载的纹理,融合模式设为THREE. AdditiveBlending。如果要使用多张图片作为纹理,就需要使用多个粒子系统,每个粒子系统的材质使用不同的纹理。有时需要设置depthWrite属性为false,这个属性决定这个对象是否影响WebGL的深度缓存,设为false可以保证各个点云之间不会相互影响,也就是前面的粒子不会影响后面的粒子的显示。

5. 使用精灵贴图:

使用THREE.Sprite时,可以用THREE.SpriteMaterial的map属性指向一张包含所有精灵的纹理,通过map.offset和map.repeat属性选择其中的每一个精灵。map.offset属性决定纹理在x轴和y轴上的偏移量,map.repeat属性可以放大局部。 
THREE.SpriteMaterial的属性有:

属性

描述

color

粒子的颜色

map

精灵所用的纹理

sizeAnnutation

设为false,那么所有粒子尺寸相同,不取决于距离摄像机的远近。

opacity

设置粒子不透明度

blending

指定渲染粒子时的融合模式

fog

决定粒子是否受场景中雾化效果影响,默认true

还可以使用depthTest和depthWrite属性。

6. 从高级几何体创建粒子:

如果提供一个复杂的几何体,就可以根据这个几何体的顶点创建出一个PointCloud对象。

六、高级网格和几何体:

可以将已有的几何体经组合合并创建新的几何体,还可以从外部加载网格和几何体。

1. 几何体的组合与合并:

可以将几何体组合在一起,以及将多个网格合并为一个网格。 
1)组合: 
当从一个几何体创建网格并且使用多种材质时,ThreeJS就会创建一个组,该几何体的多个副本就会添加到这个组中,每份副本都有自己特定的材质,这个组是一个包含多个网格的组。 
每个创建的网格都包含子元素,子元素可以使用add函数来添加。在组中添加子元素,对父对象的移动、缩放、旋转和变形操作会影响所有子元素。 
sphere=createMesh(new THREE.SphereGeometry(5, 10, 10)); 
cube=createMesh(new THREE.BoxGeometry(6, 6, 6)); 
group=new THREE.Object3D(); 
group.add(sphere); 
group.add(cube); 
scene.add(group); 
代码中创建了一个THREE.Object3D对象,这是THREE.Mesh和THREE.Scene的基类,但是它本身不包含任何物体,也不会渲染任何物体。ThreeJS新版本中引入了THREE.Group对象以支持分组,该对象与THREE.Object3D完全相同,可以替代THREE.Object3D。这里使用add方法将sphere和cube添加到group中,然后再添加到scene中。 
创建这个group后,当对这个组进行旋转、缩放等操作时,整个组旋转、缩放。 
2)多个网络合并: 
多数情况下使用组可以很容易地操纵和管理大量网络,但组中每个对象还是独立的,仍然需要对它们分别进行处理和渲染,数量非常多时就会成为性能瓶颈。 
通过THREE.Geometry.merge()方法可以将多个几何体合并起来创建一个联合体。 
var geometry=new THREE.Geometry(); 
for(var i=0; i  var cubeMesh=addcube(); 
 cubeMesh.updateMatrix(); 
 geometry.merge(cubeMesh.geometry, cubeMesh.matrix); 

scene.add(new THREE.Mesh(geometry, cubeNaterial)); 
新版本的ThreeJS中支持THREE.Geometry.merge()方法。为了确保能正确定位好旋转合并的THREE.Geometry对象,不仅向merge方法提供THREE.Geometry对象,还提供对象的变换矩阵。将矩阵添加到merge方法后,合并的几何体将会正确定位。 
merge方法得到的是一个几何体,不能为其中的每个几何体单独添加材质,这个问题可以使用THREE.MeshFaceMaterial来部分地解决。组合成的几何体,已经失去对其中每个对象的单独控制。

2. 从外部资源加载几何体:

ThreeJS可以读取几种三维模型文件格式,并从中导入几何体和网格。支持的文件格式有:

格式

描述

JSON

ThreeJS有自己的JSON格式,可用来声明几何体和场景

OBJ及MTL

是使用最广泛的一种简单的三维文件格式,用来定义几何体

Collada

一种基于XML格式的定义数字内容的格式,也被广泛使用

STL

广泛用于快速成形的模型文件,如用于三维打印机

CTM

由openCTM创建的一种文件格式,用压缩格式存储三维网络的三角形面

VTK

Visualization Toolkit创建的文件格式,指定顶点和面,只支持ASCII的

AWD

用于三维场景的二进制格式,通常与away3d引擎一起使用

Assimp

是一种各种三维格式的标准方法,由assimp2json转换的格式可以导入

VRML

一种基于文本的格式,允许定义三维世界和物体,已被X3D取代

Babylon

是一个JavaScript游戏库,以自己的格式存储模型

PDB

由蛋白质数据银行Protein Data Bank创建,定义蛋白质的形状

PLY

多边形文件格式,通常用来保存三维扫描仪的信息

ThreeJS还有可定制的OBJ及STL导出器,可以用来将ThreeJS中的模型导出为OBJ或STL文件。 
1)JSON格式: 
ThreeJS中导出JSON格式非常容易,不需要引入额外的库,只需要将THREE.Mesh导出为JSON: 
var result=knot.tiJSON(); 
localStorage.setItem("json", JSON.stringify(result)); 
这个JSON格式信息可以使用HTML5的本地存储API保存。而将这个几何体JSON文件加载到ThreeJS中,加载代码为: 
var json=localStorage.getItem("json"); 
if(json){ 
 var loadedGeometry=JSON.parse(json); 
 var loader=new THREE.ObjectLoader(); 
 loadedMesh-loader.parse(loadedGeometry); 
 loadedMesh.position.x-=50; 
 scene.add(loadedMesh); 

这个加载器还提供了load方法,用于传入URL地址,指向一个含义JSON定义的文件。 
上面这里只保存了THREE.Mesh信息,如果想保存整个场景,包括光源和摄像机,要使用THREE.SceneExporter,需要引入SceneLoader.js和SceneExporter.js脚本文件。到处的代码: 
var exporter=new THREE.SceneExporter(); 
var sceneJson=JSON.stringify(exporter.parse(scene)); 
localStorage.setItem('scene', sceneJson); 
当再次加载此JSON时,只是三其导出时的定义重新创建对象。代码: 
var json=localStorage.getItem("scene"); 
var sceneLoader=new THREE.SceneLoader(); 
sceneLoader.parse(JSON.parse(json), function(e) { 
 scene=e.scene; 
}, '.'); 
传递给加载器的最后一个参数('.')是一个URL相对地址。 
2)Blender: 
Blender是一种常用的创建三维模型的软件。可以在其中添加ThreeJS插件,就可以直接到出ThreeJS模型。在ThreeJS发布包中有utils/exporters/blender/2.65/scripts/addons/文件夹,其中有子目录,可以将这个子目录复制到Blender安装目录的addons文件夹中。启动Blender,需要激活导出器,打开Blender User Preferences (File|User Preferences),在弹出的窗口中找到Addons标签页,在其中搜索框中输入three,找到插件后,选择右边的小复选框,导出器就激活了。然后Blender的File|Export菜单项中会看到Three.js出现在Export选项中。 
使用Blender的ThreeJS插件,导出的是JSON格式的文件。 
3)导入OBJ和MTL格式文件: 
OBJ和MTL是相互配合的两种格式,都是基于文本的,其中OBJ文件定义几何体,而MTL文件定义所用的材质。ThreeJS可以很好地理解这两种文件,Blender也支持这两种文件格式。 
加载OBJ几何体使用OBJLoader加载器,需要引入OBJLoader.js脚本文件。代码为: 
var loader=new THREE.OBJLoader(); 
loader.load ('pin.obj', function (loadedMesh){ 
 var material = new THREE. MeshLambertMaterial ({color: 0x5c3a21})}); 
 loadedMesh. children.forEach (function (child) { 
  child.material=material; 
  child.geometry.computeFaceNormals(): 
  child.geometry.computeVertexNormals(); 
 }); 
 mesh=loadedMesh; 
 loadedMesh.scale.set(100, 100, 100); 
 loadedMesh.rotation.x=-0.3; 
 scene.add(loadedMesh); 
}); 
而加载MTL文件需要使用MTLLoader加载器,也需要引入MTLLoader.js脚本。 
4)加载Collada模型: 
Collada模型文件扩展名为dae,其中不仅定义几何体,也定义材质,甚至还可以定义光源。要使用ColladaLoader加载器加载文件,需要引入ColladaLoader.js脚本。代码为: 
var mesh; 
loader.load("truck.dae", function(result) { 
 mesh=result.scene.children[0].children[0].clone(); 
 mesh.scale.set(4, 4, 4); 
 scene.add(mesh); 

因为模型中纹理使用的是tga格式,WebGL不支持,必须把tga格式转换成png文件,并修改dae文件的XML元素,指向转换后的png文件,这样才能正确渲染。 
5)加载STL、CTM、VTK、AWD、Assimp、VRML、Babylon和PLY模型: 
需要在模型渲染之前改变一些材质属性,或者对其进行缩放。 
6)加载PDB蛋白质数据银行格式: 
加载PDB文件需要使用PDBLoader加载器,这需要引入PDBLoader.js脚本。 
7)加载Blender、Collada、MD2、glTF动画: 
有些外部模型软件,如Blender、Collada、MD2、glTF等,可以创建动画模型。Blender中创建的动画以骨骼动画方式导出,ThreeJS可以加载导出的JSON文件。Collada动画模型也是dae文件,而MD2需要转换为js文件及纹理图片。

七、加载和使用纹理:

ThreeJS可以使用纹理实现不同的效果,定义网格的颜色,定义高光、凹凸和反光。

1. 加载纹理并应用到网格:

纹理最基础的用法是作为贴图被添加到材质上,当使用这种材质创建网格时,网格的颜色来源于纹理。使用的方法为: 
function createMesh(geom, imageFile) { 
 var texture=THREE.ImageUtils.loadTexture("textures/"+imageFile); 
 var mat=new THREE.MeshPhongMaterial(); 
 mat.map=texture; 
 var mesh=new THREE.Mesh(geom, mat); 
 return mesh; 

代码中从指定位置加载图片文件,图片格式可以是PNG、GIF、JPEG。纹理的加载是异步的,如果想在纹理加载前一直等待,可以使用: 
texture=THREE.ImageUtils.loadTexture('texture.png', {}, function() {renderer.render(scene);}); 
loadTexture提供了回调函数,回调函数会在纹理加载完成之后调用。代码中并没有使用回调函数,而是依赖于render循环在纹理加载完成时显示纹理。 
为了达到最好效果,最好使用长宽大小为2的次方的正方形图片。由于纹理通常需要放大或缩小,所以纹理上的像素不会一对一地映射到面的像素上。为此,WebGL和ThreeJS提供了各种选项,可以设置magFilter属性来指定纹理如何放大,设置manFilter属性指定纹理如何缩小。

THREE.NearestFilter

最邻近过滤,将纹理上最近的像素颜色应用到面上,放大时会导致方块化,缩小时会丢失很多细节

THREE.LinearFilter

线性过滤,最终的颜色由周围4个像素来决定,缩小时仍会丢失一些细节,放大时会平滑很多

还可以使用mipmap。mipmap是把纹理按照2的倍数进行缩小,直到像素为1x1,然后这些图像都存储起来。mipmap纹理的过滤模式有:

THREE.NearestMipMapNearestFilter

选择最邻近的mip层,并执行最邻近过滤,虽然放大时仍然会有方块化,但缩小时效果会好很多

THREE.NearestMipMapLinearFilter

选择最邻近的两个mip层,并分别在这两个mip层上运行最邻近过滤获取两个中间值,最后将这两个中间值传递到线性过滤器

THREE.LinearMipMapNearestFilter

选择最邻近的mip层,并执行线性过滤

THREE.LinearMipMapLinearFilter

选择最邻近的两个mip层,并分别在这两个mip层上运行最邻近过滤获取两个中间值,最后将这两个中间值传递到线性过滤器

如果没有指定magFilter和minFilter属性的值,ThreeJS会将THREE.LinearFilter作为magFilter属性的默认值,将THREE.LinearMipMapLinearFilter作为minFilter属性的默认值。 
ThreeJS还提供了一些自定义加载器以加载其他格式的纹理文件: 
·THREE.DDSLoader:可以加载DDS纹理,需要引入DDSLoader.js脚本 
·THREE.PVRLoader:可以加载PVR纹理,需要引入PVRLoader.js脚本,只支持power VR3.0 
·THREE.TGALoader:可以加载TGA纹理,需要引入TGALoader.js脚本

2. 使用凹凸贴图创建皱褶:

function createMesh(geom, imageFile, bump) { 
 var texture=THREE.ImageUtils.loadTexture("textures/"+imageFile); 
 var mat=new THREE.MeshPhongMaterial(); 
 mat.map=texture; 
 var bump=THREE.ImageUtils.loadTexture("textures/"+bump); 
 mat.bumpMap=bump; 
 mat.bumpScale=0.2; 
 var mesh=new THREE.Mesh(geom, mat); 
 return mesh; 

代码中除了设置map属性,还设置了bumpMap属性,通过bumpScale属性可以设置凹凸的高度,如果值为负则表示深度。其中的凹凸贴图是一张灰度图,也可以使用彩色图,像素的密集程度定义的是凹凸的高度,但其中只包含像素的相对高度而没有任何倾斜方向信息。

3. 使用法向贴图创建细致的凹凸和皱褶:

法线贴图保存的是法向量的方向,只需要使用很少的顶点和面就可以创建出细节很丰富的模型。 
function createMesh(geom, imageFile, normal) { 
 var tex=THREE.ImageUtils.loadTexture("textures/"+imageFile); 
 var norm=THREE.ImageUtils.loadTexture("textures/"+bump); 
 var mat2=new THREE.MeshPhongMaterial(); 
 mat2.map=tex; 
 mat.normalMap=norm; 
 var mesh=new THREE.Mesh(geom, mat2); 
 return mesh; 

代码中将normalMap属性设置为法向纹理,还可以设置normalScale属性为mat.normalScale. set(1, 1)来指定凹凸程度,通过这两个参数可以沿x轴和y轴进行缩放,但最好的方式是将它们的值设置成一样,以达到最好的效果。如果设置为负值,高度就会反转。 
法向贴图的最大问题是很难创建,需要使用Blender和Photoshop,这些工具可以将高分辨率的效果图或者纹理作为输入来创建法向贴图。ThreeJS提供了运行期创建法向贴图的方法,THREE.ImageUtils对象有一个getNormalMap方法,该方法接受JavaScript/DOM图像作为输入并将其转换为法向贴图。

4. 使用光照贴图创建阴影效果:

光照贴图是预先渲染好的阴影,可以用来模拟真实的阴影。使用这种技术可以创建出分辨率较高的阴影,而且也不会损害渲染的性能,但只对静态场景有效。 
var lm=THREE.ImageUtils.loadTexture("textures/"+lightFile); 
var wood=THREE.ImageUtils.loadTexture("textures/"+woodFile); 
var groundMaterial=new THREE.MeshBasicMaterial({lightMap: lm, map: wood}); 
groundGeom.faceVertexUvs[1]=groundGeom.faceVertexUvs[0]; 
使用光照贴图时,只需要将材质的lightMap属性设置为所需的纹理即可。但如果要将光照效果显示出来,还需要额外的步骤,需要明确指定光照贴图的UV映射,这样才能将光照贴图的使用和映射与其他纹理独立开来。当阴影贴图设置好后,还需要将方块放置在正确位置。

5. 使用环境贴图创建反光:

计算环境的反光效果对CPU耗费很大,而且通常会使用光线追踪算法。可以通过创建一个对象所处环境的纹理来伪装反光。 
首先要创建CubeMap对象,其中包含6个纹理集合,这些纹理可以应用到方块的每个面上: 
function createCubeMap() { 
 var path="textures/parliament/"; 
 var format='.jpg'; 
 var urls=[ 
  path+'posx'+format, path+'negx'+format, 
  path+'posy'+format, path+'negy'+format, 
  path+'posz'+format, path+'negz'+format 
 ]; 
 var textureCube=THREE.ImageUtils.loadTexttureCube(urls); 
 return textureCube; 

创建一个带有CubeMap对象的方块,这就是移动摄像机时看到的环境。将CubeMap作为纹理使用,CubeMap同样可以作为纹理应用在网格中,ThreeJS会让它看上去像是环境光。为了使用CubeMap,需要预先准备6张构建环境场景的图片,6张图片分别为朝前的posz、朝后的negz、朝上的posy、朝下的negy、朝右的posz、朝左的negx,一些网站可以提供下载这样的图片,如www.humus.name/index.php?page=Textures。有了这些图片就可以创建场景。如果有一个360度的全景图像,也可以转换成一组图片,然后来创建CubeMap对象。ThreeJS也可以完成图像的转换: 
var textureCube=THREE.ImageUtils.loadTexture("360-degrees.png", new THREE.UNMapping()); 
有了CubeMap后,先要创建一个方块: 
var textureCube=createCubeMap(); 
var shader=THREE.ShaderLib['cube']; 
shader.uniforms['tCube'].value=textureCube; 
var material=new THREE.ShaderMaterial( { 
 fragmentShader: shader.fragmentShader, 
 vertexShader: shader.vertexShader, 
 uniforms: shader.uniforms, 
 depthWrite: false, 
 side: THREE.BackSide 
}); 
cubeMesh=new THREE.Mesh(new THREE.BoxGeometry(100, 100, 100), material); 
ThreeJS提供了一个特殊着色器,可以与THREE.ShaderMaterial一起创建出一个基于CubeMap的环境。使用CubeMap对象配置着色器,创建一个网格,并将它添加到场景中。如果从里面看,这个网格所代表的就是所处的那个虚假环境。 
这个CubeMap还需要应用到创建反光效果的网格上,网格会反射所处的环境,通过修改材质的reflectivity属性以决定材质能够反射多少场景。 
ThreeJS还可以使用CubeMap实现折射,需要修改纹理的加载方法: 
var textureCube=THREE.ImageUtils.loadTexttureCube(urls, THREE.CubeRefractionMapping()); 
可以通过修改材质的refraction属性来控制折射率。 
使用ThreeJS也可以创建能够反射出场景中其他物体的反光。为了对场景中的其他物体也进行反射,需要使用ThreeJS的其他组件,包括THREE.CubeCamera摄像机。

6. 高光贴图:

通过高光贴图,可以为材质指定一个闪亮的贴图。通常高光贴图会与specular属性一起使用,该属性可以用来决定反光的颜色。 
var specularTexture=THREE.ImageUtils.loadTexture('textures/earthspec.png'); 
var normalTexture=THREE.ImageUtils.loadTexture('texture/earthnormal.png'); 
var planetMaterial=new THREE.MeshPhongMaterial(); 
planetMaterial.specularMap=specularTexture; 
planetMaterial.specular=new THREE.Color(0xff0000); 
planetMaterial.shininess=1; 
planetMaterial.normalMap=normalTexture;

7. UV映射:

UV是纹理的坐标,通过UV映射可以指定纹理的哪部分会显示在物体的表面。在ThreeJS中创建几何体时,UV映射会基于几何体的类型自动创建。也可以自定义纹理,比如在Blender软件中,为物体的每个面指定要显示纹理的哪个部分,为此要为每个面的每个顶点设置u坐标和v坐标。格式为: 
geom.faceVertexUvs[0][0][0].x=0.5; 
geom.faceVertexUvs[0][0][0].y=0.7; 
这里将第1个面的uv值设为特定值。因为每个面都是用三维坐标表示的,所以为每个面的nv属性设置值时需要设置6个值。

8. 重复纹理:

当在创建的几何体上应用纹理时,ThreeJS会尽量实现最好的效果。如在方块上使用纹理时,会在每个面上都显示完整的纹理;对于球体会用完整的纹理包围球体。 
一些情况下,可能不想将纹理遍布整个面或整个几何体,而是让纹理重复。 
cube.material.map.warpS=THREE.RepeatWrapping; 
cube.material.map.warpT=THREE.RepeatWrapping; 
warpS属性定义的纹理沿x轴方向的行为,而warpY属性定义的是纹理沿y轴方向的行为。ThreeJS为这些属性提供了两个选项: 
·THREE.RepeatWrapping:允许纹理重复 
·THREE.ClampToEdgeWrapping:纹理的整体不会重复,只会重复纹理边缘的像素来填满剩下的空间,这是默认值 
如果使用THREE.RepeatWrapping,设置repeat属性的方法为: 
cube.material.map.repeat.set(repeatX, repeatY); 
变量repeatX用来指定纹理在x轴方向多久重复一次,而变量repeatY则用来指定纹理在y轴方向多久重复一次。如果变量的值为1,那么纹理不会重复;如果设置成大于1的值,那么纹理开始重复;设置为小于1的值,纹理被放大;如果值设为负数,会产生纹理的镜像。 
修改repeat属性时,ThreeJS会自动更新纹理,并使用新值进行渲染。如果将值从THREE. RepeatWrapping修改为THREE.ClampToEdgeWrapping,需要明确更新纹理: 
cube.material.map.needsUpdate=true;

9. 将画布作为纹理:

将画布上绘制的任何图形作为纹理并渲染到三维几何体上,使用ThreeJS只需要几步: 
function canvasMesh(geom) { 
 var canvasMap=new THREE.Texture(canvas); 
 var mat=new THREE.MeshPhongMaterial(); 
 mat.map=canvasMap; 
 var mesh=new THREE.Mesh(geom, mat); 
 return mesh; 

用JavaScript创建一个canvas元素,并将其添加到指定的div元素上。创建纹理时将画布元素的引用作为参数传递给纹理对象的构造函数,这样就可以创建出一个以画布为来源的纹理。最后就是在渲染时更新材质。

10. 将画布用作凹凸贴图:

使用凹凸贴图可以创建有皱褶的纹理,贴图中像素的密集程度越高贴图看上去越皱。凹凸贴图只是简单的黑白图片,也可以在画布上创建,并作为凹凸贴图输入。 
创建凹凸贴图,可以使用随机噪声来填充画布,可以产生看上去自然的随机纹理。 
var bumpMap=new THREE.Texture(canvas); 
var mat=new THREE.MeshPhongMaterial(); 
mat.color=new THREE.Color(0x77ff77); 
mat.bumpMap=bumpMap; 
bumpMap.needsUpdate=true; 
var mesh=new THREE.Mesh(geom, mat); 
return mesh;

11. 将视频输出作为纹理:

ThreeJS直接支持HTML5视频元素。首先在网页中加入

八、后期处理和自定义着色器:

ThreeJS提供了许多后期通道,这些通道可以直接添加到THREE.EffectComposer组合器中使用。

名称

描述

THREE.BloomPass

该通道通过增强场景中明亮的区域来模拟真实世界中的摄像机

THREE.DotScreenPass

该通道会将黑点图层应用到屏幕的原始图片上

THREE.FilmPass

该通道通过扫描线和失真来模拟电视屏幕效果

THREE.GlitchPass

该通道会随机地在屏幕上显示电脉冲

THREE.MaskPass

使用该通道可以在当前图片上添加掩码,后续通道只影响掩码区域

THREE.RenderPass

该通道会在当前场景和摄像机的基础上渲染出一个新场景

THREE.SavePass

当该通道执行时会复制当前的渲染结果,在后续的步骤中可以使用,实际作用不大

THREE.ShaderPass

该通道接受自定义的着色器为参数以生成一个高级的自定义的后期处理通道

THREE.TexturePass

该通道将组合器的当前状态保存为纹理,然后将其作为参数传入到其他的EffectComposer组合器中

要使用ThreeJS后期处理,要创建效果组合器THREE.EffectComposer对象,在该对象上可以添加后期处理通道,并进行配置,然后在render循环中使用效果组合器来渲染场景。要使用效果组合器,需要包含EffectComposer.js及其他脚本文件。

1. 简单后期处理通道:

1)THREE.FilmPass:创建类似电视的效果 
创建FilmPass通道: 
var effectFilm=new THREE.FilmPass(0.8, 0.325, 256, false); 
effectFilm.renderToScreen=true; 
var composer4=new THREE.EffectComposer(webGLRenderer); 
composer4.addPass(renderScene); 
composer4.addPass(effectFilm); 
FilmPass通道接受的参数有:

参数

描述

noiseIntensity

控制场景的粗糙程度

scanlinesIntensity

指定扫描线的显著程度

scanLinesCount

控制扫描线的数量

grayscale

设为true,输出结果将会被转换为灰度图

有两种方法来传递这些参数,可以作为构造函数的参数传递,或者直接设置: 
effectFilm.uniforms.grayscale.value=controls.grayscale; 
effectFilm.uniforms.nIntensity.value=controls.noiseIntensity; 
effectFilm.uniforms.sIntensity.value=controls.scanlines.Intensity; 
effectFilm.uniforms.sCount.value=controls.scanlinesCount; 
代码中使用了uniform属性,该属性可以直接和WebGL进行通信。 
2)THREE.BloomPass添加泛光效果 
应用泛光效果,场景中的明亮区域将会变得更加显著,而且还会渗入较暗的区域。 
var bloomPass=new THREE.BloomPass(3, 25, 5, 256); 
var composer3=new THREE.EffectComposer(webGLRenderer); 
composer3.addPass(renderScene); 
composer3.addPass(bloomPass); 
composer3.addPass(effectCopy); 
代码中添加了effectCopy通道,将最后一个通道的结果复制到屏幕上,因为THREE. BloomPass()通道不能直接将渲染结果输出到屏幕上。THREE. BloomPass()可以设置的属性有:

参数

描述

Strength

定义泛光效果的强度,值越大则明亮区域越明亮,且渗入较暗区域的也就越多

kernelSize

控制的是泛光效果的偏移量

sigma

控制泛光效果的锐利程度,值越大则泛光看起来越模糊

Resolution

定义泛光效果的精确度,值越低则泛光效果的方块化越严重

3)THREE.DotScreenPass:将场景作为点集输出 
var dotScreenPass=new THREE.DotScreenPass(); 
var composer1=new THREE.EffectComposer(webGLRenderer); 
composer1.addPass(renderScene); 
composer1.addPass(bloomPass); 
composer1.addPass(effectCopy); 
THREE. DotScreenPass()可以设置的属性有:

参数

描述

center

可以微调点的偏移量

angle

可以改变点的对齐方式

Scale

设置所用点的大小,值越小则点越大

4)THREE.GlitchPass:显示电脉冲 
使用GlitchPass显示电脉冲需要引入GlitchPass.js和DigitalGlitch.js脚本文件,然后创建GlitchPass对象: 
var effectGlitch=new THREE.GlitchPass(64); 
effectGlitch.renderToScreen=true; 
5)在同一个屏幕上显示多个渲染器的输出结果: 
EffectComposer.js脚本文件提供了EffectComposer效果组合器对象,RenderPass.js文件用于在效果组合器上添加渲染效果,CopyShader.js等为EffectComposer内部使用,还有一些所用通道对应的脚本文件。 
使用时要创建一个EffectComposer对象,接着为这个组合器添加各个通道,第一个要加入RenderPass.通道,其中传入要渲染的场景和摄像机: 
var renderPass=new THREE.RenderPass(scene, camera); 
composer.addPass(renderPass); 
调用addPass()方法就可以将RenderPass.添加到EffectComposer对象上。将webGLRenderer. autoClear属性设为false,并显示调用clear()方法,这样在循环开始时将所有的内容清除。 
将效果组合器所用的WebGLRenderer的视图区设置成屏幕的不同部分,设置视图区域的方法接受x、y、width、height四个参数,使每个效果组合器在各自的区域中进行渲染。也可以将此方法用于多场景、多摄像机和多WebGLRenderer情况下。

2. THREE.MaskPass:使用掩码的高级效果组合器

ThreeJS可以在特定的区域使用通道。要使用掩码,需要用不同的方法场景EffectComposer。要创建一个新的THREE.WebGLRenderTarget对象,然后将这个内部使用的渲染对象的模板缓存stencilBuffer属性设置true。模板缓存是一种特殊的缓存,用于限制渲染区域,启用后就可以使用掩码了。然后分别创建几个通道,分别渲染不同的场景。 
THREE.MaskPass中有inverse属性,设为true就会掩码反转。

3. THREE.ShaderPass:自定义效果

通过THREE.ShaderPass可以传递一个自定义着色器,将额外效果添加到场景中。 
简单着色器有:

名称

描述

THREE.MirrorShader

可以为部分屏幕创建镜面效果

THREE.HueSaturationShader

可以改变颜色的色调和饱和度

THREE.VignetteShader

添加晕映效果,在图片中央周围显示黑色边框

THREE.ColorCorrectionShader

可以调整颜色的分布

THREE.RGBShiftShader

可以将构成颜色的红、绿、蓝分开

THREE.BrightnessContrastShader

可以改变图片的亮度和对比度

THREE.ColorifyShader

可以将颜色覆盖在整个屏幕上

THREE.SepiaShader

可以在屏幕上创建类似乌贼墨效果

THREE.KaleidoShader

可以在场景上添加类似万花筒效果

THREE.LuminosityShader

提供亮度效果,可以显示场景的亮度

THREE.TechnicolorShader

可以模拟类似老电影里面的两条彩色效果

提供模糊效果的着色器:

名称

描述

THREE.HorizontalBlurShader和 
THREE.VerticalBlurShader

可以向整个屏幕添加模糊效果

THREE.HorizontalTiltShiftShader 
THREE.VerticalTiltShiftShader

可以创建出倾斜平移效果,使其中只有部分图片看起来比较尖锐从而创建出一个缩微的场景

THREE.TriangleBlurShader

使用基于三角形的方法在场景中添加模糊效果

提供高级效果的着色器有:

名称

描述

THREE.BleachBypassShader

可以创建漂白效果,使图片看上去覆盖一层银

THREE.EdgeShader

可以找到图片的尖锐边界并突显

THREE.FXAAShader

在后期处理节段添加抗锯齿效果

THREE.FocusShader

渲染结果是中央比较尖锐,而边界比较模糊

ThreeJS还提供了在场景中添加散景效果,以模糊部分场景而突显主要对象,其中使用通道THREE.BrokerPass或THREE.BokehShader2和THREE.DOFMipMapShader着色器来实现。

4. 创建自定义后期着色器:

要创建自定义着色器,需要实现顶点着色器vertexShader和片元着色器fragmentShader。顶点着色器可以用来改变每个顶点的位置,片元着色器用来定义每个像素的颜色。对于后期处理着色器,只需要实现判断着色器,然后使用ThreeJS提供的默认顶点着色器。GPU通常可以支持多个着色器管道,也就是GPU在执行顶点着色器时会有多个着色器同时执行。

九、添加物理效果:

物理效果是指物体会有重力效果,可以相互碰撞,施加力后可以移动,还可以通过合页和滑块在移动过程中在物体上施加约束。一般使用js库,如Physijs,需要导入相应脚本文件。

1. Physijs物理引擎:

Physijs是在后台线程计算处理,使用了WebWorker规范,这样就不会影响场景的渲染。 
Physijs只是ammo.js的包装器,而ammo.js才是实现物理引擎的库,Physijs对这个库进行了封装。Physijs也可以与其他物理引擎一起工作,比如Cannon.js。 
为了配置Physijs,需要设置属性: 
Physijs.scripts.worker='physijs_worker.js'; 
Physijs.script.ammo='ammo.js'; 
然后就是创建场景: 
var scene=new Physijs.Scene(); 
scene.setGravity(new THREE.Vector3(0, -10, 0)); 
其中还在y轴上设置了值为-10的重力效果。需要在场景中创建物体: 
var stoneGeom=new THREE.BoxGeometry(0.6, 6, 2); 
var stone=new Physijs.BoxMesh(stoneGeom, new THREE.MeshPhongMaterial({color: 0xff0000})); 
scene.add(stone); 
这里创建了Physijs.BoxMesh对象,用来让Physijs模拟物理效果和碰撞效果时将该网格视为一个Box。Physijs还提供了应用于各种图形的网格。用Physijs模拟物理效果并更新物体的位置和角度,要在创建的场景上调用simulate方法,这在render循环中修改为: 
render=function() { 
 requestAnimationFrame(render); 
 renderer.render(scene, camera); 
 scene.simulate(); 
}

2. Physijs材质属性:

Physijs可以在创建的材质上设置摩擦系数friction、弹性系数restitution,已模仿实际物体的物理特性。使用物理引擎时,碰撞检测由物理引擎实现,需要加事件监听器: 
mesh.addEventListener('collision', function( 
other_object, relative_velocity, relative_rotation, contact_normal) {} ); 
Physijs提供了很多用于包装几何体的图形类,使用这些网格替换THREE.Mesh的网格对象的构造函数,包括:

名称

描述

Physijs.PlaneMesh

用于创建厚度为0的平面

Physijs.BoxMesh

用于看起来像方块的物体

Physijs.SphereMesh

用于球形物体

Physijs.CylinderMesh

用于创建各种柱状图形,顶面与底面半径一样

Physijs.ConeMesh

圆锥体,顶面半径为1,底面半径不为0

Physijs.CapsuleMesh

胶囊,顶部和底部都是圆的

Physijs.ConvexMesh

用于创建复杂图形的粗略图形,模拟凸包

Physijs.ConcaveMesh

对复杂图形进行复杂的表示,但对性能影响较大

Physijs.HeightfieldMesh

可以用来从PlaneGeometry中创建高度场

3. 使用Physijs约束:

Physijs提供的约束有:

名称

描述

PointConstraint

使两个物体的关系固定,一个移动,另一个也会随之移动

HingeContraint

限制物体像合页一样移动

SliderContraint

将物体的移动限制在一个轴上,如推拉门

ConeTwistContraint

类似关节,用一个物体限制另一个物体的移动和旋转

DOFContraint

限制物体在任意轴上的移动,可以设置运动的最小最大角度

1)使用PointConstraint约束: 
var obj1=new THREE.SphereGeometry(2); 
var objectine=new Physijs.SphereMesh(obj1, 
  Physijs.createMaterial(new THREE.MeshPhongMaterial({color: 0xff4444, 
  transparent: true, opacity: 0.7}), 0, 0)); 
...... 
var constraint=new Physijs.PointConstraint(objectone, objecttwo, objecttwo.position); 
scene.addConstaint(constraint); 
其中使用特定的Physijs网格来创建对象,然后添加到场景中。然后使用Physijs.PointConstraint构造函数创建约束,其中包括3个参数,前2个参数指定连接的两个对象,第3个参数指定约束的位置。如果将一个对象绑定到一个固定点上,可以忽略第二个参数。 
addConstaint()中可以传递一个参数true,这样就能在场景中看到约束点和方向。 
2)使用HingeContraint约束: 
通过HingeContraint可以创建类似于合页的约束,围绕固定的轴旋转,并只能在固定的角度间移动。 
var constraint=new Physijs.HingeConstraint(flip1, flip2, flip2.position, new THREE.Vector3(0,1,0)); 
scene.addConstaint(constraint); 
constraint.setLimits(-2.2, -0.6, 0.1, 0); 
这个约束有4个参数:

参数

描述

mesh1

表示将要被约束的对象

mesh2

表示受哪个对象约束

position

表示约束应用到的点的位置

axis

指定合页可以旋转的角度

setLimits方法接受4个参数:

参数

描述

low

指定旋转的最小弧度

high

指定旋转的最大弧度

bias_factor

指定处于错误位置时修正的速度,值大修正速度快,最好小于0.5

relaxation_factor

指定约束以什么比率改变速度,值大时到最大最小位置后会反弹

3)使用SliderContraint约束: 
用来将某个对象的移动限制在某个轴上。 
var constraint=new Physijs.SliderConstraint(sliderMesh, new THREE.Vector3( 0, 2,0 ), new THREE. Vector3(0, 1, 0)); 
scene.addConstaint(constraint); 
constraint.setLimits(-10, 10, 0, 0); 
constraint.setRestitution(0.1, 0.1); 
这个约束有4个参数:

参数

描述

mesh1

表示将要被约束的对象

mesh2

表示受哪个对象约束

position

表示约束应用到的点的位置

axis

指定mesh1沿哪个轴移动。如果指定了mesh2,这个轴就是相对于mesh2方向的

axis沿x轴表示为new THREE.Vector3(0, 1, 0);沿y轴表示为new THREE.Vector3(0, 0, Math.PI/2);沿z轴表示为new THREE.Vector3(Math.PI/2, 0, 0)。 
setLimit方法接受4个参数:

参数

描述

linear_lower

指定线性下限

linear_upper

指定线性上限

angular_lower

指定角度下限

angular_higher

指定角度上限

setRestitution()设置达到极限时的弹性,前一个是指定达到线性限制时的弹性,第二个指定达到角度限制时的弹性。 
4)使用ConeTwistContraint约束: 
用来创建一个移动受一系列角度限制的约束,可以指定一个物体绕另一个物体转动时在x、y、z轴上的最小角度和最大角度。 
var constraint=new Physijs.ConeTwistContraint(obj1, obj2, obj2.position); 
scene.addConstaint(constraint); 
constraint.setLimit(0.5*Math.PI, 0.5*Math.PI, 0.5*Math.PI); 
constraint.setMaxMotorImpulse(1); 
constraint.setMotorTarget(new THREE.Vector3(0, 0, 0)); 
ConeTwistContraint约束的3个参数分别为要约束的对象、要约束到的对象和约束到的位置。setLimit方法设置中使用三个弧度值来表示对象绕每个轴旋转的最大角度,setMaxMotor Impulse设置可以施加的力。 
5)使用DOFContraint约束: 
DOFContraint为自由约束,可以准确控制线性方向和角度方向的移动。比如将车轮约束到车上。 
var constraint=new Physijs.DOFContraint(fr, body, new THREE.Vector3(0, 4, 8)); 
scene.addConstaint(constraint); 
constraint.setAngularLowerLimit({x: 0, y: 0, z: 0}); 
constraint.setAngularUpperLimit({x: 0, y: 0, z: 0}); 
constraint.configureAngularMotor(2, 0.1, 0, -2, 1500); 
constraint.conAngularMotor(2, 0.1, 0, -2, 1500); 
constraint.enableAngularMotor(2); 
上面只是对其中一个轮子进行的设置,要分别对四个轮子进行设置。

4. 场景添加声源:

ThreeJS使用THREE.Audio对象添加声音: 
var listener1=new THREE.AudioListener(); 
camera.add(listener1); 
var sound1=new THREE.Audio(listenter1); 
sound1.load('cow.ogg'); 
sound1.setRefDistance(20); 
sound1.setLoop(true); 
sound1.setRolloffFactor(2); 
如果创建了一个Mesh对象,还可以将这个Audio对象关联到Mesh: 
mesh1.add(sound1); 
其中,setRefDistance属性决定降低声音的距离,setLoop属性如果为true就会循环播放声音,setRolloffFactor决定距离音源远后的声音下降速度。 
THREE.Audio基于Web Audio API来播放声音并决定正确的音量,是一种较新的技术,并不是所有浏览器都支持。使用THREE.Audio的方法,可以设定声音的来源物体,根据场景中的位置来改变音量大小,形成接近真实场景中的音效。为了获得控制音量的距离数据,要使用THREE.GridHelper类创建方格并指定方格的大小。

你可能感兴趣的:(GIS技术)