Vue使用three.js的GLTFLoader导入外部模型绘制边界

该文章介绍了如何在Vue项目中利用three.js库结合GLTFLoader加载外部3D模型,并通过OrbitControls实现鼠标控制。文章详细展示了从引入依赖、加载模型、设置材质和边线,到解决模型无法显示的问题的完整过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、效果展示

threeJs渲染外部模型视频

二、项目引用

OrbitControlsGLTFLoader引入到项目中

import * as THREE from 'three' //引入three
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls' //引入鼠标控件
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader' //引入渲染模型的loader

三、加载three.js的方法

这里我大概分为了三个步骤
第一步:创建场景、相机、渲染器
第二步:创建要显示的东西,设置他的材质并放到场景里
第三步:渲染场景

// 渲染外部模型并画线
loadGLTF() {
            var loader = new GLTFLoader()
            console.log(loader) //这里是为了测试是否引用成功

            loader.load(
                '/static/model.glb', //这里一定要注意引用的路径
                (gltf) => {
                    var model = gltf.scene
                    // 递归遍历设置每个模型的材质,同时设置每个模型的边线
                    gltf.scene.traverse((obj) => {
                        if (obj.isMesh) {
                            // 模型材质重新设置
                            obj.material = new THREE.MeshLambertMaterial({
                                color: 0x004444,
                                transparent: true,
                                opacity: 0.5,
                            })
                            // 模型边线设置
                            const edges = new THREE.EdgesGeometry(obj.geometry)
                            const edgesMaterial = new THREE.LineBasicMaterial({
                                color: 0x00ffff,
                            })
                            const line = new THREE.LineSegments(
                                edges,
                                edgesMaterial
                            )
                            obj.add(line)
                        }
                    })
                    this.scene.add(model)
                },
                undefined,
                function (error) {
                    console.error(error)
                }
            )
        },

四、模型出不来解决办法

自己按照three.js官网上的步骤,可能模型渲染不出来,可能会出现以下的错误
在这里插入图片描述
如果出现以上的错误,可能是你引用的模型路径不对

loader.load(
                '/static/model.glb', //**这里的模型路径,一定要放在public/static里面,否则下面的代码执行不了**
                (gltf) => {
                    var model = gltf.scene
                    // 递归遍历设置每个模型的材质,同时设置每个模型的边线
                    gltf.scene.traverse((obj) => {
                        if (obj.isMesh) {
                            // 模型材质重新设置
                            obj.material = new THREE.MeshLambertMaterial({
                                color: 0x004444,
                                transparent: true,
                                opacity: 0.5,
                            })
                            // 模型边线设置
                            const edges = new THREE.EdgesGeometry(obj.geometry)
                            const edgesMaterial = new THREE.LineBasicMaterial({
                                color: 0x00ffff,
                            })
                            const line = new THREE.LineSegments(
                                edges,
                                edgesMaterial
                            )
                            obj.add(line)
                        }
                    })
                    this.scene.add(model)
                },
                undefined,
                function (error) {
                    console.error(error)
                }
            )

五、整体代码

// vue文件
<template>
    <div class="three-container">
        <div id="webgl"></div>
    </div>
