[Qt for Android] OpenGL ES draws color cubes, qtandroid

Source: Internet
Author: User

[Qt for Android] OpenGL ES draws color cubes, qtandroid

Qt has built-in support for OpenGL ES. It is very convenient to use Qt for OpenGL ES development. Many helper classes are available. A QWindow class has been added since Qt 5.0. This class can be used to draw 3D graphics using OpenGL or QPainter to draw 2D traditional GDI + graphics. qglwidgets earlier than 5.0 are not recommended. In the coming (official time this fall), Qt 5.4 will completely discard QGLWidget. As an alternative, QOpenGLWidget and QOpenGLWindow classes will be added to facilitate OpenGL programming.

I will use OpenGL ES to draw a color Cube today. Compile and run it on the desktop platform and compile it on the Android platform, the following figure shows the running effect on Android. Four identical colored cubes are drawn based on the same shader.

To use OpenGL, I derived an OpenGLWindow class from the QWindow class and QOpenGLFunctions class. The declaration of this class is as follows:

class OpenGLWindow : public QWindow, protected QOpenGLFunctions{    Q_OBJECTpublic:    explicit OpenGLWindow(QWindow *parent = 0);    ~OpenGLWindow();    virtual void initialize();    virtual void render(QPainter *painter);    virtual void render(double currentTime = 0.0);      // elapsed seconds from program started.protected:    void exposeEvent(QExposeEvent *event);private:    QOpenGLPaintDevice *m_device;    QOpenGLContext *m_context;    QTime   startTime;    GLuint m_program;//    QOpenGLShaderProgram *m_shaderProgram; };

Because it inherits from QWindow, you can use the OpenGL environment provided by QWindow. You do not need to use EGL to control local window display graphics. At the same time, because it inherits from QOpenGLFunctions, you can directly use the gl *-style native OpenGL API in the OpenGLWindow class member functions. Many encapsulated OpenGL convenient classes are provided in Qt. For example, QOpenGLShaderProgram can be used to conveniently operate the shader program. However, this may be unfriendly to those who are not familiar with Qt, so here I don't need the convenient class provided by Qt, but directly use the native C-style OpenGL API for operations, which is completely acceptable (this is one of the reasons I like Qt: provides its own class libraries, allows you to use non-Qt classes, and provides conversions between them, for example, the container class QVector, QMap, and QString in Qt can be converted to the corresponding containers in the C ++ standard library ). You can even use Qt's OpenGL class together with the native OpenGL API.

The following describes several key functions. Initialize () is responsible for creating, compiling, linking, and other operations of the shader, and setting the background color. The Code is as follows. The annotated part uses the Qt built-in class library to implement the same function.

void OpenGLWindow::initialize(){    const char *vertexShaderSrc =            "attribute vec4 a_position; \n"            "uniform mat4 u_mvp; \n"            "varying vec4 v_color; \n"            "void main()               \n"            "{                         \n"            "      v_color = a_position*0.7 + 0.5;  \n"            "      gl_Position = u_mvp * a_position; \n"            "}                              \n";    const char *fragmentShaderSrc =            "varying vec4 v_color; \n"            "void main()                    \n"            "{                              \n"            "   gl_FragColor = v_color; \n"            "}                              \n";    GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);    glShaderSource(vertexShader, 1, &vertexShaderSrc, NULL);    glCompileShader(vertexShader);    GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);    glShaderSource(fragmentShader, 1, &fragmentShaderSrc, NULL);    glCompileShader(fragmentShader);    m_program = glCreateProgram();    glAttachShader(m_program, vertexShader);    glAttachShader(m_program, fragmentShader);    glLinkProgram(m_program);//    // add vertex shader(compiled internal)//    m_shaderProgram->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSrc);//    // add fragment shader(compiled internal)//    m_shaderProgram->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSrc);//    // link shaders to program//    m_shaderProgram->link();    // set the background clear color.    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);}

Let's take a look at the QExposeEvent event of QWindow. When QWindow needs to be re-painted, it will call the event processing function exposeEvent (). Here I have rewritten the event processing function. IsExposed () is used to determine whether the current window is displayed on the screen (onScreen or offScreen). It is re-painted only when it is displayed on the screen (although the window needs to be re-painted, however, since it is not displayed on the screen and no one can see it after re-painting, adding this judgment can reduce unnecessary drawing operations ). First, create the OpenGL context and call the corresponding initialization function. These two steps are only executed for the first time and will not be executed later. Next is the core part of the function. Call the render () function to render the image in the backend buffer, and then swap the front-end and backend buffers to display the backend buffer graphics on the interface.

