第3章 简单的材质和纹理贴图,给几何体披上好看的外衣


1、常见的材质

点材质PointsMaterial

点材质比较简单,只有PointsMaterial,通常使用点模型的时候会使用点材质PointsMaterial

点材质PointsMaterial.size属性可以每个顶点渲染的方形区域尺寸像素大小。

1
2
3
4
5
6
7
8
9
var geometry = new THREE.SphereGeometry(100, 25, 25); //创建一个球体几何对象
// 创建一个点材质对象
var material = new THREE.PointsMaterial({<!-- -->
  color: 0x0000ff, //颜色
  size: 1, //点渲染尺寸
});
//点模型对象  参数:几何体  点材质
var point = new THREE.Points(geometry, material);
scene.add(point); //网格模型添加到场景中

线材质

线材质有基础线材质LineBasicMaterial和虚线材质LineDashedMaterial两个,通常使用使用Line等线模型才会用到线材质。

基础线材质LineBasicMaterial

1
2
3
4
5
6
7
var geometry = new THREE.SphereGeometry(100, 25, 25);//球体
// 直线基础材质对象
var material = new THREE.LineBasicMaterial({<!-- -->
  color: 0x0000ff
});
var line = new THREE.Line(geometry, material); //线模型对象
scene.add(line); //点模型添加到场景中

虚线材质LineDashedMaterial

1
2
3
4
5
6
7
8
9
// 虚线材质对象:产生虚线效果
var material = new THREE.LineDashedMaterial({<!-- -->
  color: 0x0000ff,
  dashSize: 10,//显示线段的大小。默认为3。
  gapSize: 5,//间隙的大小。默认为1
});
var line = new THREE.Line(geometry, material); //线模型对象
//  computeLineDistances方法  计算LineDashedMaterial所需的距离数组
line.computeLineDistances();

网格模型材质

Threejs提供的网格类材质比较多,网格材质涉及的材质种类和材质属性也比较多,一节课也无法讲解完,本节课先有一个感性的认知。

网格材质顾名思义,网格类模型才会使用的材质对象。

基础网格材质对象MeshBasicMaterial,不受带有方向光源影响,没有棱角感。

1
2
3
var material = new THREE.MeshBasicMaterial({<!-- -->
  color: 0x0000ff,
})

MeshLambertMaterial材质可以实现网格Mesh表面与光源的漫反射光照计算,有了光照计算,物体表面分界的位置才会产生棱角感。

1
2
3
var material = new THREE.MeshLambertMaterial({<!-- -->
  color: 0x00ff00,
});

高光网格材质MeshPhongMaterial除了和MeshLambertMaterial一样可以实现光源和网格表面的漫反射光照计算,还可以产生高光效果(镜面反射)。

1
2
3
4
5
var material = new THREE.MeshPhongMaterial({<!-- -->
  color: 0xff0000,
  specular:0x444444,//高光部分的颜色
  shininess:20,//高光部分的亮度,默认30
});

材质的基本属性

如果你的javascript语言基础还可以,应该明白类、基类、子类、父类等概念。如果你有这些类的概念,那么在学习Threejs的过程中,如何查找Threejs文档将会比较顺利。

点材质PointsMaterial、基础线材质LineBasicMaterial、基础网格材质MeshBasicMaterial、高光网格材质MeshPhongMaterial等材质都是父类Material的子类。

各种各样的材质子类都有自己的特定属性,比如点材质特有的尺寸属性.size、高光网格材质特有的高光颜色属性.specular等等这些属性可以成为子类材质的私有属性。

所有子类的材质都会从父类材质Material继承透明度opacity、面side等属性,这些来自父类的属性都是子类共有的属性。

.side属性

在Three.js开发过程中你可能会遇到下面的问题,比如three.js矩形平面planegeometry的网格模型插入场景看不到,一个球体或立方体网格模型如何背面显示贴图,正面不显示…,对于这些问题可以通过Three.js材质对象.side属性来设置。

材质.side属性的具体介绍可以查看Threejs文档中所有材质对象的基类Material

.side属性的属性值定义面的渲染方式前面后面 或 双面. 属性的默认值是THREE.FrontSide,表示前面. 也可以设置为后面THREE.BackSide 或 双面THREE.DoubleSide.

1
2
3
4
5
var material = new THREE.MeshBasicMaterial({<!-- -->
  color: 0xdd00ff,
  // 前面FrontSide  背面:BackSide 双面:DoubleSide
  side:THREE.DoubleSide,
});

材质透明度.opacity

通过材质的透明度属性.opacity可以设置材质的透明程度,.opacity属性值的范围是0.0~1.0,0.0值表示完全透明, 1.0表示完全不透明,.opacity默认值1.0。

