1. 程式人生 > >openGL繪製正方體分別實現簡單顏色繪製、紋理繪製、光照繪製

openGL繪製正方體分別實現簡單顏色繪製、紋理繪製、光照繪製

使用openGL繪製正方體;

面1:使用簡單顏色繪製,顏色為綠色;

面2:使用簡單顏色繪製,顏色為漸變色;

面3:繪製一維紋理;

面4:繪製二維紋理;

面5:光照繪製,黃色;

面6:光照繪製,橘色;

繪製效果如下:

                

需要注意的問題:

1、  在繪製紋理和光照的時候,要正確設定每個面的法線方向;使用函式glNormal3f( )進行設定;

2、  使用光照的時候,如果只是區域性光照,要在區域性光照結束之後,關閉光源,否則別的面也被光照;使用函式glDisable(GL_LIGHTING)實現;

3、  使用png圖片作為二維紋理的時候需要將原始圖片進行上下翻轉,因為OpenGL以左下角為影象原點;自定義函式void upsidedown32(unsigned char *pImage, unsigned width, unsignedheight)實現影象上下翻轉;

#include <GL/glut.h>
#include "lodepng.h"

void init(void);
void reshape(int w, int h);
void mouse(int button, int state, int x, int y);
void motion(int x, int y);
void display(void);
void drawCoordinates(void);
void drawTetrahedron(void);

int mx,my; //position of mouse
int m_state=0; //mouse usage
float x_angle=20.0f, y_angle=20.0f; //angle of eye
float dist=10.0f; //distance from the eye

GLuint texDog, tex1D;

void upsidedown32(unsigned char *pImage, unsigned width, unsigned height)  //Upside down the image
{
	unsigned i;
	unsigned char *pLine;

	pLine = (unsigned char *)malloc(4*width);
	if(pLine == NULL)
	{
		printf("No memory left!");
		exit(0);
	}
	for(i=0; i<height/2; i++)
	{
		memcpy(pLine, &pImage[i*4*width], 4*width);
		memcpy(&pImage[i*4*width], &pImage[(height-1-i)*4*width], 4*width);
		memcpy(&pImage[(height-1-i)*4*width], pLine, 4*width);
	}
	free(pLine);
}


void init(void)
{
	int i;
	unsigned error;
	unsigned width, height;
	unsigned char *pDogImg;
	unsigned char img1D[16][3];

	error = lodepng_decode32_file(&pDogImg, &width, &height, "dog.png");
	if(error)
	{
		printf("error %u: %s\n", error, lodepng_error_text(error));
		exit(0);
	}
	upsidedown32(pDogImg, width, height); //Upside down the image
	glGenTextures(1, &texDog); //生成紋理號
	glBindTexture(GL_TEXTURE_2D, texDog);  //紋理繫結
	glTexImage2D(GL_TEXTURE_2D, 0, 4, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pDogImg); //定義紋理資料
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);  //設定紋理目標引數
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
	free(pDogImg);

	for(i=0; i<16; i++)  //構造一維紋理
		if(i%4)
			img1D[i][0] = img1D[i][1] = img1D[i][2] = 255;
		else
			img1D[i][0] = img1D[i][1] = img1D[i][2] = 0;
	glGenTextures(1, &tex1D);
	glBindTexture(GL_TEXTURE_1D, tex1D);
	glTexImage1D(GL_TEXTURE_1D, 0, 3, 16, 0, GL_RGB, GL_UNSIGNED_BYTE, img1D);
	glTexParameteri(GL_TEXTURE_1D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
	glTexParameteri(GL_TEXTURE_1D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);

	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);  //設定紋理環境引數
	glEnable(GL_DEPTH_TEST);
}

void reshape(int w, int h)
{
	glViewport(0, 0, w, h);
}


void mouse(int button, int state, int x, int y)
{
	if(button==GLUT_LEFT_BUTTON && state == GLUT_DOWN)
	{
		mx = x;
		my = y;
		m_state = 0;
	}
	if(button==GLUT_RIGHT_BUTTON && state == GLUT_DOWN)
	{
		mx = x;
		my = y;
		m_state = 1;
	}
}

