OpenGL:多种渲染方法..什么时候使用哪种?

OpenGL: Multiple Rending methods .. When to use which?

我是 OpenGL 的新手,我正在学习多个教程,我注意到有多种方法用于渲染对象,但我仍然不明白它们之间的区别以及何时使用它们?

例如 .. 我正在关注这个 example,它使用着色器渲染立方体,当我尝试使用 "normal" 方式渲染它时 - 如果这是一个正确的表达式。没有任何东西被渲染。我总是需要调用 shaderProgram.setAttributeArray()shaderProgram.enableAttributeArray()shaderProgram.disableAttributeArray()

但是,如果我尝试使用其他方式直接渲染它 - 同样,如果这是一个正确的表达式 - 使用 glBegin()glEnd()。没有任何效果

另外,我还有一个问题shader概念本身,我不太明白什么时候该用什么时候不该

这是我的例子:

#include "glwidget.h"

GlWidget::GlWidget(QWidget *parent)
    : QGLWidget(QGLFormat(/* Additional format options */), parent)
{
    alpha = 25;
    beta = -25;
    distance = 2.5;
}

void GlWidget::initializeGL()
{
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_CULL_FACE);

    qglClearColor(QColor(Qt::white));

    shaderProgram.addShaderFromSourceFile(QGLShader::Vertex, ":/vertexShader.vsh");
    shaderProgram.addShaderFromSourceFile(QGLShader::Fragment, ":/fragmentShader.fsh");
    shaderProgram.link();

    vertices << QVector3D(-0.5, -0.5,  0.5) << QVector3D( 0.5, -0.5,  0.5) << QVector3D( 0.5,  0.5,  0.5) // Front
             << QVector3D( 0.5,  0.5,  0.5) << QVector3D(-0.5,  0.5,  0.5) << QVector3D(-0.5, -0.5,  0.5)
             << QVector3D( 0.5, -0.5, -0.5) << QVector3D(-0.5, -0.5, -0.5) << QVector3D(-0.5,  0.5, -0.5) // Back
             << QVector3D(-0.5,  0.5, -0.5) << QVector3D( 0.5,  0.5, -0.5) << QVector3D( 0.5, -0.5, -0.5)
             << QVector3D(-0.5, -0.5, -0.5) << QVector3D(-0.5, -0.5,  0.5) << QVector3D(-0.5,  0.5,  0.5) // Left
             << QVector3D(-0.5,  0.5,  0.5) << QVector3D(-0.5,  0.5, -0.5) << QVector3D(-0.5, -0.5, -0.5)
             << QVector3D( 0.5, -0.5,  0.5) << QVector3D( 0.5, -0.5, -0.5) << QVector3D( 0.5,  0.5, -0.5) // Right
             << QVector3D( 0.5,  0.5, -0.5) << QVector3D( 0.5,  0.5,  0.5) << QVector3D( 0.5, -0.5,  0.5)
             << QVector3D(-0.5,  0.5,  0.5) << QVector3D( 0.5,  0.5,  0.5) << QVector3D( 0.5,  0.5, -0.5) // Top
             << QVector3D( 0.5,  0.5, -0.5) << QVector3D(-0.5,  0.5, -0.5) << QVector3D(-0.5,  0.5,  0.5)
             << QVector3D(-0.5, -0.5, -0.5) << QVector3D( 0.5, -0.5, -0.5) << QVector3D( 0.5, -0.5,  0.5) // Bottom
             << QVector3D( 0.5, -0.5,  0.5) << QVector3D(-0.5, -0.5,  0.5) << QVector3D(-0.5, -0.5, -0.5);
}

void GlWidget::resizeGL(int width, int height)
{
    if (height == 0) {
        height = 1;
    }

    pMatrix.setToIdentity();
    pMatrix.perspective(60.0, (float) width / (float) height, 0.001, 1000);

    glViewport(0, 0, width, height);
}

void GlWidget::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    QMatrix4x4 mMatrix;
    QMatrix4x4 vMatrix;

    QMatrix4x4 cameraTransformation;
    cameraTransformation.rotate(alpha, 0, 1, 0);
    cameraTransformation.rotate(beta, 1, 0, 0);

    QVector3D cameraPosition = cameraTransformation * QVector3D(0, 0, distance);
    QVector3D cameraUpDirection = cameraTransformation * QVector3D(0, 1, 0);

    vMatrix.lookAt(cameraPosition, QVector3D(0, 0, 0), cameraUpDirection);

    shaderProgram.bind();
    shaderProgram.setUniformValue("mvpMatrix", pMatrix * vMatrix * mMatrix);

    // This code is able to draw the cube
    shaderProgram.setAttributeArray("vertex", vertices.constData());
    shaderProgram.enableAttributeArray("vertex");
    glDrawArrays(GL_TRIANGLES, 0, vertices.size());
    shaderProgram.disableAttributeArray("vertex");
    // end

    // This code is never able to draw the cube or anything
    glBegin(GL_TRIANGLES);
    for (int var = 0; var < vertices.size(); ++var) {
        glVertex3f(vertices[var][0],vertices[var][1],vertices[var][2]);
    }
    glEnd();
    // end

    shaderProgram.release();
}

OpenGL 曾经有所谓的“immediate mode". In it, you would use glBegin() and glEnd() and, between them, specify your data (points, normals, texture coordinates) point by point. You would do this on every frame, so obviously this is very slow. This functionality has long been deprecated, but most graphics card drivers still support it so as not to break existing software. However, if you want to learn modern OpenGL, I would ignore any tutorial that has glBegin() in it. Today, you transfer the data to the GPU in one go (into something called Vertex Buffer Object), then draw with one command (using a Vertex Array Object)

你的另一个问题是关于着色器的。同样,在过去,OpenGL 曾经有一个 fixed-function pipeline. That means that you only supply vertex (normal, ...) data and the graphics card goes on and does its thing. You could not modify what it does with the data. In the modern world, some parts of the pipeline are programmable, meaning that you can change what some parts of the pipeline do (by supplying your own programs - shaders)。这非常有用,因为有许多效果是否则无法实现的。同样,如果您不提供自己的着色器,出于兼容性原因,显卡将大多退回到默认实现。但是你绝对应该编写自己的着色器(基本的着色器只有几行)。

总而言之,如果您开始学习现代 OpenGL(VBO、VAO、着色器),可能需要更长的时间才能掌握基础知识,但如果您开始学习传统知识,总有一天您将不得不离开它,从头开始学习现代 OpenGL。

编辑:混合现代代码和遗留代码通常不是一个好主意。您可能会成功,但不值得为此付出痛苦。