材质用于在几何体的每个可见像素上添加颜色
初始化基础网格材质MeshBasicMaterial,这种材质不受光照的影响。
const material = new THREE.MeshBasicMaterial()
接下来我们往场景中添加三个网格物体
//球形缓冲几何体
const sphere = new THREE.Mesh(new THREE.SphereBufferGeometry(0.5,16,16),material)
//平面缓冲几何体
const plane = new THREE.Mesh(new THREE.PlaneBufferGeometry(1,1),material)
//圆环缓冲几何体
const torus = new THREE.Mesh(new THREE.TorusBufferGeometry(0.5,0.2,16,32),material)
sphere.position.x = -1.5
torus.position.x = 1.5
scene.add(sphere,plane,torus)
const material = new THREE.MeshBasicMaterial({map:doorColorTexture})
或者这样写
const material = new THREE.MeshBasicMaterial()
material.map = doorColorTexture
// 材质颜色设置红色
const material = new THREE.MeshBasicMaterial({color:0xff0000})
另外一种写法,效仿上面设置纹理贴图,但你会发现如果直接设置材质的颜色,会报错
// 材质颜色设置红色
const material = new THREE.MeshBasicMaterial()
console.log(material.color)
material.color = 'red' //报错
这是因为一旦材质被实例化后,它的.color
属性会是一个Color类
材质对象的一些属性可以在构造函数参数中设置,也可以访问材质对象的属性设置。
你可以通过下面俩种方式设置材质颜色属性
material.color.set('#ff00ff')
//或者
material.color = new THREE.Color('red')
若想设置材质透明,则必须开启透明度效果,设置.transparent
属性为true
material.transparent = true
material.opacity = 0.5
//alphaMap属性同样需要开启transparent属性
material.transparent = true
material.alphaMap = doorAlphaTexture
简单来讲,alpha贴图白色区域是可见的,黑色区域将被隐藏起来
我们可以把alpha贴图和其他纹理贴图结合起来
material.side = THREE.FrontSide //正面 (默认)
material.side = THREE.BackSide //背面
material.side = THREE.DoubleSide //双面都渲染
它是一种把法向量映射到RGB颜色的材质。
const material = new THREE.MeshNormalMaterial()
如果你改变下图摄像机位置,可以观察到物体颜色会有所不同。
法线可以用于照明、反射与折射等。
像transparent
,opacity
和side
这三个属性都是所有材质共有的属性
其定义材质是否使用平面着色进行渲染。
material.flatShading = true
但由于颜色纷呈,所以也可以试着运用到项目中
网帽材质(MeshMatcapMaterial)将通过使用法线作为参照来在看起来像球体的纹理上拾取正确的颜色来显示颜色
const material = new THREE.MeshMatcapMaterial()
我们将网帽材质的matcap
属性设置为下图matcap纹理贴图
material.matcap = matcapsTexture
查看渲染效果,我们会有一种错觉,感觉物体被照亮了一样。因此网帽材质的作用就是在场景没有光源的情况下,模拟出物体被光照的效果
如果几何体接近摄影机的“near”值,它将简单地将几何体着色为白色,如果几何体越接近摄影机的“far”值,则将几何体着色为黑色。
const material = new THREE.MeshDepthMaterial()
该材质对光线有反应
const material = new THREE.MeshLambertMaterial()
因此先往场景添加光源,才可以观察到物体,这里我们添加环境光和点光源
const ambientLight = new THREE.AmbientLight(0xffffff,0.5)
scene.add(ambientLight)
const pointLight = new THREE.PointLight(0xffffff,0.5)
pointLight.position.set(2,3,4)
scene.add(pointLight)
如果我们不添加光源,由于我们没有为渲染器添加背景颜色,所以我们会看到一片漆黑。
Phong网格材质与Lambert网格材质很相似,但是你可以仔细观察到上图中Lambert网格材质的球体表面有些像是线型一样的奇怪图案,而Phong网格材质的球体相对于前者这些图案不太明显,并且你还能看到Phong网格材质球体上光线的反射更为明亮。
我们可以通过shininess
属性控制光线反射高亮程度,数值越高越闪亮,并通过specular
属性控制反射的颜色
material.shininess = 100
material.specular = new THREE.Color('0xff0000')
Toon网格材质与Lambert网格材质很相似,但更偏向于卡通化。我们可以看出物体的颜色渐变非常明显
如果要使其渐变层次更丰富,我们可以将toon材质的gradientMap
属性设置为gradient渐变纹理贴图
material.gradientMap = gradientTexture
下图是渐变纹理贴图
观察下图效果,我们不能说它与Lambert网格材质十分相似,只能说是一模一样,但是很明显失去了卡通化的效果
这是因为放大滤镜magFilter试图通过拉伸来修复这个非常小的渐变纹理贴图,这过程就使用到了mip映射(mipmapping)使其变得模糊。
所以若想防止此种情况,我们可以设置纹理贴图的缩小滤镜minFilter
属性和放大滤镜magFilter
属性为THREE.NearestFilter。
关于滤镜属性可以查看我另一篇笔记three.js学习笔记(二)——textures纹理
gradientTexture.minFilter = THREE.NearestFilter
gradientTexture.magFilter = THREE.NearestFilter
// 因为我们的渐变纹理贴图的缩小滤镜minFilter属性使用了NearestFilter
// 所以我们可以为该纹理停用mipmapping,使得GPU不再处理其mip映射
gradientTexture.generateMipmaps = false
一种基于物理的渲染(PBR)的标准材质,该材质提供了比MeshLambertMaterial 或MeshPhongMaterial 更精确和逼真的结果,代价是计算成本更高。
材质与金属的相似度。非金属材质,如木材或石材,使用0.0,金属使用1.0,通常没有中间值。 默认值为0.0。0.0到1.0之间的值可用于生锈金属的外观。
材质的粗糙程度。0.0表示平滑的镜面反射,1.0表示完全漫反射。
以上两种属性可通过添加GUI面板改变数值进行观察
aoMap(ambient occlusion map)环境遮挡贴图。它将在纹理较暗的地方添加阴影,因此我们必须添加另外一组uv坐标,即uv2。
在我们的例子中,它与默认UV的坐标相同,因此我们将重用它。
sphere.geometry.setAttribute('uv2',new THREE.BufferAttribute(sphere.geometry.attributes.uv.array,2))
plane.geometry.setAttribute('uv2',new THREE.BufferAttribute(plane.geometry.attributes.uv.array,2))
torus.geometry.setAttribute('uv2',new THREE.BufferAttribute(torus.geometry.attributes.uv.array,2))
为材质aoMap
属性设置ao(ambient occlusion)纹理贴图
material.aoMap = doorAmbientOcclusionTexture
我们还可以设置环境遮挡效果的强度aoMapIntensity
属性。默认值为1。零是不遮挡效果。
material.aoMapIntensity = 3.1
位移贴图会影响网格顶点的位置。换句话说就是它可以移动顶点来创建浮雕。
为材质displacementMap
属性设置位移纹理贴图,使得平面物体中间的门有凸起效果。
material.displacementMap = doorHeightTexture
物体看起来非常糟糕奇怪。这是因为我们的几何体中没有足够的顶点,所以你可以观察到平面几何体没有任何变化
重新设置几何体的分段数,给其设置更多些
const sphere = new THREE.Mesh(new THREE.SphereBufferGeometry(0.5,64,64),material)
const plane = new THREE.Mesh(new THREE.PlaneBufferGeometry(1,1,100,100),material)
const torus = new THREE.Mesh(new THREE.TorusBufferGeometry(0.3,0.2,64,128),material)
重新观察
观察上图可以发现几何体顶点数多起来后,物体稍微变得不再那么奇怪,至少有点规则性了。
同时我们也注意到这默认位移效果有点用力过猛,这时我们可以设置displacementScale
属性:位移贴图对网格的影响程度(黑色是无位移,白色是最大位移)。默认值为1。
// 设置位移程度小一点
material.displacementScale = 0.1
同样道理,还有metalnessMap
属性和roughnessMap
属性也一样可以设置相应纹理贴图,这样我们可以不必为整个几何体指定均匀的金属程度和粗糙度,而是变为局部改变。
// 为避免反射效果变得怪异,记得先把前面的metalness属性和roughness属性给重设为默认值
material.metalnessMap = doorMetalnessTexture
material.roughnessMap = doorRoughnessTexture
用于创建法线纹理贴图的纹理。它将伪造法线方向,并在物体表面上添加细节。
material.normalMap = doorNormalTexture
可以观察到这个木门已经开始有点栩栩如生了
我们可以normalScale
属性改变法线纹理贴图对材质的影响程度。典型范围是0-1。默认值是Vector2设置为(1,1)。
// 可以发现细节程度变小了
material.normalScale.set(0.5,0.5)
最后我们往材质中再设置alphaMap
属性,添加alpha纹理贴图
material.alphaMap = doorAlphaTexture
// 使用alphaMAp记得开启transparent属性
material.transparent = true
// 标准网格材质(MeshStandardMaterial)
const material = new THREE.MeshStandardMaterial()
material.map = doorColorTexture
material.aoMap = doorAmbientOcclusionTexture
material.aoMapIntensity = 1
material.displacementMap = doorHeightTexture
material.displacementScale = 0.05
material.metalnessMap = doorMetalnessTexture
material.roughnessMap = doorRoughnessTexture
material.normalMap = doorNormalTexture
material.normalScale.set(0.5,0.5)
material.alphaMap = doorAlphaTexture
material.transparent = true
物理网格材质MeshPhysicalMaterial与标准网格材质MeshStandardMaterial很相似,只不过物理网格材质具有清晰的涂层效果和更高级的基于物理的渲染属性,可以将其看作是标准网格材质的扩展
我们可以用点材质创建粒子
环境贴图是场景周围环境的图像。它可以用于反射或折射,也可以用于一般照明,支持多种材质。Three.js仅支持立方环境贴图。
使用CubeTextureLoader而不是TextureLoader
const cubeTextureLoader = new THREE.CubeTextureLoader()
const environmentMapTexture = cubeTextureLoader.load([
'/textures/environmentMaps/0/px.jpg',
'/textures/environmentMaps/0/nx.jpg',
'/textures/environmentMaps/0/py.jpg',
'/textures/environmentMaps/0/nx.jpg',
'/textures/environmentMaps/0/pz.jpg',
'/textures/environmentMaps/0/nz.jpg',
])
material.envMap = environmentMapTexture
观察效果。可以通过设置metalness
金属度和roughness
粗糙度控制反射情况
//环境贴图environment map
const material = new THREE.MeshStandardMaterial()
material.metalness = 0.7
material.roughness = 0.2
material.envMap = environmentMapTexture
gui.add(material,'metalness').min(0).max(1).step(0.0001)
gui.add(material,'roughness').min(0).max(1).step(0.0001)
polyhaven
从上面这个网站下载的环境贴图是一张HDRI图片,可以使用这个工具HDRI-to-CubeMap将HDRI转化为立方体贴图