【问题标题】:Drawing multiple triangles in OpenGL在OpenGL中绘制多个三角形
【发布时间】:2018-05-25 09:52:08
【问题描述】:

我刚开始使用 OpenGL,我已经制作了自己的“OOP”版本,用 c++ 绘制三角形。

如果这很重要,我正在使用 glfw 和 glew。

我不明白为什么我不能绘制超过 1 个三角形。

这是主要功能:

int main()
{
    Graphics::Window window(1280, 720, "Take me to heaven");
    window.MakeOpenGLAvailable(); // makes context with OpenGL after which initializes GLEW

    Graphics::Objects::Triangle firstTriangle(Graphics::Vec2( 0.0f,  0.0f),
                                              Graphics::Vec2( 1.0f,  1.0f),
                                              Graphics::Vec2(-1.0f,  1.0f));

    Graphics::Objects::Triangle secondTriangle(Graphics::Vec2( 0.0f,  0.0f),
                                               Graphics::Vec2(-1.0f, -1.0f),
                                               Graphics::Vec2( 1.0f, -1.0f));

    window.SetBackground(0.0f, 0.0f, 0.0f, 1.0f);

    while (!window.isClosed() && !window.isKeyPressed(256)/*Escape*/)
    {
        window.DrawBackGround();

        firstTriangle.Draw();
        secondTriangle.Draw();

        window.Update();
        window.CheckForEvents();
    }

    return 0;
}

三角形类的构造函数如下所示:

namespace Graphics { namespace Objects {

Triangle::Triangle(Vec2& a, Vec2& b, Vec2& c, bool normalised, short drawtype)
            : points{ a, b, c }
        {
            glGenBuffers(1, &this->triangleID);
            glBindBuffer(GL_ARRAY_BUFFER, this->triangleID);
            glBufferData(GL_ARRAY_BUFFER, sizeof(Vec2) * 3, points, (drawtype == 0) ? GL_STATIC_DRAW : ((drawtype == 1) ? GL_STREAM_DRAW : GL_DYNAMIC_DRAW));

            glEnableVertexAttribArray(0);
            glVertexAttribPointer(0, 2, GL_FLOAT, (normalised == false) ? GL_FALSE : GL_TRUE, sizeof(Vec2), 0);
        }
    }
}

这是三角形类的draw方法:

void Triangle::Draw()
        {
            glBindBuffer(GL_ARRAY_BUFFER, this->triangleID);
            glDrawArrays(GL_TRIANGLES, 0, 3);
        }

如果有帮助,这是 Triangle 类的原型:

    class Triangle : public Shape
            {
            public:
                Triangle();
                Triangle(Vec2& a, Vec2& b, Vec2& c, bool normalised = false, short drawtype = 0);
                virtual ~Triangle();

                void Prepare(); // this just binds the buffer though I didn't use it since I bound the buffer inside the Draw method
                void Draw();

            private:
                Vec2 points[3];
                unsigned int triangleID;
}

如有必要,我会提供更多代码,但问题是程序只绘制了第二个三角形,我似乎不明白为什么...... 我遇到的互联网上的大多数教程都只是定义了一个类似于具有 6 个顶点位置的浮点数组,而不是调用

glDrawArrays(GL_TRIANGLES, 0, 3)

他们打电话

glDrawArrays(GL_TRIANGLES, 0, 6); // 12 etc.

是什么阻止了第一个三角形的绘制?还是它被画了,我看不到?我在做傻事吗?

【问题讨论】:

  • @Rabbid76 他是,它在构造函数中。不过应该在绘图命令中。
  • 你能显示你的视口设置吗?我有一种预感,可能会绘制您的三角形,但它们是在 Z=0.0 处绘制的,因此它们正在被剔除。也许尝试使用 Vec3 但将 Z 设置为 -1.0
  • @Rabbid76 非常感谢您向我澄清这一点。它现在完美运行!出于某种原因,我认为每次调用这两个函数会很耗时,这就是我在构造函数中调用它们的原因。

标签: c++ opengl


【解决方案1】:

顶点数组

例如顶点 (x, y, z)、法线 (x, y, z) 和纹理坐标 (u, v) 的缓冲区:

绘制数组:

