Vue3+TypeScript项目实战——打造雨雪交加的智慧城市
个人简介
👀个人主页: 前端杂货铺
⚡开源项目: rich-vue3 (基于 Vue3 + TS + Pinia + Element Plus + Spring全家桶 + MySQL)
🙋♂️学习方向: 主攻前端方向,正逐渐往全干发展
📃个人状态: 研发工程师,现效力于中国工业软件事业
🚀人生格言: 积跬步至千里,积小流成江海
🥇推荐学习:🍖开源 rich-vue3 🍍前端面试宝典 🍉Vue2 🍋Vue3 🍓Vue2/3项目实战 🥝Node.js实战 🍒Three.js🌕个人推广:每篇文章最下方都有加入方式,旨在交流学习&资源分享,快加入进来吧
内容 | 参考链接 |
---|---|
THREE.JS 专栏 | Three.js 入门 |
文章目录
- 前言
- 项目概况
- 源码路径
- 文件结构与职责
- 写在最后
前言
大家好,这里是前端杂货铺。
这篇文章我们使用 Vue3+TypeScript+Three.js 等主流前端技术,打造 雨雪交加的智慧城市 项目。
three.js-雨雪交加的智慧城市
项目源码 => 请点击此处自行获取 [github] rich-vue3
如果此项目对你有些帮助,欢迎给个免费的 Star !!!(Thanks♪(・ω・)ノ)
项目概况
源码路径
该项目已被托管到 rich-vue3 中,具体源码在 rich-vue3 项目的 rich-vue3-webapp/src/views/city-three 路径。
文件结构与职责
下面是该项目涉及到文件的基本结构:
- base/index.css:页面的基础样式
- config/index.ts:存储项目中需要使用的颜色
- effect/…: 各种效果及特效,包括 天空盒子、扩散半球、扩散圆、旋转四棱锥、飞线、文字、雷达、雨、路径运动、烟雾、雪、建筑物外围线条、透明墙等
- enter/initCity.ts:初始化场景、 创建城市实例、监听浏览器变化、动画
- enter/city.ts:城市类,加载城市模型、初始化各种效果、点击聚焦和滑动滑轮缩放
- utils/index.ts:封装加载城市模型的方法
- index.vue:基本 UI,初始化项目的入口
城市类代码如下,在 initEffect() 方法中会创建很多种效果。
import { loadFBX } from "../utils"
import * as THREE from "three"
import * as TWEEN from "@tweenjs/tween.js"
import { SurroundLine } from "@/views/city-three/effect/surroundLine"
import { Background } from "@/views/city-three/effect/background"
import { Radar } from "../effect/radar"
import { Wall } from "../effect/wall"
import { Circle } from "@/views/city-three/effect/circle"
import { Ball } from "@/views/city-three/effect/ball"
import { Cone } from "@/views/city-three/effect/cone"
import { Fly } from "@/views/city-three/effect/fly"
import { Road } from "@/views/city-three/effect/road"
import { Font } from "@/views/city-three/effect/font"
import { Snow } from "@/views/city-three/effect/snow"
import { Rain } from "@/views/city-three/effect/rain"
import { Smoke } from "@/views/city-three/effect/smoke";export class City {private readonly scene: anyprivate readonly camera: anyprivate readonly controls: anyprivate tweenPosition: anyprivate tweenRotation: anyprivate flag: booleanprivate readonly height: { value: number }private readonly time: { value: number }private readonly top: { value: number }private readonly effect: {snow: anyrain: anysmoke: any}constructor(scene: object, camera: object, controls: any) {this.scene = scenethis.camera = camerathis.controls = controlsthis.flag = falsethis.tweenPosition = nullthis.tweenRotation = nullthis.height = {value: 5}this.time = {value: 0}this.top = {value: 0}// 雪、雨、烟雾this.effect = {snow: null,rain: null,smoke: null}this.loadCity()}loadCity() {// 加载城市模型,并且渲染到画布loadFBX("model/beijing.fbx").then((object: any) => {object.traverse((child: any) => {if (child.isMesh) {new SurroundLine(this.scene, child, this.height, this.time)}})this.initEffect()})}// 初始化效果,各个功能点都放在了这里initEffect() {new Background(this.scene)new Radar(this.scene, this.time)new Wall(this.scene, this.time)new Circle(this.scene, this.time)new Ball(this.scene, this.time)new Cone(this.scene, this.top, this.height)new Fly(this.scene, this.time)new Road(this.scene, this.time)new Font(this.scene)this.effect.snow = new Snow(this.scene)this.effect.rain = new Rain(this.scene)this.effect.smoke = new Smoke(this.scene)// 点击选择this.addClick()this.addWheel()}addClick() {let flag = truedocument.onmousedown = () => {flag = truedocument.onmousemove = () => {flag = false}}document.onmouseup = (event) => {if (flag) {this.clickEvent(event)}document.onmousemove = null}}// 场景跟随鼠标坐标缩放addWheel() {const body: HTMLElement = document.body// @ts-ignorebody.onmousewheel = (event: MouseEvent) => {// 鼠标当前的坐标const x = (event.clientX / window.innerWidth) * 2 - 1const y = -(event.clientY / window.innerHeight) * 2 + 1const value = 30const vector = new THREE.Vector3(x, y, 0.5)vector.unproject(this.camera)vector.sub(this.camera.position).normalize()// @ts-ignoreif (event.wheelDelta > 0) {this.camera.position.x += vector.x * valuethis.camera.position.y += vector.y * valuethis.camera.position.z += vector.z * valuethis.controls.target.x += vector.x * valuethis.controls.target.y += vector.y * valuethis.controls.target.z += vector.z * value} else {this.camera.position.x -= vector.x * valuethis.camera.position.y -= vector.y * valuethis.camera.position.z -= vector.z * valuethis.controls.target.x -= vector.x * valuethis.controls.target.y -= vector.y * valuethis.controls.target.z -= vector.z * value}}}// 点击聚焦clickEvent(event: MouseEvent) {// 归一化坐标(将鼠标位置归一化为设备坐标。x 和 y 方向的取值范围是 (-1 to +1))const x = (event.clientX / window.innerWidth) * 2 - 1const y = -(event.clientY / window.innerHeight) * 2 + 1// 创建设备坐标(三维)const standardVector = new THREE.Vector3(x, y, 0.5)// 转化为世界坐标 (将此向量 (坐标) 从相机的标准化设备坐标 (NDC) 空间投影到世界空间)const worldVector = standardVector.unproject(this.camera)// 做序列化const ray = worldVector.sub(this.camera.position).normalize()// 实现点击选中// 创建一个射线发射器,用来发射一条射线const raycaster = new THREE.Raycaster(this.camera.position, ray)// 返回射线碰撞到的物体const intersects = raycaster.intersectObjects(this.scene.children, true)let point3d = nullif (intersects.length) {point3d = intersects[0]}if (point3d) {const proportion = 3// 开始动画修改观察点const time = 1000this.tweenPosition = new TWEEN.Tween(this.camera.position).to({ x: point3d.point.x * proportion, y: point3d.point.y * proportion, z: point3d.point.y * proportion }, time).start()this.tweenRotation = new TWEEN.Tween(this.camera.rotation).to({ x: this.camera.rotation.x, y: this.camera.rotation.y, z: this.camera.rotation.z }, time).start()}}start(delta: number) {for (const key in this.effect) {// @ts-ignorethis.effect[key] && this.effect[key].animation()}if (this.tweenPosition && this.tweenRotation) {this.tweenPosition.update()this.tweenRotation.update()}this.height.value += 0.4if (this.height.value > 160) {this.height.value = 5}this.time.value += deltaif (this.top.value > 15 || this.top.value < 0) {this.flag = !this.flag}this.top.value += this.flag ? -0.8 : 0.8}
}
写在最后
由于本项目涉及到的代码较多,在本篇文章中就不一一讲解了,感兴趣的同学可以去下载项目源码自行学习,有问题的话可以评论区一起讨论交流~
好啦,本篇文章到这里就要和大家说再见啦,祝你这篇文章阅读愉快,你下篇文章的阅读愉快留着我下篇文章再祝!
参考资料:
- Three.js 官方文档
- WebGL+Three.js 入门与实战【作者:慕课网_yancy】
相关文章:

Vue3+TypeScript项目实战——打造雨雪交加的智慧城市
个人简介 👀个人主页: 前端杂货铺 ⚡开源项目: rich-vue3 (基于 Vue3 TS Pinia Element Plus Spring全家桶 MySQL) 🙋♂️学习方向: 主攻前端方向,正逐渐往全干发展 …...

经典游戏案例:植物大战僵尸
学习目标:植物大战僵尸核心玩法实现 游戏画面 项目结构目录 部分核心代码 using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement; using Random UnityEngine.Random;public enum Z…...

Go 与 Java 字符编码选择:UTF-8 与 UTF-16 的较量
💝💝💝欢迎莅临我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…...

vscode+picgo+gitee实现Markdown图床
vscode中编辑Markdown文件,复制的图片默认是保存在本地的。当文档上传csdn时,会提示图片无法识别 可以在gitee上创建图床仓库,使用picgo工具上传图片,在Markdown中插入gitee链接的方式来解决该问题。 一、 安装picgo工具 1.1 v…...
【thinkphp问题栏】tp5.0分页技巧
一、调用内置方法paginate thinkphp内置了一个paginate方法支持分页功能 该方法位于library\think\db\Query.php内 /*** 分页查询* param int|array $listRows 每页数量 数组表示配置参数* param int|bool $simple 是否简洁模式或者总记录数* param array $config 配…...

获取时间戳是使用System.currentTimeMillis()还是使用new Date().getTime()(阿里开发规范)?
1.阿里规范 在阿里的Java开发手册中强制要求使用System.currentTimeMillis() 2.为什么(源码详解) new Date().getTime()它实际上也是调用的System.currentTimeMillis(),源码分析。 这个fastTime是它的成员变量,在new Date()的时候就被赋值了。 扩展一…...

仿饿了么加入购物车旋转控件 - 自带闪转腾挪动画 的按钮
, mWidth - mCircleWidth, mHeight - mCircleWidth); canvas.drawRoundRect(rectF, mHintBgRoundValue, mHintBgRoundValue, mHintPaint); //前景文字 mHintPaint.setColor(mHintFgColor); // 计算Baseline绘制的起点X轴坐标 int baseX (int) (mWidth / 2 - mHintPaint.m…...
Docker部署nacos集群
docker拉取nacos镜像,本文使用nacos2.0.3 三台服务器都要执行以下命令 docker pull nacos/nacos-server:v2.2.0准备挂载的日志目录和配置文件目录 日志:mkdir /usr/local/software/nacos/logs 配置文件:/usr/local/software/nacos/conf在配…...
centos查找文件 及 操作写入的进程
du -sh * 查看目录空间占用、发现大文件,确定进程,结束 yum install lsof 安装lsof 查看文件写入的 进程 2. lsof /root/.influxdbv2/engine/data/bab49411e5f7cbce/autogen/1/000000036-000000002.tsm COMMAND PID USER FD TYPE …...
构建高可用Java微服务架构的秘籍
构建高可用Java微服务架构的秘籍 大家好,我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿! 随着云计算和分布式系统的快速发展,微服务架构已成为构建大型应用…...

VBA学习(18):VBA制作任意工作表均可使用的聚光灯
在需要制作聚光的工作簿,按<ALTF11>组合键,打开VBE编辑器。在右侧[工程资源管理器窗格]选中ThisWorkbook模块,将以下代码复制粘贴到该模块的代码窗口。 Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal Target …...

【STM32-启动文件 startup_stm32f103xe.s】
STM32-启动文件 startup_stm32f103xe.s ■ STM32-启动文件■ STM32-启动文件主要做了以下工作:■ STM32-启动文件指令■ STM32-启动文件代码详解■ 栈空间的开辟■ 栈空间大小 Stack_Size■ .map 文件的详细介绍■ 打开map文件 ■ 堆空间■ PRESERVE8 和 THUMB 指令…...

51学习记录(一)——51介绍及震动感应灯
文章目录 前言一、STC89C522.内部结构及引脚 二、继电器原理及震动传感器原理三、项目搭建及实现 前言 一个学习嵌入式的小白~ 有问题评论区或私信指出 提示:以下是本篇文章正文内容,下面案例可供参考 一、STC89C52 1.简介 所属系列:51单…...

2024GLEE生活暨教育(上海)博览会,8月20-22日,国家会展中心(上海)
2024GLEE生活暨教育(上海)博览会将于8月20-22日在中国国家会展中心(上海)举行,博览会总面积近万平方米,设有美好生活和教育产品两大主力展区,全面覆盖婴幼儿、学龄前、小学、初中、高中、大学、中年、老年各个年龄段的…...

debug调试高级功能 断点、布局 及Android Studio常用快捷按键使用详情
文章目录 debug断点篇:打临时断点(只用一次):alt断点条件断点:在断点上,点击右键,在Condition那里,设置我们需要的值,循环就会自动停到我们设置的那个值那里依赖断点&…...

51单片机STC89C52RC——6.1 中断系统
一,文字层面理解 反正我看下面的几段文字时脑壳没有正常运转。一个头几个大 中断系统是为使CPU具有对外界紧急事件的实时处理能力而设置的。 当中央处理机CPU正在处理某件事的时候外界发生了紧急事件请求,要求CPU暂停当前的工作,转而去处理这…...
Redis源码学习:高性能Hash表的设计与实现
哈希表(Hash)是Redis数据库的数据类型之一,理解哈希表的实现对于掌握Redis非常重要。这篇文章,从哈希冲突和哈希扩展这两个角度,来一步步讲解Redis哈希表的工作原理。 什么是哈希表? 哈希表是一种通过哈希…...
如何防范常见的数据库安全问题
随着数据量的增加和系统的复杂性提高,数据库可能面临多种安全威胁,包括未授权访问、数据泄露、注入攻击等。 1. 未授权访问 未授权访问是指,未经授权的用户对数据库的内容进行访问。这会导致数据泄露、数据篡改或其他安全事故。 针对未授权访问的防范措施如下。 (1)强化…...
[Day 19] 區塊鏈與人工智能的聯動應用:理論、技術與實踐
區塊鏈的數據透明性 區塊鏈技術作為一種分布式賬本技術,因其去中心化、不可篡改和高度透明的特性,已經在各行各業中得到了廣泛應用。在本文中,我們將深入探討區塊鏈的數據透明性,包括其原理、實現方法及相關代碼示例,…...

【Hadoop学习笔记】认识Hadoop
认识Hadoop 从网上找的课程做的笔记,有些图是自己理解画的,可能不正确,可以作为参考,有疑问的地方请直接指出,共同交流。 Hadoop是由Apache基金会开发的一个分布式系统基础架构,主要解决海量数据的存储和海…...
零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?
一、核心优势:专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发,是一款收费低廉但功能全面的Windows NAS工具,主打“无学习成本部署” 。与其他NAS软件相比,其优势在于: 无需硬件改造:将任意W…...

【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器
一.自适应梯度算法Adagrad概述 Adagrad(Adaptive Gradient Algorithm)是一种自适应学习率的优化算法,由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率,适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...

屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!
5月28日,中天合创屋面分布式光伏发电项目顺利并网发电,该项目位于内蒙古自治区鄂尔多斯市乌审旗,项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站,总装机容量为9.96MWp。 项目投运后,每年可节约标煤3670…...
【算法训练营Day07】字符串part1
文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接:344. 反转字符串 双指针法,两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...

uniapp微信小程序视频实时流+pc端预览方案
方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度WebSocket图片帧定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐RTMP推流TRTC/即构SDK推流❌ 付费方案 (部分有免费额度&#x…...
大学生职业发展与就业创业指导教学评价
这里是引用 作为软工2203/2204班的学生,我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要,而您认真负责的教学态度,让课程的每一部分都充满了实用价值。 尤其让我…...

SAP学习笔记 - 开发26 - 前端Fiori开发 OData V2 和 V4 的差异 (Deepseek整理)
上一章用到了V2 的概念,其实 Fiori当中还有 V4,咱们这一章来总结一下 V2 和 V4。 SAP学习笔记 - 开发25 - 前端Fiori开发 Remote OData Service(使用远端Odata服务),代理中间件(ui5-middleware-simpleproxy)-CSDN博客…...
Caliper 配置文件解析:fisco-bcos.json
config.yaml 文件 config.yaml 是 Caliper 的主配置文件,通常包含以下内容: test:name: fisco-bcos-test # 测试名称description: Performance test of FISCO-BCOS # 测试描述workers:type: local # 工作进程类型number: 5 # 工作进程数量monitor:type: - docker- pro…...

【Linux系统】Linux环境变量:系统配置的隐形指挥官
。# Linux系列 文章目录 前言一、环境变量的概念二、常见的环境变量三、环境变量特点及其相关指令3.1 环境变量的全局性3.2、环境变量的生命周期 四、环境变量的组织方式五、C语言对环境变量的操作5.1 设置环境变量:setenv5.2 删除环境变量:unsetenv5.3 遍历所有环境…...

Golang——7、包与接口详解
包与接口详解 1、Golang包详解1.1、Golang中包的定义和介绍1.2、Golang包管理工具go mod1.3、Golang中自定义包1.4、Golang中使用第三包1.5、init函数 2、接口详解2.1、接口的定义2.2、空接口2.3、类型断言2.4、结构体值接收者和指针接收者实现接口的区别2.5、一个结构体实现多…...