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

Posted 鲨鱼小猫

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了手把手制作太阳系运行模型,纹理贴图模型变换动画计算机图形学(OpenGLC++实现超级详细)相关的知识,希望对你有一定的参考价值。

在这里插入图片描述

一、基本原理

  • 使用封装的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以上是关于手把手制作太阳系运行模型,纹理贴图模型变换动画计算机图形学(OpenGLC++实现超级详细)的主要内容,如果未能解决你的问题,请参考以下文章

基于全景照片和场景模型计算导出纹理贴图

将地球纹理贴图应用到 Sphere

计算机图形学----基于3D图形开发技术

Unity对项目性能优化的实现

Unity3D纹理贴图 ( 纹理 Texture 简介 | 为 3D 模型设置纹理贴图 )

将纹理 3d 模型和纹理从搅拌机导出到 xna 4.0