Skip to content

glTF 模型绘制

组合 DrawManager 与实体管理插件,在场景中交互选点,并通过 viewer.createEntity() 创建带 glTF/GLB 模型的装备。

概述

模型绘制不是一套独立的模型 Entity 工厂,而是两项既有公共能力的组合:

  • DrawManager 负责鼠标取点、提示、取消和交互资源清理;
  • viewer.createEntity() 负责装备身份、模型组件和生命周期管理。

这种职责分离确保模型装备始终进入 EntityManager,后续可以统一查询、更新、显隐和删除。DrawManager 完成点只是绘图结果,不应作为最终装备保留。

基础用法

typescript
import {
  CesiumViewer,
  DrawManager,
  viewerEntityMixin,
} from '@nexa/gis-cesium'
import { Cartographic, Math as CesiumMath } from 'cesium'

const nexaGis = new CesiumViewer('container')
nexaGis.extend(viewerEntityMixin)

const { viewer } = nexaGis
const drawManager = new DrawManager(viewer)

drawManager.onDrawComplete(({ mode, entity: marker, positions }) => {
  // DrawManager 返回的完成点不是装备,由调用方移除。
  viewer.entities.remove(marker)

  if (mode !== 'point' || !positions[0]) return
  const position = Cartographic.fromCartesian(positions[0])

  viewer.createEntity({
    id: `vehicle-${Date.now()}`,
    name: '地面车辆',
    entityType: 'vehicle',
    components: [
      {
        id: 'position',
        type: 'PositionComponent',
        lon: CesiumMath.toDegrees(position.longitude),
        lat: CesiumMath.toDegrees(position.latitude),
        alt: position.height,
      },
      {
        id: 'model',
        type: 'ModelComponent',
        url: '/static/GroundVehicle.glb',
        scale: 1,
      },
    ],
    modules: [],
  })
})

drawManager.startDraw('point')

多种装备预设

预设只保存装备数据,不直接创建 Cesium Entity。用户选点后,将预设转换为 ScenarioEntity 并交给 createEntity()

typescript
const presets = {
  operator: {
    name: '操作员',
    entityType: 'other',
    modelUrl: '/static/Cesium_Man.glb',
    scale: 2,
  },
  vehicle: {
    name: '地面车辆',
    entityType: 'vehicle',
    modelUrl: '/static/GroundVehicle.glb',
    scale: 1,
  },
}

let selectedPreset = presets.operator

function startPlacement(preset: keyof typeof presets): void {
  selectedPreset = presets[preset]
  drawManager.cancelDraw()
  drawManager.startDraw('point')
}

完整案例还演示了四种人员/车辆预设、模型选中轮廓、只清理自身装备,以及把当前部署结果导出为 GeoJSON FeatureCollection

资源所有权

资源所有者清理方式
鼠标事件、Tooltip、临时预览DrawManagerdrawManager.destroy()
绘制完成点调用方回调中 viewer.entities.remove(marker)
模型装备EntityManagerviewer.entityManager.remove(id) 或 Viewer 销毁钩子
选中事件注册事件的调用方执行 addEventListener() 返回的移除函数
下载 Object URL导出逻辑调用方URL.revokeObjectURL(url)

页面退出时不要调用 viewer.entities.removeAll() 清理装备,因为它可能误删其他模块创建的实体。应保存本功能创建的装备 ID,并逐个交给 EntityManager 删除。

清理

typescript
const removeSelectionListener = viewer.selectedEntityChanged.addEventListener(() => {
  // 更新本功能拥有的模型选中状态
})

function destroy(): void {
  drawManager.destroy()
  removeSelectionListener()

  for (const id of ownedEquipmentIds) {
    viewer.entityManager.remove(id)
  }
  ownedEquipmentIds.clear()
}

托管式 CesiumViewer 示例应把以上清理接入 Viewer 销毁钩子,确保切换案例或重置场景时不会残留 handler、Tooltip、事件监听或装备。

限制

  • 当前组合案例在地球/地形表面取点,不包含 3D Tiles 建筑表面贴附。
  • 模型上传、资源库管理以及平移、旋转、缩放编辑属于独立能力,不在模型绘制范围内。
  • 模型 URL 的可用性、跨域策略和授权由调用方负责。

相关链接