SuperMap Hi-Fi 3D SDK + Unity 2019.4:从零搭建一个可交互的3D智慧城市场景(含完整代码)
SuperMap Hi-Fi 3D SDK + Unity 2019.4:从零搭建可交互的3D智慧城市场景实战指南
当GIS数据与游戏引擎的实时渲染能力相遇,城市规划、智慧园区等领域的可视化应用便获得了全新的表达维度。本文将手把手带你用SuperMap Hi-Fi 3D SDK和Unity 2019.4构建一个完整的3D智慧城市交互场景——从数据准备到功能实现,每个环节都配有可直接复用的代码片段。
1. 环境配置与数据准备
在开始编码前,需要确保开发环境正确搭建。推荐使用Unity 2019.4 LTS版本(具体版本号2019.4.39f1),这是经过验证与SuperMap SDK兼容性最好的稳定版本。同时安装Visual Studio 2019作为代码编辑器,它能完美支持Unity的C#脚本调试。
关键工具下载清单:
| 工具名称 | 推荐版本 | 官方下载地址 |
|---|---|---|
| Unity Hub | 3.3.1或更高 | https://unity.cn/releases |
| SuperMap Hi-Fi 3D SDK | 11.1.1 | http://support.supermap.com.cn |
数据准备阶段需要三种核心资源:
- S3M缓存数据:建筑模型的二进制缓存文件(如Building.scp)
- 地形数据:DEM数字高程模型(如BeijingTerrain.sct)
- 影像底图:高分辨率卫星或航拍影像(如BeijingTerrain.sci3d)
提示:所有数据路径建议使用相对路径而非绝对路径,便于项目迁移。可将数据统一放在Assets/StreamingAssets文件夹下。
2. Unity项目初始化与SDK集成
新建Unity项目时,选择3D模板并命名为"SmartCityDemo"。导入SuperMap SDK的UnityPackage后,需特别注意以下配置:
// 初始化SDK的核心代码 using SuperMapSDK; void Start() { // 确保SDK单例初始化 if (!SupermapGIS.Instance.IsInitialized) { SupermapGIS.Instance.Initialize(); } // 设置场景地理空间参考 RealspaceView realspace = SupermapGIS.Instance.Realspace; realspace.SceneControl.Scene.CoordinateSystem = 4326; // WGS84坐标系 }常见问题排查:
- 如果场景加载后一片漆黑,检查相机位置是否在地形下方
- 模型显示异常时,确认S3M缓存生成时使用的坐标系与场景设置一致
3. 多源数据加载与场景构建
数据加载是智慧城市场景的基础,需要处理不同类型图层的加载顺序和显示控制:
public void LoadAllLayers() { // 地形图层(必须最先加载) string terrainPath = "StreamingAssets/BeijingTerrain_Terrain.sct"; SupermapGIS.Instance.Realspace.SceneControl.Scene.TerrainLayers.Add(terrainPath); // 影像底图 string imageryPath = "StreamingAssets/BeijingTerrain.sci3d"; SupermapGIS.Instance.Realspace.SceneControl.Scene.Layers.Add( imageryPath, Layer3DType.Map, false, "BaseMap" ); // 建筑模型 string buildingPath = "StreamingAssets/Building.scp"; Layer3D buildingLayer = SupermapGIS.Instance.Realspace.SceneControl.Scene.Layers.Add( buildingPath, Layer3DType.S3M, false, "Buildings" ); // 设置建筑模型显示范围 buildingLayer.MinVisibleDistance = 10; buildingLayer.MaxVisibleDistance = 5000; }图层加载优化技巧:
- 使用协程分帧加载大型数据集
- 对远离中心区的建筑启用LOD(细节层次)控制
- 动态加载/卸载图层基于视域范围
4. 交互功能实现
4.1 场景漫游控制
通过脚本实现第一人称和鸟瞰视角切换:
public class CameraController : MonoBehaviour { public float moveSpeed = 50f; public float rotateSpeed = 100f; void Update() { // WASD移动控制 float horizontal = Input.GetAxis("Horizontal") * moveSpeed * Time.deltaTime; float vertical = Input.GetAxis("Vertical") * moveSpeed * Time.deltaTime; transform.Translate(horizontal, 0, vertical); // 鼠标右键旋转 if (Input.GetMouseButton(1)) { float mouseX = Input.GetAxis("Mouse X") * rotateSpeed * Time.deltaTime; float mouseY = Input.GetAxis("Mouse Y") * rotateSpeed * Time.deltaTime; transform.Rotate(Vector3.up, mouseX); transform.Rotate(Vector3.left, mouseY); } } public void FlyToOverview() { CameraState state = new CameraState( 116.404, 39.915, // 北京天安门坐标 5000, // 高度5000米 -30, // 俯角30度 0, 0 // 无旋转 ); SupermapGIS.Instance.Realspace.SceneControl.Scene.Fly(state, 3000); } }4.2 模型属性查询
实现点击建筑显示属性信息的功能:
void HandleModelClick() { Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); RaycastHit hit; if (Physics.Raycast(ray, out hit)) { Layer3DS3MFile s3mLayer = hit.collider.GetComponentInParent<Layer3DS3MFile>(); if (s3mLayer != null) { int modelID = s3mLayer.GetObjectID(hit.point); Dictionary<string, object> attributes = s3mLayer.GetAllFieldValue(modelID); // 显示属性窗口 ShowAttributeWindow(attributes); } } }注意:需要给S3M图层添加碰撞体组件才能正确触发射线检测
5. 场景风格化定制
通过代码动态调整场景风格,实现白天/黑夜模式切换:
public void SetNightMode(bool isNight) { // 调整环境光 RenderSettings.ambientIntensity = isNight ? 0.3f : 1.0f; // 获取所有建筑图层 List<LayerInfo> layers = SupermapGIS.Instance.Layers.LayerInfos; foreach (LayerInfo layerInfo in layers) { Layer3D layer = layerInfo.Layer as Layer3D; if (layer != null && layer.Type == Layer3DType.S3M) { Style3D style = layer.Style; if (isNight) { // 夜间模式:建筑亮窗效果 style.EmissiveColor = new Color(0.8f, 0.8f, 0.1f); style.EmissiveIntensity = 1.5f; } else { // 日间模式:自然材质 style.EmissiveColor = Color.clear; } layer.Style = style; layer.UpdateData(); } } // 调整太阳位置 Light sun = GameObject.Find("Directional Light").GetComponent<Light>(); sun.transform.rotation = isNight ? Quaternion.Euler(150, 0, 0) : Quaternion.Euler(60, 0, 0); }风格参数对照表:
| 参数名称 | 日间值 | 夜间值 |
|---|---|---|
| 环境光强度 | 1.0 | 0.3 |
| 建筑自发光颜色 | Clear (0,0,0,0) | 暖黄色 (0.8,0.8,0.1) |
| 太阳高度角 | 60度 | 150度 |
6. 性能优化实战技巧
在大型城市场景中,性能优化至关重要。以下是经过验证的优化方案:
- 动态加载技术:
IEnumerator DynamicLoading() { while (true) { Vector3 cameraPos = Camera.main.transform.position; List<Layer3D> layers = GetLayersInView(cameraPos); foreach (Layer3D layer in allLayers) { bool shouldLoad = layers.Contains(layer); if (shouldLoad && !layer.IsLoaded) { layer.Load(); } else if (!shouldLoad && layer.IsLoaded) { layer.Unload(); } } yield return new WaitForSeconds(1f); // 每秒检测一次 } }- 遮挡剔除配置:
void SetupOcclusionCulling() { // 为建筑图层生成遮挡区域 Layer3DS3MFile buildingLayer = GetLayer("Buildings") as Layer3DS3MFile; if (buildingLayer != null) { buildingLayer.GenerateOcclusionArea(0.1f); // 10%的冗余度 } // 启用Unity原生遮挡剔除 Camera.main.useOcclusionCulling = true; }- 内存管理策略:
- 使用对象池管理动态创建的UI元素
- 对远离视点的模型自动降低LOD级别
- 定期调用Resources.UnloadUnusedAssets()
7. 项目打包与部署
完成开发后,需要根据目标平台进行打包:
WebGL平台特殊配置:
// 在启动脚本中添加 void Awake() { #if UNITY_WEBGL // 禁用多线程以提高兼容性 SupermapGIS.Instance.Config.MultithreadingEnabled = false; // 减小初始加载块大小 SupermapGIS.Instance.Config.ChunkSize = 512; #endif }PC平台打包清单:
- 确保包含所有数据文件:
- StreamingAssets文件夹完整复制
- 检查S3M缓存路径是否正确
- 添加必要的依赖项:
- SuperMap运行时库
- VC++ Redistributable
- 配置图形API:
- 优先使用DirectX11
- 保留OpenGL作为备选
在项目开发过程中,建议建立自动化构建管道,使用Unity命令行工具实现一键打包:
#!/bin/bash UNITY_PATH="/Applications/Unity/Hub/Editor/2019.4.39f1/Unity.app/Contents/MacOS/Unity" PROJECT_PATH="/Users/yourname/Projects/SmartCityDemo" BUILD_PATH="$PROJECT_PATH/Builds" $UNITY_PATH -quit -batchmode -projectPath $PROJECT_PATH -executeMethod BuildScript.BuildWindows64 -logFile -实际部署后发现,建筑模型加载时间过长的问题可以通过预加载关键区域数据来解决。在项目启动时先加载中心区域1km范围内的建筑,其他区域采用动态加载策略,这样既保证了初始加载速度,又不会影响完整功能的可用性。
