课程表

three.js课程

工具箱
速查手册

Three 材质效果

当前位置:免费教程 » JS/JS库/框架 » three.js

本章节主要目的是认识Threejs的各类材质Material,所谓材质,简单地说就是字面意思,就像生活中你聊天一样,说这是塑料材质,这是金属材质,这是纤维材质...,深入一点说,就是包含光照算法的着色器GLSL ES代码。如果你想给一个模型设置特定的颜色,如果你想给一个模型设置一定透明度,如果你想实现一个金属效果,你想设置模型纹理贴图,那么Threejs的提供各种材质类就是你的选择。

本章节除了讲解Threejs材质知识以外,还会提一些javascript编程概念,比如类、基类、子类、属性、方法等,当然了,对于熟练使用javascript语言的程序员来说,提到这些概念完全是多余的,不过考虑到部分初学者可能也是刚刚接触javascript,就简单提下。之所以强调这些内容,目的不出为了讲解这些javascript语法,而是强调Threejs所谓材质、几何体、相机等对象都是通过Threejs封装的类或者说构造函数实例化创建,如果你了解Threejs类与类之间的继承关系,将有助于你系统学习Threejs。

前面案例中几何体对应网格模型材质只是设置了一个颜色,实际渲染的时候往往会设置其他的参数,比如实现玻璃效果要设置材质透明度,一些光亮的表面要添加高光效果。

半透明效果

更改场景中的球体材质对象构造函数THREE.MeshLambertMaterial()的参数,添加opacity和transparent属性,opacity的值是0~1之间,transparent表示是否开启透明度效果, 默认是false表示透明度设置不起作用,值设置为true,网格模型就会呈现透明的效果,使用下面的代码替换原来的球体网格模型的材质, 刷新浏览器,通过鼠标旋转操作场景,可以看到半透明的球体和立方体颜色叠加融合的效果。

  1. var sphereMaterial=new THREE.MeshLambertMaterial({
  2.     color:0xff0000,
  3.     opacity:0.7,
  4.     transparent:true
  5. });//材质对象

材质对象的一些属性可以在构造函数参数中设置,也可以通过以下代码设置材质对象的属性:

  1. material.opacity = 0.5;
  2. material.transparent = true;

添加高光效果

直接使用下面的代码替换上面的透明度材质即可,刷新浏览器可以看到球体表面的高光效果。

  1. var sphereMaterial=new THREE.MeshPhongMaterial({
  2.     color:0x0000ff,
  3.     specular:0x4488ee,
  4.     shininess:12
  5. });//材质对象

处在光照条件下的物体表面会发生光的反射现象,不同的表面粗糙度不同,宏观上来看对光的综合反射效果,可以使用两个反射模型来概括,一个是漫反射,一个是镜面反射, 使用渲染软件或绘画的时候都会提到一个高光的概念,其实说的就是物理光学中镜面反射产生的局部高亮效果。实际生活中的物体都是镜面反射和漫反射同时存在,只是哪个占得比例大而已, 比如树皮的表面更多以漫反射为主基本没有体现出镜面反射,比如一辆轿车的外表面在阳光下你会看到局部高亮的效果,这很简单汽车表面经过抛光等表面处理粗糙度非常低, 镜面反射效果明显,对于three.js而言漫反射、镜面反射分别对应两个构造函数MeshLambertMaterial()、MeshPhongMaterial(),通过three.js引擎你可以很容易实现这些光照模型,不需要自己再使用原生WebGL实现,更多关于光照模型的知识可以参考文章《WebGL_course光照渲染立方体》或计算机图形学的相关书籍。

