《OpenGL入门教程》上的代码复现

编程入门 行业动态 更新时间:2024-10-28 06:29:17

《OpenGL<a href=https://www.elefans.com/category/jswz/34/1766128.html style=入门教程》上的代码复现"/>

《OpenGL入门教程》上的代码复现

首先是Windows10 + Visual Studio 2019 搭建OpenGL环境可以查看如下链接:

萌新向!!!Windows10 + Visual Studio 2019 搭建OpenGL环境(图文教程) - 哔哩哔哩 (bilibili)

//使用PC端浏览器打开,Android端似乎被删除了

其次是《OpenGL入门教程》原文链接:_OpenGL入门教程 - 百度文库 (baidu)       

或者在我的主页的资源处下载该文件,链接如下:《OpenGL入门教程》十二讲详解与代码分析-图像处理文档类资源-CSDN文库

目录

第一讲

第一个OpenGL程序

 第二讲

例一、画一个圆 

例二、画一个五角星

例三、画出正弦函数的图形

第三讲

 1、关于点

 2、关于直线

 3.1、关于多边形

 3.2、关于镂空多边形

 第四讲

1、RGBA颜色

2、索引颜色

3、指定清除屏幕用的颜色

4、指定着色模型 

第五讲

太阳,地球和月亮 

第六讲

 2、实现连续动画

 4、计算帧速

第七讲

光照演示

第八讲

彩色四面体

第九讲

 二、二维图形混合举例

 二、实现三维混合

第十讲

抓取窗口图片保存为BMP文件

4、glDrawPixels的用法和举例 

5、glCopyPixels的用法和举例

第十一讲

5、示例程序

第十二讲

2、Alpha测试

3、模板测试


第一讲

第一个OpenGL程序

代码:

#include <Windows.h>
#include <GL/glut.h>void myDisplay(void)
{glClear(GL_COLOR_BUFFER_BIT);glRectf(-0.5f, -0.5f, 0.5f, 0.5f);glFlush();
}int main(int argc, char* argv[])
{glutInit(&argc, argv);glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);glutInitWindowPosition(100, 100);glutInitWindowSize(400, 400);glutCreateWindow("第一个OpenGL程序");glutDisplayFunc(&myDisplay);glutMainLoop();return 0;
}

结果:

 第二讲

例一、画一个圆 

 代码:

#include <Windows.h>
#include <GL/glut.h>
#include <cmath>
#include <cstdio>const int n = 20;
const GLfloat R = 0.5f;
const GLfloat Pi = 3.1415926536f;void myDisplay(void)
{int i;glClear(GL_COLOR_BUFFER_BIT);glBegin(GL_POLYGON);//将GL_POLYGON改为GL_LINE_LOOP、GL_POINTS等其它方式,观察输出的变化情况for (i = 0; i < n; ++i)glVertex2f(R * cos(2 * Pi / n * i), R * sin(2 * Pi / n * i));glEnd();glFlush();
}int main(int argc, char* argv[])
{glutInit(&argc, argv);glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);glutInitWindowPosition(100, 100);glutInitWindowSize(400, 400);glutCreateWindow("第一个OpenGL程序");glutDisplayFunc(&myDisplay);glutMainLoop();return 0;
}

 结果:

(使用GL_POLYGON)

(使用GL_LINE_LOOP)

(使用GL_POINTS) 

 例二、画一个五角星

代码:

#include <Windows.h>
#include <GL/glut.h>
#include <cmath>
#include <cstdio>const GLfloat Pi = 3.1415926536f;
void myDisplay(void)
{GLfloat a = 1 / (2 - 2 * cos(72 * Pi / 180));GLfloat bx = a * cos(18 * Pi / 180);GLfloat by = a * sin(18 * Pi / 180);GLfloat cy = -a * cos(18 * Pi / 180);GLfloatPointA[2] = { 0, a },PointB[2] = { bx, by },PointC[2] = { 0.5, cy },PointD[2] = { -0.5, cy },PointE[2] = { -bx, by };glClear(GL_COLOR_BUFFER_BIT);// 按照A->C->E->B->D->A的顺序,可以一笔将五角星画出glBegin(GL_LINE_LOOP);glVertex2fv(PointA);glVertex2fv(PointC);glVertex2fv(PointE);glVertex2fv(PointB);glVertex2fv(PointD);glEnd();glFlush();
}int main(int argc, char* argv[])
{glutInit(&argc, argv);glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);glutInitWindowPosition(100, 100);glutInitWindowSize(400, 400);glutCreateWindow("第一个OpenGL程序");glutDisplayFunc(&myDisplay);glutMainLoop();return 0;
}

结果:

例三、画出正弦函数的图形

 代码:

#include <Windows.h>
#include <GL/glut.h>
#include <cmath>
#include <cstdio>const GLfloat factor = 0.1f;
void myDisplay(void)
{GLfloat x;glClear(GL_COLOR_BUFFER_BIT);glBegin(GL_LINES);glVertex2f(-1.0f, 0.0f);glVertex2f(1.0f, 0.0f);        // 以上两个点可以画x轴glVertex2f(0.0f, -1.0f);glVertex2f(0.0f, 1.0f);        // 以上两个点可以画y轴glEnd();glBegin(GL_LINE_STRIP);for (x = -1.0f / factor; x < 1.0f / factor; x += 0.01f){glVertex2f(x * factor, sin(x) * factor);}glEnd();glFlush();
}int main(int argc, char* argv[])
{glutInit(&argc, argv);glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);glutInitWindowPosition(100, 100);glutInitWindowSize(400, 400);glutCreateWindow("第一个OpenGL程序");glutDisplayFunc(&myDisplay);glutMainLoop();return 0;
}

结果:

第三讲

 1、关于点

代码:

#include <Windows.h>
#include <GL/glut.h>
#include <cmath>
#include <cstdio>void myDisplay(void)
{glClear(GL_COLOR_BUFFER_BIT);glPointSize(5.0f);glBegin(GL_POINTS);glVertex2f(0.0f, 0.0f);glVertex2f(0.5f, 0.5f);glEnd();glFlush();
}int main(int argc, char* argv[])
{glutInit(&argc, argv);glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);glutInitWindowPosition(100, 100);glutInitWindowSize(400, 400);glutCreateWindow("第一个OpenGL程序");glutDisplayFunc(&myDisplay);glutMainLoop();return 0;
}

结果:

 2、关于直线

代码:

#include <Windows.h>
#include <GL/glut.h>
#include <cmath>
#include <cstdio>void myDisplay(void)
{glClear(GL_COLOR_BUFFER_BIT);glEnable(GL_LINE_STIPPLE);glLineStipple(2, 0x0F0F);glLineWidth(10.0f);glBegin(GL_LINES);glVertex2f(0.0f, 0.0f);glVertex2f(0.5f, 0.5f);glEnd();glFlush();
}int main(int argc, char* argv[])
{glutInit(&argc, argv);glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);glutInitWindowPosition(100, 100);glutInitWindowSize(400, 400);glutCreateWindow("第一个OpenGL程序");glutDisplayFunc(&myDisplay);glutMainLoop();return 0;
}

结果:

3.1、关于多边形

代码:

#include <Windows.h>
#include <GL/glut.h>
#include <cmath>
#include <cstdio>void myDisplay(void)
{glClear(GL_COLOR_BUFFER_BIT);glPolygonMode(GL_FRONT, GL_FILL); // 设置正面为填充模式glPolygonMode(GL_BACK, GL_LINE);  // 设置反面为线形模式glFrontFace(GL_CCW);              // 设置逆时针方向为正面glBegin(GL_POLYGON);              // 按逆时针绘制一个正方形,在左下方glVertex2f(-0.5f, -0.5f);glVertex2f(0.0f, -0.5f);glVertex2f(0.0f, 0.0f);glVertex2f(-0.5f, 0.0f);glEnd();glBegin(GL_POLYGON);              // 按顺时针绘制一个正方形,在右上方glVertex2f(0.0f, 0.0f);glVertex2f(0.0f, 0.5f);glVertex2f(0.5f, 0.5f);glVertex2f(0.5f, 0.0f);glEnd();glFlush();
}int main(int argc, char* argv[])
{glutInit(&argc, argv);glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);glutInitWindowPosition(100, 100);glutInitWindowSize(400, 400);glutCreateWindow("第一个OpenGL程序");glutDisplayFunc(&myDisplay);glutMainLoop();return 0;
}

