vlambda博客
学习文章列表

Threejs 创建一个虚拟城市三维场景




前情回顾

前几篇文章大概讲述了threejs如何创建场景,创建几何体,纹理贴图等... 

本篇文章主要讲述threejs如何去搭建一个智慧城市虚拟场景(主要讲述如何去加载模型以及加载贴图) 

开发前准备

1. 从官方下载threejs的包,引入到项目中
2. 智慧城市模型一份( 本篇文章主要加载的 OBJ + MTL )
3. 具备前几章节讲到的一些基础知识(如果还不会的话请看前几篇文章哦)
4. 学习了解 MTLLoader.js 和 OBJLoader.js (加载模型主要用到这两个js)
5. vue 基础 ( 本人做的所有实例都是基于vue来开发的 )

先看一波效果吧 :

Threejs 创建一个虚拟城市三维场景


主要代码如下所示:
1. 引入 MTLLoader.js 和 OBJLoader.js 文件
// MTLimport { MTLLoader } from "../threeLibs/loaders/MTLLoader.js";// ObjLoaderimport { OBJLoader } from "../threeLibs/loaders/OBJLoader.js";
2. 参考官方的例子,首先加载MTL,再去加载对应的OBJ; 这里由于模型比较多,每一个都写一次加载感觉比较麻烦,所以对加载的方法做了封装,具体代码如下: 
// 模型按照数组的方式一一对应const list = [ // 一般建筑模型 ["./city/ny1.mtl", "./city/ny1.obj"], ["./city/ny2.mtl", "./city/ny2.obj"], ["./city/ny3.mtl", "./city/ny3.obj"], ["./city/ny4.mtl", "./city/ny4.obj"], ["./city/ny5.mtl", "./city/ny5.obj"], ["./city/ny6.mtl", "./city/ny6.obj"], ["./city/ny7.mtl", "./city/ny7.obj"], ["./city/ny8.mtl", "./city/ny8.obj"], ];
const list2 = [ // 其他模型 ["./city/multi_storied_01.mtl", "./city/multi_storied_01.obj"], ["./city/triangle_01.mtl", "./city/triangle_01.obj"], ["./city/white_house.mtl", "./city/white_house.obj"], ]; // 加载方法封装 // 加载MTL OBJ MOLoader(group, list) { list.forEach((urlList) => { const mtlLoader = new MTLLoader(); const objLoader = new OBJLoader(); mtlLoader.load(urlList[0], (materials) => { materials.preload(); //实例化obj加载方法 //设置mtl文件的材质 objLoader.setMaterials(materials); //文件名 objLoader.load(urlList[1], (object) => { object.position.set(6691, 604.35216, 2154.6111); group.add(object); }); }); }); },

3. 按照分组的方式加载模型,具体 api 方法自行查阅官方文档 :  http://www.webgl3d.cn/threejs/docs/
// 执行加载方法this.building = new THREE.Group();this.othersBuilding = new THREE.Group();this.scene.add(this.building);this.scene.add(this.othersBuilding);
this.MOLoader(this.building, list);this.MOLoader(this.othersBuilding, list2);

完整代码如下: 

<template> <div class> <div ref="content" style="position: absolute;top:0;left:0;right:0;bottom: 0;overflow: hidden"></div> <div class style="position: fixed;z-index: 999;background: #fff"> <span class="btn" @click="getCameraPosition">获取相机位置</span> </div> </div></template>
<script>// 引入threejsimport * as THREE from "../threeLibs/three.module.js";//鼠标控制import { OrbitControls } from "../threeLibs/controls/OrbitControls.js";// MTLimport { MTLLoader } from "../threeLibs/loaders/MTLLoader.js";// ObjLoaderimport { OBJLoader } from "../threeLibs/loaders/OBJLoader.js";
export default { components: {}, data() { return { // 创建一个场景 scene: null, // 创建一个相机 camera: null, // 创建一个渲染器 renderer: null, // 模型对象 mesh: null, // 平面 plane: null, // 点光源 point: null,
// step step: 0,
building: undefined, othersBuilding: undefined, }; },
mounted() { this.init(); }, methods: { // 初始化 init() { // 初始化容器 var content = this.$refs.content;
// 创建一个场景 this.scene = new THREE.Scene(); this.scene.background = new THREE.Color("#000"); this.scene.updateMatrixWorld(true);
// 创建几何体 // var geometry = new THREE.SphereGeometry(30, 50, 50); // // 纹理加载器 ( 此处加载贴图 ) // // var texture = new THREE.TextureLoader().load(require('./Earth.png'));
// // 几何体材质对象 // var material = new THREE.MeshLambertMaterial({ // color:"#000" // });
// // 创建网格模型对象 // this.mesh = new THREE.Mesh(geometry, material); // //设置几何体位置 // this.mesh.position.x = 0; // this.mesh.position.y = 10; // this.mesh.position.z = 0; // this.scene.add(this.mesh);
//创建环境光 var ambient = new THREE.AmbientLight(0xffffff); this.scene.add(ambient);
const directionalLight = new THREE.DirectionalLight(0xffffff, 2); directionalLight.position.set(50, 25, 10); directionalLight.castShadow = true; this.scene.add(directionalLight);
// 创建一个相机 this.camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 1000000 ); this.camera.position.set(6691, 604.35216, 2154.6111);
//照相机帮助线 // var cameraHelper = new THREE.CameraHelper( this.camera); // this.scene.add(cameraHelper);
//坐标轴辅助器,X,Y,Z长度30 // var axes = new THREE.AxesHelper(3000); // this.scene.add(axes); // 辅助网格 // let gridHelper = new THREE.GridHelper(3000, 3000); // this.scene.add(gridHelper);
// 创建一个平面 const planeGeometry = new THREE.PlaneGeometry(6000, 6000); const planeMaterial = new THREE.MeshLambertMaterial({ color: 0xffffff, side: THREE.DoubleSide, //两面 // THREE.FrontSide 、THREE.BackSide }); const plane = new THREE.Mesh(planeGeometry, planeMaterial); //水平面旋转并且设置位置 plane.rotation.x = -0.5 * Math.PI; plane.position.x = 0; plane.position.y = 0; plane.position.z = 0; // this.scene.add(plane);
// 创建渲染器 this.renderer = new THREE.WebGLRenderer({ // 开启抗锯齿 antialias: true, // 开启背景透明 alpha: true, }); this.renderer.setSize(window.innerWidth, window.innerHeight); //插入 dom 元素 content.appendChild(this.renderer.domElement);
this.controls = new OrbitControls(this.camera, this.renderer.domElement);
// this.controls.target.set(-8148, -604, -3919)
// this.camera.position.set(-10176, 1666, -1674) this.camera.position.set(6691, 604.35216, 2154.6111);
const list = [ // 一般建筑模型 ["./city/ny1.mtl", "./city/ny1.obj"], ["./city/ny2.mtl", "./city/ny2.obj"], ["./city/ny3.mtl", "./city/ny3.obj"], ["./city/ny4.mtl", "./city/ny4.obj"], ["./city/ny5.mtl", "./city/ny5.obj"], ["./city/ny6.mtl", "./city/ny6.obj"], ["./city/ny7.mtl", "./city/ny7.obj"], ["./city/ny8.mtl", "./city/ny8.obj"], ];
const list2 = [ // 其他模型 ["./city/multi_storied_01.mtl", "./city/multi_storied_01.obj"], ["./city/triangle_01.mtl", "./city/triangle_01.obj"], ["./city/white_house.mtl", "./city/white_house.obj"], ];
this.building = new THREE.Group(); this.othersBuilding = new THREE.Group(); this.scene.add(this.building); this.scene.add(this.othersBuilding);
this.MOLoader(this.building, list); // this.MOLoader(this.othersBuilding, list2)
const t = this; function render() { t.controls.update(); t.renderer.render(t.scene, t.camera); requestAnimationFrame(render); } render(); },
// 加载MTL OBJ MOLoader(group, list) { list.forEach((urlList) => { const mtlLoader = new MTLLoader(); const objLoader = new OBJLoader(); mtlLoader.load(urlList[0], (materials) => { materials.preload(); //实例化obj加载方法 //设置mtl文件的材质 objLoader.setMaterials(materials); //文件名 objLoader.load(urlList[1], (object) => { object.position.set(6691, 604.35216, 2154.6111); group.add(object); }); }); }); },
getCameraPosition() { console.log("控制器中心", this.controls.target); console.log("相机位置", this.camera.position); }, },};</script>
<style lang="scss" scoped>body { margin: 0; overflow: hidden; background: url("http://pic.sc.chinaz.com/files/pic/pic9/202001/zzpic22739.jpg") center no-repeat; background-size: cover;}</style>



本人,某个不知名小公司的前端小菜鸡,由于技术太菜,业余时间总是喜欢捣鼓一些花里胡哨的东西,一边学习一边分享,希望能够和大家一起成长,梦想着成为一位前端大大牛。



觉得本文对你有帮助?请分享给更多人或点个在看

关注==>>「前端开发爱好者」,一起提升前端技能!