学习threejs,使用MeshFaceMaterial面材质容器

发布于:2025-03-15 ⋅ 阅读:(13) ⋅ 点赞:(0)

👨‍⚕️ 主页: gis分享者
👨‍⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅!
👨‍⚕️ 收录于专栏:threejs gis工程师



一、🍀前言

本文详细介绍如何基于threejs在三维场景中使用MeshFaceMaterial面材质容器,亲测可用。希望能帮助到您。一起学习,加油!加油!

1.1 ☘️THREE.MeshFaceMaterial

THREE.MeshFaceMaterial是一个材质容器,用于为几何体的每个面分配不同的材质。
代码示例:

// 创建材质数组,并为每个面指定不同的材质
const faceMaterialArray = [];
faceMaterialArray.push(new THREE.MeshBasicMaterial({ color: 0x009e60 }));
faceMaterialArray.push(new THREE.MeshBasicMaterial({ color: 0x0051ba }));
faceMaterialArray.push(new THREE.MeshBasicMaterial({ color: 0xffd500 }));
faceMaterialArray.push(new THREE.MeshBasicMaterial({ color: 0xff5800 }));
faceMaterialArray.push(new THREE.MeshBasicMaterial({ color: 0xc41e3a }));
faceMaterialArray.push(new THREE.MeshBasicMaterial({ color: 0xffffff }));

// 注意:对于立方体,由于每个面由两个三角形组成,因此我们需要为每个面指定两个相同的材质。
// 但为了简化示例,这里只为每个“可见”面指定了一个材质,另一个三角形面将使用相同的材质。

// 实例化MeshFaceMaterial
const faceMaterial = new THREE.MeshFaceMaterial(faceMaterialArray);

// 创建几何体并应用材质
const cubeGeom = new THREE.BoxGeometry(3, 3, 3);
const cube = new THREE.Mesh(cubeGeom, faceMaterial);

// 将几何体添加到场景中(这里假设已经有一个场景对象scene)
scene.add(cube);

替代方案:
在 Three.js 中,MeshFaceMaterial 是一个历史遗留的材质类,用于为几何体(Geometry)的每个面(Face)分配不同的材质。不过,自 Three.js r125+ 版本后,随着 Geometry 类被废弃并逐步替换为 BufferGeometry,MeshFaceMaterial 也已被弃用。
BufferGeometry + 多材质

  • (1) 使用多材质组(groups)
    将几何体划分为多个材质组,每组对应一个材质。
const geometry = new THREE.BufferGeometry();
const material1 = new THREE.MeshBasicMaterial({ color: 0xff0000 });
const material2 = new THREE.MeshBasicMaterial({ color: 0x00ff00 });

// 假设几何体有 6 个面(立方体)
geometry.groups.push(
  { start: 0, count: 3, materialIndex: 0 }, // 前3个顶点用材质0
  { start: 3, count: 3, materialIndex: 1 }  // 后3个顶点用材质1
);

// 创建网格时传入材质数组
const mesh = new THREE.Mesh(geometry, [material1, material2]);
  • (2) 使用多材质组(groups)
    通过顶点颜色或纹理坐标实现面级差异化效果。
// 顶点颜色示例
const colors = new Float32Array([
  1, 0, 0, // 顶点1颜色(红)
  1, 0, 0, 
  1, 0, 0, 
  0, 1, 0, // 顶点4颜色(绿)
  0, 1, 0, 
  0, 1, 0
]);
geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3));

const material = new THREE.MeshBasicMaterial({ vertexColors: true });
const mesh = new THREE.Mesh(geometry, material);

二、🍀使用MeshFaceMaterial面材质容器

