three.js提供了一个THREE.Materail 材质的抽象基类,所有其他材质类型都继承了以下属性和方法:
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,
})
blending(融合):该属性决定物体上的材质如何与背景融合。一般的融合模式是 THREE.NormalBlending,在这种模式下只显示材质的上层。
blendSrc(混合源):
除了使用标准融合模式之外,还可以通过设置 blendsrc、 blenddst 和 blendequation 来创建自定义的融合模式。
这个属性定义了该物体(源)如何与背景(目标)相融合。默认值为THREE.SrcAlphaFactor,即使用 alpha(透明度)通道进行融合。
blendDst(混合目标): 这个属性定义了融合时如何使用背景(目标),默认值为 THREE.OneMinusSrcAlphaFactor,其含义是目标也使用源的 alpha 通道进行融合,只是使用的值是 1(源的 alpha 通道值),必须将材质的blending设置为CustomBlending才能生效。
blendEquation(融合公式):定义了如何使用 blendsrc 和 blenddst 的值。默认值为使它们相加(AddEquation)。通过使用这三个属性,可以创建自定义的融合模式。
depthTest / depthWrite:绘制不透明物体时,深度测试开启是能保证正确的遮挡关系,绘制透明物体时,关掉深度测试能保证正确的blend。
polygonOffset / polygonOffsetFactor / polygonOffsetUnits
alphatest:如果某个像素小于这个值,则不会显示。
定义:MeshBasicMaterial是一种比较简单的材质
特点:这种材质不受光照的影响,不考虑光照的影响,可以渲染基础的平面或者几何体。
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,那么我们全局雾化效果设置就不会影响当前对象的渲染。
map:颜色贴图。
aoMap:该纹理的红色通道用作环境遮挡贴图,aoMap需要第二组UV。
envMap:环境贴图。
lightMap:光照贴图,lightMap需要第二组UV。
alphaMap:alpha贴图是一张灰度纹理,用于控制整个表面的不透明度。(黑色:完全透明;白色:完全不透明)。
specularMap:材质使用的高光贴图。
示例一:颜色纹理贴图
// 导入纹理
// 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('修改颜色')
一种按深度绘制几何体的材质。深度基于相机远近平面。白色最近,黑色最远。使用这种材质的物体,其外观不是由光照或者某个材质属性决定的,而是由物体到摄像机的距离决定的。我们可将这种材质与其他材质结合使用,从而很容易地创建出逐渐消失得效果。
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相关数据调整相机的近面值及远面值。
这里要特别注意如下几个地方:
一种把法向量映射到RGB颜色的材质,使用这种材质,每一面的颜色是由从该面向外指的法向量计算得到的。
// 创建法向量纹理
var meshMaterial = new THREE.MeshNormalMaterial({
flatShading: THREE.FlatShading,
transparent: true,
opacity: 0.7
});
在此有两个比较重要的属性:ambient(环境色)和 emissive(发射的)
// 创建网格模型
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)
通过 THREE.MeshPhongMaterial 可以创建一种具有镜面高光的光泽表面的材质。
为实例物体一个光源(环境光与点光源),并使用该材质创建一个小球。可以看到这个材质看上去比较光亮。
// 创建球体
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);