物质的多样性才让整个世界五彩斑斓 --- 佚名
在之前的部分中已经有涉及到材质部分了, 不过只是使用, 没有深入的说明, 比如
- MeshBasicMaterial -- 基本材质, 给几何体赋予颜色, 不随光照变化, 可以用于线框的表示
- MeshPhongMaterial/MeshLambertMaterial -- 考虑光照对材质的影响, 前者明亮, 后者暗淡
- MeshPhysicalMaterial -- AreaLight支持的光源之一
以下部分将更加深入的讲解相关内容
材质的共有属性
先看共同点, 所有的材质都是继承了一个基类, THREE.Material, 列出了所有共有属性
- 基础属性
- 渲染 overdraw(是否过度描绘), side(定义某一个面的材质), needUpdate(是否需要更新)
- 不透明度 opacity, transparent,
- 可见性 visible
- 如何被引用 id,uuid,name,
- 融合属性 每个材质如何与背景融合
- blending 融合模式
- NormalBlending 只显示材质的上层
- 创建自定义模式
- blendsrc 融合源 定义融合时如何使用源
- SrcAlphaFactor 默认值 以透明度通道进行融合
- blenddist 融合目标 定义融合时如何使用背景
- OneMinusSrcAlphaFactor 默认值 也是使用源的alpha通道进行融合, 且使用的值为1
- blendequation定义如何使用blendsrc/dist
- AddEquation 默认值, 相加
- blendsrc 融合源 定义融合时如何使用源
- blending 融合模式
- 高级属性
- 控制WebGL上下文对象渲染物体的方式. 大多数情况下无需使用
- 可了解OpenGL规范
简单材质
- MeshBasicMaterial
- MeshDepthMaterial
- MeshNormalMaterial
- MeshFaceMaterial
如何传入配置
- 在构造函数中传入
const material = new THREE.MeshBasicMaterial({
color: 0xffccdd,
name: 'material-1',
opacity: 0.3,
transparency: true
})
- 在实例上设置
const cubeMaterial = new THREE.MeshBasicMaterial()
const cubeGeometry = new THREE.BoxGeometry(5, 5, 5)
cubeMaterial.color = new THREE.Color(0xffccdd)
cubeMaterial.name = 'material-1'
cubeMaterial.opacity = '0.3'
cubeMaterial.transparent = true
两者的参数格式除了颜色外都一样, 但是更推荐在构造函数中传入. 在构造函数中颜色可以传一个十六进制的值, 而在实例上进行设置的时候必须传一个Color实例, 注意看看看不透明度的样式,本节详细的代码均请见github

基本网格的其他属性
除了上述属性那个外还有以下可以设置
- wireframe 是不是添加线框, 用于调试
- ~Linecap 线框端点显示样式
- round 圆 -- 默认值
- butt 平
- square 方
- ~Linejoin 线段连接点
- round 圆角 -- 默认值
- bevel 斜角
- mitter 尖角
- ~Linecap 线框端点显示样式

- shade 着色方式
- SmoothingShading -- 默认值
- NoShading
- FlatShading
- vertexColors 顶点颜色
- NoColor -- 默认值
- VectorColors 渲染器会采用Geometry中的颜色
- fog 雾化 是否受全局雾化效果的影响
MeshDepthMaterial
由名字可以看出, depth, 它的材质外观不是由光照或者某个属性决定, 而实由物体到摄像机的距离.这种材质很简单, 只有两个控制线框显示的属性
- wireframe
- wireframeLineWidth 由下图可以明显看出来不同cube之间的颜色深浅的区别, 摄像机的near与far属性差值越小, 颜色消失得越快.效果越明显, 需配合perspectiveCamera使用

联合材质
上述的MeshDepthMaterial是没有地方给他设置方块的颜色的, 一切都是默认属性决定. 联合材质就起到了融合的作用

const cubeGeometry = new THREE.BoxGeometry(cubeSize, cubeSize, cubeSize)
const cubeMaterial = new THREE.MeshDepthMaterial()
const colorMaterial = new THREE.MeshBasicMaterial({
color: 0x00ff00,
transparent: true,
blending: THREE.MultiplyBlending,
})
const cube = createMultiMaterialObject(cubeGeometry, [colorMaterial, cubeMaterial])
需要注意的是
- createMultiMaterialObject的第二个参数是混合材质列表, 最好按外到内的顺序进行添加
- 需要去掉scene的overrideMaterial, 不然colorMaterial无法应用上 具体的代码更改可参考commit
MeshNormalMaterial
该材质会将每一个方向进行一次颜色的计算, 使得颜色更加的自然, 如下图, 注意, 此时的亮暗并不是像MeshDepthMaterial一样因为距离摄像头远近, 而是每个物体的每个面不一样, 单个物体的亮度并没有发生改变:

