返回 导航

Vue.js

hangge.com

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

作者:hangge | 2026-06-13 10:40
    STLStereolithography)是 3D 打印常用的文件格式,用于表示三维模型的表面几何形状。本文我将接着演示如何在 Vue 中使用 Babylon.js 加载 STL 模型。

四、加载 STL 模型

1,模型准备

我们将需要加载的 STL 模型文件放置项目的 public/models/stl 目录下。

2,样例代码

下面代码我使用 Babylon.js 加载这个 stl 格式的鸭舌帽模型。
提示:由于 STL 格式通常只包含几何体数据(三角形面片),不包含材质、颜色或动画,因此在加载后,我们通常需要手动为它赋予一个材质,否则它可能看起来只是一个纯色或黑色的形状。
<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,
                2,
                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: 1, height: 1 },
                scene
            );
            const groundMaterial = new BABYLON.StandardMaterial('groundMaterial', scene);
            groundMaterial.diffuseColor = new BABYLON.Color3(0.8, 0.8, 0.8);
            ground.material = groundMaterial;

            // 加载 STL 模型
            BABYLON.SceneLoader.ImportMesh(
                null,
                '/models/stl/',
                'Cap.stl',
                scene,
                (meshes) => {
                    // STL 通常只有一个 mesh
                    const mesh = meshes[0]

                    // STL 没材质,手动给一个
                    const mat = new BABYLON.StandardMaterial('stlMat', scene)
                    mat.diffuseColor = new BABYLON.Color3(0.6, 0.6, 0.6)
                    mesh.material = mat

                    // 常见 STL 需要缩放(毫米 → 米)
                    mesh.scaling.setAll(0.001)

                    // 位置修正
                    mesh.position.y = 0.1

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

                    // 更新统计
                    this.$nextTick(() => {
                        this.objectCount = scene.meshes.length
                        this.loading = false
                    })
                },
                null,
                (scene, message) => {
                    console.error('STL 加载失败:', message)
                }
            )

            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>

3,运行测试

(1)页面加载后除了会显示地面外,还会加载显示一个鸭舌帽 STL 模型。

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

全部评论(0)

回到顶部