如何从常规单元格网格生成3d纹理以进行体积渲染?

时间:2019-03-24 01:03:32

标签: opengl graphics visualization

我需要生成对象的可视化,为此,我计划使用GPU射线投射技术。在两个txt文件中描述了该对象的信息。一个文件通过规则的单元格网格描述该对象的结构,另一个文件包含有关网格中每个单元格强度的信息。

网格由笛卡尔轴上的x,y,z浮点列表来描述,这些浮点形成了单元格,第二个文件只是一个列表o float,描述了每个单元格的强度。

如何使用这些文件生成3d纹理,以便以后创建体积可视化的“体积射线投射”?

[Spektre编辑1]

这里sample input file

1
0
0
0
1 1 1
32 32 32
-1.495980e+14
-1.402481e+14
-1.308982e+14
-1.215484e+14
-1.121985e+14
-1.028486e+14
-9.349875e+13
-8.414888e+13
-7.479900e+13
-6.544912e+13
-5.609925e+13
-4.674938e+13
-3.739950e+13
-2.804962e+13
-1.869975e+13
-9.349875e+12
 0.000000e+00
 9.349875e+12
 1.869975e+13
 2.804962e+13
 3.739950e+13
 4.674938e+13
 5.609925e+13
 6.544912e+13
 7.479900e+13
 8.414888e+13
 9.349875e+13
 1.028486e+14
 1.121985e+14
 1.215484e+14
 1.308982e+14
 1.402481e+14
 1.495980e+14
-1.495980e+14
-1.402481e+14
-1.308982e+14
-1.215484e+14
-1.121985e+14
-1.028486e+14
-9.349875e+13
-8.414888e+13
-7.479900e+13
-6.544912e+13
-5.609925e+13
-4.674938e+13
-3.739950e+13
-2.804962e+13
-1.869975e+13
-9.349875e+12
 0.000000e+00
 9.349875e+12
 1.869975e+13
 2.804962e+13
 3.739950e+13
 4.674938e+13
 5.609925e+13
 6.544912e+13
 7.479900e+13
 8.414888e+13
 9.349875e+13
 1.028486e+14
 1.121985e+14
 1.215484e+14
 1.308982e+14
 1.402481e+14
 1.495980e+14
-1.495980e+14
-1.402481e+14
-1.308982e+14
-1.215484e+14
-1.121985e+14
-1.028486e+14
-9.349875e+13
-8.414888e+13
-7.479900e+13
-6.544912e+13
-5.609925e+13
-4.674938e+13
-3.739950e+13
-2.804962e+13
-1.869975e+13
-9.349875e+12
 0.000000e+00
 9.349875e+12
 1.869975e+13
 2.804962e+13
 3.739950e+13
 4.674938e+13
 5.609925e+13
 6.544912e+13
 7.479900e+13
 8.414888e+13
 9.349875e+13
 1.028486e+14
 1.121985e+14
 1.215484e+14
 1.308982e+14
 1.402481e+14
 1.495980e+14

还有file format info

对于不进行网格优化的常规网格,amr grid.inp看起来像:

  

iformat <===目前通常为1 0 <===网格样式(常规= 0)   coordsystem gridinfo incl_x incl_y incl_z nx ny nz

     

xi [1] xi [2] xi [3] .....…xi [nx + 1]

     

yi [1] yi [2] yi [3] .....…yi [ny + 1]

     

zi [1] zi [2] zi [3] .....…zi [nz + 1]

     

条目的含义是:

     

iformat:当前的格式号1.对于未格式化的文件,此   必须为4个字节的整数。

     

坐标系:如果坐标系<100,则坐标系为笛卡尔坐标系。   如果100 <=坐标系<200,则坐标系为球形(极坐标)。   如果200 <=坐标系<300,则坐标系为圆柱。   未格式化的文件,必须为4字节整数。

     

gridinfo:如果gridinfo == 1,将有大量的网格信息   写入此文件,可能对后处理例程有用。   通常,这是多余的信息,因此建议您设置   gridinfo = 0以节省磁盘空间。在下文中,我们将假定   gridinfo = 0。对于未格式化的文件,必须为4字节整数。

     

incl x,incl y,incl z:这些是0或1。如果为0,则此为   尺寸未激活(因此,在网格细化后,此细化将不进行细化)   尺寸已完成)。如果为1,则此维度完全有效,即使   该方向上的基本网格单元数仅为1。   单元也将在此维度上拆分。对于未格式化   文件中,这些数字必须为4字节整数。

     

nx,ny,nz:这些是基础网格中的网格单元数   这些尺寸中的每一个。对于未格式化的文件,这些数字必须为   4字节整数。

     

