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

準備把自己這幾天的學習opengl的經驗寫下來,自己是這方面的小白,希望大神可以對有問題以及可以優化的地方提出來。也歡迎指出不足和吐槽。希望幫到小白。

自己參考得比較多的網站是這個:
http://www.cppblog.com/doing5552/archive/2009/01/08/71532.html
第一個實例也是上面的網站給出來的,但是進行了一點點優化。

所有代碼都可以去github免費下載(不怎麼喜歡CSDN的積分下載):
https://github.com/Iamttp/OpenGLTest

我一直比較推崇實例學習,並且網上opengl的實例比較少,所以會一直用實例。好先上這一節的效果圖。

在這裏插入圖片描述

先把基本的框架弄出來,功能就是畫一個白色的矩形,然後空閒時調用,會一直更新my_angle,如果不理解這裏,可以查看剛剛提到的網站:http://www.cppblog.com/doing5552/archive/2009/01/08/71532.html

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

// 表示旋轉的角度
static int my_angle = 0;

void myDisplay(void) {
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glRectf(-0.5f, -0.5f, 0.5f, 0.5f);
	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空閒的時間調用某一函數
	// 在OpenGL中,默認是沒有開啓深度檢測的,後繪製的物體覆蓋先繪製的物體。
	// GL_DEPTH_TEST 用來開啓更新深度緩衝區的功能
	glEnable(GL_DEPTH_TEST);
	glutMainLoop();
	return 0;
}

然後就可以更改myDisplay函數,來渲染地球月亮和太陽,這裏太陽是靜止的,地球就先調用函數:glTranslatef(0.5, 0.5, -0.5); //平移,參數分別表示平移的座標xyz。

那爲什麼是0.5呢?
OpenGL僅當3D座標在3個軸(x、y和z)上都爲-1.0到1.0的範圍內時才處理它。所有在所謂的標準化設備座標(Normalized Device Coordinates)範圍內的座標纔會最終呈現在屏幕上(在這個範圍以外的座標都不會顯示)。

那爲什麼是0.5, 0.5, -0.5呢?
因爲我想呈現三維效果,然後就假設旋轉的軸是1,1,1,對着屏幕的右邊爲x正向,上邊爲y正向,屏幕朝外爲z正向。

然後就是月亮,對於月亮,先假設原點爲地球,讓月亮繞着原點旋轉,然後在平移到地球周圍。注意渲染順序是從下往上。
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); //平移

然後總的代碼就是:

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

// 表示旋轉的角度
static int my_angle = 0;

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空閒的時間調用某一函數
	// 在OpenGL中,默認是沒有開啓深度檢測的,後繪製的物體覆蓋先繪製的物體。
	// GL_DEPTH_TEST 用來開啓更新深度緩衝區的功能
	glEnable(GL_DEPTH_TEST);
	glutMainLoop();
	return 0;
}

這裏有一個奇怪的地方就是深度(z方向上)有問題,月亮有時候本應該被遮擋卻會在地球上面。解決方法是在glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);後面添加代碼

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(75, 1, 0.001f, 1000000000000.0f);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	gluLookAt(0, 0, 3, 0, 0, -1, 0.0f, 1.0f, 0.0f);

這樣你的太陽、地球、月亮有“近大遠小”的透視效果。並啓動了深度測試(解決深度(z方向上)的問題)。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章