Cesium入门之九:Cesium加载gltf文件

glTF文件介绍

glTF(Graphics Library Transmission Format)是一种用于存储3D模型和场景的格式。它是一种开放的标准格式,可用于在不同的3D引擎和软件之间传输和交换3D模型和场景数据。

glTF文件包含了设计场景或模型的几何形状、材质、纹理、动画等信息,同时有很好的兼容性和可扩展性。glTF文件基于JSON格式,具有易于阅读和修改的特点,同时也易于使用编程语言进行解析和使用。

glTF支持两种文件格式:*.glTF和 *.glb。

.glTF是一个基于JSON格式的文本文件,它可以包含场景、节点、网格信息、材质、动画、相机等3D模型元素,并且可以包括外部资源,如纹理、图像和二进制数据等。.glTF文件易于阅读、修改和编辑,同时可以使用gzip进行压缩以减小文件大小。但是.glTF文件格式在处理复杂场景时,可能会变得比较冗长,处理速度较慢。

.glb是一种基于二进制的文件格式,它包含所有的glTF数据,包括所有的外部资源。由于.glb文件是二进制文件,大大减小了文件大小和加载时间,同时保持了.glTF文件的灵活性和可编辑性。.glb文件也可以使用gzip压缩以进一步减小文件大小。但是.glb文件格式作为二进制文件,难以直接进行编辑和修改。

Cesium中的模型坐标系

在Cesium中,为了确保各种数据都可以在三维场景中正确地显示和交互,定义了一个特定的模型坐标系,即ENU坐标系,其中ENU代表东北上。

  • 东(East):X轴朝向地球表面东方,单位为米。
  • 北(North):Y轴朝向地球表面北方,单位为米。
  • 上(Up):Z轴朝向地心,在ENU坐标系中通常是指垂直于地球表面的向上方向,单位为米。

在默认状态下,Cesium场景的坐标系原点位于地心,在地球表面上方的大气层之外,坐标轴和地球表面相切。假设我们要添加一个三维模型到Cesium场景中,我们需要确保该模型使用ENU坐标系并位于与地球表面相切的位置。可以通过以下步骤将模型从外部坐标系(如笛卡尔坐标系)转换到ENU坐标系。

  1. 将模型从外部坐标系转换到笛卡尔坐标系。

  2. 将笛卡尔坐标系中的坐标点转换到ENU坐标系中的坐标点。

  3. 将ENU坐标系中的原点与地球表面相切。

要将模型从外部坐标系转换到ENU坐标系,我们需要使用Cesium的坐标转换功能。Cesium提供了许多函数和对象,用于将3D模型从外部坐标系转换到ENU坐标系。

相关类介绍

Cesium.Cartesian3(x, y, z)类

Cesium.Cartesian3是Cesium库中用于表示三维世界空间中笛卡尔坐标的类。每个Cartesian3实例都代表了空间中的一个点,可以用其X、Y和Z坐标分量来描述。

  • x 坐标表示在东西方向上的位移,单位为米。
  • y 坐标表示在南北方向上的位移,单位为米。
  • z 坐标表示在垂直于地球表面的方向上的位移,单位为米。

Cartesian3的常用方法

  • Cartesian3.add(left, right, result): 将两个向量相加,结果存储在result对象中。
  • Cartesian3.subtract(left, right, result): 将两个向量相减,结果存储在result对象中。
  • Cartesian3.magnitude(cartesian): 返回向量的长度。
  • Cartesian3.normalize(cartesian, result): 返回向量的单位向量,结果存储在result对象中。
  • Cartesian3.dot(left, right): 返回两个向量的点积。
  • Cartesian3.cross(left, right, result): 返回两个向量的叉积,结果存储在result对象中。
  • Cesium.Cartesian3.fromDegrees(longitude, latitude, height, ellipsoid, result):用于将给定经纬度高程坐标转换为笛卡尔坐标系下的向量的函数。
    该函数接受五个参数longitude、latitude、height、ellipsoid和result。longitude和latitude是以度为单位的浮点数,表示地球表面上几何点所对应的经度和纬度。height是这个几何点的高程值(以海平面作为参考)。ellipsoid是一个可选参数,表示使用的椭球体,如果未提供,则使用WGS84椭球体。result是一个可选的Cartesian3对象,表示转换后的笛卡尔坐标系下的向量。如果未提供result参数,则新创建一个Cartesian3对象,其中计算后的向量储存在其中,然后返回该对象。
    该函数首先将经度和纬度转换为弧度,并根据该椭球体的参数计算该几何点的地心向径。使用此信息可以计算笛卡尔坐标,同时可将高度添加到Z分量中。