xi [1] ... xi [nx + 1]:基础网格中单元格的边缘   x方向。对于nx个网格单元,我们有nx + 1个单元壁,因此nx + 1   细胞壁位置。对于未格式化的文件,这些数字必须为   8字节实数(=双精度)。

     

yi [1] ... yi [ny + 1]:与上面相同,但现在用于y方向。

     

zi [1] ... zi [nz + 1]:与上面相同,但现在用于z方向。

     

在笛卡尔坐标中的简单2x2x2正则网格示例:1 0 1   0 1 1 1 2 2 2   -1。 0. 1。   -1。 0. 1。   -1。 0. 1。

1 个答案:

答案 0 :(得分:0)

很好奇,根据您的示例网格,这是我想出的:

//---------------------------------------------------------------------------
//--- AMR class ver: 1.000 --------------------------------------------------
//---------------------------------------------------------------------------
#ifndef _amr_grid_h
#define _amr_grid_h
//---------------------------------------------------------------------------
#include "gl\OpenGL3D_double.cpp"
//---------------------------------------------------------------------------
// https://stackoverflow.com/q/55319835/2521214
//---------------------------------------------------------------------------
class amr_grid
    {
public:
    // BVH file
    int iformat;        // 0,1
    int gridstyle;      // 0 regular
    int coordsystem;    // <0,100) cartesian, <100<200) spherical/polar, <200,300) cylindrical
    int gridinfo;       // 0:  1: additional info added to file
    int en[3];          // enable x,y,z?
    int sz[3];          // size of grid [cells]
    List<double> p[3];  // walls per dimension
    // misc
    double min[3],max[3];   // BBOX
    double dl;              // avg cell size

    amr_grid(){ reset(); }
    amr_grid(amr_grid& a)   { *this=a; }
    ~amr_grid(){}
    amr_grid* operator = (const amr_grid *a) { *this=*a; return this; }
    //bvh* operator = (const bvh &a) { ...copy... return this; }
    // render/set/load
    void reset();               // clear whole skeleton data
    void draw();                // render actual set frame
    void load(AnsiString name); // load from AMR grid file
    };
//---------------------------------------------------------------------------
void amr_grid::reset()
    {
    iformat=1;
    gridstyle=0;
    coordsystem=0;
    gridinfo=0;
    en[0]=1; sz[0]=0;   p[0].num=0; min[0]=0.0; max[0]=0.0;
    en[1]=1; sz[1]=0;   p[1].num=0; min[1]=0.0; max[1]=0.0;
    en[2]=1; sz[2]=0;   p[2].num=0; min[2]=0.0; max[2]=0.0;
    dl=0.0;
    }
//---------------------------------------------------------------------------
void amr_grid::draw()
    {
    int i,x,y,z;

    glColor3f(0.0,1.0,0.5);
    glBegin(GL_LINES);

    if ((gridstyle>=0)&&(gridstyle<100))    // cartesian
        {
        if ((en[0])&&(en[1])&&(en[2]))      // 3D
            {
            for (x=0;x<=sz[0];x++)
             for (y=0;y<=sz[1];y++)
                {
                glVertex3d(p[0][x],p[1][y],min[2]);
                glVertex3d(p[0][x],p[1][y],max[2]);
                }
            for (x=0;x<=sz[0];x++)
             for (z=0;z<=sz[2];z++)
                {
                glVertex3d(p[0][x],min[1],p[2][z]);
                glVertex3d(p[0][x],max[1],p[2][z]);
                }
            for (y=0;y<=sz[1];y++)
             for (z=0;z<=sz[2];z++)
                {
                glVertex3d(min[0],p[1][y],p[2][z]);
                glVertex3d(max[0],p[1][y],p[2][z]);
                }
            }
        }

    glEnd();
    }
