opengl 太陽、地球、月亮 酷炫實例(二)

自己是這方面的小白,希望大神可以對有問題以及可以優化的地方提出來。也歡迎指出不足和吐槽。希望幫到小白。

opengl 太陽、地球、月亮 酷炫實例(一):
https://blog.csdn.net/qq_40515692/article/details/100778870

自己參考得比較多的網站是這個:
http://www.cppblog.com/doing5552/archive/2009/01/08/71532.html
以及:https://blog.csdn.net/xie_zi/article/details/1911406

所有代碼都可以去github免費下載:
https://github.com/Iamttp/OpenGLTest

好先上這一節的效果圖。這一節是上一節的繼續,在上一節的代碼基礎上添加了場景漫遊,可以用鍵盤控制“相機”了。
在這裏插入圖片描述
首先是添加場景漫遊相關的基礎函數,我們先假設初始化相機位於(0,0,3)的位置,相機鏡頭對着(0,0,-1)方向,那麼就是相當於你的眼睛是相機,顯示屏在原點,你和顯示屏的距離爲3(好吧,並不直觀 / w \)。

gluLookAt函數提供了一個簡單直觀的方法來設置照相機的位置和方向。它有三組參數,每一組由三個浮點型數組成。前三個參數表明照相機的位置,第二組參數定義照相機觀察的方向,最後一組表明向上的向量,這個通常設爲(0.0,1.0,0.0)。也就是說照相機並沒有傾斜。如你想看到所有的物體都是倒置的則可以設置爲(0.0,-1.0,0.0)。

那麼我們定義orientMe表示根據傳入的角度對lx,lz進行更改,即給定和y軸的角度,求出方向向量。
定義moveMeFlat表示根據給定的距離對當前x,z進行更改,即給定距離,然後和當前方向相乘,然後更新x,z。

static float angle = 0.0, ratio;  // angle繞y軸的旋轉角,ratio窗口高寬比
static float x = 0.0f, y = 0.0f, z = 3.0f;  //相機位置
static float lx = 0.0f, ly = 0.0f, lz = -1.0f;  //視線方向,初始設爲沿着Z軸負方向

void orientMe(float ang) {
	lx = sin(ang);
	lz = -cos(ang);
	glLoadIdentity();
	gluLookAt(x, y, z, x + lx, y + ly, z + lz, 0.0f, 1.0f, 0.0f);
}
void moveMeFlat(int direction) {
	x = x + direction * (lx) * 0.1;
	z = z + direction * (lz) * 0.1;
	glLoadIdentity();
	gluLookAt(x, y, z, x + lx, y + ly, z + lz, 0.0f, 1.0f, 0.0f);
}

然後是按鍵控制,這個比較簡單,在主函數裏面加入。

glutSpecialFunc(&processSpecialKeys);  // 按鍵

然後定義按鍵函數即可,左右方向鍵,將照相機繞y軸旋轉,上下方向鍵,將前後方向移動照相機。調用上面提到的函數。

void processSpecialKeys(int key, int x, int y) {
	switch (key) {
	case GLUT_KEY_LEFT:
		angle -= 0.01f;
		orientMe(angle);
		break;
	case GLUT_KEY_RIGHT:
		angle += 0.01f;
		orientMe(angle);
		break;
	case GLUT_KEY_UP:
		moveMeFlat(1);
		break;
	case GLUT_KEY_DOWN:
		moveMeFlat(-1);
		break;
	}
}

最後一步我們添加 glutReshapeFunc,設置觀察方式。具體的代碼我就直接放在最終代碼那裏了。最終代碼爲:

#include <gl/glut.h>
#include <stdio.h>
#include <time.h>
#include <cmath>

static float angle = 0.0, ratio;  // angle繞y軸的旋轉角,ratio窗口高寬比
static float x = 0.0f, y = 0.0f, z = 3.0f;  //相機位置
static float lx = 0.0f, ly = 0.0f, lz = -1.0f;  //視線方向,初始設爲沿着Z軸負方向
static int my_angle = 0; // 表示旋轉的角度

/**
 * 定義觀察方式
 */
void changeSize(int w, int h) {
	//除以0的情況
	if (h == 0) h = 1;
	ratio = 1.0f * w / h;
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	//設置視口爲整個窗口大小
	glViewport(0, 0, w, h);
	//設置可視空間
	gluPerspective(45, ratio, 1, 1000);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	gluLookAt(x, y, z, x + lx, y + ly, z + lz, 0.0f, 1.0f, 0.0f);
}
/**
 * 視野漫遊函數
 */
void orientMe(float ang) {
	lx = sin(ang);
	lz = -cos(ang);
	glLoadIdentity();
	gluLookAt(x, y, z, x + lx, y + ly, z + lz, 0.0f, 1.0f, 0.0f);
}
void moveMeFlat(int direction) {
	x = x + direction * (lx) * 0.1;
	z = z + direction * (lz) * 0.1;
	glLoadIdentity();
	gluLookAt(x, y, z, x + lx, y + ly, z + lz, 0.0f, 1.0f, 0.0f);
}

/**
 * 加入按鍵控制
 */
void processSpecialKeys(int key, int x, int y) {
	switch (key) {
	case GLUT_KEY_LEFT:
		angle -= 0.01f;
		orientMe(angle);
		break;
	case GLUT_KEY_RIGHT:
		angle += 0.01f;
		orientMe(angle);
		break;
	case GLUT_KEY_UP:
		moveMeFlat(1);
		break;
	case GLUT_KEY_DOWN:
		moveMeFlat(-1);
		break;
	}
}

void myDisplay(void) {
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	// 太陽
	glPushMatrix();
	glColor3f(1.0, 1.0, 0.0);
	glutSolidSphere(0.15, 200, 200);
	glPopMatrix();

	// 地球
	glPushMatrix();
	glColor3f(0.0, 0.0, 1.0);
	glRotated(my_angle, 1.0, 1.0, 1.0);  //公轉
	glTranslatef(0.5, 0.5, -0.5);        //平移
	glutSolidSphere(0.1, 200, 200);
	glPopMatrix();

	// 月亮
	glPushMatrix();
	glColor3f(1.0, 1.0, 1.0);
	glRotated(my_angle, 1.0, 1.0, 1.0);  //然後移動到地球旁邊旋轉
	glTranslatef(0.5, 0.5, -0.5);        //平移
	glRotated(my_angle, 1.0, 1.0, 1.0);  //先假設原點爲地球旋轉
	glTranslatef(-0.15, -0.15, 0.15);    //平移
	glutSolidSphere(0.05, 200, 200);     //繪製月亮
	glPopMatrix();

	glutSwapBuffers();
}
/**
 * 計時增加角度
 */
void myIdle(void) {
	static int mm = 0;
	mm++;
	if (mm % 300000 == 0) {
		++my_angle;
		if (my_angle >= 360) my_angle = 0;
		myDisplay();
	}
}

int main(int argc, char* argv[]) {
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
	glutInitWindowPosition(100, 100);
	glutInitWindowSize(1000, 1000);
	glutCreateWindow("太陽,地球和月亮");  // 改了窗口標題

	glutDisplayFunc(&myDisplay);
	glutIdleFunc(&myIdle);  // 表示在CPU空閒的時間調用某一函數
	glutSpecialFunc(&processSpecialKeys);  // 按鍵
	glutReshapeFunc(&changeSize);

	// 在OpenGL中,默認是沒有開啓深度檢測的,後繪製的物體覆蓋先繪製的物體。
	// GL_DEPTH_TEST 用來開啓更新深度緩衝區的功能
	glEnable(GL_DEPTH_TEST);
	glutMainLoop();
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章