μκΈ°κ° ν μ μλ λͺ¨λ κ²μ νλ κ²μ μΈκ°μ΄ λλ κ²μ΄μ, μκΈ°κ° νκ³ μΆμ λͺ¨λ κ²μ νλ κ²μ μ μ΄ λλ κ²μ΄λ€ --λν΄λ μΉ
Compiled Vertex Array (CVA's) example #
- μμ μ : Nutty. ( http://www.nutty.org )
There seems to be bit of misconception of what CVA's actually do. Because of the word "compiled" alot of people assume they're going to perform like display lists.
CVAκ° μ€μ λ‘ λ¬΄μμ νλμ§μ λν μ€ν΄μ μ¬μ§κ° μ‘°κΈ μλ€. "compiled"λΌλ λ¨μ΄λλ¬Έμ λ§μ μ¬λλ€μ΄ CVAκ° Display Listμ λΉμ·νκ² μ€νλλ κ²μΌλ‘ κ°μ£Όνλ€.
If an object is rendered by only doing one pass on it's geometry, then it is hardly likely to get any advantage at all to using CVA's. (The only advantage is if you use indexed arrays, and some vertices are used more than once, hence they might be cached and can be used straight away again)
λ§μ½ κ°μ²΄κ° κ·Έμμ μ λ°μ΄νλ₯Ό λ¨μ§ 1 ν¨μ€ μνν¨μΌλ‘μ¨ λλλ§ λλ€λ©΄, κ·Έκ²μ CVAλ₯Ό μ¬μ©νλ μμ μ μ ν μ»μ μ μλ€. (λ§μ½ μΈλ±μ€μ²λ¦¬λ λ°°μ΄μ μ¬μ©νκ³ , λͺλͺ μ μ μ 1λ²μ΄μ μ¬μ©λλ€κ³ ν λ μ μΌν μμ μ μ»μ μ μλ€. κ·Έλ¬λ―λ‘ κ·Έκ²λ€μ μΊμ¬μ²λ¦¬λ κ²μ΄κ³ λ€μ νλ² μ§μ μ μΌλ‘ μ¬μ©λ μ μλ€.) - ν΄μμ΄ μ΄μνλΉ...-_-;
However, what they are good for is drawing the same bit of geometry multiple times in the same place. (Multi pass rendering)
μ΄μ¨κ±°λ, CVAκ° μ₯μ μ λ°ννλ λμλ κ°μ μ§μ μμ μ¬λ¬λ² κ°μ λͺ¨μμ λνμ κ·Έλ €μΌ ν λμ΄λ€. (λ©ν°ν¨μ€ λλλ§)
Because the vertex array is locked (i.e. the app is not altering it) the driver can cache the transformed vertices after the first pass and use them again for the second pass, etc...
μ μ λ°°μ΄μ΄ μ 겨μκΈ° λλ¬Έμ
In the real world, it seems that the people who have used this feature, didn't really see that much of a speed gain. Typically 2 %. Hopefully this is down to the driver not really optimizing for this feature. Which means if they ever do get around to it, code using this will get a nice speedup!
In order to use the Lock and unlock functions we must first get the procedure addresses from windows. Instead of giving you a huge gl extension header file too. I've put the function declarations into this file.
This should be remedied when the next release of OpenGL comes out. At the moment they are extensions.
First we typedef how the functions look. i.e. their paremeters, and return value. Then we create two functions pointers. In glInit() function, we then get the addresses of these functions. The strings are everything! Spell these wrong, and it wont work!
The first tutorial program, used indexed vertex arrays. With the function glDrawElements.
In this program we will use non indexed vertex arrays. As I need to create vertices and their appropriate texture coordinates for each face, it means I can't reuse vertices. So it makes no sense to use extra memory on indexing them. Non indexed vertex arrays are drawn using glDrawArrays.
This source can be distributed freely.
Nutty. nutty@nutty.org
#include <stdio.h>
#include <glut.h>
#include <GL/glaux.h> //For loading bitmap textures.
// Define our vertex structure.
typedef struct
{
GLfloat x, y, z;
}Vertex3;
// Define a 2 element structure. Perfect for texture coords! :)
typedef struct
{
GLfloat u, v;
}Vertex2;
// The format of the functions we're gonna get hold of.
typedef void (APIENTRY *PFNGLLOCKARRAYSEXTPROC) (int first, int count);
typedef void (APIENTRY *PFNGLUNLOCKARRAYSEXTPROC) (void);
//Our two function pointers.
PFNGLLOCKARRAYSEXTPROC glLockArraysEXT = NULL;
PFNGLUNLOCKARRAYSEXTPROC glUnlockArraysEXT = NULL;
// The Initial size of our window
GLint window_width = 640;
GLint window_height = 480;
// Our constant. Number of faces per cube.
const GLuint NUMBER_FACES = 6;
const char *const TEXTURE1_FILENAME = "TEXTURE1.BMP";
const char *const TEXTURE2_FILENAME = "TEXTURE2.BMP";
// This is variables for rotating the cube.
GLfloat xangle=0.0f, yangle=0.0f;
GLuint g_texture1, g_texture2;
// 1 when being controlled by the mouse.
GLuint mouse_control = 0;
// Our vertex array! Holds the points for each corner of the cube.
Vertex3 cube_verts[] = {
{ -2.0f, 2.0f, 2.0f, }, //Frontface
{ -2.0f, -2.0f, 2.0f, },
{ 2.0f, -2.0f, 2.0f, },
{ 2.0f, 2.0f, 2.0f, },
{ -2.0f, 2.0f, -2.0f, }, //Backface
{ 2.0f, 2.0f, -2.0f, },
{ 2.0f, -2.0f, -2.0f, },
{ -2.0f, -2.0f, -2.0f, },
{ -2.0f, 2.0f, -2.0f, }, //Topface
{ -2.0f, 2.0f, 2.0f, },
{ 2.0f, 2.0f, 2.0f, },
{ 2.0f, 2.0f, -2.0f, },
{ -2.0f, -2.0f, 2.0f, }, //Bottom face
{ -2.0f, -2.0f, -2.0f, },
{ 2.0f, -2.0f, -2.0f, },
{ 2.0f, -2.0f, 2.0f, },
{ -2.0f, 2.0f, -2.0f, }, //Left face
{ -2.0f, -2.0f, -2.0f, },
{ -2.0f, -2.0f, 2.0f, },
{ -2.0f, 2.0f, 2.0f, },
{ 2.0, 2.0f, 2.0f, }, //Right face
{ 2.0, -2.0f, 2.0f, },
{ 2.0, -2.0f, -2.0f, },
{ 2.0, 2.0f, -2.0f, },
};
// These are the texture coords. Their positions map exactly as the vertex array.
Vertex2 tex_coords[] = {
{ 0.0, 1.0f, },
{ 1.0f, 1.0f, },
{ 1.0f, 0.0f, },
{ 0.0f, 0.0f, },
{ 1.0, 0.0f, },
{ 0.0f, 0.0f, },
{ 0.0f, 1.0f, },
{ 1.0f, 1.0f, },
{ 0.0f, 1.0f, },
{ 0.0f, 0.0f, },
{ 1.0f, 0.0f, },
{ 1.0f, 1.0f, },
{ 0.0f, 1.0f, },
{ 0.0f, 0.0f, },
{ 1.0f, 0.0f, },
{ 1.0f, 1.0f, },
{ 0.0f, 1.0f, },
{ 0.0f, 0.0f, },
{ 1.0f, 0.0f, },
{ 1.0f, 1.0f, },
{ 0.0f, 1.0f, },
{ 0.0f, 0.0f, },
{ 1.0f, 0.0f, },
{ 1.0f, 1.0f, },
};
void DrawCube(void)
{
/* In this function we use a little trick to depth sort the transparent object properly.
As we all know to draw transparent objects correctly, we must disable depth testing. However
if the faces are not drawn in the right order, it just doesn't look right. This technique is
dirty, but it works well if your objects are convex! Basically just cull front polygons, then render
again culling back polygons. You must have your polygon vertices wound anti clockwise for this to work.
If you wind them clockwise, swap GL_FRONT and GL_BACK.
As we're doing 2 passes inside here as well, it makes even more sense for us to use Array locking to
benefit from cached transformed vertices!
*/
//Enable Face culling.
glEnable(GL_CULL_FACE);
//Cull the front faces.
glCullFace(GL_FRONT);
//First pass.
glDrawArrays(GL_QUADS, 0, 24);
//Cull back polygons.
glCullFace(GL_BACK);
//2nd pass
glDrawArrays(GL_QUADS, 0, 24);
//Disable it. (These enable and disables should really not be done this often!)
glDisable(GL_CULL_FACE);
}
void Render(void)
{
//all the usual stuff.
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
//Move it and spin it!
glTranslatef(0.0f, 0.0f, -5.0f);
glRotatef(xangle, 1.0f, 0.0f, 0.0f);
glRotatef(yangle, 0.0f, 1.0f, 0.0f);
//Enable the vertex and color arrays.
glEnableClientState(GL_VERTEX_ARRAY);
//glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
//Tell gl, what our arrays look like! 3 floats per vertex, 0 packing, and their addresses.
glVertexPointer(3, GL_FLOAT, 0, cube_verts);
glTexCoordPointer(2, GL_FLOAT, 0, tex_coords);
//Lock the arrays! This tells GL we aren't altering the vertices at all From this point on!
glLockArraysEXT(0, 24);
//Bind texture1.
glBindTexture(GL_TEXTURE_2D, g_texture1);
//Full alpha.
glColor4f(1.0f, 1.0f, 1.0f, 0.9f);
//Draw the main cube. 1st pass.
DrawCube();
//Disable our texture coords! Not needed anymore.
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
//Bit less alpha.
glColor4f(1.0f, 1.0f, 1.0f, 0.4f);
//Other texture!
glBindTexture(GL_TEXTURE_2D, g_texture2);
//Turn on auto texture coord generation in 2 dimensions.
glEnable(GL_TEXTURE_GEN_S);
glEnable(GL_TEXTURE_GEN_T);
//Draw It again. 2nd pass!
DrawCube();
//Turn off auto texture coord generation.
glDisable(GL_TEXTURE_GEN_S);
glDisable(GL_TEXTURE_GEN_T);
//Unlock the arrays.
glUnlockArraysEXT();
glutSwapBuffers();
}
void Idle(void)
{
if(!mouse_control)
{
xangle += 0.4f;
if(xangle >= 360.0f)
{
xangle -= 360.0f;
}
yangle += 0.55f;
if(yangle >= 360.0f)
{
yangle -=360.0f;
}
}
glutPostRedisplay();
}
void Resize(int width, int height)
{
if(height == 0)
{
height = 1;
}
window_width = width;
window_height = height;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, window_width, window_height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective (90, (float)window_width / (float)window_height, 1, 5000);
glutPostRedisplay();
}
void Keyboard(unsigned char key, int x, int y)
{
if(key == 27) //If escape key.
{
exit(0);
}
}
void Mouse(int button, int state, int x, int y)
{
if(state == GLUT_DOWN)
{
mouse_control = 1;
}
else
{
mouse_control = 0;
}
}
void Motion(int x, int y)
{
if(mouse_control == 1)
{
xangle = y;
yangle = x;
}
}
GLuint LoadTexture(const char *const filename)
{
AUX_RGBImageRec *image;
GLuint texture;
image = auxDIBImageLoad(filename);
glEnable(GL_TEXTURE_2D);
glGenTextures(1, &texture);
//Bind the texture.
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, image->sizeX, image->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, image->data);
//Just make it simple Bi-inear filtering.
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
return texture;
}
void glInit(void)
{
glEnable(GL_DEPTH_TEST);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glShadeModel(GL_SMOOTH);
glShadeModel(GL_FLAT);
glLockArraysEXT = (PFNGLLOCKARRAYSEXTPROC) wglGetProcAddress("glLockArraysEXT");
glUnlockArraysEXT = (PFNGLUNLOCKARRAYSEXTPROC) wglGetProcAddress("glUnlockArraysEXT");
if(glLockArraysEXT == NULL || glUnlockArraysEXT == NULL)
{
printf("\nCould not get procedure addresses for Lock and Unlock functions\n");
exit(1);
}
g_texture1 = LoadTexture(TEXTURE1_FILENAME);
g_texture2 = LoadTexture(TEXTURE2_FILENAME);
//Turn off depth testing and writing. As we're blending.
glDisable(GL_DEPTH_TEST);
glDepthMask(0);
//Setup sphere mappping for Auto texture coords generation.
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
//Turn addative blending on.
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
}
void main(void)
{
//Set the window up.
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowSize(window_width,window_height);
glutCreateWindow("Compiled Vertex Array Test - Esc quits.");
//Setup our callback functions.
glutDisplayFunc(Render);
glutReshapeFunc(Resize);
glutIdleFunc(Idle);
glutKeyboardFunc(Keyboard);
glutMotionFunc(Motion);
glutMouseFunc(Mouse);
glInit();
glutMainLoop();
}








![[http]](/wiki/imgs/http.png)
