three.js加载3D模型(glb/gltf/fbx)

three.js加载3D模型(glb/gltf/fbx)

一、理解three:
1.一个可以在某个3D建模软件打开的东西,通过某种方案在浏览器中打开;
2.不要试图手动去创建3D图形,当然比较闲的话可以这样操作,
3.把three当作一个3D模型播放器,在播放器里可以对模型做一些操作:调色调光,调整坐标,切换视角,播放模型中的动画…;
4.某个建模软件(3dMax…)把已经做好的模型导出了模型文件(ojb,glb,gltf,fbx等格式),通过某个可支持此格式的Loader,最终渲染到场景里 ,就像webpack打包css需要css-loader一样的道理;
5.three 把WebGL的图形引擎封装成了3d api 
 

二、基本思路:
(1)构建场景Scene->

(2)通过Renderer渲染场景到画布->

(3)需要借助**Camera帮忙观察物体->

(4)通过loader(GLTFLoader,FBXLoader…)加载模型 ->

(5)通过requestAnimationFrame 把最新场景数据渲染出来

three.js加载3D模型(glb/gltf/fbx)_第1张图片

三、源代码

import  *as THREE from './lib.js';

import BG from './model/environment/bg.jpeg'

//模型
import xsr_fbx from './model/xsr/xsr.fbx'

//纹理贴图
import xsr_fbx_texture from './model/xsr/Stormland Robo 03H.png'

import xsr_fbx_logo_texture from './model/xsr/stormland_logo.png'


 const models = [
                {name:'机器头',path:require('./model/DamagedHelmet.glb').default,position:[0, 0, 5],type:'glb'},
                {name:'像素人',path:xsr_fbx,position:[0, 0, 50],type:'fbx',
                texture:[
                         {name:'gardener,hologram_2,hologram',path:xsr_fbx_texture},
                         {name:'Plane',path:xsr_fbx_logo_texture}],
                 }, 
                
               ]

