Three.js引入3d模型

300 阅读2分钟

three.js 引入3D模型

一、依赖安装

依赖安装只需要这一个

# three.js
npm install --save three

或者cnd导入

<script type="importmap">
  {
    "imports": {
      "three": "https://unpkg.com/three@<version>/build/three.module.js",
      "three/addons/": "https://unpkg.com/three@<version>/examples/jsm/"
    }
  }
</script>

addons为附加组件,按需引入

二、封装

准备一个js文件进行各个所需内容的封装,如下

import * as THREE from 'three'//导入three.js核心库
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls' //导入轨道控制器
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'//导入GLTF模型加载器
class MODEL3D {
  constructor(selector) {
    this.container = document.querySelector(selector)//获取容器
    this.scene
    this.camera
    this.renderer
    this.controls
    this.init() //初始化
    this.animate()//循环函数
  }
  init() {
    // 初始化场景
    this.initScene()
    // 初始化辅助轴
    // this.initAxesHelper()
    // 初始化网格辅助线
    // this.initGridHelper()
    // 初始化灯光
    this.initLight()
    // 初始化相机
    this.initCamera()
    // 初始化渲染器
    this.initRender()
    // 初始化轨道控制器
    this.initMesh()
    this.initControls()
    // 监听场景大小改变,重新渲染尺寸
    window.addEventListener('resize', this.onWindowResize.bind(this))
  }
  initMesh() {
    this.addGLTFModel()
  }
  initScene() {
    this.scene = new THREE.Scene()
    this.scene.background = new THREE.Color(0xa0a0a0)
  }
  initAxesHelper() {
    const axesHelper = new THREE.AxesHelper(1)
    this.scene.add(axesHelper)
  }
  initGridHelper() {
    const size = 10;
    const divisions = 10;
    const gridHelper = new THREE.GridHelper(size, divisions);
    const radius = 10;
    const jsectors = 16;
    const jrings = 8;
    const jringsdivisions = 64;
    const jhelper = new THREE.PolarGridHelper(radius, jsectors, jrings, jringsdivisions);
    this.scene.add(jhelper);
    this.scene.add(gridHelper);
  }
  initLight() {
    const light = new THREE.AmbientLight(0x404040); // 柔和的白光
    this.scene.add(light);
  }
​
  initCamera() {
    this.camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 100)
    this.camera.position.set(1, 0, 1)
  }
​
  initRender() {
    this.renderer = new THREE.WebGLRenderer({ antialias: true })//设置抗锯齿
    //设置屏幕像素比
    this.renderer.setPixelRatio(window.devicePixelRatio)
    //渲染的尺寸大小
    this.renderer.setSize(window.innerWidth, window.innerHeight)
    // 添加到容器
    this.container.appendChild(this.renderer.domElement)
  }
​
  render() {
    this.renderer.outputColorSpace = THREE.SRGBColorSpace
    this.renderer.shadowMap.enabled = true;
    this.renderer.hadowMapEnabled = true;
    this.renderer.render(this.scene, this.camera)
  }
  animate() {
    this.renderer.setAnimationLoop(this.render.bind(this))
  }
  initControls() {
    this.controls = new OrbitControls(this.camera, this.renderer.domElement)
    this.controls.enablePan = false
    this.controls.minPolarAngle = Math.PI/2
    this.controls.maxPolarAngle =  Math.PI/2
  }
  onWindowResize() {
    //页面大小变化时重渲染
    this.camera.aspect = window.innerWidth / window.innerHeight
    this.camera.updateProjectionMatrix() //更新矩阵,将3d内容投射到2d画面上转换
    this.renderer.setSize(window.innerWidth, window.innerHeight)
  }
  addGLTFModel() {
    return new Promise((resolve, reject) => {
      const loader = new GLTFLoader()
      loader.load('/pikaqu.glb', (gltf) => {
        console.log(gltf); //模型对象
        gltf.scene.castShadow = true;
        gltf.scene.rotation.set(0, -Math.PI / 4, 0)
        gltf.scene.position.set(0, -Math.PI/4, 0)
        //模型纯黑问题处理
        gltf.scene.traverse(function (child) {
          if (child.isMesh) {
            child.frustumCulled = true;
            //模型阴影
            child.castShadow = true;
            //模型自发光
            child.material.emissive = child.material.color;
            child.material.emissiveMap = child.material.map;
          }
        })
        this.scene.add(gltf.scene)
        // 模型自转
        var that = this
        function animate() {
          requestAnimationFrame( animate );
          gltf.scene.rotation.y += 0.01;
          that.renderer.render(that.scene, that.camera)
        }
        animate();
      })
    })
  }
}
export default MODEL3D

仅需要注意模型格式问题,有两点

  • 模型加载器不同:不同的模型加载器用于加载不同格式的模型,并不是通用的;Addons中有多种不同格式的模型加载器,选取合适的用;
  • 模型不受光影响:注意确认模型材质,有些格式模型如gltf、glb不会反射光,并且没有自发光,加载出来的模型很黑,可以给他做一个自发光的处理;

三、使用封装

<template>
  <div id="scene">
  </div>
</template>
<script setup>
import {onMounted } from 'vue'
import motor3d from './motor3d';
onMounted(()=>{ 
   new motor3d('#scene') 
 })
</script>
<style scoped></style>

id选择器直接挂上就可以