<script setup>import { ref, getCurrentInstance, onMounted, beforeUnmount } from 'vue'import * as BABYLON from '@babylonjs/core/Legacy/legacy' // 全部引入import '@babylonjs/loaders' // 模型加载loaderimport * as GUI from '@babylonjs/gui/2D' // 交互组件const { proxy } = getCurrentInstance()const emit = defineEmits(['customChange'])let engine = ref(null)let scene = ref(null)let camera = ref(null)// 模型加载进度百分比let progress = ref(0)// 是否完成模型渲染let isRendering = ref(false)// 是否展示视频let showVideo = ref(false)// 自适应渲染const engineResize = ()=> { engine.resize();}// 重置模型const reset = ()=> { scene.activeCamera.restoreState();}onMounted(() => { let canvas = document.getElementById('canvas'); // 初始化 BABYLON 3D engine engine = new BABYLON.Engine(canvas, true, { preserveDrawingBuffer: true, stencil: true, disableWebGL2Support: false }); // 自定义loading加载效果 function customLoadingScreen() { console.log('customLoadingScreen creation'); } customLoadingScreen.prototype.displayLoadingUI = function() { console.log('customLoadingScreen loading') }; customLoadingScreen.prototype.hideLoadingUI = function() { window.document.getElementById('loadingScreen').style.display = 'none'; }; engine.loadingScreen = new customLoadingScreen(); // 初始化一个场景 scene scene = new BABYLON.Scene(engine); // 设置背景色透明 scene.clearColor = new BABYLON.Color4(0, 0, 0, 0); // 初始化相机 camera camera = new BABYLON.ArcRotateCamera('Camera', 0, 0, 0, new BABYLON.Vector3(0, 0, 0), scene); /* * 天空盒 */ // 创建天空盒 const skybox = BABYLON.Mesh.CreateBox('skyBox', 21000, scene), skyboxMaterial = new BABYLON.StandardMaterial('skyboxMaterial', scene); // 关闭掉材质的背面剔除(在盒子内部也可以看到盒子) skyboxMaterial.backFaceCulling = false; // 删除盒子上的反射光(天空不会反射太阳) skyboxMaterial.disableLighting = true; // 载入天空贴图(CubeTexture是贴图加载器,只能被应用到reflectionTexture) skyboxMaterial.reflectionTexture = new BABYLON.CubeTexture('textures/sky', scene); // 修改贴图模式(reflectionTexture是反射贴图,但我们需要天空盒贴图) skyboxMaterial.reflectionTexture.coordinatesMode = BABYLON.Texture.SKYBOX_MODE; skybox.material = skyboxMaterial; // 设置天空盒跟随相机位置移动(盒子不会收缩) skybox.infiniteDistance = true; /* * 3D模型 */ // 引入外部obj模型 BABYLON.SceneLoader.Append('babylon/1/', 'model.glb', scene, (object) => { // 设置默认相机和灯光 scene.createDefaultCameraOrLight(true, true, true); const light = new BABYLON.HemisphericLight('light', new BABYLON.Vector3(1, 1, 1)); // 设置灯光亮度 light.intensity = 1; // 镜面反射 漫反射 环境光颜色调整 light.diffuse = new BABYLON.Color3(1, 1, 1); light.specular = new BABYLON.Color3(1, 1, 1); // 渲染模型后调整相机角度、位置、观察对象的三维坐标 scene.activeCamera.alpha = 0.0239; scene.activeCamera.beta = 1.51; scene.activeCamera.radius = 51.9; scene.activeCamera.setPosition(new BABYLON.Vector3(51.85, 4.32, 4.45)); scene.activeCamera.setTarget(new BABYLON.Vector3(0.04, 1.4, 3.2)); // 设置横向旋转角度上下限 scene.activeCamera.upperBetaLimit = Math.PI * 0.5; scene.activeCamera.lowerBetaLimit = 0; // 设置镜头到目标位置距离半径的最大值 scene.activeCamera.upperRadiusLimit = 102; // 设置鼠标滚轮灵敏度(数值越小灵敏度越高) scene.activeCamera.wheelPrecision = 10; // 控制鼠标平移相机镜头灵敏度(数值越小灵敏度越高|为0的时候取消平移操作) scene.activeCamera.panningSensibility = 200; // 存储当前相机状态 scene.activeCamera.storeState(); // 关闭自定义loading效果、展示标题、展示按钮 setTimeout(() => { engine.hideLoadingUI(); emit('showTitle', true); isRendering = true; }); }, (progressEvent) => { // 设置模型加载进度百分比 progress = (progressEvent.loaded / progressEvent.total).toFixed(0) * 100; }); // 注册渲染循环 runRenderLoop engine.runRenderLoop(() => { scene.render(); }); // 在 DOM 更新后执行回调 nextTick(() => { console.log('DOM 已更新'); // 注册resize监听事件 window.addEventListener('resize', engineResize); });})beforeUnmount(() => { // 离开页面销毁resize监听事件 window.removeEventListener('resize', engineResize, false);})</script><template> <div :class="isRendering ? 'containor bg' : 'containor'"> <div id="loadingScreen" class="flex_column_center"> <span class="loading"></span> <span class="progress">{{ progress }}%</span> <span class="text">3D模型加载中...</span> </div> <canvas id="canvas"></canvas> <div class="btn_list flex_middle" v-if="isRendering"> <el-button type="warning" size="small" @click="reset"><i class="el-icon-refresh"></i> 重置</el-button> </div> </div></template><style lang="scss" scoped>/*scrollbar styles*/::-webkit-scrollbar { width: 12px; height: 12px; // border-radius: 100px;}::-webkit-scrollbar-thumb { // border-radius: 100px; background: var(--color-ref-kl-primary10);}::-webkit-scrollbar-track-piece { // border-radius: 100px; background: transparent;}::-webkit-scrollbar-corner { background: transparent;}/*scrollbar styles*/#app { height: 100%; color: #4b4b4b; font-size: 13px; font-family: 'Microsoft YaHei'; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;}.flex { display: flex;}.flex_center { @extend .flex; align-items: center;}.flex_left { @extend .flex_center; justify-content: flex-start;}.flex_right { @extend .flex_center; justify-content: flex-end;}.flex_middle { @extend .flex_center; justify-content: center;}.flex_column { @extend .flex; flex-direction: column; justify-content: center;}.flex_column_center { @extend .flex_column; align-items: center;}.public_radius { border-radius: 8px;}.echarts { height: 100%; overflow: hidden;}.containor { position: relative; width: 100%; height: 100%; overflow: hidden; &.bg { background-color: #8ecbe3; } #loadingScreen { position: absolute; width: 100%; height: 100%; .loading { display: inline-block; position: relative; width: 100px; height: 100px; border: 8px solid #0934f7; border-radius: 50%; animation: rotate 1s linear infinite; &:after { position: absolute; left: 50%; top: 50%; width: 110px; height: 110px; content: ''; transform: translate(-50%, -50%); border: 8px solid transparent; border-bottom-color: #00eaff; border-radius: 50%; } } .progress { margin-top: -60px; color: #6be031; font-size: 16px; font-weight: 700; } .text { margin-top: 60px; color: #f5a327; font-size: 14px; } } canvas { width: 100%; height: 100%; outline: none; cursor: pointer; } .btn_list { position: absolute; bottom: 0; width: 100%; height: 50px; z-index: 99; button { margin: 0 15px 0 0; &:last-child { margin: 0; } } } .video_main { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 800px; height: 500px; z-index: 999; video { outline: none; } }}</style>
Useful links
Official web site: www.babylonjs.comOnline playground to learn by experimentatingOnline sandbox where you can test your .babylon and glTF scenes with a simple drag'n'dropOnline shader creation tool where you can learn how to create GLSL shaders3DS Max exporter can be used to generate a .babylon file from 3DS MaxMaya exporter can be used to generate a .babylon file from MayaBlender exporter can be used to generate a .babylon file from Blender 3dUnity 5 (deprecated) exporter can be used to export your geometries from Unity 5 scene editor(animations are supported)glTF Tools by KhronosGroup"@babylonjs/core": "^5.24.0",
"@babylonjs/gui": "^5.24.0",
"@babylonjs/loaders": "^5.24.0",
"@babylonjs/materials": "^5.24.0",
"@babylonjs/post-processes": "^5.24.0",
"@babylonjs/procedural-textures": "^5.24.0",
"@babylonjs/serializers": "^5.24.0",
"@babylonjs/viewer": "^5.24.0",
参见:
Babylon.js: Powerful, Beautiful, Simple, Open - Web-Based 3D At Its Best
Babylonjs中文网
GitHub - BabylonJS/Babylon.js: Babylon.js is a powerful, beautiful, simple, and open game and rendering engine packed into a friendly JavaScript framework.
Export To Babylon.js