本章节主要目的是认识Threejs的各类材质Material,所谓材质,简单地说就是字面意思,就像生活中你聊天一样,说这是塑料材质,这是金属材质,这是纤维材质...,深入一点说,就是包含光照算法的着色器GLSL ES代码。如果你想给一个模型设置特定的颜色,如果你想给一个模型设置一定透明度,如果你想实现一个金属效果,你想设置模型纹理贴图,那么Threejs的提供各种材质类就是你的选择。
本章节除了讲解Threejs材质知识以外,还会提一些javascript编程概念,比如类、基类、子类、属性、方法等,当然了,对于熟练使用javascript语言的程序员来说,提到这些概念完全是多余的,不过考虑到部分初学者可能也是刚刚接触javascript,就简单提下。之所以强调这些内容,目的不出为了讲解这些javascript语法,而是强调Threejs所谓材质、几何体、相机等对象都是通过Threejs封装的类或者说构造函数实例化创建,如果你了解Threejs类与类之间的继承关系,将有助于你系统学习Threejs。
前面案例中几何体对应网格模型材质只是设置了一个颜色,实际渲染的时候往往会设置其他的参数,比如实现玻璃效果要设置材质透明度,一些光亮的表面要添加高光效果。
半透明效果
更改场景中的球体材质对象构造函数THREE.MeshLambertMaterial()的参数,添加opacity和transparent属性,opacity的值是0~1之间,transparent表示是否开启透明度效果, 默认是false表示透明度设置不起作用,值设置为true,网格模型就会呈现透明的效果,使用下面的代码替换原来的球体网格模型的材质, 刷新浏览器,通过鼠标旋转操作场景,可以看到半透明的球体和立方体颜色叠加融合的效果。
- var sphereMaterial=new THREE.MeshLambertMaterial({
- color:0xff0000,
- opacity:0.7,
- transparent:true
- });//材质对象
材质对象的一些属性可以在构造函数参数中设置,也可以通过以下代码设置材质对象的属性:
- material.opacity = 0.5;
- material.transparent = true;
添加高光效果
直接使用下面的代码替换上面的透明度材质即可,刷新浏览器可以看到球体表面的高光效果。
- var sphereMaterial=new THREE.MeshPhongMaterial({
- color:0x0000ff,
- specular:0x4488ee,
- shininess:12
- });//材质对象
处在光照条件下的物体表面会发生光的反射现象,不同的表面粗糙度不同,宏观上来看对光的综合反射效果,可以使用两个反射模型来概括,一个是漫反射,一个是镜面反射, 使用渲染软件或绘画的时候都会提到一个高光的概念,其实说的就是物理光学中镜面反射产生的局部高亮效果。实际生活中的物体都是镜面反射和漫反射同时存在,只是哪个占得比例大而已, 比如树皮的表面更多以漫反射为主基本没有体现出镜面反射,比如一辆轿车的外表面在阳光下你会看到局部高亮的效果,这很简单汽车表面经过抛光等表面处理粗糙度非常低, 镜面反射效果明显,对于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 | 基础网格材质,不受光照影响的材质 |
MeshLambertMaterial | Lambert网格材质,与光照有反应,漫反射 |
MeshPhongMaterial | 高光Phong材质,与光照有反应 |
MeshStandardMaterial | PBR物理材质,相比较高光Phong材质可以更好的模拟金属、玻璃等效果 |
下面这个例子将原有的旋转正方体的不透明度修改为70%,并且将原有的粉红色球星修改为网格状,将黄色圆柱体的材质赋上高光效果。
为了方便开发Threejs提供了一系列的材质,所有材质就是对WebGL着色器代码的封装,如果你不了解WebGL,会通过查阅Threejs文档使用相关材质类即可。
点材质:PointsMaterial
点材质比较简单,只有PointsMaterial,通常使用点模型的时候会使用点材质PointsMaterial。
点材质PointsMaterial的.size属性可以每个顶点渲染的方形区域尺寸像素大小。
- var geometry = new THREE.SphereGeometry(100, 25, 25); //创建一个球体几何对象
- // 创建一个点材质对象
- var material = new THREE.PointsMaterial({
- color: 0x0000ff, //颜色
- size: 3, //点渲染尺寸
- });
- //点模型对象 参数:几何体 点材质
- var point = new THREE.Points(geometry, material);
- scene.add(point); //网格模型添加到场景中
线材质:LineBasicMaterial和LineDashedMaterial
线材质有基础线材质LineBasicMaterial和虚线材质LineDashedMaterial两个,通常使用使用Line等线模型才会用到线材质。
基础线材质LineBasicMaterial。
- var geometry = new THREE.SphereGeometry(100, 25, 25);//球体
- // 直线基础材质对象
- var material = new THREE.LineBasicMaterial({
- color: 0x0000ff
- });
- var line = new THREE.Line(geometry, material); //线模型对象
- scene.add(line); //点模型添加到场景中
虚线材质LineDashedMaterial。
- // 虚线材质对象:产生虚线效果
- var material = new THREE.LineDashedMaterial({
- color: 0x0000ff,
- dashSize: 10,//显示线段的大小。默认为3。
- gapSize: 5,//间隙的大小。默认为1
- });
- var line = new THREE.Line(geometry, material); //线模型对象
- // computeLineDistances方法 计算LineDashedMaterial所需的距离数组
- line.computeLineDistances();
网格材质:MeshBasicMaterial、MeshLambertMaterial和MeshPhongMaterial
Threejs提供的网格类材质比较多,网格材质涉及的材质种类和材质属性也比较多,一节课也无法讲解完,本节课先有一个感性的认知。
网格材质顾名思义,网格类模型才会使用的材质对象。
基础网格材质对象MeshBasicMaterial,不受带有方向光源影响,没有棱角感,跟点材料类似,接下来的案例中将不予以展示。
- var material = new THREE.MeshBasicMaterial({
- color: 0x0000ff,
- })
MeshLambertMaterial材质可以实现网格Mesh表面与光源的漫反射光照计算,有了光照计算,物体表面分界的位置才会产生棱角感。
- var material = new THREE.MeshLambertMaterial({
- color: 0x00ff00,
- });
高光网格材质MeshPhongMaterial除了和MeshLambertMaterial一样可以实现光源和网格表面的漫反射光照计算,还可以产生高光效果(镜面反射)。
- var material = new THREE.MeshPhongMaterial({
- color: 0xff0000,
- specular:0x444444,//高光部分的颜色
- shininess:20,//高光部分的亮度,默认30
- });
下面的例子,创建了4种材质的几何体,它们分别是点材质的红色球体、蓝色线材质的立方体、网格材质普光圆柱、网格材质高光圆柱(2个圆柱体除了普光和高光的区别外,没有任何不同)。
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="UTF-8">
- <title>第一个three.js文件_WebGL三维场景</title>
- <style>
- body {
- margin: 0;
- overflow: hidden;
- /* 隐藏body窗口区域滚动条 */
- }
- </style>
- <!--引入three.js三维引擎-->
- <script src="https://cdn.bootcdn.net/ajax/libs/three.js/r128/three.js"></script>
- <script src="https://www.w3xue.com/example/threejs/solarsystem/files/OrbitControls.js"></script>
- </head>
- <body>
- <script>
- /**
- * 创建场景对象Scene
- */
- var scene = new THREE.Scene();
- /**
- * 创建网格模型
- */
- // var geometry = new THREE.SphereGeometry(60, 40, 40); //创建一个球体几何对象
- // var geometry = new THREE.BoxGeometry(100, 100, 100); //创建一个立方体几何对象
- //点材料球形
- var geometry1 = new THREE.SphereGeometry(70,25, 25);
- var material1 = new THREE.PointsMaterial({ //点材料
- color:0xff0000, //颜色
- size:1, //点渲染尺寸
- });//材质对象
- var mesh1 = new THREE.Mesh(geometry1, material1); //网格模型对象Mesh
- scene.add(mesh1); //网格模型添加到场景中
- //线材料立方体
- var geometry2 = new THREE.BoxGeometry(100, 100, 100); //创建一个立方体几何对象
- var material2 = new THREE.LineDashedMaterial({
- color: 0x0000ff,
- dashSize: 10,//显示线段的大小。默认为3。
- gapSize: 5,//间隙的大小。默认为1
- });
- var line = new THREE.Line(geometry2, material2); //线模型对象
- line.computeLineDistances(); //该方法计算LineDashedMaterial所需的距离数组
- line.position.set(170,0,0);//设置mesh3模型对象的xyz坐标为120,0,0
- scene.add(line); //网格模型添加到场景中
- //圆柱普光材质
- var geometry3 = new THREE.CylinderGeometry(50, 50, 100, 25);
- var material3 = new THREE.MeshLambertMaterial({
- color:0xffff00,
- });//材质对象
- var mesh3 = new THREE.Mesh(geometry3, material3); //网格模型对象Mesh
- // mesh3.translateX(120); //球体网格模型沿Y轴正方向平移120
- mesh3.position.set(0,130,0);//设置mesh3模型对象的xyz坐标为120,0,0
- scene.add(mesh3);
- //圆柱高光材质
- var geometry4 = new THREE.CylinderGeometry(50, 50, 100, 25);
- var material4 = new THREE.MeshPhongMaterial({
- color:0xffff00,
- specular:0x4488ee, //高光部分的颜色
- shininess:12 //高光部分的亮度,默认30
- });//材质对象
- var mesh4 = new THREE.Mesh(geometry4, material4); //网格模型对象Mesh
- // mesh3.translateX(120); //球体网格模型沿Y轴正方向平移120
- mesh4.position.set(0,-130,0);//设置mesh3模型对象的xyz坐标为120,0,0
- scene.add(mesh4);
- /**
- * 光源设置
- */
- //点光源
- var point = new THREE.PointLight(0xffffff);
- point.position.set(400, 200, 300); //点光源位置
- scene.add(point); //点光源添加到场景中
- //环境光
- var ambient = new THREE.AmbientLight(0x444444);
- scene.add(ambient);
- //添加坐标系
- var axisHelper = new THREE.AxisHelper(350);
- scene.add(axisHelper);
- /**
- * 相机设置
- */
- var width = window.innerWidth; //窗口宽度
- var height = window.innerHeight; //窗口高度
- var k = width / height; //窗口宽高比
- var s = 200; //三维场景显示范围控制系数,系数越大,显示的范围越大
- //创建相机对象
- var camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 1000);
- camera.position.set(200, 300, 200); //设置相机位置
- camera.lookAt(scene.position); //设置相机方向(指向的场景对象)
- /**
- * 创建渲染器对象
- */
- var renderer = new THREE.WebGLRenderer();
- renderer.setSize(width, height);//设置渲染区域尺寸
- renderer.setClearColor(0xb9d3ff, 1); //设置背景颜色
- document.body.appendChild(renderer.domElement); //body元素中插入canvas对象
- //执行渲染操作 指定场景、相机作为参数
- renderer.render(scene, camera);
- let T0 = new Date();//上次时间
- function render() {
- let T1 = new Date();//本次时间
- let t = T1-T0;//时间差
- T0 = T1;//把本次时间赋值给上次时间
- requestAnimationFrame(render);
- renderer.render(scene,camera);//执行渲染操作
- mesh1.rotateY(0.001*t);//旋转角速度0.001弧度每毫秒
- }
- render();
- var controls = new THREE.OrbitControls(camera,renderer.domElement);//创建控件对象
- </script>
- </body>
- </html>
材质和模型对象对应关系
使用材质的时候,要注意材质和模型的对应关系,通过前面课程案例学习,目前为止你至少应该了解到了网格模型Mesh、点模型Points、线模型Line,随着课程的学习其它的模型对象也会接触到,这里先有个印象就可以。
材质共有属性、私有属性
如果你的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的属性值
- var material = new THREE.MeshPhongMaterial({
- color: 0x220000,
- // transparent设置为true,开启透明,否则opacity不起作用
- transparent: true,
- // 设置材质透明度
- opacity: 0.4,
- });
通过访问材质对象属性形式设置transparent和.opacity的属性值:
- // transparent设置为true,开启透明,否则opacity不起作用
- material.transparent = true;
- // 设置材质透明度
- material.opacity = 0.4;
下面的例子将上一个例子中的普光材质圆柱和球体设置为半透明:
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="UTF-8">
- <title>第一个three.js文件_WebGL三维场景</title>
- <style>
- body {
- margin: 0;
- overflow: hidden;
- /* 隐藏body窗口区域滚动条 */
- }
- </style>
- <!--引入three.js三维引擎-->
- <script src="https://cdn.bootcdn.net/ajax/libs/three.js/r128/three.js"></script>
- <script src="https://www.w3xue.com/example/threejs/solarsystem/files/OrbitControls.js"></script>
- </head>
- <body>
- <script>
- /**
- * 创建场景对象Scene
- */
- var scene = new THREE.Scene();
- /**
- * 创建网格模型
- */
- // var geometry = new THREE.SphereGeometry(60, 40, 40); //创建一个球体几何对象
- // var geometry = new THREE.BoxGeometry(100, 100, 100); //创建一个立方体几何对象
- //点材料球形
- var geometry1 = new THREE.SphereGeometry(70,25, 25);
- var material1 = new THREE.PointsMaterial({ //点材料
- color:0xff0000, //颜色
- size:1, //点渲染尺寸
- transparent: true, // transparent设置为true,开启透明,否则opacity不起作用
- opacity: 0.4,// 设置材质透明度
- });//材质对象
- var mesh1 = new THREE.Mesh(geometry1, material1); //网格模型对象Mesh
- scene.add(mesh1); //网格模型添加到场景中
- //线材料立方体
- var geometry2 = new THREE.BoxGeometry(100, 100, 100); //创建一个立方体几何对象
- var material2 = new THREE.LineDashedMaterial({
- color: 0x0000ff,
- dashSize: 10,//显示线段的大小。默认为3。
- gapSize: 5,//间隙的大小。默认为1
- });
- var line = new THREE.Line(geometry2, material2); //线模型对象
- line.computeLineDistances(); //该方法计算LineDashedMaterial所需的距离数组
- line.position.set(170,0,0);//设置mesh3模型对象的xyz坐标为120,0,0
- scene.add(line); //网格模型添加到场景中
- //圆柱普光材质
- var geometry3 = new THREE.CylinderGeometry(50, 50, 100, 25);
- var material3 = new THREE.MeshLambertMaterial({
- color:0xffff00,
- });//材质对象
- material3.transparent = true; // transparent设置为true,开启透明,否则opacity不起作用
- material3.opacity = 0.6; // 设置材质透明度
- var mesh3 = new THREE.Mesh(geometry3, material3); //网格模型对象Mesh
- // mesh3.translateX(120); //球体网格模型沿Y轴正方向平移120
- mesh3.position.set(0,130,0);//设置mesh3模型对象的xyz坐标为120,0,0
- scene.add(mesh3);
- //圆柱高光材质
- var geometry4 = new THREE.CylinderGeometry(50, 50, 100, 25);
- var material4 = new THREE.MeshPhongMaterial({
- color:0xffff00,
- specular:0x4488ee, //高光部分的颜色
- shininess:12 //高光部分的亮度,默认30
- });//材质对象
- var mesh4 = new THREE.Mesh(geometry4, material4); //网格模型对象Mesh
- // mesh3.translateX(120); //球体网格模型沿Y轴正方向平移120
- mesh4.position.set(0,-130,0);//设置mesh3模型对象的xyz坐标为120,0,0
- scene.add(mesh4);
- /**
- * 光源设置
- */
- //点光源
- var point = new THREE.PointLight(0xffffff);
- point.position.set(400, 200, 300); //点光源位置
- scene.add(point); //点光源添加到场景中
- //环境光
- var ambient = new THREE.AmbientLight(0x444444);
- scene.add(ambient);
- //添加坐标系
- var axisHelper = new THREE.AxisHelper(350);
- scene.add(axisHelper);
- /**
- * 相机设置
- */
- var width = window.innerWidth; //窗口宽度
- var height = window.innerHeight; //窗口高度
- var k = width / height; //窗口宽高比
- var s = 200; //三维场景显示范围控制系数,系数越大,显示的范围越大
- //创建相机对象
- var camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 1000);
- camera.position.set(200, 300, 200); //设置相机位置
- camera.lookAt(scene.position); //设置相机方向(指向的场景对象)
- /**
- * 创建渲染器对象
- */
- var renderer = new THREE.WebGLRenderer();
- renderer.setSize(width, height);//设置渲染区域尺寸
- renderer.setClearColor(0xb9d3ff, 1); //设置背景颜色
- document.body.appendChild(renderer.domElement); //body元素中插入canvas对象
- //执行渲染操作 指定场景、相机作为参数
- renderer.render(scene, camera);
- let T0 = new Date();//上次时间
- function render() {
- let T1 = new Date();//本次时间
- let t = T1-T0;//时间差
- T0 = T1;//把本次时间赋值给上次时间
- requestAnimationFrame(render);
- renderer.render(scene,camera);//执行渲染操作
- mesh1.rotateY(0.001*t);//旋转角速度0.001弧度每毫秒
- }
- render();
- var controls = new THREE.OrbitControls(camera,renderer.domElement);//创建控件对象
- </script>
- </body>
- </html>
转载本站内容时,请务必注明来自W3xue,违者必究。