Cesium for UE4中的坐标系及其转换

Cesium for UE4中的坐标系及其转换

CesiumGeoreference Actor

Controls how global geospatial coordinates are mapped to coordinates in the Unreal Engine level.

Internally, Cesium uses a global Earth-centered,Earth-fixed (ECEF) ellipsoid-centered coordinate system, where the ellipsoid
is usually the World Geodetic System 1984 (WGS84) ellipsoid.

This is a right-handed system centered at the Earth’s center of mass, where +X is in the direction of the intersection of the Equator and the Prime Meridian (zero degrees longitude), +Y is in the direction of the intersection of the Equator and +90 degrees longitude, and +Z is through the North Pole.

This Actor is used by other Cesium Actors to control how this coordinate system is mapped into an Unreal Engine world and level.

CesiumGeoreference的用途主要是控制如何将地理空间坐标转换到虚幻引擎关卡中的坐标。

Cesium 使用的地心空间直角坐标系(ECEF),这里通常使用WGS84椭球体。

地心空间直角坐标系(ECEF)是一个以地球质心为中心的右手系,其中 +X :地球质心指向赤道与本初子午线的交点方向(0经度),+Y:地球质心指向赤道和+90度的子午线的交点方向,+Z:地球质心指向北极方向。

其他 Cesium Actor使用CesiumGeoreference Actor将地心空间直角坐标系(ECEF)映射到虚幻引擎世界和关卡的坐标系当中。

ECEF

源码分析

涉及到坐标参考系
  1. XYZ: ECEF 地球地心空间直角坐标系。

  2. BLH:地理坐标,经纬度,λ和φ。

  3. ENU: 东北天坐标系,也叫站心坐标系以用户所在位置(Pawn)为坐标原点。坐标系定义为: X轴:指向东边;Y轴:指向北边 ;Z轴:指向天顶。ENU局部坐标系采用三维直角坐标系来描述地球表面,实际应用较为困难,因此一般使用简化后的二维投影坐标系来描述。

  4. UE4的空间直角坐标系,前(x)+右(y)+上(z)。

转换关系如下图所示:

在这里插入图片描述

BLH<->ECEF:

地理坐标到地心空间直角坐标的转换(geodetic to geocenter)。

//BLH->ECEF
glm::dvec3
  cartographicToCartesian(const Cartographic& cartographic) const noexcept;
  
//ECEF->BLH
  std::optional<Cartographic>
  cartesianToCartographic(const glm::dvec3& cartesian) const noexcept;

glm::dvec3 center(0.0, 0.0, 0.0);
const CesiumGeospatial::Ellipsoid& ellipsoid =
          CesiumGeospatial::Ellipsoid::WGS84;

center = ellipsoid.cartographicToCartesian(
          CesiumGeospatial::Cartographic::fromDegrees(
              this->OriginLongitude,
              this->OriginLatitude,
              this->OriginHeight));

NEU<->ECEF:

两个空间直角坐标系的转换,只要计算出转换矩阵即可。

//ENU 到 ECEF 的转换矩阵
this->_georeferencedToEcef =
        CesiumGeospatial::Transforms::eastNorthUpToFixedFrame(center);
// 求逆,即ECEF->ENU

this->_ecefToGeoreferenced = glm::affineInverse(this->_georeferencedToEcef);
原点的定义

设置NEU的坐标原点的位置。

UENUM(BlueprintType)
enum class EOriginPlacement : uint8 {
  /**
   * Use the tileset's true origin as the Actor's origin. For georeferenced
   * tilesets, this usually means the Actor's origin will be at the center
   * of the Earth.
   */
  TrueOrigin UMETA(DisplayName = "True origin"),

  /*
   * Use the center of the tileset's bounding volume as the Actor's origin. This
   * option preserves precision by keeping all tileset vertices as close to the
   * Actor's origin as possible.
   */
  BoundingVolumeOrigin UMETA(DisplayName = "Bounding volume center"),

  /**
   * Use a custom position within the tileset as the Actor's origin. The
   * position is expressed as a longitude, latitude, and height, and that
   * position within the tileset will be at coordinate (0,0,0) in the Actor's
   * coordinate system.
   */
  CartographicOrigin UMETA(DisplayName = "Longitude / latitude / height")
};
  1. True origin

    设置NEU和ECEF一致。将Actor的原点设置为地球质心。

  2. Bounding volume center

    使用包围盒的中心作为Actor的原点。这种设置使所有tileset的顶点尽可能的靠近Actor的原点,保证其精度。

  3. Longitude / latitude / height

    使用tileset中自定义的位置来作为Actor的原点。可以使用过经纬度和高程来表示其位置,这样的话在Actor的坐标系统中tileset的位置将会变成(0,0,0)。

