第05课:基础功能之Material 材质

文章推薦指數: 80 %
投票人數:10人

材质可以看成是材料和质感的结合。

在渲染程序中,它是表面各种可视属性的结合,这些可视属性是指表面的色彩、纹理、光滑度 ... 首页 图文课 文章 我的订单 我的收藏 图文课 我的文章 我的订单 第05课:基础功能之Material材质 上一篇我们讲解了模型的形状,本文我们讲解下模型的表现,也就是我们看到的的模型外观——材质。

简单的说,就是物体看起来是什么质地。

材质可以看成是材料和质感的结合。

在渲染程序中,它是表面各种可视属性的结合,这些可视属性是指表面的色彩、纹理、光滑度、透明度、反射率、折射率、发光度等。

Three.js给我们封装好了大部分的材质效果,避免我们使用复杂的Shader语言自己去实现。

接下来我们先介绍下Material常用的一些属性和方法。

基本属性和方法 needsUpdate 如果修改了Material内的内容,需要将needsUpdate属性设置为true,Three.js会在下一帧里将修改内容同步到WebGL的显存内。

切记不要在requestAnimationFrame方法内更新,会浪费性能,只需要在更新Material属性后设置一次即可。

side 此属性可以定义当前面的哪个方向会被渲染,默认值是THREE.FrontSide(只渲染正面),可选值有:THREE.BackSide(只渲染背面)和THREE.DoubleSide(正面和背面都会渲染)。

transparent 此属性定义了材质是否可以透明,因为对于透明需要材质进行特殊处理,并在不透明的物体渲染完成后再渲染透明物体。

当设置此属性为true后,可以通过设置opacity来调整透明度,默认为false。

opacity 此属性可以定义材质的透明度,必须将材质的transparent设置为true才可使透明度管用。

取值范围为0.0到1.0。

默认值是1.0,也就是不透明。

map 此属性可以配置当前材质的纹理贴图,是一个THREE.Texture对象,下面我们将会讲解如何给材质贴图。

这是大部分材质都会有的属性,只有极其个别的材质如LineBasicMaterial(线材质)等没有这个属性。

wireframe 是否将模型渲染成线框,默认为false。

个别材质也没有这个属性。

dispose() 此方法用于将材质从内存中删除,在不需要使用当前材质时使用,但不会将材质的纹理贴图删除,如果需要将纹理贴图也删除,需要调用material.map.dispose()。

配置纹理贴图 由于经常使用纹理贴图,所以在这里单独讲解一下如何实现一个纹理贴图。

实现纹理贴图有以下两种方式。

第一种,使用THREE.TextureLoader进行生成纹理对象: vartexture=newTHREE.TextureLoader().load("textures/water.jpg"); material.map=texture;//将纹理赋值给材质 或者直接实例化: vartexture=newTHREE.Texture(canvas);//实例化的第一个对象可以是`img`、`canvas`和`video`。

material.map=texture;//将纹理赋值给材质 纹理重复问题 如果图片不是标准的2的幂数(2、4、8、16、32、64、128、256、512、1024、2048……),在控制台会给我们提示:“THREE.WebGLRenderer:imageisnotpoweroftwo”,意思就是说图片不是标准格式高宽不是2的幂数。

我们需要的水平方向和垂直方向上设置的图片重复显示。

需要配置的两个属性是:texture.wrapS(水平方向重复)和texture.wrapT(垂直方向重复),默认值是:THREE.ClampToEdgeWrapping,即纹理的最后一个像素延伸到网格的边缘。

可选项有:THREE.RepeatWrapping,表示纹理将重复无穷大;MirroredRepeatWrapping,表示镜像重复,可以理解为重复时,反着绘制一个然后正着绘制一个,达到的效果就是没有强烈的过渡感觉。

needsUpdate属性 如果更新了纹理的相关属性,需要将此属性设置为true,将数据同步到WebGL。

