• MeshBasicMaterial(网格基础材质):基础材质,用于给几何体赋予一种简单的颜色,或者显示几何体的线框。
  • MeshDepthMaterial(网格深度材质): 这个材质使用从摄像机到网格的距离来决定如何给网格上色。
  • MeshLambertMaterial(网格 Lambert 材质): 这是一种考虑光照影响的材质,用于创建暗淡的、不光亮的物体。
  • MeshNormalMaterial(网格法向材质):这是一种简单的材质,根据法向向量计算物体表面的颜色。
  • MeshPhongMaterial(网格 Phong 式材质):这是一种考虑光照影响的材质,用于创建光亮的物体。

一、材质的共有属性

three.js提供了一个THREE.Materail 材质的抽象基类,所有其他材质类型都继承了以下属性和方法:

1、基础属性

  • id(标识符):此材质实例的唯一编号,并在材质创建时赋值。第一个材质的值从 0 开始,每新加一个材质,这个值就增加 1。

  • uuid(通用唯一识别码):这是生成的唯一 ID,在内部使用。

  • name(名称):可以通过这个属性赋予材质名称,用于调试的目的。

  • opacity(不透明度): 定义物体的透明度。与 transparent 属性一起使用。该属性的赋值范围从 0 到 1。

  • transparent(是否透明):定义此材质是否透明,可以通过opacity属性来控制透明程度。

    • 默认值为false,所以如果需要做透明渲染效果,需要设置transparent设置为true。

    • 如果使用 alpha(透明度)通道的纹理,该属性应该设置为 true。

  • overdraw(过度描绘):当你使用 THREE.CanvasRender 时,多边形会被渲染得稍微大一点。当使用这个渲染器渲染的物体有间隙时,可以将这个属性设置为 true。

  • visible(是否可见):定义该材质是否可见。默认为true,如果设置为 false,那么在场景中就看不到该物体。

  • side(侧面):通过这个属性,可以定义几何体的渲染哪一面。

    • 默认值为 THREE.FrontSide(前面),定义将要渲染材质的前面(外侧)。

    • 设置为 THREE.BackSide(后面),定义将要渲染材质的后面(内侧)。

    • 设置为 THREE.DoubleSide(双侧),定义将要渲染材质的内外两侧。

  • needsUpdate(是否更新):对于材质的某些修改,需要告诉 Three.js 材质已经改变了。如果该属性设置为 true,Three.js会使用新的材质属性更新它的缓存。

在使用过程中需要注意的有一下三点:

(1)opacity和transparent需要一起搭配使用,在transparent为true时,opacity才会起作用,下面举例示范;

// 创建材质
let color = new THREE.Color(Math.random(), Math.random(), Math.random())
// 未向材质中添加 transparent 属性
const material = new THREE.MeshBasicMaterial({
  color: color,
  opacity: 0.5,
})  

// 创建材质
let color = new THREE.Color(Math.random(), Math.random(), Math.random())
// 向材质中添加 transparent 属性
const material = new THREE.MeshBasicMaterial({
  color: color,
  transparent: true,
  opacity: 0.5,
})  

(2)当材质的属性发生改变时,需要将needsUpdate(指定需要重新编译材质)设置为true,才能触发材质的渲染更新。 

window.addEventListener('click', e => {
  // 当鼠标移动的时候播放视频
  // 判断视频是否属于播放状态
  if (video.paused) {
    this.$nextTick(res => {
      video.load()
      video.play()
    })
    let texture = new THREE.VideoTexture(video)
    skyMaterial.map = texture
    skyMaterial.map.needsUpdate = true
  }
})

(3)side 决定了绘制那个面,还是两个面都进行绘制

material.side = THREE.DonbleSide
// 或者
const material = new THREE.MeshStandardMaterial({
  side: DonbleSide,
})

2、融合属性

  • blending(融合):该属性决定物体上的材质如何与背景融合。一般的融合模式是 THREE.NormalBlending,在这种模式下只显示材质的上层。

  • blendSrc(混合源):

    • 除了使用标准融合模式之外,还可以通过设置 blendsrc、 blenddst 和 blendequation 来创建自定义的融合模式。

    • 这个属性定义了该物体(源)如何与背景(目标)相融合。默认值为THREE.SrcAlphaFactor,即使用 alpha(透明度)通道进行融合。

  • blendDst(混合目标): 这个属性定义了融合时如何使用背景(目标),默认值为 THREE.OneMinusSrcAlphaFactor,其含义是目标也使用源的 alpha 通道进行融合,只是使用的值是 1(源的 alpha 通道值),必须将材质的blending设置为CustomBlending才能生效。

  • blendEquation(融合公式):定义了如何使用 blendsrc 和 blenddst 的值。默认值为使它们相加(AddEquation)。通过使用这三个属性,可以创建自定义的融合模式。

