不需要VAO吗?

时间:2016-03-04 01:49:19

标签: c++ opengl

据我所知,顶点提取阶段由VAO封装,并且VAO需要包含顶点提取阶段状态,以便在缓冲区对象和顶点属性之间进行管道处理,以及格式化缓冲区对象中的数据。

我读过的两本关于i.Red书的书,蓝皮书都明确提到VAO必须包含顶点提取阶段状态数据

然而,当我实际创建2个纹理对象并简单地格式化数据一次没有VAO存储有关缓冲区的信息时,它仍然可以正常运行而没有任何打嗝,然后我重新加载第一个对象,然后再次它工作正常没有任何问题,那么这些信息从缓冲区对象中的数据格式中拉出来了什么?

我甚至第二次将缓冲区数据上传到同一个缓冲区对象,这意味着那里保存的先前信息会被重置?而且图片仍然可以很好地呈现窗口

那到底是怎么回事?书中说一件事,现实中发生的事情完全不同而且相反

有人可以解释一下这里实际需要什么,不是什么?究竟发生了什么?

我们什么时候才能真正需要VAO?什么时候可以不用? 不需要时,额外代码处理有什么意义?

以下代码:

int main(){

   int scrW=1280, scrH=720;

   //create context and shader program
   init(scrW, scrH);
   createShaders();

   //create texture objects and load data from image to server memory
   char object[2][25];
   strcpy(object[0], "back.bmp");
   strcpy(object[1], "256x256.bmp");


   //triangle 1
   GLfloat vertices[] = 
   //  X      Y      U    V
   {  -1.0, -1.0,   0.0, 0.0,
       1.0, -1.0,   1.0, 0.0,
       1.0,  1.0,   1.0, 1.0,
      -1.0,  1.0,   0.0, 1.0};


   //glPointSize(40.0f);

   //create and bound vertex buffer object(memory buffers)   
   GLuint vbo1 = createVbo();

   //The state set by glVertexAttribPointer() is stored in the currently bound vertex array object (VAO) if vertex array object bound
   //associates the format of the data for the currently bound buffer object to the vertex attribute so opengl knows how much and how to read it
   glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4*sizeof(GLfloat), 0);
   glEnableVertexAttribArray(0);

   //shader vertex attribute for texture coordinates
   glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4*sizeof(GLfloat), (const GLvoid*)(2 * sizeof(GLfloat)));
   glEnableVertexAttribArray(1);

   //upload vertices to buffer memory
   //will upload data to currently bound/active buffer object
   glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);  

   //load and create texture object from image data
   GLuint tex1 = createTexture(object[0]);

   glDrawArrays(GL_QUADS, 0, 4);

   glXSwapBuffers ( dpy, glxWin );
   sleep(3);


   GLuint tex2 = createTexture(object[1]);

   glDrawArrays(GL_QUADS, 0, 4);


   glXSwapBuffers ( dpy, glxWin );
   sleep(3);

   glBindTexture(GL_TEXTURE_2D, tex1);

   glDrawArrays(GL_QUADS, 0, 4);


   glXSwapBuffers ( dpy, glxWin );
   sleep(3);


   //////////////de-initialize
   glXMakeContextCurrent( dpy, 0, 0, NULL );
   glXDestroyContext( dpy, context );
   glXDestroyWindow(dpy, glxWin);
   XDestroyWindow( dpy, win );
   XCloseDisplay( dpy );

   return 0;
}

和着色器

 const char* vertex_shader =
      "#version 400\n"
      "layout(location =  0) in vec2 vp;"
      "layout(location = 1) in vec2 tex;"
      "out vec2 texCoord;"
      "void main () {"
      "  gl_Position = vec4 (vp, 0.0f, 1.0f);"
      "  texCoord = tex; "
      "}";

   const char* fragment_shader =
      "#version 400\n"
      "uniform sampler2D s;"
      "in vec2 texCoord;"
      "out vec4 color;"
      "void main () {"
      "color = texture(s, texCoord);"
      "}";