//---------------------------------------------------------------------------
void amr_grid::load(AnsiString name)
    {
    int hnd,siz,adr,i,j,k;
    AnsiString lin,s;
    BYTE *txt=NULL;
    reset();
    // file -> memory
    hnd=FileOpen(name,fmOpenRead);
    if (hnd<0) return;
    siz=FileSeek(hnd,0,2);
        FileSeek(hnd,0,0);
    txt=new BYTE[siz];
    if (txt==NULL) { FileClose(hnd); return; }
    siz=FileRead(hnd,txt,siz);
    FileClose(hnd);
    // memory -> amr_grid data
    adr=0;
    iformat=str2int(txt_load_lin(txt,siz,adr,true));
    gridstyle=str2int(txt_load_lin(txt,siz,adr,true));
    coordsystem=str2int(txt_load_lin(txt,siz,adr,true));
    gridinfo=str2int(txt_load_lin(txt,siz,adr,true));
    lin=txt_load_lin(txt,siz,adr,true); i=1; for (j=0;j<3;j++) en[j]=str2num(str_load_str(lin,i,true));
    lin=txt_load_lin(txt,siz,adr,true); i=1; for (j=0;j<3;j++) sz[j]=str2num(str_load_str(lin,i,true));
    for (j=0;j<3;j++) for (p[j].num=0,i=0;i<=sz[j];i++) p[j].add(str2num(txt_load_str(txt,siz,adr,true)));
    // BBOX
    for (j=0;j<3;j++) for (min[j]=max[j]=p[j][0],i=0;i<=sz[j];i++)
        {
        if (min[j]>p[j][i]) min[j]=p[j][i];
        if (max[j]<p[j][i]) max[j]=p[j][i];
        }
    double q[3];
    vector_sub(q,max,min);
    dl=3.0*vector_len(q)/double(sz[0]+sz[1]+sz[2]);
    }
//---------------------------------------------------------------------------
#endif
//---------------------------------------------------------------------------

这只是加载并绘制网格。但是,我希望您得到的3D纹理文件包含单元强度,因此只需将其用作框的颜色,然后更改绘制例程即可将单元渲染为具有纹理颜色的框。任何单元格的角点都是这些坐标的8个组合:

x: p[0][i],p[0][i+1]
y: p[1][i],p[1][i+1]
z: p[2][i],p[2][i+1]

您可以改编我的glBox(请注意其float,但上面的代码使用double ...):

void glBox(GLfloat x0,GLfloat y0,GLfloat z0,GLfloat xs,GLfloat ys,GLfloat zs)
    {
    xs*=0.5;
    ys*=0.5;
    zs*=0.5;
    glBegin(GL_QUADS);

    glNormal3f(+1.0,0.0,0.0);
    glVertex3f(x0+xs,y0-ys,z0-zs);
    glVertex3f(x0+xs,y0+ys,z0-zs);
    glVertex3f(x0+xs,y0+ys,z0+zs);
    glVertex3f(x0+xs,y0-ys,z0+zs);

    glNormal3f(-1.0,0.0,0.0);
    glVertex3f(x0-xs,y0-ys,z0+zs);
    glVertex3f(x0-xs,y0+ys,z0+zs);
    glVertex3f(x0-xs,y0+ys,z0-zs);
    glVertex3f(x0-xs,y0-ys,z0-zs);

    glNormal3f(0.0,+1.0,0.0);
    glVertex3f(x0-xs,y0+ys,z0+zs);
    glVertex3f(x0+xs,y0+ys,z0+zs);
    glVertex3f(x0+xs,y0+ys,z0-zs);
    glVertex3f(x0-xs,y0+ys,z0-zs);

    glNormal3f(0.0,-1.0,0.0);
    glVertex3f(x0-xs,y0-ys,z0-zs);
    glVertex3f(x0+xs,y0-ys,z0-zs);
    glVertex3f(x0+xs,y0-ys,z0+zs);
    glVertex3f(x0-xs,y0-ys,z0+zs);

    glNormal3f(0.0,0.0,+1.0);
    glVertex3f(x0+xs,y0-ys,z0+zs);
    glVertex3f(x0+xs,y0+ys,z0+zs);
    glVertex3f(x0-xs,y0+ys,z0+zs);
    glVertex3f(x0-xs,y0-ys,z0+zs);

    glNormal3f(0.0,0.0,-1.0);
    glVertex3f(x0-xs,y0-ys,z0-zs);
    glVertex3f(x0-xs,y0+ys,z0-zs);
    glVertex3f(x0+xs,y0+ys,z0-zs);
    glVertex3f(x0+xs,y0-ys,z0-zs);

    glEnd();
    }

x0,y0,z0,x1,y1,z1格式或编写VBO或其他任何内容...

PS。

我也使用我的动态列表模板,所以:


List<double> xxx;double xxx[];相同
xxx.add(5);5添加到列表的末尾
xxx[7]访问数组元素(安全)
xxx.dat[7]访问数组元素(不安全但快速的直接访问)
xxx.num是数组的实际使用大小
xxx.reset()清除数组并设置xxx.num=0
xxx.allocate(100)100个项目预分配空间

C ++ 代码基于 VCL ,因此您需要将AnsiString重写为可使用的字符串类型。我也使用了我自己的字符串例程来加载行,字符串并转换为数字,因此您也需要移植它,但是我想您已经有了一个加载器...

btw这是文件格式说明中简单样本文件的输出:

screenshot