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>