ThreeJs-16智慧城市项目(重磅以及未来发展ai)
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144120472-1655138301.gif" alt="GIF" loading="lazy"></p><p><strong>项目源码:https://gitee.com/hq8466/threecity-com</strong></p>
<p><strong>写在前面:很早就弄完了的,只是一直说挑个黄道吉日发上来,托了这么久也没选到什么节日,今天天气不错就发了吧,然后后面可能更新技术方面的东西就减少次数了,现在ai发展情况下,学习成本贬低,很多东西并不需要钻研太深了,你只需要钻研一个东西ai,这段时间也简单的研究了下一些在人工智能蓬勃发展时代下,对于编程有些什么冲击,就我目前的研究成果,我一个人可以做到不只是前端的活,包括前后端,threejs,3D建模等等都可以一个人完成,所以后面可以陆续发一些如何ai编程的东西上来,当然学习不止,因为不管是什么你都得会,因为出现问题还得通过你的基础去解决。</strong></p>
<h1 id="一vue创建智慧城市项目并配置glsl写法支持">一.Vue创建智慧城市项目并配置glsl写法支持</h1>
<p>这里先说一个问题,关于遇到一格式化就出现vue3一格式化就这个以前也遇到过</p>
<p>就是格式化插件的问题我用的vetur,有点问题换成就可以了</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144116955-325751990.png" alt="image-20241229165140953" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144116658-1253896372.png" alt="image-20241229165053033" loading="lazy"></p>
<p><strong>后续又知道了其实vetur还带有代码提示,还不能删用处挺大,那么继续用vetur可以加一个ts的语言</strong></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144115642-895665424.png" alt="image-20241229172104767" loading="lazy"></p>
<p>第二个问题,后面会写特效,所以肯定要用shader,但是发现项目并不支持</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144115354-376058023.png" alt="image-20241229165253164" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144115087-381376274.png" alt="image-20241229165300570" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144114802-2097352739.png" alt="image-20241229165308730" loading="lazy"></p>
<p>不管是webpack还是vite都要先配置一下对于glsl文件的支持,这里是webpack</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144114508-819953200.png" alt="image-20241229165847146" loading="lazy"></p>
<h1 id="二项目基础代码结构分解">二.项目基础代码结构分解</h1>
<p>首先我们有一个组件,专门搭建场景</p>
<p>首先把一些该先声明的three直接放在setup函数里面</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144114217-165189592.png" alt="image-20241229171658826" loading="lazy"></p>
<p>这里要注意以前是放在body,现在是放在这个组件里面</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144113927-2069943455.png" alt="image-20241229171716026" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144113636-1838758643.png" alt="image-20241229171837777" loading="lazy"></p>
<p>在onmounted钩子里面拿到div并把渲染器给进去</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144113344-1421372021.png" alt="image-20241229175146231" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144113054-615320868.png" alt="image-20241229175141600" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144112770-1701054597.png" alt="image-20241229175153764" loading="lazy"></p>
<p>当然真实场景也不会把所有这些东西全放在scripts里面,一般会分模块来放,创建一个three文件夹</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144112485-646098926.png" alt="image-20241229202455899" loading="lazy"></p>
<p>就是把各模块封装导出,在该引用的地方导入</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144112129-1973929885.png" alt="image-20241229202520008" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144108393-1132656998.png" alt="image-20241229202526761" loading="lazy"></p>
<p>这里面有两个特殊的,一个是init放一些不需要导出,一开始就可以初始化的东西</p>
<p>还有一个是后面会创建各种各样的物体,所以其实可以封装一个传参数进去返回各种物体的函数,createMesh这里还没有封装</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144108106-1762875184.png" alt="image-20241229202629071" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144107780-718928206.png" alt="image-20241229202635905" loading="lazy"></p>
<p>这样下来在组件里面就没有太多写的了</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144107446-1602654112.png" alt="image-20241229202704459" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144107138-2114987259.png" alt="image-20241229202719291" loading="lazy"></p>
<h1 id="三生成城市建筑模型">三.生成城市建筑模型</h1>
<p>推荐一个网站https://cadmapper.com/pro/home</p>
<p>可以根据框出来的范围,生成城市模型,直接导出,<strong>但是导出来是一个.dxf的文件</strong></p>
<p>需要下载一个软件 <strong>Autodesk</strong>3dsmax的软件把这个文件导入,导出可以选择.dxf或者直接一个白模.fbx格式导出</p>
<p>选择要导出的模型</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144106821-1466431560.png" alt="QQ_1735540902618" loading="lazy"></p>
<p>导出后再次用Blender导入,然后可以跳下位置按G键,x轴就是x键,y轴移动就是y键最后就可以通过Blender导出为glb格式</p>
<p>加载模型,再次封装结构</p>
<p>再次来个专门建物体的文件夹</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144106522-2055880544.png" alt="image-20241230150052901" loading="lazy"></p>
<p>createmesh就调用函数</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144106230-850833325.png" alt="image-20241230150107460" loading="lazy"></p>
<p>每个物体声明自己的函数</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144105951-1494439273.png" alt="image-20241230150121346" loading="lazy"></p>
<p>这里虽然模型加载进来了,但是发现没有出现,这是因为模型的材质颜色本身就是黑色没有颜色,所以这里需要改一下所有物体的材质颜色</p>
<p><strong>traverse函数拿到该模型场景下面所有的子元素</strong></p>
<p>只有是要展示的物体时才改他的材质,并且这里颜色不能直接修改</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144105640-1414002660.png" alt="QQ_1735542368162" loading="lazy"></p>
<p>此时如果发现一进来因为模型很大,想远点看</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144105335-1325220038.png" alt="QQ_1735543119934" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144104983-591639955.png" alt="QQ_1735543134838" loading="lazy"></p>
<h1 id="四城市模型科技感渐变效果">四.城市模型科技感渐变效果</h1>
<p>要弄特效肯定需要shader</p>
<p>创建一个文件夹这个函数传值材质,对这个材质着色器修改都写在里面</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144104709-1693517981.png" alt="image-20241230171738525" loading="lazy"></p>
<p>在刚才创建模型那里把材质传进来</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144104383-1233623528.png" alt="QQ_1735550283465" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144103988-1930424788.png" alt="QQ_1735550312211" loading="lazy"></p>
<p>渐变效果:由城市的底部到顶部给城市的建模建筑物来一个渐变的颜色</p>
<p><strong>这里大概的一个思路是这样的,我可以通过一个方法得到整个城市建模的落差,也就是最高度减去最低得到城市的落差高度,这个时候把每个建筑物的材质传进着色器函数,修改他们的着色器,会用到之前的一个混合,前三维变量就是它本身的颜色,第四维变量就是设置想要建筑物最高的颜色,实现一个过渡渐变,而混合就是把这两个颜色混合在一起,然后混合的比例就是通过建筑物的y轴高度/刚才的落差的百分比</strong></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144103668-1272406028.png" alt="image-20241230222818530" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144103356-1890174363.png" alt="image-20241230223112799" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144103046-1196623434.png" alt="image-20241230223119389" loading="lazy"></p>
<p>这个时候就可以拿到真个城市建模高度差</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144102724-327242337.png" alt="image-20241230225639383" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144102357-2094768204.png" alt="image-20241230225648942" loading="lazy"></p>
<h1 id="五多层着色器特效合并与城市光圈扩散效果">五.多层着色器特效合并与城市光圈扩散效果</h1>
<h2 id="51布局">5.1布局</h2>
<p>大概实现效果就是沿着城市中心又一圈一圈往外扩散的光圈</p>
<p>先重构一下布局,在之前的方法里面对城市建模进行了渐变但那只是一个特效所以可以封装成一个函数传需要的参数进来就可以了</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144102033-1016095402.png" alt="image-20250101130400155" loading="lazy"></p>
<p>这里再封装一个光圈扩散的效果</p>
<p><strong>需要注意的是我们为了对片段着色器进行无限往后面添加代码,可以一直往后面添加一个这个标识</strong></p>
<p>之前是直接在最后一行代码添加</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144101735-949653566.png" alt="image-20250101130547785" loading="lazy"></p>
<p>直接在最后一行添加一个注释</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144101392-31880431.png" alt="image-20250101130713456" loading="lazy"></p>
<p>后面要改的话</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144101102-52046707.png" alt="image-20250101130752095" loading="lazy"></p>
<h2 id="52逻辑">5.2逻辑</h2>
<p>大概的一个逻辑就是我们需要设置一个中心顶点的变量以及时间和扩散的条带宽度</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144100803-39158497.png" alt="image-20250101134847083" loading="lazy"></p>
<p><strong>难点逻辑理解</strong></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144100472-1039137271.png" alt="image-20250101141038510" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144059989-1484761261.png" alt="image-20250101135948605" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144054193-2142253676.gif" alt="GIF" loading="lazy"></p>
<h1 id="六直线光带掠过城市效果">六.直线光带掠过城市效果</h1>
<h2 id="61-x轴">6.1 x轴</h2>
<p>想实现直线扫过的效果其实跟刚才差不多,只不过没有了半径中心点这些的计算,然后覆盖范围就变成了x轴或者y轴等等</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144052525-463358887.png" alt="image-20250101143331363" loading="lazy"></p>
<p>但是要注意此时光线是从中间出发</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144052009-147071639.gif" alt="GIF" loading="lazy"></p>
<p>要实现从底部出发,可以修改时间,因为时间是会和x轴相减的</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144051587-466536911.png" alt="image-20250101143518374" loading="lazy"></p>
<p>但是还要同步修改动画需要走完的时间值</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144051319-1883125940.png" alt="image-20250101143537491" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144050626-884925724.gif" alt="GIF" loading="lazy"></p>
<p>如果想斜着来,那就同时修改x轴和z轴</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144050082-2118159310.png" alt="image-20250101143646175" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144047992-208052727.gif" alt="GIF" loading="lazy"></p>
<h2 id="62-y轴">6.2 y轴</h2>
<p>那么y轴其实也就是从下到上可以实现别样的效果</p>
<p>最开始的值呢就从0开始到500</p>
<p>然后把position变成y,动画时间可以改短点</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144047147-1975684910.png" alt="image-20250101144335636" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144045102-1747994363.gif" alt="GIF" loading="lazy"></p>
<h1 id="七利用tube特性生成带纹理图案飞线">七.利用tube特性生成带纹理图案飞线</h1>
<p>就是从一个建筑物到另一个建筑物有一条链接的线,这里我们可以用tube管道材质完成</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144044299-1573463345.png" alt="QQ_1735808660029" loading="lazy"></p>
<p>这里的思路是这样,加载模型之后,我们封装一个类,传入从哪里到哪里,就可以生成这里到那里的管道材质飞线,然后把它加入场景即可</p>
<p>在最开始导入模型那里</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144043969-456736953.png" alt="QQ_1735811478719" loading="lazy"></p>
<p><strong>要设置管道长度可以设置顶点参数,要设置粗细,可以设置管道几何体第三个参数</strong></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144043635-936983643.png" alt="image-20250102213653443" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144043271-1783704818.png" alt="image-20250102213702472" loading="lazy"></p>
<h2 id="71设置纹理">7.1设置纹理</h2>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144042944-566774360.png" alt="image-20250102214801520" loading="lazy"></p>
<p>设置纹理图片</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144042652-1034076727.png" alt="image-20250102215130943" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144042276-1371199089.png" alt="image-20250102215141911" loading="lazy"></p>
<p><strong>有个问题只显示了一半</strong></p>
<p>此时可以在y轴上让他重复两遍</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144041915-410710735.png" alt="image-20250102215526388" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144041591-1754395124.png" alt="image-20250102215808240" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144041240-368896811.png" alt="image-20250102215816233" loading="lazy"></p>
<p><strong>创建动画,由刚才的值,箭头要动应该是偏移x轴</strong></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144040928-218419001.png" alt="image-20250102220106694" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144034453-11425669.gif" alt="GIF" loading="lazy"></p>
<h2 id="72-着色器实现">7.2 着色器实现</h2>
<p>着色器也能实现同样的效果,和纹理相比可以实现类似彗星效果</p>
<p><strong>这个后面有时间可以看一下意义不大</strong></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144024888-1567260572.gif" alt="GIF" loading="lazy"></p>
<h1 id="八智慧城市光墙特效">八.智慧城市光墙特效</h1>
<p>给城市中间来一个光墙效果,这里我们采用圆柱几何体来做</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144022664-899810688.png" alt="image-20250106220312042" loading="lazy"></p>
<h2 id="81-布局">8.1 布局</h2>
<p>因为这是一个物体,所以放在mesh里面,同样创建一个class,new出来</p>
<p>一样的在建模这里new</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144022320-157106381.png" alt="image-20250106220521320" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144022003-632402253.png" alt="image-20250106221259484" loading="lazy"></p>
<p>先简单构建个黄色</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144021708-2071408275.png" alt="image-20250106221321196" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144021392-1129857176.png" alt="image-20250106221326966" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144021049-319989073.png" alt="image-20250106221340083" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144020667-1796547133.png" alt="image-20250106221640512" loading="lazy"></p>
<h2 id="82-实现渐变">8.2 实现渐变</h2>
<p>其实这里渐变的逻辑跟之前一样,城市模型渐变效果的时候,就是拿到高度,然后成为混合比例的颜色去和黄色混合一下颜色就渐变了</p>
<p>在封装类这边传进来高度差值</p>
<p><strong>新版three这样获取高度,要手动计算</strong></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144020299-3652205.png" alt="image-20250106223832146" loading="lazy"></p>
<p>先获取顶点</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144019991-1359745493.png" alt="image-20250106222712718" loading="lazy"></p>
<p>片段着色器,跟之前一样获取混合比例,直接把颜色给到透明度参数</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144019587-1406893833.png" alt="image-20250106223905485" loading="lazy"></p>
<p>此时</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144019253-387131813.png" alt="image-20250106223917856" loading="lazy"></p>
<p>1-翻转过来</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144018930-375410798.png" alt="image-20250106223936058" loading="lazy"></p>
<p>如果还想动画</p>
<p><strong>yoyo表示过去后又原样回来</strong></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144018416-1580072586.png" alt="image-20250106224120747" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144014747-1352247500.gif" alt="GIF" loading="lazy"></p>
<h1 id="九智慧城市雷达扫描特效">九.智慧城市雷达扫描特效</h1>
<h2 id="91-布局">9.1 布局</h2>
<p>基本布局跟上面光墙差不多先拿来修改一下,只是不再是圆柱体,而是平面</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144013247-928234363.png" alt="image-20250106225056909" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144012951-783709730.png" alt="image-20250106225148011" loading="lazy"></p>
<p>此时位置在正中心</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144012557-137857574.png" alt="image-20250106225222353" loading="lazy"></p>
<p>为了在一个位置边缘,并且要翻转过来</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144012221-1118570267.png" alt="image-20250106225344885" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144011782-602759921.png" alt="image-20250106225340244" loading="lazy"></p>
<h2 id="92-实现">9.2 实现</h2>
<p>之前在讲着色器有个案例,这里简单回顾下</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144011430-62986588.png" alt="image-20250106230850594" loading="lazy"></p>
<p>这里使用了vuv平面顶点</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144011106-127349004.png" alt="image-20250106230905861" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144010713-542453958.png" alt="image-20250106230922774" loading="lazy"></p>
<p><strong>如果想要动起来,配合动画的时间函数,而且还要配合之前shaderbook的旋转函数,直接套用即可</strong></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144010286-323379407.png" alt="image-20250106231457569" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144009972-1778220379.png" alt="image-20250106231505933" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144007513-758097901.gif" alt="GIF" loading="lazy"></p>
<h1 id="十封装3d警告标识与点击提示事件">十.封装3D警告标识与点击提示事件</h1>
<h2 id="101-布局">10.1 布局</h2>
<p>3D警告标识,就是一栋建筑物比如着火了,那么在其头上来一个标识图片,要实现这个效果需要制作 <strong>精灵图</strong></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144006409-75243817.png" alt="image-20250107215957538" loading="lazy"></p>
<p>他最后也是创建一个物体,所以这里也是封装一个类,拿到他的物体</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144006024-928713369.png" alt="image-20250107220229911" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144005719-1484732640.png" alt="image-20250107220356561" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144005313-955366545.png" alt="image-20250107220406779" loading="lazy"></p>
<h2 id="102-实现3d物体点击事件">10.2 实现3D物体点击事件</h2>
<p><strong>注意这里封装思想</strong></p>
<p>在创建new这里拿到class,假装调用他的点击事件,这个其实也是封装在类里面的方法 <strong>注意不再是constructor里面的属性</strong></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144004945-1009063215.png" alt="image-20250107221947805" loading="lazy"></p>
<p>封装大概思路</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144004631-1403832831.png" alt="image-20250107222534432" loading="lazy"></p>
<p>此时是点击任意位置都可以实现点击事件</p>
<p><strong>如果还要只点击这个图标才触发那么这里的原理还是利用投射光线</strong></p>
<p><strong><mark>原理:通过鼠标点击位置和摄像机打一束光出去,我们如果能判断打出去的光里面如果有要点击的这个物体,那么就可以去执行这个回调</mark></strong></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144004184-1963325142.png" alt="image-20250107223349652" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144001612-926664174.gif" alt="GIF" loading="lazy"></p>
<p>如果你想拿到点击的这个事件对象或者说物体</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144000557-711789842.png" alt="image-20250107223633445" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326144000268-606671705.png" alt="image-20250107223647677" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143959983-1863794567.png" alt="image-20250107223705526" loading="lazy"></p>
<h1 id="十一添加智慧城市天空盒子和设置抗锯齿效果">十一.添加智慧城市天空盒子和设置抗锯齿效果</h1>
<p>就是设置整个场景的一个大背景</p>
<p>以我这里这几张图为例</p>
<p>设置天空盒子图片切图可自行百度</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143959696-995738645.png" alt="image-20250107224219082" loading="lazy"></p>
<p>!(F:\前端\阶段十二 threeJS\04-光照与阴影\16智慧城市项目.assets\GIF-17362612172353.gif)</p>
<p>开启抗锯齿</p>
<p>目前可以看到建筑物边缘锯齿感还是比较重</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143957531-1565266191.png" alt="image-20250107224746955" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143957240-141607623.png" alt="image-20250107224849334" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143956909-913281001.png" alt="image-20250107224832345" loading="lazy"></p>
<h1 id="十二智慧城市大屏样式与结构">十二.智慧城市大屏样式与结构</h1>
<p>一个3D项目如果要配合数字孪生等,那是需要大屏支持的,也就是在3D表面再来左右两边2D,配合一起展示,像我这个就可以看城市的火警之类的,并且点击大屏可以对3D做出对应的显示操作</p>
<h2 id="121-布局">12.1 布局</h2>
<p>首先布局,需要跟3D同级再来一个组件</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143956582-779968084.png" alt="image-20250113113954737" loading="lazy"></p>
<p>大概布局占满全屏,分为左和右,zindex跟3D一样</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143956264-886244296.png" alt="image-20250113134614740" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143955988-261470315.png" alt="image-20250113134629764" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143955397-1134319759.png" alt="QQ_1736747211971" loading="lazy"></p>
<h2 id="122-pointer-events穿透事件">12.2 Pointer-events穿透事件</h2>
<p>现在的话由于2D大屏在前,所以像去转动3D等一些操作,是不行的,我们可以设置让2D点击事件穿透过去</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143954848-2145249202.png" alt="image-20250113135142190" loading="lazy"></p>
<p>那么此时左右两边的2D点击事件就不会生效了,<strong>我们可以单独设置这个2D元素的pointevent的css</strong></p>
<h1 id="十三-智慧城市动态数字面板动画">十三. 智慧城市动态数字面板动画</h1>
<h2 id="131-根据apifox制造mock数据">13.1 根据apifox制造mock数据</h2>
<p>下载好后创建一个项目</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143954549-1578117417.png" alt="image-20250113141211429" loading="lazy"></p>
<p>导入数据选择apifox</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143954212-74319993.png" alt="image-20250113141227831" loading="lazy"></p>
<p>回来之后可以运行调试,<strong>注意切换mock环境</strong></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143953835-876068328.png" alt="image-20250113141329247" loading="lazy"></p>
<p>创建接口环境</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143953510-297995018.png" alt="QQ_1736748978048" loading="lazy"></p>
<h2 id="132-发起请求并动态生成数据">13.2 发起请求并动态生成数据</h2>
<p>发起请求</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143953203-1606495359.png" alt="QQ_1736749751466" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143952858-1815182435.png" alt="image-20250113142939892" loading="lazy"></p>
<p>接下来把接口用在页面上</p>
<p>注意这里对数据做出处理,拿回来的数据一共四个对象,我也是放在对象里面并不是数组,这个大对象有四个属性分别是iot、event等,并且给number属性给一个初始值0</p>
<p><strong>然后这里做出了一个处理,就是我想number数字是动态慢慢增长生成的,不是一下子数据就上来了,那么动画效果就可以用到gasp来实现,单独实现number属性</strong></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143952559-1745094168.png" alt="image-20250113170229894" loading="lazy"></p>
<p>这边遍历数据注意此时数据是</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143952250-1703029053.png" alt="image-20250113170950570" loading="lazy"></p>
<p>遍历的是一个对象,遍历对象,前面是key后面是value,所以这里的item实际上就是iot这个对象,所以可以直接用.name</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143951933-1692699454.png" alt="image-20250113171033290" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143948451-668564611.gif" alt="GIF 2025-1-7 11-23-10" loading="lazy"></p>
<p>如果不想要小数,只显示整数</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143947246-427747133.png" alt="QQ_1736759591748" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143946950-487533757.png" alt="QQ_1736759600648" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143945939-634636623.gif" alt="GIF 2025-1-13 17-13-35" loading="lazy"></p>
<h2 id="133-通过接口生成城市事件列表">13.3 通过接口生成城市事件列表</h2>
<p>也就是右边的部分,右边是一个事件列表,通过接口获取,有多少火情等一些灾害显示</p>
<p>先调用接口获取参数</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143945214-668929242.png" alt="image-20250114095543067" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143944923-942436167.png" alt="image-20250114095529753" loading="lazy"></p>
<p>一样的传过来</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143944643-441500096.png" alt="QQ_1736819890347" loading="lazy"></p>
<p>遍历循环</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143944378-1854118791.png" alt="image-20250114100536607" loading="lazy"></p>
<p>对于这里图片的处理,我们一共有三种分别对应治安电力和火警这里可以创造一个对象,key就是name,value就是图片地址,通过name去匹配是什么图片</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143944077-724982131.png" alt="QQ_1736820523523" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143943757-1820499580.png" alt="QQ_1736820566171" loading="lazy"></p>
<p>然后再图片右边我们可以显示发生的时间,但是通过刚才的接口得知没得时间字段,<strong>这里展示用apifox快速创建一个接口字段</strong></p>
<p>直接在修改接口里面新增一个子节点,并且可以修改类型和要什么样的数据都可以</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143943444-114946141.png" alt="image-20250114101201497" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143943122-403195341.png" alt="image-20250114102657670" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143942604-1021709986.png" alt="image-20250114102707088" loading="lazy"></p>
<h2 id="134-城市事件列表动态生成雷达-飞线-光墙">13.4 城市事件列表动态生成雷达-飞线-光墙</h2>
<p>这是一个复杂大的流程</p>
<p>首先把列表也给3D传一份</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143942140-770974077.png" alt="QQ_1736824156371" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143941873-1483835972.png" alt="QQ_1736824438260" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143941573-983296866.png" alt="image-20250114111417964" loading="lazy"></p>
<p>说下这里的逻辑这个接口返回会有position也就是坐标</p>
<p>我们之前封装过一个警告的雪碧图</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143941274-4830252.png" alt="image-20250114111613865" loading="lazy"></p>
<p>基于这个封装来修改,new这个类,需要三个参数,分别是type也就是name,用来匹配什么样的标志,然后是position也就是位置,还有就是color标志的颜色也可以传,当然也可以给个默认值</p>
<p>改造对应的图标</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143940865-771213241.png" alt="QQ_1736825325612" loading="lazy"></p>
<p>改造位置</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143940597-1239241795.png" alt="QQ_1736825385594" loading="lazy"></p>
<p><strong>这两个接口每次刷新都会有随机数据,所以这里制造一种长链接的效果</strong></p>
<p>每隔一段时间就刷新,有不同的灾害发生用定时器实现</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143940329-1218594997.png" alt="QQ_1736840782839" loading="lazy"></p>
<p>这边3D需要拿到每次不同的数据,并且把参数传进刚才封装的类里面,用watch来实现</p>
<p>每五秒获取一次数据</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143940047-926556736.png" alt="image-20250114155842864" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143939705-1143523718.png" alt="image-20250114155834652" loading="lazy"></p>
<p>每一次来新的数据,将position改造一下,让他只在-几到几的范围内,因为整个建筑物没有高于这个值得高度</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143939414-602942969.png" alt="image-20250115092926745" loading="lazy"></p>
<p>但是现在有个问题就是,会有新增的进来,但是之前的也不会删除</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143938926-261543995.png" alt="image-20250115095326461" loading="lazy"></p>
<p>这里我们采用3D物体上有一个方法</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143938529-835648443.png" alt="QQ_1736906123196" loading="lazy"></p>
<p>这里我们采用这个方法,在封装类里面,跟之前的点击事件同级封装一个remove方法,将当前这个mesh和父级删除,注意mesh的材质和几何体调用dispose表示不受影响</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143938179-1952078403.png" alt="QQ_1736907151979" loading="lazy"></p>
<p>然后我们定义一个空数组,每次数据有变化都进行一个全清的操作,同时下面把这次的新数据给到数组里面</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143937870-1041484068.png" alt="image-20250115101414654" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143925451-290758310.gif" alt="GIF 2025-1-15 10-14-56" loading="lazy"></p>
<p>第二个问题现在存在深度检测</p>
<p><strong>也就是两个叠加在一起应该混合一下成为一体的颜色</strong></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143922373-1634804517.png" alt="image-20250115105224558" loading="lazy"></p>
<p>给材质设置一下</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143922015-1556477928.png" alt="image-20250115105944400" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143921714-39440471.png" alt="image-20250115110157117" loading="lazy"></p>
<p>!(F:\前端\阶段十二 threeJS\04-光照与阴影\16智慧城市项目.assets\GIF 2025-1-15 10-14-56-1736910121965-4.gif)</p>
<p><strong>接下来根据火灾警情等动态生成雷达光墙</strong></p>
<p><strong>光墙</strong></p>
<p>根据火灾动态生成光墙,光墙就是圆柱体向外扩展那一个</p>
<p>这是原来封装的类</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143919215-1230798948.png" alt="image-20250116102925116" loading="lazy"></p>
<p>现在改造一下,圆柱体的两个半径我们输入参数,半径变化范围也是我们自己来</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143918875-406002206.png" alt="QQ_1736994664599" loading="lazy"></p>
<p>这里的逻辑是这样的,创建一个对象是三种警情的名字,然后在遍历创建之前雪碧图那里通过名字把每一次产生的警情position数据传进来,给到光墙,半径和变化的长度是固定的就可以实现,根据数据在不同的地方产生光墙</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143918538-1892179387.png" alt="QQ_1736995469330" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143918206-756102332.png" alt="QQ_1736995552947" loading="lazy"></p>
<p>这里封装位置别忘记改</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143917875-1513616240.png" alt="QQ_1736995691826" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143906021-136149353.gif" alt="GIF 2025-1-15 10-14-56" loading="lazy"></p>
<p>同理完成治安和电力的数据交互,先治安</p>
<p>治安我们用飞线来完成</p>
<p>其实大致差不多,之前也封装过关于飞线的类,这里主要就是不断地位置变换</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143903077-915296438.png" alt="image-20250123160312455" loading="lazy"></p>
<p>先new类出来</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143902578-1307502197.png" alt="image-20250123160624753" loading="lazy"></p>
<p>封装这边主要就是设置飞线顶点,从哪里到哪里,一般第一个0 0 0不变,然后最后一个就是落地的位置,中间一般介于两点之间的位置</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143902100-2014960604.png" alt="image-20250123163652633" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143857444-585562570.gif" alt="GIF 2024-11-7 17-39-00" loading="lazy"></p>
<p>最后电力我们用雷达图来展示</p>
<p>在雷达图里面我们除了位置需要定义一个半径</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143856598-776508040.png" alt="QQ_1737625256210" loading="lazy"></p>
<p>这边封装,同样的给到position,同时雷达图需要定义一个半径</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143856154-904919844.png" alt="QQ_1737626129031" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143850435-629285761.gif" alt="GIF 2025-1-15 10-14-56" loading="lazy"></p>
<h1 id="十四大屏html元素与场景物体数据交互与特效展现">十四.大屏HTML元素与场景物体数据交互与特效展现</h1>
<p>也就是当我点击左右两边的2D面板对应的3D物体会做出一些处理,反之亦可</p>
<p>要实现这种操作,需要消息传送,可以时间总线也可以vuex等,这里用到一个插件</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143849140-150912561.png" alt="QQ_1738830777737" loading="lazy"></p>
<p>先封装出来一个可以直接用的bus总线</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143848852-467882360.png" alt="QQ_1738830868472" loading="lazy"></p>
<p>之前封装过一个每一个出来的图标点击绑定的有点击事件</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143848386-1317470213.png" alt="image-20250206164007476" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143848104-173418912.png" alt="image-20250206164015679" loading="lazy"></p>
<p>通过点击3D把数据给到2D页面</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143847828-1982335298.png" alt="QQ_1738831291502" loading="lazy"></p>
<p>2D页面接收</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143847522-941543661.png" alt="image-20250206164226985" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143847239-1569894033.png" alt="image-20250206164233334" loading="lazy"></p>
<p><strong>实现效果,点击3D页面对应2D列表为红色</strong></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143846945-769439659.png" alt="QQ_1738832059890" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143846579-223726327.png" alt="QQ_1738832074708" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143836923-218733343.gif" alt="GIF 2025-1-15 10-14-56" loading="lazy"></p>
<p><strong>然后就是点击2D面板,相应的3D进行交互</strong></p>
<p>绑定点击事件,通过插件传值</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143834709-1863387849.png" alt="image-20250206172301760" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143834399-91635541.png" alt="image-20250206172313339" loading="lazy"></p>
<p>我们可以拿到点击的生成列表的下标,注意这里逻辑,在我们原来通过定时器生成雪碧图的时候,给每个物体添加一个index属性就是生成的顺序,然后这里通过点击事件拿到的顺序就可以让点击的显示,其他不显示</p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143834071-1378733818.png" alt="QQ_1738834265710" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143833742-283075104.png" alt="QQ_1738834317575" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143825758-1263001613.gif" alt="GIF 2025-1-15 10-14-56" loading="lazy"></p>
<p><strong>如果要改对应的颜色,那就直接mesh的材质修改即可</strong></p>
<p><strong>接下来在做一个功能,当我点击2D面板,不仅显示这一个3D图,并且镜头要转向这个地方</strong></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143823563-104556630.png" alt="QQ_1738835681641" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/2680817/202503/2680817-20250326143803534-221230949.gif" alt="GIF 2025-1-15 10-14-56" loading="lazy"></p><br><br>
来源:https://www.cnblogs.com/heymar/p/18793716
頁:
[1]