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都没有了,汗!!

原文地址:https://www.cnblogs.com/piaoger/p/2183037.html