OpenGL:多种渲染方法.. 何时使用哪个?

Posted

技术标签:

【中文标题】OpenGL:多种渲染方法.. 何时使用哪个?【英文标题】:OpenGL: Multiple Rending methods .. When to use which? 【发布时间】:2015-01-12 21:06:53 【问题描述】:

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

例如 .. 我正在关注使用着色器渲染立方体的 example,当我尝试使用“正常”方式渲染它时 - 如果这是一个正确的表达式。什么都没有被渲染。我总是需要打电话给shaderProgram.setAttributeArray()shaderProgram.enableAttributeArray()shaderProgram.disableAttributeArray()

但是如果我尝试使用另一种方式直接渲染它 - 再次,如果这是一个正确的表达式 - 使用 glBegin()glEnd()。没有任何工作

另外,我有另一个问题着色器概念本身,我真的不明白什么时候应该使用它,什么时候不应该使用它

这是我的例子:

#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();

【问题讨论】:

【参考方案1】:

OpenGL 曾经有所谓的“immediate mode”。在其中,您将使用glBegin()glEnd(),并在它们之间逐点指定您的数据(点、法线、纹理坐标)。你会在每一帧上都这样做,所以显然这很慢。此功能早已被弃用,但大多数显卡驱动程序仍然支持它,以免破坏现有软件。但是,如果您想学习现代 OpenGL,我会忽略任何包含 glBegin() 的教程。今天,您一次性将数据传输到 GPU(到称为 Vertex Buffer Object 的东西),然后用一个命令绘制(使用 Vertex Array Object)

您的另一个问题是关于着色器的。同样,在过去,OpenGL 曾经有一个fixed-function pipeline。这意味着您只提供顶点(正常,...)数据,而显卡会继续执行它的工作。您无法修改它对数据的作用。在现代世界中,管道的某些部分是可编程的,这意味着您可以更改管道的某些部分的功能(通过提供您自己的程序 - shaders)。这非常有用,因为有许多其他方式无法实现的效果。同样,如果您不提供自己的着色器,出于兼容性原因,显卡大多会退回到默认实现。但是您绝对应该编写自己的着色器(基本的只是几行代码)。

总而言之,如果您开始学习现代 OpenGL(VBO、VAO、着色器),可能需要更长的时间来完成基础知识,但如果您开始学习遗留的东西,总有一天您将不得不离开它并从头开始学习现代 OpenGL。

编辑:混合现代和遗留代码通常不是一个好主意。你可能会得到它的工作,但它只是不值得痛苦。

【讨论】:

但我有一个问题......在最后一个例子中,这家伙到底在哪里使用 VertexBufferObject 和 VertexArrayObject? 此外,此示例仅显示如何使用调用 glDrawArrays(GL_TRIANGLES, 0, vertices.size()); 渲染三角形,但如果我想渲染例如 Normals .. 使用 shaders 模式可以替代什么? .. 即,glNormal3d() 呼叫的替代方案是什么? 在示例中,作者没有使用VBO和VAO,而是使用glDrawArrays,在渲染之前将数据从内存一次性复制到OpenGL。它介于即时模式和 VBO 之间(今天也已弃用)。您找到的示例是,我想较少解释一般的 OpenGL,而更多地考虑 Qt OpenGL 库。 你不渲染法线。您像顶点一样传递它们(每个顶点都应该有一个法线),然后将它们全部渲染。法线用于照明,所以我建议阅读“照明”一章,其中可能有一些解释。 我不知道很多教程网站,但opengl-tutorial.org 看起来不错 - 你可以看看。

以上是关于OpenGL:多种渲染方法.. 何时使用哪个?的主要内容,如果未能解决你的问题,请参考以下文章

使用 opencl 将软件渲染到 opengl 2d 视图 [关闭]

OPENGL和D3D哪个好

如何使用 openGL 在 android studio 中渲染 .dae(collada) 文件

OpenGL 无效的纹理或状态

OpenGL游戏引擎渲染器[关闭]

在窗口中渲染时,OpenGL 中的第三个三角形顶点显示为 0.0