void motion(int x, int y)
{
	int dx,dy; //offset of mouse;

	dx = x-mx;
	dy = y-my;

	if(m_state == 0)
	{
		y_angle += dx*0.1f;
		x_angle += dy*0.1f;
	}
	else if(m_state == 1)
		dist += (dx+dy)*0.05f;
	
	mx = x;
	my = y;

	glutPostRedisplay();
}

void display(void)
{
	int rect[4];
	float w, h;
	//float lit_position[] = {0.0f, 0.0f, 1.0f, 0.0f};
	//float mat_yellow[] = {1.0f, 1.0f, 0.0f, 1.0f};

	glGetIntegerv(GL_VIEWPORT, rect);
	w = rect[2];
	h = rect[3];

	glClearColor(1.0f,1.0f,1.0f,0.0f);
	glClearDepth(1.0);
	glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity(); //對應單位陣I

	if(h < 1) h=1;
	gluPerspective(30.0, w/h, 0.1, 20.0); //對應變換陣T0

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity(); //對應單位陣I

	glTranslated(0.0, 0.0, -dist); //對應變換陣T1
	glRotatef(x_angle, 1.0f, 0.0f, 0.0f); //對應變換陣T2
	glRotatef(y_angle, 0.0f, 1.0f, 0.0f); //對應變換陣T3
	
	glPushMatrix();
		glScalef(1.5f, 1.5f, 1.5f); //對應變換陣T6
		drawCoordinates();
		drawTetrahedron();
	glPopMatrix();

	glFlush();
	glutSwapBuffers();
}

