在三维可视化领域,导航控制一直是个痛点问题。传统三维场景中,用户经常因为视角迷失而不得不反复调整相机位置,既浪费时间又影响操作体验。SuperMap iClient3D for WebGL 提供的ViewCube控件,正是为了解决这一核心痛点而设计的交互工具。
我第一次接触ViewCube是在BIM软件中,那种通过简单点击就能快速定位标准视角的体验让我印象深刻。现在,这个功能被完美移植到了WebGL三维场景中。ViewCube本质上是一个3D指南针,它以立方体的形式呈现,六个面分别对应前、后、左、右、上、下六个标准视角。但它的价值远不止于此——它实现了场景视角与导航控件之间的双向同步,这在复杂场景操作中尤为实用。
当前最新版本为:
这两个包可以从官方提供的百度网盘链接获取。下载后解压,建议使用VS Code作为开发环境,通过Live Server插件运行示例代码。
注意:确保下载的版本号完全匹配,不同版本的API可能存在兼容性问题。我曾遇到过因版本不一致导致的初始化失败问题,排查了很久才发现是版本不匹配。
ViewCube的集成非常简单,只需要在HTML中引入必要的资源文件:
html复制<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>模型视图</title>
<link href="./SuperMap3D/Widgets/widgets.css" rel="stylesheet">
<script src="./SuperMap3D/SuperMap3D.js"></script>
<script type="text/javascript" src="./viewcube/viewcube.js"></script>
</head>
<body>
<div id="Container"></div>
<div class="loading-container">
<div class="circle"></div>
</div>
<script type="module">
// 初始化代码将放在这里
</script>
</body>
</html>
ViewCube需要与三维场景协同工作,因此首先需要正确初始化场景:
javascript复制const viewer = new SuperMap3D.Viewer('Container', {
contextOptions: {
contextType: Number(2), // 使用WebGL2渲染引擎
msaaLevel: 2, // 抗锯齿级别
},
timeline: true, // 启用时间轴
useSuperMapOIT: true, // 启用顺序无关透明度
navigation: false // 禁用默认导航控件
});
这里有几个关键参数需要注意:
contextType: 2 表示使用WebGL2渲染器,性能更好msaaLevel 影响画面质量,值越高效果越好但性能消耗越大navigation: false 因为我们使用ViewCube替代默认导航在场景加载完成后,我们可以初始化ViewCube控件:
javascript复制function initViewcube(scene, viewer) {
// 场景显示设置
scene.sun.show = true;
scene.globe.show = false;
scene.globe.baseColor = SuperMap3D.Color.BLACK;
scene.skyAtmosphere.show = false;
// 计算相机距离
const layer = viewer.scene.layers.layerQueue[0];
const boundingSphere = layer.boundingSphere ||
SuperMap3D.BoundingSphere.fromRectangle3D(layer.layerBounds);
const distance = boundingSphere.radius * 3;
// 初始化ViewCube
var viewcube = new ViewCube(viewer, {
language: "zh", // 中文显示
width: 300, // 控件宽度
height: 300, // 控件高度
home: layer._matModel, // 模型变换矩阵
distance: distance // 相机距离
});
}
当用户在场景中通过鼠标或触摸操作改变视角时,ViewCube会自动更新其显示状态以反映当前视角。这种同步是通过监听场景相机变化实现的:
这种同步是实时的,延迟几乎不可察觉。在实际项目中,这种反馈机制大大提升了用户的空间感知能力。
更强大的是反向同步功能——通过操作ViewCube来控制场景视角:
拖拽旋转:
点击定位:
重要细节:旋转中心点的计算逻辑
- 优先使用屏幕中心拾取到的场景坐标
- 如果拾取失败(如指向天空),则使用相机前方100米处作为默认中心
- 这种设计确保了在各种情况下的操作连贯性
ViewCube提供了多个可配置参数,满足不同场景需求:
javascript复制{
language: "zh", // 界面语言
container: "viewCubeContainer", // 自定义容器ID
width: 300, // 宽度(px)
height: 300, // 高度(px)
home: matModel, // 初始位置矩阵
distance: 1000, // 初始距离
showCompass: true, // 是否显示罗盘
compassSize: 80, // 罗盘大小
fadeTime: 1.0 // 动画过渡时间(秒)
}
在复杂场景中使用ViewCube时,可以考虑以下优化措施:
问题1:ViewCube不显示
问题2:同步延迟明显
问题3:点击无响应
在移动设备上使用ViewCube需要特殊处理:
javascript复制// 检测触摸设备
const isTouchDevice = 'ontouchstart' in window;
// 调整ViewCube参数
const viewcube = new ViewCube(viewer, {
width: isTouchDevice ? 200 : 300,
height: isTouchDevice ? 200 : 300,
touchEnabled: isTouchDevice
});
移动端还需要考虑:
以下是完整的HTML实现,包含所有关键功能:
html复制<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ViewCube完整示例</title>
<link href="./SuperMap3D/Widgets/widgets.css" rel="stylesheet">
<script src="./SuperMap3D/SuperMap3D.js"></script>
<script src="./viewcube/viewcube.js"></script>
<style>
#Container {
width: 100%;
height: 100vh;
margin: 0;
padding: 0;
overflow: hidden;
}
.loading-container {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
</style>
</head>
<body>
<div id="Container"></div>
<div class="loading-container">
<div class="circle"></div>
</div>
<script type="module">
// 等待SuperMap3D加载
if (typeof SuperMap3D !== 'undefined') {
initViewer();
} else {
console.error('SuperMap3D未正确加载');
}
function initViewer() {
const viewer = new SuperMap3D.Viewer('Container', {
contextOptions: {
contextType: 2,
msaaLevel: 2
},
timeline: false,
navigation: false
});
viewer.scenePromise.then(function(scene) {
loadScene(scene, viewer);
});
}
function loadScene(scene, viewer) {
scene.globe.show = false;
scene.skyAtmosphere.show = false;
const promise = scene.open("http://www.supermapol.com/realspace/services/3D-BIM-new/rest/realspace", null, {
autoSetView: false
});
SuperMap3D.when(promise, function() {
document.querySelector('.loading-container').style.display = 'none';
setupViewCube(viewer);
});
}
function setupViewCube(viewer) {
const layer = viewer.scene.layers.layerQueue[0];
const boundingSphere = layer.boundingSphere ||
SuperMap3D.BoundingSphere.fromRectangle3D(layer.layerBounds);
const distance = boundingSphere.radius * 3;
new ViewCube(viewer, {
language: "zh",
width: 250,
height: 250,
home: layer._matModel,
distance: distance,
showCompass: true,
fadeTime: 0.8
});
}
</script>
</body>
</html>
ViewCube不仅适用于BIM领域,在其他三维可视化场景中同样表现优异:
在实际项目中,我曾将ViewCube与热点标记结合使用:当用户点击某个热点时,不仅场景会聚焦到目标位置,ViewCube也会同步更新,形成完整的空间位置反馈。这种设计显著提升了用户体验。
对于需要更高定制化的场景,可以通过继承ViewCube类来实现自定义功能。例如添加一个"返回初始视角"按钮,或者集成到更大的控制面板中。ViewCube的API设计充分考虑了扩展性,让开发者能够灵活应对各种需求。