课程表

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,网格模型就会呈现透明的效果,使用下面的代码替换原来的球体网格模型的材质, 刷新浏览器,通过鼠标旋转操作场景,可以看到半透明的球体和立方体颜色叠加融合的效果。

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基础网格材质,不受光照影响的材质
MeshLambertMaterialLambert网格材质,与光照有反应,漫反射
MeshPhongMaterial高光Phong材质,与光照有反应
MeshStandardMaterialPBR物理材质,相比较高光Phong材质可以更好的模拟金属、玻璃等效果

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

在线运行实例

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

1.jpg

点材质: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,随着课程的学习其它的模型对象也会接触到,这里先有个印象就可以。

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的属性值

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,违者必究。
 友情链接: NPS