基于 HTML5 WebGL 构建智能城市 3D 场景
<p> </p><h2>前言</h2>
<p>随着城市规模的扩大,传统的方式很难彻底地展示城市的全貌,但随着 3D 技术的应用,出现了 3D 城市群的方式以动态,交互式地把城市全貌呈现出来。配合智能城市系统,通过 Web 可视化的方式,使得城市管理者可以更及时地了解交通情况,城市消防,电力管理等方面的运行情况,做出处理。</p>
<p>本 demo 使用 HT for Web 产品轻量化 HTML5/WebGL 建模的方案,传统的 智慧楼宇/楼宇自动化/楼宇安防/智慧园区 常会采用 BIM(建筑信息模型 Building information modeling)软件,如 Autodesk 的 Revit 或 Bentley 这类建筑和工程软件,但这些 BIM 建模模型的数据往往过于庞大臃肿,绝大部分细节信息对楼宇自控意义不大,反而影响拖累了行业 Web SCADA 或 Web 组态监控的趋势,所以我们采用以 Hightopo 的 HT for Web 产品轻量化 HTML5/WebGL 建模的方案,实现快速建模、运行时轻量化到甚至手机终端浏览器即可 3D 可视化运维的良好效果。</p>
<p>demo 地址:http://www.hightopo.com/demo/city/<br></p>
<p>预览图:</p>
<p><img src="https://img2018.cnblogs.com/common/1496396/201911/1496396-20191120175112860-1385852555.gif"></p>
<h2>代码实现</h2>
<p><strong>加载 3d 场景</strong></p>
<p>新建一个 3d 场景,并加入到页面中。</p>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">const g3d = new ht.graph3d.Graph3dView();
const dm3d = g3d.dm();
g3d.addToDOM();</pre>
</div>
<p>addToDOM 函数默认将场景加载到 body 中并填充窗口。</p>
<p>接下来反序列化城市场景 json,并在反序列化函数的回调中设置了场景的视角,中心位置,天空盒,并获得各图元信息,调用 startAnim 函数:</p>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">g3d.deserialize('scenes/ny.json', () => {
g3d.setEye();
g3d.setCenter();
g3d.setSkyBox(dm3d.getDataByTag('skyBox'));
// 获取扩散效果的图元
scaleList.push(
dm3d.getDataByTag('scaleBlue'),
dm3d.getDataByTag('scaleRed')
);
···
// 开始动画
startAnim();
});</pre>
</div>
<p> </p>
<p><strong>动画实现</strong></p>
<p>加载后的城市场景如下图所示:</p>
<p><img src="https://img2018.cnblogs.com/common/1496396/201911/1496396-20191120175523113-1190181098.png"></p>
<p> 我们可以看到场景中有蓝黄水波纹效果,道路,消防通道的流动效果,上下浮动的效果和旋转的 logo 和卫星。</p>
<p>动画的实现均通过 ht.Default.startAnim 实现的,先来了解一下:</p>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">ht.Default.startAnim({
// 动画帧数
frames: 12,
// 动画帧间隔毫秒数
interval: 10,
// 动画缓动函数,默认采用 ht.Default.animEasing
easing: function(t){ return t * t; },
// 动画结束后调用的函数
finishFunc: function(){ console.log('Done!') },
// action 函数必须提供,实现动画过程中的属性变化
action: function(v, t){
// 此例子展示将节点 node 从位置 p1 动画到位置 p2
node.setPosition(
p1.x + (p2.x - p1.x) * v,
p1.y + (p2.y - p1.y) * v
);
}
});
</pre>
</div>
<p> </p>
<p>以上为 Frame-Based 方式动画, 这种方式用户通过指定 frames 动画帧数,以及 interval 动画帧间隔参数控制动画效果。</p>
<p>ht的动画手册可以参照:动画手册</p>
<p> </p>
<p> </p>
<p>下面依次介绍各个效果的实现。</p>
<p>1. 波纹效果</p>
<p>预览图:</p>
<p><img src="https://img2018.cnblogs.com/common/1496396/201911/1496396-20191121152608946-2035115465.gif"></p>
<p>代码:</p>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">function waveScale(obj, dlt, max, min) {
obj.forEach(node => {
// 扩散半径增加
let s = node.getScaleX() + dlt;
// 扩散半径大于最大值的时候, 重置为最小值
if (s >= max) s = min;
// 设置 x,y,z 方向的缩放值
node.setScale3d(s, s, s);
});
}
function startAnim() {
ht.Default.startAnim({
frames: Infinity,
interval: 20,
action: () => {
// 扩散蓝和扩散红
waveScale(scaleList, dltScale, maxScale, minScale);
}
});
}
</pre>
</div>
<p> </p>
<p>2. 旋转效果</p>
<p>预览图:</p>
<p><img src="https://img2018.cnblogs.com/common/1496396/201911/1496396-20191121155615419-1173370393.gif"></p>
<p>代码:</p>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">function rotateAction(obj, dlt) {
// 获取图元旋转弧度值,没有就置零
let rotation = obj.getRotation() || 0;
// 每帧弧度增加
obj.setRotation(rotation + dlt);
}
function startAnim() {
ht.Default.startAnim({
frames: Infinity,
interval: 20,
action: () => {
// 卫星转动
rotateAction(star, dltRoattion);
}
});
}
</pre>
</div>
<p> </p>
<p>3. 流动效果</p>
<p>预览图:</p>
<p><img src="https://img2018.cnblogs.com/common/1496396/201911/1496396-20191121155513548-1352699687.gif"></p>
<p>流动效果是非常常见的效果,实现的过程也较为简单,只需要动态地去改变 uv 贴图的偏移值即可。在本例中,通过对模型六面的贴图的 U 方向实施动态增减实现了多个流动效果:</p>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">function uvFlow(obj, dlt) {
// 改变贴图 uv 坐标实现流动效果
let offset = obj.s('all.uv.offset') || ;
obj.s('all.uv.offset', + dlt, offset]);
}
function startAnim() {
ht.Default.startAnim({
frames: Infinity,
interval: 20,
action: () => {
// 小路流动效果
uvFlow(roadSmall, dltRoadSmall);
}
});
}</pre>
</div>
<p> </p>
<p>4. 浮动效果</p>
<p>预览图:</p>
<p><img src="https://img2018.cnblogs.com/common/1496396/201911/1496396-20191121150629383-494216129.gif"></p>
<p>代码:</p>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">function blockFloat(obj, dis, dlt) {
obj.forEach(node => {
let startE = node.a('startE');
if (startE == null)
// 获得图元在 y(高度)方向上的值
node.a('startE', startE = node.getElevation());
let float = node.a('float') || 0;
// 设置 status 为方向
let status = node.a('status') || 1;
node.setElevation(startE + dis * float);
if (float > 1 || float < 0)
// 超出阀值则改变方向
node.a('status', status = -status);
float += dlt * status;
// 重新设置图元高度
node.a('float', float);
});
}
function startAnim() {
ht.Default.startAnim({
frames: Infinity,
interval: 20,
action: () => {
// 消防标志浮动效果
blockFloat(fireFloatList, fireFloadDis, fireFloatDlt)
}
});
}
</pre>
</div>
<p> </p>
<p> </p>
<p>这样,一个基本的效果就实现了。</p>
<p>HT 的 3D 城市群方案不仅可以在大屏上有良好的效果,在移动端也有着不错的体验,这使得城市管理者不管何时何地都能获取到实时的监控信息,这里放两张在移动端浏览器上的预览图给大家体验一下:</p>
<div class="img-wrapper" style="display: flex; align-items: center; flex-direction: row; justify-content: space-around"><img src="https://img2018.cnblogs.com/common/1496396/201911/1496396-20191123184741883-170935474.jpg"> <img src="https://img2018.cnblogs.com/common/1496396/201911/1496396-20191123184759714-1073921744.jpg"></div>
<p> </p>
<p>HT包含了数百个工业互联网 2D 3D 可视化应用案例,点击这里体验把玩:http://www.hightopo.com/demos/index.html</p>
<p> </p><br><br>
来源:https://www.cnblogs.com/htdaydayup/p/11898465.html
頁:
[1]