Vue3+TypeScript+ThreeJS实现模型(GLB)点击事件
随着技术的发展,及现代互联网的普及,前端工作已经不是简单的html+css+javascript了,今天分享一下ThreeJS前端3D库在vue3+ts中的使用,以及实现模型的导入及模型的点击交互事件。
使用脚手架搭建 vue3+ts 项目
使用命令快速搭建
1、在PowerShell或黑窗口中执行命令:
npm create vue@latest
2、选择以下命令:
3、运行绿色命令进行依赖安装; ()
配置
1、 package.json
依赖安装:
"dependencies": {
"less": "^4.2.0",
"three": "^0.162.0",
"unplugin-vue-components": "^0.26.0",
"vue": "^3.4.21"
},
"devDependencies": {
"@tsconfig/node20": "^20.1.4",
"@types/node": "^20.12.5",
"@types/three": "^0.164.0",
"@vitejs/plugin-vue": "^5.0.4",
"@vue/tsconfig": "^0.5.1",
"npm-run-all2": "^6.1.2",
"typescript": "~5.4.0",
"vite": "^5.2.8",
"vue-tsc": "^2.0.11"
}
2、vite.config.ts
配置
import { defineConfig,loadEnv } from "vite";
import vue from "@vitejs/plugin-vue";
// @ts-ignore
import { resolve } from "path";
// @ts-ignore
import Components from "unplugin-vue-components/vite";
// @ts-ignore
import { AntDesignVueResolver } from "unplugin-vue-components/resolvers";
// https://vitejs.dev/config/
export default defineConfig(({mode})=>{
// 运行模式
console.log('mode',mode)
// 当前路径
console.log('process.cwd()',process.cwd())
// @ts-ignore
const env=loadEnv(mode,process.cwd())
console.log('env',env)
const proxy={
"^/api/": {
target: env.VITE_APP_HOST,
changeOrigin: true,
ws: true,
rewrite: (path: any) => path.replace(/^/api/, ""),
},
};
return {
// 打包相对路径
base: './',
server: {
port: 3000,
open: true,
cors: true,
proxy: {
...proxy
},
},
"css": {
preprocessorOptions: {
less: {
javascriptEnabled: true,
patterns: [resolve(__dirname, "./src/style/main.less")],
},
},
},
resolve: {
alias: {
"@": resolve(__dirname, "src"),
},
},
plugins: [
vue(),
Components({
resolvers: [AntDesignVueResolver()],
}),
],
}
});
ThreeJS的使用
因本篇文章为demo,所有内容集合于app.vue文件中。
代码部分
<template>
<div class="container-three-box">
<div class="view-box" id="viewBox"> </div>
</div>
</template>
<script setup lang="ts">
import {
Color, Raycaster,
AmbientLight, DirectionalLight,
Vector2, PerspectiveCamera,
Scene, WebGLRenderer,
DoubleSide
} from "three";
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import {type GLTF, GLTFLoader} from "three/examples/jsm/loaders/GLTFLoader";
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
import {reactive,onMounted} from 'vue'
type StateType = {
title: string,
demoId: string
}
const state: StateType = reactive({
title: '加载模型',
demoId: 'viewBox'
})
// 本地开发路径
// const url = "../public/static/model/model.glb";
// 打包路径
const url = "../public/static/model/model.glb";
const renderThree=() => {
// 初始化场景
const scene = new Scene();
// 设置场景背景色
scene.background = new Color("#FFFFFF");
// 初始化相机
const camera = new PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
// 初始化渲染器
const renderer = new WebGLRenderer({
// 开启抗锯齿
antialias: true
});
// 设置渲染器大小
renderer.setSize( window.innerWidth, window.innerHeight );
// 渲染器追加至节点中
(document.getElementById(state.demoId) as HTMLElement).appendChild( renderer.domElement );
// 初始化射线辅助器
const rayCaster = new Raycaster();
// 鼠标控制对象
const mouse = new Vector2();
camera.position.z = 5;
// 添加轨道控制器(控制的是相机)
const controls = new OrbitControls(camera, renderer.domElement);
// 设置带阻尼的惯性
controls.enableDamping = true;
// 设置阻尼系数,系数越小惯性越大
controls.dampingFactor = 0.05;
// 初始化模型加载器
const loader = new GLTFLoader();
// 初始化模型解压器
const dracoLoader = new DRACOLoader()
// 设置解压器使用位置(本地开发路径)
// dracoLoader.setDecoderPath('../public/static/draco/')
// 设置解压器使用位置(打包路径)
dracoLoader.setDecoderPath('./static/draco/')
// 设置模型载入解压器
loader.setDRACOLoader(dracoLoader);
// 加载模型
loader.load(url, (gltf: GLTF) => {
// 初始化环境光,环境光不能用来投射阴影,因为它没有方向。
const ambientLight = new AmbientLight(0xffffff, 1); // 白光,强度为1
// 环境光添加至场景中
scene.add(ambientLight);
// 添加平行光,使物体看起来更加有效果
const dirLight = new DirectionalLight(0xffffff, 5);
// 根据需要自行调整位置
dirLight.position.set(0, 1, 0);
// 场景中添加平行光
scene.add(dirLight);
gltf.scene.traverse((child: any) => {
if (child.isMesh) {
// 模型双面渲染
child.material.side = DoubleSide;
// 光照是否有阴影
child.castShadow = true;
// 是否接收阴影
child.receiveShadow = true;
child.frustumCulled = false;
}
});
// console.log(gltf);
const model = gltf.scene;
// 将模型添加至场景中
scene.add(model)
// 设置模型加载完毕后大小
model.scale.set( 5.0, 5.0, 5.0 );
})
const clickEvent = (event: MouseEvent) => {
// 得到鼠标相对于容器的坐标
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
// 执行射线检测
rayCaster.setFromCamera(mouse, camera);
// 射线涉及到的物体集合
const intersects = rayCaster.intersectObjects(scene.children, true)
// todo
// 以下编写点击事件后需要做的内容
console.log('intersects:', intersects)
if (!intersects.length) {
console.log('未选中任何模型')
} else {
console.log('选中模型咯')
}
}
document.addEventListener('click',clickEvent, false )
function animate() {
requestAnimationFrame( animate );
renderer.render( scene, camera );
}
animate();
}
onMounted(()=>{
renderThree()
})
</script>
<style lang="less">
.view-box{
width:600px;
height: 600px;
}
</style>
注意事项
1、当前案例模型使用格式为 .glb
格式,文件存放路径为根目录public/static/model/
下。
2、模型加载需要使用解压器,解压器为threejs自带,文件夹为draco
,源文件存储路径为\node_modules\three\examples\jsm\libs\draco
,为了方便开发使用及打包后可直接的静态资源,可将此包进行拷贝,放置在public/static/
下:
3、使用模型引入路径及使用模型解压器引入路径需要手动切换:
效果
本文源码地址:
转载自:https://juejin.cn/post/7363138988011847695