cesium-native+OpenGL开发笔记—渲染GIS球

坐标系转换

  • OpenGL 坐标系
    右手坐标系,X 轴水平向右,Y 轴竖直向上,Z 轴指向屏幕外面。
          Y(绿色,朝上)  
          ^  
          |  
          |  
          |  
          *----> X(红色,向右)  
         /  
        /  
       Z(蓝色,向前)  
      (指向屏幕外)  

  • 3D Tiles 坐标系
    右手坐标系, Z 轴朝上
         Z(蓝色,朝上)  
         ^  
         |  
         | /  Y(绿色,朝屏幕内)
         |/  
         *----> X(红色,朝右)  
  • glTF 模型坐标系
    右手坐标系,Y 轴朝上

在这里插入图片描述

  • 3D Tiles 和 OpenGL 坐标系上方向存在差异,实际绘制是在 OpenGL 坐标系下进行,需要调整。
CesiumGeospatial::LocalHorizontalCoordinateSystem CesiumGeoreference::createCoordinateSystem() {
    double scaleToMeters = 1.0 / scale;
    if (originPlacement == CesiumGeoreferenceOriginPlacement::TrueOrigin) {
    // 3D Tiles 坐标系轴向与OpenGL不同,需要转换
         glm::dmat4 localToEcef(
             glm::dvec4(scaleToMeters, 0.0, 0.0, 0.0),  
             glm::dvec4(0.0, 0.0, scaleToMeters, 0.0), // 将 3D Tiles 朝上的 Z 轴作为 OpenGL 朝上的 Y 轴
             glm::dvec4(0.0, -scaleToMeters, 0.0, 0.0), // 根据右手法则,在 X 轴朝向相同的情况下,3D Tiles Y 轴负方向作为 OpenGL Z 轴正方向
            glm::dvec4(0.0, 0.0, 0.0, 1.0)
        );
        return CesiumGeospatial::LocalHorizontalCoordinateSystem(localToEcef);
    }
	/**
     east(X)-up(Z)-south(Y)地理方位构成右手坐标系
           N
           |
     W ----|----- E
           |
           S
           
    **/
    if (originAuthority == CesiumGeoreferenceOriginAuthority::EarthCenteredEarthFixed) {
        return CesiumGeospatial::LocalHorizontalCoordinateSystem(glm::dvec3(ecefX, ecefY, ecefZ),
                                                                 CesiumGeospatial::LocalDirection::East,
                                                                 CesiumGeospatial::LocalDirection::Up,
                                                                 CesiumGeospatial::LocalDirection::South,
                                                                 scaleToMeters,
                                                                 ellipsoid->getNativeEllipsoid());
    }
    return CesiumGeospatial::LocalHorizontalCoordinateSystem(glm::dvec3(longitude, latitude, height),
                                                             CesiumGeospatial::LocalDirection::East,
                                                             CesiumGeospatial::LocalDirection::Up,
                                                             CesiumGeospatial::LocalDirection::South,
                                                             scaleToMeters,
                                                             ellipsoid->getNativeEllipsoid());
}

void *PrepareRendererResources::prepareInMainThread(Cesium3DTilesSelection::Tile &tile, void *pLoadThreadResult_) {
    // SPDLOG_INFO("---------prepare in main---------");
    const Cesium3DTilesSelection::TileContent &content = tile.getContent();
    const Cesium3DTilesSelection::TileRenderContent *pRenderContent = content.getRenderContent();
    if (!pRenderContent) {
        return nullptr;
    }

    std::unique_ptr<LoadThreadResult> pLoadThreadResult(static_cast<LoadThreadResult *>(pLoadThreadResult_));
    std::vector<std::shared_ptr<Mesh>> meshes = pLoadThreadResult->meshes;
    const std::vector<CesiumPrimitiveInfo> &primitiveInfos = pLoadThreadResult->primitiveInfos;

    const CesiumGltf::Model &model = pRenderContent->getModel();
    glm::dmat4 tileTransform = tile.getTransform();

    tileTransform = CesiumGltfContent::GltfUtilities::applyRtcCenter(model, tileTransform);
    tileTransform = CesiumGltfContent::GltfUtilities::applyGltfUpAxisTransform(model, tileTransform); 
    // 将模型从 glTF 的 Y 轴向上坐标系转换为 Cesium 的 Z 轴向上坐标系。
    tileTransform = tileTransform * CesiumGeometry::Transforms::Y_UP_TO_Z_UP;

    int32_t meshSize = meshes.size();
    if (!meshSize) {
        return nullptr;
    }

    std::string name = "glTF";
    auto urlIt = model.extras.find("Cesium3DTiles_TileUrl");
    if (urlIt != model.extras.end()) {
        name = urlIt->second.getStringOrDefault("glTF");
    }

    size_t meshIndex = 0;

    GameComponent* tilesetComponentPtr = pTileset;
    CesiumGeoreference* georeferencePtr = pTileset->getGeoreference();
    model.forEachPrimitiveInScene(
        -1,
        [tilesetComponentPtr, georeferencePtr, &meshes, &primitiveInfos, &meshIndex, &tile, &tileTransform](const CesiumGltf::Model &gltf,
                                                      const CesiumGltf::Node &node,
                                                      const CesiumGltf::Mesh &mesh,
                                                      const CesiumGltf::MeshPrimitive &primitive,
                                                      const glm::dmat4 &transform) {
        auto positionAccessorIt = primitive.attributes.find("POSITION");
        if (positionAccessorIt == primitive.attributes.end()) {
            return;
        }

        int32_t positionAccessorID = positionAccessorIt->second;
        CesiumGltf::AccessorView<glm::vec3> positionView(gltf, positionAccessorID);
        if (positionView.status() != CesiumGltf::AccessorViewStatus::Valid) {
            return;
        }

        const CesiumPrimitiveInfo &primitiveInfo = primitiveInfos[meshIndex];
        glm::dmat4 modelToEcef = tileTransform * transform;

        auto meshInstancePtr = meshes[meshIndex];
        meshInstancePtr->setParent(tilesetComponentPtr);

        // 地球锚点配置
        CesiumGlobeAnchor* anchor= new CesiumGlobeAnchor(georeferencePtr);
        meshInstancePtr->addGlobeAnchor(anchor);
        anchor->setDetectTransformChanges(false);
        anchor->setAdjustOrientationForGlobeWhenMoving(false);
        anchor->updateLocalToGlobeFixedMatrixAndEcef(modelToEcef);
        anchor->setParent(meshInstancePtr.get());

        const CesiumGltf::Material *pMaterial = CesiumGltf::Model::getSafe(&gltf.materials, primitive.material);
        if (pMaterial) {
            setGltfMaterialParameterValues(gltf, primitiveInfo, pMaterial, meshes[meshIndex++]);
        }
    });

    return new CesiumGltfObject{std::move(meshes), std::move(pLoadThreadResult->primitiveInfos)};
}