3、高级属性

  • depthTest / depthWrite:绘制不透明物体时,深度测试开启是能保证正确的遮挡关系,绘制透明物体时,关掉深度测试能保证正确的blend。

  • polygonOffset / polygonOffsetFactor / polygonOffsetUnits

  • alphatest:如果某个像素小于这个值,则不会显示。

二、各种材质说明

1、THREE.MeshBasicMaterial(网格基础材质):

  • 定义:MeshBasicMaterial是一种比较简单的材质

  • 特点:这种材质不受光照的影响,不考虑光照的影响,可以渲染基础的平面或者几何体。

(1)属性介绍

  • color(颜色):材质的颜色,默认值为白色 (0xffffff)。可以通过this.cube.material.color.set(value)改变材质颜色属性

  • xxxMap(纹理贴图):demo10

  • wireframe(线框):默认值为false(即渲染为平面多边形), 设置这个属性可以将材质渲染成线框。

  • wireframeLinewidth(线框线宽):如果已经打开了 wireframe,这个属性定义线框中线的宽度。

  • wireframeLinecap(线框线段端点):定义线两端的外观

    • round(默认值):圆

    • square:方

    • butt:平

  • wireframeLinejoin(线框线段连接点):这个属性定义了线段的连接点如何显示。可选的值有:

    • round:圆(默认值)

    • bevel:斜角

    • miter:尖角

  • shading(着色): 该属性定义如何着色。可选的值有:

    • THREE.SmoothShading(默认值,这个将产生一个平滑的对象,看不到单个面)

    • THREE.NoShading

    • THREE.FlatShading

  • vertexColors(顶点颜色)

    • 可以通过这个属性给每个顶点定义不同的颜色。默认值为:THREE.NoColors。如果将这个值设置为 THREE.VertexColors,渲染器会采用 THREE.Geometry 对象的 colors 属性的值。

    • 该属性对 CanvasRenderer不起作用,但对 WebGLRender 起作用。比如我们可以使用该属性为线段的不同部分设置不同的颜色。也可以使用这个属性为这种材质类型创建渐变效果。

  • fog(雾化): 该属性指定当前材质是否受全局雾化效果设置的影响,默认为true。如果将该属性设置为 false,那么我们全局雾化效果设置就不会影响当前对象的渲染。

(2)该材质所包含的的纹理贴图:

  • map:颜色贴图。

  • aoMap:该纹理的红色通道用作环境遮挡贴图,aoMap需要第二组UV。

  • envMap:环境贴图。

  • lightMap:光照贴图,lightMap需要第二组UV。

  • alphaMap:alpha贴图是一张灰度纹理,用于控制整个表面的不透明度。(黑色:完全透明;白色:完全不透明)。

  • specularMap:材质使用的高光贴图。

(3)使用示例:

示例一:颜色纹理贴图

// 导入纹理
// TextureLoader创建一个纹理加载器对象,可以加载图片作为几何体纹理
const textureLoader = new THREE.TextureLoader()
// 执行load方法,加载纹理贴图成功后,返回一个纹理对象Texture
const picTexture = textureLoader.load('./static/images/detail1.jpg')

// 添加物体:纹理贴图映射到一个矩形平面上
const cubeGeometry = new THREE.BoxBufferGeometry(1, 1, 1)

// 设置材质
const material = new THREE.MeshBasicMaterial({
  color: '#dda0dd',
  // 添加纹理贴图
  map: picTexture,
  transparent: true,
  opacity: 0.5,
  side: THREE.DoubleSide,
})
this.cube = new THREE.Mesh(cubeGeometry, material)
// 将物体添加到场景中
this.scene.add(this.cube)

实例二:基础示例

// 添加物体
// 创建几何体
const geometry = new THREE.BoxGeometry(1, 1, 1)
// 创建材质
const material = new THREE.MeshBasicMaterial({ color: '#dda0dd' })
// 根据几何体和材质创建物体
this.cube = new THREE.Mesh(geometry, material)
// 将几何体添加到场景中
this.scene.add(this.cube)