四个坐标转换矩阵
  // ENU转ECEF (ENU->XYZ)
  glm::dmat4 _georeferencedToEcef;
  // ECEF转ENU (XYZ->ENU)
  glm::dmat4 _ecefToGeoreferenced;
  // UE4 绝对坐标转 ECEF 
  glm::dmat4 _ueAbsToEcef;
  //  ECEF 转 UE4 绝对坐标
  glm::dmat4 _ecefToUeAbs;

构造函数中四个矩阵初始化为单位矩阵:

ACesiumGeoreference::ACesiumGeoreference()
    : _georeferencedToEcef(1.0),
      _ecefToGeoreferenced(1.0),
      _ueAbsToEcef(1.0),
      _ecefToUeAbs(1.0),
      _insideSublevel(false) {
  PrimaryActorTick.bCanEverTick = true;
}

四个矩阵的更新:

void ACesiumGeoreference::UpdateGeoreference() {

  // update georeferenced -> ECEF

   //  将Actor的原点放置在ECEF的中心,即 NEU和ECEF重合。

  if (this->OriginPlacement == EOriginPlacement::TrueOrigin) {
    this->_georeferencedToEcef = glm::dmat4(1.0);
  } 
  else
  {

    glm::dvec3 center(0.0, 0.0, 0.0);

    //将Actor的原点放置在tileset的包围盒中心

    if (this->OriginPlacement == EOriginPlacement::BoundingVolumeOrigin) 
    {

      // TODO: it'd be better to compute the union of the bounding volumes and
      // then use the union's center,
      //       rather than averaging the centers.


      // 遍历每一个地理参考的对象,合并计算它们包围盒的中心

      size_t numberOfPositions = 0;

      for (const TWeakInterfacePtr<ICesiumGeoreferenceable> pObject : this->_georeferencedObjects) 
      {
        if(pObject.IsValid() && pObject->IsBoundingVolumeReady()) 
        {
          std::optional<Cesium3DTiles::BoundingVolume> bv = pObject->GetBoundingVolume();
          if (bv) 
          {
            center += Cesium3DTiles::getBoundingVolumeCenter(*bv);
            ++numberOfPositions;
          }
        }
      }

      if (numberOfPositions > 0) 
      {
        center /= numberOfPositions;
      }

    } 

    //使用自定义经纬度高程设置原点位置

    else if (this->OriginPlacement == EOriginPlacement::CartographicOrigin) 
    {

      const CesiumGeospatial::Ellipsoid& ellipsoid = CesiumGeospatial::Ellipsoid::WGS84;

        //由经纬度高程换算到ECEF中的位置,并将其作为原点

      center = ellipsoid.cartographicToCartesian(CesiumGeospatial::Cartographic::fromDegrees(
              this->OriginLongitude,
              this->OriginLatitude,
              this->OriginHeight));
    }

     // 上述两种center设置是ENU原点在ECEF当中的坐标,ENU->ECEF的计算。

    this->_georeferencedToEcef =
        CesiumGeospatial::Transforms::eastNorthUpToFixedFrame(center);
  }


  // update ECEF -> georeferenced
  // 求逆矩阵
  this->_ecefToGeoreferenced = glm::affineInverse(this->_georeferencedToEcef);

  // update UE -> ECEF
  // 
  this->_ueAbsToEcef = this->_georeferencedToEcef *
                       CesiumTransforms::scaleToCesium *
                       CesiumTransforms::unrealToOrFromCesium;

  // update ECEF -> UE
  this->_ecefToUeAbs = CesiumTransforms::unrealToOrFromCesium *
                       CesiumTransforms::scaleToUnrealWorld *
                       this->_ecefToGeoreferenced;

  //通知所有Object参考系的变化

  for (TWeakInterfacePtr<ICesiumGeoreferenceable> pObject :
       this->_georeferencedObjects) {
    if (pObject.IsValid()) {
      pObject->NotifyGeoreferenceUpdated();
    }
  }

  this->_setSunSky(this->OriginLongitude, this->OriginLatitude);
}

参考

  1. 地心坐标系
  2. Cesium for UE4 wiki
  • 8
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值