GLsizei              no_of_points; // number of vertices and attrbuts
std::vector<GLfloat> vertex;       // linearized array (no_of_points * 3): [ Vx0, Vy0, Vz0, Vx1, Vy1, Vz1, .... ] 
std::vector<GLfloat> normal;       // linearized array (no_of_points * 3): [ Nx0, Ny0, Nz0, Nx1, Ny1, Nz1, .... ] 
std::vector<GLfloat> color;        // linearized array (no_of_points * 5): [ R0, G0, B0, A0, R1, G1, B1, A1, .... ] 

GLuint vetexAttribIndex;  // index of the vertex attrbute (shader)
GLuint normalAttribIndex; // index of the normal attribute (shader)
GLuint colorAttribIndex;  // index of the color attribute (shader)

glVertexAttribPointer( vetexAttribIndex,  3, GL_FLOAT, GL_FALSE, 0, vertex.data() ); // 3: Vx, Vy, Vz
glVertexAttribPointer( normalAttribIndex, 3, GL_FLOAT, GL_TRUE,  0, normal.data() ); // 3: Nx, Ny, Nz  -  GL_TRUE: values should be normalized
glVertexAttribPointer( colorAttribIndex,  4, GL_FLOAT, GL_FALSE, 0, color.data() );  // 4: R, G, B, A 

glEnableVertexAttribArray( vetexAttribIndex );
glEnableVertexAttribArray( normalAttribIndex );
glEnableVertexAttribArray( colorAttribIndex );

glDrawArrays( GL_TRIANGLES, 0, no_of_points ); 

glDisableVertexAttribArray( vetexAttribIndex );
glDisableVertexAttribArray( normalAttribIndex );
glDisableVertexAttribArray( colorAttribIndex );

见:


顶点缓冲对象

关于Vertex Specification 的 Khronos OpenGL wiki 明确表示:

glVertexAttribPointer 函数 state 属性索引从中获取其数组数据。

可以使用glGetVertexAttrib 检索此状态。

关于顶点属性的更多信息可以在第 10.2 章到第 10.6 章的OpenGL 4.6. core specification 中找到。

例如顶点、法线向量和纹理坐标

[ Vx0, Vy0, Vz0, Nx0, Ny0, Nz0, Tv0, Tu0,
  Vx1, Vy1, Vz1, Nx1, Ny1, Nz1, Tv1, Tu1,
  .....
]   

创建顶点数组缓冲区:

GLsizei no_of_points;
std::vector<GLfloat> data; // attribute set: [ Vx0, Vy0, Vz0, Nx0, Ny0, Nz0, Tv0, Tu0, Vx1, Vy1, Vz1, Nx1, Ny1, Nz1, Tv1, Tu1, .... ]

GLuint vbo;

glGenBuffers( 1, &vbo );
glBindBuffer( GL_ARRAY_BUFFER, vbo );
glBufferData( GL_ARRAY_BUFFER, data.size() * sizeof(GLfloat), data.data(), GL_STATIC_DRAW );
glBindBuffer( GL_ARRAY_BUFFER, 0 );

见:

绘制数组:

GLuint vetexAttribIndex;  // index of the vertex attrbute (shader)
GLuint normalAttribIndex; // index of the normal attribute (shader)
GLuint texCorAttribIndex; // index of the texture coordinate attribute (shader)

glBindBuffer( GL_ARRAY_BUFFER, vbo );

GLsizei stride = 8 * sizeof(GL_float); // size of one record in bytes: 8 * float [ Vx, Vy, Vz, Nx, Ny, Nz, Tv, Tu]
GLsizei offsV  = 0 * sizeof(GL_float); // offset of the vertex inside the reccord
GLsizei offsNV = 3 * sizeof(GL_float); // offset of the normal vector inside the reccord
GLsizei offsTC = 6 * sizeof(GL_float); // offset of the tecture coordinate inside the reccord

glVertexAttribPointer( vetexAttribIndex,  3, GL_FLOAT, GL_FALSE, stride, offsV );  // 3: Vx, Vy, Vz
glVertexAttribPointer( normalAttribIndex, 3, GL_FLOAT, GL_TRUE,  stride, offsNV ); // 3: Nx, Ny, Nz  -  GL_TRUE: values should be normalized
glVertexAttribPointer( texCorAttribIndex, 2, GL_FLOAT, GL_FALSE, stride, offsTC ); // 2: Tu, Tv 

glEnableVertexAttribArray( vetexAttribIndex );
glEnableVertexAttribArray( normalAttribIndex );
glEnableVertexAttribArray( texCorAttribIndex );