前面案例都是通过构造函数MeshLambertMaterial()实现漫反射进行渲染,高光效果要通过构造函数MeshPhongMaterial()模拟镜面反射实现,属性specular表示球体网格模型的高光颜色,改颜色的RGB值会与光照颜色的RGB分量相乘, shininess属性可以理解为光照强度的系数,初学的的时候这些细节如果不清楚,不用深究,每个人的基础不同,理解问题的深度和角度不同,比如高光,学习过计算机图形学的会联想到镜面反射模型和物理光学, 从事过与美术相关工作,都知道需要的时候会给一个物体添加高光,视觉效果更加高亮,因此对于构造函数MeshPhongMaterial()的参数设置不太清除也没关系,对于零基础的读者本节课的要求就是有个简单印象就可以, 站在黑箱外面理解黑箱;对于有WebGL基础的,可以思考three.js引擎构造函数实际封装了哪些WebGL API和图形学算法,站在黑箱里面理解黑箱,如果是你你会怎么封装开发一个三维引擎,这样你可以从底层理解上层的问题, 保证学习的连贯性;如果你使用过其它的三维建模渲染软件,那就使用three.js这个黑箱类比一个你熟悉的黑箱,通过类比降低学习难度,比如你可以打开3dmax软件设置一个材质的高光,体验下视觉效果。

材质类型

threejs提供了很多常用的材质效果,这些效果本质上都是对WebGL着色器的封装,对于开发者来说直接使用就可以,这里不再做过多介绍,大家现有一个印象即可。

材质类型功 能
MeshBasicMaterial基础网格材质,不受光照影响的材质
MeshLambertMaterialLambert网格材质,与光照有反应,漫反射
MeshPhongMaterial高光Phong材质,与光照有反应
MeshStandardMaterialPBR物理材质,相比较高光Phong材质可以更好的模拟金属、玻璃等效果

下面这个例子将原有的旋转正方体的不透明度修改为70%,并且将原有的粉红色球星修改为网格状,将黄色圆柱体的材质赋上高光效果。

在线运行实例

为了方便开发Threejs提供了一系列的材质,所有材质就是对WebGL着色器代码的封装,如果你不了解WebGL,会通过查阅Threejs文档使用相关材质类即可。

1.jpg

点材质:PointsMaterial

点材质比较简单,只有PointsMaterial,通常使用点模型的时候会使用点材质PointsMaterial。

点材质PointsMaterial的.size属性可以每个顶点渲染的方形区域尺寸像素大小。

  1. var geometry = new THREE.SphereGeometry(100, 25, 25); //创建一个球体几何对象
  2. // 创建一个点材质对象
  3. var material = new THREE.PointsMaterial({
  4.   color: 0x0000ff, //颜色
  5.   size: 3, //点渲染尺寸
  6. });
  7. //点模型对象  参数:几何体  点材质
  8. var point = new THREE.Points(geometry, material);
  9. scene.add(point); //网格模型添加到场景中

线材质:LineBasicMaterial和LineDashedMaterial

线材质有基础线材质LineBasicMaterial和虚线材质LineDashedMaterial两个,通常使用使用Line等线模型才会用到线材质。

基础线材质LineBasicMaterial。

  1. var geometry = new THREE.SphereGeometry(100, 25, 25);//球体
  2. // 直线基础材质对象
  3. var material = new THREE.LineBasicMaterial({
  4.   color: 0x0000ff
  5. });
  6. var line = new THREE.Line(geometry, material); //线模型对象
  7. scene.add(line); //点模型添加到场景中

虚线材质LineDashedMaterial。

  1. // 虚线材质对象:产生虚线效果
  2. var material = new THREE.LineDashedMaterial({
  3.   color: 0x0000ff,
  4.   dashSize: 10,//显示线段的大小。默认为3。
  5.   gapSize: 5,//间隙的大小。默认为1
  6. });
  7. var line = new THREE.Line(geometry, material); //线模型对象
  8. //  computeLineDistances方法  计算LineDashedMaterial所需的距离数组
  9. line.computeLineDistances();

网格材质:MeshBasicMaterial、MeshLambertMaterial和MeshPhongMaterial

Threejs提供的网格类材质比较多,网格材质涉及的材质种类和材质属性也比较多,一节课也无法讲解完,本节课先有一个感性的认知。

网格材质顾名思义,网格类模型才会使用的材质对象。

