Guía Práctica de CesiumJS para Desarrollo de Geovisualización 3D

CesiumJS es una biblioteca de JavaScript de código abierto y de alto rendimiento diseñada para la creación de aplicaciones de visualización geoespacial 3D basadas en la web. Su motor WebGL permite la representación de grandes conjuntos de datos geográficos, modelos terrestres de alta precisión y la visualización dinámica de datos.

Este artículo se basa en la versión 1.119 de CesiumJS.

Preparación en un entorno Vue 3 con Vite

Para integrar Cesium en un proyecto Vue 3, instale las dependencias necesarias y configure el complemento de Vite.

npm install cesium@1.119
npm install vite-plugin-cesium -D

La configuración en vite.config.js debe incluir el plugin de Cesium.

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue';
import cesium from 'vite-plugin-cesium';

export default defineConfig({
  plugins: [vue(), cesium()]
})

Inicialiazción del Visor Cesium

El componente principal es el Viewer. Su inicialización requiere un token de acceso y un contenedor DOM.

<template>
  <div id="cesiumViewport"></div>
</template>

<script setup>
import { onMounted } from 'vue';
import * as Cesium from 'cesium';
import 'cesium/Build/Cesium/Cesium';

Cesium.Ion.defaultAccessToken = 'TU_CESIUM_ION_TOKEN';

const initializeViewer = () => {
  const viewerInstance = new Cesium.Viewer('cesiumViewport', {
    baseLayerPicker: false,
    geocoder: false,
    sceneModePicker: true,
    animation: false,
    timeline: false,
    vrButton: false,
    infoBox: false,
    shadows: true,
  });

  // Ocultar la atribución de Cesium en la esquina
  viewerInstance.cesiumWidget.creditContainer.style.display = 'none';
};

onMounted(initializeViewer);
</script>

Carga de Capas de Imágenes

Cesium soporta múltiples proveedores de imágenes, como ArcGIS, Bing Maps y OpenStreetMap. Por defecto, carga Bing Maps si no se especifica otro.

const imageryProvider = new Cesium.OpenStreetMapImageryProvider({
  url: 'https://a.tile.openstreetmap.org/'
});

const viewer = new Cesium.Viewer('cesiumViewport', {
  imageryProvider: imageryProvider,
});

Integración de Terreno 3D

El terreno mundial de Cesium proporciona un modelo terrestre tridimensional detallado, incluyendo relieve y cuerpos de agua.

async function setupViewerWithTerrain() {
  const viewer = new Cesium.Viewer('cesiumViewport', {
    terrainProvider: await Cesium.createWorldTerrainAsync({
      requestWaterMask: true, // Habilita la detección de cuerpos de agua
      requestVertexNormals: true, // Habilita sombreado basado en normales
    }),
  });
  return viewer;
}

Representación de Datos 3D Tiles

3D Tiles es un formato para la transmisión eficiente de grandes modelos 3D, como ciudades enteras. Los datos se dividen en teselas para una carga y renderizado óptimos.

Carga de un conjunto de tiles desde Ion

Los recursos de Cesium Ion se pueden cargar usando su ID de activo.

async function loadCesiumOsmBuildings(viewer) {
  const osmBuildingsTileset = await Cesium.Cesium3DTileset.fromIonAssetId(96188);
  viewer.scene.primitives.add(osmBuildingsTileset);

  // Enfocar la vista en una ubicación específica
  viewer.camera.flyTo({
    destination: Cesium.Cartesian3.fromDegrees(-74.006, 40.7128, 500),
    orientation: {
      heading: Cesium.Math.toRadians(0),
      pitch: Cesium.Math.toRadians(-45),
      roll: 0.0
    }
  });
}

Estilizado condicional de entidades 3D Tiles

Se pueden aplicar estilos basados en propiedadse como la altura o la ubicación geográfica.

function styleBuildingsByHeight(tileset) {
  tileset.style = new Cesium.Cesium3DTileStyle({
    color: {
      conditions: [
        ['${Height} >= 200', "color('#FF5733')"],  // Color para edificios altos
        ['${Height} >= 100', "color('#FFC300')"],  // Color para edificios medianos
        ['${Height} >= 50',  "color('#DAF7A6')"],  // Color para edificios bajos
        ['true',            "color('#900C3F')"]    // Color por defecto
      ]
    }
  });
}

Manejo de interacción con el ratón

Se pueden detectar eventos como pasar el ratón sobre un edificio para resaltarlo o mostrar información.

