OpenGL之再向虎山行[2]:超越glBegin/glEnd
想当年学习OpenGL的时候,就是从glBegin/glEnd开始的,呵呵。
但是glBegin/glEnd并不适合大场景绘制,在OpenGL ES中甚至被踢出局,所以再玩OpenGL,必然要超越它。
Data:
// cube ///////////////////////////////////////////////////////////////////////
// v6----- v5
// /| /|
// v1------v0|
// | | | |
// | |v7---|-|v4
// |/ |/
// v2------v3
// vertex coords array
GLfloat vertices[] = {1,1,1, -1,1,1, -1,-1,1, 1,-1,1, // v0-v1-v2-v3
1,1,1, 1,-1,1, 1,-1,-1, 1,1,-1, // v0-v3-v4-v5
1,1,1, 1,1,-1, -1,1,-1, -1,1,1, // v0-v5-v6-v1
-1,1,1, -1,1,-1, -1,-1,-1, -1,-1,1, // v1-v6-v7-v2
-1,-1,-1, 1,-1,-1, 1,-1,1, -1,-1,1, // v7-v4-v3-v2
1,-1,-1, -1,-1,-1, -1,1,-1, 1,1,-1}; // v4-v7-v6-v5
// normal array
GLfloat normals[] = {0,0,1, 0,0,1, 0,0,1, 0,0,1, // v0-v1-v2-v3
1,0,0, 1,0,0, 1,0,0, 1,0,0, // v0-v3-v4-v5
0,1,0, 0,1,0, 0,1,0, 0,1,0, // v0-v5-v6-v1
-1,0,0, -1,0,0, -1,0,0, -1,0,0, // v1-v6-v7-v2
0,-1,0, 0,-1,0, 0,-1,0, 0,-1,0, // v7-v4-v3-v2
0,0,-1, 0,0,-1, 0,0,-1, 0,0,-1}; // v4-v7-v6-v5
// color array
GLfloat colors[] = {1,1,1, 1,1,0, 1,0,0, 1,0,1, // v0-v1-v2-v3
1,1,1, 1,0,1, 0,0,1, 0,1,1, // v0-v3-v4-v5
1,1,1, 0,1,1, 0,1,0, 1,1,0, // v0-v5-v6-v1
1,1,0, 0,1,0, 0,0,0, 1,0,0, // v1-v6-v7-v2
0,0,0, 0,0,1, 1,0,1, 1,0,0, // v7-v4-v3-v2
0,0,1, 0,0,0, 0,1,0, 0,1,1}; // v4-v7-v6-v5
// index array of vertex array for glDrawElements()
// Notice the indices are listed straight from beginning to end as exactly
// same order of vertex array without hopping, because of different normals at
// a shared vertex. For this case, glDrawArrays() and glDrawElements() have no
// difference.
GLubyte indices[] = {0,1,2,3,
4,5,6,7,
8,9,10,11,
12,13,14,15,
16,17,18,19,
20,21,22,23};
补充一个原来做的小例子:
void drawTorus(int numMajor, int numMinor, float majorRadius, float minorRadius)
{
static double PI = 3.1415926535897932384626433832795;
double majorStep = 2.0 * PI / numMajor;
double minorStep = 2.0 * PI / numMinor;
GLint shine = 128;
GLfloat opacity = 255;
GLfloat ambiMat[4] = { 0.2f, 0.5f, 0.7f, opacity };
GLfloat diffMat[4] = { 0.7f, 0.7f, 0.7f, opacity };
GLfloat specMat[4] = { 1.0f, 1.0f, 1.0f, opacity };
GLfloat specRef[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
// Enable Material
glEnable(GL_COLOR_MATERIAL);
glEnable(GL_AUTO_NORMAL);
glEnable(GL_NORMALIZE);
glDepthFunc(GL_LESS);
//Setup Material
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, ambiMat);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffMat);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specMat);
// All materials hereafter have full specular reflectivity
// with a high shine
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specRef);
glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, shine);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
for (int i = 0; i < numMajor; ++i)
{
double a0 = i * majorStep;
double a1 = a0 + majorStep;
GLdouble x0 = cos(a0);
GLdouble y0 = sin(a0);
GLdouble x1 = cos(a1);
GLdouble y1 = sin(a1);
glBegin(GL_TRIANGLE_STRIP);
for (int j = 0; j <= numMinor; ++j)
{
double b = j * minorStep;
GLdouble c = cos(b);
GLdouble r = minorRadius * c + majorRadius;
GLdouble z = minorRadius * sin(b);
glNormal3d(x0 * c, y0 * c, z / minorRadius);
glTexCoord2d(i / (GLdouble) numMajor, j / (GLdouble) numMinor);
glVertex3d(x0 * r, y0 * r, z);
glNormal3d(x1 * c, y1 * c, z / minorRadius);
glTexCoord2d((i + 1) / (GLdouble) numMajor, j / (GLdouble) numMinor);
glVertex3d(x1 * r, y1 * r, z);
}
glEnd();
}
}
老办法:glBegin/glEnd (Immediate Mode)
///////////////////////////////////////////////////////////////////////////////
// draw 1, immediate mode
// 54 calls = 24 glVertex*() calls + 24 glColor*() calls + 6 glNormal*() calls
///////////////////////////////////////////////////////////////////////////////
void draw1()
{
glPushMatrix();
glTranslatef(-2, 2, 0); // move to upper left corner
glBegin(GL_QUADS);
// face v0-v1-v2-v3
glNormal3f(0,0,1);
glColor3f(1,1,1);
glVertex3f(1,1,1);
glColor3f(1,1,0);
glVertex3f(-1,1,1);
glColor3f(1,0,0);
glVertex3f(-1,-1,1);
glColor3f(1,0,1);
glVertex3f(1,-1,1);
// face v0-v3-v4-v6
glNormal3f(1,0,0);
glColor3f(1,1,1);
glVertex3f(1,1,1);
glColor3f(1,0,1);
glVertex3f(1,-1,1);
glColor3f(0,0,1);
glVertex3f(1,-1,-1);
glColor3f(0,1,1);
glVertex3f(1,1,-1);
// face v0-v5-v6-v1
glNormal3f(0,1,0);
glColor3f(1,1,1);
glVertex3f(1,1,1);
glColor3f(0,1,1);
glVertex3f(1,1,-1);
glColor3f(0,1,0);
glVertex3f(-1,1,-1);
glColor3f(1,1,0);
glVertex3f(-1,1,1);
// face v1-v6-v7-v2
glNormal3f(-1,0,0);
glColor3f(1,1,0);
glVertex3f(-1,1,1);
glColor3f(0,1,0);
glVertex3f(-1,1,-1);
glColor3f(0,0,0);
glVertex3f(-1,-1,-1);
glColor3f(1,0,0);
glVertex3f(-1,-1,1);
// face v7-v4-v3-v2
glNormal3f(0,-1,0);
glColor3f(0,0,0);
glVertex3f(-1,-1,-1);
glColor3f(0,0,1);
glVertex3f(1,-1,-1);
glColor3f(1,0,1);
glVertex3f(1,-1,1);
glColor3f(1,0,0);
glVertex3f(-1,-1,1);
// face v4-v7-v6-v5
glNormal3f(0,0,-1);
glColor3f(0,0,1);
glVertex3f(1,-1,-1);
glColor3f(0,0,0);
glVertex3f(-1,-1,-1);
glColor3f(0,1,0);
glVertex3f(-1,1,-1);
glColor3f(0,1,1);
glVertex3f(1,1,-1);
glEnd();
glPopMatrix();
}
glDrawArray
明显清爽了很多啊,效率高也是必然啦。
///////////////////////////////////////////////////////////////////////////////
// draw cube at upper-right corner with glDrawArrays
///////////////////////////////////////////////////////////////////////////////
void draw2()
{
// enble and specify pointers to vertex arrays
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
glNormalPointer(GL_FLOAT, 0, normals);
glColorPointer(3, GL_FLOAT, 0, colors);
glVertexPointer(3, GL_FLOAT, 0, vertices);
glPushMatrix();
glTranslatef(2, 2, 0); // move to upper-right
glDrawArrays(GL_QUADS, 0, 24);
glPopMatrix();
glDisableClientState(GL_VERTEX_ARRAY); // disable vertex arrays
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
}
glDrawElements
///////////////////////////////////////////////////////////////////////////////
// draw cube at bottom-left corner with glDrawElements
// In this example, glDrawElements() has no advantage over glDrawArrays(),
// because the shared vertices cannot share normals, so they must be duplicated
// once per face. Look at the index array defined earlier in this file. The
// indices are marching straight from 0 to 23 without hopping.
///////////////////////////////////////////////////////////////////////////////
void draw3()
{
// enable and specify pointers to vertex arrays
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
glNormalPointer(GL_FLOAT, 0, normals);
glColorPointer(3, GL_FLOAT, 0, colors);
glVertexPointer(3, GL_FLOAT, 0, vertices);
glPushMatrix();
glTranslatef(-2, -2, 0); // move to bottom-left
glDrawElements(GL_QUADS, 24, GL_UNSIGNED_BYTE, indices);
glPopMatrix();
glDisableClientState(GL_VERTEX_ARRAY); // disable vertex arrays
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
}
glDrawRangeElements
///////////////////////////////////////////////////////////////////////////////
// draw cube at bottom-right corner with glDrawRangeElements()
// glDrawRangeElements() has two more parameters compared with glDrawElements(),
// start and end index. The values in index array must lie in between start and
// end. Note that not all vertices in range (start, end) must be referenced.
// But, if you specify a sparsely used range, it causes unnecessary process for
// many unused vertices in that range.
///////////////////////////////////////////////////////////////////////////////
void draw4()
{
// enable and specify pointers to vertex arrays
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
glNormalPointer(GL_FLOAT, 0, normals);
glColorPointer(3, GL_FLOAT, 0, colors);
glVertexPointer(3, GL_FLOAT, 0, vertices);
glPushMatrix();
glTranslatef(2, -2, 0); // move to bottom-right
// draw first half (12 elements) {0,1,2,3, 4,5,6,7, 8,9,10,11}
// tell the driver we use vertices from index 0 to index 11, which means 11-0+1 = 12 vertices
// So, the driver can prefetch an amount of 12 vertex data prior to rendering
glDrawRangeElements(GL_QUADS, 0, 11, 12, GL_UNSIGNED_BYTE, indices);
// draw last half (12 elements) {12,13,14,15, 16,17,18,19, 20,21,22,23}
// tell the driver we use vertices from index 12 to index 23, which means 23-12+1 = 12 vertices
// So, the driver can prefetch an amount of 12 vertex data prior to rendering
glDrawRangeElements(GL_QUADS, 12, 23, 12, GL_UNSIGNED_BYTE, indices + 12);
glPopMatrix();
glDisableClientState(GL_VERTEX_ARRAY); // disable vertex arrays
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
}
Reference:
http://www.songho.ca/opengl/index.html
本文的例子,就是这位仁兄写的,我这叫阉割后的转贴,很不好意思。
在我自己的实验里面,连文本和glDrawRangeElements都没有了,汗!!