太阳系Demo(openGL)
这个是8年前写的demo,提交的一份作业,按照提出的需求点,以最快和最简单的方式完成功能,因此代码比较简单。
1)截图
2) 功能点描述:
1、公转,自传
2、基础的摄像机运动
3、正视和顶视
4、天空盒
5、太阳黑子爆炸
6、彗星带尾巴
7、录制重播
3) 实现代码:
1、简单的摄像机代码(目前仅支持移动,不支持旋转)
struct glCamera
{
vec3 pos;//摄像机的世界空间坐标
float viewMatrix[];
vec3 forward;
vec3 right;
vec3 up; public : glCamera( vec3 at)
{
pos=at;
} void getViewMatrix()
{
glMatrixMode(GL_MODELVIEW);
glGetFloatv(GL_MODELVIEW_MATRIX,viewMatrix);
} void update()
{
glMatrixMode(GL_MODELVIEW);
glLoadIdentity(); glTranslatef(-pos.x,-pos.y,-pos.z); getViewMatrix();
right=vec3(viewMatrix[],viewMatrix[],viewMatrix[]);
up=vec3(viewMatrix[],viewMatrix[],viewMatrix[]);
forward=vec3(viewMatrix[],viewMatrix[],viewMatrix[]);
} };
2、天空盒
glDrawSkyBox(glTexture *tex,float x,float y,float z,float width,float height,float len)
{
tex->MakeCurrent(); //获取中心点
x=x-width/;
y=y-height/;
z=z-len/; //back face
glBegin(GL_QUADS);
glNormal3f(0.0,0.0,1.0);
glTexCoord2f(1.0f, 0.0f);
glVertex3f(x+width, y, z); glTexCoord2f(1.0f, 1.0f);
glVertex3f(x+width, y+height, z); glTexCoord2f(0.0f, 1.0f);
glVertex3f(x, y+height, z); glTexCoord2f(0.0f, 0.0f);
glVertex3f(x, y, z);
glEnd();
//front face
glBegin(GL_QUADS);
glNormal3f(0.0,0.0,-1.0);
glTexCoord2f(1.0f, 0.0f);
glVertex3f(x, y, z+len); glTexCoord2f(1.0f, 1.0f);
glVertex3f(x, y+height, z+len); glTexCoord2f(0.0f, 1.0f);
glVertex3f(x+width, y+height, z+len); glTexCoord2f(0.0f, 0.0f);
glVertex3f(x+width, y, z+len);
glEnd();
//bottom face
glBegin(GL_QUADS);
glNormal3f(0.0,1.0,0.0);
glTexCoord2f(1.0f, 0.0f);
glVertex3f(x, y, z); glTexCoord2f(1.0f, 1.0f);
glVertex3f(x, y, z+len); glTexCoord2f(0.0f, 1.0f);
glVertex3f(x+width, y, z+len); glTexCoord2f(0.0f, 0.0f);
glVertex3f(x+width, y, z);
glEnd();
//top face
glBegin(GL_QUADS);
glNormal3f(0.0,-1.0,0.0);
glTexCoord2f(1.0f, 0.0f);
glVertex3f(x+width, y+height, z); glTexCoord2f(1.0f, 1.0f);
glVertex3f(x+width, y+height, z+len); glTexCoord2f(0.0f, 1.0f);
glVertex3f(x, y+height, z+len); glTexCoord2f(0.0f, 0.0f);
glVertex3f(x, y+height, z);
glEnd();
//left face
glBegin(GL_QUADS);
glNormal3f(1.0,0.0,0.0);
glTexCoord2f(1.0f, 0.0f);
glVertex3f(x, y+height, z); glTexCoord2f(1.0f, 1.0f);
glVertex3f(x, y+height, z+len); glTexCoord2f(0.0f, 1.0f);
glVertex3f(x, y, z+len); glTexCoord2f(0.0f, 0.0f);
glVertex3f(x, y, z);
glEnd(); //right face
glBegin(GL_QUADS);
glNormal3f(0.0,0.0,-1.0);
glTexCoord2f(1.0f, 0.0f);
glVertex3f(x+width, y, z); glTexCoord2f(1.0f, 1.0f);
glVertex3f(x+width, y, z+len); glTexCoord2f(0.0f, 1.0f);
glVertex3f(x+width, y+height, z+len); glTexCoord2f(0.0f, 0.0f);
glVertex3f(x+width, y+height, z);
glEnd();
}
3、彗星尾巴(billboard一种运用)
class glTrail
{
public:
std::vector<vec3> path;
float width;
float color[];
glTexture* texture; glTrail(const char* texname) :
width(0.2)
{
color[] = 1.0f;
color[] = 1.0f;
color[] = 1.0f;
color[] = 1.0f;
texture = new glTexture(texname, true);
} virtual ~glTrail()
{
delete texture;
} //设置trail的位置坐标
void setPath(vec3 pos)
{
for (int i = ; i < ; i++)
path.push_back(vec3((i + 0.5f), , ));
} void draw(vec3 pos)
{
vec3 v, v1, v2, v3, z;
float f;
int i; if (path.size() <= )
return; texture->MakeCurrent(); //深度写入禁止,但是深度比较还是需要的啦
glDepthMask(GL_FALSE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
glBegin(GL_QUAD_STRIP); for (i = ; i < path.size(); i++)
{
z = pos - path[i];
v3.x = v3.y = v3.z = 0.0f;
if (i > )
{
v1 = path[i] - path[i - ];
v2.cross(z, v1);
v2.normalize();
v3 += v2;
}
if (i < (path.size() - ))
{
v1 = path[i + ] - path[i];
v2.cross(z, v1);
v2.normalize();
v3 += v2;
}
v3.normalize(); f = (float)i / (path.size() - );
v = path[i] + v3*width;
glTexCoord2f(, f);
glVertex3fv(&v.x);
v = path[i] - v3*width;
glTexCoord2f(, f);
glVertex3fv(&v.x);
}
glEnd();
glDepthMask(GL_FALSE);
glDisable(GL_BLEND);
}
};
4、粒子系统(billboard另外一种运用)
struct glParticle
{
vec3 m_pos;
vec3 m_prevPos;
vec3 m_velocity;
vec3 m_acceleration;
float m_energy; float m_size;
float m_sizeDelta; float m_weight;
float m_weightDelta; float m_color[];
float m_colorDelta[];
}; class glParticleSystem
{
public: glParticleSystem(int maxParticles, vec3 origin); virtual ~glParticleSystem() { KillSystem(); } virtual void Update(float elapsedTime) = ;
virtual void Render() = ; virtual int Emit(int numParticles); virtual void InitializeSystem();
virtual void KillSystem(); protected:
//纯虚函数,子类override
virtual void InitializeParticle(int index) = ; //指针指向glParticle数组首地址
//数量 = m_maxParticles
//由于粒子系统会产生大量的小对象,因此用预先分配内存方式提高效率
glParticle *m_particleList; //最多可以产生的粒子数量
int m_maxParticles; //当前的粒子数量
int m_numParticles; //粒子发生的位置坐标
vec3 m_origin; float m_accumulatedTime; vec3 m_force;
}; glParticleSystem::glParticleSystem(int maxParticles, vec3 origin)
{
//记录最大数量和原始坐标
m_maxParticles = maxParticles;
m_origin = origin;
m_particleList = NULL;
m_numParticles = ;
m_accumulatedTime = 0.0f;
} int glParticleSystem::Emit(int numParticles)
{
//粒子数量最多不能超过m_maxParticles
while (numParticles && (m_numParticles < m_maxParticles))
{ InitializeParticle(m_numParticles++);
--numParticles;
} return numParticles;
} void glParticleSystem::InitializeSystem()
{
if (m_particleList)
{
delete[] m_particleList;
m_particleList = NULL;
} m_particleList = new glParticle[m_maxParticles]; m_numParticles = ;
m_accumulatedTime = 0.0f;
} void glParticleSystem::KillSystem()
{
if (m_particleList)
{
delete[] m_particleList;
m_particleList = NULL;
} m_numParticles = ;
m_accumulatedTime = 0.0f;
}
5、爆炸粒子系统
#include "glparticle.h" const vec3 PARTICLE_VELOCITY (0.0f, 2.0f, 0.0f);
const vec3 VELOCITY_VARIATION (4.0f, 4.0f, 4.0f);
const vec3 PARTICLE_ACCELERATION (0.0f, -5.0f, 0.0f);
const float PARTICLE_SIZE = 3.0f;//5.0f;
const float SIZE_VARIATION = 0.3f;//2.0f;
#define FRAND (((float)rand()-(float)rand())/RAND_MAX) class glExplosion : public glParticleSystem
{
public:
glExplosion(int maxParticles, vec3 origin, float spread, GLuint texture);
void Update(float elapsedTime);
void Render();
bool IsDead() { return m_numParticles == ; } void InitializeParticle(int index);
float m_spread;
GLuint m_texture;
}; glExplosion::glExplosion(int numParticles, vec3 origin, float spread, GLuint texture)
: m_texture(texture), m_spread(spread), glParticleSystem(numParticles, origin)
{
srand(timeGetTime());
glParticleSystem::InitializeSystem();
Emit(numParticles);
} void glExplosion::InitializeParticle(int index)//爆炸初始化
{
m_particleList[index].m_pos.x = m_origin.x + FRAND * m_spread;
m_particleList[index].m_pos.y = m_origin.y + FRAND * m_spread;
m_particleList[index].m_pos.z = m_origin.z + FRAND * m_spread; m_particleList[index].m_size = PARTICLE_SIZE + FRAND * SIZE_VARIATION; m_particleList[index].m_velocity.x = PARTICLE_VELOCITY.x + FRAND * VELOCITY_VARIATION.x;
m_particleList[index].m_velocity.y = PARTICLE_VELOCITY.y + FRAND * VELOCITY_VARIATION.y;
m_particleList[index].m_velocity.z = PARTICLE_VELOCITY.z + FRAND * VELOCITY_VARIATION.z; m_particleList[index].m_acceleration = PARTICLE_ACCELERATION;
m_particleList[index].m_color[] = 1.0;
m_particleList[index].m_color[] = 0.5f + FRAND * 0.5f;
m_particleList[index].m_color[] = 0.01f;
m_particleList[index].m_color[] = 1.0;
m_particleList[index].m_energy = 1.5f + FRAND / 2.0f;
m_particleList[index].m_colorDelta[] = 0.0;
m_particleList[index].m_colorDelta[] = -(m_particleList[index].m_color[] / 2.0f) / m_particleList[index].m_energy;
m_particleList[index].m_colorDelta[] = 0.0;
m_particleList[index].m_colorDelta[] = -1.0f / m_particleList[index].m_energy;
m_particleList[index].m_sizeDelta = -m_particleList[index].m_size / m_particleList[index].m_energy;
}
void glExplosion::Update(float elapsedTime)//清除爆炸动画
{
for (int i = ; i < m_numParticles;)
{
//更新位置s=vt;
m_particleList[i].m_pos = m_particleList[i].m_pos + m_particleList[i].m_velocity * elapsedTime;
//更新速度v=at;
m_particleList[i].m_velocity = m_particleList[i].m_velocity + m_particleList[i].m_acceleration * elapsedTime;
//能量随着时间流逝
m_particleList[i].m_energy -= elapsedTime; //size以及颜色随着时间变换
m_particleList[i].m_size += m_particleList[i].m_sizeDelta * elapsedTime;
m_particleList[i].m_color[] += m_particleList[i].m_colorDelta[] * elapsedTime;
m_particleList[i].m_color[] += m_particleList[i].m_colorDelta[] * elapsedTime; //如果当前粒子的能量<=0,说明没有了
//则将最后一个粒子放入当前位置
if (m_particleList[i].m_energy <= 0.0)
{
m_particleList[i] = m_particleList[--m_numParticles];
}
else
{
++i;
}
}
} void glExplosion::Render()//爆炸动画
{
glPushAttrib(GL_CURRENT_BIT);//保存现有颜色属性 glPopAttrib();//恢复前一属性 float viewMatrix[];
glGetFloatv(GL_MODELVIEW_MATRIX, viewMatrix);
vec3 right(viewMatrix[], viewMatrix[], viewMatrix[]);
vec3 up(viewMatrix[], viewMatrix[], viewMatrix[]); glDepthMask(GL_FALSE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_DST_ALPHA); glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, m_texture);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glBegin(GL_QUADS);
for (int i = ; i < m_numParticles; ++i)
{
GLfloat size = m_particleList[i].m_size / ;
vec3 pos = m_particleList[i].m_pos;
glColor4fv(m_particleList[i].m_color); glTexCoord2f(0.0, 0.0); glVertex3fv((pos + (right + up) * -size).v);
glTexCoord2f(1.0, 0.0); glVertex3fv((pos + (right - up) * size).v);
glTexCoord2f(1.0, 1.0); glVertex3fv((pos + (right + up) * size).v);
glTexCoord2f(0.0, 1.0); glVertex3fv((pos + (up - right) * size).v);
}
glEnd();
//glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
glDepthMask(GL_TRUE);
glPopAttrib();//恢复前一属性
}
6、由于整个系统大部分都是圆形以及像土星一样带光圈的图形,因此在opengl中,二次曲面对象最适合这种显示
void drawInit();
void drawSphere(double radius , int slices, int stack,bool texture);
void drawDisk( GLdouble innerRadius,
GLdouble outerRadius,
GLint slices);
void drawDeInit(); GLUquadricObj * m_quad = NULL; void drawInit()
{
m_quad = gluNewQuadric();
} void drawDeInit()
{
gluDeleteQuadric(m_quad);
} void drawSphere(double radius , int slices, int stack ,bool texture)
{ gluQuadricTexture(m_quad, true);
gluSphere(m_quad,radius,slices,stack);
} void drawDisk(GLdouble innerRadius,
GLdouble outerRadius,
GLint slices )
{
gluDisk(m_quad,innerRadius,
outerRadius,
slices,
true);
}
7、纹理载入,使用lodepng库读取png图像,该库最大的好处是只有单独一个文件,不需要依赖zlib和libpng等库就能惊醒png读写。
class glTexture
{
public:
GLuint m_tex;
glTexture(){m_tex=;} glTexture(const char* fname,
bool make_mipmaps=true); ~glTexture(); void MakeCurrent();
}; glTexture::glTexture(const char *fname,
bool make_mipmaps)
{ std::vector<unsigned char> image;
unsigned int width, height;
unsigned int error = lodepng::decode(image, width, height, fname); if (error != )
{
std::cout << "error " << error << ": " << lodepng_error_text(error) << std::endl;
return;
} m_tex = ;
glEnable(GL_TEXTURE_2D);
glPixelStorei(GL_UNPACK_ALIGNMENT, ); //Get a texture space and make it active
glGenTextures(, &m_tex);
glBindTexture(GL_TEXTURE_2D, m_tex); //Set default(and fastest) texture propoties
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); //Determine if mipmaps are used
if (make_mipmaps)
{
gluBuild2DMipmaps(GL_TEXTURE_2D, , width, height, GL_RGBA, GL_UNSIGNED_BYTE, &image[]);
}
else
{ double xPow2, yPow2;
int ixPow2, iyPow2;
int xSize2, ySize2;
unsigned char* pData = NULL; GLint glMaxTexDim;
//Get the maximum texture size
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &glMaxTexDim);
//Get the powers of 2 that correspond to the width and height of the original
//or of the maxmaximum texture size if widthor height is larger than the maxmaximum texture size
if (width <= glMaxTexDim)
xPow2 = log((double)width) / log((double)2.0);
else
xPow2 = log((double)glMaxTexDim) / log((double)2.0); if (height <= glMaxTexDim)
yPow2 = log((double)height) / log((double)2.0);
else
yPow2 = log((double)glMaxTexDim) / log((double)2.0); //round the power of 2 up to the nearest power of 2
ixPow2 = (int)xPow2;
iyPow2 = (int)yPow2; if (xPow2 != (double)ixPow2)
ixPow2++;
if (yPow2 != (double)iyPow2)
iyPow2++;
//convert power to actual value
xSize2 = << ixPow2;
ySize2 = << iyPow2;
//if the new sizes are different than the old ones
//resize and scale the "RGBAImage"
if (xSize2 != width || ySize2 != height)
{
pData = (unsigned char*)malloc(xSize2 * ySize2 * * sizeof(unsigned char)); if (!pData)
return; gluScaleImage(GL_RGBA,
width,
height,
GL_UNSIGNED_BYTE,
&image[],
xSize2,
ySize2,
GL_UNSIGNED_BYTE,
pData); width = xSize2;
height = ySize2;
} glTexImage2D(GL_TEXTURE_2D,
, , width,height,
, GL_RGB, GL_UNSIGNED_BYTE,pData); if (pData)
{
free(pData);
pData = NULL;
}
}
} void glTexture::MakeCurrent()
{
glBindTexture(GL_TEXTURE_2D, m_tex);
} glTexture::~glTexture()
{
glDeleteTextures(, &m_tex);
}
8、行星结构的定义
class planet
{
public:
float aroundRotatedSpeed;//公转
float selfRotatedSpeed;//自转
float radius;//行星的半径,影响绘制的大小啦
//下面这个变量代表当前行星离父亲之间的的距离拉
//1.太阳系以太阳为中心进行运动
//2.除地球外其他行星相对于太阳进行自转和公转,因此对于其他行星来说,太阳就是父亲,其他行星就是儿子
//3比较特殊的是地球,地球也是相对太阳进行自转和公转的,但是地球还有一个儿子,既月球,因此对于月球来说,他的父亲是地球,他的父亲的父亲是太阳
//层次关系总结如下:
// 太阳
// 除地球和月球外的其他行星
// 地球
// 月球
vec3 pos; glTexture *texture;
public: planet(const char* texname,float as,float ss,float radius,vec3 pos)
{
texture=new glTexture(texname,true);
this->aroundRotatedSpeed =as;
this->selfRotatedSpeed =ss;
this->radius =radius;
this->pos =pos; } ~planet()
{
if (!texture)
{
delete texture;
texture = NULL;
}
} };
9、录制与回放,采取最简单的方式,记录当前的angle,所有的星球运动都是基于当前anlge变量,因此其他运动都是当前角度的某个映射关系,因此只要记录当前的angle,就能实现录制和回放功能(其实由上述代码可见,纯粹是为了完成任务,因此采取最简洁有效方式,哈哈哈)
int angle = ; //核心变量,所有行星的移动和转动的速度是以angle为基础的啦,改变angle旋转速度会影响所有行星的运动速度,包括角速度和距离,所有行星都是按照angle相对比例进行运动 void record()
{
if (filesys.beginWrite("test.txt"))
{
filesys.writeInt(angle);
filesys.closeFile();
}
} void rePlay()
{
if (filesys.beginRead("test.txt"))
{
filesys.readInt(&angle);
filesys.closeFile();
}
}
10、main.cpp
//全局变量声明
bool lighting = true;
fileSystem filesys;//record/replay系统使用
int frontViewOnOff;//开关变量,前视图和正视图转换
glTexture *boxtex;//天空盒纹理贴图,理论上天空盒需要六张无缝拍摄的纹理,现在就用一张贴在天空盒六个面上,简化一下
glTexture *parttex;
glExplosion * glexp = new glExplosion(, vec3(, , ), 1.0f, );
bool isexp = true;
int numexp;
float px, py, pz;
glTrail* trail; //行星系统
planet *sun; //太阳
planet *sx; //水星
planet *jx; //金星
planet *hx; //火星
planet *mx; //木星
planet *tx; //土星
planet *twx; //天王星
planet *hwx; //海王星 planet * earth; //地球
planet * moon; //月亮 glCamera camera(vec3(0.0f, 0.0f, 10.0f)); //摄像机初始位置,w/s键控制摄像机前后移动,a/d控制摄像机左右移动,鼠标左键按下拖动控制摄像机的pitch/yaw旋转 int angle = ; //核心变量,所有行星的移动和转动的速度是以angle为基础的啦,改变angle旋转速度会影响所有行星的运动速度,包括角速度和距离,所有行星都是按照angle相对比例进行运动 void SetLight(bool b)
{
float amb[] = { 1.0, 0.8, 0.8, };
float dif[] = { 1.0, 1.0, 1.0, };
float pos[] = { , , , };
glLightfv(GL_LIGHT0, GL_AMBIENT, amb);
glLightfv(GL_LIGHT0, GL_DIFFUSE, dif);
glLightfv(GL_LIGHT0, GL_SPECULAR, dif);
glLightfv(GL_LIGHT0, GL_POSITION, pos);
glColorMaterial(GL_FRONT, GL_DIFFUSE); if (b)
{
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
}
else
{
glDisable(GL_LIGHTING);
glDisable(GL_LIGHT0);
} glShadeModel(GL_SMOOTH);
} void init()
{
boxtex = new glTexture("星空图.png", true); sun = new planet("太阳.png", 0.0f, 1.0f, 1.0f, vec3(0.0f, 0.0f, 0.0f));
sx = new planet("水星.png", 0.5f, 0.5f, 0.2f, vec3(1.4f, 0.4f, 0.0f));
jx = new planet("金星.png", 0.5f, 0.5f, 0.2f, vec3(3.0f, -0.4f, 0.0f));
earth = new planet("地球.png", 1.0f, 2.0f, 0.5f, vec3(5.0f, 2.0f, 8.0f));
moon = new planet("月亮.png", 0.5f, 0.5f, 0.2f, vec3(1.5f, 0.0f, 0.0f));
hx = new planet("火星.png", 0.2f, 0.3f, 0.3f, vec3(7.0f, 0.0f, 0.0f));
mx = new planet("木星.png", 0.4f, 1.0f, 0.5f, vec3(10.0f, 0.0f, 0.0f));
tx = new planet("土星.png", -0.4f, 0.2f, 1.0f, vec3(15.0f, 1.0f, 0.0f));
twx = new planet("天王星.png", 0.8f, 0.5f, 0.3f, vec3(17.0f, 0.0f, 0.0f));
hwx = new planet("海王星.png", 0.6f, 0.5f, 0.4f, vec3(19.0f, 0.8f, 0.0f)); parttex = new glTexture("particle.png"); trail = new glTrail("spawnflash.png");
trail->setPath(vec3(, , )); glFrontFace(GL_CCW);
glCullFace(GL_BACK); //初始化二次曲面对象
drawInit();
} void deinit()
{
delete boxtex;
delete sun;
delete sx;
delete jx;
delete earth;
delete moon;
delete hx;
delete mx;
delete tx;
delete twx;
delete hwx;
delete parttex;
delete trail;
delete glexp;
drawDeInit();
} void record()
{
if (filesys.beginWrite("test.txt"))
{
filesys.writeInt(angle);
filesys.closeFile();
}
} void rePlay()
{
if (filesys.beginRead("test.txt"))
{
filesys.readInt(&angle);
filesys.closeFile();
}
} static void DrawEarthAndMoon(planet *earth, planet *moon)
{
glPushMatrix();//地球公转+自转(围绕太阳)
earth->texture->MakeCurrent(); glRotatef(angle*earth->aroundRotatedSpeed, 0.0f, 1.0f, 0.0f);
glTranslatef(earth->pos.x, earth->pos.y, earth->pos.z);
glRotatef(angle*earth->selfRotatedSpeed, 0.0f, 1.0f, 0.0f);
drawSphere(earth->radius, , , true); glPushMatrix();//月球公转+自转(围绕地球)
moon->texture->MakeCurrent();
glRotatef(angle*moon->aroundRotatedSpeed, 0.0f, 1.0f, 0.0f);
glTranslatef(moon->pos.x, moon->pos.y, moon->pos.z);
glRotatef(angle*moon->selfRotatedSpeed, 0.0f, 1.0f, 0.0f);
drawSphere(moon->radius, , , true);
glPopMatrix(); glPopMatrix();
}
static void DrawOtherPlanet(planet * p)
{
glPushMatrix();
p->texture->MakeCurrent();
glRotatef(angle*p->aroundRotatedSpeed, 0.0f, 1.0f, 0.0f);
glTranslatef(p->pos.x, p->pos.y, p->pos.z);
glRotatef(angle*p->selfRotatedSpeed, 0.0f, 1.0f, 0.0f);
drawSphere(p->radius, , , true);
glPopMatrix();
} static void DrawTrail(planet * p)
{
glPushMatrix();
glRotatef(angle*p->aroundRotatedSpeed*2.0f, 0.0f, 1.0f, 0.0f);
glTranslatef(p->pos.x + 0.4f, p->pos.y + 0.3, p->pos.z);
glPushMatrix();
glRotatef(-90.0f, 0.0f, 1.0f, 0.0f);
trail->draw(camera.pos);
glPopMatrix();
glRotatef(angle*p->selfRotatedSpeed, 0.0f, 1.0f, 0.0f);
drawSphere(p->radius, , , true);
glPopMatrix();
} static void DrawOtherPlanet2(planet * p)
{
glPushMatrix();
p->texture->MakeCurrent(); glRotatef(angle*p->aroundRotatedSpeed, 0.0f, 1.0f, 0.0f); glTranslatef(p->pos.x, p->pos.y, p->pos.z); glRotatef(angle*p->selfRotatedSpeed, 0.0f, 1.0f, 0.0f); drawSphere(p->radius, , , true); glPushMatrix();
glRotatef(, 1.0f, 0.0f, 0.0f); drawDisk(1.5, , ); glPopMatrix();
glPopMatrix(); }
void DrawJX()
{
glPushMatrix();
jx->texture->MakeCurrent(); glRotatef(angle*jx->aroundRotatedSpeed * , 1.0, 1.0, 1.0); glTranslatef(5.0f, 0.0, 0.0f);
glRotatef(angle*jx->aroundRotatedSpeed * , 0.0f, 0.0f, 1.0f); drawSphere(jx->radius, , , true);
glPopMatrix();
}
void DrawHX()
{
glPushMatrix();
hx->texture->MakeCurrent(); glRotatef(angle*hx->aroundRotatedSpeed * , -1.0, -1.0, 0.0); glTranslatef(5.0f, 0.0, 0.0f); glRotatef(angle*hx->aroundRotatedSpeed * , 0.0f, 0.0f, 1.0f); drawSphere(hx->radius, , , true); glPopMatrix(); }
void testdraw1(planet *p)
{
glPushMatrix();
p->texture->MakeCurrent(); glRotatef(, 1.0, 0.0, 0.0);
glRotatef(angle*p->aroundRotatedSpeed * , 0.0f, 1.0f, 0.0f); glTranslatef(5.0f, , 0.0f);
glRotatef(angle*p->aroundRotatedSpeed * , 0.0f, 0.0f, 1.0f); drawSphere(p->radius, , , true);
glPopMatrix();
} void DrawSolarSystem(planet *sun)
{
sun->texture->MakeCurrent(); SetLight(lighting);
glTranslatef(sun->pos.x, sun->pos.y, sun->pos.z);
glRotatef(angle*sun->selfRotatedSpeed, 0.0f, 1.0f, 0.0f);
drawSphere(sun->radius, , , true);
DrawEarthAndMoon(earth, moon);//地月绘制
DrawOtherPlanet(sx);
DrawOtherPlanet(jx);
DrawOtherPlanet(twx);
DrawOtherPlanet(hwx);
//带光圈绘制
DrawOtherPlanet2(mx);
DrawOtherPlanet2(tx);
DrawTrail(jx);
} void myKeyboardFunc(unsigned char key, int x, int y)
{
switch (key)
{
case : //ESC
exit(); //退出系统
break;
case 'w'://摄像机向前运动 camera.pos -= camera.forward*0.5;
glutPostRedisplay();
break;
case 's'://摄像机向后运动
camera.pos += camera.forward*0.5; glutPostRedisplay();
break;
case 'a'://摄像机向左运动 camera.pos -= camera.right *0.5;
glutPostRedisplay();
break;
case 'd'://摄像机向右运动 camera.pos += camera.right*0.5;
glutPostRedisplay();
break;
case 'f'://正视图和顶视图切换 frontViewOnOff ^= ;
glutPostRedisplay();
break;
case 'r'://记录
record();
glutPostRedisplay();
break;
case 'p'://回放
rePlay();
glutPostRedisplay();
break;
case 'l'://灯源开关
lighting = !lighting;
glutPostRedisplay();
break;
} } void myReshape(int w, int h)
{
glViewport(, , w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(, GLfloat(w) / h, 0.1, );
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
glClearDepth(1.0f);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glShadeModel(GL_SMOOTH);
} void creatExplosion(float x, float y, float z, int num, float spread)
{
if (glexp != NULL) { delete glexp; glexp = NULL; }
glexp = new glExplosion(num, vec3(, , ), spread, parttex->m_tex);
px = x, pz = z, py = y;
isexp = false;
numexp = ;
} void drawExplosion()
{
glPushMatrix();
glTranslatef(px, py, pz);
if (isexp == false)
{
glexp->Render();
isexp = true;
}
if (isexp)
{
glexp->Update(0.03f);
isexp = false;
}
glPopMatrix();
} void myDisplay(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); camera.update(); //如果顶视图的话,沿着x轴旋转90度
glRotatef(frontViewOnOff*90.0f, 1.0f, 0.0f, 0.0f); //绘制天空盒
glDrawSkyBox(boxtex, 0.0f, 0.0f, 0.0f, 1000.0f, 1000.0f, 1000.0f); DrawJX();
DrawHX();
DrawSolarSystem(sun); if (numexp > )
{
creatExplosion(1.0f, 1.0f, 1.0f, , 1.5f);
} drawExplosion(); angle += ;
numexp++; glutSwapBuffers();
} void myTimerFunc(int val)
{
myDisplay();
glutTimerFunc(, myTimerFunc, );
} int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowPosition(, );
glutInitWindowSize(, );
glutCreateWindow("太阳系 w/s/a/d控制摄像机运动 r/录制 p/回放 f/切换正顶视图 l/光源开关");
init();
glutDisplayFunc(&myDisplay);
glutReshapeFunc(&myReshape);
glutKeyboardFunc(&myKeyboardFunc);
glutTimerFunc(, myTimerFunc, );
glutMainLoop();
deinit();
return ;
}
11、源码下载以及参考文档
完整的源代码可以到 https://github.com/jackyblf/SolarSystem-openGL- 进行下载。
源码中包含了billboardingtut.pdf的文档,讲解了所有的billboard类型以及适用范围,基于opengl描述。强烈推荐这篇文档
太阳系Demo(openGL)的更多相关文章
- Android OpenGL ES 开发教程 从入门到精通
感谢,摘自:http://blog.csdn.net/mapdigit/article/details/7526556 Android OpenGL ES 简明开发教程 Android OpenGL ...
- Android View部分消失效果实现
本文来自网易云社区 作者:孙有军 老需求 我们经常会有需求就是View消失的效果,这里我们说的消失往往是全部消失,我们可能采用一个alpha动画,在指定的时间内消失掉View,出现则实现相反的动画.我 ...
- Android中使用MediaCodec硬件解码,高效率得到YUV格式帧,快速保存JPEG图片(不使用OpenGL)(附Demo)
MediaCodec的使用demo: https://github.com/vecio/MediaCodecDemo https://github.com/taehwandev/MediaCodecE ...
- 基于Opengl的太阳系动画实现
#include <GL\glut.h> float fEarth = 2.0f;//地球绕太阳的旋转角度float fMoon = 24.0f;//月球绕地球的旋转角度 void Ini ...
- 配置自己的OpenGL库,glew、freeglut库编译,库冲突解决(附OpenGL Demo程序)
平台:Windows7,Visual C++ 2010 1. 引言 实验室的一个项目,用到OpenGL进行实时绘制,还用到一些其他的库,一个困扰我很久的问题就是编译时遇到的各种符号未定义,符号重定义之 ...
- OpenGL 太阳系行星拾取例子(GL_SELECT) VS2008 + glut实现
太阳系:Solar System 以太阳(Sun)为中心,由内到外分别是: 水星(Mercury) 金星(Venus) 地球(Earth) 火星(Mars) 木星(Jupiter) 土星(Saturn ...
- opengl学习笔记(五):组合变换,绘制一个简单的太阳系
创建太阳系模型 描述的程序绘制一个简单的太阳系,其中有一颗行星和一颗太阳,用同一个函数绘制.需要使用glRotate*()函数让这颗行星绕太阳旋转,并且绕自身的轴旋转.还需要使用glTranslate ...
- 【AR实验室】OpenGL ES绘制相机(OpenGL ES 1.0版本)
0x00 - 前言 之前做一些移动端的AR应用以及目前看到的一些AR应用,基本上都是这样一个套路:手机背景显示现实场景,然后在该背景上进行图形学绘制.至于图形学绘制时,相机外参的解算使用的是V-SLA ...
- opengl 笔记(2)
/*- * Opengl Demo Test * * Fredric : 2016-7-10 */ #include <GLUT/GLUT.h> #include <stdlib.h ...
随机推荐
- HubSpot – 网站开发必备的 jQuery 信息提示库
HubSpot 一款功能丰富的 jQuery 消息提示插件.它可以帮助你个性化显示您的应用程序的事务性消息.您可以轻松地包裹 Ajax 请求进度,成功和错误消息,还可以添加操作链接到您的消息中. Hu ...
- Pizza Pie Charts – 基于 Snap SVG 框架的响应式饼图
Pizza Pie Charts 是一个基于 Adobe 的 Snap SVG 框架的响应式饼图插件.它着重于集成 HTML 标记和 CSS,而不是 JavaScript 对象,当然Pizza Pie ...
- sql搜索数据库中具有某列的表
在接口中明明有某个节点,但在数据库中却找不到,为此本人写了一个sql,以供快速查找. Select distinct syscolumns.name,sysobjects.name from sysc ...
- 【转】ES6 手册
目录 var 和 let/const 的比较 用块级作用域代替 IIFES 箭头函数 字符串 解构 模块 参数 类 Classes Symbols Maps WeakMaps Promises Gen ...
- 总结CSS3新特性(Transition篇)
CSS 过渡(transition), 是 CSS3 规范的一部分, 用来控制 CSS 属性的变化速率. 可以让属性的变化过程持续一段时间,而不是立即生效.比如,将元素的颜色从白色改为黑色,通常这个改 ...
- [ javascript canvas isPointInPath(x,y) 判断点是否在最后绘制的图形中 ] javascript canvas isPointInPath(x,y) 判断点是否在最后绘制的图形中方法演示 效果之三
<!DOCTYPE html> <html lang='zh-cn'> <head> <title>Insert you title</title ...
- Xcode中的常用快捷键
新建项目 com + shift +N 新建文件 com + N 偏好设置 通用 com + , 跳到指定行 com + L 当前行加断点 com + \ 移动编辑区最上方 ...
- 属性(@property)、@synthesize
先前我们学的实例变量是这样的 { int _age; int _height; int age; } 后来学属性 @property int age; 看到@property 会自动编译生成某个成员变 ...
- 使用ContentProvider访问其他应用的SharedPreferences数据
@Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs ...
- OC中的面向对象语法4
一. 继承 1. 继承的基本用法 l 设计两个类Bird.Dog // Bird的声明 @interface Bird : NSObject { @public int weight; } - (vo ...