OpenGL是否会消除没有绑定顶点缓冲区的顶点着色器?

3

《OpenGL超级圣经第6版》(适用于OpenGL 4.3)中有一些使用顶点着色器的示例,这些着色器没有顶点属性输入,而是硬编码的顶点,例如:

#version 420 core
void main(void) 
{                                                                 
    const vec4 vertices[] = vec4[](vec4( 0.4, -0.4, 0.5, 1.0), 
                                   vec4(-0.4, -0.4, 0.5, 1.0),    
                                   vec4( 0.4,  0.4, 0.5, 1.0));   
    gl_Position = vertices[gl_VertexID];  
 }

当我运行示例时,窗口被清除但是没有其他反应。
通过实验,我发现将空缓冲区绑定到上下文中,程序才能按预期运行。以下是示例程序:
#include <stdio.h>
#include <stdlib.h>
#include <GL/glew.h> /
#include <GLFW/glfw3.h> 
#define GLM_MESSAGES
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtx/vector_angle.hpp>

int main(int argc, char* argv[]) {
    GLuint program;
    GLuint vao;
    GLuint vbo;

    glfwInit();
    GLFWwindow* window = glfwCreateWindow(640, 480, "gl_InstanceID", NULL, NULL);
    glfwMakeContextCurrent(window);

    glewInit();
    program = glCreateProgram();
    GLuint vs = load("vertex.glsl", GL_VERTEX_SHADER, true);
    GLuint fs = load("frag.glsl", GL_FRAGMENT_SHADER, true);
    glAttachShader(program, vs);
    glAttachShader(program, fs);
    glLinkProgram(program); 
    glDeleteShader(vs);
    glDeleteShader(fs);

    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);

//**************************************
//no triangle drawn when below these lines commented out
    glGenBuffers(1, &vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, 4, NULL, GL_DYNAMIC_COPY);
    glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, NULL);
    glEnableVertexAttribArray(0);
//***************************************

    do {
        static const GLfloat green[] = { 0.0f, 0.2f, 0.0f, 1.0f };
        glClearBufferfv(GL_COLOR, 0, green);
        glUseProgram(program);
        glDrawArrays(GL_TRIANGLES, 0, 3); //OR glDrawArraysInstanced(GL_TRIANGLES, 0, 3,1);
        glfwSwapBuffers(window);

        glfwPollEvents();
        if (GLFW_PRESS == glfwGetKey(window, GLFW_KEY_ESCAPE)) {
            glfwSetWindowShouldClose(window, 1);
        }
    } while (!glfwWindowShouldClose(window));
    glfwTerminate();
    return 0;
}

在星号之间添加代码,将绘制三角形。没有缓冲区就不会绘制三角形。

此外,当顶点数组对象(VAO)被移除(或像上面那样使用)时,三角形也不会显示。只有带有(空的)VBO和VAO时才会绘制三角形。 移除VAO但保留缓冲区则会显示三角形。没有缓冲区就没有三角形。VAO似乎没有什么影响。

还要注意的是,顶点着色器没有输入。

这是怎么回事?

  1. 编译器/显卡认为顶点着色器没有任何作用并将其删除吗?我感觉是显卡(驱动程序)。
  2. 这是否符合OpenGL的预期,还是因为显卡的原因?
  3. 我对缓冲区、VAO和着色器的理解有所欠缺吗?

其他可能有用的信息

  • GLEW 1.10.0
  • GLFW 3.0.3

片段着色器:

#version 420 core
out vec4 color;
void main(void)
{
color = vec4(1.0);
}

操作系统详细信息:

  • Linux版本:3.2.0-4-amd64
  • 发行版:Debian 7.3 Wheezy
  • uname -m:x86_64

编译器详细信息:

  • g++ --version: g++ (Debian 4.7.2-5) 4.7.2

OpenGL详细信息:

  • OpenGL供应商: Advanced Micro Devices(来自AMD Catalyst Control Center)
  • OpenGL渲染器: AMD Radeon HD 7600M Series(来自AMD Catalyst Control Center)
  • OpenGL版本: 4.2.11762 Compatibility Profile Context(来自AMD Catalyst Control Center)
  • glxinfo:
  • server glx version string: 1.4
  • client glx version string: 1.4
  • GLX version: 1.4
  • OpenGL version string: 4.2.11762 Compatibility Profile Context
  • OpenGL shading language version string: 4.20
  • server glx vendor string: ATI
  • client glx vendor string: ATI

在Windows上,使用与Linux相同的显卡时也会出现问题,即:

  • Windows 8
  • 64位
  • 运行在一个来自ATI Technologies Inc.的AMD Radeon HD 7670M上。
  • 支持OpenGL版本4.2.11762 Compatibility Profile Context

AMD有一个新的Linux驱动程序版本13.12(我正在使用13.4)。当我有时间时,我会尝试安装它,因为上次的安装并不容易。

我还记录了Unofficial AMD Bugzilla上的问题984。但也许在13.12中已经修复了。