结果:

 3.2、关于镂空多边形

代码:

#include <Windows.h>
#include <GL/glut.h>
#include <cmath>
#include <cstdio>
#include <cstdlib>void myDisplay(void)
{static GLubyte Mask[128] ={0x00, 0x00, 0x00, 0x00,   //这是最下面的一行0x00, 0x00, 0x00, 0x00,0x03, 0x80, 0x01, 0xC0,   //麻0x06, 0xC0, 0x03, 0x60,   //烦0x04, 0x60, 0x06, 0x20,   //的0x04, 0x30, 0x0C, 0x20,   //初0x04, 0x18, 0x18, 0x20,   //始0x04, 0x0C, 0x30, 0x20,   //化0x04, 0x06, 0x60, 0x20,   //,0x44, 0x03, 0xC0, 0x22,   //不0x44, 0x01, 0x80, 0x22,   //建0x44, 0x01, 0x80, 0x22,   //议0x44, 0x01, 0x80, 0x22,   //使0x44, 0x01, 0x80, 0x22,   //用0x44, 0x01, 0x80, 0x22,0x44, 0x01, 0x80, 0x22,0x66, 0x01, 0x80, 0x66,0x33, 0x01, 0x80, 0xCC,0x19, 0x81, 0x81, 0x98,0x0C, 0xC1, 0x83, 0x30,0x07, 0xE1, 0x87, 0xE0,0x03, 0x3F, 0xFC, 0xC0,0x03, 0x31, 0x8C, 0xC0,0x03, 0x3F, 0xFC, 0xC0,0x06, 0x64, 0x26, 0x60,0x0C, 0xCC, 0x33, 0x30,0x18, 0xCC, 0x33, 0x18,0x10, 0xC4, 0x23, 0x08,0x10, 0x63, 0xC6, 0x08,0x10, 0x30, 0x0C, 0x08,0x10, 0x18, 0x18, 0x08,0x10, 0x00, 0x00, 0x08   // 这是最上面的一行};glClear(GL_COLOR_BUFFER_BIT);glEnable(GL_POLYGON_STIPPLE);glPolygonStipple(Mask);glRectf(-0.5f, -0.5f, 0.0f, 0.0f);  // 在左下方绘制一个有镂空效果的正方形glDisable(GL_POLYGON_STIPPLE);glRectf(0.0f, 0.0f, 0.5f, 0.5f);    // 在右上方绘制一个无镂空效果的正方形glFlush();
}int main(int argc, char* argv[])
{glutInit(&argc, argv);glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);glutInitWindowPosition(100, 100);glutInitWindowSize(400, 400);glutCreateWindow("第一个OpenGL程序");glutDisplayFunc(&myDisplay);glutMainLoop();return 0;
}//另外一种更方便的做法
//首先,用Windows自带的画笔程序新建一副图片,取名为mask.bmp,
//注意保存时,应该选择“单色位图”。在“图象”->“属性”对话框中,设置图片的高度和宽度均为32。
//用放大镜观察图片,并编辑之。黑色对应二进制零(镂空),白色对应二进制一(不镂空),编辑完毕后保存。
//然后,就可以使用以下代码来获得这个Mask数组了。
//static GLubyte Mask[128];
//FILE * fp;
//fp  = fopen("mask.bmp", "rb");
//if (!fp )
//exit(0);
//if (fseek(fp, -(int)sizeof(Mask), SEEK_END))
//exit(0);
//if (!fread(Mask, sizeof(Mask), 1, fp))
//exit(0);
//fclose(fp);

结果:

 第四讲

1、RGBA颜色

代码:

#include <Windows.h>
#include <GL/glut.h>
#include <cmath>
#include <cstdio>
#include <cstdlib>void myDisplay(void)
{glClear(GL_COLOR_BUFFER_BIT);glColor3f(0.0f, 1.0f, 1.0f);glRectf(-0.5f, -0.5f, 0.5f, 0.5f);glFlush();
}int main(int argc, char* argv[])
{glutInit(&argc, argv);glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);glutInitWindowPosition(100, 100);glutInitWindowSize(400, 400);glutCreateWindow("第一个OpenGL程序");glutDisplayFunc(&myDisplay);glutMainLoop();return 0;
}

结果:

2、索引颜色

        因为博主的VS里面没有aux这个包,所以颜色索引就跳过了。

3、指定清除屏幕用的颜色

代码:

#include <Windows.h>
#include <GL/glut.h>
#include <cmath>
#include <cstdio>
#include <cstdlib>void myDisplay(void)
{glClearColor(1.0f, 0.0f, 0.0f, 0.0f);glClear(GL_COLOR_BUFFER_BIT);glFlush();
}int main(int argc, char* argv[])
{glutInit(&argc, argv);glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);glutInitWindowPosition(100, 100);glutInitWindowSize(400, 400);glutCreateWindow("第一个OpenGL程序");glutDisplayFunc(&myDisplay);glutMainLoop();return 0;
}

结果:

4、指定着色模型 

代码:

#include <Windows.h>
#include <GL/glut.h>
#include <cmath>
#include <cstdio>
#include <cstdlib>const GLdouble Pi = 3.1415926536;
void myDisplay(void)
{int i;// glShadeModel(GL_FLAT);glClear(GL_COLOR_BUFFER_BIT);glBegin(GL_TRIANGLE_FAN);glColor3f(1.0f, 1.0f, 1.0f);glVertex2f(0.0f, 0.0f);for (i = 0; i <= 8; ++i){glColor3f(i & 0x04, i & 0x02, i & 0x01);glVertex2f(cos(i * Pi / 4), sin(i * Pi / 4));}glEnd();glFlush();
}int main(int argc, char* argv[])
{glutInit(&argc, argv);glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);glutInitWindowPosition(100, 100);glutInitWindowSize(400, 400);glutCreateWindow("第一个OpenGL程序");glutDisplayFunc(&myDisplay);glutMainLoop();return 0;
}

结果:

第五讲

太阳,地球和月亮 

代码:

#include <Windows.h>
#include <GL/glut.h>
#include <cmath>
#include <cstdio>
#include <cstdlib>static int day = 200; // day的变化:从0到359
void myDisplay(void)
{glDepthFunc(GL_LEQUAL);//设置深度<=通过,与物体之间的前后有关//原《OpenGL入门教程》遗落了glDepthFunc(GL_LEQUAL)这个函数出现了问题,需要加上glEnable(GL_DEPTH_TEST);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glMatrixMode(GL_PROJECTION);glLoadIdentity();gluPerspective(75, 1, 1, 400000000);glMatrixMode(GL_MODELVIEW);glLoadIdentity();gluLookAt(0, -200000000, 200000000, 0, 0, 0, 0, 0, 1);// 绘制红色的“太阳”glColor3f(1.0f, 0.0f, 0.0f);glutSolidSphere(69600000, 20, 20);// 绘制蓝色的“地球”glColor3f(0.0f, 0.0f, 1.0f);glRotatef(day / 360.0 * 360.0, 0.0f, 0.0f, -1.0f);glTranslatef(150000000, 0.0f, 0.0f);glutSolidSphere(15945000, 20, 20);// 绘制黄色的“月亮”glColor3f(1.0f, 1.0f, 0.0f);glRotatef(day / 30.0 * 360.0 - day / 360.0 * 360.0, 0.0f, 0.0f, -1.0f);glTranslatef(38000000, 0.0f, 0.0f);glutSolidSphere(4345000, 20, 20);glFlush();
}int main(int argc, char* argv[])
{glutInit(&argc, argv);glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);glutInitWindowPosition(100, 100);glutInitWindowSize(400, 400);glutCreateWindow("第一个OpenGL程序");glutDisplayFunc(&myDisplay);glutMainLoop();return 0;
}

 结果:

第六讲

 2、实现连续动画

代码:

#include <Windows.h>
#include <GL/glut.h>
#include <cmath>
#include <cstdio>
#include <cstdlib>static int day = 200; // day的变化:从0到359
void myDisplay(void)
{glDepthFunc(GL_LEQUAL);//设置深度<=通过,与物体之间的前后有关glEnable(GL_DEPTH_TEST);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glMatrixMode(GL_PROJECTION);glLoadIdentity();gluPerspective(75, 1, 1, 400000000);glMatrixMode(GL_MODELVIEW);glLoadIdentity();gluLookAt(0, -200000000, 200000000, 0, 0, 0, 0, 0, 1);// 绘制红色的“太阳”glColor3f(1.0f, 0.0f, 0.0f);glutSolidSphere(69600000, 20, 20);// 绘制蓝色的“地球”glColor3f(0.0f, 0.0f, 1.0f);glRotatef(day / 360.0 * 360.0, 0.0f, 0.0f, -1.0f);glTranslatef(150000000, 0.0f, 0.0f);glutSolidSphere(15945000, 20, 20);// 绘制黄色的“月亮”glColor3f(1.0f, 1.0f, 0.0f);glRotatef(day / 30.0 * 360.0 - day / 360.0 * 360.0, 0.0f, 0.0f, -1.0f);glTranslatef(38000000, 0.0f, 0.0f);glutSolidSphere(4345000, 20, 20);glFlush();glutSwapBuffers();
}void myIdle(void)
{/* 新的函数,在空闲时调用,作用是把日期往后移动一天并重新绘制,达到动画效果 */++day;if (day >= 360)day = 0;Sleep(30);myDisplay();
}int main(int argc, char* argv[])
{glutInit(&argc, argv);glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); // 修改了参数为GLUT_DOUBLEglutInitWindowPosition(100, 100);glutInitWindowSize(400, 400);glutCreateWindow("太阳,地球和月亮");   // 改了窗口标题glutDisplayFunc(&myDisplay);glutIdleFunc(&myIdle);               // 新加入了这句glutMainLoop();return 0;
}

 结果:

 4、计算帧速

代码:

#include <Windows.h>
#include <GL/glut.h>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <time.h>// 太阳、地球和月亮
// 假设每个月都是12天
// 一年12个月,共是360天
static int day = 200; // day的变化:从0到359double CalFrequency()
{static int count;static double save;static clock_t last, current;double timegap;++count;if (count <= 50)return save;count = 0;last = current;current = clock();timegap = (current - last) / (double)CLK_TCK;save = 50.0 / timegap;return save;
}void myDisplay(void)
{double FPS = CalFrequency();printf("FPS = %f\n", FPS);glDepthFunc(GL_LEQUAL);//设置深度<=通过,与物体之间的前后有关glEnable(GL_DEPTH_TEST);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glMatrixMode(GL_PROJECTION);glLoadIdentity();gluPerspective(75, 1, 1, 400000000);glMatrixMode(GL_MODELVIEW);glLoadIdentity();gluLookAt(0, -200000000, 200000000, 0, 0, 0, 0, 0, 1);// 绘制红色的“太阳”glColor3f(1.0f, 0.0f, 0.0f);glutSolidSphere(69600000, 20, 20);// 绘制蓝色的“地球”glColor3f(0.0f, 0.0f, 1.0f);glRotatef(day / 360.0 * 360.0, 0.0f, 0.0f, -1.0f);glTranslatef(150000000, 0.0f, 0.0f);glutSolidSphere(15945000, 20, 20);// 绘制黄色的“月亮”glColor3f(1.0f, 1.0f, 0.0f);glRotatef(day / 30.0 * 360.0 - day / 360.0 * 360.0, 0.0f, 0.0f, -1.0f);glTranslatef(38000000, 0.0f, 0.0f);glutSolidSphere(4345000, 20, 20);glFlush();glutSwapBuffers();
}void myIdle(void)
{++day;if (day >= 360)day = 0;Sleep(30);myDisplay();
}int main(int argc, char* argv[])
{glutInit(&argc, argv);glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);glutInitWindowPosition(100, 100);glutInitWindowSize(400, 400);glutCreateWindow("太阳,地球和月亮");glutDisplayFunc(&myDisplay);glutIdleFunc(&myIdle);glutMainLoop();return 0;
}

结果:

第七讲

光照演示

代码:

#include <Windows.h>
#include <GL/glut.h>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <time.h>#define WIDTH 400
#define HEIGHT 400static GLfloat angle = 0.0f;void myDisplay(void)
{glClearColor(1.0f,1.0f,1.0f,1.0f);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// 创建透视效果视图glMatrixMode(GL_PROJECTION);glLoadIdentity();gluPerspective(90.0f, 1.0f, 1.0f, 20.0f);glMatrixMode(GL_MODELVIEW);glLoadIdentity();gluLookAt(0.0, 5.0, -10.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);// 定义太阳光源,它是一种白色的光源{GLfloat sun_light_position[] = { 0.0f, 0.0f, 0.0f, 1.0f };GLfloat sun_light_ambient[] = { 0.0f, 0.0f, 0.0f, 1.0f };GLfloat sun_light_diffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f };GLfloat sun_light_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f };glLightfv(GL_LIGHT0, GL_POSITION, sun_light_position);glLightfv(GL_LIGHT0, GL_AMBIENT, sun_light_ambient);glLightfv(GL_LIGHT0, GL_DIFFUSE, sun_light_diffuse);glLightfv(GL_LIGHT0, GL_SPECULAR, sun_light_specular);glEnable(GL_LIGHT0);glEnable(GL_LIGHTING);glEnable(GL_DEPTH_TEST);}// 定义太阳的材质并绘制太阳{GLfloat sun_mat_ambient[] = { 0.0f, 0.0f, 0.0f, 1.0f };GLfloat sun_mat_diffuse[] = { 0.0f, 0.0f, 0.0f, 1.0f };GLfloat sun_mat_specular[] = { 0.0f, 0.0f, 0.0f, 1.0f };GLfloat sun_mat_emission[] = { 0.5f, 0.0f, 0.0f, 1.0f };GLfloat sun_mat_shininess = 0.0f;glMaterialfv(GL_FRONT, GL_AMBIENT, sun_mat_ambient);glMaterialfv(GL_FRONT, GL_DIFFUSE, sun_mat_diffuse);glMaterialfv(GL_FRONT, GL_SPECULAR, sun_mat_specular);glMaterialfv(GL_FRONT, GL_EMISSION, sun_mat_emission);glMaterialf(GL_FRONT, GL_SHININESS, sun_mat_shininess);glutSolidSphere(2.0, 40, 32);}// 定义地球的材质并绘制地球{GLfloat earth_mat_ambient[] = { 0.0f, 0.0f, 0.5f, 1.0f };GLfloat earth_mat_diffuse[] = { 0.0f, 0.0f, 0.5f, 1.0f };GLfloat earth_mat_specular[] = { 0.0f, 0.0f, 1.0f, 1.0f };GLfloat earth_mat_emission[] = { 0.0f, 0.0f, 0.0f, 1.0f };GLfloat earth_mat_shininess = 30.0f;glMaterialfv(GL_FRONT, GL_AMBIENT, earth_mat_ambient);glMaterialfv(GL_FRONT, GL_DIFFUSE, earth_mat_diffuse);glMaterialfv(GL_FRONT, GL_SPECULAR, earth_mat_specular);glMaterialfv(GL_FRONT, GL_EMISSION, earth_mat_emission);glMaterialf(GL_FRONT, GL_SHININESS, earth_mat_shininess);glRotatef(angle, 0.0f, -1.0f, 0.0f);glTranslatef(5.0f, 0.0f, 0.0f);glutSolidSphere(2.0, 40, 32);}glutSwapBuffers();
}
void myIdle(void)
{angle += 1.0f;if (angle >= 360.0f)angle = 0.0f;Sleep(30);myDisplay();
}int main(int argc, char* argv[])
{glutInit(&argc, argv);glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);glutInitWindowPosition(200, 200);glutInitWindowSize(WIDTH, HEIGHT);glutCreateWindow("OpenGL光照演示");glutDisplayFunc(&myDisplay);glutIdleFunc(&myIdle);glutMainLoop();return 0;
}

 结果:

第八讲

彩色四面体

 代码:

#include <Windows.h>
#include <GL/glut.h>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <time.h>#define WIDTH 400
#define HEIGHT 400#define ColoredVertex(c, v) do{ glColor3fv(c); glVertex3fv(v); }while(0)GLfloat angle = 0.0f;void myDisplay(void)
{static int list = 0;if (list == 0){// 如果显示列表不存在,则创建/* GLfloatPointA[] = {-0.5, -5*sqrt(5)/48,  sqrt(3)/6},PointB[] = { 0.5, -5*sqrt(5)/48,  sqrt(3)/6},PointC[] = {   0, -5*sqrt(5)/48, -sqrt(3)/3},PointD[] = {   0, 11*sqrt(6)/48,          0}; */// 2007年4月27日修改GLfloatPointA[] = { 0.5f, -sqrt(6.0f) / 12, -sqrt(3.0f) / 6 },PointB[] = { -0.5f, -sqrt(6.0f) / 12, -sqrt(3.0f) / 6 },PointC[] = { 0.0f, -sqrt(6.0f) / 12,  sqrt(3.0f) / 3 },PointD[] = { 0.0f,   sqrt(6.0f) / 4,             0 };GLfloatColorR[] = { 1, 0, 0 },ColorG[] = { 0, 1, 0 },ColorB[] = { 0, 0, 1 },ColorY[] = { 1, 1, 0 };list = glGenLists(1);glNewList(list, GL_COMPILE);glBegin(GL_TRIANGLES);// 平面ABCColoredVertex(ColorR, PointA);ColoredVertex(ColorG, PointB);ColoredVertex(ColorB, PointC);// 平面ACDColoredVertex(ColorR, PointA);ColoredVertex(ColorB, PointC);ColoredVertex(ColorY, PointD);// 平面CBDColoredVertex(ColorB, PointC);ColoredVertex(ColorG, PointB);ColoredVertex(ColorY, PointD);// 平面BADColoredVertex(ColorG, PointB);ColoredVertex(ColorR, PointA);ColoredVertex(ColorY, PointD);glEnd();glEndList();glEnable(GL_DEPTH_TEST);}// 已经创建了显示列表,在每次绘制正四面体时将调用它glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glPushMatrix();glRotatef(angle, 1, 0.5, 0);glCallList(list);glPopMatrix();glutSwapBuffers();
}void myIdle(void)
{++angle;if (angle >= 360.0f)angle = 0.0f;Sleep(30);myDisplay();
}int main(int argc, char* argv[])
{glutInit(&argc, argv);glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);glutInitWindowPosition(200, 200);glutInitWindowSize(WIDTH, HEIGHT);glutCreateWindow("OpenGL 窗口");glutDisplayFunc(&myDisplay);glutIdleFunc(&myIdle);glutMainLoop();return 0;
}

结果:

第九讲

二、二维图形混合举例

代码:

#include <Windows.h>
#include <GL/glut.h>
#include <cmath>
#include <cstdio>
#include <cstdlib>#define WIDTH 400
#define HEIGHT 400void myDisplay(void)
{glClear(GL_COLOR_BUFFER_BIT);glEnable(GL_BLEND);glBlendFunc(GL_ONE, GL_ZERO);//尝试把glBlendFunc的参数修改为glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);以及glBlendFunc(GL_ONE, GL_ONE);glColor4f(1, 0, 0, 0.5);glRectf(-1, -1, 0.5, 0.5);glColor4f(0, 1, 0, 0.5);glRectf(-0.5, -0.5, 1, 1);glutSwapBuffers();
}int main(int argc, char* argv[])
{glutInit(&argc, argv);glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);glutInitWindowPosition(200, 200);glutInitWindowSize(WIDTH, HEIGHT);glutCreateWindow("OpenGL 窗口");glutDisplayFunc(&myDisplay);glutMainLoop();return 0;
}

结果:

(使用glBlendFunc(GL_ONE, GL_ZERO);)

(使用glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);) 

 (使用glBlendFunc(GL_ONE, GL_ONE);)

 二、实现三维混合

代码:

#include <Windows.h>
#include <GL/glut.h>
#include <cmath>
#include <cstdio>
#include <cstdlib>#define WIDTH 400
#define HEIGHT 400void setLight(void)
{static const GLfloat light_position[] = { 1.0f, 1.0f, -1.0f, 1.0f };static const GLfloat light_ambient[] = { 0.2f, 0.2f, 0.2f, 1.0f };static const GLfloat light_diffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f };static const GLfloat light_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f };glLightfv(GL_LIGHT0, GL_POSITION, light_position);glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);glEnable(GL_LIGHT0);glEnable(GL_LIGHTING);glEnable(GL_DEPTH_TEST);
}void setMatirial(const GLfloat mat_diffuse[4], GLfloat mat_shininess)
{static const GLfloat mat_specular[] = { 0.0f, 0.0f, 0.0f, 1.0f };static const GLfloat mat_emission[] = { 0.0f, 0.0f, 0.0f, 1.0f };glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, mat_diffuse);glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);glMaterialfv(GL_FRONT, GL_EMISSION, mat_emission);glMaterialf(GL_FRONT, GL_SHININESS, mat_shininess);
}void myDisplay(void)
{// 定义一些材质颜色const static GLfloat red_color[] = { 1.0f, 0.0f, 0.0f, 1.0f };const static GLfloat green_color[] = { 0.0f, 1.0f, 0.0f, 0.3333f };const static GLfloat blue_color[] = { 0.0f, 0.0f, 1.0f, 0.5f };// 清除屏幕glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// 启动混合并设置混合因子glEnable(GL_BLEND);glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);// 设置光源setLight();// 以(0, 0, 0.5)为中心,绘制一个半径为.3的不透明红色球体(离观察者最远)setMatirial(red_color, 30.0);glPushMatrix();glTranslatef(0.0f, 0.0f, 0.5f);glutSolidSphere(0.3, 30, 30);glPopMatrix();// 下面将绘制半透明物体了,因此将深度缓冲设置为只读glDepthMask(GL_FALSE);// 以(0.2, 0, -0.5)为中心,绘制一个半径为.2的半透明蓝色球体(离观察者最近)setMatirial(blue_color, 30.0);glPushMatrix();glTranslatef(0.2f, 0.0f, -0.5f);glutSolidSphere(0.2, 30, 30);//第一个参数表示球体的半径,后两个参数代表了“面”的数目,简单点说就是球体的精确程度,数值越大越精确,当然代价就是速度越缓慢glPopMatrix();// 以(0.1, 0, 0)为中心,绘制一个半径为.15的半透明绿色球体(在前两个球体之间)setMatirial(green_color, 30.0);glPushMatrix();glTranslatef(0.1, 0, 0);glutSolidSphere(0.15, 30, 30);glPopMatrix();// 完成半透明物体的绘制,将深度缓冲区恢复为可读可写的形式glDepthMask(GL_TRUE);glutSwapBuffers();
}int main(int argc, char* argv[])
{glutInit(&argc, argv);glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);glutInitWindowPosition(200, 200);glutInitWindowSize(WIDTH, HEIGHT);glutCreateWindow("OpenGL 窗口");glutDisplayFunc(&myDisplay);glutMainLoop();return 0;
}

结果:

第十讲

抓取窗口图片保存为BMP文件

代码:

 (以上一讲代码为例题试验)