void drawTetrahedron(void)
{
	float pnt[8][3] = {{0.0,0.0,0.0}, {0.0,1.0,0.0}, {1.0,1.0,0.0}, {1.0,0.0,0.0},{0.0,0.0,1.0},{0.0,1.0,1.0},{1.0,1.0,1.0},{1.0,0.0,1.0}};
	int tetra[6][4] = {{0,1,2,3}, {1,5,6,2}, {0,3,7,4}, {2,6,7,3},{0,4,5,1},{4,7,6,5}};
	float lit_position1[] = {1.0f, 0.0f, 0.0f, 0.0f};
	float lit_position2[] = {-1.0f, 0.0f, 0.0f, 0.0f};
	float yellow[] = {1.0f, 1.0f, 0.0f, 1.0f};
	float orange[] = {1.0f, 0.5f, 0.0f, 1.0f};
	
	//glNormal3f(0.0f, 0.0f, -1.0f);
	glBegin(GL_QUADS);  //簡單顏色繪兩個面,一個單一色,一個漸變色
		glColor3f(0.0f,1.0f,0.0f);  //綠色
		glVertex3fv(pnt[tetra[0][0]]); //glVertex3fv(pnt[0]); glVertex3f(0.0f, 0.0f, 0.0f); 
		glVertex3fv(pnt[tetra[0][1]]); //glVertex3fv(pnt[2]); glVertex3f(0.0f, 1.0f, 0.0f); 
		glVertex3fv(pnt[tetra[0][2]]); //glVertex3fv(pnt[1]); glVertex3f(1.0f, 0.0f, 0.0f); 
		glVertex3fv(pnt[tetra[0][3]]);
    glEnd();

	//glNormal3f(0.0f, 1.0f, 0.0f);
	glBegin(GL_QUADS);
		glColor3f(0.0f,1.0f,1.0f); glVertex3fv(pnt[tetra[1][0]]);
		glColor3f(1.0f,0.0f,1.0f); glVertex3fv(pnt[tetra[1][1]]);
		glColor3f(1.0f,1.0f,0.0f); glVertex3fv(pnt[tetra[1][2]]);
		glColor3f(1.0f,1.0f,1.0f); glVertex3fv(pnt[tetra[1][3]]);
	glEnd();


	/* 繪製紋理圖案    */
	glNormal3f(0.0f, -1.0f, 0.0f);//一維紋理繪製
	glDisable(GL_TEXTURE_2D);
	glEnable(GL_TEXTURE_1D);
	glBegin(GL_POLYGON); 
		glTexCoord1f(0.0f); glVertex3fv(pnt[tetra[2][0]]);  //設定紋理座標
		glTexCoord1f(0.0f); glVertex3fv(pnt[tetra[2][1]]);
		glTexCoord1f(1.0f); glVertex3fv(pnt[tetra[2][2]]);
		glTexCoord1f(1.0f); glVertex3fv(pnt[tetra[2][3]]);
	glEnd();

	glNormal3f(0.0f, 0.0f, 1.0f); //二維紋理的繪製
	glDisable(GL_TEXTURE_1D);
	glEnable(GL_TEXTURE_2D);
	glBegin(GL_POLYGON);  // 正對面
	glTexCoord2f(0.0f, 0.0f); glVertex3fv(pnt[tetra[5][0]]);
	glTexCoord2f(1.0f, 0.0f); glVertex3fv(pnt[tetra[5][1]]);
	glTexCoord2f(1.0f, 1.0f); glVertex3fv(pnt[tetra[5][2]]);
	glTexCoord2f(0.0f, 1.0f); glVertex3fv(pnt[tetra[5][3]]);
    glEnd();
	glDisable(GL_TEXTURE_2D);
	glDisable(GL_TEXTURE_1D);


	/* 兩個光照面  */
	glLightfv(GL_LIGHT0, GL_POSITION, lit_position2);  //光源位置
	glEnable(GL_LIGHT0);
	glEnable(GL_LIGHTING);  //之後使用光照模型計算頂點顏色
	glMaterialfv(GL_FRONT, GL_DIFFUSE, yellow);

	glNormal3f(-1.0f,0.0f,0.0f);
	glBegin(GL_QUADS);
	glVertex3fv(pnt[tetra[4][0]]);
	glVertex3fv(pnt[tetra[4][1]]);
	glVertex3fv(pnt[tetra[4][2]]);
	glVertex3fv(pnt[tetra[4][3]]);
	glEnd();
	glDisable(GL_LIGHTING);	//(不能省略)之後頂點顏色為當前顏色,當前顏色可以通過glColor*函式指定。  	

	glLightfv(GL_LIGHT0, GL_POSITION, lit_position1);  //普通光照(橘色)
	glEnable(GL_LIGHT0);
	glEnable(GL_LIGHTING);  
	glMaterialfv(GL_FRONT, GL_DIFFUSE, orange);

	glNormal3f(1.0f,0.0f,0.0f);   
	glBegin(GL_QUADS);
		glVertex3fv(pnt[tetra[3][0]]); 
		glVertex3fv(pnt[tetra[3][1]]);
		glVertex3fv(pnt[tetra[3][2]]);
		glVertex3fv(pnt[tetra[3][3]]);
	glEnd();
	glDisable(GL_LIGHTING); 
}

void drawCoordinates(void)
{
	glColor3f(1.0f,0.0f,0.0f); //畫紅色的x軸
	glBegin(GL_LINES);
	glVertex3f(0.0f, 0.0f, 0.0f);
	glVertex3f(2.0f, 0.0f, 0.0f);
	glEnd();
	glColor3f(0.0,1.0,0.0); //畫綠色的y軸
	glBegin(GL_LINES);
	glVertex3f(0.0f, 0.0f, 0.0f);
	glVertex3f(0.0f, 2.0f, 0.0f);
	glEnd();
	glColor3f(0.0,0.0,1.0); //畫藍色的z軸
	glBegin(GL_LINES);
	glVertex3f(0.0f, 0.0f, 0.0f);
	glVertex3f(0.0f, 0.0f, 2.0f);
	glEnd();
}


int main(int argc,char **argv)
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
	glutInitWindowSize(500,500);
	glutInitWindowPosition(0,0);
	glutCreateWindow("model & zbuffer");
	init();

	glutDisplayFunc(display);
	glutReshapeFunc(reshape);
	glutMouseFunc(mouse);
	glutMotionFunc(motion);
	glutMainLoop();

	glDeleteTextures(1, &texDog); //刪除紋理
	glDeleteTextures(1, &tex1D);  //刪除紋理

	return 0;
}