repeat 纹理在整个表面水平方向和垂直方向重复多少次,也会受纹理重复设置的影响,设置方式为: vartexture=newTHREE.TextureLoader().load("textures/water.jpg"); texture.wrapS=THREE.RepeatWrapping;//设置水平方向无限循环 texture.wrapT=THREE.RepeatWrapping;//设置垂直方向无限循环 texture.repeat.set(4,4);//水平方向和垂直方向都重复四次 内置常用材质 在讲解常用材质之前,我们先讲解一下如何实例化一个材质和一些需要注意的地方。

我们使用第一个讲到的材质MeshBasicMaterial作为例子。

MeshBasicMaterial和设置颜色的方法 这种材质是一种简单的材质,不会受到光的影响,直接看到的效果就是整个物体的颜色都是一样,没有立体的感觉。

在实例化材质时,我们可以传入一个对象,设置材质的相关属性可以通过对象属性的方式传入,但是属性color(颜色)例外,实例化的时候可以传入十六进制数,也可以写十六进制字符串。

实例化完成后再修改需要重新赋值THREE.Color对象,或者调用material.color.set方法赋值。

varmaterial=newTHREE.MeshBasicMaterial({color:0x00ffff}); vargeometry=newTHREE.BoxGeometry(1,1,1); varmesh=newTHREE.Mesh(geometry,material); scene.add(mesh); 上面的案例就是使用MeshBasicMaterial材质创建了一个立方体,我们设置了显示颜色为一种浅蓝色,除了上面实例化的时候进行设置,后面也可以再修改: varmaterial=newTHREE.MeshBasicMaterial({color:0x00ffff});//设置初始的颜色为浅蓝色 material.color.set(0xff00ff);//将颜色修改为紫色 我们也可以直接赋值一个新的THREE.Color对象,如: varmaterial=newTHREE.MeshBasicMaterial({color:0x00ffff});//设置初始的颜色为浅蓝色 material.color=newTHREE.Color(0xff00ff);//将颜色修改为紫色 我们可以通过newTHREE.Color创建一个颜色对象,Three.js支持的颜色书写方式比较丰富,如: //直接传入十六进制数或者字符串 varcolor=newTHREE.Color(0xff0000); varcolor=newTHREE.Color("#ff0000"); //RGB字符串 varcolor=newTHREE.Color("rgb(255,0,0)"); varcolor=newTHREE.Color("rgb(100%,0%,0%)"); //支持一百四十多中颜色名称 varcolor=newTHREE.Color('skyblue'); //HSL字符串 varcolor=newTHREE.Color("hsl(0,100%,50%)"); //支持RGB值设置在0到1之间的方式 varcolor=newTHREE.Color(1,0,0); MeshNormalMaterial法向材质 这种材质会根据面的方向不同自动改变颜色,也是我们之前一直在用的材质。

此材质不受灯光影响。

geometry=newTHREE.BoxGeometry(2,2,2);//创建几何体 material=newTHREE.MeshNormalMaterial();//创建材质 mesh=newTHREE.Mesh(geometry,material);//创建网格 scene.add(mesh);//将网格添加到场景 LineBasicMaterial线条材质 在上一篇我们讲几何体时,没有讲解如何画直线,是由于直线需要单独的材质进行实现,所以我们将直线放到了材质这一篇中进行讲解。

注意,由于Windows系统的原因,线的宽度只能为1。

要绘制线段,我们需要确定两个点,就是起点和终点,案例中我们使用了四个顶点创建了三条线。

然后Geometry对象使用这组顶点配置几何体,实例化线的材质,最后使用THREE.Line生成线。

//添加直线 varpointsArr=[ newTHREE.Vector3(-10,0,-5), newTHREE.Vector3(-5,15,5), newTHREE.Vector3(20,15,-5), newTHREE.Vector3(10,0,5) ]; varlineGeometry=newTHREE.Geometry();//实例化几何体 lineGeometry.setFromPoints(pointsArr);//使用当前点的属性配置几何体 varlineMaterial=newTHREE.LineBasicMaterial({color:0x00ff00});//材质 line=newTHREE.Line(lineGeometry,lineMaterial); scene.add(line); LineDashedMaterial虚线 我们也可以创建虚线,这里我们来点新花样,就是实现曲线。

曲线也和直线一样,在Windows系统线的粗度只能为1。