</template>
<script>
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
export default {
    // 借助EdgesGeometry可以给模型设置一个模型边界线
    data() {
        return {
            scene: null,
            camera: null,
            renderer: null,
            mesh: null,
            geometry: null,
            material: null,
        }
    },
    mounted() {
        this.$nextTick(() => {
            this.init()
        })
        window.onresize = () => {
            // 重置渲染器输出画布canvas尺寸
            this.renderer.setSize(window.innerWidth, window.innerHeight)
            // 全屏情况下:设置观察范围长宽比aspect为窗口宽高比
            this.camera.aspect = window.innerWidth / window.innerHeight
            // 渲染器执行render方法的时候会读取相机对象的投影矩阵属性projectionMatrix
            // 但是不会每渲染一帧,就通过相机的属性计算投影矩阵(节约计算资源)
            // 如果相机的一些属性发生了变化,需要执行updateProjectionMatrix ()方法更新相机的投影矩阵
            this.camera.updateProjectionMatrix()
        }
    },
    methods: {
        init() {
            //第一步:创建场景、相机、渲染器
            this.scene = new THREE.Scene()
            this.loadGLTF() //渲染模型
            this.initCamera() //渲染相机
            this.initRender() //渲染器
            //第二步:创建要显示的立方体,设置它的属性材质,并把它放入场景里
            // this.initMesh()
            //创建光源
            this.initLight() //加载灯光
            //第三步:渲染场景

            this.animate() //加载渲染场景

            //鼠标操作三维场景
            var controls = new OrbitControls(
                this.camera,
                this.renderer.domElement
            ) //创建控件对象
        },
        loadGLTF() {
            var loader = new GLTFLoader()
            console.log(loader)

            loader.load(
                '/static/model.glb',
                (gltf) => {
                    var model = gltf.scene
                    // 递归遍历设置每个模型的材质,同时设置每个模型的边线
                    gltf.scene.traverse((obj) => {
                        if (obj.isMesh) {
                            // 模型材质重新设置
                            obj.material = new THREE.MeshLambertMaterial({
                                color: 0x004444,
                                transparent: true,
                                opacity: 0.5,
                            })
                            // 模型边线设置
                            const edges = new THREE.EdgesGeometry(obj.geometry)
                            const edgesMaterial = new THREE.LineBasicMaterial({
                                color: 0x00ffff,
                            })
                            const line = new THREE.LineSegments(
                                edges,
                                edgesMaterial
                            )
                            obj.add(line)
                        }
                    })
                    this.scene.add(model)
                },
                undefined,
                function (error) {
                    console.error(error)
                }
            )
        },
        animate() {
            // this.mesh.rotateY(0.01)
            // this.mesh.rotation.x += 0.005
            // this.mesh.rotation.y += 0.01
            this.renderer.render(this.scene, this.camera)
            requestAnimationFrame(this.animate)
        },
        initCamera() {
            this.camera = new THREE.PerspectiveCamera(
                75,
                window.innerWidth / window.innerHeight,
                1,
                1000
            )
            this.camera.position.set(-500, 350, 500)
            this.camera.lookAt(0, 0, 0) //指向this.mesh对应的位置
        },
        initMesh() {
            this.geometry = new THREE.BoxGeometry(150, 150, 150) //立方体

            this.material = new THREE.MeshBasicMaterial()
            this.mesh = new THREE.Mesh(this.geometry, this.material)

            //设置网格模型在三维空间中的位置坐标,默认是坐标原点
            this.mesh.position.set(100, 0, 0)

            this.scene.add(this.mesh)
        },
        initLight() {
            //点光源:两个参数分别表示光源颜色和光照强度
            // 参数1:0xffffff是纯白光,表示光源颜色
            // 参数2:1.0,表示光照强度,可以根据需要调整
            const pointLight = new THREE.DirectionalLight(0xffffff, 1.0)
            pointLight.position.set(100, 100, 100)
            this.scene.add(pointLight)
        },
        initRender() {
            this.renderer = new THREE.WebGLRenderer()

            //设置渲染器背景颜色
            //设置渲染器像素分辨值
            this.renderer.setPixelRatio(window.devicePixelRatio)
            this.renderer.setSize(window.innerWidth, window.innerHeight)
            document
                .getElementById('webgl')
                .appendChild(this.renderer.domElement)
        },
    },
}
</script>
<style scoped>
.three-container {
    position: absolute;
    top: 0;
    right: 0;
    left: 0;
    bottom: 0;
}
</style>

这里是所有的代码,其中方法都已提炼出来了,也有大量的注释

### 使用 Three.js 实现智慧城市的代码示例 在实现智慧城市的项目中,Three.js 提供了强大的工具来构建复杂的 3D 场景。以下是一个简单的示例代码片段,展示如何利用 Three.js 创建一个基础的城市模型。 #### 城市网格初始化 ```javascript // 初始化场景、相机和渲染器 const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); const renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); // 添加光源 const light = new THREE.AmbientLight(0xffffff, 0.8); // 白光强度为0.8 scene.add(light); // 构建建筑物 function createBuilding(x, y, z, width, height, depth) { const geometry = new THREE.BoxGeometry(width, height, depth); const material = new THREE.MeshStandardMaterial({ color: Math.random() * 0xffffff }); const building = new THREE.Mesh(geometry, material); building.position.set(x, height / 2, z); scene.add(building); } createBuilding(-5, 0, -5, 4, 10, 4); // 示例建筑之一 createBuilding(5, 0, 5, 6, 15, 6); // 示例建筑之二 camera.position.z = 20; // 渲染循环 function animate() { requestAnimationFrame(animate); renderer.render(scene, camera); } animate(); ``` 此代码展示了如何创建基本的建筑物以及设置灯光环境[^1]。为了进一步扩展功能,可以引入更复杂的数据结构或外部数据源(如 GeoJSON 文件),用于定义城市布局。 #### 高级功能集成 如果希望增加更多高级特性,例如动态天气效果或实时数据分析,则可参考其他开源项目的实践方法: - **three-cesium-examples** 提供了结合 Cesium 和 Three.js 的解决方案,适用于地理空间数据处理[^2]。 - 另外,在 Vue3+Three.js 的组合下,还可以借助 AntV G2 进行图表绘制,从而增强用户体验[^3]。 对于需要封装好的 SDK 组件的情况,某些资源提供了针对智慧城市需求定制的功能模块,比如城市边界的高亮显示等[^5]。 #### 小窗叠加显示 three.js 场景 当考虑多窗口或多视图的应用场合时,“小窗叠加”的方式能够有效提升界面灵活性。具体做法涉及调整摄像机视角范围及分层管理不同对象组[^4]。 --- ###
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

岩岩很哇塞!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值