天天看点

手把手制作太阳系运行模型,纹理贴图、模型变换、动画、计算机图形学(OpenGL、C++实现、超级详细)

这里写目录标题

    • 一、基本原理
    • 二、代码(完整版本)
      • 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函数代码。其他版本可能不需要转化,去掉就可以。
  • 求个三连!不明白的可以评论或者私信我~