要创建曲线,我们需要使用到THREE.CatmullRomCurve3来生成一个curve对象,这是一个曲线对象,可以从对象获取生成的曲线的点的集合,在这里科普一下,曲线也是由无数段的直线组成的,段数分的越清晰,曲线过渡越顺滑。

varpointsArr=[ newTHREE.Vector3(-10,0,-5), newTHREE.Vector3(-5,15,5), newTHREE.Vector3(20,15,-5), newTHREE.Vector3(10,0,5) ]; //指定一些用于生成曲线线的三维顶点 varcurve=newTHREE.CatmullRomCurve3(pointsArr); varpoints=curve.getPoints(50);//使用getPoints获取当前曲线分成50段后的所有顶点 varcurveGeometry=newTHREE.BufferGeometry().setFromPoints(points);//使用顶点生成几何体 varcurveMaterial=newTHREE.LineDashedMaterial({color:0xff0000});//创建一条红色的线材质 //使用THREE.Line创建线 curveLine=newTHREE.Line(curveGeometry,curveMaterial); curveLine.computeLineDistances();//需要重新计算位置才能显示出虚线 scene.add(curveLine); 添加光 由于MeshBasicMaterial不会受光的影响,即使有光也不会影响它的效果,前面我们也没有添加光。

但是后面介绍的材质会受到光源的影响,在介绍之前,我们需要添加一个光源,来影响材质的显示效果。

//创建灯光 functioninitLight(){ varlight=newTHREE.DirectionalLight(0xffffff);//添加了一个白色的平行光 light.position.set(20,50,50);//设置光的方向 scene.add(light);//添加到场景 //添加一个全局环境光 scene.add(newTHREE.AmbientLight(0x222222)); } 上面我们添加了一个模拟太阳光线的平行光和一个对每一个物理都造成影响的环境光,具体的内容将会在下一篇讲解。

下面介绍的材质都是对光有反应的,而且如果场景内没有光,模型将无法显示。

MeshLambertMaterial兰伯特材质 这种材质会对光有反应,但是不会出现高光,可以模拟一些粗糙的材质的物体,比如木头或者石头。

实现案例,如下: geometry=newTHREE.BoxGeometry(2,2,2);//创建几何体 material=newTHREE.MeshLambertMaterial({color:0x00ffff});//创建材质 mesh=newTHREE.Mesh(geometry,material);//创建网格 scene.add(mesh);//将网格添加到场景 MeshPhongMaterial高光材质 这种材质具有高光效果,可以模拟一些光滑的物体的材质效果,比如油漆面,瓷瓦等光滑物体。

实现案例如下: geometry=newTHREE.BoxGeometry(2,2,2);//创建几何体 material=newTHREE.MeshPhongMaterial({color:0x00ffff});//创建材质 mesh=newTHREE.Mesh(geometry,material);//创建网格 scene.add(mesh);//将网格添加到场景 MeshStandardMaterial基于物理的渲染(PBR)材质 这种材质基于物理的渲染(PBR)材质,生成的材质效果更佳,但是相应也占用更多的计算量。

这种材质我们可以定义它的粗糙度来确定反光效果,经常用于模拟金属的质感,使金属质感更加真实。

实现案例如下: geometry=newTHREE.BoxGeometry(2,2,2);//创建几何体 material=newTHREE.MeshPhongMaterial({color:0x00ffff});//创建材质 material.metalness=0.1;//设置的值的范围为0-1,值越小,材质越光滑,高光越明显 material.metalnessMap=0.1;//设置的值的范围为0-1,值越大,越有生锈金属的质感,值越小反光越清晰 mesh=newTHREE.Mesh(geometry,material);//创建网格 scene.add(mesh);//将网格添加到场景 案例代码 最后,我将本文的内容整理成了一个案例放到了Github上: Github代码地址 案例效果查看地址:Github地址 内容互动 评论 加载更多 课程详情 1 第01课:入门前准备 2 第02课:初识Three.js 3 第03课:基础功能之Scene场景 4 第04课:基础功能之Geometry几何体 5 第05课:基础功能之Material材质 6 第06课:基础功能之Light光照 7 第07课:基础功能之Camera相机 8 第08课:基础功能之Points粒子 9 第09课:进阶篇之Controls相机控制器 10 第10课:进阶篇之使用Loaders加载模型到Three.js 11 第11课:进阶篇之Three.js动画 12 第12课:进阶篇之使用Tween.js创建补间动画 13 第13课:进阶篇之Three.js场景交互 14 第14课:进阶篇之Three.js性能优化 15 第15课:进阶篇之Three.js核心对象 16 第16课:实战篇之人物操作案例 第05课:基础功能之Material材质 上一篇我们讲解了模型的形状,本文我们讲解下模型的表现,也就是我们看到的的模型外观——材质。