void PrepareRendererResources::attachRasterInMainThread(const Cesium3DTilesSelection::Tile &tile,
                                                        int32_t overlayTextureCoordinateID,
                                                        const CesiumRasterOverlays::RasterOverlayTile &rasterTile,
                                                        void *pMainThreadRendererResources,
                                                        const glm::dvec2 &translation,
                                                        const glm::dvec2 &scale) {
    const Cesium3DTilesSelection::TileContent &content = tile.getContent();
    const Cesium3DTilesSelection::TileRenderContent *pRenderContent = content.getRenderContent();
    if (!pRenderContent) {
        return;
    }

    CesiumGltfObject *pCesiumGltfObj = static_cast<CesiumGltfObject *>(pRenderContent->getRenderResources());
    Texture *pTexture = static_cast<Texture *>(pMainThreadRendererResources);
    if (!pCesiumGltfObj || pCesiumGltfObj->meshes.empty() || !pTexture) {
        return;
    }

    std::string key = rasterTile.getOverlay().getName();
    size_t primitiveIndex = 0;
    std::vector<std::shared_ptr<Mesh>> meshes = pCesiumGltfObj->meshes;
    std::vector<CesiumPrimitiveInfo> primitiveInfos = pCesiumGltfObj->primitiveInfos;
    for (size_t i = 0, len = meshes.size(); i < len; ++i) {
        const CesiumPrimitiveInfo &primitiveInfo = primitiveInfos[primitiveIndex++];
        auto texCoordIndexIt = primitiveInfo.rasterOverlayUvIndexMap.find(overlayTextureCoordinateID);
        if (texCoordIndexIt == primitiveInfo.rasterOverlayUvIndexMap.end()) {
            continue;
        }
        
        pTexture->offset = translation;
        pTexture->scale = scale;
        pTexture->flipY = true; // 纹理在Y方向需要翻转,否则瓦片贴图错乱
    
        std::vector<Texture> textures{*pTexture};
        meshes[i]->setTextures(textures);
    }
};

在这里插入图片描述

在这里插入图片描述

### Cesium Native 开发指南和资源 #### 了解 Cesium Native 的基础概念 Cesium Native 是一个用于创建高效、高质量三维地和地图应用程序的开源库。它允许开发者利用现代图形硬件加速渲染复杂场景,适用于桌面端以及移动端的应用开发[^1]。 #### 获取并安装 Cesium Native 为了开始使用 Cesium Native 进行开发,首先需要下载官方发布的 SDK 或者克隆 GitHub 上的仓库来获得最新版本。对于初次使用者来说,建议按照官方提供的快速入门教程来进行环境搭建,这通常包括设置编译工具链(如 CMake)、配置依赖项等操作。 #### 学习 API 及最佳实践 深入理解 Cesium Native 提供的各种类及其方法至关重要。官方文档不仅涵盖了详细的API说明,还提供了丰富的示例代码帮助学习如何实现特定功能。此外,探索社区贡献的例子也是掌握该技术的有效途径之一。这些实例往往展示了实际应用场景下的解决方案和技术细节。 #### 利用在线资源加深认识 除了阅读官方手册外,还可以访问论坛和其他社交平台上的讨论区寻求指导和支持。许多有经验的开发者会在那里分享自己的见解和个人项目经历,这些都是宝贵的学习材料。同时也可以关注一些知名博客或 YouTube 频道发布的内容,它们经常更新有关新技术趋势的文章视频。 ```cpp // 创建一个新的 Viewer 实例 #include "Viewer.hpp" using namespace cesium; int main() { auto viewer = std::make_shared<cesium::Viewer>(); // 设置初始视角位置 const double latitude = 37.8; const double longitude = -122.4; const double height = 10000; // 海拔高度 viewer->setView(latitude, longitude, height); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值