前言 趁着双休日和大家一起来学习一下智慧城市是怎么基本实现的,和大家一起学习,努力做大做强。
Vue创建智慧城市项目并配置glsl写法支持 创建项目 根据npm版本创建vite项目,如果没有vite或者想了解更多可以前往vite官网 查看
查看npm版本
创建项目 1 npm create vite@latest threeapp -- --template vue
打开项目并安装依赖运行
配置glsl写法支持 新建测试的glsl文件 在src目录下新建一个shader文件夹,然后新建一个test文件夹,再创建Vertex.glsl的顶点着色器文件
配置vite支持@符号 此时,项目是不支持@符号的,我们只需要添加以下代码
1 2 3 4 5 6 7 import { resolve } from 'path' resolve : { alias : { "@" : resolve (__dirname, 'src' ), }, extensions : ['.js' , '.json' , '.glsl' ] }
这样,我们的项目就支持了@符号了
在helloword中导入glsl文件 1 2 import testVertex from "@/shader/test/Vertex.glsl" ;console .log (testVertex);
我们可以看到,在浏览器中,他并不支持,浏览器显示了语法错误 这是因为默认把这个当成了js文件造成的
让vite识别字符串文件 那该如何解决呢,其实很简单,我们只需要告诉vite,我们导入的字符串就行了,导入文件后缀名加上raw
1 import testVertex from "@/shader/test/Vertex.glsl?raw" ;
拓展webpack配置 这里我们拓展一下,如果是使用webpack脚手架,让支持glsl文件,那么就稍微比较麻烦了,配置如下 首先安装一个webpack-glsl-loader
1 npm i webpack-glsl-loader --save -dev
接下来在vue.config.js中配置
1 2 3 4 5 6 7 8 9 10 configureWebpack :(config )=> { config.module .rules .push ({ text :/\.glsl$/ , use :[ { loader :'webpack-glsl-loader' } ] }) }
ok,这样我们就可以在vue项目中使用glsl文件了
下面开始我们的项目基础代码结构分解,我们写代码的,不能把所有代码都写到一个组件里面去,这样上拉下拉太累了,所以要学会封装
项目基础代码结构分解 基础配置 安装three和gsap 1 2 npm install three npm install gsap
在package.json中可以看到three就是安装成功了
设置全局样式 清除style.css中原有样式,设置margin,padding都为0
创建一个场景组件Scene.vue,并配置基础代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 <template> <div class="scene" ref="sceneDiv"> </div> </template> <script setup> import {onMounted,ref} from 'vue'; import * as THREE from 'three'; // 导入轨道控制器 import { OrbitControls } from "three/examples/jsm/controls/OrbitControls"; // 场景元素div let sceneDiv = ref(null); // 1.创建场景 const scene = new THREE.Scene() // 2.创建相机 const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000) // 设置相机位置 camera.position.set(0, 0, 10) // 添加相机 scene.add(camera) // 初始化渲染器 const renderer = new THREE.WebGLRenderer(); //设置渲染的尺寸大小 renderer.setSize(window.innerWidth, window.innerHeight); //当前是平面的,让平面立体起来,使用控制器controls // 创建轨道控制器 const controls = new OrbitControls(camera, renderer.domElement); controls.enableDamping=true // 添加坐标轴辅助器 const axesHelper = new THREE.AxesHelper(5); scene.add(axesHelper) // 监听画面的变化,更新渲染的画面 window.addEventListener("resize", () => { // console.log("画面变化了") // 更新摄像头 camera.aspect = window.innerWidth / window.innerHeight; // 更新摄像机的投影矩阵 camera.updateProjectionMatrix(); // 更新渲染器 renderer.setSize(window.innerWidth, window.innerHeight); // 设置渲染器的像素比 renderer.setPixelRatio(window.devicePixelRatio) }) onMounted(()=>{ // 将webgl渲染的canvas内容添加到body上 sceneDiv.value.appendChild(renderer.domElement); animate(); }) function animate() { controls.update() requestAnimationFrame(animate); // 使用渲染器渲染相机看这个场景的内容渲染出来 renderer.render(scene, camera); } </script> <style> .scene{ width: 100vw; height: 100vh; position: fixed; z-index:100; left:0; top:0; } </style>
在App.vue中导入Scene.vue
拆分代码 接下来我们把代码拆分出去,让我们的主函数组件更加的简洁 拆分成如下结构 按照图片中目录结构的顺序,我把每个文件的代码贴一下
1 2 3 4 5 6 7 8 9 10 11 12 13 import camera from "./camera" ;import renderer from "./renderer" ;import controls from "./controls" ;import scene from "./scene" ;function animate ( ) { controls.update (); requestAnimationFrame (animate); renderer.render (scene, camera); } export default animate;
1 2 3 4 5 import * as THREE from "three" ;const axesHelper = new THREE .AxesHelper (5 );export default axesHelper;
1 2 3 4 5 6 7 8 9 import * as THREE from 'three' ;const camera = new THREE .PerspectiveCamera (75 , window .innerWidth / window .innerHeight , 0.1 , 1000 )camera.position .set (0 , 0 , 10 ) export default camera;
1 2 3 4 5 6 7 8 9 10 11 12 13 import { OrbitControls } from "three/examples/jsm/controls/OrbitControls" ;import camera from "./camera" ;import renderer from "./renderer" ;const controls = new OrbitControls (camera, renderer.domElement );controls.enableDamping = true ; export default controls;
1 2 3 export default function createMesh ( ) { console .log ("111" ) }
1 2 3 4 5 6 7 import { GUI } from "three/examples/jsm/libs/lil-gui.module.min.js" ;const gui = new GUI ();export default gui;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import camera from "./camera" ;import renderer from "./renderer" ;camera.aspect = window .innerWidth / window .innerHeight ; camera.updateProjectionMatrix (); window .addEventListener ("resize" , () => { camera.aspect = window .innerWidth / window .innerHeight ; camera.updateProjectionMatrix (); renderer.setSize (window .innerWidth , window .innerHeight ); renderer.setPixelRatio (window .devicePixelRatio ); });
1 2 3 4 5 6 7 8 9 10 11 import * as THREE from 'three' ;const renderer = new THREE .WebGLRenderer ();renderer.setSize (window .innerWidth , window .innerHeight ); renderer.shadowMap .enabled = true ; export default renderer;
1 2 3 4 5 6 import * as THREE from 'three' ;const scene = new THREE .Scene ();export default scene;
然后在scene.vue中导入这些文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 <template> <div class="scene" ref="sceneDiv"> </div> </template> <script setup> import {onMounted,ref} from 'vue'; import * as THREE from 'three'; // 导入场景 import scene from "@/three/scene" // 导入相机 import camera from "@/three/camera" // 导入gui对象 import gui from "@/three/gui" // 导入renderer对象 import renderer from "@/three/renderer" // 导入辅助坐标轴 import axesHelper from "@/three/axesHelper"; // 导入控制器 import controls from "@/three/controls"; // 导入每一帧的执行函数 import animate from "@/three/animate"; // 初始化调整屏幕 import "@/three/init"; // 导入创建物体函数 import createMesh from "@/three/createMesh"; // 场景元素div let sceneDiv = ref(null); // 添加相机 scene.add(camera) // 添加辅助坐标轴 scene.add(axesHelper); createMesh(); onMounted(()=>{ // 将webgl渲染的canvas内容添加到body上 sceneDiv.value.appendChild(renderer.domElement); animate(); }) </script> <style> .scene{ width: 100vw; height: 100vh; position: fixed; z-index:100; left:0; top:0; } </style>
我们可以看到,代码依旧是正常可以执行的