【免费下载链接】HeliosHelios - Make your energy visible, in 2.5D in a Lovelace card for Home Assistant项目地址https://gitcode.com/gh_mirrors/helios34/Helios点击查看免费下载Helios 是一个 Home Assistant 的 2.5D 能源可视化卡片它把你家周围的真实建筑竖在地图上。神奇的是整个场景没有使用 WebGL也没有 z-buffer 深度缓冲建筑立体感完全靠三样东西拼出来——建筑挤出extrusion、Lambert 着色和画家算法排序。这篇文章带你拆解这套纯 SVG 渲染方案的实现思路。1. 场景架构为什么这里没有 z-buffer先看一下 Helios 场景的构成地面层瓦片地图 canvas 通过 CSS 3D 变换rotateXrotateZperspective倾斜旋转得到 2.5D 的俯视大地场景层一个屏幕空间的svg每帧重绘阴影和建筑投影公式与地面的透视函数严格一致正因为叠加层是扁平 SVG浏览器无法为它提供硬件深度测试——谁先画谁就在下面。所以 Helios 必须自己回答先画谁、后画谁这就是画家算法painters algorithm登场的原因。核心渲染入口在 renderer.ts 的_draw()每帧先提交阴影层再提交建筑层this._sceneLayers.commit( renderShadows(this.camera, drawn, this._sun, ...), renderBuildings(this.camera, drawn, alt, ...), )投影本身是一个针孔相机见 projection.ts 的project3()每个世界坐标点除了算出屏幕x/y还会返回depth即相机空间 Z 值它后面会成为排序的钥匙。2. 建筑挤出把 OSM 足迹立成棱柱建筑数据来自 OpenFreeMap 的矢量瓦片见 openfreemap.ts拿到的是每个建筑在地面上的足迹多边形footprint。挤出的规则很简单粗暴把足迹的每个顶点投影到地面up 0和屋顶up height各投一遍足迹的每条边生成一个贯穿全高的墙面四边形屋顶作为一个整体多边形画在最上面对应代码在 buildings.ts。这里有两个省掉大量废面的小技巧屏幕空间背面剔除背面墙根本不用画。Helios 把墙面 quad 投影到屏幕后用shoelace 公式算符号面积朝向相机的一面符号为负背离相机的一面符号为正正的直接丢弃见 buildings.ts。妙在它读的是投影后的四边形而不是全局方位角——场景边缘的建筑受透视影响视角和 bearing 并不平行用屏幕空间判断才永远正确。合并同高邻接建筑两栋等高房子挨在一起时中间那堵墙是共面的深度排序永远分不出先后会随相机角度忽隐忽现。Helios 的解法是釜底抽薪用布尔并集把同高且相邻的足迹合并成一个体量内部墙直接消失见 buildings.ts 的mergeSameHeight()原轮廓线则平铺在屋顶上当露台分界。3. Lambert 着色让每面墙都知道太阳在哪如果所有墙涂同一种颜色建筑就没有方向感。Helios 用最经典的Lambert 余弦定律墙面亮度 ∝ 外法线与太阳方向的点积负值截断为 0背光墙不吸收负光。一行核心逻辑buildings.tsconst lit Math.max(0, (ey / el) * sunE (-ex / el) * sunN) * sunFade; const shade mixHex(wallAmbient, wallLit, lit);外法线不用额外算——足迹环是逆时针存储的边向量(ex, ey)左转 90° 就是外法线。lit在 [0,1] 之间用mixHex在环境暗色和受光色之间插值墙面就有了自然的明暗过渡。两个让效果更活的细节sunFade跟随太阳高度角日出日落时建筑墙面和地面阴影同步暗下去不会出现地面无影、墙仍亮的割裂高度角色调colors.ts 的buildingColor()夜晚偏靛蓝、黄昏偏紫、低空偏暖、白天还原本色建筑颜色随一天周期整体呼吸4. 画家算法排序depth 从哪来怎么排有了可见的墙和屋顶最后一步是从远到近依次画。depth 键取最近角点不是中心一个常见错误是按建筑质心排序——一栋远处的大楼质心可能比近处小房子更靠近相机排序就错了。Helios 的 depth 键是建筑足迹所有顶点中 cameraZ 最大的那个离相机最近的角见 buildings.ts大建筑该排在前面时依然正确。面级稳定排序建筑先按paintOrder排好再拆成一个个面墙 quad、屋顶 path所有面混进同一个列表按 depth 做一次稳定排序buildings.ts。稳定是关键两栋楼共墙时深度完全相同稳定排序会让它们保持paintOrder给出的拓扑顺序而不是落到任意的实现细节上。5. 当排序失效分离平面 拓扑排序单键排序有个无解场景一栋细长建筑指着相机它的近端比另一栋小楼更近、远端又比它更远——一个数字键无法同时说在这头前面、那头后面。Helios 的解法非常优雅buildings.ts 的paintOrder()找分离平面对每对相邻建筑从真实轮廓的边法线中找一条能分开两个足迹的轴findSeparatingAxisbuildings.ts。被竖直平面分开的两栋楼绝不会互相穿插——站在相机这一侧的一定在前面平面只算一次平面只依赖足迹、不依赖相机用WeakMap缓存每帧只需把眼睛相机落点见eyeGroundPoint代入平面方程判断哪侧在前Kahn 拓扑排序把谁必须先画建成有向图每次从当前无依赖的建筑里挑最远的一个画。平面没覆盖到的对自动落回 depth 键顺序环兜底三栋楼围成环时存在矛盾依赖代码检测无解节点后直接取最远者继续最坏情况退化为纯 depth 排序永远不会画错得离谱6. 源码导览模块职责路径挤出、着色、排序、阴影建筑渲染全部纯函数src/scene/buildings.ts针孔投影 相机姿态project3()与depth来源src/scene/projection.ts每帧绘制调度、姿态守卫_draw()提交阴影建筑src/scene/renderer.ts高度角色调、颜色混合buildingColor()等src/core/render-kit/colors.ts建筑足迹数据源OpenFreeMap 瓦片解码src/scene/openfreemap.ts7. 小结Helios 证明了不需要 WebGL 也能画出有说服力的 2.5D 建筑挤出足迹每条边一个全高 quad屏幕空间 shoelace 剔除背面合并同高邻接体量消灭共面墙Lambert 着色法线·太阳方向点积 clamp配合高度角色调让墙面随一天明暗呼吸画家算法最近角点 depth 键 面级稳定排序打底分离平面 Kahn 拓扑排序解决单键排不出的穿插情况这套方案全部是纯函数操作 SVG 属性帧间只改动的节点会被就地重写见 scene-dom.ts因此对低端设备的 WebView 极其友好——而这正是一个要在家庭 NAS 浏览器里 24 小时运行的卡片最需要的品质。赞分享【免费下载链接】HeliosHelios - Make your energy visible, in 2.5D in a Lovelace card for Home Assistant项目地址https://gitcode.com/gh_mirrors/helios34/Helios点击查看免费下载相关推荐three.js 自定义 GLSL 着色器画面不显示怎么排查three.js 自定义 GLSL 着色器画面不显示怎么排查 在 three.js 中用 ShaderMaterial 之类的方式编写自定义 GLSL 着色器前端3D渲染图形学lottie-ios工程建筑工程设计与建筑可视化中的动画革命lottie ios工程建筑工程设计与建筑可视化中的动画革命 引言当建筑遇见动态美学 在传统的工程建筑领域设计图纸和静态效果图长期占据主导地位。然而随着图形学移动开发AssetRipper 使用教程10 分钟把 Unity 游戏资源导出成工程AssetRipper 使用教程10 分钟把 Unity 游戏资源导出成工程 你手里有一个 Unity 游戏的安装目录想把模型、贴图、音频导出来放进自己的开发工具逆向工程游戏开发上一篇Angular Zones 深度解析Zone.js 变更检测信号机制、Zone Pollution 治理与 Zoneless 演进下一篇chezmoi 模板函数 stat 与 lstat 实战指南在 dotfiles 模板中安全探测文件系统状态创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考