Cartesian3示例:
以下代码将两个Cartesian3对象相加,并输出结果:

var a = new Cesium.Cartesian3(1, 2, 3);
var b = new Cesium.Cartesian3(4, 5, 6);
var result = new Cesium.Cartesian3();
Cesium.Cartesian3.add(a, b, result);
console.log(result); // Cartesian3{x: 5, y: 7, z: 9}

在Cesium的场景中,Cartesian3对象通常用于表示场景中的位置和方向。例如,当我们在3D场景中选择一个对象后,返回的结果就是一个包含位置坐标的Cartesian3对象。它们还可以用于执行向量运算和执行3D图形的变换。

Cesium.HeadingPitchRoll(heading, pitch, roll) 类

Cesium.HeadingPitchRoll是一个定义方位、俯仰和滚转角度的类,该类用于描述3D物体的旋转状态。该类的构造函数使用三个参数headingpitchroll来分别定义目标物体绕Y轴的旋转角度(方位)、绕X轴的旋转角度(俯仰)和绕Z轴的旋转角度(滚转),并把它们存储在类的实例中以供使用。

所有参数都是以弧度为单位的浮点数,且值在-π到π之间。heading参数定义了绕Y轴旋转的角度,以正北方向为0度。pitch参数定义了物体绕X轴旋转的角度,以水平位置为0度,向上旋转为正,向下旋转为负。roll参数定义了物体绕Z轴旋转的角度,以输入的旋转方向的垂直方向为0度。

例如,以下代码创建了一个绕Y、X和Z轴分别旋转45度的旋转状态:

var heading = Cesium.Math.toRadians(45);
var pitch = Cesium.Math.toRadians(45);
var roll = Cesium.Math.toRadians(45);

var hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll);

对于通过Cesium.HeadingPitchRoll构造函数创建的旋转状态,我们可以使用以下示例代码中的实例方法来获得和设置旋转状态对象的特定成分:

var hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll);

// 获取当前HPR对象的heading、pitch和roll值
var currentHeading = hpr.heading;
var currentPitch = hpr.pitch;
var currentRoll = hpr.roll;

// 设置HPR对象的heading、pitch和roll值
hpr.heading = Cesium.Math.toRadians(90);
hpr.pitch = Cesium.Math.toRadians(-45);
hpr.roll = Cesium.Math.toRadians(0);

也可以使用以下示例代码创建一个包含默认旋转(均为0度)的Cesium.HeadingPitchRoll对象:

var hpr = new Cesium.HeadingPitchRoll();

常用转换函数

Cesium.Transforms.eastNorthUpToFixedFrame(origin, ellipsoid, result) 函数

Cesium.Transforms.eastNorthUpToFixedFrame(origin, ellipsoid, result)是Cesium中用于计算以给定点为原点的地心坐标系的转换矩阵的方法。该方法接受三个参数:

  • origin: 以笛卡尔坐标系表示的点,即作为地心坐标系原点的点。
  • ellipsoid(可选): Earth Ellipsoid对象(默认为WGS84椭球体),用于计算与地心坐标系相关的坐标。
  • result(可选):用于存储结果转换矩阵的Matrix4对象。

