6

基于 GPU 渲染的高性能空间包围计算

 7 months ago
source link: https://blog.51cto.com/u_15550686/9580368
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

基于 GPU 渲染的高性能空间包围计算

精选 原创

图扑软件 2024-02-04 11:12:56 ©著作权

文章标签 3d 着色器 顶点着色器 文章分类 Python 后端开发 阅读数179

空间包围检测在计算机图形学、虚拟仿真、工业生产等有着广泛的应用。

现代煤矿开采过程中,安全一直是最大的挑战之一。地质空间中存在诸多如瓦斯积聚、地质构造异常、水文条件不利等隐蔽致灾因素,一旦被触发,可能引发灾难性的后果。因此在安全生产过程中有效的管理和规避各隐蔽致灾因素,有着重要的意义。

通过对煤矿地质空间中各地质因素建模,建立空间数据库,还原地下真实场景,使用计算机图形学进行空间计算,可以实时监测各隐蔽致灾因素的位置和距离,指导安全生产,并进行可视化展示。

空间包围检测有多种方法,比如基于包围盒的检测,三角面碰撞检测等。本文提出了一种基于 GPU 渲染的高效计算方法。

假定待检测球体范围的半径为r。两种检测方法如下:

  • 方法 1:遍历模型所有的点,计算点和球心的距离。如果有距离小于 r,模型在球体范围内。
  • 方法 2:以检测区域的包围盒为正交投影空间,渲染所有需要检测的模型。渲染过程中计算每个渲染点到球心的距离,如果有距离小于r的渲染点,模型在球体范围内。

模型和检测区域有以下几种位置关系:

基于 GPU 渲染的高性能空间包围计算_顶点着色器
  • 图 1:模型完全在球体范围内:方法 1 可检测
  • 图 2:模型部分点在球体范围内:方法 1 可检测
  • 图 3:模型点不在球体范围内,部分三角面在球形范围内:方法 2 可检测
  • 图 4:模型不在球体范围内:方法 1 + 2 可检测
  • 图 5:模型完全包含球体范围:模型如果是空心的,方法 1 + 2 可检测模型不在球体范围内。如果需要计算结果是模型在球体范围内,也就是模型是实心的,建模时需要在模型内部加上额外的辅助计算的三角面,用于表达内部信息。此时用方法 1 + 2 可检测模型在球体范围内。
基于 GPU 渲染的高性能空间包围计算_着色器_02

以上方法使用 WebGL 渲染到纹理(Render To Texture) 和 readPixels 功能。图扑 HT for Web SDK 组件库对 WebGL 底层复杂操作做了封装, 为用户省掉了繁琐的底层 WebGL 操作,可以方便快捷的实现正交透视、渲染到纹理和异步 readPixels 等高级 WebGL 功能。

方法 1:点检测法

准备一张 N X N 纹理图 texture1(HT RenderTarget),保证要检测的模型的数量不大于 N X N。每一个模型在纹理上分配一个像素,像素的位置为 (x,y)。

创建点渲染模式着色器程序,实现以下功能:

  • 顶点着色器:检测每个点到球心的距离,将距离是否小于r的信息传给片段着色器。指定的位置 (x,y) 赋给 gl_Position。
  • 片段着色器:如果距离小于 r, 渲染红色,否则不渲染颜色。

JavaScript 程序遍历每一个待检测模型,将模型的顶点和模型在纹理上的位置 (x,y) 通过 attribute 和 uniform 传给顶点着色器。所有模型渲染结束后,使用异步 readPixels 将渲染结果读出来。通过判断读取结果里每个像素点颜色值,获得模型是否在球体内部信息。

基于 GPU 渲染的高性能空间包围计算_着色器_03

主要代码:

// 创建渲染材质1
const texture1 = new ht.graph3d.RenderTarget(g3d, g3d.getGL(), 100, 100);

