Three.js 模型渲染,更换模型渲染颜色

1,060 阅读4分钟

前言

接上一篇文章# html页面3D模型渲染之——three.js,进行了更深的研究,之前只是把模型渲染出来了。

简单的进行预览,后面就想着能不能换肤(因为3D看车,一般都是可以换色的),网上找了好多的例子,都满足不了我的需求,很多都是官网的例子拿来渲染的,我也把那些demo下载下来,换上自己的模型的时候,无论如何都渲染不上颜色,也不知道哪里的问题。

说实话three.JS对初学者确实不友好,一定要大量的时间去研究才可行(后面也没时间去研究,网址上面也就只上了简单的预览)。

直到昨天看到一篇文字,这里引用一下一篇文章# threejs3D汽车换肤实战 当然也是three.js官方的demo,不过这里说的挺详细的。一些具体的解释可以去看这篇文章。

我说一下,需要注意的问题,不然就还是和官网一样,换上自己的模型就渲染不了。 先看效果

QQ2024717-115845.gif

重点

里面有这么一段代码,它就是渲染颜色的

loader.load('./models/gltf/ferrari.glb', function (gltf) {

    const carModel = gltf.scene.children[0];
    console.log(carModel);
    carModel.getObjectByName('body').material = bodyMaterial;

    carModel.getObjectByName('rim_fl').material = detailsMaterial;
    carModel.getObjectByName('rim_fr').material = detailsMaterial;
    carModel.getObjectByName('rim_rr').material = detailsMaterial;
    carModel.getObjectByName('rim_rl').material = detailsMaterial;
    carModel.getObjectByName('trim').material = detailsMaterial;

    carModel.getObjectByName('glass').material = glassMaterial;

    wheels.push(
        carModel.getObjectByName('wheel_fl'),
        carModel.getObjectByName('wheel_fr'),
        carModel.getObjectByName('wheel_rl'),
        carModel.getObjectByName('wheel_rr')
    );

    //shadow
    const mesh = new THREE.Mesh(
        new THREE.PlaneGeometry(0.655 * 4, 1.3 * 4),
        new THREE.MeshBasicMaterial({
            map: shadow, blending: THREE.MultiplyBlending, toneMapped: false, transparent: true
        })
    );
    //设置阴影效果x轴方向的角度
    mesh.rotation.x = -Math.PI / 2 ;
    mesh.renderOrder = 2;
    carModel.add(mesh);

    scene.add(carModel);

});

这段代码的解释就是

上面的代码分别是获取模型中车身区域(body),获取轮毂区域(rim_fl、rim_fr、rim_rr、rim_rl)、座椅区域(trim)、玻璃区域(glass)

当然如果是我们自己的模型,复制这段代码,肯定是渲染不出来颜色的。

那么我们需要怎么做呢,肯定是替换我们自己模型的名字,也就是,你模型每块地方的名字(也就是图层)“可以这么去理解,你ps做图的时候,肯定是一块块的图层拼起来的,而这个图层的名称就是你模型的的名称”

上面汽车的名称就是(rim_fl、rim_fr、rim_rr、rim_rl)代表前左、前右、后左、后右的轮毂,车辆的玻璃部分的名字叫做glass,等

那么我们要如何看自己模型的名称呢,很简单

// 打印模型中的所有对象名称
carModel.traverse(function (child) {
    if (child.isMesh) {
        console.log(child.name);
    }
});

这是我打印出来的名称

image.png 很多,因为这是图层太多了,他每个图层的名称都打印出来了,这时候你可以去跟公司设计这个模型的人,说一下,看能不能合并一下图层,

不合并也没关系,那你就找到你要渲染区域的名称,然后,比如我的就是这样

 loader.load('./3D/BS-36KS.glb', function (gltf) {
        const carModel = gltf.scene;
        // 打印模型中的所有对象名称
        carModel.traverse(function (child) {
            if (child.isMesh) {
                console.log(child.name);
            }
        });
        carModel.getObjectByName( '机箱主体(645A35A7-9576-4813-A74A-DB3A21C92CF3)' ).material = bodyMaterial;
        carModel.getObjectByName( '机箱外壳(5FFEA2F7-BAC5-4065-AA8B-A0A88CF6B687)' ).material = detailsMaterial;

        scene.add(carModel);
        progressBar.style.display = 'none';

    },

就渲染了两个区域,然后你运行一下代码,换肤就成功了。

还有一个需要注意的地方就是,材质,每个区域的材质是不一样的,还是用车demo来举例,

//汽车body的材质。采用了物理网格材质,车漆具有反光效果
const bodyMaterial = new THREE.MeshPhysicalMaterial({
    color: 0x333333, metalness: 1.0, roughness: 0.5, clearcoat: 1.0, clearcoatRoughness: 0.03
});

//汽车轮毂的材质,采用了标准网格材质,threejs解析gltf模型,会用两种材质PBR材质去解析
const detailsMaterial = new THREE.MeshStandardMaterial({
    color: 0xffffff, metalness: 1.0, roughness: 0.5
});

//汽车玻璃的材质
const glassMaterial = new THREE.MeshPhysicalMaterial({
    color: 0xffffff, metalness: 0.25, roughness: 0, transmission: 1.0
});

而官网也提个了,很多材质,可以去研究研究。 附上链接 three.js image.png

总结

至此我想要的功能就完成了,说的可能不够好,也有可能说的的不正确,这些只是我的思路,和见解,也是在别人的demo上面去改的,当然欢迎大家评论,或者有什么不懂的地方,都可以说出来,或许我也不懂呢,哈哈。

最后附上源码

gitee.com