卖相很重要,Threejs里面的那些Material们

在Threejs开发中,材质作为三要素中的其中之一,扮演着一个很重要的角色,就好比一件物体的皮肤一样,决定着这件物体是否透明,是否有金属效果,是否显示为线框,最近也是略微系统的学了一遍材质相关的知识点,打算用一篇文章记录一下。

材质的种类与特性

在Threejs中有很多种材质,每一种材质都有不一样的特性

  • MeshBasicMaterial:网格基础材质,能够给几何体赋予简单的颜色,也可以显示几何体的线框
  • MeshDephMaterial:网格深度材质,这种材质是使用摄像机与网格的距离来给网格赋予颜色
  • MeshNormalMaterial:网格法向材质,根据法向向量来计算物体表面的颜色
  • MeshLambertMaterial:网格Lambert材质,会受光照影响,会创建出暗淡不光亮的物体
  • MeshPhongMaterial:网格Phong式材质,会受光照影响,会创建出光亮的物体
  • MeshStandardMaterial:网格标准材质,基于PBR算法来绘制物体表面,能够计算出表面与光线的正确互动关系,从而使渲染出来的物体更加真实
  • MeshPhysicalMaterial:网格物理材质,MeshStandardMaterial的扩展材质,为光线反射计算模型提供了更多的控制
  • MeshToonMaterial:网格卡通材质,MeshPhongMaterial的扩展材质,使得物体渲染更加卡通化
  • ShadowMaterial:阴影材质,专门用于接收阴影图的特殊材质,这种材质里面只有阴影图像,非阴影部分为完全透明的区域
  • ShaderMaterial:着色器材质,允许使用自定义的着色器,直接控制顶点的放置方式以及像素的着色方式
  • LineBasicMaterial:直线基础材质,与THREE.Line一起使用,用于创建着色的直线
  • LineDashMaterial:虚线材质,与LineBasicMaterial一样,但是可以创建出虚线的效果

材质的共有属性

既然有那么多种材质,我们除了要了解什么时候该使用哪种材质之外,还应该清楚每一种材质都有哪些属性,属性决定着材质的呈现样式与方式,我们可以通过查看源码的方式去了解一个材质具备哪些属性,而属性的共有属性就定义在所有材质的基类THREE.Material中,这些共有属性总结起来可以分为三大类,基础属性,融合属性以及高级属性

基础属性

  • id:材质的唯一标识
  • uuid:生成的唯一标识,不可编辑
  • name:材质的名称
  • opacity:透明度,取值范围是0-1,与transparent属性一起使用
  • transparent:是否透明
  • visible:决定这个材质是否为可见
  • side:侧面,决定哪一面会被绘制,默认是THREE.FrontSide,还有THREE.BackSideTHREE.DoubleSide取值
  • needsUpdate:如果材质做了某些修改,可以使用这个属性让它为true,Threejs会使用新的材质属性来更新缓存
  • colorWrite:默认为true,表示材质是否输出颜色,即是否可见,当设置这个属性为false的时候,具备该材质的物体不会被渲染到场景中,也就是不可见,其他物体被它挡住的部分也是不可见的
  • premultipliedAlpha:控制半透明表面的颜色混合方式,默认为false
  • dithering:是否启用颜色抖动模式,默认为false
  • shadowSide:决定物体的哪一面会投射阴影
  • vertexColors:顶点颜色,为物体的每一个顶点指定特有的颜色

融合属性

融合属性决定了渲染的颜色如何与后面的颜色交互,有以下几种融合属性

  • blending:决定物体上的材质如何与背景融合,一般使用Three.NormalBlending,这种模式只显示材质的上层
  • blendSrc:使用alpha通道进行材质与背景的融合,默认值为THREE.SrcAlphaFactor
  • blendSrcAlpha:为blendSrc指定透明度
  • blendDst:融合时如何使用目标进行融合,默认值为THREE.OneMinusSrcAlphaFactor
  • blendDstAlpha:为blendDst指定透明度
  • blendEquation:表示如何使用blendSrcblendDst,默认方式是使它们相加,可用于创建自定义的融合模式

高级属性

高级属性一般都是一些偏低层的内容,通常使用默认值就可以了,但我们也应该了解下

  • depthTest:GL_DEPTH_TEST参数的开关,这个参数是用来控制是否使用像素深度来计算新像素的值
  • depthWrite:用来决定材质是否影响WebGL的深度缓存
  • depthFunc:决定使用的深度测试算法
  • polygonOffset:是否使用多边形偏移
  • polygonOffsetFactor:给多边形偏移设置值
  • polygonOffsetUnits:多边形偏移的单位
  • alphatest:当某个像素的透明值小于这个属性设置的值,那么该像素就不会显示出来
  • precision:设置当前材质的计算精度

