从1开始学习THREE.js--材质

1,579 阅读6分钟

物质的多样性才让整个世界五彩斑斓 --- 佚名

在之前的部分中已经有涉及到材质部分了, 不过只是使用, 没有深入的说明, 比如

  • 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 默认值, 相加
  • 高级属性
    • 控制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 尖角

  • 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的内容