1. ☘️实现思路

  • 1、初始化renderer渲染器。
  • 2、初始化Scene三维场景scene。
  • 3、初始化camera相机,定义相机位置 camera.position.set,设置相机方向camera.lookAt。
  • 4、创建THREE.SpotLight聚光灯光源spotLight,设置聚光灯光源位置和投影,scene场景加入spotLight。
  • 5、加载几何模型:创建二维平面网格对象plane,设置plane的旋转角度和位置,scene场景加入plane。定义数组变量mats,mats添加六个THREE.MeshBasicMaterial基础材质作为立方体的六个面材质,六个基础材质设置为不同颜色。传入mats参数创建MeshFaceMaterial面材质容器faceMaterial。创建THREE.Mesh网格group,x、y、z方向循环使用faceMaterial材质创建27个小立方体cube,设置cube位置,group添加cube。scene场景添加group。定义render方法,实现立方体魔方group的旋转动画。具体代码参考下面代码样例。
  • 6、加入gui控件,控制group的旋转速度。加入stats监控器,监控帧数信息。

2. ☘️代码样例

<!DOCTYPE html>
<html>
<head>
    <title>学习threejs,使用MeshFaceMaterial面材质容器</title>
    <script type="text/javascript" src="../libs/three.js"></script>
    <script type="text/javascript" src="../libs/stats.js"></script>
    <script type="text/javascript" src="../libs/dat.gui.js"></script>
    <style>
        body {
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>

<div id="Stats-output">
</div>
<!-- Div which will hold the Output -->
<div id="WebGL-output">
</div>

<!-- Js 代码块 -->
<script type="text/javascript">

    // 初始化
    function init() {

        var stats = initStats();

        // 创建三维场景
        var scene = new THREE.Scene();

        // 创建相机
        var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);

        // 创建渲染器,设置颜色和大小
        var renderer = new THREE.WebGLRenderer();

        renderer.setClearColor(new THREE.Color(0xEEEEEE, 1.0));
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.shadowMapEnabled = false;

        // 创建二维平面,并设置投影
        var planeGeometry = new THREE.PlaneGeometry(60, 40, 1, 1);
        var planeMaterial = new THREE.MeshLambertMaterial({color: 0xffffff});
        var plane = new THREE.Mesh(planeGeometry, planeMaterial);
        plane.receiveShadow = true;

        // 设置二维平面的位置和旋转角度
        plane.rotation.x = -0.5 * Math.PI;
        plane.position.x = 0;
        plane.position.y = -2;
        plane.position.z = 0;

        // 场景scene添加二维平面
        scene.add(plane);

        // 设置相机位置和方向
        camera.position.x = -40;
        camera.position.y = 40;
        camera.position.z = 40;
        camera.lookAt(scene.position);

        // 添加聚光灯光源,设置光源位置和投影
        var spotLight = new THREE.SpotLight(0xffffff);
        spotLight.position.set(-40, 60, -10);
        spotLight.castShadow = true;
        scene.add(spotLight);

        // renderer渲染器绑定html要素
        document.getElementById("WebGL-output").appendChild(renderer.domElement);

        var group = new THREE.Mesh();
        // 添加立方体六个面材质
        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);
		
		// 创建27个小立方体组成大立方体
        for (var x = 0; x < 3; x++) {
            for (var y = 0; y < 3; y++) {
                for (var z = 0; z < 3; z++) {
                    var cubeGeom = new THREE.BoxGeometry(2.9, 2.9, 2.9);
                    var cube = new THREE.Mesh(cubeGeom, faceMaterial);
                    cube.position.set(x * 3 - 3, y * 3, z * 3 - 3);

                    group.add(cube);
                }
            }
        }


        scene.add(group);
        var step = 0;

        var controls = new function () {
            this.rotationSpeed = 0.02;
            this.numberOfObjects = scene.children.length;
        };

        var gui = new dat.GUI();
        gui.add(controls, 'rotationSpeed', 0, 0.5);

        render();

        function render() {
            stats.update();


            group.rotation.y = step += controls.rotationSpeed;
            requestAnimationFrame(render);
            renderer.render(scene, camera);
        }

        function initStats() {

            var stats = new Stats();

            stats.setMode(0);

            stats.domElement.style.position = 'absolute';
            stats.domElement.style.left = '0px';
            stats.domElement.style.top = '0px';

            document.getElementById("Stats-output").appendChild(stats.domElement);

            return stats;
        }
    }
    window.onload = init;
</script>
</body>
</html>

效果如下:
在这里插入图片描述