基础网格材质对象MeshBasicMaterial,不受带有方向光源影响,没有棱角感,跟点材料类似,接下来的案例中将不予以展示。

  1. var material = new THREE.MeshBasicMaterial({
  2.   color: 0x0000ff,
  3. })

MeshLambertMaterial材质可以实现网格Mesh表面与光源的漫反射光照计算,有了光照计算,物体表面分界的位置才会产生棱角感。

  1. var material = new THREE.MeshLambertMaterial({
  2.   color: 0x00ff00,
  3. });

高光网格材质MeshPhongMaterial除了和MeshLambertMaterial一样可以实现光源和网格表面的漫反射光照计算,还可以产生高光效果(镜面反射)。

  1. var material = new THREE.MeshPhongMaterial({
  2.   color: 0xff0000,
  3.   specular:0x444444,//高光部分的颜色
  4.   shininess:20,//高光部分的亮度,默认30
  5. });

下面的例子,创建了4种材质的几何体,它们分别是点材质的红色球体、蓝色线材质的立方体、网格材质普光圆柱、网格材质高光圆柱(2个圆柱体除了普光和高光的区别外,没有任何不同)。

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4.   <meta charset="UTF-8">
  5.   <title>第一个three.js文件_WebGL三维场景</title>
  6.   <style>
  7.     body {
  8.       margin: 0;
  9.       overflow: hidden;
  10.       /* 隐藏body窗口区域滚动条 */
  11.     }
  12.   </style>
  13.   <!--引入three.js三维引擎-->
  14.   <script src="https://cdn.bootcdn.net/ajax/libs/three.js/r128/three.js"></script>
  15.   <script src="https://www.w3xue.com/example/threejs/solarsystem/files/OrbitControls.js"></script>
  16. </head>
  17.  
  18. <body>
  19.   <script>
  20.     /**
  21.      * 创建场景对象Scene
  22.      */
  23.     var scene = new THREE.Scene();
  24.     /**
  25.      * 创建网格模型
  26.      */
  27.     // var geometry = new THREE.SphereGeometry(60, 40, 40); //创建一个球体几何对象
  28. // var geometry = new THREE.BoxGeometry(100, 100, 100); //创建一个立方体几何对象
  29.  
  30. //点材料球形
  31. var geometry1 = new THREE.SphereGeometry(70,25, 25);
  32. var material1 = new THREE.PointsMaterial({ //点材料
  33.      color:0xff0000,  //颜色
  34. size:1, //点渲染尺寸
  35. });//材质对象
  36. var mesh1 = new THREE.Mesh(geometry1, material1); //网格模型对象Mesh
  37. scene.add(mesh1); //网格模型添加到场景中
  38.   
  39. //线材料立方体
  40. var geometry2 = new THREE.BoxGeometry(100, 100, 100); //创建一个立方体几何对象
  41. var material2 = new THREE.LineDashedMaterial({
  42.    color: 0x0000ff,
  43.    dashSize: 10,//显示线段的大小。默认为3。
  44.    gapSize: 5,//间隙的大小。默认为1
  45. });
  46. var line = new THREE.Line(geometry2, material2); //线模型对象
  47. line.computeLineDistances(); //该方法计算LineDashedMaterial所需的距离数组
  48. line.position.set(170,0,0);//设置mesh3模型对象的xyz坐标为120,0,0
  49. scene.add(line); //网格模型添加到场景中
  50.   
  51. //圆柱普光材质
  52. var geometry3 = new THREE.CylinderGeometry(50, 50, 100, 25);
  53. var material3 = new THREE.MeshLambertMaterial({
  54.             color:0xffff00,
  55.         });//材质对象
  56. var mesh3 = new THREE.Mesh(geometry3, material3); //网格模型对象Mesh
  57. // mesh3.translateX(120); //球体网格模型沿Y轴正方向平移120
  58. mesh3.position.set(0,130,0);//设置mesh3模型对象的xyz坐标为120,0,0
  59. scene.add(mesh3);
  60.   
  61. //圆柱高光材质
  62. var geometry4 = new THREE.CylinderGeometry(50, 50, 100, 25);
  63. var material4 = new THREE.MeshPhongMaterial({
  64.             color:0xffff00,
  65.             specular:0x4488ee, //高光部分的颜色
  66.             shininess:12 //高光部分的亮度,默认30
  67.         });//材质对象
  68. var mesh4 = new THREE.Mesh(geometry4, material4); //网格模型对象Mesh
  69. // mesh3.translateX(120); //球体网格模型沿Y轴正方向平移120
  70. mesh4.position.set(0,-130,0);//设置mesh3模型对象的xyz坐标为120,0,0
  71. scene.add(mesh4);
  72.   
  73.   
  74.     /**
  75.      * 光源设置
  76.      */
  77.     //点光源
  78.     var point = new THREE.PointLight(0xffffff);
  79.     point.position.set(400, 200, 300); //点光源位置
  80.     scene.add(point); //点光源添加到场景中
  81.     //环境光
  82.     var ambient = new THREE.AmbientLight(0x444444);
  83.     scene.add(ambient);
  84.   
  85. //添加坐标系
  86. var axisHelper = new THREE.AxisHelper(350);
  87. scene.add(axisHelper);
  88.  
  89.   
  90.     /**
  91.      * 相机设置
  92.      */
  93.     var width = window.innerWidth; //窗口宽度
  94.     var height = window.innerHeight; //窗口高度
  95.     var k = width / height; //窗口宽高比
  96.     var s = 200; //三维场景显示范围控制系数,系数越大,显示的范围越大
  97.     //创建相机对象
  98.     var camera = new THREE.OrthographicCamera(-* k, s * k, s, -s, 1, 1000);
  99.     camera.position.set(200, 300, 200); //设置相机位置
  100.     camera.lookAt(scene.position); //设置相机方向(指向的场景对象)
  101.     /**
  102.      * 创建渲染器对象
  103.      */
  104.     var renderer = new THREE.WebGLRenderer();
  105.     renderer.setSize(width, height);//设置渲染区域尺寸
  106.     renderer.setClearColor(0xb9d3ff, 1); //设置背景颜色
  107.     document.body.appendChild(renderer.domElement); //body元素中插入canvas对象
  108.     //执行渲染操作   指定场景、相机作为参数
  109.     renderer.render(scene, camera);
  110.  
  111. let T0 = new Date();//上次时间
  112. function render() {
  113.         let T1 = new Date();//本次时间
  114.         let t = T1-T0;//时间差
  115.         T0 = T1;//把本次时间赋值给上次时间
  116.         requestAnimationFrame(render);
  117.         renderer.render(scene,camera);//执行渲染操作
  118.         mesh1.rotateY(0.001*t);//旋转角速度0.001弧度每毫秒
  119.     }
  120. render();
  121.   
  122. var controls = new THREE.OrbitControls(camera,renderer.domElement);//创建控件对象
  123.  
  124.   </script>
  125. </body>
  126. </html>

