Vue集成three.js,并加载glb、gltf、FBX、json模型

Vue集成three.js,并加载glb、gltf、FBX、json模型,第1张

最近刚开始做的一个项目,后面有个模块要通过three.js实现3D的场景,因为之前也没接触过3D这块,就提前学了一下,做个记录。

先上几个网址

ThreeJS官方:http://www.thingjs.com/guide/city2/ 

ThreeJS文档:https://threejs.org/docs/index.html#manual/en/introduction/Creating-a-scene  

免费模型网:http://glbxz.com/err/search.php?keyword=%E5%85%8D%E8%B4%B9  

ThreeJS在线开发

接下来就我做的一个demo开始 

安装
npm i three
npm i three-orbitcontrols
npm i stats.js // 性能监测
组件中引入 
import * as THREE from 'three'
import * as Stats from 'stats.js'
import OrbitControls from 'three-orbitcontrols'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js'
import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader.js'
基本使用  1.创建场景 
this.scene = new THREE.Scene();
2.相机 
this.camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 1000);
// 设置摄像机位置,相机方向逆X轴方向,倾斜向下看
this.camera.position.set(360, 360, 360);
// 指向场景中心
this.camera.lookAt(this.scene.position);
3. 渲染器
this.renderer = new THREE.WebGLRenderer({ antialias: true });
// 设置环境
this.renderer.setClearColor(new THREE.Color("#f1f9fb"));
// 设置场景大小
this.renderer.setSize(window.innerWidth / window.innerHeight);
// 渲染器开启阴影效果
this.renderer.shadowMap.enabled = true;
4.创建纹理加载器 
this.textureLoader = new THREE.TextureLoader();
5.创建组合对象 

加载外部模型的时候,基本上都是一个组合对象,因为外部模型都是比较大的,把零散的模型组合到一块便于 *** 作,可以使用THREE.Group来 *** 作一组对象,包括旋转,缩放,移动等,里面的子对象都会受到影响。THREE.Group继承自THREE.Object3D对象,并且和THREE.Object3D对象没有任何区别,仅仅是名字上的差异