简单的说,就是物体看起来是什么质地。

材质可以看成是材料和质感的结合。

在渲染程序中,它是表面各种可视属性的结合,这些可视属性是指表面的色彩、纹理、光滑度、透明度、反射率、折射率、发光度等。

Three.js给我们封装好了大部分的材质效果,避免我们使用复杂的Shader语言自己去实现。

接下来我们先介绍下Material常用的一些属性和方法。

基本属性和方法 needsUpdate 如果修改了Material内的内容,需要将needsUpdate属性设置为true,Three.js会在下一帧里将修改内容同步到WebGL的显存内。

切记不要在requestAnimationFrame方法内更新,会浪费性能,只需要在更新Material属性后设置一次即可。

side 此属性可以定义当前面的哪个方向会被渲染,默认值是THREE.FrontSide(只渲染正面),可选值有:THREE.BackSide(只渲染背面)和THREE.DoubleSide(正面和背面都会渲染)。

transparent 此属性定义了材质是否可以透明,因为对于透明需要材质进行特殊处理,并在不透明的物体渲染完成后再渲染透明物体。

当设置此属性为true后,可以通过设置opacity来调整透明度,默认为false。

opacity 此属性可以定义材质的透明度,必须将材质的transparent设置为true才可使透明度管用。

取值范围为0.0到1.0。

默认值是1.0,也就是不透明。

map 此属性可以配置当前材质的纹理贴图,是一个THREE.Texture对象,下面我们将会讲解如何给材质贴图。

这是大部分材质都会有的属性,只有极其个别的材质如LineBasicMaterial(线材质)等没有这个属性。

wireframe 是否将模型渲染成线框,默认为false。

个别材质也没有这个属性。

dispose() 此方法用于将材质从内存中删除,在不需要使用当前材质时使用,但不会将材质的纹理贴图删除,如果需要将纹理贴图也删除,需要调用material.map.dispose()。

配置纹理贴图 由于经常使用纹理贴图,所以在这里单独讲解一下如何实现一个纹理贴图。

实现纹理贴图有以下两种方式。

第一种,使用THREE.TextureLoader进行生成纹理对象: vartexture=newTHREE.TextureLoader().load("textures/water.jpg"); material.map=texture;//将纹理赋值给材质 或者直接实例化: vartexture=newTHREE.Texture(canvas);//实例化的第一个对象可以是`img`、`canvas`和`video`。

material.map=texture;//将纹理赋值给材质 纹理重复问题 如果图片不是标准的2的幂数(2、4、8、16、32、64、128、256、512、1024、2048……),在控制台会给我们提示:“THREE.WebGLRenderer:imageisnotpoweroftwo”,意思就是说图片不是标准格式高宽不是2的幂数。

我们需要的水平方向和垂直方向上设置的图片重复显示。

需要配置的两个属性是:texture.wrapS(水平方向重复)和texture.wrapT(垂直方向重复),默认值是:THREE.ClampToEdgeWrapping,即纹理的最后一个像素延伸到网格的边缘。

可选项有:THREE.RepeatWrapping,表示纹理将重复无穷大;MirroredRepeatWrapping,表示镜像重复,可以理解为重复时,反着绘制一个然后正着绘制一个,达到的效果就是没有强烈的过渡感觉。

needsUpdate属性 如果更新了纹理的相关属性,需要将此属性设置为true,将数据同步到WebGL。

