把监控视频投放到三维实景中,可以将静态的三维数据实现动态的显示效果,可以极大方便一些区域的查看和监管,该文章记录该投放的实现过程,以供入门参考。
效果如下:
在进行视频投放之前,首先安装SuperMap iDesktopX和SuperMap iServer,在实践中使用的是11i版本。
打开SuperMap iDesktopX 11i
在左侧工作空间管理器中找到场景,并右键,选择新建球面场景,之后即可看到工作空间中出现了地球画面
在左下角图层管理器中,找到普通图层并右键,选择添加三维切片缓存数据·,如果有其他类型的三维数据可以选则其他选项,找到模型文件并加载(三维切片缓存数据的元文件后缀是scp),加载之后双击图层就可以定位到模型所在位置。
之后按Ctri+S把制作好的三维场景保存,保存路径里面不能含有中文,否则后面发布的服务可能加载不出。
三维场景制作完成之后,把场景发布到服务端,首先打开SuperMap iServer 11i
点击启动服务即可打开,大概要等2分钟左右,跟电脑配置有关。
如果第一次打开,需要访问http://localhost:8090/iserver/services/security/login,进行管理员注册,在此已经注册过了,记住自己的账户和密码。
回到SuperMap iDesktopX 11i,打开创建好的的场景,右键左侧工作空间管理器中的工作空间名称,选择发布工作空间,
输入自己的服务端账户密码
勾选三维服务之后点击发布
之后打开浏览器,登录自己的管理员账号,就可以在服务管理中找到发布的三维服务
点击进入并复制服务地址,如果想要查看模型数据或者预览,可以点击链接,然后探索里面的内容。至此三维场景发布完成,得到一个服务端链接。
首先按照SuperMap iClient3D for Cesium官网教程配置环境,得到一个Html前端工程,官方教程在:SuperMap iClient3D for Cesium 开发指南
,官网教程内容很详细,还有API可以学习。
本开发使用的是VScode,其他开发工具一样,根据官网教程创建viewer之后,使用打开场景,下面的地址就是刚刚服务端的链接。效果如下:(注意在此过程中SuperMap iServer 11i需要保持打开状态)
var scene = viewer.scene;
var promise = scene.open("http://localhost:8090/iserver/services/3D-test/rest/realspace"); //url为在SuperMap iServer上发布的服务地址
最后一步,在场景中加载视频。
实际上,如果使用Cesium直接进行视频投放,原理类似把视频作为纹理贴到一个矩形实体上面,但是SuperMap在Cesium的基础上,把该步骤封装成了一个类,也就是Cesium.ProjectionImage,所以使用起来非常方便。
关于ProjectionImage的详细介绍,可以查看官方文档3D WebGL API
在自己书写代码之前可以在官网http://support.supermap.com.cn:8090/webgl/examples/webgl/editor.html#projectionImage进行练习
下面书写的代码也是对官方源码的理解
首先在
然后创建ProjectionImage对象,并跟视频对象绑定起来
var videoElement = document.getElementById('trailer');
var projectionImage = new Cesium.ProjectionImage(scene);
projectionImage.setImage({
video: videoElement
});
获取视频之后,需要的就是视频投放的观测点、方向、距离这些参数了。
观测点使用
projectionImage.viewPosition = [longitude, latitude, height];
视频的长和宽使用
projectionImage.horizontalFov = 20;
projectionImage.verticalFov = 10;
之后设置投射的方向和距离
projectionImage.setDistDirByPoint([longitude, latitude, height]);
projectionImage.distance = 200;
不出意外的话,根据上面的代码,视频就可以正常投射了。
完整的JavaScript代码如下:
$(document).ready(function(){
var viewer = new Cesium.Viewer('cesiumContainer');
var scene = viewer.scene;
var promise = scene.open("http://localhost:8090/iserver/services/3D-3D_Try/rest/realspace");
promise.then(function(layers){
console.log(layers)
var videoElement = document.getElementById('trailer');
var projectionImage = new Cesium.ProjectionImage(scene);
projectionImage.distance = 0.1;
var wgsPosition = scene.camera.positionCartographic;
var longitude = Cesium.Math.toDegrees(wgsPosition.longitude);
var latitude = Cesium.Math.toDegrees(wgsPosition.latitude);
var height = wgsPosition.height;
projectionImage.viewPosition = [longitude, latitude, height];
projectionImage.horizontalFov = 20;
projectionImage.verticalFov = 10;
projectionImage.setImage({
video: videoElement
});
//videoElement.play();
projectionImage.removeAllClipRegion();
projectionImage.build();
var handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
handler.setInputAction(function (movement) {
var last = scene.pickPosition(movement.position);
console.log(1);
//计算该点与视口位置点坐标的距离
var distance = Cesium.Cartesian3.distance(scene.camera.position, last);
if (distance > 0) {
//将鼠标当前点坐标转化成经纬度
var cartographic = Cesium.Cartographic.fromCartesian(last);
var longitude = Cesium.Math.toDegrees(cartographic.longitude);
var latitude = Cesium.Math.toDegrees(cartographic.latitude);
var height = cartographic.height;
//通过该点设置视频投放对象的距离及方向
projectionImage.setDistDirByPoint([longitude, latitude, height]);
projectionImage.distance = 200;
var wgsPosition = scene.camera.positionCartographic;
var longitude = Cesium.Math.toDegrees(wgsPosition.longitude);
var latitude = Cesium.Math.toDegrees(wgsPosition.latitude);
var height = wgsPosition.height;
projectionImage.viewPosition = [longitude, latitude, height];
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
})
})
本文是对三维场景视频投放的一个简单尝试,代码和功能都是很简略(几乎没什么功能),但是教程是很详细的,对于初学者比较友好,如果想要较好的投射效果,还需要对视频投射的参数进行仔细的打磨。。