OpenGL Programming Guild 第八版,示例程序和“NumVAOs”

Posted

技术标签:

【中文标题】OpenGL Programming Guild 第八版,示例程序和“NumVAOs”【英文标题】:OpenGL Programming Guild Eighth Edition, sample programs and 'NumVAOs' 【发布时间】:2013-07-23 00:44:32 【问题描述】:

对于看过我之前问题的任何人,在完成了 2.1 版的红皮书之后,我现在转向 4.3 版。 (你说老胡说,因为你们中的许多人多年来一直告诉我这样做。)

所以,我已经深入第 3 章了,但仍然没有让第 1 章的示例程序正常工作。

我有两个问题。 (实际上是3。)首先,它不编译。好的,这是一个问题,但考虑到接下来的两个,有点无关紧要。其次,我不完全了解它是如何工作的或它试图做什么,但我们会继续讨论的。

第三,在我看来,这段代码的作者是一个完全的魔术师。我建议这里正在发生各种修补黑客行为。这很可能是因为第 2 个问题,即我不明白它要做什么。写这本书的人当然不是白痴,但请耐心等待,我举个例子。

这是取自main.cpp 文件顶部的一段代码。稍后我将包含文件的其余部分,但现在:

enum VAO_IDs 
    Triangles,
    NumVAOs
;

如果我理解正确,这将给VAO_IDs::Triangles 提供1 的值,因为枚举是从零开始的。 (我希望我在这里是正确的,否则我会很尴尬。)

不久之后,你可以看到这一行:

GLuint VAOs[NumVAOs];

它声明了一个 GLuint 的数组,其中包含 1 个 GLuint,因为 NumVAOs 等于 1。现在,首先,它不应该是 VAO_IDs::NumVAOs 吗?

其次,到底为什么要以这种方式使用枚举?出于显而易见的原因,我永远不会使用这样的枚举 - 不能有多个具有相同值的数据,没有明确指定值等等......

我在这里吠叫正确的树吗?这样做是没有意义的...... VAO 应该是一个全球性的,像这样,肯定吗? GLuint NumVAOs = 1;这只是对枚举的滥用!

事实上,const GLuint NumVertices = 6; 语句的下方出现了。这是有道理的,不是吗,因为我们可以根据需要更改值 6,但是我们不能将 NumVAOs 更改为 0,例如,因为 Triangles 已经设置为 0。(为什么它在枚举中?说真的?)

无论如何,忘记枚举的...现在...好吧,我做了很多事情,这就是问题的结束...我现在拥有的任何其他 cmets 都在代码中。你可以忽略大部分 glfw 的东西,它本质上和 glut 一样。

// ----------------------------------------------------------------------------
//
// Triangles - First OpenGL 4.3 Program
//
// ----------------------------------------------------------------------------

#include <cstdlib>
#include <cstdint>
#include <cmath>

#include <stdio.h>
#include <iostream>

//#include <GL/gl.h>
//#include <GL/glu.h>
#include <GL/glew.h>
#include <GLFW/glfw3.h>


/// OpenGL specific
#include "vgl.h"
#include "LoadShaders.h" // These are essentially empty files with some background work going on, nothing declared or defined which is relevant here

enum VAO_IDs 
    Triangles,
    NumVAOs
;
// So Triangles = 0, NumVAOs = 1
// WHY DO THIS?!

enum Buffer_IDs 
    ArrayBuffer,
    NumBuffers
;

enum Attrib_IDs 
    vPosition = 0

// Please, please, please someone explain the enum thing to me, why are they using them instead of global -just- variables.
// (Yeah an enum is a variable, okay, but you know what I mean.)

GLuint VAOs[NumVAOs]; // Compile error: expected initializer before 'VAOs'
GLuint Buffers[NumBuffers]; // NumBuffers is hidden in an enum again, so it NumVAOs

const GLuint NumVertices = 6; // Why do something different here?

// ----------------------------------------------------------------------------
//
// Init
//
// ----------------------------------------------------------------------------