repeat 纹理在整个表面水平方向和垂直方向重复多少次,也会受纹理重复设置的影响,设置方式为: vartexture=newTHREE.TextureLoader().load("textures/water.jpg"); texture.wrapS=THREE.RepeatWrapping;//设置水平方向无限循环 texture.wrapT=THREE.RepeatWrapping;//设置垂直方向无限循环 texture.repeat.set(4,4);//水平方向和垂直方向都重复四次 内置常用材质 在讲解常用材质之前,我们先讲解一下如何实例化一个材质和一些需要注意的地方。

我们使用第一个讲到的材质MeshBasicMaterial作为例子。

MeshBasicMaterial和设置颜色的方法 这种材质是一种简单的材质,不会受到光的影响,直接看到的效果就是整个物体的颜色都是一样,没有立体的感觉。

在实例化材质时,我们可以传入一个对象,设置材质的相关属性可以通过对象属性的方式传入,但是属性color(颜色)例外,实例化的时候可以传入十六进制数,也可以写十六进制字符串。

实例化完成后再修改需要重新赋值THREE.Color对象,或者调用material.color.set方法赋值。

varmaterial=newTHREE.MeshBasicMaterial({color:0x00ffff}); vargeometry=newTHREE.BoxGeometry(1,1,1); varmesh=newTHREE.Mesh(geometry,material); scene.add(mesh); 上面的案例就是使用MeshBasicMaterial材质创建了一个立方体,我们设置了显示颜色为一种浅蓝色,除了上面实例化的时候进行设置,后面也可以再修改: varmaterial=newTHREE.MeshBasicMaterial({color:0x00ffff});//设置初始的颜色为浅蓝色 material.color.set(0xff00ff);//将颜色修改为紫色 我们也可以直接赋值一个新的THREE.Color对象,如: varmaterial=newTHREE.MeshBasicMaterial({color:0x00ffff});//设置初始的颜色为浅蓝色 material.color=newTHREE.Color(0xff00ff);//将颜色修改为紫色 我们可以通过newTHREE.Color创建一个颜色对象,Three.js支持的颜色书写方式比较丰富,如: //直接传入十六进制数或者字符串 varcolor=newTHREE.Color(0xff0000); varcolor=newTHREE.Color("#ff0000"); //RGB字符串 varcolor=newTHREE.Color("rgb(255,0,0)"); varcolor=newTHREE.Color("rgb(100%,0%,0%)"); //支持一百四十多中颜色名称 varcolor=newTHREE.Color('skyblue'); //HSL字符串 varcolor=newTHREE.Color("hsl(0,100%,50%)"); //支持RGB值设置在0到1之间的方式 varcolor=newTHREE.Color(1,0,0); MeshNormalMaterial法向材质 这种材质会根据面的方向不同自动改变颜色,也是我们之前一直在用的材质。

此材质不受灯光影响。

geometry=newTHREE.BoxGeometry(2,2,2);//创建几何体 material=newTHREE.MeshNormalMaterial();//创建材质 mesh=newTHREE.Mesh(geometry,material);//创建网格 scene.add(mesh);//将网格添加到场景 LineBasicMaterial线条材质 在上一篇我们讲几何体时,没有讲解如何画直线,是由于直线需要单独的材质进行实现,所以我们将直线放到了材质这一篇中进行讲解。

注意,由于Windows系统的原因,线的宽度只能为1。

要绘制线段,我们需要确定两个点,就是起点和终点,案例中我们使用了四个顶点创建了三条线。

然后Geometry对象使用这组顶点配置几何体,实例化线的材质,最后使用THREE.Line生成线。

//添加直线 varpointsArr=[ newTHREE.Vector3(-10,0,-5), newTHREE.Vector3(-5,15,5), newTHREE.Vector3(20,15,-5), newTHREE.Vector3(10,0,5) ]; varlineGeometry=newTHREE.Geometry();//实例化几何体 lineGeometry.setFromPoints(pointsArr);//使用当前点的属性配置几何体 varlineMaterial=newTHREE.LineBasicMaterial({color:0x00ff00});//材质 line=newTHREE.Line(lineGeometry,lineMaterial); scene.add(line); LineDashedMaterial虚线 我们也可以创建虚线,这里我们来点新花样,就是实现曲线。