MeshFaceMaterial(已废弃)
这是最后一个基本材质, 准确说应该是一种材质容器. threejs按照三角形渲染, 那么一个立方体cube就有12个face, 但这个属性已经被官方废弃了, 可参考 链接.直接在创建材质时用数组即可

const cube = new Three.Mesh(geo, [material1, material2])
高级材质
之前就多次使用的MeshPhongMaterial 和 MeshLambertMaterial材质会对光源做出反应, 可以用于创建光明和暗淡的材质.还有一种通用但难用的ShaderMaterial, 可以创建自己的着色程序, 定义材质和物体如何显示
MeshLambertMaterial
该材质具有以下通用属性属性, 已经在前文中提到
- color
- opacity
- shading
- blending
- depthTest
- depthWrite
- wireframe
- wireframeLinewidth
- wireframeLinecap
- wireframeLineJoin
- vertexColors
- fog 还有几个特殊属性
- ambient: 环境色, 于环境光源的颜色相乘, 默认为白色
- emissive: 发射的颜色, 默认为黑色, 不是一个光源, 不会影响其他材质的颜色显示
- wrapAround: 如果设置为true, 启动半光照技术, 光线下降得更微妙
- wrapRGB: wrapAround为true, 可以使用颜色控制光的下降速度
color为红色, emisive为默认黑色

emisive设置为白色

可以看到emisive属性是会影响材质对外展现的颜色的.
与之对应的有暗淡色就有一个光亮色
MeshPhongMaterial
除了基本属性以及Lambert具有的ambient,emissive, wrapAroud, wrapRGB之外, 还有以下特殊的属性
- specular: 指定材质光亮程度即高光部分颜色. 如果与color相同, 那么就会得到一个类似于金属的材质. 如果设置未灰色, 则更像塑料
- shininess: 该属性指定镜面高光部分, 默认值未30
不过我在实现过程中进行了尝试, 这两个属性确实变化不大.几乎可以忽略
我很奇怪为什么我无法实现官网所描述的这样的效果

原来忽略了一句话, 配合MeshStandardMaterial和MeshPhysicMaterial食用更佳
线性几何体的材质
下面的几种材质只能用于一个特别的几何体, THREE.LINE, 只是一条线段, 不包含任何的面.
- THREE.LineBasicMaterial
- color
- linecap 端点如何显示,butt-平 round(默认)-圆角 square-方, WebGLREnderer不支持
- linejoin线段连接点如何显示 round-圆 bevel-斜角 miter-尖角, WebGLREnderer不支持
- linewidth
- vertexColor 顶点颜色
- fog 是否受全局雾化效果设置
- THREE.LineDashedMaterial
- 同上
- scale: gapSize和dashSize的scale值, 大于1放大, 小于1缩小
- gapSize: 虚线间隔长度
- dashSize: 虚线段的长度
// Ordinary Line
const lineMaterial = new Three.LineBasicMaterial({
linecap: 'butt',
linewidth: 20,
color: 'blue',
})
const linesGeo = new Three.Geometry()
// 定义顶点
linesGeo.vertices.push(new Three.Vector3([1, 10, 10]), new Three.Vector3([10, 10, 10]))
const lines = new Three.Line(linesGeo, lineMaterial)
// DashedLine
const dashLineGeo = new Three.Geometry()
dashLineGeo.vertices.push(new Three.Vector3(0, 5, 0), new Three.Vector3(10, 5, 10))
const dashLine = new Three.Line(dashLineGeo, dashLineMaterial)
// 一定要注意调用这个方法才可以实现虚线的效果
dashLine.computeLineDistances()
const dashLineMaterial = new Three.LineDashedMaterial({
color: 0xffffff,
linewidth: 1,
scale: 1,
dashSize: 3,
gapSize: 2,
})

总结
以上就是常用的材质类型, 可以看到材质几乎是与几何体同时出现的, 下一篇会重点介绍关于几何体也就是Geometry的内容