Three.js - 材质的使用详解2(网格基础材质、深度材质、法向材质、面材质)
一、THREE.MeshBasicMaterial(网格基础材质)
MeshBasicMaterial 是一种非常简单的材质,这种材质不考虑场景中光照的影响。使用这种材质的网格会被渲染成简单的平面多边形,而且也可以显示几何体的线框。
1,属性介绍
除了那些共有属性之外,MeshBasicMaterial 还有如下特有的属性。名称 | 描述 |
color(颜色) | 设置材质的颜色。 |
wireframe(线框) | 设置这个属性可以将材质渲染成线框,非常适用于调试。 |
wireframeLinewidth(线框线宽) | 如果已经打开了 wireframe,这个属性定义线框中线的宽度。 |
wireframeLinecap(线框线段端点) | 这个属性定义了线框模式下顶点间线段的端点如何显示。可选的值包括:
|
wireframeLinejoin(线框线段连接点) | 这个属性定义了线段的连接点如何显示。可选的值有:
|
shading(着色) | 该属性定义如何着色。可选的值有:
|
vertexColors(顶点颜色) | 可以通过这个属性给每个顶点定义不同的颜色。默认值为:THREE.NoColors。如果将这个值设置为 THREE.VertexColors,渲染器会采用 THREE.Geometry 对象的 colors 属性的值。 该属性对 CanvasRenderer不起作用,但对 WebGLRender 起作用。比如我们可以使用该属性为线段的不同部分设置不同的颜色。也可以使用这个属性为这种材质类型创建渐变效果。 |
fog(雾化) | 该属性指定当前材质是否受全局雾化效果设置的影响。如果将该属性设置为 false,那么我们全局雾化效果设置就不会影响当前对象的渲染。 |
2,使用样例
这里我们创建一个小方块,使用的材质颜色为紫色且半透明。var meshMaterial = new THREE.MeshBasicMaterial({ color: 0x7777ff, name: 'material-1', opacity: 0.5, transparent: true }); var cubeGeometry = new THREE.BoxGeometry(4, 4, 4); var cube = new THREE.Mesh(cubeGeometry, meshMaterial); scene.add(cube);
二、THREE.MeshDepthMaterial(网格深度材质)
使用这种材质的物体,其外观不是由光照或者某个材质属性决定的,而是由物体到摄像机的距离决定的。我们可将这种材质与其他材质结合使用,从而很容易地创建出逐渐消失得效果。
1,属性介绍
除了那些共有属性之外,MeshDepthMaterial 还有如下两个控制线框显示的属性。
名称 | 描述 |
wireframe(线框) | 设置这个属性可以将材质渲染成线框,非常适用于调试。 |
wireframeLinewidth(线框线宽) | 如果已经打开了 wireframe,这个属性定义线框中线的宽度。 |
2,样例效果图
下面是一个通过联合材质创建出的新效果(两种材质融合起作用):- 我们往场景中添加 20 个自动旋转的方块,位置随机。
- 这些方块从 THREE.MeshDepthMaterial 对象获得亮度。
- 并从 THREE.MeshBasicMaterial 对象获得颜色。
3,样例代码
这里要特别注意如下几个地方:- 要把 THREE.MeshBasicMaterial 的 transparent 属性设置为 true,并指定一个融合模式。否则 THREE.js 不会执行任何融合操作,方块始终未纯绿色。
- 融合模式这里使用的是 THREE.MultiplyBlending,该模式会把前景色和背景色相乘,得到想要的结果。
- 当 THREE.SceneUtils.createMultiMaterialObject() 方法创建一个网格的时候,几何体会被复制,返回一个网格组(里面两个网格完全相同)。当渲染的物体有一个在别的物体上,并且有一个物体是透明的,那么渲染时会出现画面闪烁问题。这里我们通过缩小带有 THREE.MeshDepthMaterial 材质的网格,就可以避免这种现象。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>hangge.com</title> <script type="text/javascript" src="three.min.js"></script> <style> body { margin: 0; overflow: hidden; } </style> </head> <body> <!-- 作为Three.js渲染器输出元素 --> <div id="WebGL-output"> </div> <!-- 第一个 Three.js 样例代码 --> <script type="text/javascript"> //网页加载完毕后会被调用 function init() { //创建一个场景(场景是一个容器,用于保存、跟踪所要渲染的物体和使用的光源) var scene = new THREE.Scene(); //创建一个摄像机对象 var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 10, 130); camera.position.x = -30; camera.position.y = -40; camera.position.z = 30; camera.near = 0.1; camera.far = 139; //最远看到139 camera.lookAt(scene.position); //创建一个WebGL渲染器并设置其大小 var renderer = new THREE.WebGLRenderer(); renderer.setClearColor(new THREE.Color(0x00000)); //0xc0c0c0 renderer.setSize(window.innerWidth, window.innerHeight); //将渲染的结果输出到指定页面元素中 document.getElementById("WebGL-output").appendChild(renderer.domElement); //方块使用的Geometry对象 var cubeGeometry = new THREE.BoxGeometry(4, 4, 4); //方块使用的网格深度材质 var cubeMaterial = new THREE.MeshDepthMaterial(); //方块使用的网格基础材质 var colorMaterial = new THREE.MeshBasicMaterial({ color: 0x00ff00, transparent: true, blending: THREE.MultiplyBlending }); //创建20个方块对象并添加到舞台中 for(var i=0; i<20; i++) { var cube = new THREE.SceneUtils.createMultiMaterialObject(cubeGeometry, [colorMaterial, cubeMaterial]); //缩小带有THREE.MeshDepthMaterial材质的网格,避免闪烁问题。 cube.children[1].scale.set(0.99, 0.99, 0.99); cube.castShadow = true; //方块位置随机 cube.position.x = Math.round((Math.random() * 60)); cube.position.y = Math.round((Math.random() * 60)); cube.position.z = Math.round((Math.random() * -60)); //将方块添加到舞台中 scene.add(cube); } //渲染场景 render(); function render() { //方块自动旋转 scene.traverse(function (e) { if (e instanceof THREE.Mesh) { e.rotation.x += 0.02; e.rotation.y += 0.02; e.rotation.z += 0.02; } }); requestAnimationFrame(render); renderer.render(scene, camera); } } //确保init方法在网页加载完毕后被调用 window.onload = init; </script> </body> </html>
三、THREE.MeshNormalMaterial(网格法向量材质)
使用这种材质,每一面的颜色是由从该面向外指的法向量计算得到的。
1,属性介绍
除了那些共有属性之外,MeshNormalMaterial 还有如下属性。
名称 | 描述 |
wireframe(线框) | 设置这个属性可以将材质渲染成线框,非常适用于调试。 |
wireframeLinewidth(线框线宽) | 如果已经打开了 wireframe,这个属性定义线框中线的宽度。 |
shading(着色方法) | THREE.FlatShading:平面着色 THREE.SmoothShading:平滑着色 |
2,使用样例
(1)效果图- 下面是一个使用 MeshNormalMaterial 材质的球体。左右两侧的 shading(着色方法)分别为 THREE.FlatShading 和 THREE.SmoothShading。
- 法向量所指的方向决定了在使用 MeshNormalMaterial 材质时,每个面获取的颜色。由于球体各个面的法向量都不相同,所以我们看到的是一个色彩斑斓的球体。
- 而且即使在球体旋转时,这些颜色也基本保持在原来的位置(不会跟着面的移动而移动)。
(2)样例代码
//网格法向材质 var meshMaterial = new THREE.MeshNormalMaterial(); meshMaterial.shading = THREE.FlatShading; var sphereGeometry = new THREE.SphereGeometry(14, 20, 20); var sphere = new THREE.Mesh(sphereGeometry, meshMaterial); scene.add(sphere);
3,使用 THREE.ArrowHelper 添加箭头
法向量是指与面垂直的向量。法向量在 Three.js 库中有很广泛的应用。它可以用来决定光的反射,有助于将纹理映射到三维模型,并提供有关如何计算光照、阴影和为表面像素着色的信息。为了便于观察,这里我们遍历 THREE.SphereGeometry 的所有面。对于每个 THREE.Face3 对象来说,我们把构成该面的顶点相加再除以 3 来计算中心(质心)。使用这个质心连同该面的法向量来绘制箭头(THREE.ArrowHelper)。
//遍历球体的每一个面 for (var f = 0, fl = sphere.geometry.faces.length; f < fl; f++) { var face = sphere.geometry.faces[f]; //计算每个面的中心(质心) var centroid = new THREE.Vector3(0, 0, 0); centroid.add(sphere.geometry.vertices[face.a]); centroid.add(sphere.geometry.vertices[face.b]); centroid.add(sphere.geometry.vertices[face.c]); centroid.divideScalar(3); //使用质心与该面的法向量绘制箭头 var arrow = new THREE.ArrowHelper( face.normal, centroid, 2, 0x3333FF, 0.5, 0.5); sphere.add(arrow); }
四、THREE.MeshFaceMaterial(网格面材质)
THREE.MeshFaceMaterial 并不是一种真正的材质,而更像是一种材质容器。它允许给几何体的每个面指定不同的材质。1,效果图
我们使用 MeshFaceMaterial 给方块的每个面指定一种不同颜色的材质。2,样例代码
//网格面材质 var mats = []; mats.push(new THREE.MeshBasicMaterial({color: 0x009e60})); mats.push(new THREE.MeshBasicMaterial({color: 0x0051ba})); mats.push(new THREE.MeshBasicMaterial({color: 0xffd500})); mats.push(new THREE.MeshBasicMaterial({color: 0xff5800})); mats.push(new THREE.MeshBasicMaterial({color: 0xC41E3A})); mats.push(new THREE.MeshBasicMaterial({color: 0xffffff})); var faceMaterial = new THREE.MeshFaceMaterial(mats); var cubeGeom = new THREE.BoxGeometry(6, 6, 6); var cube = new THREE.Mesh(cubeGeom, faceMaterial); scene.add(cube);