该方法返回一个Matrix4对象,该对象表示将ENU坐标系(东北向上)转换为以指定原点为中心的地心坐标系所需的变换矩阵。该方法计算的结果矩阵与ENU坐标系的单位向量旋转和平移有关,可以使用该矩阵来将3D对象从ENU坐标系转换为地心坐标系。

例如,以下代码将纽约的地理坐标(-74.00,40.71)作为原点,计算出以该点为原点的地心坐标系的转换矩阵:

var origin = Cesium.Cartesian3.fromDegrees(-74.00, 40.71, 0);
var enuToFixedFrameTransform = Cesium.Transforms.eastNorthUpToFixedFrame(origin);

如果需要将3D对象从东北向上的ENU坐标系转换为指定原点的地心坐标系,则可以使用该矩阵将其转换为所需的参考系。例如:

var enuPoint = new Cesium.Cartesian3(10, 10, 0);
var fixedFramePoint = new Cesium.Cartesian3();
Cesium.Matrix4.multiplyByPoint(enuToFixedFrameTransform, enuPoint, fixedFramePoint);

在上面的代码中,enuPoint表示在ENU坐标系中的一个点(假设该点可以表示为(10,10,0))。通过使用变换矩阵将该点转换为地心坐标系。结果存储在fixedFramePoint变量中 ,即此点在地心坐标系的一个位置。

Cesium.Transforms.headingPitchRollQuaternion(origin, headingPitchRoll, ellipsoid, fixedFrameTransform, result) 函数

Cesium.Transforms.headingPitchRollQuaternion(origin, headingPitchRoll, ellipsoid, fixedFrameTransform, result)函数是Cesium API中用于将给定原点,方位、俯仰和滚转转换为四元数的函数。该函数的其余参数可用于指定椭球体、参考框架和结果的传出四元数。

origin参数是一个Cartesian3对象,它定义了旋转的中心点。输入的headingPitchRoll参数是一个带有方位、俯仰和滚转角度的HeadingPitchRoll对象。需要注意的是,输入的这三个角度应该以弧度为单位。

可选参数ellipsoid定义了参与旋转的椭球体,如果未指定,则使用标准的WGS84椭球体。fixedFrameTransform参数可以被用来在结果四元数应用于一个不同的设备坐标系的情况下调整结果的方向。result参数是一个输出结果的空对象,如果该参数被省略,则会创建一个新的四元数对象来存储结果。如果提供了该参数,则该函数修改该对象而不是创建一个新的对象。

以下是一些该函数的示例用法:

var origin = Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883);
var heading = Cesium.Math.toRadians(90);
var pitch = 0;
var roll = 0;
var hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll);

// 默认椭球体(WGS84),默认坐标系(惯性坐标系)下的旋转
var quat1 = Cesium.Transforms.headingPitchRollQuaternion(origin, hpr);

// 在一个不同的坐标系下的旋转
var fixedFrameTransform = Cesium.Transforms.northEastDownToFixedFrame(origin);
var quat2 = Cesium.Transforms.headingPitchRollQuaternion(origin, hpr, undefined, fixedFrameTransform);

// 使用不同的椭球体,并使用提供的四元数存储结果
var ellipsoid = Cesium.Ellipsoid.UNIT_SPHERE;
var quat3 = new Cesium.Quaternion();
Cesium.Transforms.headingPitchRollQuaternion(origin, hpr, ellipsoid, undefined, quat3);

上述代码基于给定的origin原点、heading, pitch和 roll角度计算了一个四元数旋转。第一个示例创建了一个默认的旋转,并存储在quat1中。第二个示例中,使用了一个变换矩阵进行了固定坐标系的旋转,结果被存储在quat2中。第三个示例使用给定的椭球体并将结果存储在提供的quat3四元数对象中。

Cesium加载gltf文件的方法

在Cesium中加载gltf文件,可以使用viewer.entities.add方法进行加载,在这里需要注意一个细节,在add方法中加载model时,配置的参数是uri,不是url,这里一定要注意,否则会无法加载
在这里插入图片描述
详细代码如下

