opengl入门教程(精)的学习笔记

1.小球旋转

知识点:1.光照、视角、材质、矩阵变换的基本用法

2.计算FPS


#include "stdafx.h"
#include 
#include 
#include 
#include 
#include 

#define WIDTH 400
#define HEIGHT 400

//#define ColoredVertex(c,v) do{glColor3fv(c);glVertex3fv(v);}while(0)

GLfloat angle=0.0f;
static int day =200;


double 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);
	
	
	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,5.0,-10.0,0,0,0,0,1,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);
		glMaterialfv(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);
		glMaterialfv(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);
	}
	
	//glFlush();
	glutSwapBuffers();
}

void myIdle(void)
{
	angle+=1.0f;
	if(angle>=360.0f)
		angle=0.0f;
	myDisplay();
}

int _tmain(int argc, char* argv[])
{
	glutInit(&argc,argv);
	glutInitDisplayMode(GLUT_DEPTH|GLUT_DOUBLE|GLUT_RGBA);
	glutInitWindowPosition(200,200);
	glutInitWindowSize(WIDTH,HEIGHT);
	glutCreateWindow("tanrunj");
	glutDisplayFunc(myDisplay);
	glutIdleFunc(myIdle);
	
	glutMainLoop();
	
	return 0;
}


2.图像读取

知识点:1.BMP文件的正确读入

2.glReadPixels的正确

#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++;

	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的文件头复制为新文件头
	//pDummy->bmp_header
	fread(BMP_Header,sizeof(BMP_Header),1,pDummyFile);
	//bmp_header->pwriting
	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);
}


3.贴图

知识点:1.纹理的载入

2.贴图的用法

// ConsoleApplication1.cpp : ¶¨Òå¿ØÖÆ̨ӦÓóÌÐòµÄÈë¿Úµã¡£
//

#include "stdafx.h"
#include 
#include 
#include 
#include 
#include 

#define WIDTH 400
#define HEIGHT 400

#define WindowWidth 400
#define WindowHeight 400

//grab 窗口的像素

#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++;

	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的文件头复制为新文件头
	//pDummy->bmp_header
	fread(BMP_Header,sizeof(BMP_Header),1,pDummyFile);
	//bmp_header->pwriting
	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);
}

//判断是否2的幂次
int power_of_two(int n)
{
	if(n<=0)
		return 0;
	return (n&(n-1))==0;
}

GLfloat angle=0.0f;

GLuint load_texture(const char* file_name)
{
	GLint width,height,total_bytes;
	GLubyte* pixels = 0;
	GLint last_texture_ID;
	GLuint 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;
	}

	//旧版中,纹理宽高不是整数次方或太大需缩放
	{
		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);

			//释放,指向新数据,重设宽高
			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,&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后可以释放,已被存到专门图形硬件
		free(pixels);
		return texture_ID;
		
}
//计算FPS
double 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;
}

//纹理编号
GLuint texGround;
GLuint texWall;

void myDisplay(void)
{
	double FPS=CalFrequency();
	printf("FPS=%f\n",FPS);
	
	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,0); glVertex3f(-8,-8,0);
	glTexCoord2f(0,5); glVertex3f(-8,8,0);
	glTexCoord2f(5,5); glVertex3f(8,8,0);
	glTexCoord2f(5,0); glVertex3f(8,-8,0);
	glEnd();

	//贴墙
	glBindTexture(GL_TEXTURE_2D,texWall);
	glBegin(GL_QUADS);
	glTexCoord2d(0,0); glVertex3f(-6,-3,0);
	glTexCoord2d(0,1); glVertex3f(-6,-3,1.5);
	glTexCoord2f(5,1); glVertex3f(6,-3,1.5);
	glTexCoord2f(5,0); glVertex3f(6,-3,0);
	glEnd();

	//旋转再绘制墙
	glRotatef(-90,0,0,1);
	glBegin(GL_QUADS);
	glTexCoord2f(0,0); glVertex3f(-6,-3,0);
	glTexCoord2f(0,1); glVertex3f(-6,-3,1.5);
	glTexCoord2f(5,1); glVertex3f(6,-3,1.5);
	glTexCoord2f(5,0); glVertex3f(6,-3,0);
	glEnd();
	
	glutSwapBuffers();

	grab();
}

//转动调整
void myIdle(void)
{
	angle+=1.0f;
	if(angle>=360.0f)
		angle=0.0f;
	myDisplay();
}

int _tmain(int argc, char* argv[])
{
	glutInit(&argc,argv);
	glutInitDisplayMode(GLUT_DEPTH|GLUT_DOUBLE|GLUT_RGBA);
	glutInitWindowPosition(200,200);
	glutInitWindowSize(WIDTH,HEIGHT);
	glutCreateWindow("tanrunj");
	glutDisplayFunc(myDisplay);
	
	glEnable(GL_DEPTH_TEST);
	glEnable(GL_TEXTURE_2D);
	texGround = load_texture("ground.bmp");
	texWall = load_texture("wall.bmp");
	glutIdleFunc(myIdle);
	
	glutMainLoop();
	
	return 0;
}


4.颜色混合(从而形成半透明,注意要先绘画不透明远处物)

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,0,0.5);
	//°ë¾¶£¬¾­Î³¶ÎÊý
	glutSolidSphere(0.3,30,30);
	glPopMatrix();

	//»æÖÆ°ë͸Ã÷£¬Éî¶È»º³åΪֻ¶Á
	//glDepthMask(GL_FALSE);

	//ÒÔ(0.2,0,-0.5)ΪÖÐÐÄ£¬»æÖÆ.2µÄ°ë͸Ã÷À¶Çò£¨×î½ü£©
	setMatirial(blue_color,30);
	glPushMatrix();
	glTranslatef(0.2,0,-0.5);
	glutSolidSphere(0.2,30,30);
	glPopMatrix();

	//ÒÔ(0.1,0,0)ΪÖÐÐÄ£¬»æÖÆ.15°ë͸Ã÷ÂÌÇò£¨Öм䣩
	setMatirial(green_color,30);
	glPushMatrix();
	glTranslatef(0.1,0,0);
	glutSolidSphere(0.15,30,30);
	glPopMatrix();

	//Íê³É°ë͸Ã÷£¬Éî¶È»Ö¸´¿É¶Á¿Éд
	glDepthMask(GL_TRUE);

5.ALPHA和模板测试

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();
}

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();
}


你可能感兴趣的:(OPENGL学习)