回 帖 发 新 帖 刷新版面

主题:[原创]OpenGL入门学习——第十六课

现在即将放出的是第十六课的内容。

首先还是以前课程的连接:
[url=http://www.programfan.com/club/showbbs.asp?id=184355]第一课,编写第一个OpenGL程序[/url]
[url=http://www.programfan.com/club/showbbs.asp?id=184525]第二课,绘制几何图形[/url]
[url=http://www.programfan.com/club/showbbs.asp?id=184769]第三课,绘制几何图形的一些细节问题[/url]
[url=http://www.programfan.com/club/showbbs.asp?id=185032]第四课,颜色的选择[/url]
[url=http://www.programfan.com/club/showbbs.asp?id=196017]第五课,三维的空间变换[/url]
[url=http://www.programfan.com/club/showbbs.asp?id=196231]第六课,动画的制作[/url]
[url=http://www.programfan.com/club/showbbs.asp?id=218828]第七课,使用光照来表现立体感[/url]
[url=http://www.programfan.com/club/showbbs.asp?id=219518]第八课,使用显示列表[/url]
[url=http://www.programfan.com/club/showbbs.asp?id=224877]第九课,使用混合来实现半透明效果[/url]
[url=http://www.programfan.com/club/post-227694.html]第十课,BMP文件与像素操作[/url]
[url=http://www.programfan.com/club/post-244703.html]第十一课,纹理的使用入门[/url]
[url=http://bbs.pfan.cn/post-252901.html]第十二课,OpenGL片断测试[/url]
[url=http://bbs.pfan.cn/post-275218.html]第十三课,OpenGL是一个状态机[/url]
[url=http://bbs.pfan.cn/post-275219.html]第十四课,OpenGL版本和OpenGL扩展[/url]
[url=http://bbs.pfan.cn/post-275223.html]第十五课,从“绘制一个立方体”来看OpenGL的进化过程[/url]
第十六课,在Windows系统中显示文字  ——→  [color=0000FF]本次课程的内容[/color]

内容超多的一课!不过我想精彩的程度也一定不会让大家失望。大家不妨先浏览一下课程里的图片:)。

[color=FF0000]2008-06-10 修改了附件[/color]
增加了两个文件,showline.c, showtext.c。分别为第二个和第三个示例程序的main函数相关部分。
在ctbuf.h和textarea.h最开头部分增加了一句#include <stdlib.h>
附件中一共有三个示例程序:
第一个,飘动的“曹”字旗。代码为:flag.c, GLee.c, GLee.h
第二个,带缓冲的显示文字。代码为:showline.c, ctbuf.c, ctbuf.h, GLee.c, GLee.h
第三个,显示歌词。代码为:showtext.c, ctbuf.c, ctbuf.h, textarea.c, textarea.h, GLee.c, GLee.h
其中,GLee.h和GLee.c可以[url=http://www.opengl.org/sdk/libs/GLee/GLee5_21.zip]从网上下载[/url],因此这里并没有放到附件中。在编译的时候应该将这两个文件和其它代码文件一起编译。

=====================未完,请勿跟帖=====================

回复列表 (共106个回复)

91 楼

要使用高版本的OpenGL函数,用glext.h是可以,但是比较麻烦。推荐还是glee或者glew,目前后者使用比较多,楼主可以用google搜索glew,下载其最新版本,安装。然后把代码中的glext.h替换为glew.h即可。

#pragma comment(lib,"freeglut.lib")
#pragma comment(lib,"glut32.lib")

这两句去掉,换成
#pragma comment(lib,"glew32.lib")

这样编译链接就都能通过。
如果要顺利运行,还需要在glutCreateWindow之后加上一句glewInit();
这样程序就可以显示出图形来了。

92 楼


谢谢,这是按照你说的改后的源程序:
[code=c]
/////////////////////////////////////////////////////
#define GL_GLEXT_PROTOTYPES
#include <Windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <GL/glew.h>
#include <GL/freeglut.h>
#pragma comment(lib,"glew32.lib")

#define BUFFER_OFFSET(offset) (GLvoid*)(NULL+offset)
#define XStart -0.8
#define XEnd 0.8
#define YStart -0.8
#define YEnd 0.8
#define NumXPoints 11
#define NumYPoints 11
#define NumPoints (NumXPoints * NumYPoints)
#define NumPointsPerStrip (2*NumXPoints)
#define NumStrips (NumYPoints-1)
#define RestartIndex 0xffff

void init()
{
    GLuint vbo, ebo;
    GLfloat *vertices;
    GLushort *indices;
    /* Set up vertex data */
    glGenBuffers(1, &vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, 2*NumPoints*sizeof(GLfloat), NULL, GL_STATIC_DRAW);
    vertices = (GLfloat *)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
    if (vertices == NULL) 
    {
        fprintf(stderr, "Unable to map vertex buffer\n");
        exit(EXIT_FAILURE);
    }
    else 
    {
        int i, j;
        GLfloat dx = (GLfloat)((XEnd-XStart)/(NumXPoints-1));
        GLfloat dy = (GLfloat)((YEnd-YStart)/(NumYPoints-1));
        GLfloat *tmp = vertices;
        int n = 0;
        for (j = 0; j < NumYPoints; ++j) 
        {
            GLfloat y = (GLfloat)(YStart + j*dy);
            for (i = 0; i < NumXPoints; ++i) 
            {
                GLfloat x = (GLfloat)(XStart + i*dx);
                *tmp++ = x;
                *tmp++ = y;
            }
        }
        glUnmapBuffer(GL_ARRAY_BUFFER);
        glVertexPointer(2, GL_FLOAT, 0, BUFFER_OFFSET(0));
        glEnableClientState(GL_VERTEX_ARRAY);
    }
    /* Set up index data */
    glGenBuffers(1, &ebo);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
    
    glBufferData( GL_ELEMENT_ARRAY_BUFFER, NumStrips*(NumPointsPerStrip+1)*sizeof(GLushort),
    NULL, GL_STATIC_DRAW );
    indices = (GLushort *)glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
    if (indices == NULL) 
    {
        fprintf(stderr, "Unable to map index buffer\n");
        exit(EXIT_FAILURE);
    }
    else 
    {
        int i, j;
        GLushort *index = indices;
        for (j = 0; j < NumStrips; ++j) 
        {
            GLushort bottomRow = j*NumYPoints;
            GLushort topRow = bottomRow + NumYPoints;
            for (i = 0; i < NumXPoints; ++i) 
            {
                *index++ = topRow + i;
                *index++ = bottomRow + i;
            }
            *index++ = RestartIndex;
        }
        glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
    }
    glPrimitiveRestartIndex(RestartIndex);
    glEnable(GL_PRIMITIVE_RESTART);
}

void display(void)
{
    //int i, start;
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glColor3f(1, 1, 1);
    glDrawElements(GL_TRIANGLE_STRIP, NumStrips*(NumPointsPerStrip+1), GL_UNSIGNED_SHORT, BUFFER_OFFSET(0));
    glutSwapBuffers();
}

int main(int argc, char** argv)
{
   glutInit(&argc, argv);
   glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);
   glutInitWindowSize (650, 650); 
   glutInitWindowPosition (100, 100);
   glutCreateWindow (argv[0]);
   glewInit();
   init ();
   glutDisplayFunc(display); 
   glutMainLoop();
   return 0;
}[/code]
生成的时侯出现这个错误:
primrestart.c(55): error C2036: “void *”: 未知的大小
这该是C语言的错误,我在网上搜了一下,按照网上说的方法改,也不行,错的是这一句:
glVertexPointer(2, GL_FLOAT, 0, BUFFER_OFFSET(0));
要是把BUFFER_OFFSET(0)改为NULL,程序能够运行,但画的是一个矩形,而不是书上说
的三角形串,楼主看看是哪的问题?我都绕晕了。

93 楼

我这里编译没有问题。
运行起来看似是一个矩形,但实际上它是由一系列的三角形组成的(GL_TRIANGLE_STRIP)。为了证明这一点,其实也很容易。在display函数的第一句之前加上:
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
看看运行结果发生了什么变化,是不是明显的看到是由若干三角形构成了呢?呵呵。

94 楼


非常感谢,显示结果如你所说。出现的错误可能是这个版本不支持这样的宏了。
最初我在百度上搜索,看到过三个帖子,都是转载你的这十六个课程的,搜到你的这个原帖还真不容易。
编程搜索用GOOGLE要好些,因为可以搜到一些英文的网页,对一些常见错误有很好的解释。
NEHE的教程我也看过,感觉学OPENGL远比学计算编程困难,我一直用VC++编程(不是专业的),从没这样吃力。
楼主学OPENGL该很有心得,能不能给推荐几本书,英文的也可以,我想既然学了,还是应当学会,因为工作用的着。谢谢。

95 楼

我也没怎么看书,《OpenGL编程指南》(第五版)看了几遍,然后就没了。仅仅是编程接口熟悉一点,如果遇到算法方面的问题,我也没办法了。

96 楼


非常感谢你的帮助,再次谢谢!

97 楼

保存你所有贴

98 楼

你好,上次哪个C语言问题试了几次可以通过了(92楼),把这一句:
#define BUFFER_OFFSET(offset) (GLvoid*)(NULL+offset)
改成这样程序就可以运行了:
#define BUFFER_OFFSET(offset) (GLubyte*)(NULL+offset)
至于怎么解释也搞不清楚。

请教一个程序,还是编程指南里的 teapots.c,这是源码:

[code=c]
#include <stdlib.h>
#include <GL/glut.h>

GLuint teapotList;

/*
 * Initialize depth buffer, projection matrix, light source, and lighting
 * model.  Do not specify a material property here.
 */
void init(void)
{
   GLfloat ambient[] = {0.0, 0.0, 0.0, 1.0};
   GLfloat diffuse[] = {1.0, 1.0, 1.0, 1.0};
   GLfloat position[] = {0.0, 3.0, 3.0, 0.0};

   GLfloat lmodel_ambient[] = {0.2, 0.2, 0.2, 1.0};
   GLfloat local_view[] = {0.0};

   glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
   glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
   glLightfv(GL_LIGHT0, GL_POSITION, position);
   glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
   glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, local_view);

   glFrontFace(GL_CW);
   glEnable(GL_LIGHTING);
   glEnable(GL_LIGHT0);
   glEnable(GL_AUTO_NORMAL);
   glEnable(GL_NORMALIZE);
   glEnable(GL_DEPTH_TEST); 
/*  be efficient--make teapot display list  */
   teapotList = glGenLists(1);
   glNewList (teapotList, GL_COMPILE);
   glutSolidTeapot(1.0);
   glEndList ();
}

/*
 * Move object into position.  Use 3rd through 12th 
 * parameters to specify the material property.  Draw a teapot.
 */
void renderTeapot(GLfloat x, GLfloat y,
   GLfloat ambr, GLfloat ambg, GLfloat ambb,
   GLfloat difr, GLfloat difg, GLfloat difb,
   GLfloat specr, GLfloat specg, GLfloat specb, GLfloat shine)
{
   GLfloat mat[4];

   glPushMatrix();
   glTranslatef(x, y, 0.0);
   mat[0] = ambr; mat[1] = ambg; mat[2] = ambb; mat[3] = 1.0;
   glMaterialfv(GL_FRONT, GL_AMBIENT, mat);
   mat[0] = difr; mat[1] = difg; mat[2] = difb;
   glMaterialfv(GL_FRONT, GL_DIFFUSE, mat);
   mat[0] = specr; mat[1] = specg; mat[2] = specb;
   glMaterialfv(GL_FRONT, GL_SPECULAR, mat);
   glMaterialf(GL_FRONT, GL_SHININESS, shine * 128.0);
   glCallList(teapotList);
   glPopMatrix();
}

/**
 *  First column:  emerald, jade, obsidian, pearl, ruby, turquoise
 *  2nd column:  brass, bronze, chrome, copper, gold, silver
 *  3rd column:  black, cyan, green, red, white, yellow plastic
 *  4th column:  black, cyan, green, red, white, yellow rubber
 */
void display(void)
{
   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
   renderTeapot(2.0, 17.0, 0.0215, 0.1745, 0.0215,
      0.07568, 0.61424, 0.07568, 0.633, 0.727811, 0.633, 0.6);
   renderTeapot(2.0, 14.0, 0.135, 0.2225, 0.1575,
      0.54, 0.89, 0.63, 0.316228, 0.316228, 0.316228, 0.1);
   renderTeapot(2.0, 11.0, 0.05375, 0.05, 0.06625,
      0.18275, 0.17, 0.22525, 0.332741, 0.328634, 0.346435, 0.3);
   renderTeapot(2.0, 8.0, 0.25, 0.20725, 0.20725,
      1, 0.829, 0.829, 0.296648, 0.296648, 0.296648, 0.088);
   renderTeapot(2.0, 5.0, 0.1745, 0.01175, 0.01175,
      0.61424, 0.04136, 0.04136, 0.727811, 0.626959, 0.626959, 0.6);
   renderTeapot(2.0, 2.0, 0.1, 0.18725, 0.1745,
      0.396, 0.74151, 0.69102, 0.297254, 0.30829, 0.306678, 0.1);
   renderTeapot(6.0, 17.0, 0.329412, 0.223529, 0.027451,
      0.780392, 0.568627, 0.113725, 0.992157, 0.941176, 0.807843,
      0.21794872);
   renderTeapot(6.0, 14.0, 0.2125, 0.1275, 0.054,
      0.714, 0.4284, 0.18144, 0.393548, 0.271906, 0.166721, 0.2);
   renderTeapot(6.0, 11.0, 0.25, 0.25, 0.25,
      0.4, 0.4, 0.4, 0.774597, 0.774597, 0.774597, 0.6);
   renderTeapot(6.0, 8.0, 0.19125, 0.0735, 0.0225,
      0.7038, 0.27048, 0.0828, 0.256777, 0.137622, 0.086014, 0.1);
   renderTeapot(6.0, 5.0, 0.24725, 0.1995, 0.0745,
      0.75164, 0.60648, 0.22648, 0.628281, 0.555802, 0.366065, 0.4);
   renderTeapot(6.0, 2.0, 0.19225, 0.19225, 0.19225,
      0.50754, 0.50754, 0.50754, 0.508273, 0.508273, 0.508273, 0.4);
   renderTeapot(10.0, 17.0, 0.0, 0.0, 0.0, 0.01, 0.01, 0.01,
      0.50, 0.50, 0.50, .25);
   renderTeapot(10.0, 14.0, 0.0, 0.1, 0.06, 0.0, 0.50980392, 0.50980392,
      0.50196078, 0.50196078, 0.50196078, .25);
   renderTeapot(10.0, 11.0, 0.0, 0.0, 0.0,
      0.1, 0.35, 0.1, 0.45, 0.55, 0.45, .25);
   renderTeapot(10.0, 8.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0,
      0.7, 0.6, 0.6, .25);
   renderTeapot(10.0, 5.0, 0.0, 0.0, 0.0, 0.55, 0.55, 0.55,
      0.70, 0.70, 0.70, .25);
   renderTeapot(10.0, 2.0, 0.0, 0.0, 0.0, 0.5, 0.5, 0.0,
      0.60, 0.60, 0.50, .25);
   renderTeapot(14.0, 17.0, 0.02, 0.02, 0.02, 0.01, 0.01, 0.01,
      0.4, 0.4, 0.4, .078125);
   renderTeapot(14.0, 14.0, 0.0, 0.05, 0.05, 0.4, 0.5, 0.5,
      0.04, 0.7, 0.7, .078125);
   renderTeapot(14.0, 11.0, 0.0, 0.05, 0.0, 0.4, 0.5, 0.4,
      0.04, 0.7, 0.04, .078125);
   renderTeapot(14.0, 8.0, 0.05, 0.0, 0.0, 0.5, 0.4, 0.4,
      0.7, 0.04, 0.04, .078125);
   renderTeapot(14.0, 5.0, 0.05, 0.05, 0.05, 0.5, 0.5, 0.5,
      0.7, 0.7, 0.7, .078125);
   renderTeapot(14.0, 2.0, 0.05, 0.05, 0.0, 0.5, 0.5, 0.4,
      0.7, 0.7, 0.04, .078125);
   glFlush();
}

99 楼


[code=c]
void reshape(int w, int h)
{
   glViewport(0, 0, (GLsizei) w, (GLsizei) h);
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   if (w <= h)
      glOrtho(0.0, 16.0, 0.0, 16.0*(GLfloat)h/(GLfloat)w,
              -10.0, 10.0);
   else
      glOrtho(0.0, 16.0*(GLfloat)w/(GLfloat)h, 0.0, 16.0,
              -10.0, 10.0);
   glMatrixMode(GL_MODELVIEW);
}

void keyboard(unsigned char key, int x, int y)
{
   switch (key) {
      case 27:
         exit(0);
         break;
   }
}


/*
 * Main Loop 
 */
int main(int argc, char **argv)
{
   glutInit(&argc, argv);
   glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
   glutInitWindowSize(500, 600);
   glutInitWindowPosition(50,50);
   glutCreateWindow(argv[0]);
   init();
   glutReshapeFunc(reshape);
   glutDisplayFunc(display);
   glutKeyboardFunc (keyboard);
   glutMainLoop();
   return 0;
}[/code]

这个程序编译运行都没问题,可是什么都不显示,全部是黑色,烦楼主给看看是哪的问题,谢谢。

100 楼

我运行并无问题,显示出24个不同材质的茶壶。
楼主的代码一字未改,拷贝后编译运行。环境为Windows7 Home Basic + Visual Studio 2010 + FreeGLUT。显卡是nVidia Geforce GT 335M。
你可以试试只显示一个茶壶,并把它位置坐标设置到(0, 0, 0),把光照关闭,把显示列表换为直接调用glutSolidTeaport,把reshape函数中的内容全部移动到init函数中,等等。一点一点的试,应该可以找到原因。

我来回复

您尚未登录,请登录后再回复。点此登录或注册