OpenGL繪製光照和材質效果

OpenGL繪製光照和材質效果


在這裏插入圖片描述

本次任務主要實踐三維空間的平移旋轉、透視投影、光照及材質。有關陰影效果,課程的本節內容僅講述了手動操作模型矩陣來繪製的陰影平面,而主流的陰影繪製方法是利用紋理和貼圖來渲染陰影。


1. 將三個物體同軸排列

前面幾個小節已經繪製了平面五角星、三維彩色立方體以及遞歸細分四面體法的三維球體,本節的要求首先是將三個物體同軸排列,使之在視景體中可見並設置透視投影來觀察三者。爲了更好地觀察空間中的物體,本代碼中額外繪製了三維座標架,並繪製出了XOY平面,相關代碼如下:

void frame()
{
	// 繪製三維座標架
	glColor3f(0.3f, 0.3f, 0.3f);
	glLineWidth(0.75);
	glBegin(GL_LINES);
	glVertex3f(-100.0f, 0.0f, 0.0f);
	glVertex3f(100.0f, 00.0f, 0.0f);
	glVertex3f(0.0f, -100.0f, 0.0f);
	glVertex3f(0.0f, 100.0f, 0.0f);
	glVertex3f(0.0f, 0.0f, -100.0f);
	glVertex3f(0.0f, 0.0f, 100.0f);
	glEnd();
	// 繪製XOY平面
	glColor4f(0.8f, 0.8f, 0.8f, 0.5f);
	glNormal3f(0.0f, 0.0f, 1.0f);
	glBegin(GL_QUADS);
	glVertex3f(8.0f, 8.0f, 0.0f);
	glVertex3f(-8.0f, 8.0f, 0.0f);
	glVertex3f(-8.0f, -8.0f, 0.0f);
	glVertex3f(8.0f, -8.0f, 0.0f);
	glEnd();
}

在這裏插入圖片描述

繪製好座標架後,三個物品依次排列時就可以清晰地看出其空間關係。三個物體繪製的具體代碼不再贅述,以下是display函數中將三個物體依次排列的相關代碼:

void display()
{
	// 設置背景爲白色
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	// 加載單位陣
	glLoadIdentity();
	// 設置相機的位置和視角
	gluLookAt(7, 4, 4, 0.0, 0.0, 0.0, 0, 0, 1);
	// 繪製座標架以及XOY平面
	frame();
	// 平移座標系,讓三個待繪製物品的底部排列在X軸上
	glTranslatef(0.0f, 0.0f, 1.0f);
	// 在中心繪製三維彩色立方體,並繪製簡單陰影
	glTranslatef(-0.75f, -0.75f, -0.75f);
	color_cube(1.5f);
	cube_shadow(0.0f, 0.0f, 6.0f, 1.5f);
	glTranslatef(0.75f, 0.75f, 0.75f);
	// 在左側(Y軸負半軸)繪製紅色球面
	glTranslatef(0.0f, -4.0f, 0.0f);
	sphere();
	glTranslatef(0.0f, 4.0f, 0.0f);
	// 在右側(Y軸正半軸)繪製平面的五角星
	glTranslatef(0.0f, 4.0f, 0.0f);
	pentagram();
	glTranslatef(0.0f, -4.0f, 0.0f);
	// 刷新幀緩存
	glutSwapBuffers();
}

在不添加光照和陰影效果時,三個物品依次排列繪製出的效果如下:

在這裏插入圖片描述

可以看出,我們將三個物體的中心排列在同一高度,但由於使用了透視投影,靠右側的五角星在視覺上要比靠左側的球體更大,但實際上五角星的外接圓半徑與球體半徑是相同的,均爲1。但由於沒有使用光照效果,球體看上去只是一個圓(透視投影下被拉成橢圓)。


2. 光照、材質與簡單陰影效果

光照和材質效果可以在init()函數中設置,此外在使用光照時,需要在繪製圖像過程中增加每一點法向量的設置。指定法線向量的方式與指定顏色的方式有雷同之處。在指定顏色時,只需要指定每一個頂點的顏色,OpenGL就可以自行計算頂點之間的其它點的顏色。並且,顏色一旦被指定,除非再指定新的顏色,否則以後指定的所有頂點都將以這一向量作爲自己的顏色。在指定法線向量時,只需要指定每一個頂點的法線向量,OpenGL會自行計算頂點之間的其它點的法線向量。並且,法線向量一旦被指定,除非再指定新的法線向量,否則以後指定的所有頂點都將以這一向量作爲自己的法線向量。使用glColor*()函數可以指定顏色,而使用glNormal*()函數則可以指定法線向量。