glDrawArrays( GL_TRIANGLES, 0, no_of_points ); 

glBindBuffer( GL_ARRAY_BUFFER, 0 );
glDisableVertexAttribArray( vetexAttribIndex );
glDisableVertexAttribArray( normalAttribIndex );
glDisableVertexAttribArray( texCorAttribIndex );

索引缓冲区对象

例如顶点、法线向量和纹理坐标

[ Vx0, Vy0, Vz0, Nx0, Ny0, Nz0, Tv0, Tu0,
  Vx1, Vy1, Vz1, Nx1, Ny1, Nz1, Tv1, Tu1,
  .....
]

创建顶点数组缓冲区和索引缓冲区:

GLsizei no_of_points;
std::vector<GLfloat> data;    // attribute set: [ Vx0, Vy0, Vz0, Nx0, Ny0, Nz0, Tv0, Tu0, Vx1, Vy1, Vz1, Nx1, Ny1, Nz1, Tv1, Tu1, .... ]
std::vector<GLuint>  indices; // indces: [ I0, I1, I2, I3, I4, ..... ]

GLuint vbo;

glGenBuffers( 1, &vbo );
glBindBuffer( GL_ARRAY_BUFFER, vbo );
glBufferData( GL_ARRAY_BUFFER, data.size() * sizeof(GLfloat), data.data(), GL_STATIC_DRAW );
glBindBuffer( GL_ARRAY_BUFFER, 0 );

GLuint ibo;

glGenBuffers( 1, &ibo );
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, ibo );
glBufferData( GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(GLuint), indices.data(), GL_STATIC_DRAW );
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );

绘制数组:

GLuint vetexAttribIndex;  // index of the vertex attrbute (shader)
GLuint normalAttribIndex; // index of the normal attribute (shader)
GLuint texCorAttribIndex; // index of the texture coordinate attribute (shader)

glBindBuffer( GL_ARRAY_BUFFER, vbo );

GLsizei stride = 8 * sizeof(GL_float); // size of one record in bytes: 8 * float [ Vx, Vy, Vz, Nx, Ny, Nz, Tv, Tu]
GLsizei offsV  = 0 * sizeof(GL_float); // offset of the vertex inside the reccord
GLsizei offsNV = 3 * sizeof(GL_float); // offset of the normal vector inside the reccord
GLsizei offsTC = 6 * sizeof(GL_float); // offset of the tecture coordinate inside the reccord

glVertexAttribPointer( vetexAttribIndex,  3, GL_FLOAT, GL_FALSE, stride, offsV );  // 3: Vx, Vy, Vz
glVertexAttribPointer( normalAttribIndex, 3, GL_FLOAT, GL_TRUE,  stride, offsNV ); // 3: Nx, Ny, Nz  -  GL_TRUE: values should be normalized
glVertexAttribPointer( texCorAttribIndex,  2, GL_FLOAT, GL_FALSE, stride, offsTC ); // 2: Tu, Tv 

glEnableVertexAttribArray( vetexAttribIndex );
glEnableVertexAttribArray( normalAttribIndex );
glEnableVertexAttribArray( texCorAttribIndex );

glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, ibo );
glDrawElements( GL_TRIANGLES, (GLsizei)indices.size(), GL_UNSIGNED_INT, nullptr );
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 ); 

glBindBuffer( GL_ARRAY_BUFFER, 0 );
glDisableVertexAttribArray( vetexAttribIndex );
glDisableVertexAttribArray( normalAttribIndex );
glDisableVertexAttribArray( texCorAttribIndex );

顶点数组对象

