据我所知,顶点抓取阶段是由VAO封装的,VAO需要包含顶点抓取阶段状态,以便在缓冲区对象和顶点属性之间进行管道传输,以及格式化缓冲区对象中的数据。
我读过的两本关于i.Red主题的书,蓝皮书都明确提到VAO必须包含顶点fetch阶段状态数据
然而,当我实际创建2个纹理对象并简单地格式化数据一次而没有VAO来存储关于buffer的信息时,它仍然运行得很好,没有任何问题,然后我再次重新加载第一个对象,它同样工作得很好,没有任何问题,那么这些关于buffer对象中数据格式化的信息是从哪里提取的呢?
我甚至第二次将buffer数据上传到同一个buffer对象,这意味着之前保存在那里的信息将被重置?并且图片仍然可以很好地呈现在窗口上
那么到底是怎么回事呢?书中说了一件事,现实中发生的事情是完全不同和相反的
有人能解释一下这里到底需要什么,不需要什么吗?到底是怎么回事?
什么时候我们真的需要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"
}发布于 2016-03-04 09:55:32
如果使用兼容性OpenGL上下文,则不需要VAO。从某种意义上说,有一个“默认”的VAO总是被绑定的。这就是它在OpenGL 2.x中的工作方式,这也是“兼容性配置文件”中“兼容性”含义的一部分。
在使用核心OpenGL上下文时,您确实需要一个VAO。如果你不这样做,你的代码就不能工作。如果你想继续假装你不需要一个VAO,你可以创建一个单独的VAO,并在整个程序期间绑定它。
选择核心配置文件与兼容性配置文件的问题有其细微差别,但一般来说,如果您正在开发新程序,建议您请求核心配置文件。无论如何,并不是所有的系统都对兼容性配置文件有很好的支持。Mesa将兼容性配置文件限制为3.0,而OS X将其限制为2.1。如果您需要核心概要文件,则必须在创建上下文时显式请求核心概要文件。
https://stackoverflow.com/questions/35786560
复制相似问题