void OpenGLWindow::exposeEvent(QExposeEvent *event){    Q_UNUSED(event)    static bool needInit = true;    // Returns true if this window is exposed in the windowing system.    if (isExposed())    {        if (m_context == nullptr)        {            m_context = new QOpenGLContext(this);            m_context->setFormat(requestedFormat());            m_context->create();        }        m_context->makeCurrent(this);        if (needInit)        {            initializeOpenGLFunctions();            this->initialize();            needInit = false;        }        // calculate elapsed seconds from program started.        double duration = startTime.msecsTo(QTime::currentTime()) / 1000.0;        render(duration);        m_context->swapBuffers(this);    }}

Finally, let's look at the render () Rendering function, which is also the main part of learning OpenGL.

A QOpenGLPaintDevice instance is created at the beginning of the render () function. This example is used to plot the QPainter. It can be ignored or deleted here. The next step is to define the vertex position of the cube and the vertex index. Create two vertex buffer objects (vertex buffer objects). Use the glBufferData () function to place the vertex positions and vertices of the cube in the vertex buffer object and use glVertexAttribPointer () passed to the vertex shader. Calculate model/view/projection, pass the result to the mvp in the vertex coloring tool through glUniformMatrix4fv (), and draw the cube using glDrawElement. The color of each vertex in a cube is determined by its position. Therefore, vertices in different positions have different colors.

void OpenGLWindow::render(double currentTime){    if (m_device == nullptr)        m_device = new QOpenGLPaintDevice;    m_device->setSize(this->size());    static GLfloat vCubeVertices[] = {        -0.5f,  0.5f,  0.5f,  // v0        -0.5f, -0.5f,  0.5f,  // v1         0.5f, -0.5f,  0.5f,  // v2         0.5f,  0.5f,  0.5f,  // v3         0.5f, -0.5f, -0.5f,  // v4         0.5f,  0.5f, -0.5f,  // v5        -0.5f,  0.5f, -0.5f,  // v6        -0.5f, -0.5f, -0.5f, // v7    };    static GLushort vCubeIndices[] = {        0, 1, 2, 0, 2, 3,   // front face        5, 6, 7, 4, 5, 7,   // back face        0, 1, 7, 0, 6, 7,   // left face        2, 3, 4, 3, 4, 5,   // right face        0, 3, 5, 0, 5, 6,   // top face        1, 2, 4, 1, 4, 7    // bottom face    };    glViewport(0, 0, width(), height());    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);    glUseProgram(m_program);    GLuint vbos[2];    glGenBuffers(2, vbos);    glBindBuffer(GL_ARRAY_BUFFER, vbos[0]);    glBufferData(GL_ARRAY_BUFFER, sizeof(vCubeVertices), vCubeVertices, GL_STATIC_DRAW);    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbos[1]);    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(vCubeIndices), vCubeIndices, GL_STATIC_DRAW);    glBindBuffer(GL_ARRAY_BUFFER, vbos[0]);    glEnableVertexAttribArray(0);    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);    glBindAttribLocation(m_program, 0, "a_position");    static GLfloat angle = 0.0;    GLuint mvpLoc = glGetUniformLocation(m_program, "u_mvp");    QMatrix4x4 model, view, projection, mvp;    model.rotate(angle + 5, QVector3D(1,0,0));    model.rotate(angle - 5, QVector3D(0,1,0));    model.scale(0.5, 0.5, 0.5);    view.translate(0.5, 0.5, 0);    angle += 10;    mvp = projection * view * model;    glUniformMatrix4fv(mvpLoc, 1, GL_FALSE, mvp.constData());    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbos[1]);    glDrawElements(GL_TRIANGLES, sizeof(vCubeIndices)/sizeof(GLushort), GL_UNSIGNED_SHORT, 0);    /* draw another cube in different place with the same shader */    view.translate(-1.0, 0, 0);    mvp = projection * view * model;    glUniformMatrix4fv(mvpLoc, 1, GL_FALSE, mvp.constData());    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbos[1]);    glDrawElements(GL_TRIANGLES, sizeof(vCubeIndices)/sizeof(GLushort), GL_UNSIGNED_SHORT, 0);    view.translate(0.0, -1.0, 0);    mvp = projection * view * model;    glUniformMatrix4fv(mvpLoc, 1, GL_FALSE, mvp.constData());    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbos[1]);    glDrawElements(GL_TRIANGLES, sizeof(vCubeIndices)/sizeof(GLushort), GL_UNSIGNED_SHORT, 0);    view.translate(1.0, 0, 0);    mvp = projection * view * model;    glUniformMatrix4fv(mvpLoc, 1, GL_FALSE, mvp.constData());    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbos[1]);    glDrawElements(GL_TRIANGLES, sizeof(vCubeIndices)/sizeof(GLushort), GL_UNSIGNED_SHORT, 0);    QPainter painter(m_device);    render(&painter);    glDeleteBuffers(2, vbos);}

Okay, that's all ~


Android opengl es makes a cube, how to achieve touch and drag it to rotate

Set a speed variable fSpeed. It is equal to the drag distance/drag time, so that the faster the drag, the faster the conversion.
It's nothing more than letting the fSpeed reduce an offset when there is no drag operation.
 
Use opengl to draw color cubes. I'm a newbie, guide

Remove these three rows. You do not need to set glOrtho as follows:
GlMatrixMode (GL_MODELVIEW );
GlLoadIdentity ();
GluLookAt (1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0 );

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.