第一讲
#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 <GL/glut.h>
#include <math.h>
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);
GLfloat
PointA[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 <GL/glut.h>
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;
}
第四讲
void myDisplay(void)
{
int i;
for(i=0; i<8; ++i)
auxSetOneColor(i, (float)(i&0x04), (float)(i&0x02), (float)(i&0x01));
glShadeModel(GL_FLAT);
glClear(GL_COLOR_BUFFER_BIT);
glBegin(GL_TRIANGLE_FAN);
glVertex2f(0.0f, 0.0f);
for(i=0; i<=8; ++i)
{
glIndexi(i);
glVertex2f(cos(i*Pi/4), sin(i*Pi/4));
}
glEnd();
glFlush();
}
int main(void)
{
auxInitDisplayMode(AUX_SINGLE|AUX_INDEX);
auxInitPosition(0, 0, 400, 400);
auxInitWindow(L"");
myDisplay();
Sleep(10 * 1000);
return 0;
}
第五讲
#include <stdio.h>
#include <math.h>
#include <Windows.h>
#include <Gl/glut.h>
int day = 200; // day的变化:从到
void myDisplay(void)
{
glEnable(GL_BLEND);// 深度测试
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//清空深度缓冲
glMatrixMode(GL_PROJECTION);//投影矩阵
glLoadIdentity();//当前矩阵设置为单位矩阵
gluPerspective(60, 1, 1, 400000000);//设置可视空间可视角高宽比最近可视空间最远可视空间
glMatrixMode(GL_MODELVIEW);//模型视图矩阵
glLoadIdentity();
//前三个参数表示了观察点的位置,中间三个参数表示了观察目标的位置,最后三个参数代表从(0,0,0)到(x,y,z)的直线,它表示了观察者认为的“上”方向。
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);//GLUT初始化使用前调用
glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);//显示方式GLUT-RGB表示RGB颜色GLUT_SINGLE单缓冲
glutInitWindowPosition(100, 100);// 设置窗口在屏幕中的位置
glutInitWindowSize(400, 400);// 设置窗口的大小长宽
glutCreateWindow("OpenGL");// 窗口的标题
glutDisplayFunc(&myDisplay);//需要进行画图时,这个函数就会被调用
glutMainLoop();//保持窗口显示
return 0;
}
第六讲
#include <stdio.h>
#include <math.h>
#include <Windows.h>
#include <Gl/glut.h>
int day = 0; // day的变化:从到
void myDisplay(void)
{
glEnable(GL_BLEND);// 深度测试
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//清空深度缓冲
glMatrixMode(GL_PROJECTION);//投影矩阵
glLoadIdentity();//当前矩阵设置为单位矩阵
gluPerspective(60, 1, 1, 400000000);//设置可视空间可视角高宽比最近可视空间最远可视空间
glMatrixMode(GL_MODELVIEW);//模型视图矩阵
glLoadIdentity();
//前三个参数表示了观察点的位置,中间三个参数表示了观察目标的位置,最后三个参数代表从(0,0,0)到(x,y,z)的直线,它表示了观察者认为的“上”方向。
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);
glutSwapBuffers();
}
void OnTimer(int value)
{
//改变角度
day += 1;
day%=360;
glutPostRedisplay();//重画
glutTimerFunc(16, OnTimer, 1);
}
int main(int argc, char *argv[])
{
glutInit(&argc, argv);//GLUT初始化使用前调用
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);//显示方式GLUT-RGB表示RGB颜色GLUT_SINGLE单缓冲
glutInitWindowPosition(100, 100);// 设置窗口在屏幕中的位置
glutInitWindowSize(400, 400);// 设置窗口的大小长宽
glutCreateWindow("OpenGL");// 窗口的标题
glutDisplayFunc(&myDisplay);//需要进行画图时,这个函数就会被调用
glutTimerFunc(16, OnTimer, 1);//计时器定时运行FPS
glutMainLoop();//保持窗口显示
return 0;
}
第七讲
include <gl/glut.h>
#define WIDTH 400
#define HEIGHT 400
static GLfloat angle = 0.0f;
void myDisplay(void)
{
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;
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 <gl/glut.h>
#define WIDTH 400
#define HEIGHT 400
#include <math.h>
#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 )
{
// 如果显示列表不存在,则创建
/* GLfloat
PointA[] = {-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年月日修改
GLfloat
PointA[] = { 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};
GLfloat
ColorR[] = {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);
// 平面ABC
ColoredVertex(ColorR, PointA);
ColoredVertex(ColorG, PointB);
ColoredVertex(ColorB, PointC);
// 平面ACD
ColoredVertex(ColorR, PointA);
ColoredVertex(ColorB, PointC);
ColoredVertex(ColorY, PointD);
// 平面CBD
ColoredVertex(ColorB, PointC);
ColoredVertex(ColorG, PointB);
ColoredVertex(ColorY, PointD);
// 平面BAD
ColoredVertex(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;
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 <stdio.h>
#include <math.h>
#include <Windows.h>
#include <Gl/glut.h>
#define WIDTH 400
#define HEIGHT 400
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();
}
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;
}
第十讲
#include <math.h>
#include <Windows.h>
#include <Gl/glut.h>
#include <stdio.h>
#include <stdlib.h>
#define WindowWidth 400
#define WindowHeight 400
/* 函数grab
* 抓取窗口中的像素
* 假设窗口宽度为WindowWidth,高度为WindowHeight
*/
#define BMP_Header_Length 54
void grab(void)
{
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);
pDummyFile = fopen("dummy.bmp", "rb");
if( pDummyFile == 0 )
exit(0);
pWritingFile = fopen("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(WindowWidth, WindowHeight);
glutCreateWindow("OpenGL 窗口");
glutDisplayFunc(&display);
glutMainLoop();
return 0;
}
第十一讲
#include<stdio.h>
#include<stdlib.h>
#include <math.h>
#include <Gl/glut.h>
#include<glaux.h>
#include <time.h>
#define WindowWidth 500
#define WindowHeight 500
/* 函数grab
* 抓取窗口中的像素
* 假设窗口宽度为WindowWidth,高度为WindowHeight
*/
#define BMP_Header_Length 54
void grab(void)
{
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, "dummy.bmp", "rb");
if (pDummyFile == 0)
exit(0);
fopen_s(&pWritingFile, "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
* 检查一个整数是否为的整数次方,如果是,返回,否则返回
* 实际上只要查看其二进制位中有多少个,如果正好有个,返回,否则返回
* 在“查看其二进制位中有多少个”时使用了一个小技巧
* 使用n &= (n-1)可以使得n中的减少一个(具体原理大家可以自己思考)
*/
int power_of_two(int n)
{
if (n <= 0)
return 0;
return (n & (n - 1)) == 0;
}
/* 函数load_texture
* 读取一个BMP文件作为纹理
* 如果失败,返回,如果成功,返回纹理编号
*/
GLuint load_texture(const char* file_name)
{
GLint width, height, total_bytes;
GLubyte* pixels = 0;
GLuint last_texture_ID, texture_ID = 0;
// 打开文件,如果失败,返回
FILE* pFile;
fopen_s(&pFile, file_name, "rb");
if (pFile == 0)
return 0;
// 读取文件中图象的宽度和高度
fseek(pFile, 0x0012, SEEK_SET);
fread(&width, 4, 1, pFile);
fread(&height, 4, 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和height
free(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, (GLint*)&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);//利用glTexImage2D函数可以载入一个二维的纹理
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);//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();
grab();
// 交换缓冲区,并保存像素数据到文件
glutSwapBuffers();
}
int main(int argc, char* argv[])
{
// GLUT初始化
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowPosition(100, 100);
glutInitWindowSize(WindowWidth, WindowHeight);
glutCreateWindow("纹理映射测试");
glutDisplayFunc(&display);
// 在这里做一些初始化
glEnable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
texGround = load_texture("ground.bmp");
printf("%d", (int)texGround);
texWall = load_texture("wall.bmp");
printf("%d", (int)texWall);
// 开始显示
glutMainLoop();
return 0;
}
第十二讲-1
#include <gl/glut.h>
#include <stdio.h>
#include <stdlib.h>
#define WindowWidth 400
#define WindowHeight 400
#define WindowTitle "OpenGL模板测试"
#define BMP_Header_Length 54
void grab(void)
{
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);
pDummyFile = fopen("dummy.bmp", "rb");
if (pDummyFile == 0)
exit(0);
pWritingFile = fopen("grab.bmp", "wb");
if (pWritingFile == 0)
exit(0);
// 读取像素
glReadBuffer(GL_FRONT);
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);
{
GLfloat
pos[] = { 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;
}
}
第十二讲-2
#include <gl/glut.h>
#include <stdio.h>
#include <stdlib.h>
#define WindowWidth 400
#define WindowHeight 400
#define WindowTitle "OpenGLalpha测试"
GLuint texGround;
GLuint texWall;
#define BMP_Header_Length 54
/* 函数power_of_two
* 检查一个整数是否为的整数次方,如果是,返回,否则返回
* 实际上只要查看其二进制位中有多少个,如果正好有个,返回,否则返回
* 在“查看其二进制位中有多少个”时使用了一个小技巧
* 使用n &= (n-1)可以使得n中的减少一个(具体原理大家可以自己思考)
*/
int power_of_two(int n)
{
if (n <= 0)
return 0;
return (n & (n - 1)) == 0;
}
/* 函数load_texture
* 读取一个BMP文件作为纹理
* 如果失败,返回,如果成功,返回纹理编号
*/
GLuint load_texture(const char* file_name)
{
GLint width, height, total_bytes;
GLubyte* pixels = 0;
GLuint last_texture_ID, texture_ID = 0;
// 打开文件,如果失败,返回
FILE* pFile = fopen(file_name, "rb");
if (pFile == 0)
return 0;
// 读取文件中图象的宽度和高度
fseek(pFile, 0x0012, SEEK_SET);
fread(&width, 4, 1, pFile);
fread(&height, 4, 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和height
free(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, (GLint*)&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
*/
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四种分量,表示最小,表示最大
{
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;
else
pixels[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("pic.bmp");
texWindow = load_texture("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;
}
=========================================================================
参考 :第11讲OpenGL程序出错,希望有大神帮忙解决一下!(有源程序)-CSDN论坛
图片资源:https://download.csdn.net/download/weixin_45322373/75434457