MeshDephMaterial

说了一堆属性后,我们来尝试几个材质以及它们固有的特性,首先来看看深度材质MeshDephMaterial,当我们查看深度材质的参数列表的时候,会发现除了一些处理纹理相关的属性之外,几乎没有什么与渲染有关属性,其实深度材质的渲染完全取决于摄像机的可视区域,也就是nearfar之间的大小,来写个例子看看

这里给一个摄像机的最近最远距离分别设置了1与2000,然后在这个场景中我们添一个方块进去

这个方块使用了深度材质,并且构造函数里面没有设置任何属性,当我们前后拖动这个方块的时候,效果会是什么样子的呢

看到啥了?这个方块在朝着摄像机方向挪动到很近的位置的时候,消失了,这也刚好证明了深度材质的物体的可视范围刚好是在nearfar之间,刚才方块挪动的距离小于near了,所以方块才变消失了,除此之外,摄像机nearfar之间距离大小还关系到物体消失的速度,我们来尝试着把摄像机远近距离调小一点,然后再拖动一下方块看看

从效果图中可以发现当我们把远近距离调小后,深度材质的物体消失速度变的更快了,从上面这个例子中可以得出结论,当摄像机nearfar的距离很大的时候,深度材质的物体消失的效果不明显,反之,则消失的效果明显

MeshNormalMaterial

法向材质,对它不熟悉的可能脑子里一点概念也没有,我们先来看个例子来了解下

这里有一个球体几何体,使用的是法向材质,同时我们将法向材质的flatShading属性设置为true,就得到了如下这么个球

这是一个色彩鲜艳的球,它之所以鲜艳是因为这个球体上每一面的颜色都是通过该面的法向量计算得到的,所以这个球在旋转的时候,颜色由于每个面的法向量没有改变,它们的位置就不会改变的,这里flatShading设置为true表示使用平面着色,如果使用flatShading:false,那么就表示使用光滑着色

MeshLambertMaterial

兰伯特材质可以用来创建暗淡的并不光亮的表面,它是感光的材质,所以如果没有光源的话你是看不到它的,它有个比较有意思的属性叫emissive,意思是自发光,如果兰伯特材质设置了自发光属性,就算是场景里面没有光源,也是可以看到它的,看下面的例子

代码中把环境光给删掉了,应当这个时候所有感光材质应该是看不到的,但是由于球体是设置了自发光为蓝色的兰伯特材质,所以依然可以看到这个球

这个emissive属性相当于是让物体自身变成了一个光源,如果我们将注释掉的环境光打开,那么球体的自发光会不会因环境光受影响呢?我们看下

事实证明,环境光是会和自发光叠加在一起的

MeshPhongMaterial

这种材质与与MeshLambertMaterial比较类似,也可以创建出光亮材质的效果,区别在于MeshPhongMaterial制造出的材质更加光亮,除此之外,MeshPhongMaterial可以用它特有的属性speclar以及shiness,可以在一定程度上制造出一种金属的质感,方式就是将speclarcolor设置成一种颜色,下面来试一下

场景中有个球体几何体,使用了MeshPhongMaterial材质,并且将颜色设置成红色,场景中还添加了环境光与平行光,毕竟这是感光材质,没有光源是不行的,现在得到的效果如下所示

我们得到了一个有立体感的球体,但是缺乏金属感,如果想要让球体有金属感的话,就要加上speclar属性,色值与color用的一致

现在得到的效果就有点金属感了

加上speclar的效果就是球体表面有个高光区域,而这个高光区域的清晰程度就是有另一个属性shiness属性来控制,默认大小为30,这个值越大就表示高光区域越清晰,反之就越模糊,下面分别是将shiness设置成140以及10的效果

MeshStandardMaterial

标准材质在金属性上处理的要比MeshPhongMaterial更加的好,它也有自己特有的属性来创建出金属材质

  • metalness:控制物体表面的金属质感,取值为0-1,0表示完全塑料化,1表示完全金属化
  • roughness:控制物体表面的粗糙程度,取值0-1,0表现的如镜面效果,1的时候基本没有反射或者是漫反射

