【问题标题】:Generate a plane with triangle strips生成带三角条的平面
【发布时间】:2011-08-20 10:05:48
【问题描述】:

生成顶点列表以使用三角形带绘制平面的最佳算法是什么?

我正在寻找一个函数,它接收平面的宽度和高度并返回一个包含正确索引顶点的浮点数组。

宽度表示每行的顶点数。

height 表示每列的顶点数。

float* getVertices( int width, int height ) {
    ...
}

void render() {
    glEnableClientState(GL_VERTEX_ARRAY);
    glVertexPointer(3, GL_FLOAT, 0, getVertices(width,heigth));
    glDrawArrays(GL_TRIANGLE_STRIP, 0, width*height);
    glDisableClientState(GL_VERTEX_ARRAY);
}

【问题讨论】:

  • 有什么限制吗?我的意思是,你可以生成一个有 4 个顶点的平面。 :)
  • 需要更多信息。菱形、平行四边形、矩形、梯形和正方形都定义了一个平面,但每个平面都由不同的三角形条带组成。需要角度信息或计算角度以绘制三角形的能力。有没有你没有告诉我们的假设?
  • 它只是一个正方形,但它必须细分为许多三角形,以便我可以调整顶点位置并更改平面形状。 WIDTH 表示每行的顶点数,HEIGHT 表示每列的顶点数。
  • 另外看看这个:chadvernon.com/blog/resources/directx9/… 不是 OpenGl,但我猜还是有用的

标签: c++ opengl geometry plane gl-triangle-strip


【解决方案1】:

谢谢大家。我已经对此进行了编码。这是正确的吗?还是生成的条带有些错误?

int width;
int height;
float* vertices = 0;
int* indices = 0;

int getVerticesCount( int width, int height ) {
    return width * height * 3;
}

int getIndicesCount( int width, int height ) {
    return (width*height) + (width-1)*(height-2);
}

float* getVertices( int width, int height ) {
    if ( vertices ) return vertices;

    vertices = new float[ getVerticesCount( width, height ) ];
    int i = 0;

    for ( int row=0; row<height; row++ ) {
        for ( int col=0; col<width; col++ ) {
            vertices[i++] = (float) col;
            vertices[i++] = 0.0f;
            vertices[i++] = (float) row;
        }
    }

    return vertices;
}

int* getIndices( int width, int height ) {
    if ( indices ) return indices;

    indices = new int[ iSize ];
    int i = 0;

    for ( int row=0; row<height-1; row++ ) {
        if ( (row&1)==0 ) { // even rows
            for ( int col=0; col<width; col++ ) {
                indices[i++] = col + row * width;
                indices[i++] = col + (row+1) * width;
            }
        } else { // odd rows
            for ( int col=width-1; col>0; col-- ) {
                indices[i++] = col + (row+1) * width;
                indices[i++] = col - 1 + + row * width;
            }
        }
    }
    if ( (mHeight&1) && mHeight>2 ) {
        mpIndices[i++] = (mHeight-1) * mWidth;
    }

    return indices;
}

void render() {
    glEnableClientState( GL_VERTEX_ARRAY );
    glVertexPointer( 3, GL_FLOAT, 0, getVertices(width,height) );
    glDrawElements( GL_TRIANGLE_STRIP, getIndicesCount(width,height), GL_UNSIGNED_INT, getIndices(width,height) );
    glDisableClientState( GL_VERTEX_ARRAY );
}

当 width=4 和 height=4 这就是我得到的:

在这里我正在修改一些顶点高度:

【讨论】:

  • 好吧,你也许可以自己回答这个问题。它是否按您的预期工作或有任何问题?如果不渲染线框,而是渲染实心三角形,它看起来还不错吗?
  • 确定曲面边缘没有问题?
  • 是的,边缘有伪影。
  • 这部分你也能解释一下吗? if ( (mHeight&amp;1) &amp;&amp; mHeight&gt;2 ) { mpIndices[i++] = (mHeight-1) * mWidth; }
  • 你能解释一下 iSize 是什么吗?
【解决方案2】:

这是一些执行此操作的代码(未经测试,但至少您明白了):

void make_plane(int rows, int columns, float *vertices, int *indices) {
    // Set up vertices
    for (int r = 0; r < rows; ++r) {
        for (int c = 0; c < columns; ++c) {
            int index = r*columns + c;
            vertices[3*index + 0] = (float) c;
            vertices[3*index + 1] = (float) r;
            vertices[3*index + 2] = 0.0f;
        }
    }

    // Set up indices
    int i = 0;
    for (int r = 0; r < rows - 1; ++r) {
        indices[i++] = r * columns;
        for (int c = 0; c < columns; ++c) {
            indices[i++] = r * columns + c;
            indices[i++] = (r + 1) * columns + c;
        }
        indices[i++] = (r + 1) * columns + (columns - 1);
    }
 }