// 创建 GUI
const gui = new dat.GUI()
gui
  .add(this.cube.position, 'x')
  .min(0)
  .max(5)
  .step(0.01)
  .name('移动x轴')
  .onChange(value => {
     console.log('值被修改了')
  })
  .onFinishChange(value => {
    console.log('完全停下来')
  })
// 修改物体的颜色
const params = {
  color: '#dda0dd',
  fn: () => {
    // 让立方体运动起来
    gsap.to(this.cube.position, { x: 10, duration: 2, yoyo: true, repeat: -1 })
  },
}

// 设置选项框
gui.add(this.cube, 'visible').name('是否显示')
// 点击触发某个事件
gui.add(params, 'fn').name('点击立方体运动')
// 添加文件夹(折叠选项)
let folder = gui.addFolder('设置立方体')
folder.add(this.cube.material, 'wireframe')
  folder
  .addColor(params, 'color')
  .onChange(value => {
    this.cube.material.color.set(value)
  })
  .name('修改颜色')

2、THREE.MeshDepthMaterial(网格深度材质):

一种按深度绘制几何体的材质。深度基于相机远近平面。白色最近,黑色最远。使用这种材质的物体,其外观不是由光照或者某个材质属性决定的,而是由物体到摄像机的距离决定的。我们可将这种材质与其他材质结合使用,从而很容易地创建出逐渐消失得效果。

(1)属性介绍:

  •  wireframe(线框):设置这个属性可以将材质渲染成线框,非常适用于调试。
  • wireframeLinewidth(线框线宽): 在线框模式下,此属性决定线框的宽度。

(2)该材质所包含的的纹理贴图:

  • map:颜色贴图。
  • alphaMap:alpha贴图是一张灰度纹理,用于控制整个表面的不透明度。(黑色:完全透明;白色:完全不透明)。
  • displacementMap:位移贴图会影响网格顶点的位置,与仅影响材质的光照和阴影的其他贴图不同,移位的顶点可以投射阴影,阻挡其他对象,以及充当真实的几何体。 可以通过设置displacementScale大小来调整位移贴图对网格的影响程度。

(3)使用示例:

	this.scene = new THREE.Scene()
    this.scene.overrideMaterial = new THREE.MeshDepthMaterial()	

	// 环境光
	const ambientLight = new THREE.AmbientLight(0xffffff, 0.1) // 创建环境光
	this.scene.add(ambientLight) // 将环境光添加到场景

    addCube() {
      const cubeSize = Math.ceil(3 + Math.random() * 3)
      const cubeGeometry = new THREE.BoxGeometry(cubeSize, cubeSize, cubeSize)

      const cubeMaterial = new THREE.MeshLambertMaterial({
        color: 0xffffff,
      })

      this.cube = new THREE.Mesh(cubeGeometry, cubeMaterial)

      this.cube.castShadow = true
      this.cube.updateMatrix()

      // 设置方块位置
      this.cube.position.x = -50 + Math.round(Math.random() * 150)
      this.cube.position.y = Math.round(Math.random() * 10)
      this.cube.position.z = -150 + Math.round(Math.random() * 250)

      // 将方块添加到场景
      this.scene.add(this.cube)
    },

    // 更新属性
    updateFun() {
      this.camera.near = this.properties.near.value
      this.camera.far = this.properties.far.value

      this.camera.updateProjectionMatrix()
      const THIS = this
      THIS.scene.traverse(function (e) {
        if (e instanceof THREE.Mesh) {
          e.rotation.x += THIS.properties.speed.value
          e.rotation.y += THIS.properties.speed.value
          e.rotation.z += THIS.properties.speed.value
        }
      })
    },

 

由上图可以看出来,远近的明亮程度不一样,通过右上角gui相关数据调整相机的近面值及远面值。

这里要特别注意如下几个地方:

  • 要把 THREE.MeshBasicMaterial 的 transparent 属性设置为 true,并指定一个融合模式。否则 THREE.js 不会执行任何融合操作,方块始终未纯绿色。
  • 融合模式这里使用的是 THREE.MultiplyBlending,该模式会把前景色和背景色相乘,得到想要的结果。
  • 当 THREE.SceneUtils.createMultiMaterialObject() 方法创建一个网格的时候,几何体会被复制,返回一个网格组(里面两个网格完全相同)。当渲染的物体有一个在别的物体上,并且有一个物体是透明的,那么渲染时会出现画面闪烁问题。这里我们通过缩小带有 THREE.MeshDepthMaterial 材质的网格,就可以避免这种现象。

