【ThreeJS基础教程-材质纹理篇】3.4 Standard材质的简单应用

学习ThreeJS的捷径

本段内容会写在0篇以外所有的,本人所编写的Threejs教程中

对,学习ThreeJS有捷径
当你有哪个函数不懂的时候,第一时间去翻一翻文档
当你有哪个效果不会做的时候,第一时间去翻一翻所有的案例,也许就能找到你想要的效果
最重要的一点,就是,绝对不要怕问问题,越怕找找别人问题,你的问题就会被拖的越久

如果你确定要走WebGL/ThreeJS的开发者路线的话,以下行为可以让你更快的学习ThreeJS

  1. 没事就把所有的文档翻一遍,哪怕看不懂,也要留个印象,至少要知道Threejs有什么
  2. 没事多看看案例效果,当你记忆的案例效果足够多时,下次再遇到相似问题时,你就有可能第一时间来找对应的案例,能更快解决你自己的问题
  3. 上述案例不只是官网的案例,郭隆邦技术博客,跃焱邵隼,暮志未晚等站点均有不少优质案例,记得一并收藏
    http://www.yanhuangxueyuan.com/ 郭隆邦技术博客
    https://www.wellyyss.cn/ 跃焱邵隼
    http://www.wjceo.com/ 暮志未晚
    这三个站点是我最常逛的站点,推荐各位有事没事逛一下,看看他们的案例和写法思路,绝对没坏处

宝石效果

首先,我们先找到threejs开发包中的宝石模型,路径对应
three.js-master\examples\models\obj\emerald.obj

然后我们先给它加载出来

    import * as THREE from '../three.js-master/build/three.module.js';
    import {OrbitControls} from "../three.js-master/examples/jsm/controls/OrbitControls.js";
    import {OBJLoader} from "../three.js-master/examples/jsm/loaders/OBJLoader.js";

    let scene,renderer,camera,orbitControls;
    function init(){
        scene = new THREE.Scene();
        renderer = new THREE.WebGLRenderer({
            alpha:true,
            antialias:true
        });
        renderer.setSize(window.innerWidth,window.innerHeight);
        document.body.appendChild(renderer.domElement);
        camera = new THREE.PerspectiveCamera(60,window.innerWidth/window.innerHeight,1,1000);
        //根据宝石的大小,我们调整相机的位置,来适配宝石的实际显示效果
        camera.position.set(50,50,50);
        orbitControls = new OrbitControls(camera,renderer.domElement);
        let light = new THREE.PointLight();
        camera.add(light);
        scene.add(camera);

        let helper = new THREE.AxesHelper(5);
        scene.add(helper);

    }
    function addMesh(){
    	//由于宝石的模型是一个obj格式,所以我们使用objLoader来加载宝石模型
        let loader = new OBJLoader();
        loader.load('./emerald.obj',obj=>{
            scene.add(obj);

        })
    }
    function render(){
        renderer.render(scene,camera);
        requestAnimationFrame(render);
    }
    init();
    addMesh();
    render();

在这里插入图片描述

以上为宝石的初步加载效果,接下来,我们需要给宝石添加一个材质,这里官方的模型使用的是MeshPhongMaterial,但是不影响我们的使用,我们需要给所有模型下的Mesh修改为我们自定义的Material

	    function addMesh(){
        let loader = new OBJLoader();
        loader.load('./emerald.obj',obj=>{
            scene.add(obj);

            let material = new THREE.MeshStandardMaterial({
                color : "#ff0000", //给宝石赋予红色
                transparent:true,//允许宝石透明
                opacity:0.7, //透明度
                metalness:0.3,//金属度
                roughness:0.2//粗糙度
            });

            //遍历模型下的所有子元素,并返回一个函数,函数中带有一个参数,参数为obj的children数组的子元素或children递归下来的children的子元素
            obj.traverse(object=>{
                //这个object有可能不是mesh,所以我们借用官方的isMesh来判断这个物体是一个mesh类型
                //仅有mesh类型拥有material属性,能被修改材质
                if(object.isMesh){
                    let oldMaterial = object.material;//记录原有旧材质
                    object.material = material;//替换材质
                    oldMaterial.dispose();//养成好习惯,旧的材质如果完全不用了,使用dispose()来清理掉
                }
            })

        })
    }
	

在这里插入图片描述
这样我们的红宝石的基本效果就出来了,如果还想再进一步的增强效果,我们还能添加环境贴图

	    function addMesh(){
        let loader = new OBJLoader();
        loader.load('./emerald.obj',obj=>{
            scene.add(obj);

            let material = new THREE.MeshStandardMaterial({
                color : "#ff0000", //给宝石赋予红色
                transparent:true,//允许宝石透明
				//二次调整红宝石的各项参数用于让它更接近宝石的效果
                opacity:0.8, //透明度
                metalness:0.3,//金属度
                roughness:0//粗糙度
            });

            //遍历模型下的所有子元素,并返回一个函数,函数中带有一个参数,参数为obj的children数组的子元素或children递归下来的children的子元素
            obj.traverse(object=>{
                //这个object有可能不是mesh,所以我们借用官方的isMesh来判断这个物体是一个mesh类型
                //仅有mesh类型拥有material属性,能被修改材质
                if(object.isMesh){
                    let oldMaterial = object.material;//记录原有旧材质
                    object.material = material;//替换材质
                    oldMaterial.dispose();//养成好习惯,旧的材质如果完全不用了,使用dispose()来清理掉
                }
            })

            let loader = new THREE.CubeTextureLoader();
            //设置加载图片组的路径
            loader.setPath('./Park2/');
            //threeJS中天空盒加载顺序  px,nx,py,ny,pz,nz 或 left,right,top,bottom,front,back
            //一定要按顺序加载,否则会出现严重的拼合错误问题
            loader.load([
                "posx.jpg",
                "negx.jpg",
                "posy.jpg",
                "negy.jpg",
                "posz.jpg",
                "negz.jpg",
            ],(texture)=>{
                scene.background = texture;
                material.envMap = texture;
            });
        })
    }

