我成功地在openGL中使用VBO和IBO生成高度图。该数据的完整图片如下图所示。我想要真正展示的只是非黑色的数据。当颜色为黑色时,我将z值设为零。
这是我生成索引的代码
void triangle::getIndices(QVector<double> minmaxX_, QVector<double> minmaxY_)
{
indices.clear();
int numY = round((minmaxY_[1] - minmaxY_[0]) / minmaxY_[2]) + 1;
int numX = round((minmaxX_[1] - minmaxX_[0]) / minmaxX_[2]) + 1;
for (int row=0; row<numY-1; row++) {
if ((row&1) == 0 ) { // even rows
for ( int col=0; col<numX; col++ ) {
indices.append(col + row*numX);
indices.append(col + (row + 1)*numX);
}
}
else {
for ( int col=numX-1; col>=0; col-- ) {
indices.append(col + (row*numX));
indices.append(col + ((row + 1)*numX));
}
}
}
}
我的着色器代码
const char* const frgshdr_source =
"uniform const float colorSize;\n"
"uniform vec3 colorTable[512];"
"varying float height;\n"
"uniform float heightSize;\n"
"uniform float heightMin;\n"
"void main() {\n"
" //vec3 colorTable2[int(colorSize)+1] = colorTable;\n"
" float h = (height - heightMin)/heightSize;\n"
" if (h < 0.0f || h > 1.0f) {\n"
" gl_FragColor = vec4(0.0f, 0.0f, 0.0f, 0.0f);}\n"
" else {"
" int i = 0;\n"
" while (h >= float(i + 1)/colorSize) {\n"
" i += 1;}\n"
" vec3 base = mix(colorTable[i], colorTable[i+1], colorSize*(h - (float(i)/colorSize)));\n"
" gl_FragColor = vec4(base, 1.0f);}\n"
"}\n";
不幸的是,在使用我的投影矩阵(正交)剪辑z值之后。我仍然在边缘得到一些文物,如下图所示。
这是我的正投影矩阵
m_projection.ortho( minX, maxX, minY, maxY, minZ, maxZ);
看起来像openGL会自动重新创建一些三角形,因此它会在边缘(紫色线条)周围形成artifac。
是否有任何方法可以使此边缘工件消失或者我需要再次定义索引?
提前感谢您的帮助。
答案 0 :(得分:2)
很抱歉让你失望,但这就是裁剪应该起作用的方式。每个基元(三角形或线形)的剪切过程不以二进制答案结束(即抛出或保留整个基元)。相反,基元被一个或多个基元替换,基元表示限幅体积内原始基元的一部分。所以如果你有一个三角形ABC:
A---------B
\ |
\ |
\ |
\ |
C
分别使用A,B,C的高度10,-1,-1,并将其与height = 0进行剪裁,然后OpenGL用这个较小的三角形Abc替换它:
A---b B
\ |
c
C
分别为A,b,c的高度10,0,0。
您可以将其想象为通过提高剪切平面高度来提升虚拟水位,并且OpenGL正确地重建与该水位相对应的岸线。
这些小三角形是期望的行为的结果。
请参阅wiki中的Vertex Post-Processing或OpenGL规范中的Primitive Clipping章节。
如果你想扔掉在高度
如果您的硬件不支持几何着色器(并且高度图是动态的),那么您唯一的选择是减少工件。一种选择是使用GL_LINE_STRIP
而不是glPolygonMode
绘制线条(因为您现在正在做的事情)。它将避免在边缘处生成那些长线,但仍会看到在顶点处相遇的那些短截线段。
这与神器无关,但它可能在将来派上用场。您当前的索引生成代码似乎以来回的方式遍历网格。我不知道你为什么要这样做,但请记住,你可以按顺序生成所有内容,并使用GL_PRIMITIVE_RESTART
结束一个GL_TRIANGLE_STRIP
(或GL_LINE_STRIP
)并开始一个新的一个来自同一个VBO 内的不同顶点。
答案 1 :(得分:1)
正如@ybungalobill在他/她的回答中所解释的那样,工件是openGL行为并且很难被改变。所以我的解决方案是创建新程序来创建索引。这是代码
void triangle::getIndices(QVector<double> minmaxX_, QVector<double> minmaxY_)
{
indices.clear();
int numY = round((minmaxY_[1] - minmaxY_[0]) / minmaxY_[2]) + 1;
int numX = round((minmaxX_[1] - minmaxX_[0]) / minmaxX_[2]) + 1;
for (int row = 0; row < numY - 1; row++) {
if ((row&1) == 0 ) { // even rows
for ( int col=0; col<numX; col++ ) {
if (vertices[row*numX + col][2] != 0 && vertices[(row+1)*numX + col][2] != 0) {
indices.append(row*numX + col);
indices.append((row + 1)*numX + col);
}
else if (vertices[row*numX + col][2] == 0 && vertices[(row+1)*numX + col][2] != 0) {
indices.append((row + 1)*numX + col);
indices.append((row + 1)*numX + col);
}
else if (vertices[row*numX + col][2] != 0 && vertices[(row+1)*numX + col][2] == 0) {
indices.append(row*numX + col);
indices.append(row*numX + col);
}
else {
indices.append(-1);
}
}
}
else {
for ( int col=0; col<numX; col++ ) {
if (vertices[row*numX + col][2] != 0 && vertices[(row+1)*numX + col][2] != 0) {
indices.append(row*numX + col);
indices.append((row + 1)*numX + col);
}
else if (vertices[row*numX + col][2] == 0 && vertices[(row+1)*numX + col][2] != 0) {
indices.append((row + 1)*numX + col);
indices.append((row + 1)*numX + col);
}
else if (vertices[row*numX + col][2] != 0 && vertices[(row+1)*numX + col][2] == 0) {
indices.append(row*numX + col);
indices.append(row*numX + col);
}
else {
indices.append(-1);
}
}
}
}
qDebug() << indices.size();
}
绘制时也会输入此代码
glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
glDrawElements(GL_TRIANGLE_STRIP, indices.size(), GL_UNSIGNED_INT, 0);
glDisable(GL_PRIMITIVE_RESTART_FIXED_INDEX);