#include <Windows.h>
#include <GL/glut.h>
#include <cmath>
#include <cstdio>
#include <cstdlib>#define WIDTH 400
#define HEIGHT 400//以下是抓取保存为BMP文件的开始代码
#define WindowWidth  400
#define WindowHeight 400/* 函数grab* 抓取窗口中的像素* 假设窗口宽度为WindowWidth,高度为WindowHeight*/
#define BMP_Header_Length 54
void grab(void)
{glReadBuffer(GL_FRONT);FILE* pDummyFile;FILE* pWritingFile;GLubyte* pPixelData;GLubyte  BMP_Header[BMP_Header_Length];GLint    i, j;GLint    PixelDataLength;// 计算像素数据的实际长度i = WindowWidth * 3;   // 得到每一行的像素数据长度while (i % 4 != 0)      // 补充数据,直到i是的倍数++i;               // 本来还有更快的算法,// 但这里仅追求直观,对速度没有太高要求PixelDataLength = i * WindowHeight;// 分配内存和打开文件pPixelData = (GLubyte*)malloc(PixelDataLength);if (pPixelData == 0)exit(0);//fopen函数似乎用不了,在这里用fopen_s函数,需要先创建du.bmp文件1*1的黑色bmp文件,文件的路径要写全fopen_s(&pDummyFile,"D:\\Visual Studio\\MyOpenGL\\du.bmp", "rb");if (pDummyFile == 0)exit(0);//fopen函数似乎用不了,在这里用fopen_s函数,需要先创建grab.bmp文件空的bmp文件,文件的路径要写全fopen_s(&pWritingFile,"D:\\Visual Studio\\MyOpenGL\\grab.bmp", "wb");if (pWritingFile == 0)exit(0);// 读取像素glPixelStorei(GL_UNPACK_ALIGNMENT, 4);glReadPixels(0, 0, WindowWidth, WindowHeight,GL_BGR_EXT, GL_UNSIGNED_BYTE, pPixelData);// 把dummy.bmp的文件头复制为新文件的文件头fread(BMP_Header, sizeof(BMP_Header), 1, pDummyFile);fwrite(BMP_Header, sizeof(BMP_Header), 1, pWritingFile);fseek(pWritingFile, 0x0012, SEEK_SET);i = WindowWidth;j = WindowHeight;fwrite(&i, sizeof(i), 1, pWritingFile);fwrite(&j, sizeof(j), 1, pWritingFile);// 写入像素数据fseek(pWritingFile, 0, SEEK_END);fwrite(pPixelData, PixelDataLength, 1, pWritingFile);// 释放内存和关闭文件fclose(pDummyFile);fclose(pWritingFile);free(pPixelData);
}
//到此结束void setLight(void)
{static const GLfloat light_position[] = { 1.0f, 1.0f, -1.0f, 1.0f };static const GLfloat light_ambient[] = { 0.2f, 0.2f, 0.2f, 1.0f };static const GLfloat light_diffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f };static const GLfloat light_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f };glLightfv(GL_LIGHT0, GL_POSITION, light_position);glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);glEnable(GL_LIGHT0);glEnable(GL_LIGHTING);glEnable(GL_DEPTH_TEST);
}void setMatirial(const GLfloat mat_diffuse[4], GLfloat mat_shininess)
{static const GLfloat mat_specular[] = { 0.0f, 0.0f, 0.0f, 1.0f };static const GLfloat mat_emission[] = { 0.0f, 0.0f, 0.0f, 1.0f };glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, mat_diffuse);glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);glMaterialfv(GL_FRONT, GL_EMISSION, mat_emission);glMaterialf(GL_FRONT, GL_SHININESS, mat_shininess);
}void myDisplay(void)
{// 定义一些材质颜色const static GLfloat red_color[] = { 1.0f, 0.0f, 0.0f, 1.0f };const static GLfloat green_color[] = { 0.0f, 1.0f, 0.0f, 0.3333f };const static GLfloat blue_color[] = { 0.0f, 0.0f, 1.0f, 0.5f };// 清除屏幕glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// 启动混合并设置混合因子glEnable(GL_BLEND);glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);// 设置光源setLight();// 以(0, 0, 0.5)为中心,绘制一个半径为.3的不透明红色球体(离观察者最远)setMatirial(red_color, 30.0);glPushMatrix();glTranslatef(0.0f, 0.0f, 0.5f);glutSolidSphere(0.3, 30, 30);glPopMatrix();// 下面将绘制半透明物体了,因此将深度缓冲设置为只读glDepthMask(GL_FALSE);// 以(0.2, 0, -0.5)为中心,绘制一个半径为.2的半透明蓝色球体(离观察者最近)setMatirial(blue_color, 30.0);glPushMatrix();glTranslatef(0.2f, 0.0f, -0.5f);glutSolidSphere(0.2, 30, 30);//第一个参数表示球体的半径,后两个参数代表了“面”的数目,简单点说就是球体的精确程度,数值越大越精确,当然代价就是速度越缓慢glPopMatrix();// 以(0.1, 0, 0)为中心,绘制一个半径为.15的半透明绿色球体(在前两个球体之间)setMatirial(green_color, 30.0);glPushMatrix();glTranslatef(0.1, 0, 0);glutSolidSphere(0.15, 30, 30);glPopMatrix();// 完成半透明物体的绘制,将深度缓冲区恢复为可读可写的形式glDepthMask(GL_TRUE);glutSwapBuffers();grab();
}int main(int argc, char* argv[])
{glutInit(&argc, argv);glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);glutInitWindowPosition(200, 200);glutInitWindowSize(WIDTH, HEIGHT);glutCreateWindow("OpenGL 窗口");glutDisplayFunc(&myDisplay);glutMainLoop();return 0;
}

结果:

(此图为抓取的图片)

4、glDrawPixels的用法和举例 

 代码:

#include <Windows.h>
#include <GL/glut.h>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#define FileName "D:\\Visual Studio\\MyOpenGL\\grab.bmp"static GLint    ImageWidth;
static GLint    ImageHeight;
static GLint    PixelLength;
static GLubyte* PixelData;void display(void)
{// 清除屏幕并不必要// 每次绘制时,画面都覆盖整个屏幕// 因此无论是否清除屏幕,结果都一样// glClear(GL_COLOR_BUFFER_BIT);// 绘制像素glDrawPixels(ImageWidth, ImageHeight,GL_BGR_EXT, GL_UNSIGNED_BYTE, PixelData);// 完成绘制glutSwapBuffers();
}int main(int argc, char* argv[])
{// 打开文件FILE* pFile;//这里fopen函数用不了,因此使用fopen_s,打开的文件为D:\\Visual Studio\\MyOpenGL\\grab.bmpfopen_s(&pFile,"D:\\Visual Studio\\MyOpenGL\\grab.bmp", "rb");if (pFile == 0)exit(0);// 读取图象的大小信息fseek(pFile, 0x0012, SEEK_SET);fread(&ImageWidth, sizeof(ImageWidth), 1, pFile);fread(&ImageHeight, sizeof(ImageHeight), 1, pFile);// 计算像素数据长度PixelLength = ImageWidth * 3;while (PixelLength % 4 != 0)++PixelLength;PixelLength *= ImageHeight;// 读取像素数据PixelData = (GLubyte*)malloc(PixelLength);if (PixelData == 0)exit(0);fseek(pFile, 54, SEEK_SET);fread(PixelData, PixelLength, 1, pFile);// 关闭文件fclose(pFile);// 初始化GLUT并运行glutInit(&argc, argv);glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);glutInitWindowPosition(100, 100);glutInitWindowSize(ImageWidth, ImageHeight);glutCreateWindow(FileName);glutDisplayFunc(&display);glutMainLoop();// 释放内存// 实际上,glutMainLoop函数永远不会返回,这里也永远不会到达// 这里写释放内存只是出于一种个人习惯// 不用担心内存无法释放。在程序结束时操作系统会自动回收所有内存free(PixelData);return 0;
}

结果:

5、glCopyPixels的用法和举例

代码:

#include <Windows.h>
#include <GL/glut.h>
#include <cmath>
#include <cstdio>
#include <cstdlib>#define WIDTH 400
#define HEIGHT 400//以下是抓取保存为BMP文件的开始代码
#define WindowWidth  400
#define WindowHeight 400/* 函数grab* 抓取窗口中的像素* 假设窗口宽度为WindowWidth,高度为WindowHeight*/
#define BMP_Header_Length 54void grab(void)
{glReadBuffer(GL_FRONT);FILE* pDummyFile;FILE* pWritingFile;GLubyte* pPixelData;GLubyte  BMP_Header[BMP_Header_Length];GLint    i, j;GLint    PixelDataLength;// 计算像素数据的实际长度i = WindowWidth * 3;   // 得到每一行的像素数据长度while (i % 4 != 0)      // 补充数据,直到i是的倍数++i;               // 本来还有更快的算法,// 但这里仅追求直观,对速度没有太高要求PixelDataLength = i * WindowHeight;// 分配内存和打开文件pPixelData = (GLubyte*)malloc(PixelDataLength);if (pPixelData == 0)exit(0);fopen_s(&pDummyFile, "D:\\Visual Studio\\MyOpenGL\\du.bmp", "rb");if (pDummyFile == 0)exit(0);fopen_s(&pWritingFile, "D:\\Visual Studio\\MyOpenGL\\grab.bmp", "wb");if (pWritingFile == 0)exit(0);// 读取像素glPixelStorei(GL_UNPACK_ALIGNMENT, 4);glReadPixels(0, 0, WindowWidth, WindowHeight,GL_BGR_EXT, GL_UNSIGNED_BYTE, pPixelData);// 把dummy.bmp的文件头复制为新文件的文件头fread(BMP_Header, sizeof(BMP_Header), 1, pDummyFile);fwrite(BMP_Header, sizeof(BMP_Header), 1, pWritingFile);fseek(pWritingFile, 0x0012, SEEK_SET);i = WindowWidth;j = WindowHeight;fwrite(&i, sizeof(i), 1, pWritingFile);fwrite(&j, sizeof(j), 1, pWritingFile);// 写入像素数据fseek(pWritingFile, 0, SEEK_END);fwrite(pPixelData, PixelDataLength, 1, pWritingFile);// 释放内存和关闭文件fclose(pDummyFile);fclose(pWritingFile);free(pPixelData);
}
//到此结束void display(void)
{// 清除屏幕glClear(GL_COLOR_BUFFER_BIT);// 绘制glBegin(GL_TRIANGLES);glColor3f(1.0f, 0.0f, 0.0f);    glVertex2f(0.0f, 0.0f);glColor3f(0.0f, 1.0f, 0.0f);    glVertex2f(1.0f, 0.0f);glColor3f(0.0f, 0.0f, 1.0f);    glVertex2f(0.5f, 1.0f);glEnd();glPixelZoom(-0.5f, -0.5f);glRasterPos2i(1, 1);glCopyPixels(WindowWidth / 2, WindowHeight / 2,WindowWidth / 2, WindowHeight / 2, GL_COLOR);// 完成绘制,并抓取图象保存为BMP文件glutSwapBuffers();grab();
}int main(int argc, char* argv[])
{glutInit(&argc, argv);glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);glutInitWindowPosition(200, 200);glutInitWindowSize(WIDTH, HEIGHT);glutCreateWindow("OpenGL 窗口");glutDisplayFunc(&display);glutMainLoop();return 0;
}

 结果:

(窗口)

(生成的grab.bmp文件)

第十一讲

5、示例程序

代码:

#include <Windows.h>
#include <GL/glut.h>
#include <cmath>
#include <cstdio>
#include <cstdlib>#define WindowTitle  "OpenGL纹理测试"//在这里必须把读入图片的长和高的像素设置好
static GLint ImageWidth=601;
static GLint ImageHeight=411;//以下是抓取保存为BMP文件的开始代码
#define WindowWidth  400
#define WindowHeight 400/* 函数grab* 抓取窗口中的像素* 假设窗口宽度为WindowWidth,高度为WindowHeight*/
#define BMP_Header_Length 54void grab(void)
{glReadBuffer(GL_FRONT);FILE* pDummyFile;FILE* pWritingFile;GLubyte* pPixelData;GLubyte  BMP_Header[BMP_Header_Length];GLint    i, j;GLint    PixelDataLength;// 计算像素数据的实际长度i = WindowWidth * 3;   // 得到每一行的像素数据长度while (i % 4 != 0)      // 补充数据,直到i是的倍数++i;               // 本来还有更快的算法,// 但这里仅追求直观,对速度没有太高要求PixelDataLength = i * WindowHeight;// 分配内存和打开文件pPixelData = (GLubyte*)malloc(PixelDataLength);if (pPixelData == 0)exit(0);fopen_s(&pDummyFile, "D:\\Visual Studio\\MyOpenGL\\du.bmp", "rb");if (pDummyFile == 0)exit(0);fopen_s(&pWritingFile, "D:\\Visual Studio\\MyOpenGL\\grab.bmp", "wb");if (pWritingFile == 0)exit(0);// 读取像素glPixelStorei(GL_UNPACK_ALIGNMENT, 4);glReadPixels(0, 0, WindowWidth, WindowHeight,GL_BGR_EXT, GL_UNSIGNED_BYTE, pPixelData);// 把dummy.bmp的文件头复制为新文件的文件头fread(BMP_Header, sizeof(BMP_Header), 1, pDummyFile);fwrite(BMP_Header, sizeof(BMP_Header), 1, pWritingFile);fseek(pWritingFile, 0x0012, SEEK_SET);i = WindowWidth;j = WindowHeight;fwrite(&i, sizeof(i), 1, pWritingFile);fwrite(&j, sizeof(j), 1, pWritingFile);// 写入像素数据fseek(pWritingFile, 0, SEEK_END);fwrite(pPixelData, PixelDataLength, 1, pWritingFile);// 释放内存和关闭文件fclose(pDummyFile);fclose(pWritingFile);free(pPixelData);
}
//到此结束/* 函数power_of_two* 检查一个整数是否为2的整数次方,如果是,返回1,否则返回0* 实际上只要查看其二进制位中有多少个,如果正好有1个,返回1,否则返回0* 在“查看其二进制位中有多少个”时使用了一个小技巧* 使用n &= (n-1)可以使得n中的减少一个(具体原理大家可以自己思考)*/
int power_of_two(int n)
{if (n <= 0)return 0;return (n & (n - 1)) == 0;
}/* 函数load_texture* 读取一个BMP文件作为纹理* 如果失败,返回0,如果成功,返回纹理编号*/
GLuint load_texture(const char* file_name)
{//在这里必须把last_texture_ID设置为GLint因为下面glGetIntegerv(,);第二个参数的必须是GLint*类型GLint width, height, total_bytes,last_texture_ID;GLubyte* pixels = 0;GLuint texture_ID = 0;// 打开文件,如果失败,返回FILE* pFile;//fopen用不了必须用fopen_sfopen_s(&pFile, file_name, "rb");if (pFile == 0) {return 0;}// 读取文件中图象的宽度和高度// 这里读取的文件长宽必须与输入文件的一致fseek(pFile, 0x0012, SEEK_SET);fread(&width, sizeof(ImageWidth), 1, pFile);fread(&height, sizeof(ImageHeight), 1, pFile);fseek(pFile, BMP_Header_Length, SEEK_SET);// 计算每行像素所占字节数,并根据此数据计算总像素字节数{GLint line_bytes = width * 3;while (line_bytes % 4 != 0)++line_bytes;total_bytes = line_bytes * height;}// 根据总像素字节数分配内存pixels = (GLubyte*)malloc(total_bytes);if (pixels == 0){fclose(pFile);return 0;}// 读取像素数据if (fread(pixels, total_bytes, 1, pFile) <= 0){free(pixels);fclose(pFile);return 0;}// 在旧版本的OpenGL中// 如果图象的宽度和高度不是的整数次方,则需要进行缩放// 这里并没有检查OpenGL版本,出于对版本兼容性的考虑,按旧版本处理// 另外,无论是旧版本还是新版本,// 当图象的宽度和高度超过当前OpenGL实现所支持的最大值时,也要进行缩放{GLint max;glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max);if (!power_of_two(width)|| !power_of_two(height)|| width > max|| height > max){const GLint new_width = 256;const GLint new_height = 256; // 规定缩放后新的大小为边长的正方形GLint new_line_bytes, new_total_bytes;GLubyte* new_pixels = 0;// 计算每行需要的字节数和总字节数new_line_bytes = new_width * 3;while (new_line_bytes % 4 != 0)++new_line_bytes;new_total_bytes = new_line_bytes * new_height;// 分配内存new_pixels = (GLubyte*)malloc(new_total_bytes);if (new_pixels == 0){free(pixels);fclose(pFile);return 0;}// 进行像素缩放gluScaleImage(GL_RGB,width, height, GL_UNSIGNED_BYTE, pixels,new_width, new_height, GL_UNSIGNED_BYTE, new_pixels);// 释放原来的像素数据,把pixels指向新的像素数据,并重新设置width和heightfree(pixels);pixels = new_pixels;width = new_width;height = new_height;}}// 分配一个新的纹理编号glGenTextures(1, &texture_ID);if (texture_ID == 0){free(pixels);fclose(pFile);return 0;}// 绑定新的纹理,载入纹理并设置纹理参数// 在绑定前,先获得原来绑定的纹理编号,以便在最后进行恢复glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture_ID);glBindTexture(GL_TEXTURE_2D, texture_ID);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,GL_BGR_EXT, GL_UNSIGNED_BYTE, pixels);glBindTexture(GL_TEXTURE_2D, last_texture_ID);// 之前为pixels分配的内存可在使用glTexImage2D以后释放// 因为此时像素数据已经被OpenGL另行保存了一份(可能被保存到专门的图形硬件中)free(pixels);return texture_ID;
}/* 两个纹理对象的编号*/
GLuint texGround;
GLuint texWall;void display(void)
{// 清除屏幕glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// 设置视角glMatrixMode(GL_PROJECTION);glLoadIdentity();gluPerspective(75, 1, 1, 21);glMatrixMode(GL_MODELVIEW);glLoadIdentity();gluLookAt(1, 5, 5, 0, 0, 0, 0, 0, 1);// 使用“地”纹理绘制土地glBindTexture(GL_TEXTURE_2D, texGround);glBegin(GL_QUADS);glTexCoord2f(0.0f, 0.0f); glVertex3f(-8.0f, -8.0f, 0.0f);glTexCoord2f(0.0f, 5.0f); glVertex3f(-8.0f, 8.0f, 0.0f);glTexCoord2f(5.0f, 5.0f); glVertex3f(8.0f, 8.0f, 0.0f);glTexCoord2f(5.0f, 0.0f); glVertex3f(8.0f, -8.0f, 0.0f);glEnd();// 使用“墙”纹理绘制栅栏glBindTexture(GL_TEXTURE_2D, texWall);glBegin(GL_QUADS);glTexCoord2f(0.0f, 0.0f); glVertex3f(-6.0f, -3.0f, 0.0f);glTexCoord2f(0.0f, 1.0f); glVertex3f(-6.0f, -3.0f, 1.5f);glTexCoord2f(5.0f, 1.0f); glVertex3f(6.0f, -3.0f, 1.5f);glTexCoord2f(5.0f, 0.0f); glVertex3f(6.0f, -3.0f, 0.0f);glEnd();// 旋转后再绘制一个glRotatef(-90, 0, 0, 1);glBegin(GL_QUADS);glTexCoord2f(0.0f, 0.0f); glVertex3f(-6.0f, -3.0f, 0.0f);glTexCoord2f(0.0f, 1.0f); glVertex3f(-6.0f, -3.0f, 1.5f);glTexCoord2f(5.0f, 1.0f); glVertex3f(6.0f, -3.0f, 1.5f);glTexCoord2f(5.0f, 0.0f); glVertex3f(6.0f, -3.0f, 0.0f);glEnd();// 交换缓冲区,并保存像素数据到文件glutSwapBuffers();grab();
}int main(int argc, char* argv[])
{// GLUT初始化glutInit(&argc, argv);glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);glutInitWindowPosition(100, 100);glutInitWindowSize(WindowWidth, WindowHeight);glutCreateWindow(WindowTitle);glutDisplayFunc(&display);// 在这里做一些初始化glEnable(GL_DEPTH_TEST);glEnable(GL_TEXTURE_2D);texGround = load_texture("D:\\Visual Studio\\MyOpenGL\\ground.bmp");texWall = load_texture("D:\\Visual Studio\\MyOpenGL\\wall.bmp");printf("texGround =%d\ntexWall =%d", texGround, texWall);// 开始显示glutMainLoop();return 0;
}