在OpenGL中,僅僅支持有限數量的光源。使用GL_LIGHT0表示第0號光源,GL_LIGHT1表示第1號光源,依次類推。OpenGL至少會支持8個光源,即GL_LIGHT0到GL_LIGHT7。每一個光源都可以設置其屬性,這一動作是通過glLight*()函數完成的。glLight*()函數具有三個參數,第一個參數指明是設置哪一個光源的屬性,第二個參數指明是設置該光源的哪一個屬性,第三個參數則是指明把該屬性值設置成多少。GL_AMBIENT、GL_DIFFUSE、GL_SPECULAR這三個屬性表示了光源所發出的光的反射特性(以及顏色),每個屬性由四個值表示,分別代表了顏色的R, G, B, A值。GL_AMBIENT表示該光源所發出的光,經過非常多次的反射後,最終遺留在整個光照環境中的強度(顏色)。GL_DIFFUSE表示該光源所發出的光,照射到粗糙表面時經過漫反射,所得到的光的強度(顏色)GL_SPECULAR表示該光源所發出的光,照射到光滑表面時經過鏡面反射,所得到的光的強度(顏色)。GL_POSITION屬性表示光源所在的位置。由四個值(X, Y, Z, W)表示。如果第四個值W爲零,則表示該光源位於無限遠處,前三個值表示了它所在的方向。這種光源稱爲方向性光源,通常,太陽可以近似的被認爲是方向性光源。如果第四個值W不爲零,則X/W, Y/W, Z/W表示了光源的位置。這種光源稱爲位置性光源。對於位置性光源,設置其位置與設置多邊形頂點的方式相似,各種矩陣變換函數例如:glTranslate*()、glRotate*()等在這裏也同樣有效。方向性光源在計算時比位置性光源快了不少,因此,在視覺效果允許的情況下,應該儘可能的使用方向性光源。

材質與光源相似,也需要設置衆多的屬性。不同的是,光源是通過glLight*()函數來設置的,而材質則是通過glMaterial*()函數來設置的。glMaterial*()函數有三個參數。第一個參數表示指定哪一面的屬性。可以是GL_FRONT、GL_BACK或者GL_FRONT_AND_BACK。分別表示設置“正面”“背面”的材質,或者兩面同時設置。第二、第三個參數與glLight*函數的第二、三個參數作用類似。GL_AMBIENT、GL_DIFFUSE、GL_SPECULAR這三個屬性與光源的三個對應屬性類似,每一屬性都由四個值組成。GL_SHININESS屬性只有一個值,稱爲“鏡面指數”,取值範圍是0到128。該值越小,表示材質越粗糙,點光源發射的光線照射到上面,也可以產生較大的亮點。該值越大,表示材質越類似於鏡面,光源照射到上面後,產生較小的亮點。GL_EMISSION屬性由四個值組成,表示一種顏色。OpenGL認爲該材質本身就微微的向外發射光線,以至於眼睛感覺到它有這樣的顏色,但這光線又比較微弱,以至於不會影響到其它物體的顏色。

