当前位置:   article > 正文

vue3 + Babylon.js 实现3D场景

vue3 + Babylon.js 实现3D场景
  1. <script setup>
  2. import { ref, getCurrentInstance, onMounted, beforeUnmount } from 'vue'
  3. import * as BABYLON from '@babylonjs/core/Legacy/legacy' // 全部引入
  4. import '@babylonjs/loaders' // 模型加载loader
  5. import * as GUI from '@babylonjs/gui/2D' // 交互组件
  6. const { proxy } = getCurrentInstance()
  7. const emit = defineEmits(['customChange'])
  8. let engine = ref(null)
  9. let scene = ref(null)
  10. let camera = ref(null)
  11. // 模型加载进度百分比
  12. let progress = ref(0)
  13. // 是否完成模型渲染
  14. let isRendering = ref(false)
  15. // 是否展示视频
  16. let showVideo = ref(false)
  17. // 自适应渲染
  18. const engineResize = ()=> {
  19.     engine.resize();
  20. }
  21. // 重置模型
  22. const reset = ()=> {
  23.     scene.activeCamera.restoreState();
  24. }
  25. onMounted(() => {
  26.     let canvas = document.getElementById('canvas');
  27.     // 初始化 BABYLON 3D engine
  28.     engine = new BABYLON.Engine(canvas, true, { preserveDrawingBuffer: true, stencil: true, disableWebGL2Support: false });
  29.     // 自定义loading加载效果
  30.     function customLoadingScreen() {
  31.         console.log('customLoadingScreen creation');
  32.     }
  33.     customLoadingScreen.prototype.displayLoadingUI = function() {
  34.         console.log('customLoadingScreen loading')
  35.     };
  36.     customLoadingScreen.prototype.hideLoadingUI = function() {
  37.         window.document.getElementById('loadingScreen').style.display = 'none';
  38.     };
  39.     engine.loadingScreen = new customLoadingScreen();
  40.     // 初始化一个场景 scene
  41.     scene = new BABYLON.Scene(engine);
  42.     // 设置背景色透明
  43.     scene.clearColor = new BABYLON.Color4(0, 0, 0, 0);
  44.     // 初始化相机 camera
  45.     camera = new BABYLON.ArcRotateCamera('Camera', 0, 0, 0, new BABYLON.Vector3(0, 0, 0), scene);
  46.     /*
  47.         * 天空盒
  48.         */
  49.     // 创建天空盒
  50.     const skybox = BABYLON.Mesh.CreateBox('skyBox', 21000, scene),
  51.         skyboxMaterial = new BABYLON.StandardMaterial('skyboxMaterial', scene);
  52.     // 关闭掉材质的背面剔除(在盒子内部也可以看到盒子)
  53.     skyboxMaterial.backFaceCulling = false;
  54.     // 删除盒子上的反射光(天空不会反射太阳)
  55.     skyboxMaterial.disableLighting = true;
  56.     // 载入天空贴图(CubeTexture是贴图加载器,只能被应用到reflectionTexture)
  57.     skyboxMaterial.reflectionTexture = new BABYLON.CubeTexture('textures/sky', scene);
  58.     // 修改贴图模式(reflectionTexture是反射贴图,但我们需要天空盒贴图)
  59.     skyboxMaterial.reflectionTexture.coordinatesMode = BABYLON.Texture.SKYBOX_MODE;
  60.     skybox.material = skyboxMaterial;
  61.     // 设置天空盒跟随相机位置移动(盒子不会收缩)
  62.     skybox.infiniteDistance = true;
  63.     /*
  64.         * 3D模型
  65.         */
  66.     // 引入外部obj模型
  67.     BABYLON.SceneLoader.Append('babylon/1/', 'model.glb', scene, (object) => {
  68.         // 设置默认相机和灯光
  69.         scene.createDefaultCameraOrLight(true, true, true);
  70.         const light = new BABYLON.HemisphericLight('light', new BABYLON.Vector3(1, 1, 1));
  71.         // 设置灯光亮度
  72.         light.intensity = 1;
  73.         // 镜面反射 漫反射 环境光颜色调整
  74.         light.diffuse = new BABYLON.Color3(1, 1, 1);
  75.         light.specular = new BABYLON.Color3(1, 1, 1);
  76.         // 渲染模型后调整相机角度、位置、观察对象的三维坐标
  77.         scene.activeCamera.alpha = 0.0239;
  78.         scene.activeCamera.beta = 1.51;
  79.         scene.activeCamera.radius = 51.9;
  80.         scene.activeCamera.setPosition(new BABYLON.Vector3(51.85, 4.32, 4.45));
  81.         scene.activeCamera.setTarget(new BABYLON.Vector3(0.04, 1.4, 3.2));
  82.         // 设置横向旋转角度上下限
  83.         scene.activeCamera.upperBetaLimit = Math.PI * 0.5;
  84.         scene.activeCamera.lowerBetaLimit = 0;
  85.         // 设置镜头到目标位置距离半径的最大值
  86.         scene.activeCamera.upperRadiusLimit = 102;
  87.         // 设置鼠标滚轮灵敏度(数值越小灵敏度越高)
  88.         scene.activeCamera.wheelPrecision = 10;
  89.         // 控制鼠标平移相机镜头灵敏度(数值越小灵敏度越高|为0的时候取消平移操作)
  90.         scene.activeCamera.panningSensibility = 200;
  91.         // 存储当前相机状态
  92.         scene.activeCamera.storeState();
  93.         // 关闭自定义loading效果、展示标题、展示按钮
  94.         setTimeout(() => {
  95.             engine.hideLoadingUI();
  96.             emit('showTitle', true);
  97.             isRendering = true;
  98.         });
  99.     }, (progressEvent) => {
  100.         // 设置模型加载进度百分比
  101.         progress = (progressEvent.loaded / progressEvent.total).toFixed(0) * 100;
  102.     });
  103.     // 注册渲染循环 runRenderLoop
  104.     engine.runRenderLoop(() => {
  105.         scene.render();
  106.     });
  107.     // 在 DOM 更新后执行回调
  108.     nextTick(() => {
  109.         console.log('DOM 已更新');
  110.         // 注册resize监听事件
  111.         window.addEventListener('resize', engineResize);
  112.     });
  113. })
  114. beforeUnmount(() => {
  115.     // 离开页面销毁resize监听事件
  116.     window.removeEventListener('resize', engineResize, false);
  117. })
  118. </script>
  119. <template>
  120.     <div :class="isRendering ? 'containor bg' : 'containor'">
  121.         <div id="loadingScreen" class="flex_column_center">
  122.             <span class="loading"></span>
  123.             <span class="progress">{{ progress }}%</span>
  124.             <span class="text">3D模型加载中...</span>
  125.         </div>
  126.         <canvas id="canvas"></canvas>
  127.         <div class="btn_list flex_middle" v-if="isRendering">
  128.             <el-button type="warning" size="small" @click="reset"><i class="el-icon-refresh"></i> 重置</el-button>
  129.         </div>
  130.     </div>
  131. </template>
  132. <style lang="scss" scoped>
  133. /*scrollbar styles*/
  134. ::-webkit-scrollbar {
  135.     width: 12px;
  136.     height: 12px;
  137.     // border-radius: 100px;
  138. }
  139. ::-webkit-scrollbar-thumb {
  140.     // border-radius: 100px;
  141.     background: var(--color-ref-kl-primary10);
  142. }
  143. ::-webkit-scrollbar-track-piece {
  144.     // border-radius: 100px;
  145.     background: transparent;
  146. }
  147. ::-webkit-scrollbar-corner {
  148.     background: transparent;
  149. }
  150. /*scrollbar styles*/
  151. #app {
  152.     height: 100%;
  153.     color: #4b4b4b;
  154.     font-size: 13px;
  155.     font-family: 'Microsoft YaHei';
  156.     -webkit-font-smoothing: antialiased;
  157.     -moz-osx-font-smoothing: grayscale;
  158. }
  159. .flex {
  160.     display: flex;
  161. }
  162. .flex_center {
  163.     @extend .flex;
  164.     align-items: center;
  165. }
  166. .flex_left {
  167.     @extend .flex_center;
  168.     justify-content: flex-start;
  169. }
  170. .flex_right {
  171.     @extend .flex_center;
  172.     justify-content: flex-end;
  173. }
  174. .flex_middle {
  175.     @extend .flex_center;
  176.     justify-content: center;
  177. }
  178. .flex_column {
  179.     @extend .flex;
  180.     flex-direction: column;
  181.     justify-content: center;
  182. }
  183. .flex_column_center {
  184.     @extend .flex_column;
  185.     align-items: center;
  186. }
  187. .public_radius {
  188.     border-radius: 8px;
  189. }
  190. .echarts {
  191.     height: 100%;
  192.     overflow: hidden;
  193. }
  194. .containor {
  195.     position: relative;
  196.     width: 100%;
  197.     height: 100%;
  198.     overflow: hidden;
  199.     &.bg {
  200.         background-color: #8ecbe3;
  201.     }
  202.     #loadingScreen {
  203.         position: absolute;
  204.         width: 100%;
  205.         height: 100%;
  206.         .loading {
  207.             display: inline-block;
  208.             position: relative;
  209.             width: 100px;
  210.             height: 100px;
  211.             border: 8px solid #0934f7;
  212.             border-radius: 50%;
  213.             animation: rotate 1s linear infinite;
  214.             &:after {
  215.                 position: absolute;
  216.                 left: 50%;
  217.                 top: 50%;
  218.                 width: 110px;
  219.                 height: 110px;
  220.                 content: '';
  221.                 transform: translate(-50%, -50%);
  222.                 border: 8px solid transparent;
  223.                 border-bottom-color: #00eaff;
  224.                 border-radius: 50%;
  225.             }
  226.         }
  227.         .progress {
  228.             margin-top: -60px;
  229.             color: #6be031;
  230.             font-size: 16px;
  231.             font-weight: 700;
  232.         }
  233.         .text {
  234.             margin-top: 60px;
  235.             color: #f5a327;
  236.             font-size: 14px;
  237.         }
  238.     }
  239.     canvas {
  240.         width: 100%;
  241.         height: 100%;
  242.         outline: none;
  243.         cursor: pointer;
  244.     }
  245.     .btn_list {
  246.         position: absolute;
  247.         bottom: 0;
  248.         width: 100%;
  249.         height: 50px;
  250.         z-index: 99;
  251.         button {
  252.             margin: 0 15px 0 0;
  253.             &:last-child {
  254.                 margin: 0;
  255.             }
  256.         }
  257.     }
  258.     .video_main {
  259.         position: absolute;
  260.         top: 50%;
  261.         left: 50%;
  262.         transform: translate(-50%, -50%);
  263.         width: 800px;
  264.         height: 500px;
  265.         z-index: 999;
  266.         video {
  267.             outline: none;
  268.         }
  269.     }
  270. }
  271. </style>

Useful links

  • Official web site: www.babylonjs.com
  • Online playground to learn by experimentating
  • Online sandbox where you can test your .babylon and glTF scenes with a simple drag'n'drop
  • Online shader creation tool where you can learn how to create GLSL shaders
  • 3DS Max exporter can be used to generate a .babylon file from 3DS Max
  • Maya exporter can be used to generate a .babylon file from Maya
  • Blender exporter can be used to generate a .babylon file from Blender 3d
  • Unity 5 (deprecated) exporter can be used to export your geometries from Unity 5 scene editor(animations are supported)
  • glTF Tools by KhronosGroup

参见:

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.

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/104083
推荐阅读
相关标签
  

闽ICP备14008679号