映射的纹理的ground.bmp图片

映射的纹理的wall.bmp图片

 

结果: 

第十二讲

2、Alpha测试

代码:

#include <Windows.h>
#include <GL/glut.h>
#include <cmath>
#include <cstdio>
#include <cstdlib>#define WindowTitle  "OpenGL纹理测试"static GLint ImageWidth = 404;
static GLint ImageHeight = 453;#define WindowWidth  400
#define WindowHeight 400
#define BMP_Header_Length 54/* 函数power_of_two* 检查一个整数是否为2的整数次方,如果是,返回1,否则返回0* 实际上只要查看其二进制位中有多少个,如果正好有1个,返回1,否则返回0* 在“查看其二进制位中有多少个”时使用了一个小技巧* 使用n &= (n-1)可以使得n中的减少一个(具体原理大家可以自己思考)*/
int power_of_two(int n)
{if (n <= 0)return 0;return (n & (n - 1)) == 0;
}/* 函数load_texture* 读取一个BMP文件作为纹理* 如果失败,返回0,如果成功,返回纹理编号*/
GLuint load_texture(const char* file_name)
{GLint width, height, total_bytes, last_texture_ID;GLubyte* pixels = 0;GLuint texture_ID = 0;// 打开文件,如果失败,返回FILE* pFile;fopen_s(&pFile, file_name, "rb");if (pFile == 0) {return 0;}// 读取文件中图象的宽度和高度fseek(pFile, 0x0012, SEEK_SET);fread(&width, sizeof(ImageWidth), 1, pFile);fread(&height, sizeof(ImageHeight), 1, pFile);fseek(pFile, BMP_Header_Length, SEEK_SET);// 计算每行像素所占字节数,并根据此数据计算总像素字节数{GLint line_bytes = width * 3;while (line_bytes % 4 != 0)++line_bytes;total_bytes = line_bytes * height;}// 根据总像素字节数分配内存pixels = (GLubyte*)malloc(total_bytes);if (pixels == 0){fclose(pFile);return 0;}// 读取像素数据if (fread(pixels, total_bytes, 1, pFile) <= 0){free(pixels);fclose(pFile);return 0;}// 在旧版本的OpenGL中// 如果图象的宽度和高度不是的整数次方,则需要进行缩放// 这里并没有检查OpenGL版本,出于对版本兼容性的考虑,按旧版本处理// 另外,无论是旧版本还是新版本,// 当图象的宽度和高度超过当前OpenGL实现所支持的最大值时,也要进行缩放{GLint max;glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max);if (!power_of_two(width)|| !power_of_two(height)|| width > max|| height > max){const GLint new_width = 256;const GLint new_height = 256; // 规定缩放后新的大小为边长的正方形GLint new_line_bytes, new_total_bytes;GLubyte* new_pixels = 0;// 计算每行需要的字节数和总字节数new_line_bytes = new_width * 3;while (new_line_bytes % 4 != 0)++new_line_bytes;new_total_bytes = new_line_bytes * new_height;// 分配内存new_pixels = (GLubyte*)malloc(new_total_bytes);if (new_pixels == 0){free(pixels);fclose(pFile);return 0;}// 进行像素缩放gluScaleImage(GL_RGB,width, height, GL_UNSIGNED_BYTE, pixels,new_width, new_height, GL_UNSIGNED_BYTE, new_pixels);// 释放原来的像素数据,把pixels指向新的像素数据,并重新设置width和heightfree(pixels);pixels = new_pixels;width = new_width;height = new_height;}}// 分配一个新的纹理编号glGenTextures(1, &texture_ID);if (texture_ID == 0){free(pixels);fclose(pFile);return 0;}// 绑定新的纹理,载入纹理并设置纹理参数// 在绑定前,先获得原来绑定的纹理编号,以便在最后进行恢复glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture_ID);glBindTexture(GL_TEXTURE_2D, texture_ID);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,GL_BGR_EXT, GL_UNSIGNED_BYTE, pixels);glBindTexture(GL_TEXTURE_2D, last_texture_ID);// 之前为pixels分配的内存可在使用glTexImage2D以后释放// 因为此时像素数据已经被OpenGL另行保存了一份(可能被保存到专门的图形硬件中)free(pixels);return texture_ID;
}/* 将当前纹理BGR格式转换为BGRA格式* 纹理中像素的RGB值如果与指定rgb相差不超过absolute,则将Alpha设置为0.0,否则设置为1.0*/
void texture_colorkey(GLubyte r, GLubyte g, GLubyte b, GLubyte absolute)
{GLint width, height;GLubyte* pixels = 0;// 获得纹理的大小信息glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height);// 分配空间并获得纹理像素pixels = (GLubyte*)malloc(width * height * 4);if (pixels == 0)return;glGetTexImage(GL_TEXTURE_2D, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, pixels);// 修改像素中的Alpha值// 其中pixels[i*4], pixels[i*4+1], pixels[i*4+2], pixels[i*4+3]//   分别表示第i个像素的蓝、绿、红、Alpha四种分量,0表示最小,255表示最大{GLint i;GLint count = width * height;for (i = 0; i < count; ++i){if (abs(pixels[i * 4] - b) <= absolute&& abs(pixels[i * 4 + 1] - g) <= absolute&& abs(pixels[i * 4 + 2] - r) <= absolute)pixels[i * 4 + 3] = 0;elsepixels[i * 4 + 3] = 255;}}// 将修改后的像素重新设置到纹理中,释放内存glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,GL_BGRA_EXT, GL_UNSIGNED_BYTE, pixels);free(pixels);
}void display(void)
{static int initialized = 0;static GLuint texWindow = 0;static GLuint texPicture = 0;// 执行初始化操作,包括:读取相片,读取相框,将相框由BGR颜色转换为BGRA,启用二维纹理if (!initialized){texPicture = load_texture("D:\\Visual Studio\\MyOpenGL\\pic.bmp");texWindow = load_texture("D:\\Visual Studio\\MyOpenGL\\window.bmp");glBindTexture(GL_TEXTURE_2D, texWindow);texture_colorkey(255, 255, 255, 10);glEnable(GL_TEXTURE_2D);initialized = 1;}// 清除屏幕glClear(GL_COLOR_BUFFER_BIT);// 绘制相片,此时不需要进行Alpha测试,所有的像素都进行绘制glBindTexture(GL_TEXTURE_2D, texPicture);glDisable(GL_ALPHA_TEST);glBegin(GL_QUADS);glTexCoord2f(0, 0);     glVertex2f(-1.0f, -1.0f);glTexCoord2f(0, 1);     glVertex2f(-1.0f, 1.0f);glTexCoord2f(1, 1);     glVertex2f(1.0f, 1.0f);glTexCoord2f(1, 0);     glVertex2f(1.0f, -1.0f);glEnd();// 绘制相框,此时进行Alpha测试,只绘制不透明部分的像素glBindTexture(GL_TEXTURE_2D, texWindow);glEnable(GL_ALPHA_TEST);glAlphaFunc(GL_GREATER, 0.5f);glBegin(GL_QUADS);glTexCoord2f(0, 0);     glVertex2f(-1.0f, -1.0f);glTexCoord2f(0, 1);     glVertex2f(-1.0f, 1.0f);glTexCoord2f(1, 1);     glVertex2f(1.0f, 1.0f);glTexCoord2f(1, 0);     glVertex2f(1.0f, -1.0f);glEnd();// 交换缓冲glutSwapBuffers();
}int main(int argc, char* argv[])
{// GLUT初始化glutInit(&argc, argv);glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);glutInitWindowPosition(100, 100);glutInitWindowSize(WindowWidth, WindowHeight);glutCreateWindow(WindowTitle);glutDisplayFunc(&display);// 开始显示glutMainLoop();return 0;
}

