欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

GANOS 3D引擎详解系列之一:深度剖析倾斜摄影数据管理和可视化功能

最编程 2024-02-18 11:03:51
...

关于Ganos

Ganos是阿里云数据库产品事业部联合阿里巴巴达摩院数据库与存储实验室联合共同研发的新一代云原生位置智能引擎,它将时空数据处理能力融入了云原生关系型数据库PolarDB、云原生多模数据库Lindorm、云原生数据仓库AnalyticDB和云数据库RDS PG等核心产品中。Ganos目前拥有几何、栅格、轨迹、表面网格、体网格、3D实景、点云、路径、地理网格、快显十大核心引擎,为数据库构建了面向新型多模多态时空数据的存储、查询、分析、服务等一体化能力。

网络异常,图片无法展示
|

本文介绍的三维引擎能力,依托阿里云云原生关系型数据库PolarDB建设输出。

关于Ganos三维引擎

三维数据管理是当前时空领域的热点,以数字孪生为代表的一系列三维空间系统应运而生,推动各类管理业务逐步走向精细。这种背景下,三维数据采集类别越发多样,采集精度越发提升,业务背后的三维空间计算效率与大规模三维模型渲染效率也逐步成为空间信息系统的痛点。

为了降低技术栈的复杂性,解决三维数据管理方面的痛难点,Ganos自v5.0版本全面推出了三维引擎,库内提供三维空间数据存储、分析与可视化渲染支撑能力。随着多个小版本的迭代,目前Ganos三维引擎已经构建了视算一体的闭环能力,并在多个项目的验证中三维空间计算效率相较传统技术栈有百倍提升。从本篇文章开始,Ganos团队将以系列文章的方式,介绍三维引擎的各项能力。

三维引擎概述

为了解决传统空间技术栈中“文件管、瓦片看、客户端算”所带来的数据资产分散、数据冗余及技术架构复杂问题,Ganos提出了基于大规模元胞网格构建视算一体能力的方案。存储方面,Ganos三维引擎提供了表面网格模型、体网格模型与实景模型三种存储结构,其中表面网格模型用于存储带有语义的类BIM的精细化三维模型,体网格模型用于存储地质体等匀质/非匀质“场”类三维模型,3D实景模型用于存储倾斜摄影、精白模等用于渲染的三维模型;计算方面,Ganos提供了多种三维空间计算函数,并且将PolarDB弹性并行查询能力(ePQ)拓展到三维计算中,在多个数字孪生应用中实测全空间复杂分析计算效率相较于传统方案有50倍以上的提升;渲染方面,作为数据库产品,Ganos并不直接提供渲染引擎,但依托矢量快显的构建经验,Ganos将快显能力延伸至了三维数据,除了库内提供模型简化、纹理材质处理外,还提供了三维存储结构统一动态构建三维瓦片的方式直接对接渲染引擎提供可视化服务。

网络异常,图片无法展示
|

表面网格模型

表面网格模型(SFMesh)是一种利用表面三角网格描述的三维模型的存储结构,包括三维模型的几何对象、三维模型的纹理贴图、三维模型的材质等基本信息,Ganos SFMesh支持引用,支持多层次的模型组织结构,主要应用于类BIM的强语义化的三维模型存储与计算分析。

关于SFMesh在业务中的具体应用,请关注Ganos三维引擎系列后续文章。

体网格模型

体网格模型(VOMesh)是一种利用定点、面以及体元综合描述三维空间信息的存储结构,支持存储复杂非匀质多面体数据并进行空间运算。Ganos VOMesh主要用于表示地质体、洋流以及各类场(电磁场、大气场等)等三维不均匀空间。

关于VOMesh在业务中的具体应用,请关注Ganos三维引擎系列后续文章。

实景模型

实景模型(Scene,参考手册)是一种以渲染为主要用途的三维模型存储结构,保留了三维模型的一切信息,包括:材质、纹理、骨骼、动画等,力争最大程度还原模型本身的各类信息。

本文所介绍的倾斜摄影数据管理与可视化功能,就是基于Ganos Scene实现。

Ganos倾斜摄影数据管理与可视化功能

倾斜摄影数据管理现状

倾斜摄影数据管理一直是测绘信息领域的重要工作,当前主要的方式是通过无人机采集倾斜照片后,通过商用数据处理软件开展稀疏、稠密点云提取,随之开展三维重建,最终生成带层级的OSGB数据保存,为支持后续应用往往还需要通过相关软件将osgb转换为3dtiles瓦片,发布三维空间服务后对接渲染引擎进行展示。这种方式带来的问题包括:

  • 数据资产管理混乱。数据存储多份造成冗余分散,存储介质多样无法与其他空间数据进行统一管理与检索,技术栈复杂。
  • 视算分离远离业务。倾斜摄影数据大多用于三维底图的展示,复杂的业务分析往往采用线下方式处理或者前端GPU示意的方式,无法精准指导业务。