在线运行实例

材质和模型对象对应关系

使用材质的时候,要注意材质和模型的对应关系,通过前面课程案例学习,目前为止你至少应该了解到了网格模型Mesh、点模型Points、线模型Line,随着课程的学习其它的模型对象也会接触到,这里先有个印象就可以。

1.jpg

材质共有属性、私有属性

如果你的javascript语言基础还可以,应该明白类、基类、子类、父类等概念。如果你有这些类的概念,那么在学习Threejs的过程中,如何查找Threejs文档将会比较顺利。

点材质PointsMaterial、基础线材质LineBasicMaterial、基础网格材质MeshBasicMaterial、高光网格材质MeshPhongMaterial等材质都是父类Material的子类。

各种各样的材质子类都有自己的特定属性,比如点材质特有的尺寸属性.size、高光网格材质特有的高光颜色属性.specular等等这些属性可以成为子类材质的私有属性。

所有子类的材质都会从父类材质Material继承透明度opacity、面side等属性,这些来自父类的属性都是子类共有的属性。

.side属性

在Three.js开发过程中你可能会遇到下面的问题,比如three.js矩形平面planegeometry的网格模型插入场景看不到,一个球体或立方体网格模型如何背面显示贴图,正面不显示...,对于这些问题可以通过Three.js材质对象.side属性来设置。

