页面结构
展示页面
<template><div class="login flex flex-col"><div class="scene" id="scene"></div></div>
</template><script lang="ts" setup>
import { computed, onMounted, reactive, ref, shallowRef } from "vue";
import type { InputInstance, FormInstance } from "element-plus";
import useAppStore from "@/stores/modules/app";
import useUserStore from "@/stores/modules/user";
import cache from "@/utils/cache";const passwordRef = shallowRef<InputInstance>();
const formRef = shallowRef<FormInstance>();
const appStore = useAppStore();
const userStore = useUserStore();
const route = useRoute();
const router = useRouter();
const config = computed(() => appStore.config);import Base3d from "@/utils/glb";
const data = reactive({base3d: {},
});
onMounted(() => {data.base3d = new Base3d("#scene");
});
</script>
glb.js文件
import * as THREE from 'three' //导入整个 three.js核心库
import { EquirectangularReflectionMapping } from 'three' //导入纹理映射模块
import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader' //导入RGB加载器
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls' //导入控制器模块,轨道控制器
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader' //导入GLTF模块,模型解析器,根据文件格式来定class Base3d {constructor(selector) {this.container = document.querySelector(selector)this.camerathis.scenethis.rendererthis.controlsthis.init()this.animate()}init() {//初始化场景this.initScene()//初始化相机this.initCamera()//初始化渲染器this.initRender()//初始化控制器,控制摄像头,控制器一定要在渲染器后this.initControls()// 添加物体模型this.addMesh()//监听场景大小改变,跳转渲染尺寸window.addEventListener("resize", this.onWindowResize.bind(this))}initScene() {this.scene = new THREE.Scene()this.setEnvMap('079')}initCamera() {this.camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.25, 200)this.camera.position.set(-1.8, 0.6, 20)}initRender() {this.renderer = new THREE.WebGLRenderer({ antialias: true }) //设置抗锯齿//设置屏幕像素比this.renderer.setPixelRatio(window.devicePixelRatio)//渲染的尺寸大小this.renderer.setSize(window.innerWidth, window.innerHeight)//色调映射this.renderer.toneMapping = THREE.ACESFilmicToneMapping//曝光this.renderer.toneMappingExposure = 3this.container.appendChild(this.renderer.domElement)}setEnvMap(hdr) { //设置环境背景new RGBELoader().setPath('').load('http://xx.xx/image/' + hdr + '.hdr', (texture) => {texture.mapping = EquirectangularReflectionMapping //圆柱形形纹理映射this.scene.background = texturethis.scene.environment = texture})}render() {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)}//加载模型setModel(modelName) {return new Promise((resolve, reject) => {const loader = new GLTFLoader().setPath('')loader.load('http://xx.xx/image/ff.glb', (gltf) => {console.log(gltf);this.model = gltf.scene.children[0]this.scene.add(this.model)resolve(this.modelName + '模型添加成功')})})}addMesh() {this.setModel('ff.glb')}onWindowResize() { //调整屏幕大小this.camera.aspect = window.innerWidth / window.innerHeight //摄像机宽高比例this.camera.updateProjectionMatrix() //相机更新矩阵,将3d内容投射到2d面上转换this.renderer.setSize(window.innerWidth, window.innerHeight)}
}
export default Base3d
上边的http://xx.xx/image/为服务器资源地址,记得开启Nginx配置跨源资源共享(CORS)请求
设置 add_header Access-Control-Allow-Origin *; 即可 例如:location /image/ {add_header Access-Control-Allow-Origin *********
}也可以把静态资源放在项目中 setPath('./')设置为./new RGBELoader().setPath('./').load('/xxx/xxx/xxx' + hdr + '.hdr', (texture) => {texture.mapping = EquirectangularReflectionMapping //圆柱形形纹理映射this.scene.background = texturethis.scene.environment = texture})
还有部署到服务器后进入页面第一次正常刷新404的问题
在conf文件中添加属性
try_files $uri $uri/ /index.html;
尝试解析下列2个文件/文件夹(分辨IP后面的路径是文件还是文件夹), $uri/$uri/,解析到则返回 否则就跳转index.thmltry_files 固定语法
$uri 指代home文件(ip地址后面的路径,假如是127.0.0.1/index/a.png,那就指代index/a.png)
$uri/ 指代home文件夹
/index.html 向ip/index.html 地址发起请求location / {root /deplay/dist;index index.html index.htm;try_files $uri $uri/ /index.html;}
还有打包时 如果静态文件在本地,结构如图hdr和glb文件引用路径会错
第一种方式在dist里创建一个public文件夹 再把文件放进去即可
第二种方式是服务器引入则无需改动
第三种
引入对应资源文件
在vite.config.ts文件中配置
assetsInclude: [‘/*.hdr’, '/*.glb’]
我的配置 供参考
export default defineConfig({base: './',server: {host: '0.0.0.0',},plugins: [vue(),vueJsx(),AutoImport({imports: ['vue', 'vue-router'],resolvers: [ElementPlusResolver()],eslintrc: {enabled: true}}),Components({directoryAsNamespace: true,resolvers: [ElementPlusResolver()]}),createStyleImportPlugin({resolves: [ElementPlusResolve()]}),createSvgIconsPlugin({// 配置路劲在你的src里的svg存放文件iconDirs: [fileURLToPath(new URL('./src/assets/icons', import.meta.url))],symbolId: 'local-icon-[dir]-[name]'}),vueSetupExtend()// legacyPlugin({// targets: ['defaults', 'IE 11']// })],resolve: {alias: {'@': fileURLToPath(new URL('./src', import.meta.url))}},assetsInclude: ['**/*.hdr', '**/*.glb'],build: {rollupOptions: {manualChunks(id) {if (id.includes('node_modules')) {return id.toString().split('node_modules/')[1].split('/')[0].toString()}},output: {assetFileNames: (assetInfo: any) => {if (/\.(mp4|webm|ogg|mp3|wav|flac|aac)$/.test(assetInfo.name)) { // 匹配资源文件后缀return `media/[name].[hash][ext]`; // 创建media文件夹存放匹配的资源文件,name为该文件的原名,hash为哈希值,ext为文件后缀名,以[name].[hash][ext]命名规则}// else if (/\.(glb|hdr)$/.test(assetInfo.name)) { // 匹配资源文件后缀 可以自定义存放位置// return `public/[name].[ext]`; // 创建media文件夹存放匹配的资源文件,name为该文件的原名,hash为哈希值,ext为文件后缀名,以[name].[hash][ext]命名规则// }return `assets/[name]-[hash].[ext]`; // 不匹配的资源文件存放至assets,以[name]-[hash].[ext]命名规则,注意两处的命名规则不同},}}}
})
import hdr from '../assets/079.hdr'
import glb from '../assets/ff.glb'
使用时const loader = hdr.includes('http') ? new RGBELoader().setPath('') : new RGBELoader().setPath('./')const loader = glb.includes('http') ? new GLTFLoader().setPath('') : new GLTFLoader().setPath('./')
判断绝对|相对路径
打包后对应的资源路径
最后我还尝试在uniapp中进行配置 发现只能使用服务器引用资源才会成功