準備把自己這幾天的學習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方向上)的問題)。