材质.side属性的具体介绍可以查看Threejs文档中所有材质对象的基类Material。

.side属性的属性值定义面的渲染方式前面后面 或 双面. 属性的默认值是THREE.FrontSide,表示前面. 也可以设置为后面THREE.BackSide 或 双面THREE.DoubleSide。

材质透明度.opacity

通过材质的透明度属性.opacity可以设置材质的透明程度,.opacity属性值的范围是0.0~1.0,0.0值表示完全透明, 1.0表示完全不透明,.opacity默认值1.0。

当设置.opacity属性值的时候,需要设置材质属性transparent值为true,如果材质的transparent属性没设置为true, 材质会保持完全不透明状态。

在构造函数参数中设置transparent和.opacity的属性值

  1. var material = new THREE.MeshPhongMaterial({
  2.   color: 0x220000,
  3.   // transparent设置为true,开启透明,否则opacity不起作用
  4.   transparent: true,
  5.   // 设置材质透明度
  6.   opacity: 0.4,
  7. });

通过访问材质对象属性形式设置transparent和.opacity的属性值:

  1. // transparent设置为true,开启透明,否则opacity不起作用
  2. material.transparent = true;
  3. // 设置材质透明度
  4. material.opacity = 0.4;

下面的例子将上一个例子中的普光材质圆柱和球体设置为半透明:

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4.   <meta charset="UTF-8">
  5.   <title>第一个three.js文件_WebGL三维场景</title>
  6.   <style>
  7.     body {
  8.       margin: 0;
  9.       overflow: hidden;
  10.       /* 隐藏body窗口区域滚动条 */
  11.     }
  12.   </style>
  13.   <!--引入three.js三维引擎-->
  14.   <script src="https://cdn.bootcdn.net/ajax/libs/three.js/r128/three.js"></script>
  15.   <script src="https://www.w3xue.com/example/threejs/solarsystem/files/OrbitControls.js"></script>
  16. </head>
  17.  
  18. <body>
  19.   <script>
  20.     /**
  21.      * 创建场景对象Scene
  22.      */
  23.     var scene = new THREE.Scene();
  24.     /**
  25.      * 创建网格模型
  26.      */
  27.     // var geometry = new THREE.SphereGeometry(60, 40, 40); //创建一个球体几何对象
  28. // var geometry = new THREE.BoxGeometry(100, 100, 100); //创建一个立方体几何对象
  29.  
  30. //点材料球形
  31. var geometry1 = new THREE.SphereGeometry(70,25, 25);
  32. var material1 = new THREE.PointsMaterial({ //点材料
  33.        color:0xff0000,  //颜色
  34.           size:1, //点渲染尺寸
  35.           transparent: true, // transparent设置为true,开启透明,否则opacity不起作用
  36.           opacity: 0.4,// 设置材质透明度
  37. });//材质对象
  38. var mesh1 = new THREE.Mesh(geometry1, material1); //网格模型对象Mesh
  39. scene.add(mesh1); //网格模型添加到场景中
  40.   
  41. //线材料立方体
  42. var geometry2 = new THREE.BoxGeometry(100, 100, 100); //创建一个立方体几何对象
  43. var material2 = new THREE.LineDashedMaterial({
  44.    color: 0x0000ff,
  45.    dashSize: 10,//显示线段的大小。默认为3。
  46.    gapSize: 5,//间隙的大小。默认为1
  47. });
  48. var line = new THREE.Line(geometry2, material2); //线模型对象
  49. line.computeLineDistances(); //该方法计算LineDashedMaterial所需的距离数组
  50. line.position.set(170,0,0);//设置mesh3模型对象的xyz坐标为120,0,0
  51. scene.add(line); //网格模型添加到场景中
  52.   
  53. //圆柱普光材质
  54. var geometry3 = new THREE.CylinderGeometry(50, 50, 100, 25);
  55. var material3 = new THREE.MeshLambertMaterial({
  56.             color:0xffff00,
  57.         });//材质对象
  58.         material3.transparent = true; // transparent设置为true,开启透明,否则opacity不起作用
  59. material3.opacity = 0.6;  // 设置材质透明度
  60. var mesh3 = new THREE.Mesh(geometry3, material3); //网格模型对象Mesh
  61. // mesh3.translateX(120); //球体网格模型沿Y轴正方向平移120
  62. mesh3.position.set(0,130,0);//设置mesh3模型对象的xyz坐标为120,0,0
  63. scene.add(mesh3);
  64.   
  65. //圆柱高光材质
  66. var geometry4 = new THREE.CylinderGeometry(50, 50, 100, 25);
  67. var material4 = new THREE.MeshPhongMaterial({
  68.             color:0xffff00,
  69.             specular:0x4488ee, //高光部分的颜色
  70.             shininess:12 //高光部分的亮度,默认30
  71.         });//材质对象
  72. var mesh4 = new THREE.Mesh(geometry4, material4); //网格模型对象Mesh
  73. // mesh3.translateX(120); //球体网格模型沿Y轴正方向平移120
  74. mesh4.position.set(0,-130,0);//设置mesh3模型对象的xyz坐标为120,0,0
  75. scene.add(mesh4);
  76.   
  77.   
  78.     /**
  79.      * 光源设置
  80.      */
  81.     //点光源
  82.     var point = new THREE.PointLight(0xffffff);
  83.     point.position.set(400, 200, 300); //点光源位置
  84.     scene.add(point); //点光源添加到场景中
  85.     //环境光
  86.     var ambient = new THREE.AmbientLight(0x444444);
  87.     scene.add(ambient);
  88.   
  89. //添加坐标系
  90. var axisHelper = new THREE.AxisHelper(350);
  91. scene.add(axisHelper);
  92.  
  93.   
  94.     /**
  95.      * 相机设置
  96.      */
  97.     var width = window.innerWidth; //窗口宽度
  98.     var height = window.innerHeight; //窗口高度
  99.     var k = width / height; //窗口宽高比
  100.     var s = 200; //三维场景显示范围控制系数,系数越大,显示的范围越大
  101.     //创建相机对象
  102.     var camera = new THREE.OrthographicCamera(-* k, s * k, s, -s, 1, 1000);
  103.     camera.position.set(200, 300, 200); //设置相机位置
  104.     camera.lookAt(scene.position); //设置相机方向(指向的场景对象)
  105.     /**
  106.      * 创建渲染器对象
  107.      */
  108.     var renderer = new THREE.WebGLRenderer();
  109.     renderer.setSize(width, height);//设置渲染区域尺寸
  110.     renderer.setClearColor(0xb9d3ff, 1); //设置背景颜色
  111.     document.body.appendChild(renderer.domElement); //body元素中插入canvas对象
  112.     //执行渲染操作   指定场景、相机作为参数
  113.     renderer.render(scene, camera);
  114.  
  115. let T0 = new Date();//上次时间
  116. function render() {
  117.         let T1 = new Date();//本次时间
  118.         let t = T1-T0;//时间差
  119.         T0 = T1;//把本次时间赋值给上次时间
  120.         requestAnimationFrame(render);
  121.         renderer.render(scene,camera);//执行渲染操作
  122.         mesh1.rotateY(0.001*t);//旋转角速度0.001弧度每毫秒
  123.     }
  124. render();
  125.   
  126. var controls = new THREE.OrbitControls(camera,renderer.domElement);//创建控件对象
  127.  
  128.   </script>
  129. </body>
  130. </html>

在线运行实例


转载本站内容时,请务必注明来自W3xue,违者必究。
 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号