效果大概这样,这个宝箱模型是直接初始化就显示的,人物模型是自己本地添加上去的,代码如下。
<template>
<div class="container" ref="container">
<el-row>
<el-col :span="24">
<div class="grid-content ep-bg-purple-dark"></div>
<el-tabs v-model="activeTab" class="demo-tabs" @tab-click="handleClick">
<el-tab-pane label="3d模型" name="first">
<input type="file" accept=".obj,.pltf,.fbx" @change="handleFileUpload">
<div ref="modelContainer"></div>
</el-tab-pane>
</el-tabs>
</el-col>
</el-row>
</div>
</template>
<script>
import { ref, reactive, onMounted,getCurrentInstance} from 'vue'
import * as THREE from 'three'
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import { AmbientLight, DirectionalLight } from 'three';
export default {
setup() {
const model = ref(null);
const container = ref(null)
const modelContainer = ref(null)
const previewContainer = ref(null);
const pond = FilePond.create(inputElement);
const state = reactive({
uploadedFile: null,
modelLoaded: false
})
let scene = null
let controls = null
onMounted(() => {
// 初始化场景
scene = new THREE.Scene() // 将 scene 赋值
// 初始化相机c
let camera = new THREE.PerspectiveCamera(
75,
container.value.clientWidth / container.value.clientHeight,//纵横比
0.1,//近截面距离
1000//远截面距离
)
camera.position.z = 5
// 初始化渲染器
let renderer = new THREE.WebGLRenderer({ antialias: true })
renderer.setSize(container.value.clientWidth, container.value.clientHeight)
modelContainer.value.appendChild(renderer.domElement)
// 添加光源
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5); // 环境光
const directionalLight = new THREE.DirectionalLight(0xffffff, 1); // 平行光
directionalLight.position.set(1, 1, 1);
scene.add(ambientLight);
scene.add(directionalLight);
// 初始化控制器
initOrbitControls(camera, renderer)
// 加载obj模型
// const loader = new OBJLoader()
// loader.load(
// './public/static/obj/man.obj',
// (object) => {
// // 加载成功后的回调函数
// // 在这里处理加载的模型对象
// handleModelLoaded(object, scene) // 将 scene 作为参数传递
// },
// (xhr) => {
// // 加载过程中的回调函数
// console.log((xhr.loaded / xhr.total) * 100 + '% loaded')
// },
// (error) => {
// // 加载失败的回调函数
// console.error('加载失败', error)
// }
// )
// 加载gltf模型
const loader = new GLTFLoader();
loader.load(
'./public/static/obj/scene.gltf',
(gltf) => {
scene.add(gltf.scene);
},
undefined,
(error) => {
console.error('加载失败', error);
}
);
// 循环渲染
const animate = () => {
requestAnimationFrame(animate)
renderer.render(scene, camera)
}
animate()
})
// 更改颜色
const handleModelLoaded = (object, scene) => {
if (scene) {
object.traverse((child) => {
if (child instanceof THREE.Mesh) {
child.material.color.set('#ff0000')
}
})
scene.add(object)
} else {
console.error('Scene is not defined')
}
}
// 控制器
function initOrbitControls(camera, renderer) {
controls = new OrbitControls(camera, renderer.domElement)
controls.enableDamping = true
controls.enableZoom = true
controls.autoRotate = false
// 禁用自动旋转
controls.autoRotateSpeed = 3
// 设置自动旋转速度
controls.enablePan = true
// 启用相机平移
controls.enableKeys = true
// 启用键盘控制
controls.keyPanSpeed = 7
//平移速度
controls.keys = {
LEFT: 37,
UP: 38,
RIGHT: 39,
BOTTOM: 40
}
// 键盘控制按键码设置
}
const getBigectURL = (event) => {
const current = event.target.files[0]
const fileReader = new FileReader()
fileReader.readAsDataURL(current)
fileReader.onload = (e) => {
state.videoSrc = e.currentTarget.result
}
}
return {
container,
modelContainer,
...state,
initOrbitControls,
activeTab: 'first',
videoSrc: '',
container,
state,
model,
}
}
}
</script>
<style>
.container {
height: 100%;
width: 100%;
}
</style>