为了避免混淆,这里是init()过程

 static int att[] =
   {
      GLX_X_RENDERABLE    , True,
      GLX_DRAWABLE_TYPE   , GLX_WINDOW_BIT,
      GLX_RENDER_TYPE     , GLX_RGBA_BIT,
      GLX_X_VISUAL_TYPE   , GLX_TRUE_COLOR,
      GLX_RED_SIZE        , 8,
      GLX_GREEN_SIZE      , 8,
      GLX_BLUE_SIZE       , 8,
      GLX_ALPHA_SIZE      , 8,
      GLX_DEPTH_SIZE      , 24,
      GLX_STENCIL_SIZE    , 8,
      GLX_DOUBLEBUFFER    , True,
      //GLX_SAMPLE_BUFFERS  , 1,
      //GLX_SAMPLES         , 4,
      None
   };

   Display                          *dpy;
   Window                            root;   
   XVisualInfo                      *vi;
   Colormap                          cmap;
   XSetWindowAttributes              swa;
   Window                            win;
   GLXContext                        context;
   GLXFBConfig                      *fbc;
   GLXWindow                         glxWin; 
   int                               fbcount;


void init(int width, int height){

   //set and choose displays for creating window
   dpy = XOpenDisplay(NULL);
   if (!dpy){
      printf("Failed to open X display\n");
      exit(1);
   }   

   root = DefaultRootWindow(dpy);

   //request a framebuffer configuration
   fbc = glXChooseFBConfig(dpy, DefaultScreen(dpy), att, &fbcount);

   if (!fbc){
      printf( "Failed to retrieve a framebuffer config\n" );
      exit(1);
   }

   vi = glXGetVisualFromFBConfig( dpy, fbc[0] );

   if(vi==NULL){
      printf("Error getting visual info\n");
      exit(1);
   }
   swa.colormap = XCreateColormap( dpy, RootWindow( dpy, vi->screen ), vi->visual, AllocNone );

   swa.background_pixmap = None ;
   swa.border_pixel            = 0;
   swa.event_mask            = StructureNotifyMask;

   //Window XCreateWindow(display, parent, x, y, width, height, border_width, depth, class, visual, valuemask, attributes) 

   win = XCreateWindow( dpy, RootWindow( dpy, vi->screen ), 0, 0, width, height, 0, vi->depth, InputOutput, vi->visual, CWBorderPixel|CWColormap|CWEventMask, &swa );
   if ( !win ){
      printf( "Failed to create window.\n" );
      exit(1);
   }

   context = glXCreateNewContext( dpy, fbc[0], GLX_RGBA_TYPE, NULL, True );

   glxWin = glXCreateWindow(dpy, fbc[0], win, NULL);

   XMapWindow(dpy, win);

   glXMakeContextCurrent(dpy, glxWin, glxWin, context);

   // start GLEW extension handler
   glewExperimental = GL_TRUE;
   GLuint err = glewInit();

   if(err!=GLEW_OK){
      fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
      exit(1);
   }


   XSelectInput(dpy, win, ButtonPressMask|KeyPressMask);

   // tell GL to only draw onto a pixel if the shape is closer to the viewer
   //glEnable (GL_DEPTH_TEST); // enable depth-testing
   //glDepthFunc (GL_LESS); // depth-testing interprets a smaller value as "closer"


}

1 个答案:

答案 0 :(得分:3)

如果使用兼容性OpenGL上下文,则不需要VAO。从某种意义上说,有一个“默认”VAO始终受到约束。这就是它在OpenGL 2.x中的工作方式,这是“兼容性”在“兼容性配置文件”中的含义。

在使用核心OpenGL上下文时,您需要一个VAO。如果不这样做,您的代码将无法正常工作。如果你想继续假装你不需要VAO,你可以创建一个VAO并让它在整个程序期间受到限制。

选择核心与兼容性配置文件的问题有其细微差别,但一般情况下,如果您正在开发新程序,建议请求核心配置文件。并非所有系统都支持兼容性配置文件。 Mesa将兼容性配置文件限制为3.0,OS X将它们限制为2.1。如果需要核心配置文件,则必须在创建上下文时明确请求核心配置文件。