在数字孪生应用愈发蓬勃的当下,诸多测绘生产管理部门迫切需要构建统一便捷的数管平台,提供视算一体的能力,开展各类空间数据的一库统管。

Ganos倾斜摄影数据管理整体方案

Ganos倾斜摄影数据管理方案主要分为倾斜摄影入库工具、倾斜摄影库内存储结构与倾斜摄影可视化支撑三部分组成。

1. Ganos倾斜摄影入库工具

为了解决各空间数据快速入库的问题,Ganos提供了一套Importer扩展,可以方便地从多种存储介质导入数据。通过执行如下SQL语句创建该扩展及依赖:

create extension ganos_importer cascade;

创建成功后即可使用ST_ImportOSG函数(参考手册)导入倾斜数据,该函数原型如下:

boolean ST_ImportOSG(cstring table_name, cstring url, cstring options default '{}');

其中table_name参数用于定义osg表名其相关表前缀,导入成功后会在库内生成主表、瓦片表和空间树划分表共计三张(详见下文);url用于定义数据所在存储的路径;options用于对并行度、SRID、导入方式等参数进行配置。

2. Ganos倾斜摄影库内存储

数据导入后生成如下结构的三张表,其中:

  • 主表[table_name]用于存储项目信息、空间参考、空间范围等元数据;
  • 瓦片表[table_name]_tile用于存储瓦片ID、瓦片LOD层级、瓦片父子关系、瓦片元数据、瓦片实体数据等;
  • 空间树划分表[table_name]_tileset用于存储项目倾斜摄影数据的空间结构;

三张表通过项目ID进行关联。

3. Ganos倾斜摄影可视化支撑

使用ST_ImportOSGB函数导入倾斜摄影数据时,已经同步构建了描述整个数据集的空间划分树,存储在空间树划分表中,因此可直接发布为3DTiles服务(标准为3DTiles 1.0)供前端调用,无需切片处理。

空间树可以指向子树或某个B3DM数据。

{
    "content": {
      "uri": "/tileset/851f8751-1037-44d5-9127-d55fd25b37ed/095a4edf-e818-42b6-8816-151e906c2465",
      "boundingVolume": {
        "box": [
          231.57069396972657,922.3930053710938,-237.97698974609376,
          160.7499237060547,0,0,
          0,89.12469482421875,0,
          0,0,22.76641845703125
        ]
      }
  }
}

综上,我们可以仅通过代理3DTiles的HTTP请求,执行对应的SQL语句,构建一个简易的免切片动态3DTiles文件服务(详见下文案例)。

Ganos倾斜摄影数据管理方案的特点

通过以上的介绍我们可以看出,相较于OSGB转3DTiles存储在本地磁盘或对象存储的方案,Ganos倾斜摄影数据管理方案提供了导入-存储-计算-渲染支持全套方案,在不造成数据冗余的情况下,构建了视算一体的“空间数据一库统管”能力,技术栈简单,使用方便,具体说来有如下特点:

  • 实现了倾斜摄影数据的“存算显”一体化全链路

Ganos内置了倾斜摄影数据存储类型Scene,原生提供库内存储能力,数据入库后Scene类型提供了多种空间查询与数据处理算子,供用户开展后续分析工作,最终处理完的结果动态生成3DTiles瓦片对接渲染引擎。这样的方式保证所有的操作基于一份数据开展,构建了三维数据“存算显”一体化的完整链路,避免了由于数据切片带来的现势性不足及分析渲染“两张皮”等问题。

  • 平衡了存储成本与应用性能之间的问题

Ganos在倾斜摄影数据入库时,可以选择是否采用"gateway模式”,gateway为布尔型变量,用于在库内构建Scene类型后判断是否真正将倾斜摄影数据写入库中,对于看重成本的用户而言,可以使用gateway将数据保留至对象存储,仅在库内构建类型,这种情况下依然可以对倾斜摄影对象开展各类空间查询、分析与渲染操作,只是效率会略低于入库模式。

  • 提供了海量的倾斜摄影数据处理能力供下游应用开发

Ganos Scene除了提供基础的三维空间关系判断算子外,还提供三维模型简化、纹理裁剪与简化等轻量化能力,同时为了满足更加复杂的业务场景,Scene在库内提供了视锥构造、可视体、射线求交等基础算子,用于解决可视域分析、阴影率分析等往往需要前端GPU处理的业务,相较于传统GPU前端方案,Ganos构造出的可视体等对象可精准计算出轮廓与体积,并可长期存储在库内,用于开展更进一步的业务分析。该能力已经应用于智慧园区中传感器布设分析等场景。

Ganos三维引擎系列后续文章会专题介绍库内开展可视域、阴影率等三维分析的具体方法与技术优势