function enableBuildingHoverInteraction(viewer, tileset) {
  const screenEventHandler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
  let highlightedEntity = null;
  const originalColor = new Cesium.Color();

  screenEventHandler.setInputAction(function onMouseMove(movement) {
    if (highlightedEntity) {
      highlightedEntity.color = Cesium.Color.clone(originalColor);
    }

    const pickedFeature = viewer.scene.pick(movement.endPosition);
    if (Cesium.defined(pickedFeature) && pickedFeature instanceof Cesium.Cesium3DTileFeature) {
      highlightedEntity = pickedFeature;
      Cesium.Color.clone(pickedFeature.color, originalColor);
      pickedFeature.color = Cesium.Color.YELLOW;
      // Mostrar tooltip con propiedades, ej: pickedFeature.getProperty('name')
    }
  }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
}

Visualización de Datos Vectoriales

GeoJSON

GeoJSON es un formato común para intercambiar datos geográficos simples.

async function loadGeoJSONDataSource(viewer, geojsonUrl) {
  const geoJsonDataSource = await Cesium.GeoJsonDataSource.load(geojsonUrl, {
    stroke: Cesium.Color.GREENYELLOW,
    fill: Cesium.Color.GREEN.withAlpha(0.3),
    strokeWidth: 2
  });
  viewer.dataSources.add(geoJsonDataSource);
  viewer.zoomTo(geoJsonDataSource);
}

KML y CZML

KML es un formato XML para datos geográficos, mientras que CZML es un formato JSON específico de Cesium para describir escenas dinámicas.

// Ejemplo de carga de KML
async function loadKmlData(viewer, kmlUrl) {
  const kmlDataSource = await Cesium.KmlDataSource.load(kmlUrl, {
    camera: viewer.scene.camera,
    canvas: viewer.scene.canvas
  });
  viewer.dataSources.add(kmlDataSource);
}

// Ejemplo de carga de CZML
async function loadCzmlData(viewer, czmlUrl) {
  const czmlDataSource = await Cesium.CzmlDataSource.load(czmlUrl);
  viewer.dataSources.add(czmlDataSource);
}

Importación de Modelos glTF

glTF es un formato eficiente para modelos 3D. Se pueden cargar usando entidades.

function loadGltfModel(viewer, modelUrl, positionDegrees) {
  const position = Cesium.Cartesian3.fromDegrees(...positionDegrees);
  const modelEntity = viewer.entities.add({
    position: position,
    model: {
      uri: modelUrl,
      scale: 1.0,
      minimumPixelSize: 64
    }
  });
  viewer.trackedEntity = modelEntity;
}

Configuración de la Escena

El objeto scene controla la apariencia visual global, como el fondo, la atmósfera y el sol.

function configureSceneAppearance(viewer) {
  viewer.scene.backgroundColor = Cesium.Color.fromCssColorString('#1a1a2e');
  viewer.scene.fog.enabled = true;
  viewer.scene.fog.density = 0.0002;
  viewer.scene.globe.enableLighting = true;
  viewer.scene.sun.show = true;
  viewer.scene.moon.show = true;
}

Control de la Cámara

La cámara se puede manipular para establecer vistas iniciales o animaciones de vuelo.

function flyToLocation(viewer, longitude, latitude, height, heading, pitch) {
  viewer.camera.flyTo({
    destination: Cesium.Cartesian3.fromDegrees(longitude, latitude, height),
    orientation: {
      heading: Cesium.Math.toRadians(heading),
      pitch: Cesium.Math.toRadians(pitch),
      roll: 0.0
    },
    duration: 3 // Duración de la animación en segundos
  });
}

Gestión del Tiempo y Animación

El reloj (clock) gestiona la simulación del tiempo para animaciones.

function setupClockAnimation(viewer, start, stop, speedMultiplier) {
  viewer.clock.startTime = Cesium.JulianDate.fromDate(start);
  viewer.clock.stopTime = Cesium.JulianDate.fromDate(stop);
  viewer.clock.currentTime = Cesium.JulianDate.fromDate(start);
  viewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP; // Bucle
  viewer.clock.multiplier = speedMultiplier;
  viewer.clock.shouldAnimate = true;

  // Ejemplo de reacción al tick del reloj
  viewer.clock.onTick.addEventListener((clock) => {
    // Actualizar lógica basada en el tiempo de la simulación
  });
}

Creación y Manipulación de Entidades

Las entidades representan objetos en la escena (puntos, líneas, modelos, etc.).

function addComplexEntity(viewer, positionDegrees) {
  const position = Cesium.Cartesian3.fromDegrees(...positionDegrees);
  const entity = viewer.entities.add({
    name: 'Punto de Interés',
    position: position,
    point: {
      pixelSize: 10,
      color: Cesium.Color.SKYBLUE,
      outlineColor: Cesium.Color.WHITE,
      outlineWidth: 2
    },
    label: {
      text: 'POI',
      font: '14pt sans-serif',
      style: Cesium.LabelStyle.FILL_AND_OUTLINE,
      outlineWidth: 2,
      verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
      pixelOffset: new Cesium.Cartesian2(0, -9)
    },
    billboard: {
      image: 'ruta/a/icono.png',
      width: 32,
      height: 32
    }
  });
  return entity;
}

// Eliminar una entidad específica
function removeEntityById(viewer, entityId) {
  const entity = viewer.entities.getById(entityId);
  if (entity) viewer.entities.remove(entity);
}

// Eliminar todas las entidades
function clearAllEntities(viewer) {
  viewer.entities.removeAll();
}

Etiquetas: CesiumJS WebGL Vue 3 Vite 3D Tiles

Publicado el 6-11 17:14