要处理不同的顶点属性指针而不是交替指定和启用或禁用它们,可以生成一个顶点数组对象(glGenVertexArrays,它存储了有关缓冲区位置、数据格式、状态和属性索引的所有信息:

OpenGL 4.6 core Specification - 10.3.1 Vertex Array Objects:

将GL的顶点阶段要使用的缓冲区对象收集在一起,形成一个顶点数组对象。 所有与顶点处理器使用的数据定义相关的状态都封装在一个顶点数组对象中。

....

当前绑定的顶点数组对象用于所有修改顶点数组状态的命令,例如VertexAttribPointer和EnableVertexAttribArray; 所有从顶点数组中绘制的命令,例如 DrawArrays 和 DrawElements;

例如顶点、法线向量和纹理坐标

[ Vx0, Vy0, Vz0, Nx0, Ny0, Nz0, Tv0, Tu0,
  Vx1, Vy1, Vz1, Nx1, Ny1, Nz1, Tv1, Tu1,
  .....
]

创建顶点数组缓冲区和索引缓冲区:

GLsizei no_of_points;
std::vector<GLfloat> data;    // attribute set: [ Vx0, Vy0, Vz0, Nx0, Ny0, Nz0, Tv0, Tu0, Vx1, Vy1, Vz1, Nx1, Ny1, Nz1, Tv1, Tu1, .... ]
std::vector<GLuint>  indices; // indces: [ I0, I1, I2, I3, I4, ..... ]

GLuint vbo;

glGenBuffers( 1, &vbo );
glBindBuffer( GL_ARRAY_BUFFER, vbo );
glBufferData( GL_ARRAY_BUFFER, data.size() * sizeof(GLfloat), data.data(), GL_STATIC_DRAW );
glBindBuffer( GL_ARRAY_BUFFER, 0 );

GLuint ibo;

glGenBuffers( 1, &ibo );
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, ibo );
glBufferData( GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(GLuint), indices.data(), GL_STATIC_DRAW );
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );

创建顶点数组对象:

GLuint vao;

glGenVertexArrays( 1, &vao );
glBindVertexArray( vao );

GLuint vetexAttribIndex;  // index of the vertex attrbute (shader)
GLuint normalAttribIndex; // index of the normal attribute (shader)
GLuint texCorAttribIndex; // index of the texture coordinate attribute (shader)

glBindBuffer( GL_ARRAY_BUFFER, vbo );

GLsizei stride = 8 * sizeof(GL_float); // size of one record in bytes: 8 * float [ Vx, Vy, Vz, Nx, Ny, Nz, Tv, Tu]
GLsizei offsV  = 0 * sizeof(GL_float); // offset of the vertex inside the reccord
GLsizei offsNV = 3 * sizeof(GL_float); // offset of the normal vector inside the reccord
GLsizei offsTC = 6 * sizeof(GL_float); // offset of the tecture coordinate inside the reccord

glVertexAttribPointer( vetexAttribIndex,  3, GL_FLOAT, GL_FALSE, stride, offsV );  // 3: Vx, Vy, Vz
glVertexAttribPointer( normalAttribIndex, 3, GL_FLOAT, GL_TRUE,  stride, offsNV ); // 3: Nx, Ny, Nz  -  GL_TRUE: values should be normalized
glVertexAttribPointer( texCorAttribIndex,  2, GL_FLOAT, GL_FALSE, stride, offsTC ); // 2: Tu, Tv 

glEnableVertexAttribArray( vetexAttribIndex );
glEnableVertexAttribArray( normalAttribIndex );
glEnableVertexAttribArray( texCorAttribIndex );

glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, ibo ); // Associate the element array buffer (index buffer) to the vertex array object

glBindVertexArray( 0 ); // Unbind the vertex array object

glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 ); // Unbinde the element array buffer. This has to be done after the vertex array object is unbound, otherwise the association to the vertex array object would be lost.

见:

绘制数组:

glBindVertexArray( vao );
glDrawElements( GL_TRIANGLES, (GLsizei)indices.size(), GL_UNSIGNED_INT, nullptr );
glBindVertexArray( 0 );

注意,与index buffer (ELEMENT_ARRAY_BUFFER) 相比,vertex buffer 绑定 (ARRAY_BUFFER) 是一个全局状态。
在 VAO 状态向量中陈述的每个属性都可以引用不同的ARRAY_BUFFER。在调用glVertexAttribPointer 时存储此引用,然后将当前绑定到目标ARRAY_BUFFER 的缓冲区关联到指定的属性索引,并将对象的名称(值)存储在当前的状态向量中绑定 VAO。
但索引缓冲区是 VAO 的一种状态。当缓冲区绑定到目标ELEMENT_ARRAY_BUFFER 时,此缓冲区将关联到当前绑定的顶点数组对象。

【讨论】:

  • 我明天一定会检查这个答案,因为现在在我的国家已经很晚了。 OpenGL 文档网站对我来说的问题是,它们以正式的方式解释事情,这让我非常困惑
猜你喜欢
  • 2013-07-04
  • 1970-01-01
  • 2020-12-08
  • 2015-05-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多