這裡寫目錄标題
-
- 一、基本原理
- 二、代碼(完整版本)
-
- 2.1 頭檔案
- 2.2 mian函數
- 2.3 OnReshape防止變形函數
- 2.4 Init初始化函數
- 2.5 OnTimer函數
- 2.6 DrawCircle畫軌道函數
- 2.7 gltDrawSphere繪制星球函數
- 2.8 OnDisplay函數
- 三、注意事項
手把手制作太陽系運作模型,紋理貼圖、模型變換、動畫、計算機圖形學(OpenGL、C++實作、超級詳細) 一、基本原理
- 使用封裝的gltDrawSphere繪制星球,DrawCircle繪制軌道
- 在封裝的Init函數中開啟燈光,OnDisplay函數中繪制時候寫好光照參數
- 在封裝的Init函數中使用auxDIBImageLoad函數讀取bmp檔案的寬、高與data
- 在封裝的OnDisplay函數中使用glPushMatrix與glPopMatrix依次繪制每一個星球
- 使用glutTimerFun函數實作動畫
二、代碼(完整版本)
2.1 頭檔案
ifndef _HERDER_H_
#define _HERDER_H_
#include <GL/glut.h>
#include <GL/GLAux.h>
#include <tchar.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
AUX_RGBImageRec* Images[10];
GLuint ImagesIDs[11]; //索引
char* szFiles[10] = {
("F:\\OGL\\sun\\Sun.bmp"),
("F:\\OGL\\sun\\Mercury.bmp"),
("F:\\OGL\\sun\\Venus.bmp"),
("F:\\OGL\\sun\\Earth.bmp"),
("F:\\OGL\\sun\\Mars.bmp"),
("F:\\OGL\\sun\\Jupiter.bmp"),
("F:\\OGL\\sun\\Saturn.bmp"),
("F:\\OGL\\sun\\Uranus.bmp"),
("F:\\OGL\\sun\\Neptune.bmp"),
("F:\\OGL\\sun\\Moon.bmp"),};
GLubyte* pImg;
GLint iWidth, iHeight;
#define PI 3.1415926
static float year = 0, month = 0, day = 0, angle = 30;
GLint W, H, width, height;
float pox = 2, poy = 3, poz = 8; //照相機的位置
GLint fovy = 60;
void Init();
void OnDisplay();
void OnReshape(int, int);
void OnTimer(int);
void DrawCircle(GLdouble);
void gltDrawSphere(GLfloat, GLint, GLint);
#endif
2.2 mian函數
int main(int argc, char* argv[]){
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
glutInitWindowSize(400, 400);
glutInitWindowPosition(100, 100);
glutCreateWindow("太陽系");
Init();
glutReshapeFunc(OnReshape);
glutDisplayFunc(&OnDisplay);
glutTimerFunc(100, OnTimer, 1);
glutMainLoop();
return 0;
}
2.3 OnReshape防止變形函數
void OnReshape(int w, int h){
W = w; H = h;
width = W; height = H;
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, (GLfloat)w / (GLfloat)h, 1, 20);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();}
2.4 Init初始化函數
void Init(){
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
for (int i = 0; i < 10; i++){
glGenTextures(1, &ImagesIDs[i]); //生成紋理
glBindTexture(GL_TEXTURE_2D, ImagesIDs[i]); //綁定紋理
//vs2019下必須進行轉化
WCHAR wfilename[256];
memset(wfilename, 0, sizeof(wfilename));
//該函數映射一個字元串到一個寬字元(unicode)的字元串
MultiByteToWideChar(CP_ACP, 0, szFiles[i], strlen(szFiles[i]) + 1, wfilename, sizeof(wfilename) / sizeof(wfilename[0]));
Images[i] = auxDIBImageLoad(wfilename); //加載圖檔
iWidth = Images[i]->sizeX;
iHeight = Images[i]->sizeY;
pImg = Images[i]->data;
//裝載紋理
glTexImage2D(GL_TEXTURE_2D, 0, 3, iWidth, iHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, pImg);
//紋理過濾、紋理裁剪
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
//紋理環境
glTexEnvf(GL_TEXTURE_2D, GL_TEXTURE_ENV_MODE, GL_REPLACE);
//啟動紋理
glEnable(GL_TEXTURE_2D);
glEnable(GL_DEPTH_TEST);
}
glEnable(GL_LIGHTING); // 開啟光照效果
glEnable(GL_LIGHT0);
}
2.5 OnTimer函數
void OnTimer(int value){
day += angle;
glutPostRedisplay();
glutTimerFunc(100, OnTimer, 1);
}
2.6 DrawCircle畫軌道函數
//軌道函數
void DrawCircle(GLdouble R){
glPushMatrix();
glRotatef(90.0, 1.0, 0.0, 0.0);
glColor3f(1.0, 1.0, 1.0);
glBegin(GL_LINE_LOOP);
for (int i = 0; i < 1000; i++){
GLdouble angle1 = i * 2 * PI / 1000;
glVertex2d(R * cos(angle1), R * sin(angle1));
}
glEnd();
glPopMatrix();
}
2.7 gltDrawSphere繪制星球函數
//繪制星球
void gltDrawSphere(GLfloat fRadius, GLint iSlices, GLint iStacks){
GLfloat drho = (GLfloat)(3.141592653589) / (GLfloat)iStacks;
GLfloat dtheta = 2.0f * (GLfloat)(3.141592653589) / (GLfloat)iSlices;
GLfloat ds = 1.0f / (GLfloat)iSlices;
GLfloat dt = 1.0f / (GLfloat)iStacks;
GLfloat t = 1.0f;
GLfloat s = 0.0f;
GLint i, j;
for (i = 0; i < iStacks; i++){
GLfloat rho = (GLfloat)i * drho;
GLfloat srho = (GLfloat)(sin(rho));
GLfloat crho = (GLfloat)(cos(rho));
GLfloat srhodrho = (GLfloat)(sin(rho + drho));
GLfloat crhodrho = (GLfloat)(cos(rho + drho));
glBegin(GL_TRIANGLE_STRIP);
s = 0.0f;
}
for (j = 0; j <= iSlices; j++){
GLfloat theta = (j == iSlices) ? 0.0f : j * dtheta;
GLfloat stheta = (GLfloat)(-sin(theta));
GLfloat ctheta = (GLfloat)(cos(theta));
GLfloat x = stheta * srho;
GLfloat y = ctheta * srho;
GLfloat z = crho;
glTexCoord2f(s, t);
glNormal3f(x, y, z);
glVertex3f(x * fRadius, y * fRadius, z * fRadius);
x = stheta * srhodrho;
y = ctheta * srhodrho;
z = crhodrho;
glTexCoord2f(s, t - dt);
s += ds;
glNormal3f(x, y, z);
glVertex3f(x * fRadius, y * fRadius, z * fRadius);
}
glEnd();
t -= dt;
}
2.8 OnDisplay函數
void OnDisplay(){
glColor3f(1.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
year = day / 365;
month = day / 30;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(fovy, (GLfloat)W / (GLfloat)H, 2, 60.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(pox, poy, poz, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
//太陽光
GLfloat sun_mat_ambient[4] = { 1.0,1.0,1.0,0.0 };
GLfloat sun_mat_diffuse[4] = { 1.0,1.0,0.5,1.0 };
GLfloat sun_mat_specular[4 = { 1.0,1.0,1.0,1.0 };
GLfloat sun_mat_shininess[] = { 10.0 };
GLfloat sun_mat_emission[4]= { 0.1,0.1,0.1,1.0 };
GLfloat mat_ambient[4] = { 0.2,0.2,0.2,1.0 };
GLfloat mat_diffuse[4] = { 1.0,1.0,1.0,1.0 };
GLfloat mat_specular[4] = { 0.5,0.5,0.5,1.0 };
GLfloat mat_shininess[] = { 5.0 };
GLfloat light_position[]={ -10.0,10.0,0.0, 1.0};//光源位置
glLightfv(GL_LIGHT0, GL_POSITION, light_position); // 建立光源
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, sun_mat_ambient); // 材質設定
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, sun_mat_diffuse);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, sun_mat_specular);
glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, sun_mat_shininess);
glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, sun_mat_emission);
//繪制太陽
glPushMatrix();
glLightfv(GL_LIGHT0, GL_POSITION, light_position); // 建立光源
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, sun_mat_ambient); // 材質設定
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, sun_mat_diffuse);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, sun_mat_specular);
glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, sun_mat_shininess);
glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, sun_mat_emission);
glBindTexture(GL_TEXTURE_2D, ImagesIDs[0]);
glRotatef((GLfloat)month, 0.0, 1.0, 0.0); //太陽自轉
glRotatef(90.0, -1.0, 0.0, 0.0);
gltDrawSphere(1.0, 50, 50);
glPopMatrix();
//繪制水星
glPushMatrix();
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat_ambient); // 材質設定
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_diffuse);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess);
DrawCircle(2.0);//繪制水星的軌道
glRotatef((GLfloat)month / 2, 0.0, 1.0, 0.0); //水星圍繞太陽轉
glTranslatef(2, 0.0, 0.0); //向x軸右移,讓其在軌道上
glBindTexture(GL_TEXTURE_2D, ImagesIDs[1]);
glRotatef((GLfloat)month, 0.0, 1.0, 0.0);
glRotatef(90.0, -1.0, 0.0, 0.0);//自轉
gltDrawSphere(0.2, 10, 10);
glPopMatrix();
//繪制金星
glPushMatrix();
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat_ambient); // 材質設定
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_diffuse);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess);
DrawCircle(3.0);
glRotatef((GLfloat)month / 3, 0.0, 1.0, 0.0); //金星圍繞太陽轉
glTranslatef(3, 0.0, 0.0); //向x軸右移
glRotatef(30.0, -1.0, 0.0, 0.0);
glBindTexture(GL_TEXTURE_2D, ImagesIDs[2]);
glRotatef((GLfloat)month, 0.0, 1.0, 0.0);
glRotatef(90.0, -1.0, 0.0, 0.0);
gltDrawSphere(0.25, 10, 10);
glPopMatrix();
//繪制地月系統
glPushMatrix();
//繪制地球
DrawCircle(4.5);
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat_ambient); // 材質設定
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_diffuse);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess);
glRotatef((GLfloat)year, 0.0, 1.0, 0.0); //地球公轉
glTranslatef(4.5, 0.0, 0.0); //向x軸右移
glRotatef(30.0, -1.0, 0.0, 0.0);//讓地球傾斜
glPushMatrix();
glBindTexture(GL_TEXTURE_2D, ImagesIDs[3]);
glRotatef((GLfloat)month, 0.0, 1.0, 0.0);
glRotatef(90.0, -1.0, 0.0, 0.0);
gltDrawSphere(0.4, 20, 20);
glPopMatrix();
//繪制月亮
glPushMatrix();
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat_ambient); // 材質設定
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_diffuse);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess);
DrawCircle(1.0);
glBindTexture(GL_TEXTURE_2D, ImagesIDs[9]);
glRotatef((GLfloat)month, 0.0, 1.0, 0.0); //月球繞地球轉
glTranslatef(1.0, 0.0, 0.0);
glRotatef((GLfloat)month, 0.0, 1.0, 0.0);
glRotatef(90.0, -1.0, 0.0, 0.0);
gltDrawSphere(0.15, 10, 10);
glPopMatrix();
glPopMatrix();
//繪制火星
glPushMatrix();
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat_ambient); // 材質設定
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_diffuse);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess);
DrawCircle(6.0);
glBindTexture(GL_TEXTURE_2D, ImagesIDs[4]);
glRotatef((GLfloat)month / 1.5, 0.0, 1.0, 0.0);
glTranslatef(6.0, 0.0, 0.0);
glRotatef(30, -1, 0, 0);
glRotatef((GLfloat)month, 0.0, 1.0, 0.0);
glRotatef(90, -1, 0, 0);
gltDrawSphere(0.3, 10, 10);
glPopMatrix();
//繪制木星
glPushMatrix();
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat_ambient); // 材質設定
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_diffuse);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess);
DrawCircle(7.0);
glBindTexture(GL_TEXTURE_2D, ImagesIDs[5]);
glRotatef((GLfloat)month / 4, 0.0, 1.0, 0.0);
glTranslatef(7.0, 0.0, 0.0);
glRotatef((GLfloat)month / 2, 0.0, 1.0, 0.0);
glRotatef(90, -1, 0, 0);
gltDrawSphere(0.42, 10, 10);
glPopMatrix();
//繪制土星
glPushMatrix();
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat_ambient); // 材質設定
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_diffuse);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess);
DrawCircle(8.0);
glBindTexture(GL_TEXTURE_2D, ImagesIDs[6]);
glRotatef((GLfloat)month / 3.5, 0.0, 1.0, 0.0);
glTranslatef(8.0, 0.0, 0.0);
glRotatef((GLfloat)month / 2, 0.0, 1.0, 0.0);
glRotatef(90, -1, 0, 0);
gltDrawSphere(0.35, 10, 10);
glPopMatrix();
//繪制天王星
glPushMatrix();
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat_ambient); // 材質設定
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_diffuse);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess);
DrawCircle(9.0);
glBindTexture(GL_TEXTURE_2D, ImagesIDs[7]);
glRotatef((GLfloat)month / 3, 0.0, 1.0, 0.0);
glTranslatef(9.0, 0.0, 0.0);
glRotatef(30, -1, 0, 0);
glRotatef((GLfloat)month / 2, 0.0, 1.0, 0.0);
glRotatef(90, -1, 0, 0);
gltDrawSphere(0.3, 10, 10);
glPopMatrix();
//繪制海王星
glPushMatrix();
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat_ambient); // 材質設定
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_diffuse);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess);
DrawCircle(10.0);
glBindTexture(GL_TEXTURE_2D, ImagesIDs[8]);
glRotatef((GLfloat)month / 2, 0.0, 1.0, 0.0);
glTranslatef(10.0, 0.0, 0.0);
glRotatef(30, -1, 0, 0);
glRotatef((GLfloat)month / 2, 0.0, 1.0, 0.0);
glRotatef(90, -1, 0, 0);
gltDrawSphere(0.25, 10, 10);
glPopMatrix();
glutSwapBuffers();
}
三、注意事項
- 除了頭檔案,其他都是依次放到cpp檔案中就可以
- 代碼使用vs2019,其他版本的可能會報錯,直接百度錯誤就可以很快的解決
- .glutXXXX的模型都是很簡陋的,沒有紋理UV坐标的模型,使用glutSolidSphere函數是無法進行貼圖。是以寫了一個gltDrawSphere函數繪制星球
- 我使用的是vs2019,在使用加載的紋理圖檔之前,要把路徑字元串轉化為寬字元字元串,這一點可以檢視上面glutSolidSphere函數代碼。其他版本可能不需要轉化,去掉就可以。
- 求個三連!不明白的可以評論或者私信我~