当前位置: > > > Three.js - 材质的使用详解2(网格基础材质、深度材质、法向材质、面材质)

Three.js - 材质的使用详解2(网格基础材质、深度材质、法向材质、面材质)

一、THREE.MeshBasicMaterial(网格基础材质)

MeshBasicMaterial 是一种非常简单的材质,这种材质不考虑场景中光照的影响。使用这种材质的网格会被渲染成简单的平面多边形,而且也可以显示几何体的线框。

1,属性介绍

除了那些共有属性之外,MeshBasicMaterial 还有如下特有的属性。
 名称 描述
 color(颜色)  设置材质的颜色。
 wireframe(线框)  设置这个属性可以将材质渲染成线框,非常适用于调试。
 wireframeLinewidth(线框线宽)  如果已经打开了 wireframe,这个属性定义线框中线的宽度。
 wireframeLinecap(线框线段端点)  这个属性定义了线框模式下顶点间线段的端点如何显示。可选的值包括:
  • round:圆(默认值)
  • butt:平
  • square:方
 在实际使用中,这个属性的修改结果很难看出来。 WebGLRenderer 对象不支持该属性。
 wireframeLinejoin(线框线段连接点)  这个属性定义了线段的连接点如何显示。可选的值有:
  • round:圆(默认值)
  • bevel:斜角
  • miter:尖角
 如果在一个使用低透明度和 wirefiameLinewidth 值很大的例子里靠近观察,就可以看到这个属性的效果。 WebGLRenderer 对象不支持该属性。
 shading(着色)  该属性定义如何着色。可选的值有:
  • THREE.SmoothShading(默认值,这个将产生一个平滑的对象,看不到单个面)
  • THREE.NoShading
  • THREE.FlatShading
 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.MeshBasicMaterialtransparent 属性设置为 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.FlatShadingTHREE.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);
评论0