3、THREE.MeshNormalMaterial(法线网格材质)

一种把法向量映射到RGB颜色的材质,使用这种材质,每一面的颜色是由从该面向外指的法向量计算得到的。

(1)属性介绍:

  • wireframe(线框)
  • wireframeLinewidth(线框线宽)
  • shading(着色方法)
  • THREE.FlatShading:平面着色
  • THREE.SmoothShading:平滑着色

(2)该材质所包含的的纹理贴图:

  • bumpMap:用于创建凹凸贴图的纹理。
  • normalMap:法线贴图的类型。
  • displacementMap:位移贴图会影响网格顶点的位置,与仅影响材质的光照和阴影的其他贴图不同,移位的顶点可以投射阴影,阻挡其他对象,以及充当真实的几何体。 可以通过设置displacementScale大小来调整位移贴图对网格的影响程度。

(3)使用示例:

// 创建法向量纹理
var meshMaterial = new THREE.MeshNormalMaterial({
  flatShading: THREE.FlatShading,
  transparent: true,
  opacity: 0.7
});

4、THREE.MeshLambertMaterial(网格Lambert 材质)

  • 定义:一种非光泽表面的材质,没有镜面高光。
  • 特点:
    • 适用于暗淡、不光亮表面,会对光源产生反应。
    • 适用于暗淡、不光亮表面,会对光源产生反应。
    • 这种材质可以用来创建暗淡的并不光亮的表面。
    • 这可以很好地模拟一些表面(如未经处理的木材或石头),但不能用镜面高光(如上漆木材)模拟光泽表面。

(1)属性介绍

  • ambient(环境色):这是材质的环境色。它跟上一章讲过的环境光源一起使用。这个颜色会与环境光提供的颜色相乘。默认值为白色。
  • emissive(发射的):这是该材质的发射的颜色。它其实并不像一个光源,只是一种纯粹的、不受其它光照影响的颜色。默认值为黑色。
  • wrapAround:如果这个属性设置为true,则启动半lambert光照技术。有了它,光下降得更微妙。如果网格有粗糙、黑暗的地区,启用此属性阴影将变得柔和并且分不更加均匀。
  • wrapRGB:当wrapAround属性设置为true时,可以使用THREE.Vector3来控制光下降得速度。

在此有两个比较重要的属性:ambient(环境色)和 emissive(发射的)

  • ambient跟AmbientLight 光源一起使用,这个颜色会与AmbientLight 光源的颜色相乘;默认为白色。

(2)该材质所包含的的纹理贴图:

  • bumpMap:用于创建凹凸贴图的纹理。
  • alphaMap:alpha贴图是一张灰度纹理,用于控制整个表面的不透明度。(黑色:完全透明;白色:完全不透明)。
  • displacementMap:位移贴图会影响网格顶点的位置,与仅影响材质的光照和阴影的其他贴图不同,移位的顶点可以投射阴影,阻挡其他对象,以及充当真实的几何体。 可以通过设置displacementScale大小来调整位移贴图对网格的影响程度。
  • emissiveMap:设置放射(发光)贴图。
  • envMap:环境贴图。
  • lightMap:光照贴图,lightMap需要第二组UV。
  • normalMap:法线贴图的类型。
  • specularMap:材质使用的高光贴图。

