vue3 + Babylon.js 实现3D场景

<script setup>

import { ref, getCurrentInstance, onMounted, beforeUnmount } from 'vue'

import * as BABYLON from '@babylonjs/core/Legacy/legacy' // 全部引入

import '@babylonjs/loaders' // 模型加载loader

import * 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.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.

相关推荐

  1. vue3 + Babylon.js 实现3D场景

    2024-02-14 11:54:01       40 阅读
  2. 用自动LOD简化3D网格【Babylon.js】

    2024-02-14 11:54:01       20 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-02-14 11:54:01       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-02-14 11:54:01       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-02-14 11:54:01       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-02-14 11:54:01       18 阅读

热门阅读

  1. 14.6 OpenGL图元装配和光栅化:多边形

    2024-02-14 11:54:01       25 阅读
  2. 14.5 OpenGL图元装配和光栅化:线段

    2024-02-14 11:54:01       28 阅读
  3. c语言练习

    2024-02-14 11:54:01       29 阅读
  4. MD5 哈希

    2024-02-14 11:54:01       25 阅读
  5. Git入门

    Git入门

    2024-02-14 11:54:01      29 阅读
  6. free pascal:fpwebview 组件简单易用

    2024-02-14 11:54:01       35 阅读
  7. QT自定义信号和槽

    2024-02-14 11:54:01       30 阅读
  8. 蓝桥杯每日一题----素数筛

    2024-02-14 11:54:01       30 阅读