<template>
  <div id="cesiumContainer"></div>
</template>
<script setup>
import * as Cesium from 'cesium' 
import {
    
     onMounted } from 'vue'; 
// import modelFile from '/feiji.glb'
let viewer, imageLayers
onMounted(async () => {
    
     
  // 初始化Cesium
  initViewer()
  // 加载影像数据
  addImageLayers()
  // 加载gltf数据
  addGLTFModel('/feiji.glb', 4000)
})

function initViewer() {
    
    
  viewer = new Cesium.Viewer('cesiumContainer', {
    
    
    animation: false,//动画小部件
    baseLayerPicker: false,//地图图层组件
    fullscreenButton: false,//全屏组件
    geocoder: false,//地理编码搜索组件
    homeButton: false,//首页组件
    infoBox: false,//信息框
    sceneModePicker: false,//场景模式
    selectionIndicator: false,//选取指示器组件
    timeline: false,//时间轴
    navigationHelpButton: false,//帮助按钮
    navigationInstructionsInitiallyVisible: false,
  })
  // console.log(viewer);
  // 隐藏logo信息
  viewer._cesiumWidget._creditContainer.style.display = 'none'
  // 隐藏地球
  // viewer.scene.globe.show = false
  imageLayers = viewer.imageryLayers
  viewer.scene.globe.depthTestAgainstTerrain = true;// 随着地图缩放深度增加会导致数据获取不到,所以需要进行开启深度监测
  // console.log(imageLayers);
}
async function addImageLayers() {
    
    
  imageLayers.remove(imageLayers.get(0)) //清楚Cesium默认加载的影像地图数据(默认是加载的bing地图) 
  // Bing地图
  const bing = await Cesium.BingMapsImageryProvider.fromUrl(
    "https://dev.virtualearth.net", {
    
    
    key: "AodxPjHCueIzbuOPovDaDba7D6qpNMPdJ8nt96KsDjKIs0yz5j4jTuNMdMdO6tJZ",
    mapStyle: Cesium.BingMapsStyle.AERIAL//可选参数,指定地图样式
  })
  imageLayers.addImageryProvider(bing) 
}
async function addGLTFModel(url, height) {
    
       
  // Entity方法加载gltf
  viewer.entities.removeAll() //加载之前先清楚所有entity
  const position = Cesium.Cartesian3.fromDegrees(-123.0744619, 44.0503706, height)
  const heading = Cesium.Math.toRadians(135) //135度转弧度
  const pitch = Cesium.Math.toRadians(0);
  const roll = 0
  const hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll)
  const orientation = Cesium.Transforms.headingPitchRollQuaternion(
    position,
    hpr
  )  
  const entity = await viewer.entities.add({
    
    
    name: 'feiji',
    position: position,
    orientation: orientation,
    model: {
    
     
      uri: url,//注意entitits.add方式加载gltf文件时,这里是uri,不是url,并且这种方式只能加载.glb格式的文件
      scale: 1.0,//缩放比例
      minimumPixelSize: 128,//最小像素大小,可以避免太小看不见
      maximumScale: 20000,//模型的最大比例尺大小。minimumPixelSize的上限  
      incrementallyLoadTextures: true,//加载模型后纹理是否可以继续流入
      runAnimations: true,//是否启动模型中制定的gltf动画
      clampAnimations: true,//制定gltf动画是否在没有关键帧的持续时间内保持最后一个姿势
      shadows: Cesium.ShadowMode.ENABLED,
      heightReference: Cesium.HeightReference.NONE
    }
  }) 
  viewer.trackedEntity = entity; // 聚焦模型
  viewer.zoomTo(entity)
}
</script>
<style  scoped></style>

运行代码,刷新浏览器,可以看到gltf模型已经加载到页面中了
在这里插入图片描述
好了,今天就到这里,有问题的评论区留言,喜欢的小伙伴关注点赞加收藏哦

猜你喜欢

转载自blog.csdn.net/w137160164/article/details/130788090