this.groupBox = new THREE.Group();
6.添加坐标轴,辅助判断位置 
let axes = new THREE.AxesHelper(1000);
this.scene.add(axes);
7.点光源 
// 点光源
let point = new THREE.PointLight(0xffffff);
point.position.set(500, 300, 400); // 点光源位置
this.scene.add(point); // 点光源添加到场景中
8.环境光 
// 环境光
let ambient = new THREE.AmbientLight(0x999999);
this.scene.add(ambient);
9.性能监测 
//创建性能监测
this.stats = new Stats()
this.stats.showPanel(0) // 0: fps, 1: ms, 2: mb, 3+: custom
this.stats.domElement.style.position = 'absolute'; //绝对坐标  this.stats.domElement.style.left = '0px';// (0,0)px,左上角  
this.stats.domElement.style.top = '0px';
$('#stats').appendChild(this.stats.domElement)
10.相机控件 
//创建相机控件
this.control = new OrbitControls(this.camera, this.renderer.domElement)
this.control.enableDamping = true
// 动态阻尼系数 就是鼠标拖拽旋转灵敏度,阻尼越小越灵敏
this.control.dampingFactor = 0.5;
// 是否可以缩放
this.control.enableZoom = true;
// 是否自动旋转
this.control.autoRotate = false;
// 设置相机距离原点的最近距离
this.control.minDistance = 20;
// 设置相机距离原点的最远距离
this.control.maxDistance = 1000;
// 是否开启右键拖拽
this.control.enablePan = true;
// 上下翻转的最大角度
this.control.maxPolarAngle = 1.5;
// 上下翻转的最小角度
this.control.minPolarAngle = 0.0;
// 是否可以旋转
this.enableRotate = true;
11.渲染canvas到容器 
$('#container').appendChild(this.renderer.domElement);
12.加载glb、gltf模型 
loadGlbModel() {
  const loader = new GLTFLoader()
  // const dracoLoader = new DRACOLoader()
  // dracoLoader.setDecoderPath('/draco/')
  // dracoLoader.preload()
  // loader.setDRACOLoader(dracoLoader)
  loader.load(`${this.publicPath}model/12OJJ6MOWT722N61Z5N92KA9C.glb`, (gltf) => {
    console.log(gltf, 'gltf----->>>')
    gltf.scene.scale.set(100,100,100)  //  设置模型大小缩放
    gltf.scene.position.set(0,0,0)
    let axis = new THREE.Vector3(0,1,0);//向量axis
    gltf.scene.rotateOnAxis(axis,Math.PI/2);
    //绕axis轴逆旋转π/16
    gltf.scene.rotateOnAxis(axis,Math.PI/-20);
    gltf.scene.rotateOnAxis(axis,Math.PI/50);
    // gltf.rotateY(Math.PI / 2);
    // this.groupBox.add(gltf);
    this.scene.add(gltf.scene)
  }, (xhr) => {
      console.log((xhr.loaded / xhr.total) * 100 + '% loaded')
  }, (error) => {
      console.error(error)
  })
},
13.加载FBX模型 
//  加载 FBX 模型
loadFbxModel() {
  const loader = new FBXLoader();
  loader.load(`${this.publicPath}model/glbxz.com6031.FBX`, object => {//加载路径fbx文件
    console.log(object, 'object----->>>')
    object.traverse( child => {
      if ( child.isMesh ){
        child.castShadow = true;
        child.receiveShadow = true;
      }
    });
    this.scene.add(object);//模型
  })
},
14.加载json模型 
//加载 JSON格式 模型
loadJsonModel() {
  //设置相机位置
  this.camera.position.z = 130
  this.camera.position.y = 80
  const loader = new THREE.ObjectLoader()
  loader.load(`${this.publicPath}model/xxxx.json`, json => {
    //处理加载模型为黑色问题
    json.traverse(child => {
      if (child.isMesh) {
        child.material.emissive = child.material.color
        child.material.emissiveMap = child.material.map
      }
    })
    this.scene.add(group)
  }, xhr => {
    // called while loading is progressing
    console.log(`${( xhr.loaded / xhr.total * 100 )}% loaded`);
  }, error => {
    // called when loading has errors
    console.error('An error happened', error);
  })
},
15.创建材质 
// 创建材质
createMaterial() {
  // 创建三维用到的材质
  /**
   * 
   * MeshBasicMaterial: 网格基础材质
   * MeshDepthMaterial: 网格深度材质
   * MeshNormalMaterial: 网格法向材质
   * MeshLambertMaterial: 网格Lambert 材质
   * MeshPhongMaterial: 网格 Phong式材质
   * MeshStandardMaterial: 网格标准材质
   * MeshPhysicalMaterial: 网格物理材质
   * MeshToonMaterial: 网格卡通材质
   * ShadowMaterial: 阴影材质
   * ShaderMaterial: 着色器材质
   * LineBasicMaterial: 直线基础材质
   * LineDashMaterial: 虚线材质
   */
  // 外墙
  let wallMaterial = new THREE.MeshLambertMaterial({ color: 0x00ffff });
  let wallGeo = new THREE.BoxGeometry(439 + 2 + 2, 120, 376.5 + 2 + 2); // 创建几何体
  let wallMesh = new THREE.Mesh(wallGeo, wallMaterial);
  wallMesh.position.set(0, 60, 0); //(0, 60, -14.95);
  this.scene.add(wallMesh) // 添加结果到场景中
  // 内墙
  let wallInnerMaterial = new THREE.MeshLambertMaterial({
    color: 0x2d1bff,
  });
  let wallInnerGeo = new THREE.BoxGeometry(439, 120, 376.5); //(270, 120, 390);
  let wallInnerMesh = new THREE.Mesh(wallInnerGeo, wallInnerMaterial);
  wallInnerMesh.position.set(0, 60, 0); //(0, 60, -14.95);
  this.scene.add(wallInnerMesh)  // 添加结果到场景中
  // 门
  let doorTexture = this.textureLoader.load(
    require("../../../../assets/img/1.png") // 暂时注掉
  );
  let boxTextureMaterial = new THREE.MeshStandardMaterial({
    map: doorTexture,
    metalness: 0.2,
    roughness: 0.07,
    side: THREE.DoubleSide,
  });
  //let doorInnerMaterial = new THREE.MeshLambertMaterial({color: 0x2D1BFF});
  let doorGeo = new THREE.BoxGeometry(2, 80, 74.5);
  let doorMesh = new THREE.Mesh(doorGeo, boxTextureMaterial);
  doorMesh.position.set(-220.5, 40, 0);
  this.scene.add(doorMesh);  // 添加结果到场景中

  /**
   *  threeBSP - 引用还有问题
   */
  // //转BSP
  // let wallBSP = new ThreeBSP(wallMesh);
  // let wallInnerBSP = new ThreeBSP(wallInnerMesh);
  // let doorBSP = new ThreeBSP(doorMesh);
  // // let window1BSP = new ThreeBSP(this.createWindowRight());
  // //let window2BSP = new ThreeBSP(this.createWindowRight());// createWindowLeft
  // let wallResultBSP = wallBSP.subtract(wallInnerBSP);
  // wallResultBSP = wallResultBSP.subtract(doorBSP);
  // // wallResultBSP = wallResultBSP.subtract(window1BSP);
  // //wallResultBSP = wallResultBSP.subtract(window2BSP);
  // let wallResultMesh = wallResultBSP.toMesh();

  // //转换后的Mesh配置属性
  // let wallTexture = this.textureLoader.load(require("../../../../assets/img/3.jpg")); // 暂时注掉
  // let wallTextureMaterial = new THREE.MeshStandardMaterial({
  //   map: wallTexture,
  //   metalness: 0.2,
  //   roughness: 0.07,
  //   side: THREE.DoubleSide,
  // });
  // let wallInnerTexture = this.textureLoader.load(
  //   require("../../../../assets/img/6.jpg") // 暂时注掉
  // );
  // let wallInnerTextureMaterial = new THREE.MeshStandardMaterial({
  //   map: wallInnerTexture,
  //   metalness: 0.2,
  //   roughness: 0.07,
  //   side: THREE.DoubleSide,
  // });
  // let wallResultMeshMaterial = [];
  // wallResultMeshMaterial.push(wallTextureMaterial);
  // wallResultMeshMaterial.push(wallInnerTextureMaterial);
  // //wallResultMeshMaterial.push(boxTextureMaterial);
  // wallResultMesh.material = wallResultMeshMaterial;

  // // console.log(wallResultMesh.geometry.faces, 112233);
  // wallResultMesh.geometry.faces.forEach((item, i) => {
  //   if (i < 160) {
  //     item.materialIndex = 0;
  //   } else {
  //     item.materialIndex = 1;
  //   }
  // });

  // wallResultMesh.geometry.computeFaceNormals();
  // wallResultMesh.geometry.computeVertexNormals();
  // //添加结果到场景中
  // this.scene.add(wallResultMesh);
},
16.进行渲染 
render() {
  let animate = () => {
    //循环调用函数
    requestAnimationFrame(animate)
    //更新相机控件
    this.control.update()
    // 更新性能插件
    this.stats.update()
    //渲染界面
    this.renderer.render(this.scene, this.camera)
  }
  animate()
}
17.为模型绑定事件 

这里以点击事件为例 

this.renderer.domElement.addEventListener('click', this.modelMouseClick, false)
// 模型的点击事件
modelMouseClick( event ) {
  var raycaster = new THREE.Raycaster();
  var mouse = new THREE.Vector2();
  // 将鼠标位置归一化为设备坐标。x 和 y 方向的取值范围是 (-1 to +1)
  mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
  mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
  raycaster.setFromCamera(mouse, this.camera);
  const intersects = raycaster.intersectObjects(this.scene.children);
  // 根据它来判断点击的什么,length为0即没有点击到模型
  console.log(intersects, 'intersects----->>>')
}
完整代码 



效果 

  

最后再补充一下,有个threeBSP,,到现在还没知道怎么去引用,搞这个东西才两天,很多还需要慢慢摸索 ,好像这个threBSP不支持npm装,而且必须要引在THREE后面。。。慢慢再搞

 这个是threeBSP在线的包,如果向上面例子按需引入THREE,那应该怎么去引这个包呢,, 

不断学习中。。。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1320684.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-11
下一篇 2022-06-11

发表评论

登录后才能评论

评论列表(0条)

保存