曲线也和直线一样,在Windows系统线的粗度只能为1。

要创建曲线,我们需要使用到THREE.CatmullRomCurve3来生成一个curve对象,这是一个曲线对象,可以从对象获取生成的曲线的点的集合,在这里科普一下,曲线也是由无数段的直线组成的,段数分的越清晰,曲线过渡越顺滑。

varpointsArr=[ newTHREE.Vector3(-10,0,-5), newTHREE.Vector3(-5,15,5), newTHREE.Vector3(20,15,-5), newTHREE.Vector3(10,0,5) ]; //指定一些用于生成曲线线的三维顶点 varcurve=newTHREE.CatmullRomCurve3(pointsArr); varpoints=curve.getPoints(50);//使用getPoints获取当前曲线分成50段后的所有顶点 varcurveGeometry=newTHREE.BufferGeometry().setFromPoints(points);//使用顶点生成几何体 varcurveMaterial=newTHREE.LineDashedMaterial({color:0xff0000});//创建一条红色的线材质 //使用THREE.Line创建线 curveLine=newTHREE.Line(curveGeometry,curveMaterial); curveLine.computeLineDistances();//需要重新计算位置才能显示出虚线 scene.add(curveLine); 添加光 由于MeshBasicMaterial不会受光的影响,即使有光也不会影响它的效果,前面我们也没有添加光。

但是后面介绍的材质会受到光源的影响,在介绍之前,我们需要添加一个光源,来影响材质的显示效果。

//创建灯光 functioninitLight(){ varlight=newTHREE.DirectionalLight(0xffffff);//添加了一个白色的平行光 light.position.set(20,50,50);//设置光的方向 scene.add(light);//添加到场景 //添加一个全局环境光 scene.add(newTHREE.AmbientLight(0x222222)); } 上面我们添加了一个模拟太阳光线的平行光和一个对每一个物理都造成影响的环境光,具体的内容将会在下一篇讲解。

下面介绍的材质都是对光有反应的,而且如果场景内没有光,模型将无法显示。

MeshLambertMaterial兰伯特材质 这种材质会对光有反应,但是不会出现高光,可以模拟一些粗糙的材质的物体,比如木头或者石头。

实现案例,如下: geometry=newTHREE.BoxGeometry(2,2,2);//创建几何体 material=newTHREE.MeshLambertMaterial({color:0x00ffff});//创建材质 mesh=newTHREE.Mesh(geometry,material);//创建网格 scene.add(mesh);//将网格添加到场景 MeshPhongMaterial高光材质 这种材质具有高光效果,可以模拟一些光滑的物体的材质效果,比如油漆面,瓷瓦等光滑物体。

实现案例如下: geometry=newTHREE.BoxGeometry(2,2,2);//创建几何体 material=newTHREE.MeshPhongMaterial({color:0x00ffff});//创建材质 mesh=newTHREE.Mesh(geometry,material);//创建网格 scene.add(mesh);//将网格添加到场景 MeshStandardMaterial基于物理的渲染(PBR)材质 这种材质基于物理的渲染(PBR)材质,生成的材质效果更佳,但是相应也占用更多的计算量。

这种材质我们可以定义它的粗糙度来确定反光效果,经常用于模拟金属的质感,使金属质感更加真实。

实现案例如下: geometry=newTHREE.BoxGeometry(2,2,2);//创建几何体 material=newTHREE.MeshPhongMaterial({color:0x00ffff});//创建材质 material.metalness=0.1;//设置的值的范围为0-1,值越小,材质越光滑,高光越明显 material.metalnessMap=0.1;//设置的值的范围为0-1,值越大,越有生锈金属的质感,值越小反光越清晰 mesh=newTHREE.Mesh(geometry,material);//创建网格 scene.add(mesh);//将网格添加到场景 案例代码 最后,我将本文的内容整理成了一个案例放到了Github上: Github代码地址 案例效果查看地址:Github地址 上一篇 下一篇 回到目录 收藏



請為這篇文章評分?