这里来看下标准材质在金属性上的处理与MeshPhongMaterial有什么不同,上面的代码中我们将球体的材质改为标准材质,颜色依然是红色,金属质感属性与粗糙质感属性分别设置为0.5,效果如下

可以看到无论从金属质感上还是高光效果上,都要比MeshPhongMaterial做出来的更加真实,而且还可以通过调整金属质感以及粗糙质感的大小,来达到不一样的金属效果

MeshPhysicalMaterial

物理材质与标准材质其实无论是在用法上还是在实际展示效果上都是蛮相似的,它们区别在于物理材质在反光效果上做了更多的处理,主要体现在以下三个属性上

  • clearcoat:控制物体表面清漆效果的明显程度,属性值越高,清漆涂层越厚,取值范围是0-1
  • clearcoatRoughness:控制物体表面的粗糙程度,粗糙程度越高,漫反射效果越明显,一般来讲这个属性与clearcoat属性一起使用,clearcoat属性值越高,clearcoatRoughness效果越明显
  • reflectivity:控制非金属表面的反光程度,所以当材质属性metalness接近于1的时候,reflectivity属性效果就不明显

大致了解了物理材质几个特有属性之后,我们来看下它与标准材质区别在哪,下面来写一个使用标准材质的四方体,同时将金属属性降低,粗糙程度升高,让它的反光效果不是很明显

同时在它的边上我们也再放一个四方体,用物理材质,并且将它反光程度值调到0.9,表面粗糙程度以及明显程度都调为0.5

这样就能看出这两种材质在处理反光效果时有什么区别,效果如下

仔细看的话还是可以发现,右边使用物理材质的物体,在同样的非金属属性下,反光效果比左边使用标准材质要明显一点

LineBasicMaterial

线材质专门用在创建线网格场景中,想要创建一个线网格,必须首先确定这个线的几个顶点坐标,比如一个简单的线网格,代码就长下面这样

如果想要将两个端点连接在一起,就可以使用THREE.LineLoop网格,代码如下

我们还可以使用另一种网格对象THREE.LineSegments,这种网格对象可以将顶点两两组合形成互不相关的线段,为了演示,我们需要再增加一个顶点坐标,代码如下

使用了THREE.LineSegments网格后,四个点都两两组成了两个线段,下面来介绍另一个线材质

LineDashedMaterial

虚线材质基本同线材质类似,区别在于它提供了设置虚线的能力,比如在上面的例子中我们换成虚线材质后就是下面这个样子

注意的是当设置了dashSizegapSize之后,一定要调用computeLineDistances函数,不然虚线效果是看不到的,上述代码的效果如下

如果需要调整虚线长度以及间隔大小,不用直接去调整gapSizedashSize,可以将scale参数调整为大于1的值,gapSizedashSize的大小就会等比例缩小了,当然scale小于1就会等比例变大,我们将scale调为1.5以后看下效果

总结

这篇文章我们了解了材质的一些共有属性,以及一些常用材质的用法以及各自的区别,在开发当中我们应该根据实际情况来挑选适当的材质来使用,了解材质的朋友们可能发现了,这篇文章里面漏了ShaderMaterial以及RawShadermaterial,主要是因为这俩材质东西太多,我打算整理一下单独用一篇文章来讲,包括一些GLSL的语法点,着色器的使用等,我们下一篇文章见

相关推荐
海上彼尚几秒前
实现3D热力图
前端·javascript·3d
杨过姑父几秒前
org.springframework.context.support.ApplicationListenerDetector 详细介绍
java·前端·spring
理想不理想v10 分钟前
使用JS实现文件流转换excel?
java·前端·javascript·css·vue.js·spring·面试
惜.己30 分钟前
Jmeter中的配置原件(四)
java·前端·功能测试·jmeter·1024程序员节
EasyNTS31 分钟前
无插件H5播放器EasyPlayer.js网页web无插件播放器vue和react详细介绍
前端·javascript·vue.js
poloma37 分钟前
五千字长文搞清楚 Blob File ArrayBuffer TypedArray 到底是什么
前端·javascript·ecmascript 6
guokanglun1 小时前
Vue.js动态组件使用
前端·javascript·vue.js
Go4doom1 小时前
vue-cli3+qiankun迁移至rsbuild
前端
-seventy-1 小时前
Ajax 与 Vue 框架应用点——随笔谈
前端
我认不到你1 小时前
antd proFromSelect 懒加载+模糊查询
前端·javascript·react.js·typescript