当设置.opacity属性值的时候,需要设置材质属性transparent值为true,如果材质的transparent属性没设置为true, 材质会保持完全不透明状态。

在构造函数参数中设置transparent.opacity的属性值

1
2
3
4
5
6
7
var material = new THREE.MeshPhongMaterial({<!-- -->
  color: 0x220000,
  // transparent设置为true,开启透明,否则opacity不起作用
  transparent: true,
  // 设置材质透明度
  opacity: 0.4,
});

通过访问材质对象属性形式设置transparent.opacity的属性值

1
2
3
4
  // transparent设置为true,开启透明,否则opacity不起作用
material.transparent = true;
  // 设置材质透明度
material.opacity = 0.4;

2、创建纹理贴图

通过纹理贴图加载器TextureLoader的load()方法加载一张图片可以返回一个纹理对象Texture,纹理对象Texture可以作为模型材质颜色贴图.map属性的值。

材质的颜色贴图属性.map设置后,模型会从纹理贴图上采集像素值,这时候一般来说不需要在设置材质颜色.color.map贴图之所以称之为颜色贴图就是因为网格模型会获得颜色贴图的颜色值RGB。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 纹理贴图映射到一个矩形平面上
var geometry = new THREE.PlaneGeometry(204, 102); //矩形平面
// TextureLoader创建一个纹理加载器对象,可以加载图片作为几何体纹理
var textureLoader = new THREE.TextureLoader();
// 执行load方法,加载纹理贴图成功后,返回一个纹理对象Texture
textureLoader.load('Earth.png', function(texture) {<!-- -->
  var material = new THREE.MeshLambertMaterial({<!-- -->
    // color: 0x0000ff,
    // 设置颜色纹理贴图:Texture对象作为材质map属性的属性值
    map: texture,//设置颜色贴图属性值
  }); //材质对象Material
  var mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
  scene.add(mesh); //网格模型添加到场景中

  //纹理贴图加载成功后,调用渲染函数执行渲染操作
  // render();
})

不同的几何体有不同的UV坐标来设置贴图和模型的映射规律,你可以尝试把颜色纹理贴图映射到不同的几何体上查看渲染效果。

1
2
var geometry = new THREE.BoxGeometry(100, 100, 100); //立方体
var geometry = new THREE.SphereGeometry(60, 25, 25); //球体

纹理对象Texture

如果你想进一步了解.map的属性值Texture可以阅读下面的代码。

通过图片加载器ImageLoader可以加载一张图片,所谓纹理对象Texture简单地说就是,纹理对象Texture的.image属性值是一张图片。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 图片加载器
var ImageLoader = new THREE.ImageLoader();
// load方法回调函数,按照路径加载图片,返回一个html的元素img对象
ImageLoader.load('Earth.png', function(img) {<!-- -->
  // image对象作为参数,创建一个纹理对象Texture
  var texture = new THREE.Texture(img);
  // 下次使用纹理时触发更新
  texture.needsUpdate = true;
  var material = new THREE.MeshLambertMaterial({<!-- -->
    map: texture, //设置纹理贴图
  });
  var mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
  scene.add(mesh); //网格模型添加到场景中
});

3、重新为地板设置贴图,观察效果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
let buildingObjects = {
    objects: [
        {
            objectName: 'floor',
            objectType: 'cube',
            length: 3400,
            width: 1200,
            height: 1,
            position: {
                x: 0,
                y: 0,
                z: 0
            },
            style:{
                color: 0x5F7480,
                image:'./res/floor.jpg',
                allowRepeat:1
            }
        }
    ]
}

还记得上节课的时候我们的cube类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/**
 * 立方体类
 * 我们生活中很多的物体都可以归结为立方体类,比如墙体,地板,窗户等都可看成是立方体类
 * @param option
 * @constructor
 */
function Cube(option){
    this.length = option.length || 1;
    this.width = option.width || 1;
    this.height = option.height || 1;

    this.Name = option.objName;

    this.positionX = option.position.x || 0;
    this.positionY = option.position.y || 0;
    this.positionZ = option.position.z || 0;

    this.style=option.style||{color:0xFF0000};

    let curmaterial=CommonFunction.createMaterial(this.width,this.height,this.style);

    let cubeGeometry = new THREE.BoxGeometry(this.length, this.height, this.width);

    let cube = new THREE.Mesh( cubeGeometry, curmaterial );
    cube.name=this.Name;
    cube.position.x=this.positionX;
    cube.position.y=this.positionY;
    cube.position.z=this.positionZ;
    return cube;
}

我们给地板加上一个纹理贴图,这样就可以让地板显示贴图了。
在这里插入图片描述