void init()
{
	// 計算五角星有關數據
	get_pentagram();
	// 設置逆時針排列的點圍成的平面爲正面
	glFrontFace(GL_CCW);
	// 設置不繪製背面,節省算力同時不會出現背面覆蓋正面的情況
	glCullFace(GL_BACK);
	glEnable(GL_CULL_FACE);
	// 啓用抗鋸齒(使線平滑)
	glEnable(GL_BLEND);
	glEnable(GL_LINE_SMOOTH);
	glHint(GL_LINE_SMOOTH_HINT, GL_FASTEST);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	// 設置材質和光照的信息
	// 有關光照與材質:https://blog.csdn.net/timidsmile/article/details/7017197
	GLfloat mat_ambient[4] = { 1.0f, 1.0f, 1.0f, 0.0f };
	GLfloat mat_diffuse[4] = { 1.0f, 1.0f, 1.0f, 0.0f };
	GLfloat mat_specular[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
	GLfloat mat_shininess[4] = { 100.0f };
	GLfloat light_ambient[4] = { 0.2f, 0.2f, 0.2f, 0.0f };
	GLfloat light_diffuse[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
	GLfloat light_specular[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
	GLfloat light_position[4] = { 0.0f, 6.0f, 0.0f, 1.0f };
	// 設置正向面的材質和光源的光照
	glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
	glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
	glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
	glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
	glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
	glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
	glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
	glLightfv(GL_LIGHT0, GL_POSITION, light_position);
	// 設置顏色材料,使光照模式下仍然可以顯示原本的顏色
	glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
	glEnable(GL_COLOR_MATERIAL);
	// 啓用平滑着色功能
	glShadeModel(GL_SMOOTH);
	// 啓用光照功能
	glEnable(GL_LIGHTING);
	// 啓用0號光源
	glEnable(GL_LIGHT0);
	// 啓用檢測深度
	glEnable(GL_DEPTH_TEST);
	// 環境顏色設置爲白色
	glClearColor(1.0, 1.0, 1.0, 1.0);
}

在這裏插入圖片描述

可以看出,在(0, 0, 6)處設置一點光源,從上方照射三個物體,物體的側面由於受到光照較少,會產生出陰影的質感。下面是變換光源位置以及光源三種屬性後的不同效果。爲了更好地展現光照效果,此處將環境顏色設置成深色。

從Z軸負向,即底部向上照射三個物體:

在這裏插入圖片描述

從頂部向下照射三個物體,但去除了環境光,只保留漫反射和鏡面反射:

在這裏插入圖片描述

光照之後的任務要求即爲繪製陰影。陰影是一種高級光照渲染,會爲物體進一步增加立體感。陰影一般由深度貼圖渲染實現,本節的課件中介紹了一種簡單的繪製陰影的方法,即手動操作變換矩陣,將原物品直接映射到一個平面上。這種方法需要繪製原物品兩次,並且需要手動計算陰影變換矩陣,不太靈活,代碼耦合性較高且手動計算複雜。下面僅實現了立方體的陰影:

在這裏插入圖片描述

void cube_shadow(GLfloat x, GLfloat y, GLfloat z, GLfloat size)
{
	GLfloat m[16] = { 0.0f };
	m[0] = m[5] = m[10] = 1.0f;
	m[11] = -1.0f / z;
	glMatrixMode(GL_MODELVIEW);
	glPushMatrix();
	glTranslatef(x, y, z);
	glMultMatrixf(m);
	glTranslatef(-x, -y, -z);
	color_cube(size);
	glPopMatrix();
}

添加陰影后效果如下,但可以看出陰影也是繪製出的多面體,同樣也要受到全局光照的影響,其原本的顏色在光照下變亮,顯然不符合陰影的效果。如果要修改,需要改動多面體本身的繪製代碼,單獨添加與光照有關的設置,非常麻煩,本代碼中沒有涉及,僅僅實踐了簡單的陰影繪製方法而已:

在這裏插入圖片描述


附錄:完整代碼

#include<GL/glut.h>
#include<math.h>
#include<iostream>
#define DEPTH 4
#define PI 3.1415926
using namespace std;

void frame()
{
	// 繪製三維座標架
	glColor3f(0.3f, 0.3f, 0.3f);
	glLineWidth(0.75);
	glBegin(GL_LINES);
	glVertex3f(-100.0f, 0.0f, 0.0f);
	glVertex3f(100.0f, 00.0f, 0.0f);
	glVertex3f(0.0f, -100.0f, 0.0f);
	glVertex3f(0.0f, 100.0f, 0.0f);
	glVertex3f(0.0f, 0.0f, -100.0f);
	glVertex3f(0.0f, 0.0f, 100.0f);
	glEnd();
	// 繪製XOY平面
	glColor4f(0.8f, 0.8f, 0.8f, 0.5f);
	glNormal3f(0.0f, 0.0f, 1.0f);
	glBegin(GL_QUADS);
	glVertex3f(8.0f, 8.0f, 0.0f);
	glVertex3f(-8.0f, 8.0f, 0.0f);
	glVertex3f(-8.0f, -8.0f, 0.0f);
	glVertex3f(8.0f, -8.0f, 0.0f);
	glEnd();
}

void normalize(GLfloat* v)
{
	GLfloat d = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
	v[0] /= d; v[1] /= d; v[2] /= d;
}

void divide_triangle(GLfloat* a, GLfloat* b, GLfloat* c, int depth)
{
	if (depth > 0) {
		GLfloat ab[3], ac[3], bc[3];
		for (unsigned int i = 0; i < 3; i++)
			ab[i] = a[i] + b[i];
		normalize(ab);
		for (unsigned int i = 0; i < 3; i++)
			ac[i] = a[i] + c[i];
		normalize(ac);
		for (unsigned int i = 0; i < 3; i++)
			bc[i] = b[i] + c[i];
		normalize(bc);
		divide_triangle(a, ab, ac, depth - 1);
		divide_triangle(b, bc, ab, depth - 1);
		divide_triangle(c, ac, bc, depth - 1);
		divide_triangle(ab, bc, ac, depth - 1);
	}
	else {
		glBegin(GL_TRIANGLES);
		glNormal3fv(a);
		glVertex3fv(a);
		glNormal3fv(b);
		glVertex3fv(b);
		glNormal3fv(c);
		glVertex3fv(c);
		glEnd();
	}
}

void sphere()
{
	GLfloat tetrahedron_vertex[][3] = {
		0.0f,		 0.0f,		 1.0f,
		0.0f,		 0.942809f, -0.333333f,
	   -0.816497f, -0.471405f, -0.333333f,
		0.816497f, -0.471405f, -0.333333f
	};
	glColor3f(1.00f, 0.00f, 0.00f);
	divide_triangle(tetrahedron_vertex[0], tetrahedron_vertex[2], tetrahedron_vertex[1], DEPTH);
	divide_triangle(tetrahedron_vertex[0], tetrahedron_vertex[3], tetrahedron_vertex[2], DEPTH);
	divide_triangle(tetrahedron_vertex[0], tetrahedron_vertex[1], tetrahedron_vertex[3], DEPTH);
	divide_triangle(tetrahedron_vertex[1], tetrahedron_vertex[2], tetrahedron_vertex[3], DEPTH);
}

GLfloat pentagram_vertex[5][3];
GLfloat pentagon_vertex[5][3];

void get_pentagram()
{
	// 五角星看作在圓上內接的五邊形的頂點連成的,此處設置外接圓半徑[0, 1]
	GLfloat r = 1.0f;
	// 五角星可以在外接圓上旋轉,此處設置旋轉角度[0, 360)
	GLfloat rotate = 18.0;
	// 依次通過外接圓計算正五邊形的五個頂點橫縱座標
	GLfloat tmp[5][2];
	for (int i = 0; i < 5; i++) {
		tmp[i][0] = (GLfloat)(r * cos(((72.0 * (GLfloat)i + rotate) / 360.0) * (2 * PI)));
		tmp[i][1] = (GLfloat)(r * sin(((72.0 * (GLfloat)i + rotate) / 360.0) * (2 * PI)));
	}
	// 將正五邊形順序的五個頂點對應到五角星順序的五個頂點(0, 1, 2, 3, 4) -> (0, 2, 4, 1, 3)
	for (int i = 0, j = 0; i < 5; i++, j = j + 2) {
		int k = j % 5;
		pentagram_vertex[i][1] = tmp[k][0];
		pentagram_vertex[i][2] = tmp[k][1];
	}
	// 五角星的邊相交得到中間的小五邊形頂點,計算以便繪圖時的着色
	GLfloat x[4], y[4];
	for (int i = 0; i < 5; i++) {
		int v[4];
		for (int j = 0; j < 4; j++)
			v[j] = (i + j) % 5;
		for (int j = 0; j < 4; j++)
			x[j] = pentagram_vertex[v[j]][1], y[j] = pentagram_vertex[v[j]][2];
		tmp[i][0] = ((x[2] - x[3]) * (x[1] * y[0] - x[0] * y[1])
			- (x[0] - x[1]) * (x[3] * y[2] - x[2] * y[3])) /
			((x[2] - x[3]) * (y[0] - y[1]) - (x[0] - x[1]) * (y[2] - y[3]));
		tmp[i][1] = ((y[2] - y[3]) * (y[1] * x[0] - y[0] * x[1])
			- (y[0] - y[1]) * (y[3] * x[2] - y[2] * x[3])) /
			((y[2] - y[3]) * (x[0] - x[1]) - (y[0] - y[1]) * (x[2] - x[3]));
	}
	for (int i = 0, j = 0; i < 5; i++, j = j + 2) {
		int k = j % 5;
		pentagon_vertex[i][1] = tmp[k][0];
		pentagon_vertex[i][2] = tmp[k][1];
	}
	for (unsigned int i = 0; i < 5; i++) {
		pentagram_vertex[i][0] = 0.0f;
		pentagon_vertex[i][0] = 0.0f;
	}
}

void pentagram()
{
	// 下面的段落繪製五角星中心所圍成小正五邊形的着色
	glColor3f(1.0f, 1.0f, 0.0f);
	glNormal3f(1.0f, 0.0f, 0.0f);
	glBegin(GL_POLYGON);
	for (unsigned int i = 0; i < 5; i++)
		glVertex3fv(pentagon_vertex[4-i]);
	glEnd();
	// 下面的段落繪製五角星的線
	glColor3f(0.0, 0.0, 0.0);
	// 設置線的寬度(0, 10]
	glLineWidth(2.5);
	glBegin(GL_LINE_LOOP);
	for (int i = 0; i < 5; i++)
		glVertex3fv(pentagram_vertex[i]);
	glEnd();
	// 下面的段落繪製五角星的五個頂點(實心圓)
	glColor3f(0.0, 0.0, 0.0);
	// 設置實心圓的半徑
	GLfloat radius = 0.05f;
	// 設置用來擬合圓形的多邊形邊個數
	int sections = 50;
	for (int i = 0; i < 5; i++) {
		glBegin(GL_TRIANGLE_FAN);
		glVertex3fv(pentagram_vertex[i]);
		for (int j = 0; j <= sections; j++)
			glVertex3f(0.0f, (GLfloat)(pentagram_vertex[i][1] + radius * cos(j * 2.0 * PI / sections)),
				(GLfloat)(pentagram_vertex[i][2] + radius * sin(j * 2.0 * PI / sections)));
		glEnd();
	}
}

void color_cube(GLfloat size)
{
	// 設置立方體的八個頂點座標
	static const GLfloat vertex[][3] = {
		0.0f, 0.0f, 0.0f,
		size, 0.0f, 0.0f,
		0.0f, size, 0.0f,
		size, size, 0.0f,
		0.0f, 0.0f, size,
		size, 0.0f, size,
		0.0f, size, size,
		size, size, size
	};
	// 設置繪製六個面時頂點的順序
	static const GLint index[][4] = {
		0, 2, 3, 1,
		0, 4, 6, 2,
		0, 1, 5, 4,
		4, 5, 7, 6,
		1, 3, 7, 5,
		2, 6, 7, 3
	};
	// 指定六個面的法向
	static const GLfloat normal[][3] = {
		0.0f, 0.0f, -1.0f,
		-1.0f, 0.0f, 0.0f,
		0.0f, -1.0f, 0.0f,
		0.0f, 0.0f, 1.0f,
		1.0f, 0.0f, 0.0f,
		0.0f, 1.0f, 0.0f
	};
	// 繪製六個面
	glBegin(GL_QUADS);
	for (unsigned int i = 0; i < 6; i++) {
		glNormal3fv(normal[i]);
		for (unsigned int j = 0; j < 4; j++) {
			// 每個頂點的RGB顏色值和其頂點位置座標一致
			glColor3f(vertex[index[i][j]][0] / size,
				vertex[index[i][j]][1] / size, vertex[index[i][j]][2] / size);
			glVertex3fv(vertex[index[i][j]]);
		}
	}
	glEnd();
}

void cube_shadow(GLfloat x, GLfloat y, GLfloat z, GLfloat size)
{

	GLfloat m[16] = { 0.0f };
	m[0] = m[5] = m[10] = 1.0f;
	m[11] = -1.0f / z;
	glMatrixMode(GL_MODELVIEW);
	glPushMatrix();
	glTranslatef(x, y, z);
	glMultMatrixf(m);
	glTranslatef(-x, -y, -z);
	color_cube(size);
	glPopMatrix();
}

void display()
{
	// 設置背景爲白色
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	// 加載單位陣
	glLoadIdentity();
	// 設置相機的位置和視角
	gluLookAt(7, 4, 4, 0.0, 0.0, 0.0, 0, 0, 1);
	// 繪製座標架以及XOY平面
	frame();
	// 平移座標系,讓三個待繪製物品的底部排列在X軸上
	glTranslatef(0.0f, 0.0f, 1.0f);
	// 在中心繪製三維彩色立方體,並繪製簡單陰影
	glTranslatef(-1.0f, -1.0f, -1.0f);
	color_cube(2.0f);
	cube_shadow(0.0f, 0.0f, 10.0f, 1.5f);
	glTranslatef(1.0f, 1.0f, 1.0f);
	// 在左側(Y軸負半軸)繪製紅色球面
	glTranslatef(0.0f, -4.0f, 0.0f);
	sphere();
	glTranslatef(0.0f, 4.0f, 0.0f);
	// 在右側(Y軸正半軸)繪製平面的五角星
	glTranslatef(0.0f, 4.0f, 0.0f);
	pentagram();
	glTranslatef(0.0f, -4.0f, 0.0f);
	// 刷新幀緩存
	glutSwapBuffers();
}

// 窗口大小自適應函數,使得窗口大小改變時仍保持圖形的比例不變
// 有關窗口自適應函數:http://blog.sina.com.cn/s/blog_5497dc110102w8qh.html
void reshape(int w, int h)
{
	glViewport(0, 0, (GLsizei)w, (GLsizei)h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(60.0, (GLfloat)w / (GLfloat)h, 1.0, 20.0);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	gluLookAt(7, 4, 4, 0.0, 0.0, 0.0, 0, 0, 1);
}

void init()
{
	// 計算五角星有關數據
	get_pentagram();
	// 設置逆時針排列的點圍成的平面爲正面
	glFrontFace(GL_CCW);
	// 設置不繪製背面,節省算力同時不會出現背面覆蓋正面的情況
	glCullFace(GL_BACK);
	glEnable(GL_CULL_FACE);
	// 啓用抗鋸齒(使線平滑)
	glEnable(GL_BLEND);
	glEnable(GL_LINE_SMOOTH);
	glHint(GL_LINE_SMOOTH_HINT, GL_FASTEST);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	// 設置材質和光照的信息
	// 有關光照與材質:https://blog.csdn.net/timidsmile/article/details/7017197
	GLfloat mat_ambient[4] = { 1.0f, 1.0f, 1.0f, 0.0f };
	GLfloat mat_diffuse[4] = { 1.0f, 1.0f, 1.0f, 0.0f };
	GLfloat mat_specular[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
	GLfloat mat_shininess[4] = { 100.0f };
	GLfloat light_ambient[4] = { 0.2f, 0.2f, 0.2f, 0.0f };
	GLfloat light_diffuse[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
	GLfloat light_specular[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
	GLfloat light_position[4] = { 0.0f, 6.0f, 0.0f, 1.0f };
	// 設置正向面的材質和光源的光照
	glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
	glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
	glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
	glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
	glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
	glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
	glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
	glLightfv(GL_LIGHT0, GL_POSITION, light_position);
	// 設置顏色材料,使光照模式下仍然可以顯示原本的顏色
	glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
	glEnable(GL_COLOR_MATERIAL);
	// 啓用平滑着色功能
	glShadeModel(GL_SMOOTH);
	// 啓用光照功能
	glEnable(GL_LIGHTING);
	// 啓用0號光源
	glEnable(GL_LIGHT0);
	// 啓用檢測深度
	glEnable(GL_DEPTH_TEST);
	// 環境顏色設置爲白色
	glClearColor(1.0, 1.0, 1.0, 1.0);
}

int main(int argc, char** argv)
{
	glutInit(&argc, argv);
	// 設置雙緩衝和RGB顏色模式
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
	// 設置窗口大小、位置和名稱
	glutInitWindowSize(1000, 500);
	glutInitWindowPosition(100, 100);
	glutCreateWindow("sphere");
	init();
	// 設置繪製函數、窗口大小自適應函數
	glutDisplayFunc(display);
	glutReshapeFunc(reshape);
	// 進入主循環
	glutMainLoop();
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章