添加envMap后,可以明显看到宝石反射了当前的立方纹理

在这里插入图片描述

在这里插入图片描述

多贴图下的金属枪支效果

模型的路径在
three.js-master\examples\models\obj\cerberus

    function addMesh(){
        let loader = new OBJLoader();
        let textureLoader = new THREE.TextureLoader();//创建纹理加载器
        loader.load('./cerberus/Cerberus.obj',obj=>{
            scene.add(obj);
			
			//加载对应的纹理
			//注意!如果你的项目要上线,应考虑线上传输速度的问题,以下写法会造成如下错误:
			// 你的贴图加载完成之前,对应的下面let 的对象已经被调用了,出现undifined的情况
			// 以下四个load均为异步函数,仅本地使用时可以这样写
            let map = textureLoader.load('./cerberus/Cerberus_A.jpg'); //颜色贴图
            let normalMap = textureLoader.load('./cerberus/Cerberus_N.jpg'); //法线贴图
            let roughnessMap = textureLoader.load('./cerberus/Cerberus_R.jpg'); //粗糙度贴图
            let metalnessMap = textureLoader.load('./cerberus/Cerberus_RM.jpg');//金属度贴图

			//处理贴图的常规操作
            map.wrapT = map.wrapS = THREE.RepeatWrapping;
            normalMap.wrapT = normalMap.wrapS = THREE.RepeatWrapping;
            roughnessMap.wrapT = roughnessMap.wrapS = THREE.RepeatWrapping;
            metalnessMap.wrapT = metalnessMap.wrapS = THREE.RepeatWrapping;

			//根据上面的所有贴图创建材质
            let material = new THREE.MeshStandardMaterial({
                transparent:true,//允许宝石透明
                side:THREE.DoubleSide,
                map:map,
                roughnessMap:roughnessMap,
                metalnessMap:metalnessMap,
                normalMap:normalMap
            });

			//以下内容与上方宝石基本一致

            //遍历模型下的所有子元素,并返回一个函数,函数中带有一个参数,参数为obj的children数组的子元素或children递归下来的children的子元素
            obj.traverse(object=>{
                //这个object有可能不是mesh,所以我们借用官方的isMesh来判断这个物体是一个mesh类型
                //仅有mesh类型拥有material属性,能被修改材质
                if(object.isMesh){
                    let oldMaterial = object.material;//记录原有旧材质
                    object.material = material;//替换材质
                    oldMaterial.dispose();//养成好习惯,旧的材质如果完全不用了,使用dispose()来清理掉
                }
            })

            let loader = new THREE.CubeTextureLoader();
            //设置加载图片组的路径
            loader.setPath('./Park2/');
            //threeJS中天空盒加载顺序  px,nx,py,ny,pz,nz 或 left,right,top,bottom,front,back
            //一定要按顺序加载,否则会出现严重的拼合错误问题
            loader.load([
                "posx.jpg",
                "negx.jpg",
                "posy.jpg",
                "negy.jpg",
                "posz.jpg",
                "negz.jpg",
            ],(texture)=>{
                scene.background = texture;
                material.envMap = texture;
            });
        })
    }

在这里插入图片描述

建模软件中的材质与threejs中的材质的关系

一般来说,建模软件中的基础材质,可以对应threejs的MeshStandardMaterial

以3dmax为例

在这里插入图片描述

3dmax中的 基础颜色 对应StandardMaterial的 color
粗糙度和金属度,透明度这几个基础属性,就不需要解释了

要注意,次表面散射,发射这些3dmax中有的属性,最终导出时不一定能带给threejs,所以这个需要你去积累经验,来判断这些东西在threejs中的对应
有的属性不一定能对应上MeshStandardMaterial,但是可以对应上其继承类MeshPhysicalMaterial的属性,当你用StandardMaterial加载不出来你建模师建出来的效果时,可以尝试使用MeshPhysicalMaterial来做尝试

在这里插入图片描述
下方的贴图区,也就对应threejs文档中的那一大堆贴图,但是也是要注意对应关系

有很多好看的效果,都是建模师用贴图贴出来的,比如说上面的枪支模型,不要盲目的使用threejs去做领导或者甲方要求你的效果,不仅浪费时间,即使能做出来,也会浪费大量的代码和性能

为什么推荐BabylonJS

在这里插入图片描述
threejs越往后做,会发现越来越无力,因为很多这些建模软件中的高级属性,threejs中都不支持,而babylon比起threejs来说支持的更多,甚至还有专门的插件,允许你在3dmax中就把效果调整好,直接导出到BabylonJS中使用,大量节省了代码,并且让很多的开发过程直接用可视化代替掉了

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值