美文网首页
Three.js加载gltf模型文件

Three.js加载gltf模型文件

作者: 黑白不过灰 | 来源:发表于2019-09-26 20:32 被阅读0次

    项目中直接使用的是three.js直接加载gltf模型文件。

    gtlf文件被誉为3d界的“jpeg”,很形象

    gltf

    个人接触的gltf文件不是很多,所以这里举一个项目中用的列子,图片奉上

    image

    scene.bin文件为3d模型导出的二进制文件,最最主要的文件之一(哈哈)
    我在写模型加载的时候,是引用的外部配置文件,这样的话,就能使组件能够复用,写一个组件,更改不同的配置文件,加载不同的模型

    后面调用组件时传递给组件的参数
    {
          // 传入给3d模型渲染组件的服务器路径
        "model": "/web_app/three3d/models/019/scene.gltf",
        "textures": "",
        "envMap": "",
        "texturesOn": true,
        "enableKeys": false,
        "autoRotate": false
    }
    

    组件编写

    render函数长这样,ref的作用是获取到标签的真实dom(哈哈,个人理解)

    render() {
        let style = { width: '100%', height: '100%' };
        return (
          <div 
            style={style}
            ref={(mount) => { this.mount = mount; }}
          />
        );
      }
    

    定义一些需要用到的全局变量

        let container,
            mixer,
            controls;
        let camera,
            scene,
            renderer,
            light;
        // 定义three中的动画时间
        let clock = new THREE.Clock();
    
        let threeConf = this.state.threeConf;
        container = document.createElement('div');
        this.mount.appendChild(container);
        container = this.mount;
        let width = this.mount.clientWidth;
        let height = this.mount.clientHeight;
        camera = new THREE.PerspectiveCamera(60, width / height, 1, 1000);
        container.addEventListener('resize', () => {
          camera.aspect = width / height;
          camera.updateProjectionMatrix();
          renderer.setSize(width, height);
        }, false);
    

    定义textures环境图片,有这个的话模型就会有反射环境,图片是从服务器拿回来的。

    // 环境设置,设置之后可以反射周围环境
        let envMap = new THREE.CubeTextureLoader().load([
          '/images/sys/three3d/envmappic/posx.jpg',
          '/images/sys/three3d/envmappic/negx.jpg',
          '/images/sys/three3d/envmappic/posy.jpg',
          '/images/sys/three3d/envmappic/negy.jpg',
          '/images/sys/three3d/envmappic/posz.jpg',
          '/images/sys/three3d/envmappic/negz.jpg'
        ]);
        scene = new THREE.Scene();
    
        // 添加光线
        light = new THREE.HemisphereLight(0xbbbbff, 0x444422);
        light.position.set(0, 1, 0);
        scene.add(light);
    

    关于gltf的模型加载器不用自己写loader加载。scene.gltf文件就是我们需要loader的文件

    // 新建loader,加载gltf文件
        let loader = new THREE.GLTFLoader();
        loader.load(threeConf.model, (gltf) => {
          const gltfScene = gltf.scene || gltf.scenes[0];
          const clips = gltf.animations || [];
          gltfScene.updateMatrixWorld();
          const box = new THREE.Box3().setFromObject(gltfScene);
          const size = box.getSize(new THREE.Vector3()).length();
          const center = box.getCenter(new THREE.Vector3());
          // controls.reset();
    
          gltfScene.position.x += gltfScene.position.x - center.x;
          gltfScene.position.y += gltfScene.position.y - center.y;
          gltfScene.position.z += gltfScene.position.z - center.z;
    
          // 重新设置相机参数
          controls.maxDistance = size * 10;
          camera.near = size / 100;
          camera.far = size * 100;
          camera.updateProjectionMatrix();
    
          camera.position.copy(center);
          camera.position.x += size / 2.0;
          camera.position.y += size / 2.0;
          camera.position.z += size / 2.0;
          camera.lookAt(center);
    
          gltf.scene.traverse((child) => {
            if (child.isMesh) {
              child.material.envMap = envMap;
            }
          });
          scene.add(gltf.scene);
          // 判断当前的gltf问价中是否有动画
          if (clips.length !== 0) {
            mixer = new THREE.AnimationMixer(gltfScene);
            mixer.clipAction(gltf.animations[0]).play();
          } else {
          }
        });
        renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
        renderer.setPixelRatio(container.devicePixelRatio);
        renderer.setSize(width, height);
        renderer.gammaOutput = true;
    

    控制器和动画的加载

        controls = new THREE.OrbitControls(camera, container);
        //按键控制
        controls.enableKeys = false;
        // 自动旋转(默认flase)
        controls.autoRotate = false;
        container.appendChild(renderer.domElement);
        container.addEventListener('resize', this.onWindowResize, false);
    
        requestAnimationFrame(function fn() {
          if (mixer) {
            let delta = clock.getDelta();
            mixer.update(delta);
          }
          requestAnimationFrame(fn);
          renderer.render(scene, camera);
          controls.update();
        });
    

    控制器中用到的监听方法

    onWindowResize = () => {
        camera.aspect = width / height;
        camera.updateProjectionMatrix();
        renderer.setSize(width, height);
      }
    

    最后附上完整代码

    import React from 'react';
    
    const THREE = window.THREE = require('three');
    
    require('three/examples/js/loaders/GLTFLoader');
    require('three/examples/js/loaders/DRACOLoader');
    require('three/examples/js/loaders/DDSLoader');
    require('three/examples/js/controls/OrbitControls');
    require('three/examples/js/controls/TrackballControls');
    require('three/examples/js/loaders/RGBELoader');
    require('three/examples/js/loaders/HDRCubeTextureLoader');
    require('three/examples/js/pmrem/PMREMGenerator');
    require('three/examples/js/pmrem/PMREMCubeUVPacker');
    
    
    THREE.DRACOLoader.setDecoderPath('lib/draco/');
    
    
    class Three3D extends React.Component {
      state = ({ threeConf: this.props.threeConf });
    
      componentDidMount() {
        let container,
          mixer,
          controls;
        let camera,
          scene,
          renderer,
          light;
        // 定义three中的动画时间
        let clock = new THREE.Clock();
    
        let threeConf = this.state.threeConf;
        container = document.createElement('div');
        this.mount.appendChild(container);
        container = this.mount;
        let width = this.mount.clientWidth;
        let height = this.mount.clientHeight;
        camera = new THREE.PerspectiveCamera(60, width / height, 1, 1000);
        container.addEventListener('resize', () => {
          camera.aspect = width / height;
          camera.updateProjectionMatrix();
          renderer.setSize(width, height);
        }, false);
    
        // 环境设置,设置之后可以反射周围环境
        let envMap = new THREE.CubeTextureLoader().load([
          '/images/sys/three3d/envmappic/posx.jpg',
          '/images/sys/three3d/envmappic/negx.jpg',
          '/images/sys/three3d/envmappic/posy.jpg',
          '/images/sys/three3d/envmappic/negy.jpg',
          '/images/sys/three3d/envmappic/posz.jpg',
          '/images/sys/three3d/envmappic/negz.jpg'  
        ]);
        scene = new THREE.Scene();
    
        // 添加光线
        light = new THREE.HemisphereLight(0xbbbbff, 0x444422);
        light.position.set(0, 1, 0);
        scene.add(light);
    
        // 新建loader,加载gltf文件
        let loader = new THREE.GLTFLoader();
        loader.load(threeConf.model, (gltf) => {
          const gltfScene = gltf.scene || gltf.scenes[0];
          const clips = gltf.animations || [];
          gltfScene.updateMatrixWorld();
          const box = new THREE.Box3().setFromObject(gltfScene);
          const size = box.getSize(new THREE.Vector3()).length();
          const center = box.getCenter(new THREE.Vector3());
          // controls.reset();
    
          gltfScene.position.x += gltfScene.position.x - center.x;
          gltfScene.position.y += gltfScene.position.y - center.y;
          gltfScene.position.z += gltfScene.position.z - center.z;
    
          // 重新设置相机参数
          controls.maxDistance = size * 10;
          camera.near = size / 100;
          camera.far = size * 100;
          camera.updateProjectionMatrix();
    
          camera.position.copy(center);
          camera.position.x += size / 2.0;
          camera.position.y += size / 2.0;
          camera.position.z += size / 2.0;
          camera.lookAt(center);
    
          gltf.scene.traverse((child) => {
            if (child.isMesh) {
              child.material.envMap = envMap;
            }
          });
          scene.add(gltf.scene);
          // 判断当前的gltf问价中是否有动画
          if (clips.length !== 0) {
            mixer = new THREE.AnimationMixer(gltfScene);
            mixer.clipAction(gltf.animations[0]).play();
          } else {
          }
        });
        renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
        renderer.setPixelRatio(container.devicePixelRatio);
        renderer.setSize(width, height);
        renderer.gammaOutput = true;
    
        controls = new THREE.OrbitControls(camera, container);
        //按键控制
        controls.enableKeys = false;
        // 自动旋转(默认flase)
        controls.autoRotate = false;
        container.appendChild(renderer.domElement);
        container.addEventListener('resize', this.onWindowResize, false);
    
        requestAnimationFrame(function fn() {
          if (mixer) {
            let delta = clock.getDelta();
            mixer.update(delta);
          }
          requestAnimationFrame(fn);
          renderer.render(scene, camera);
          controls.update();
        });
      }
    
      onWindowResize = () => {
        camera.aspect = width / height;
        camera.updateProjectionMatrix();
        renderer.setSize(width, height);
      }
    
      render() {
        let style = { width: '100%', height: '100%' };
        return (
          <div 
            style={style}
            ref={(mount) => { this.mount = mount; }}
          />
        );
      }
    }
    export default Three3D;
    

    调用

    <Three3d threeConf={this.state.threeConf} />
    

    相关文章

      网友评论

          本文标题:Three.js加载gltf模型文件

          本文链接:https://www.haomeiwen.com/subject/shbnuctx.html