const modelScene={
      State:{
        showGrid:false,
        showLightOrigin:false,
        wireframe:false,
      },
      Scene:null,
      Renderer:null,
      Camera:null,
      Model:null,
      Lights:null,
      AnimationMixer:null,
      Tclock:new THREE.Clock(),
      TestGui:null,
      TestStats:null,
      Controls:null,
      GridHelper:new THREE.GridHelper( 300, 50,  0x00FF12, 0xFFFFFF ),
      
      init:{
          //添加场景
           Scene:function(){
                  this.Scene =  new THREE.Scene()
                  this.Scene.background = new THREE.Color(0x282923);
                  
                  this.Scene.background = new THREE.TextureLoader().load(BG)
         
                  // THREE.Cache.enabled = true;
         
           },
           //添加渲染器
           Renderer:function(){
                  this.Renderer = new THREE.WebGLRenderer({antialias: true,alpha: true,premultipliedAlpha:true,precision: 'highp'})
                  this.Renderer.setPixelRatio(window.devicePixelRatio);
                  this.Renderer.setSize(window.innerWidth, window.innerHeight);
                  this.Renderer.setClearColor(0xeeeeee);
                  this.Renderer.shadowMap.enabled = true;
                  this.Renderer.physicallyCorrectLights = true;
                  this.Renderer.outputEncoding = THREE.sRGBEncoding;


                  ThreeApp.appendChild(this.Renderer.domElement); 
           },
           //添加相机
           Camera:function(){
             this.Camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight,1, 10000)
             this.Camera.position.set(0, 0, 50);
             this.Camera.lookAt(this.Scene.position)
           },

         
           TestGui:function(){
                  let _this = this;
                  this.TestGui =  new THREE.Dat.GUI()
                  this.TestGui.add({
                  changeBg: function () {
                    _this.Scene.background = new THREE.Color(0x1A1A1A);

                  }
                }, "changeBg");
           },
           //帧率状态
           Stats() {
              this.TestStats = new THREE.Stats();
              document.body.appendChild(this.TestStats.dom);
            }
      
      },

      //加载模型GLTF FBX
      modelLoader:function(MODEL){

             
              const loadTip = this.addLoadTip();
             
              this.Controls.autoRotate = false;
                //添加环境hdr
              MODEL.hdr && this.HdrLoader(MODEL.hdr);
             
              let Loader = '',MTYPE = MODEL.type || 'glb';
                 
              if('glb,gltf'.indexOf(MTYPE)!=-1){
                Loader = new THREE.GLTFLoader()
              }
               else if('fbx'.indexOf(MTYPE)!=-1){
                Loader = new THREE.FBXLoader()
              }else{
                 loadTip.textContent='请使用glb,gltf,fbx格式模型';
                 return;
              }
        

   
             

               Loader.load(MODEL.path, (geometry)=> {
                
                  loadTip.textContent='加载完成!';
                  //移除模型  
                  this.Model &&  this.Scene.remove(this.Model);
                
                  //设置相机位置
                  this.Camera.position.set(...MODEL.position);
              
                  this.Model = 'fbx'.indexOf(MTYPE)!=-1?geometry:geometry.scene;
                  
                 
                   //遍历模型字节点,获取相关参数设置
                  this.Model.traverse(function(child) {

                      if(MODEL.texture){
                        
                        MODEL.texture.map(item=>{
                           if(item.name.indexOf(child.name)!=-1){
                               child.material = new THREE.MeshPhongMaterial({
                                         map: THREE.ImageUtils.loadTexture(item.path)//颜色贴图
                                       });
                           }
                        }) 
                      }   
                       

                        if (child.isMesh) {
                            
                              // child.material.emissiveMap = child.material.map;
                           
                              //child.material.side = THREE.DoubleSide;
                              child.material.shininess=1;
                        
                              child.castShadow = true
                              child.receiveShadow = true

                              child.material.transparent=true;//材质允许透明 如果有玻璃材质时开启
                              child.material.opacity=1;//材质默认透明度                        
                            
                          }
                      } 
                   );

                  //模型自动居中
                  THREE.ModelAutoCenter(this.Model)
              
                  //查找模型动画,
                  if(this.Model.animations.length>0){

                       this.AnimationMixer = new THREE.AnimationMixer(this.Model);
                       this.AnimationMixer.clipAction(this.Model.animations[0]).play();

                       /* 其他模型动画方案:
                        const animationClip = this.Model.animations.find(animationClip => animationClip.name === "Walk");
                        this.AnimationMixer.clipAction(animationClip).play();
                        */
                  }


                  //把模型放入场景中
                  this.Scene.add(this.Model);

                  //加载完成后开始自动播放
                  setTimeout(()=>{
                     loadTip.style.display='none';
                     this.Controls.autoRotate = true;
                   },1000);
                  
                },
                (xhr)=>{
                   //加载进度
                   loadTip.textContent=(parseInt(xhr.loaded/xhr.total*100))+'%加载中...';
              
                },
                (err)=>{
                    loadTip.textContent='模型加载失败!'
                    console.log('模型加载失败!')
                }
              );
      },
      //加载光源
      addLight:function(){
            this.Lights = [
                  {name:'AmbientLight',obj:new THREE.AmbientLight(0xFFFFFF,1)},
                  {name:'DirectionalLight_top',obj:new THREE.DirectionalLight(0xFFFFFF,3),position:[0, 15, 0]},
                  {name:'DirectionalLight_bottom',obj:new THREE.DirectionalLight(0x1B1B1B,3),position:[0, -200, 0]},
                  {name:'DirectionalLight_right1',obj:new THREE.DirectionalLight(0xFFFFFF,1.5),position:[0, -5, 20]},
                  {name:'DirectionalLight_right2',obj:new THREE.DirectionalLight(0xFFFFFF,1.5),position:[0, -5, -20]},
            ];
           

           this.Lights.map(item=>{
            item.obj.name=item.name;
            item.position && item.obj.position.set(...item.position);
            item.Helper = new THREE.PointLightHelper( item.obj );
            this.Scene.add(item.obj);
           })  
           

      }, 
      //加载HDR贴图环境光
      HdrLoader:function(HDR){
          const pmremGenerator = new THREE.PMREMGenerator(this.Renderer); // 使用hdr作为背景色
                pmremGenerator.compileEquirectangularShader();
          const textureLoader = new THREE.RGBELoader()
               textureLoader.load(HDR,(texture, textureData)=> {
             
                const envMap = pmremGenerator.fromEquirectangular(texture).texture;

                envMap.isPmremTexture = true;
                pmremGenerator.dispose();
           
                this.Scene.environment = envMap; // 给场景添加环境光效果
                this.Scene.background = envMap; // 给场景添加背景图


              });
      },
      //添加事件
      addControls:function() {
         this.Controls = new THREE.OrbitControls(this.Camera, this.Renderer.domElement);
        // 如果使用animate方法时,将此函数删除
        //controls.addEventListener( 'change', render );
        // 使动画循环使用时阻尼或自转 意思是否有惯性
         this.Controls.enableDamping = true;
        //是否可以缩放
         this.Controls.enableZoom = true;
        //设置相机距离原点的最远距离-可以控制缩放程度
         this.Controls.minDistance = 0;
        //设置相机距离原点的最远距离
         this.Controls.maxDistance = 3000;//800
        //是否开启右键拖拽
         this.Controls.enablePan = false;
        //动态阻尼系数 就是鼠标拖拽旋转灵敏度
         this.Controls.dampingFactor = 0.5;
        //是否自动旋转
         this.Controls.autoRotate = false;
         this.Controls.autoRotateSpeed = 1;
      },
      //模型切换
      switchModel(){
           const _scope = this; 
   
          var switchModelStyle = document.createElement('style');
             switchModelStyle.type = "text/css";
             switchModelStyle.innerText +='.modelList{position:fixed;width:100%; display:flex;justify-content:space-around; bottom:0;left:0;color:#0EF4F4;background:rgba(14,14,44,0.9);cursor:pointer;}\
                .modelList li{width:50%;line-height:30px;padding:5px;text-align:center;font-size:14px;}.modelList li:last-child{border:0;}.modelList li:hover,.modelList li.on{background:#0E2440;}'

          const modelUL = document.createElement('ul');
                modelUL.className='modelList'

                models.map((item,index)=>{
                
                    modelUL.innerHTML+='
  • '+item.name+'
  • '; }) document.head.insertBefore(switchModelStyle, document.head.lastChild); ThreeApp.insertBefore(modelUL,ThreeApp.firstChild); let LIS = modelUL.children; for(let i=0;i{_scope.Scene.remove(item.Helper)}) _scope.State.showLightOrigin = false }else{ _scope.Lights.map(item=>{_scope.Scene.add(item.Helper)}) _scope.State.showLightOrigin = true } } }, { name:'骨架模式', todo:function(){ if(_scope.State.wireframe){ _scope.Model.traverse( child=> { if ( child.isMesh ) { child.material.wireframe=false } }) _scope.State.wireframe = false }else{ _scope.Model.traverse( child=> { if ( child.isMesh ) { child.material.wireframe=true } }) _scope.State.wireframe = true } } }, ] //辅助面板DomTree var helpPanelStyle = document.createElement('style'); helpPanelStyle.type = "text/css"; helpPanelStyle.innerText +='#helpPanel{position:fixed;width:80px;top:50px;left:0;color:#0EF4F4;background:#0E0E2C;cursor:pointer;}\ #helpPanel li{border-bottom:1px solid #fff;line-height:30px;text-align:center;font-size:14px;}#helpPanel li:last-child{border:0;}#helpPanel li.on{color:green;}'; var helpPanel = document.createElement('ul'); helpPanel.id='helpPanel'; Panels.forEach(item=>{ let LI = document.createElement('li'); LI.innerText=item.name; LI.οnclick=function(){ this.className = this.className=='on'?'':'on' item.todo(this) } helpPanel.appendChild(LI); }) document.head.insertBefore(helpPanelStyle, document.head.lastChild); ThreeApp.insertBefore(helpPanel,ThreeApp.firstChild) }, animation:function(){ //更新控制器 this.Renderer.render(this.Scene, this.Camera); this.TestStats.update(); this.Controls.update(); this.AnimationMixer && this.AnimationMixer.update(this.Tclock.getDelta()); requestAnimationFrame(()=>this.animation()); }, onWindowResize:function() { this.Camera.aspect = window.innerWidth / window.innerHeight; this.Camera.updateProjectionMatrix(); this.Renderer.setSize(window.innerWidth, window.innerHeight); this.Renderer.render(this.Scene, this.Camera); }, run:function(){ this.init.Renderer.call(this) this.init.Scene.call(this) this.init.Camera.call(this) this.addControls(); //添加环境光 this.addLight() this.modelLoader(models[0]); //添加辅助面板 this.addPanel(); this.animation(); this.switchModel() window.onresize = ()=>this.onWindowResize(); } } modelScene.run();

    四、演示效果

    演示效果:source.nullno.com/three-demo/

    你可能感兴趣的:(three.js,threejs/pltf)