功能使用案例

我们以存储于OSS上的某地区倾斜摄影数据(约93GB,40万瓦块)为例,演示倾斜数据管理与可视化的流程。

1. 数据入库

由于我们准备以并行方式入库,因此需要参照上文提前创建目标表。

创建完目标表后执行如下SQL语句,注意保持表名一致:

create extension ganos_importer cascade;
select ST_ImportOSGB('test_osgb','OSS://<ak>:<ak_secret>@oss-cn-beijing-internal.aliyuncs.com/b1/OSGB','{"parallel":16,"gateway":true,"project_name":"prj_1"}');

语句中指定使用gateway模式入库,该模式将极大减小数据库存储压力,但调用时相比存储在数据库中会有一定延迟。

2. 查看库内数据

查看主表数据:

SELECT PROJECT_ID, PROJECT_NAME, SRID, ST_ASTEXT(ANCHOR), AUX
FROM TEST_OSGB;

网络异常,图片无法展示
|

查看某个瓦块数据:

SELECT PROJECT_ID, PROJECT_NAME, UID, LOD, PARENT, CHILDREN
FROM TEST_OSGB_TILE
WHERE PROJECT_ID = '0E83090E-0658-4E18-B746-D93ECBCF3B23'
LIMIT 1;

网络异常,图片无法展示
|

查看某个tileset的数据:

SELECT PROJECT_ID, PROJECT_NAME, UID, TILESET::TEXT
FROM TEST_OSGB_TILESET
WHERE PROJECT_ID = '0E83090E-0658-4E18-B746-D93ECBCF3B23'
LIMIT 1;

3. 编写可视化服务与前端页面

我们使用Node.js编写一个简易的后端服务,实现代理3DTiles请求,并以Cesium作为前端框架展示结果。

首先在用户自定义目录下编写依赖文件package.json

{
  "dependencies": {
    "koa": "^2.14.2",
    "koa-router": "^12.0.0",
    "koa-send": "^5.0.1",
    "pg": "^8.10.0"
  }
}

在本目录下执行npm install安装依赖库。

在同一目录下创建Node.js脚本文件index.js

const Koa = require('koa');
const Send = require('koa-send');
const Router = require('koa-router');
const router = new Router()
const { Pool } = require('pg');
const pool = new Pool({ user: <YOUR_USER>, host: <YOUR_HOST>, database: <YOUR_DB_NAME>, port: <YOUR_PORT> });
const TABLE_NAME = 'test_osgb'
const PROJECT_NAME = 'prj1'
router.get('/', (_) => Send(_, '/index.html'))
/* get metadata of current project */
router.get('/project', async (ctx) => {
  const sql = `SELECT (REGEXP_MATCHES(ST_ASTEXT(ST_TRANSFORM(ANCHOR,4326)), 'POINT Z \\((.*?)\\)'))[1] _ANCHOR, PROJECT_ID FROM ${TABLE_NAME} WHERE PROJECT_NAME='${PROJECT_NAME}';`
  const { rows: [{ _anchor, project_id }] } = await pool.query(sql)
  const anchor = _anchor.split(' ').map(x => parseFloat(x))
  const url = `/tileset/${project_id}/${project_id}`
  ctx.body = { url, anchor }
})
router.get('/tileset/:project_id/:uid', async (ctx) => {
  const { params: { project_id, uid } } = ctx
  const sql = `SELECT TILESET FROM ${TABLE_NAME}_TILESET WHERE PROJECT_ID=$1::UUID AND UID=$2::UUID;`
  const { rows: [{ tileset }] } = await pool.query(sql, [project_id, uid])
  ctx.body = tileset
})
router.get('/b3dm/:project_id/:uid', async (ctx) => {
  const { params: { project_id, uid } } = ctx
  const sql = `SELECT ST_ASB3DM(TILE) TILE FROM ${TABLE_NAME}_TILE WHERE PROJECT_ID=$1::UUID AND UID=$2::UUID;`
  const { rows: [{ tile }] } = await pool.query(sql, [project_id, uid])
  ctx.body = tile
})
new Koa().use(router.routes()).listen(5500, '0.0.0.0');

在同一目录下创建HTML文件index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <script src="https://cesium.com/downloads/cesiumjs/releases/1.89/Build/Cesium/Cesium.js"></script>
  <link href="https://cesium.com/downloads/cesiumjs/releases/1.89/Build/Cesium/Widgets/widgets.css" rel="stylesheet">
  <style>
    html,
    body,
    #cesium_container {
      width: 100%;
      height: 100%;
      margin: 0;
      padding: 0;
      overflow: hidden;
    }
  </style>
</head>

						

上一篇: 图像三维重建:深度学习驱动的技术进展概览

下一篇: Flutter:实现跨设备小票标签打印的简易方法