// 循环渲染所有的模型,结果保存到texture1。
for (let i = 0; i < nodeCount; i++) {
    data = datas[i];
    tModel = getDataMesh(data); // 获取模型网格信息
    // 准备着色器数据
    tModel.mat = model4.mat;
    tModel.matDef[DEFAULT_MAT_NAME] = model4.mat;
    tModel.mat.modelMat = data.getMatrix4().toArray();
    x = i % 100;
    y = Math.floor(i / 100);
    model4.mat.uPos = [x / 100 * 2 - 1 + 1 / 200, 2 * y / 100 - 1 + 1 / 200];
    // 渲染到texture1
    g3d.setViewport(gl, 0, 0, 100, 100);
    g3d.renderModel(texture1, model4, {
        clear: false
    });
}

// 读取检测结果
texture1.readPixelsAsync(0, 0, 100, 100, null, (result) => {
    for (let y = 0; y < 100; y++) {
        for (let x = 0; x < 100; x++) {
            // 遍历像素点,检测是否是红色
            // ......
        }
    }
});

方法 2:面检测法

准备两张纹理贴图 texture1 和 texture2。Texture1 的要求同方法 1。Texture2 默认使用 1000 X 1000 的分辨率。

创建两套着色器。第一套着色器使用三角面渲染:

  • 顶点着色器:正常计算顶点投影信息
  • 片段着色器:检测每一个点到球心的距离,如果小于 r,渲染红色

第二套着色器使用点渲染:

  • 顶点着色器:根据输入的 texture2 坐标(attribute),使用 texture2D 获取对应位置的颜色值,如果是红色,表示模型在球体内部,将此信息传给片段着色器。模型在 texture1 上的位置信息 (x,y) 赋给 gl_Position。
  • 片段着色器:如果距离小于 r, 渲染红色,否则不渲染颜色。

JavaScript 程序遍历每一个模型,使用着色器 1 将结果渲染到 texture2。渲染过程使用正交透视矩阵,视锥是球体的包围盒。JavaScript 将 texture2 (uniform sampler2D)、texture2 每个像素的 x, y位置信息 (attribute)、模型在 texture1 上的位置信息 (uniform) 传给顶点着色器 2。片段着色器 2 将模型是否在球体内的信息渲染到 texture1。所有模型渲染结束后,使用异步 readPixels 将渲染结果读出来。通过判断读取结果里每个像素点颜色值,获得模型是否在球体内部信息。

基于 GPU 渲染的高性能空间包围计算_3d_04

主要代码:

// 创建渲染材质1,2
const texture1 = new ht.graph3d.RenderTarget(g3d, g3d.getGL(), 100, 100);
const texture2 = new ht.graph3d.RenderTarget(g3d, g3d.getGL(), 1000, 1000);
 
// 循环渲染所有的模型到texture2。texture2信息渲染到texture1
for (let i = 0; i < nodeCount; i++) {
data = datas[i];
// 获取模型网格信息
// 准备着色器1数据
     tModel.mat = model2.mat;
     tModel.matDef[DEFAULT_MAT_NAME] = model2.mat;
     tModel.mat.modelMat = data.getMatrix4().toArray();
// 渲染到texture2
1000, 1000);
texture2, tModel, { clear: true });
// 准备着色器2数据
model3.mat.uImage = texture2.texture;
100;
100);
100 * 2 - 1 + 1 / 200, 2 * y / 100 - 1 + 1 / 200];
// 渲染到texture1
100, 100);
texture1, model3, { clear: false });
 }

方法 1 简单快速。但检测结果不准确。方法 2 检测结果准确,但计算过程复杂。实际使用中两种方法结合使用。首先使用方法 1 检测。对于不在球体范围内的模型,再使用方法 2 检测。

如果需要检测椭球体范围或者长方体的范围,可以获取椭球体或长方的变换矩阵,计算获得逆矩阵。将逆矩阵应用于每一个待检测模型的节点。此时只需要检测变换后的模型是否在单位圆或单位立方体内即可。HT SDK 3D 引擎库提供了丰富的数学计算 API,可以非常直观简洁的实现以上功能。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK