使用网格数据和1D纹理贴图在opengl中创建等高线图

时间:2012-01-11 18:50:09

标签: c++ opengl texture-mapping

我在规则间隔的网格上有一组X,Y,Z值,我需要使用C ++创建一个颜色填充的等高线图。我已经在谷歌上搜索了好几天,而且似乎是在openGL中使用1D纹理贴图可以实现这一点。但是我还没有找到一个如何实际执行此操作的示例,并且我没有在任何地方阅读openGL文档。我的困惑归结为一个核心问题:

我的数据不包含每个像素的X,Y值 - 它是一个规则间隔的网格,在X和Y轴上每4个单位有一个数据,具有正整数Z值。

例如:(0,0,1),(4,0,1),(8,0,2),(0,4,2),(0,8,4),(4,4) ,3)等。

由于轮廓将基于Z值并且数据点之间存在间隙,因此应用1D纹理如何实现轮廓此数据(即如何在网格点之间应用1D纹理插值?)

我最接近找到一个这样的例子是在茶壶示例中的红皮书的在线版本(http://fly.cc.fer.hr/~unreal/theredbook/chapter09.html)但是我假设茶壶模型有每个像素的数据,因此不需要在数据点之间进行插值。

如果有人能够阐明我的问题或更好地指出以这种方式使用一维纹理贴图的具体例子,我将永远感激,因为我已经在这个项目上烧了两天而没什么可展示的它

编辑:

以下代码是我正在使用的代码,虽然它确实在正确的位置显示了点,但没有插值或轮廓发生 - 这些点只显示为点。

//Create a 1D image - for this example it's just a red line
int stripeImageWidth = 32;
GLubyte   stripeImage[3*stripeImageWidth];
for (int j = 0; j < stripeImageWidth; j++) {
    stripeImage[3*j] = j < 2 ? 0 : 255;
    stripeImage[3*j+1] = 255;
    stripeImage[3*j+2] = 255;
}
glDisable(GL_TEXTURE_2D);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage1D(GL_TEXTURE_1D, 0, 3, stripeImageWidth, 0, GL_RGB, GL_UNSIGNED_BYTE, stripeImage);
glTexParameterf(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameterf(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);

glTexGeni( GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
float s[4] = { 0,1,0,0 };
glTexGenfv( GL_S, GL_OBJECT_PLANE, s );
glEnable( GL_TEXTURE_GEN_S );
glEnable( GL_TEXTURE_1D );
glBegin(GL_POINTS);

//_coords contains X,Y,Z data - Z is the value that I'm trying to contour
for (int x = 0; x < _coords.size(); ++x)
{
    glTexCoord1f(static_cast<ValueCoord*>(_coords[x])->GetValue());
    glVertex3f(_coords[x]->GetX(), _coords[x]->GetY(), zIndex);
}
glEnd();

1 个答案:

答案 0 :(得分:7)

这个想法是将Z坐标用作纹理中的S坐标。纹理坐标上的线性插值然后创建轮廓。请注意,通过使用着色器,您可以将XY-&gt; Z数据放入2D纹理,并使用着色器在1D纹理的颜色渐变中间接显示2D采样器的值。

更新:代码示例

首先,我们需要改变纹理的使用方式。

为此准备纹理:

//Create a 1D image - for this example it's just a red line
int stripeImageWidth = 32;
GLubyte   stripeImage[3*stripeImageWidth];
for (int j = 0; j < stripeImageWidth; j++) {
    stripeImage[3*j] = j*255/32; // use a gradient instead of a line
    stripeImage[3*j+1] = 255;
    stripeImage[3*j+2] = 255;
}

GLuint texID;
glGenTextures(1, &texID);
glBindTexture(GL_TEXTURE_1D, texID);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage1D(GL_TEXTURE_1D, 0, 3, stripeImageWidth, 0, GL_RGB, GL_UNSIGNED_BYTE, stripeImage);

// We want the texture to wrap, so that values outside the range [0, 1] 
// are mapped into a gradient sawtooth
glTexParameterf(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);

这是绑定它以供使用。

// The texture coordinate comes from the data, it it not
// generated from the vertex position!!!
glDisable( GL_TEXTURE_GEN_S ); 
glDisable(GL_TEXTURE_2D);
glEnable( GL_TEXTURE_1D );
glBindTexture(GL_TEXTURE_1D, texID);

现在您的概念问题:您不能直接从XYZ数据制作等高线图。 XYZ只是稀疏的采样点。您需要填补空白,例如首先将其放入2D直方图中。为此创建一个网格,每个方向都有一定数量的bin,初始化为所有NaN(伪代码)

float hist2D[bins_x][bins_y] = {NaN, NaN, ...}

然后对于每个XYZ,如果不是NaN,则将Z值添加到网格的bin中,否则将NaN替换为Z值。然后在直方图上使用拉普拉斯滤波器来平滑仍然包含NaN的箱。最后,您可以使用

将网格渲染为等高线图
glBegin(GL_QUADS);
for(int y=0; y<grid_height; y+=2) for(int x=0; x<grid_width; x+=2) {
    glTexCoord1f(hist2D[x  ][y  ]]); glVertex2i(x  ,y);
    glTexCoord1f(hist2D[x+1][y  ]]); glVertex2i(x+1,y);
    glTexCoord1f(hist2D[x+1][y+1]]); glVertex2i(x+1,y+1);
    glTexCoord1f(hist2D[x  ][y+1]]); glVertex2i(x  ,y+1);
}
glEnd();

或者您可以将网格作为2D纹理上传,并使用片段着色器间接进入颜色渐变。

填充稀疏XYZ数据中的间隙的另一种方法是找到XY集的2D Voronoi图并使用它来创建采样几何。顶点的Z值将是与Voronoi单元相交的XYZ的距离加权平均值。