Qt + OpenGL4.0 --------顶点数组对象

        Qt和OpenGL都是是跨平台的库、因此在学习OpenGL的时候,如果熟悉Qt库,在Qt中使用OpenGL将是一件非常愉快的事情、由于Qt对平台GUI的封装,使得我们不用关心平台窗口的事情,同时,Qt的QGLWidget对OpenGL本事也做了一些封装,为在学习使用OpenGL的时候,提供了很大的便利,不用一开始就过于考虑细节的事情。

        本文以OpenGL4.0为基础、介绍一个简单的顶点数组对象的(VAO)使用方法。为了验证怎么使用VAO,创建了一个平面网格类,将一个平面矩形按三角形序列渲染出来。首先看看平面网格类的定义:

class CVxPlaneMesh: public Drawable
{
public:
    CVxPlaneMesh(int iRow = 10, int iCol = 10 , float fWidth = 10, float fHeight = 10);
    virtual ~CVxPlaneMesh(void);
     void render() const;
private:
    GLuint   m_iVAO;   //顶点数组对象。
    int      m_iFaces; //多少个三角形面片
};


CVxPlaneMesh::CVxPlaneMesh(int iRow, int iCol, float fWidth, float fHeight)
{
    int iVertexCnt  = ( iRow + 1) * ( iCol + 1);
    float* pVertex = new float[ iVertexCnt * 3];

    int iIndexCnt  = 2 * 3 * iRow * iCol;
    unsigned int*   pIndex  = new unsigned int[ iIndexCnt ];

    m_iFaces = iRow * iCol;

    float fDeltaX = fWidth / iCol;
    float fDeltaY = fHeight / iRow;

    for ( int i = 0; i <= iRow ; i ++)
    {
        for (int j = 0; j <= iCol; j ++ )
        {
            float* pPos = pVertex + ( i * ( iCol + 1 ) + j ) * 3;   //第多少个顶点,再*3,

            * pPos = j * fDeltaX - 0.5 * fWidth;        //X
            *(pPos + 1) =  0;                           //Y
            *(pPos + 2) = i * fDeltaY - 0.5 * fHeight;  //Z
        }
    }
    //顶点搞定,现在搞定索引。
    for ( int i = 0; i <  iRow ; i ++)
    {
        for (int j = 0; j < iCol; j ++ )
        {
            unsigned int* p = pIndex + 2 * 3 * ( i * iCol + j );  //每个方格有两个三角形组成,

            *p++ = (i + 1) * (iCol + 1) + j;
            *p++ =  i *  (iCol + 1) + j;
            *p++ =  i *  (iCol + 1) + j + 1;

            *p++ = (i + 1) *  (iCol + 1) + j;
            *p++ = (i *  (iCol + 1)) + j + 1;
            *p   = (i + 1) *  (iCol + 1) + j + 1;

        }
    }

    //生成VAO
    glGenVertexArrays( 1, &m_iVAO );
    glBindVertexArray(m_iVAO);


    GLuint iHandle[2];
    glGenBuffers(2, iHandle);

    glBindBuffer(GL_ARRAY_BUFFER,iHandle[0]);
    glBufferData(GL_ARRAY_BUFFER,3 * (iRow+1) * (iCol+1) * sizeof(float),(void*) pVertex, GL_STATIC_DRAW);
    glVertexAttribPointer( (GLuint)0, 3, GL_FLOAT, GL_FALSE, 0, ((GLubyte *)NULL + (0)) );
    glEnableVertexAttribArray(0);  // Vertex position
    
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iHandle[1]);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6 * iRow * iCol * sizeof(unsigned int),(void*)pIndex, GL_STATIC_DRAW );

     glBindVertexArray(0);
    delete[] pVertex;
    delete[] pIndex;
}


CVxPlaneMesh::~CVxPlaneMesh(void)
{
}
void CVxPlaneMesh::render() const
{
    glBindVertexArray(m_iVAO);
    glDrawElements(GL_TRIANGLES, 6 * m_iFaces, GL_UNSIGNED_INT, ((GLubyte *)NULL + (0)));

}

以上是平面网格类的定义,现在将这个网格放到一个场景中去,场景类的定义如下:

class CVxPlaneScene : public Scene
{
private:
    GLSLProgram prog;

    int width, height;
    CVxPlaneMesh *plane;
    float angle;

    mat4 model;
    mat4 view;
    mat4 projection;

    void setMatrices();
    void compileAndLinkShader();

public:
    CVxPlaneScene();

    void initScene();
    void update( float t );
    void render();
    void resize(int, int);
};
CVxPlaneScene::CVxPlaneScene() : angle(0.0f)
{
}

void CVxPlaneScene::initScene()
{
    compileAndLinkShader();

    glClearColor(0.0,0.0,0.0,1.0);
    glEnable(GL_DEPTH_TEST);

    plane = new CVxPlaneMesh();

    view = glm::lookAt(vec3(0.0f,10.0f,0.0f), vec3(0.0f,0.0f,0.0f), vec3(0.0f,0.0f,-1.0f));

    projection = glm::ortho(-10.0, 10.0, -10.0, 10.0, 0.0, 100.0);/*mat4(1.0f);*/

}

void CVxPlaneScene::update( float t )
{
    //angle += 1.0f;
    //if( angle > 360.0 ) angle -= 360.0;
}

void CVxPlaneScene::render()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glPolygonMode(GL_FRONT_AND_BACK ,GL_LINE );

    model = mat4(1.0f);
    setMatrices();
    plane->render();
}

void CVxPlaneScene::setMatrices()
{
    mat4 mv = view * model;
    prog.setUniform("MVP", projection * mv);
}

void CVxPlaneScene::resize(int w, int h)
{
    glViewport(0,0,w,h);
    width = w;
    height = h;
    projection = glm::perspective(70.0f, (float)w/h, 0.3f, 100.0f);
}

void CVxPlaneScene::compileAndLinkShader()
{
    if( ! prog.compileShaderFromFile("shader/PlaneScene.vert",GLSLShader::VERTEX) )
    {
        printf("Vertex shader failed to compile!\n%s",
               prog.log().c_str());
        exit(1);
    }
    if( ! prog.compileShaderFromFile("shader/PlaneScene.frag",GLSLShader::FRAGMENT))
    {
        printf("Fragment shader failed to compile!\n%s",
               prog.log().c_str());
        exit(1);
    }
    if( ! prog.link() )
    {
        printf("Shader program failed to link!\n%s",
               prog.log().c_str());
        exit(1);
    }

    if( ! prog.validate() )
    {
        printf("Program failed to validate!\n%s",
               prog.log().c_str());
        exit(1);
    }

    prog.use();

}

这里的Shader代码很简单,只是简单的做个变换。

#version 400
layout (location = 0) in vec3 VertexPosition;
uniform mat4 MVP;
void main()
{
   gl_Position = MVP * vec4(VertexPosition,1.0);
}



#version 400
layout( location = 0 ) out vec4 FragColor;

void main()
{
    FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}

将场景渲染到QGLWidget窗口中,显示如下图形




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值