vue3使用three.js加载.obj模型示例

vue3使用three.js加载.obj模型示例

效果:
在这里插入图片描述
在这里插入图片描述
代码:
需要先安装three.js

npm install three
<template>
  <div ref="threeContainer" class="three-container"></div>
</template>

<script>
import * as THREE from 'three'
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
let scene = null // 场景需要定义到全局

const raycaster = new THREE.Raycaster()
const mouse = new THREE.Vector2()

export default {
  name: 'ThreeModel',
  data() {
    return {
      camera: null,
      renderer: null,
      controls: null
    }
  },
  mounted() {
    this.initThree()
    this.loadModel()
    this.initControls()
    this.addBackground()
    this.animate()
  },
  unmounted() {
    this.renderer.domElement.removeEventListener('click', this.onClick)
  },
  methods: {
    /**
     * 创建场景
     */
    initThree() {
      this.scene = new THREE.Scene()
      this.scene.rotation.y = 20.75
      this.scene.rotation.x = 10
      this.scene.rotation.z = 0

      // 创建相机
      this.camera = new THREE.PerspectiveCamera(
        75,
        this.$refs.threeContainer.clientWidth / this.$refs.threeContainer.clientHeight,
        1,
        1000
      )
      this.camera.position.z = 13.9
      this.camera.position.y = -100
      this.camera.position.x = 45

      // 把画面放大一点
      // this.camera.zoom = 1
      // this.camera.updateProjectionMatrix()

      // 创建渲染器
      this.renderer = new THREE.WebGLRenderer()
      this.renderer.setSize(
        this.$refs.threeContainer.clientWidth,
        this.$refs.threeContainer.clientHeight
      )
      this.$refs.threeContainer.appendChild(this.renderer.domElement)

      // 添加光源
      const light = new THREE.DirectionalLight(0xa1a1a1, 1)
      light.position.set(10, 5, 5).normalize()
      this.scene.add(light)

      // 注册点击事件
      this.renderer.domElement.addEventListener('click', this.onClick, false)
    },
    /**
     * 点击事件
     * @param {*} event
     */
    onClick(event) {
      // 将鼠标位置归一化到-1到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)
      if (intersects.length > 0) {
        intersects.forEach((o) => {
          const intersectedObject = o.object
          // 在这里处理被点击的对象,例如改变颜色、显示信息等
          console.log('点击-on object:', intersectedObject)
          if (intersectedObject.parent.name == 'tank') {
            // 改变颜色
            intersectedObject.material.color.set(0xffffff)
          }
        })
      }
    },
    /**
     * 鼠标互动
     */
    initControls() {
      // 假设你已经有了相机、渲染器和场景
      const controls = new OrbitControls(this.camera, this.renderer.domElement)

      // 设置控制器的属性,例如最小和最大距离、旋转速度等
      controls.minDistance = 1
      controls.maxDistance = 500
      controls.enableDamping = true // 启用阻尼效果,使互动更加流畅
      controls.dampingFactor = 0.25 // 阻尼系数
      controls.screenSpacePanning = true // 是否允许平面移动
      this.controls = controls
    },
    /**
     * 场景增加背景
     */
    addBackground() {
      // 添加纯色为背景
      this.renderer.setClearColor(0xcccccc) // 设置背景颜色为天空色

      // 创建一个新的纹理加载器
      const textureLoader = new THREE.TextureLoader()

      const scene = this.scene

      // 加载图像纹理
      textureLoader.load(
        'http://cdn.yhxweb.cn/3d-sucai/BA_64_D.jpg', // 图像路径
        function (texture) {
          // 设置name
          texture.name = 'background'

          // 创建一个平面几何体(或其他几何体)
          const geometry = new THREE.PlaneGeometry(500, 500) // 假设你的场景宽度和高度是500
          const material = new THREE.MeshBasicMaterial({ map: texture })

          // 创建一个网格并添加到场景中
          const plane = new THREE.Mesh(geometry, material)
          plane.position.z = 0 // 根据你的场景深度调整位置
          scene.add(plane)
        },
        // 可选的加载进度回调函数
        undefined,
        // 可选的加载错误回调函数
        function (err) {
          console.error('An error happened while loading the texture.')
        }
      )
    },
    /**
     * 初始化模型
     */
    loadModel() {
      const loader = new OBJLoader()

      // 加载.obj模型文件
      loader.load(
        'http://cdn.yhxweb.cn/3d-sucai/OBJ_7020.obj', // 替换为你的.obj文件的URL(园林)
        (obj) => {
          // 设置name
          obj.name = 'tank'

          // 设置模型的位置和缩放
          obj.position.set(0, 0, 0)
          obj.scale.set(5, 5, 5)

          // 设置模型的旋转角度

          obj.rotation.x = 1.6
          obj.rotation.y = 2

          // 设置模型颜色
          obj.traverse((child) => {
            console.log('child:', child)

            if (child instanceof THREE.Mesh) {
              child.material.color.set(0xffd4db) // 设置颜色
            }
          })

          // 将加载的模型添加到场景中
          this.scene.add(obj)
        },
        (xhr) => {
          console.log((xhr.loaded / xhr.total) * 100 + '% loaded')
        },
        (error) => {
          console.error('An error happened', error)
        }
      )
    },
    /**
     * 动画
     */
    animate() {
      // 可以在这里添加动画逻辑,例如模型旋转
      // this.scene.rotation.y += 0.002
      // this.scene.rotation.x += 0.001

      // 更新控制器
      this.controls.update()

      this.renderer.render(this.scene, this.camera)
      // console.log(this.scene.rotation.x, this.scene.rotation.y)

      requestAnimationFrame(this.animate)
    }
  }
}
</script>

<style>
.three-container {
  width: 100%;
  height: calc(100vh - 175px);
  overflow: hidden;
}
</style>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

星月前端

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值