OpenGL 地球-纹理光照 自动旋转 鼠标拖动旋转 键盘实现缩放

本文介绍了使用OpenGL在VS2005环境中制作可旋转地球仪的教程,涉及键盘控制、光照设置、纹理加载和鼠标交互。通过MyTexMgr类实现纹理管理,用户可以控制放大缩小和鼠标操作来探索地球表面。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

环境vs2005

需要配置文件:

opengl地球-可旋转鼠标移动-其他文档类资源-优快云下载

Main.cpp

#include "MyTexMgr.h"

#include <iostream>
#include <stdlib.h>
#include <vector>
#include "MyTexMgr.h"

#ifdef __APPLE__
#include <OpenGL/OpenGL.h>
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif

using namespace std;

static float _angle = 30.0f;
static float _cameraAngle = 0.0f;

static int oldX;
static int oldY;
static float _rotX=0;
static float _rotY=0;
static float xyz[3]={1,1,1};
static float r=200;

static GLUquadric*	_earth;
static MyTexMgr		_texLoader;


//按按键操作
void handleKeypress(unsigned char key, int x, int y) {
	switch (key) {
		case 27: //Escape key
			exit(0);break;
		//按上则放大
		case 'w':
			xyz[0]+=0.1;xyz[1]+=0.1;xyz[2]+=0.1;
			//r+=10;
			glutPostRedisplay();break;
		//按下则缩小
		case 's':
			xyz[0]-=0.1;xyz[1]-=0.1;xyz[2]-=0.1;
			//r-=10;
			glutPostRedisplay();break;
	}
}

//定义光照
void initLight()
{
	GLfloat	ambientLight[]={0.2,0.2,0.2,1};
	GLfloat diffuseLight[]={0.8,.8,0.8,1};
	GLfloat specularLight[]={0.5,0.5,0.5,1};
	GLfloat posLight[]={400,240,1,1};
	GLfloat	specref[]={1,1,1,1};

	glLightModelfv(GL_LIGHT_MODEL_AMBIENT,ambientLight);
	//glLightfv(GL_LIGHT0,GL_POSITION,posLight); //指定光源位置
	glLightfv(GL_LIGHT0,GL_AMBIENT,ambientLight);
	glLightfv(GL_LIGHT0,GL_DIFFUSE,diffuseLight);
	glLightfv(GL_LIGHT0,GL_SPECULAR,specularLight);

	glMaterialf(GL_FRONT_AND_BACK,GL_SHININESS,128);
}

//定义D建模光照材质
void initRendering() {
	//创建二次曲面对象
	_earth=gluNewQuadric();
	//装载纹理
	_texLoader.loadTex(L"earth",L"E:/pic/earth1.bmp");
	initLight();

	glEnable(GL_LIGHT0);
	glEnable(GL_LIGHTING);
	glEnable(GL_DEPTH_TEST);
	glEnable(GL_LINE_SMOOTH);
 	//glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL,GL_SEPARATE_SPECULAR_COLOR);//镜面亮点
}

//删除建模
void deinitRendering()
{
	gluDeleteQuadric(_earth);
}

