返回 导航

Vue.js

hangge.com

Vue.js - 集成Babylon.js构建三维可视化场景教程3(加载OBJ模型)

作者:hangge | 2026-06-12 08:53
    前文我演示了如何使用 Babylon.js 加载 GLTF/GLB 模型(点击查看)。除了 GLTF/GLB 模型外,OBJ + MTL 是仍然常见的一种模型格式(尤其是在一些老的模型资源或 CAD 导出中)。下面我将通过样例演示如何加载 .obj 格式的模型。

三、加载 OBJ 模型

1,模型准备

(1)我们将模型文件放置项目的 public/models/obj 目录下,其中 textures 子文件夹中放置了 MTL 引用的纹理图片。

(2)打开 MTL 文件,查看纹理材质文件的相对路径设置是否正确。

2,样例代码

下面代码我使用 Babylon.js 将这个 obj 格式的木桌模型加载并展示。
<template>
    <div class="babylon-container">
        <div ref="canvasContainer" class="canvas-container">
            <canvas ref="renderCanvas" class="render-canvas"></canvas>
        </div>

        <!-- 加载状态 -->
        <div v-if="loading" class="loading-overlay">
            <div class="loader">加载中...</div>
        </div>

        <!-- 场景信息 -->
        <div class="scene-info">
            <p>物体数量: {{ objectCount }}</p>
            <p>FPS: {{ fps.toFixed(1) }}</p>
        </div>
    </div>
</template>

<script>
import * as BABYLON from 'babylonjs';
// 注册3D模型加载器
import 'babylonjs-loaders'

export default {
    name: "BabylonScene",
    data() {
        return {
            engine: null,
            scene: null,
            loading: true,
            error: null,
            objectCount: 0,
            fps: 60,
        };
    },
    mounted() {
        this.initBabylon();
    },
    beforeDestroy() {
        // 销毁组件时释放内存,防止内存泄漏
        if (this.engine) {
            this.engine.dispose();
        }
        window.removeEventListener("resize", this.onWindowResize);
    },
    methods: {
        initBabylon() {
            const canvas = this.$refs.renderCanvas;

            // 1. 初始化渲染引擎
            this.engine = new BABYLON.Engine(canvas, true,
                { preserveDrawingBuffer: true, stencil: true });

            // 2. 创建场景
            this.scene = this.createScene(this.engine, canvas);

            // 3. 隐藏加载遮罩
            //this.loading = false;

            // 4. 注册渲染循环
            this.engine.runRenderLoop(() => {
                this.scene.render();
                this.fps = this.engine.getFps();
            });

            // 5. 监听窗口调整大小
            window.addEventListener("resize", this.onWindowResize);

            // 6. 初始化场景统计
            this.updateSceneInfo();
        },

        createScene(engine, canvas) {
            const scene = new BABYLON.Scene(engine);

            // 设置背景颜色
            scene.clearColor = BABYLON.Color3.FromHexString('#aaaaaa').toColor4();

            // 添加摄像头 (ArcRotateCamera 允许用户绕着中心点旋转)
            const camera = new BABYLON.ArcRotateCamera(
                'camera',
                -Math.PI / 2,
                Math.PI / 3,
                7,
                BABYLON.Vector3.Zero(),
                scene
            );
            camera.attachControl(canvas, true);

            // 设置相机控制
            camera.wheelPrecision = 50;
            camera.lowerRadiusLimit = 2;
            camera.upperRadiusLimit = 50;

            // 添加灯光
            const light1 = new BABYLON.HemisphericLight(
                'light1',
                new BABYLON.Vector3(1, 1, 0),
                scene
            );

            const light2 = new BABYLON.DirectionalLight(
                'light2',
                new BABYLON.Vector3(0, -1, 1),
                scene
            );
            light2.position = new BABYLON.Vector3(5, 10, 5)
            light2.intensity = 0.3

            // 添加地面
            const ground = BABYLON.MeshBuilder.CreateGround(
                'ground',
                { width: 5, height: 5 },
                scene
            );
            const groundMaterial = new BABYLON.StandardMaterial('groundMaterial', scene);
            groundMaterial.diffuseColor = new BABYLON.Color3(0.8, 0.8, 0.8);
            ground.material = groundMaterial;

            // 加载 OBJ 模型
            BABYLON.SceneLoader.ImportMesh(
                null,               // null = 加载全部 mesh
                '/models/obj/',         // 模型目录
                'Wood_Table.obj',         // 文件名
                scene,
                (meshes, particleSystems, skeletons, animationGroups) => {

                    const modelMesh = meshes[0]; // 第一个网格通常是模型的根网格

                    // 调整模型大小和位置
                    modelMesh.scaling = new BABYLON.Vector3(4, 4, 4);
                    modelMesh.position = BABYLON.Vector3.Zero();

                    // 相机自动对准模型
                    camera.zoomOn(scene.meshes)

                    // 更新统计
                    this.$nextTick(() => {
                        this.objectCount = scene.meshes.length
                        this.loading = false
                    })
                }
            )

            return scene;
        },

        // 更新场景信息
        updateSceneInfo() {
            if (this.scene) {
                this.objectCount = this.scene.meshes.length;
            }
        },

        // 窗口大小变化处理
        onWindowResize() {
            if (this.engine) {
                this.engine.resize();
            }
        },
    },
};
</script>

<style scoped>
.babylon-container {
    position: relative;
    width: 100%;
    height: 100%;
}

.canvas-container {
    width: 100%;
    height: 100%;
    overflow: hidden;
}

.render-canvas {
    width: 100%;
    height: 100%;
    display: block;
    outline: none;
}

.loading-overlay {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.7);
    display: flex;
    justify-content: center;
    align-items: center;
    z-index: 1000;
}

.loader {
    color: white;
    font-size: 18px;
}

.scene-info {
    position: absolute;
    bottom: 20px;
    left: 20px;
    background: rgba(0, 0, 0, 0.6);
    color: white;
    padding: 10px 15px;
    border-radius: 5px;
    font-size: 14px;
}

.scene-info p {
    margin: 5px 0;
}
</style>

2,运行测试

(1)页面加载后除了会显示地面外,还会加载显示一个 obj 格式的木桌模型。

(2)按住鼠标左键拖动可以将视图绕模型旋转,使用滚轮可以缩放视图,按住右键拖动则可平移视角。
评论

全部评论(0)

回到顶部