第一个循环在标准矩形网格中设置顶点数组。有 R*C 顶点。

第二个循环设置索引。通常,网格中每个正方形有两个顶点。每个顶点都会导致一个新的三角形被绘制(与之前的两个顶点),所以每个正方形都是用两个三角形绘制的。

每行开头和结尾的第一个和最后一个顶点是重复的。这意味着每行之间有两个面积为零的三角形(退化三角形)。这使我们可以在一个大三角形条中绘制整个网格。这种技术称为拼接。

【讨论】:

    【解决方案3】:

    上面的代码都没有给出正确的网格生成。关于如何在简单平面上制作一条三角形的非常好的文章:http://www.learnopengles.com/android-lesson-eight-an-introduction-to-index-buffer-objects-ibos/

    这是我经过实际测试并完全正常工作的测试代码:

    int plane_width = 4; // amount of columns
    int plane_height = 2; // amount of rows
    
    int total_vertices = (plane_width + 1) * (plane_height + 1);
    planeVert = new CIwFVec2[total_vertices];
    memset(planeVert, 0, sizeof(CIwFVec2) * total_vertices);
    
    int numIndPerRow = plane_width * 2 + 2;
    int numIndDegensReq = (plane_height - 1) * 2;
    int total_indices = numIndPerRow * plane_height + numIndDegensReq;
    
    planeInd = new uint16[total_indices];
    
    make_plane(plane_width, plane_height, planeVert, planeInd);
    
    ...
    
    void make_plane(int width, int height, CIwFVec2 *vertices, uint16 *indices)
    {
    width++;
    height++;
    
    int size = sizeof(CIwFVec2);
    // Set up vertices
    for(int y = 0; y < height; y++)
    {
        int base = y * width;
        for(int x = 0; x < width; x++)
        {
            int index = base + x;
            CIwFVec2 *v = vertices + index;
            v->x = (float) x;
            v->y = (float) y;
            Debug::PrintDebug("%d: %f, %f", index, v->x, v->y);
        }
    }
    
    Debug::PrintDebug("-------------------------");
    
    // Set up indices
    int i = 0;
    height--;
    for(int y = 0; y < height; y++)
    {
        int base = y * width;
    
        //indices[i++] = (uint16)base;
        for(int x = 0; x < width; x++)
        {
            indices[i++] = (uint16)(base + x);
            indices[i++] = (uint16)(base + width + x);
        }
        // add a degenerate triangle (except in a last row)
        if(y < height - 1)
        {
            indices[i++] = (uint16)((y + 1) * width + (width - 1));
            indices[i++] = (uint16)((y + 1) * width);
        }
    }
    
    for(int ind=0; ind < i; ind++)
        Debug::PrintDebug("%d ", indices[ind]);
    }
    

    【讨论】:

    • 另外,如果你需要 UV 坐标:CIwFVec2 *uv = pUV + index; uv->x = v->x / (width-1); uv->y = v->y / (height-1);
    • NIGO的代码没有问题。关于“索引缓冲区对象(IBO)简介”请注意有一个错误!对于 w
    【解决方案4】:

    我正在做类似的事情,并使用我想出的前两个答案(经过测试,C#,XNA)

            // center x,z on origin
            float offset = worldSize / 2.0f, scale = worldSize / (float)vSize;
    
            // create local vertices
            VertexPositionColor[] vertices = new VertexPositionColor[vSize * vSize];
    
            for (uint z = 0; z < vSize; z++) {
                for (uint x = 0; x < vSize; x++) {
                    uint index = x + (z * vSize);
                    vertices[index].Position = new Vector3((scale*(float)x) - offset, 
                                                           heightValue, 
                                                           (scale*(float)z) - offset);
                    vertices[index].Color = Color.White;
                }
            }
    
            // create local indices
            var indices = new System.Collections.Generic.List<IndexType>();
    
            for (int z = 0; z < vSize - 1; z++) {
                // degenerate index on non-first row
                if (z != 0) indices.Add((IndexType)(z * vSize));
    
                // main strip
                for (int x = 0; x < vSize; x++) {
                    indices.Add((IndexType)(z * vSize + x));
                    indices.Add((IndexType)((z + 1) * vSize + x));
                }
    
                // degenerate index on non-last row
                if (z != (vSize-2)) indices.Add((IndexType)((z + 1) * vSize + (vSize - 1)));
            }
    

    这很容易转换为 c++,只需将 indices 设为 std::vector。

    我的解决方案的显着特点是: a) 不需要更改每个子带的缠绕顺序 - 添加两个点会创建两个退化三角形,因此下一个子带的顺序是正确的。 b)您应该有条件地添加第一个和最后一个 dg 三角形顶点。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-02-10
      • 2013-09-11
      • 2011-03-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多