//窗口调整调用
void handleResize(int w, int h) {
	if (h==0)
	{
		h=1;
	}	
	glViewport(0, 0, w, h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(0,w,0,h,-200,200);
	glMatrixMode(GL_MODELVIEW);
}

//画地球
void drawEarth()
{
	static bool loaded=false;
	//纹理绑定到目标
	glBindTexture(GL_TEXTURE_2D,_texLoader.getTex(L"earth"));
	if (!loaded)
	{	
		//纹理坐标自动生成	
		glTexGeni(GL_S,GL_TEXTURE_GEN_MODE,GL_SPHERE_MAP);
		glTexGeni(GL_T,GL_TEXTURE_GEN_MODE,GL_SPHERE_MAP);
		//表面生成纹理坐标
		gluQuadricDrawStyle(_earth,GL_FILL);
		gluQuadricNormals(_earth,GLU_SMOOTH);
		gluQuadricTexture(_earth,GL_TRUE);
		
	}
	//生成球体
	glPushMatrix();
	{	
		glEnable(GL_TEXTURE_2D);
		glRotatef(-90,1,0,0);
		gluSphere(_earth,r,100,100);
		glDisable(GL_TEXTURE_2D);

	}
	glPopMatrix();
	
}

//绘制D场景
void drawScene() {
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	
	glMatrixMode(GL_MODELVIEW); //切换到绘图透视图
	glLoadIdentity(); //重置绘图透视图

	glPushMatrix();
	//实现缩放
	glScalef(xyz[0],xyz[1],xyz[2]);
	//此处需要把地球往后方移动防止放大的时候中间出现黑色圆圈
	glTranslatef(400,240,-200);
	//实现拖动旋转
	glRotatef(_rotX/100,0,1,0);
	glRotatef(-_rotY/100,1,0,0);
	//实现自动旋转
	glRotatef(_angle,0,1,0);
	drawEarth();
	glPopMatrix();

	glutSwapBuffers();
}

//实现自动旋转效果
void update(int value) {
	_angle += 2.0f;
	if (_angle > 360) {
		_angle -= 360;
	}

	//重画
	glutPostRedisplay(); 
	
	//60FPS
	glutTimerFunc(16, update, 0);
}

//处理鼠标点击旋转事件
//处理鼠标点击滑动事件
void handleMotion(int x,int y)
{
	int rx=x-oldX;
	int ry=480-y-oldY;
	_rotX+=rx;
	_rotY+=ry;
	//重画
	glutPostRedisplay();
}

//处理鼠标点击事件
void handleMouse(int button,int state,int x,int y)
{
	static bool done=false;
	if (button==GLUT_LEFT_BUTTON)
	{	
		oldX=x;
		oldY=480-y;
	}	
}

int main(int argc, char** argv) {
	//初始化
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
	glutInitWindowSize(800, 480);
	
	//创建窗口
	glutCreateWindow("地球仪");
	initRendering();
	
	//设置用户操作
	glutDisplayFunc(drawScene);
	glutKeyboardFunc(handleKeypress);
	glutReshapeFunc(handleResize);
	glutMotionFunc(handleMotion);
	glutMouseFunc(handleMouse);
	
	//运动效果
	glutTimerFunc(16, update, 0); 
	
	glutMainLoop();
	//退出时删除建模
	deinitRendering();
	return 0;
}

MyTexMgr.cpp

#include <glaux.h>
#pragma comment ( lib, "glaux.lib" )
#include "MyTexMgr.h"
#include <fstream>
#include <gl/GL.h>
#include <gl/GLU.h>

MyTexMgr::MyTexMgr(void)
{
}

MyTexMgr::~MyTexMgr(void)
{
	if (m_textures.empty())
	{
		return;
	}
	map<wstring,uint>::iterator it;
	for (it=m_textures.begin();it!=m_textures.end();++it)
	{
		glDeleteTextures(1,&it->second);
	}
}

bool MyTexMgr::loadTex( const wstring& texName,const wstring& fileName )
{
	GLuint	newElem;
	glGenTextures(1,&newElem);

	AUX_RGBImageRec*	rec=loadBMP(fileName.c_str());
	if (!rec)
	{
		glDeleteTextures(1,&newElem);
		return false;
	}

	glBindTexture(GL_TEXTURE_2D,newElem);
	glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,rec->sizeX,rec->sizeY,
		0,GL_RGB,GL_UNSIGNED_BYTE,rec->data);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);

	if (getTex(texName)!=INVALD_TEXTURE)
	{
		delTex(texName);
	}
	m_textures.insert(make_pair(texName,newElem));
	delete	rec->data;
	free(rec);

	return true;

}

uint MyTexMgr::getTex( const wstring& texName )
{
	map<wstring,uint>::iterator it;
	it=m_textures.find(texName);
	if (it!=m_textures.end())
	{
		return it->second;
	}
	else
	{
		return INVALD_TEXTURE;
	}
}

bool MyTexMgr::delTex( const wstring& texName )
{
	map<wstring,uint>::iterator it;
	it=m_textures.find(texName);
	if (it!=m_textures.end())
	{
		glDeleteTextures(1,&it->second);
		m_textures.erase(it);
	}
	return true;
}

AUX_RGBImageRec* MyTexMgr::loadBMP( const wchar_t* fileName )
{
	wifstream infile(fileName);
	if (infile.is_open())
	{
		return auxDIBImageLoadW(fileName);
	} 
	else
	{
		return NULL;
	}

}

bool MyTexMgr::clear()
{
	if (m_textures.empty())
	{
		return true;
	}
	map<wstring,uint>::iterator it;
	for (it=m_textures.begin();it!=m_textures.end();++it)
	{
		glDeleteTextures(1,&it->second);
	}
	m_textures.clear();
	return true;
}

结果:

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值