void init()

    glGenVertexArrays(NumVAOs, VAOs); // Error: VAOs was not declared in this scope
    glBindVertexArray(VAOs[Triangles]);

    GLfloat vertices[NumVertices][2] = 
         -0.90, -0.90 ,
         +0.85, -0.90 ,
         -0.90, +0.85 ,
         +0.90, -0.85 ,
         +0.90, +0.90 ,
         -0.85, +0.90 
    ;

    glGenBuffers(NumBuffers, Buffers);
    glBindBuffer(GL_ARRAY_BUFFER, Buffers[ArrayBuffer]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    ShaderInfo shaders[] = 
         GL_VERTEX_SHADER, "triangles.vert" ,
         GL_FRAGMENT_SHADER, "triangles.frag" ,
         GL_NONE, nullptr 
    ;

    GLuint program = LoadShaders(shaders);
    glUseProgram(program);

    glVertexAttribPointer(vPosition, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
    glEnableVertexAttribArray(vPosition);


// ----------------------------------------------------------------------------
//
// Display
//
// ----------------------------------------------------------------------------

void display()

    glClear(GL_COLOR_BUFFER_BIT);

    glBindVertexArray(VAOs[Triangles]);
    glDrawArrays(GL_TRIANGLES, 0, NumVertices); // Error VAOs not declared

    glFlush();


// ----------------------------------------------------------------------------
//
// Main
//
// ----------------------------------------------------------------------------

void error_handle(int error, const char* description)

    fputs(description, stderr);


void key_handle(GLFWwindow* window, int key, int scancode, int action, int mods)

    if(key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
        glfwSetWindowShouldClose(window, GL_TRUE);




void handle_exit()





int main(int argc, char **argv)


    // Setup exit function
    atexit(handle_exit);


    // GLFW Window Pointer
    GLFWwindow* window;


    // Setup error callback
    glfwSetErrorCallback(error_handle);


    // Init
    if(!glfwInit())
    
        exit(EXIT_FAILURE);
    


    // Setup OpenGL
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glEnable(GL_DEPTH_TEST);


    // Set GLFW window hints
    glfwWindowHint(GLFW_DEPTH_BITS, 32);
    glfwWindowHint(GLFW_RED_BITS, 8);
    glfwWindowHint(GLFW_GREEN_BITS, 8);
    glfwWindowHint(GLFW_BLUE_BITS, 8);
    glfwWindowHint(GLFW_ALPHA_BITS, 8);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, 1);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);


    // Init GLEW
    if(glewInit())
    
        printf("GLEW init failure!\n", stderr);
        exit(EXIT_FAILURE);
    


    // Init OpenGL
    init();


    // Create Window
    window = glfwCreateWindow(800, 600, "Window Title", nullptr, nullptr);
    if(!window)
    
        glfwTerminate();
        return EXIT_FAILURE;
    

    // Make current
    glfwMakeContextCurrent(window);


    // Set key callback
    glfwSetKeyCallback(window, key_handle);


    // Check OpenGL Version
    char* version;
    version = (char*)glGetString(GL_VERSION);
    printf("OpenGL Application Running, Version: %s\n", version);


    // Enter main loop
    while(!glfwWindowShouldClose(window))
    
        // Event polling
        glfwPollEvents();

        // OpenGL Rendering

        // Setup OpenGL viewport and clear screen
        float ratio;
        int width, height;
        glfwGetFramebufferSize(window, &width, &height);
        ratio = width / height;

        glViewport(0, 0, width, height);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        // Setup projection
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluPerspective(45.0, ratio, 0.1, 10.0);

        // Render
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();

        // Swap Buffers
        glfwSwapBuffers(window);
    


    // Free glfw memory allocated for window
    glfwDestroyWindow(window);


    // Exit
    glfwTerminate();
    exit(EXIT_SUCCESS);

我意识到这是一个非常冗长的问题,但我认为重要的是解释为什么我认为它的代码很疯狂,而不是像很容易那样说“我不明白”。有人可以解释为什么这些非常聪明的人决定这样做,以及为什么会出现错误。 (我在网上找不到任何相关信息。)

【问题讨论】:

那些enums 尖叫着被重写为简单的#define 预处理器语句。我同意你的观点,作者使用enums 的决定令人困惑。 枚举的好处是当你需要增加更多的价值时,你不需要修改代码的其他部分。 @JesseCraig 好的,我真的很高兴听到其他人同意!关于其他编译错误的任何想法?我至少检查了两次,我确定这本书有误。 @yngum 这可能是真的,但它仍然无法编译...:S 【参考方案1】:

作者正在使用enums 的自动编号属性来自动更新NumVAOsNumBuffers 值的定义。例如,当新的 VAO ID 添加到 enum 时,NumVAOs 的值仍然是正确的,只要它在 enum 中最后列出。

enum VAO_IDs 
    Triangles,
    Polygons,
    Circles,
    NumVAOs
;

很可能你的编译器不支持这个技巧。

【讨论】:

嗯,这既聪明又愚蠢。我正在使用 gcc / g++ 4.6 版,或者如果需要,我可以使用 4.8 版。 gcc 4.6 肯定支持这个吗? 它是否适用于VAO_IDs::NumVAOs 语法?如果您将enum 值重新实现为const#define 值,则查看代码不会有任何改变。作者的选择确实分散了本书教授 OpenGL 的意图。 好的,它现在可以工作了,谢谢...至少它编译。没有链接,还没有......很多“未定义的引用” @JesseCraig:你为什么说这是一个“技巧”,为什么你认为某些编译器可能不支持它?这是枚举的一个非常常见(且定义明确)的用例。 @derhass:你说得很好,一个人的把戏就是另一个人的工具。

以上是关于OpenGL Programming Guild 第八版,示例程序和“NumVAOs”的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL Programming On macOS using glfw 0: Build a Simple OpenGL Program

DX与OpenGL投影矩阵的区别

Arcball轨迹球

我是不是正确使用了 on_guild_leave 函数?

discord py,ctx.guild.members,只返回bot

在 guild.roles 中获取未定义