(3)使用实例

      // 创建网格模型
      const planeMaterial = new THREE.MeshLambertMaterial({
        color: 0x777777,
      }) // 材质对象Material
      const plane = new THREE.Mesh(geometry, planeMaterial)
      plane.receiveShadow = true

      // 设置平面位置
      plane.rotation.x = -0.5 * Math.PI
      plane.position.set(0, -20, 0)

      // 平面对象添加到场景中
      this.scene.add(plane)

      const sphereGeometry = new THREE.SphereGeometry(14, 20, 20)
      const cubeGeometry = new THREE.BoxGeometry(15, 15, 15)
      const planeGeometry = new THREE.PlaneGeometry(14, 14, 4, 4)

      // 创建材质
      this.meshMaterial = new THREE.MeshLambertMaterial({
        color: 0x7777ff,
      })

      // 创建球、方块、平面
      this.sphere = new THREE.Mesh(sphereGeometry, this.meshMaterial)
      this.cube = new THREE.Mesh(cubeGeometry, this.meshMaterial)
      this.plane = new THREE.Mesh(planeGeometry, this.meshMaterial)

      this.sphere.position.set(-12, 3, 2)
      this.cube.position = this.sphere.position
      this.plane.position = this.sphere.position
      this.activeMesh = this.sphere
   
      // 环境光
      const ambientLight = new THREE.AmbientLight(0xffffff, 0.1) // 创建环境光
      this.scene.add(ambientLight) // 将环境光添加到场景

      const spotLight = new THREE.SpotLight(0xffffff) // 创建聚光灯
      spotLight.position.set(-40, 60, -10)
      this.scene.add(spotLight)

5、THREE.MeshPhongMaterial(网格 Phong 材质)

通过 THREE.MeshPhongMaterial 可以创建一种具有镜面高光的光泽表面的材质。

(1)属性介绍

  • ambient(环境色):这是材质的环境色。它跟上一章讲过的环境光源一起使用。这个颜色会与环境光提供的颜色相乘。默认值为白色。
  • emissive(发射的):这是该材质的发射的颜色。它其实并不像一个光源,只是一种纯粹的、不受其它光照影响的颜色。默认值为黑色。
  • wrapAround:如果这个属性设置为true,则启动半lambert光照技术。有了它,光下降得更微妙。如果网格有粗糙、黑暗的地区,启用此属性阴影将变得柔和并且分不更加均匀。
  • wrapRGB:当wrapAround属性设置为true时,可以使用THREE.Vector3来控制光下降得速度。
  • specular: 该属性指定该材质的光亮程度及高光部分的颜色。
    • 如果将它设置成与 color 属性相同的颜色,将会得到一个更加类似金属的材质。
    • 如果将它设置成灰色(grey),材质将变得更像塑料。
  • shininess:该属性指定镜面高光部分的亮度。默认值:30。
  • metal:如果此属性设置为 true,Three.js 会使用稍微不同的方式计算像素的颜色,以使物体看起来更像金属。要注意的是,这个效果非常小。

 (2)该材质所包含的的纹理贴图:

  • bumpMap:用于创建凹凸贴图的纹理。
  • alphaMap:alpha贴图是一张灰度纹理,用于控制整个表面的不透明度。(黑色:完全透明;白色:完全不透明)。
  • aoMap:该纹理的红色通道用作环境遮挡贴图,aoMap需要第二组UV。
  • displacementMap:位移贴图会影响网格顶点的位置,与仅影响材质的光照和阴影的其他贴图不同,移位的顶点可以投射阴影,阻挡其他对象,以及充当真实的几何体。 可以通过设置displacementScale大小来调整位移贴图对网格的影响程度。
  • emissiveMap:设置放射(发光)贴图。
  • envMap:环境贴图。
  • lightMap:光照贴图,lightMap需要第二组UV。
  • normalMap:法线贴图的类型。
  • specularMap:材质使用的高光贴图。

(3)使用详例

为实例物体一个光源(环境光与点光源),并使用该材质创建一个小球。可以看到这个材质看上去比较光亮。

// 创建球体
const loader = new THREE.TextureLoader();
const geometry = new THREE.SphereGeometry(50, 128, 128);
// 定义地球材质
const texture = loader.load('./static/images/earth_atmos_4096.jpg');
// 添加浮雕凹凸贴图
const bump = loader.load('./static/images/earth_bump.jpg');
// 添加高光贴图
const spec = loader.load('./static/images/earth_specular_2048.jpg');
// 创建材质
const material = new THREE.MeshPhongMaterial({
  map: texture,
  bumpMap: bump,
  bumpScale: 5,
  specularMap: spec,
  specular: new THREE.Color('#1a2948'),
  shininess: 2
});
const mesh = new THREE.Mesh(geometry, material);
mesh.name = 'earth';
// 添加地球到场景
this.scene.add(mesh);

// 添加光源
const ambientLight = new THREE.AmbientLight(0x999999);
const pointLight = new THREE.PointLight(0xffffff, 1, 200);
pointLight.position.set(0, 100, 0);
this.scene.add(ambientLight, pointLight);

 

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