映射的纹理的图片pic.bmp文件

映射的纹理的图片window.bmp文件

结果:

3、模板测试

代码:

#include <Windows.h>
#include <GL/glut.h>
#include <cmath>
#include <cstdio>
#include <cstdlib>#define WindowTitle  "OpenGL纹理测试"//以下是抓取保存为BMP文件的开始代码
#define WindowWidth  400
#define WindowHeight 400/* 函数grab* 抓取窗口中的像素* 假设窗口宽度为WindowWidth,高度为WindowHeight*/
#define BMP_Header_Length 54
void grab(void)
{glReadBuffer(GL_FRONT);FILE* pDummyFile;FILE* pWritingFile;GLubyte* pPixelData;GLubyte  BMP_Header[BMP_Header_Length];GLint    i, j;GLint    PixelDataLength;// 计算像素数据的实际长度i = WindowWidth * 3;   // 得到每一行的像素数据长度while (i % 4 != 0)      // 补充数据,直到i是的倍数++i;               // 本来还有更快的算法,// 但这里仅追求直观,对速度没有太高要求PixelDataLength = i * WindowHeight;// 分配内存和打开文件pPixelData = (GLubyte*)malloc(PixelDataLength);if (pPixelData == 0)exit(0);fopen_s(&pDummyFile,"D:\\Visual Studio\\MyOpenGL\\du.bmp", "rb");if (pDummyFile == 0)exit(0);fopen_s(&pWritingFile,"D:\\Visual Studio\\MyOpenGL\\grab.bmp", "wb");if (pWritingFile == 0)exit(0);// 读取像素glPixelStorei(GL_UNPACK_ALIGNMENT, 4);glReadPixels(0, 0, WindowWidth, WindowHeight,GL_BGR_EXT, GL_UNSIGNED_BYTE, pPixelData);// 把dummy.bmp的文件头复制为新文件的文件头fread(BMP_Header, sizeof(BMP_Header), 1, pDummyFile);fwrite(BMP_Header, sizeof(BMP_Header), 1, pWritingFile);fseek(pWritingFile, 0x0012, SEEK_SET);i = WindowWidth;j = WindowHeight;fwrite(&i, sizeof(i), 1, pWritingFile);fwrite(&j, sizeof(j), 1, pWritingFile);// 写入像素数据fseek(pWritingFile, 0, SEEK_END);fwrite(pPixelData, PixelDataLength, 1, pWritingFile);// 释放内存和关闭文件fclose(pDummyFile);fclose(pWritingFile);free(pPixelData);
}
//到此结束void draw_sphere()
{// 设置光源glEnable(GL_LIGHTING);glEnable(GL_LIGHT0);{GLfloatpos[] = { 5.0f, 5.0f, 0.0f, 1.0f },ambient[] = { 0.0f, 0.0f, 1.0f, 1.0f };glLightfv(GL_LIGHT0, GL_POSITION, pos);glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);}// 绘制一个球体glColor3f(1, 0, 0);glPushMatrix();glTranslatef(0, 0, 2);glutSolidSphere(0.5, 20, 20);glPopMatrix();
}void display(void)
{// 清除屏幕glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// 设置观察点glMatrixMode(GL_PROJECTION);glLoadIdentity();gluPerspective(60, 1, 5, 25);glMatrixMode(GL_MODELVIEW);glLoadIdentity();gluLookAt(5, 0, 6.5, 0, 0, 0, 0, 1, 0);glEnable(GL_DEPTH_TEST);// 绘制球体glDisable(GL_STENCIL_TEST);draw_sphere();// 绘制一个平面镜。在绘制的同时注意设置模板缓冲。// 另外,为了保证平面镜之后的镜像能够正确绘制,在绘制平面镜时需要将深度缓冲区设置为只读的。// 在绘制时暂时关闭光照效果glClearStencil(0);glClear(GL_STENCIL_BUFFER_BIT);glStencilFunc(GL_ALWAYS, 1, 0xFF);glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);glEnable(GL_STENCIL_TEST);glDisable(GL_LIGHTING);glColor3f(0.5f, 0.5f, 0.5f);glDepthMask(GL_FALSE);glRectf(-1.5f, -1.5f, 1.5f, 1.5f);glDepthMask(GL_TRUE);// 绘制一个与先前球体关于平面镜对称的球体,注意光源的位置也要发生对称改变// 因为平面镜是在X轴和Y轴所确定的平面,所以只要Z坐标取反即可实现对称// 为了保证球体的绘制范围被限制在平面镜内部,使用模板测试glStencilFunc(GL_EQUAL, 1, 0xFF);glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);glScalef(1.0f, 1.0f, -1.0f);draw_sphere();// 交换缓冲glutSwapBuffers();// 截图grab();
}int main(int argc, char* argv[])
{// GLUT初始化glutInit(&argc, argv);glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);glutInitWindowPosition(100, 100);glutInitWindowSize(WindowWidth, WindowHeight);glutCreateWindow(WindowTitle);glutDisplayFunc(&display);// 开始显示glutMainLoop();return 0;
}

结果:

更多推荐

《OpenGL入门教程》上的代码复现

本文发布于:2024-02-11 18:56:11,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1682739.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:入门教程   代码   OpenGL

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!