然而,该程序在以下系统上运行正常(无论是否使用空缓冲区):

  • Windows 7 Pro
  • 64位
  • NVIDIA GeForce GT 520M(驱动程序日期:2013/10/15,驱动程序版本:9.18.13.3158)

  • Windows 8
  • 64位
  • 运行在Intel(R) HD Graphics 4000下
  • OpenGL版本4.0.0 - Build 9.17.10.2849

将 #version 420 core 添加到片段着色器并没有起到帮助作用。 - robor
3个回答

2
不要误解,glDrawArrays (...)与哪个顶点缓冲区绑定无关。仅当设置顶点指针时,顶点缓冲区绑定才有意义,因为它定义了您传递的指针相对于的地址空间。从那时起,绑定的VBO就不再相关了。顺便说一句,如果在严格的GLSL实现上运行此片段着色器,它将发出警告/拒绝工作,因为没有#version指令,它应该假定片段着色器是针对GLSL 1.10规范编写的,这不支持out阶段变量(您需要使用gl_FragData [0])。
或者,只需像在顶点着色器中一样添加#version 420 core即可...版本指令实际上比您想象的更重要,特别是因为其缺失会导致不同厂商之间的行为差异很大。这样做可能不会解决您的问题,但这确实是一个您应该解决的问题。
至于删除VAO的问题,这是可以预料的。在核心OpenGL 3.2+上下文中,必须绑定非零VAO才能使glDrawArrays (...)工作。实际上,VAO成为顶点绘制命令的上下文。如果没有绑定一个,则无法对其进行操作的上下文。

经过进一步的实验:移除VAO但保留缓冲区可以显示三角形。VAO似乎没有什么影响,需要缓冲区才能工作。感谢版本提示。 - robor
1
那么您没有使用核心配置文件上下文。在兼容性上下文(默认情况下),它可以工作。值得一提的是,如果您启用了一个顶点属性数组,而没有将任何VBO绑定到它上面,结果将是未定义的。现在,所有属性数组最初都被禁用,因此如果这是您的整个程序,那么我必须想象这是一个驱动程序错误。 - Andon M. Coleman
我如何判断我是否正在使用核心配置文件上下文?glxinfo没有提到核心配置文件,只有兼容性。 - robor
如果你正在使用核心配置文件,你会知道的。为了获得核心配置文件,您需要执行额外的步骤,在GLFW中无法准确告诉您这些步骤是什么,但通常涉及在设置上下文时使用“窗口提示”。每个框架的处理方式略有不同,但在所有情况下,除非您进行此额外工作,否则默认情况下会获得兼容性配置文件。兼容性配置文件并不一定是坏事,它们具有比核心配置文件更宽松的限制,因此对于刚开始学习的人来说更容易。但是,某些平台不支持它们(例如OS X)。 - Andon M. Coleman
也许我应该在Windows上运行相同的程序,看看Linux和Windows的驱动程序是否不同。 - robor
显示剩余2条评论

0
请记住,顶点着色器只能操作现有的顶点。它不能创建它们。即使位置在着色器中是硬编码的,您仍然需要提供一些内容来进行转换。

1
这不是真的,你实际上可以在桌面OpenGL中很好地运行这种类型的程序。即使没有(已启用的)数组指针来提取数据,'glDrawArrays(...)'也会隐式生成每个顶点的顺序'gl_VertexID'值。 GLES则是另一回事,但在桌面GL中,您始终可以使用'gl_VertexID'索引一些硬编码点。 - Andon M. Coleman

0

不是的,看起来这是AMD Radeon HD 7600M系列(13.4)驱动程序中的一个错误。

我安装了最新的AMD驱动程序,在Windows和Linux中都解决了问题。

Linux:安装amd-catalyst-13.12-linux-x86.x86_64.zip

Windows:安装amd_catalyst_13.11_mobility_betav9.5.exe


在Linux上重新安装AMD驱动程序,我首先卸载了AMD安装(amd-catalyst-previous-version.run --uninstall),删除了所有包含名称fglrx的软件包(使用aptitude),调整了符号链接到/usr/lib64(见下文),然后运行新的amd-catalyst-13.12-linux-x86.x86_64.run。

我遇到了这个页面AMD 13.1 64位驱动程序和libGL.so.1错误,其中解释了AMD安装程序放置libGL.so文件的位置

安装程序将lib文件放在/usr/lib64中。然而,如果您使用的是Ubuntu,则64位库应该放在/usr/lib中。我采取了以下措施来解决我的问题。
卸载驱动程序 sudo ./amd-driver-installer-catalyst-13.1-legacy-linux-x86.x86_64.run --uninstall
删除/usr/lib64文件夹 sudo rm -Rf /usr/lib64
创建一个符号链接/usr/lib64,指向/lib/usr sudo ln -s /usr/lib /usr/lib64
重新安装驱动程序 sudo ./amd-driver-installer-catalyst-13.1-legacy-linux-x86.x86_64.run --force 重新启动 sudo reboot

你能在搭载AMD硬件的机器上运行Windows吗?通常来说,NV/AMD的专有Linux驱动程序与Windows驱动程序共享大致相同的代码库(尽管通常具有更长的发布时间表),但你永远不知道。 - Andon M. Coleman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接