这个是8年前写的demo,提交的一份作业,按照提出的需求点,以最快和最简单的方式完成功能,因此代码比较简单。
1)截图
2) 功能点描述:
1、公转,自传
2、基础的摄像机运动
3、正视和顶视
4、天空盒
5、太阳黑子爆炸
6、彗星带尾巴
7、录制重播
3) 实现代码:
1、简单的摄像机代码(目前仅支持移动,不支持旋转)
1 struct glCamera 2 { 3 vec3 pos;//摄像机的世界空间坐标 4 float viewMatrix[16]; 5 vec3 forward; 6 vec3 right; 7 vec3 up; 8 9 public : 10 11 glCamera( vec3 at) 12 { 13 pos=at; 14 } 15 16 void getViewMatrix() 17 { 18 glMatrixMode(GL_MODELVIEW); 19 glGetFloatv(GL_MODELVIEW_MATRIX,viewMatrix); 20 } 21 22 void update() 23 { 24 glMatrixMode(GL_MODELVIEW); 25 glLoadIdentity(); 26 27 glTranslatef(-pos.x,-pos.y,-pos.z); 28 29 getViewMatrix(); 30 right=vec3(viewMatrix[0],viewMatrix[4],viewMatrix[8]); 31 up=vec3(viewMatrix[1],viewMatrix[5],viewMatrix[9]); 32 forward=vec3(viewMatrix[2],viewMatrix[6],viewMatrix[10]); 33 } 34 35 };
2、天空盒
1 glDrawSkyBox(glTexture *tex,float x,float y,float z,float width,float height,float len) 2 { 3 tex->MakeCurrent(); 4 5 //获取中心点 6 x=x-width/2; 7 y=y-height/2; 8 z=z-len/2; 9 10 //back face 11 glBegin(GL_QUADS); 12 glNormal3f(0.0,0.0,1.0); 13 glTexCoord2f(1.0f, 0.0f); 14 glVertex3f(x+width, y, z); 15 16 glTexCoord2f(1.0f, 1.0f); 17 glVertex3f(x+width, y+height, z); 18 19 glTexCoord2f(0.0f, 1.0f); 20 glVertex3f(x, y+height, z); 21 22 glTexCoord2f(0.0f, 0.0f); 23 glVertex3f(x, y, z); 24 glEnd(); 25 //front face 26 glBegin(GL_QUADS); 27 glNormal3f(0.0,0.0,-1.0); 28 glTexCoord2f(1.0f, 0.0f); 29 glVertex3f(x, y, z+len); 30 31 glTexCoord2f(1.0f, 1.0f); 32 glVertex3f(x, y+height, z+len); 33 34 glTexCoord2f(0.0f, 1.0f); 35 glVertex3f(x+width, y+height, z+len); 36 37 glTexCoord2f(0.0f, 0.0f); 38 glVertex3f(x+width, y, z+len); 39 glEnd(); 40 //bottom face 41 glBegin(GL_QUADS); 42 glNormal3f(0.0,1.0,0.0); 43 glTexCoord2f(1.0f, 0.0f); 44 glVertex3f(x, y, z); 45 46 glTexCoord2f(1.0f, 1.0f); 47 glVertex3f(x, y, z+len); 48 49 glTexCoord2f(0.0f, 1.0f); 50 glVertex3f(x+width, y, z+len); 51 52 glTexCoord2f(0.0f, 0.0f); 53 glVertex3f(x+width, y, z); 54 glEnd(); 55 //top face 56 glBegin(GL_QUADS); 57 glNormal3f(0.0,-1.0,0.0); 58 glTexCoord2f(1.0f, 0.0f); 59 glVertex3f(x+width, y+height, z); 60 61 62 glTexCoord2f(1.0f, 1.0f); 63 glVertex3f(x+width, y+height, z+len); 64 65 66 glTexCoord2f(0.0f, 1.0f); 67 glVertex3f(x, y+height, z+len); 68 69 70 glTexCoord2f(0.0f, 0.0f); 71 glVertex3f(x, y+height, z); 72 glEnd(); 73 //left face 74 glBegin(GL_QUADS); 75 glNormal3f(1.0,0.0,0.0); 76 glTexCoord2f(1.0f, 0.0f); 77 glVertex3f(x, y+height, z); 78 79 glTexCoord2f(1.0f, 1.0f); 80 glVertex3f(x, y+height, z+len); 81 82 glTexCoord2f(0.0f, 1.0f); 83 glVertex3f(x, y, z+len); 84 85 glTexCoord2f(0.0f, 0.0f); 86 glVertex3f(x, y, z); 87 glEnd(); 88 89 //right face 90 glBegin(GL_QUADS); 91 glNormal3f(0.0,0.0,-1.0); 92 glTexCoord2f(1.0f, 0.0f); 93 glVertex3f(x+width, y, z); 94 95 glTexCoord2f(1.0f, 1.0f); 96 glVertex3f(x+width, y, z+len); 97 98 glTexCoord2f(0.0f, 1.0f); 99 glVertex3f(x+width, y+height, z+len); 100 101 glTexCoord2f(0.0f, 0.0f); 102 glVertex3f(x+width, y+height, z); 103 glEnd(); 104 }
3、彗星尾巴(billboard一种运用)
1 class glTrail 2 { 3 public: 4 std::vector<vec3> path; 5 float width; 6 float color[4]; 7 glTexture* texture; 8 9 glTrail(const char* texname) : 10 width(0.2) 11 { 12 color[0] = 1.0f; 13 color[1] = 1.0f; 14 color[2] = 1.0f; 15 color[3] = 1.0f; 16 texture = new glTexture(texname, true); 17 } 18 19 virtual ~glTrail() 20 { 21 delete texture; 22 } 23 24 //设置trail的位置坐标 25 void setPath(vec3 pos) 26 { 27 for (int i = 0; i < 5; i++) 28 path.push_back(vec3((i + 0.5f), 0, 0)); 29 } 30 31 void draw(vec3 pos) 32 { 33 vec3 v, v1, v2, v3, z; 34 float f; 35 int i; 36 37 if (path.size() <= 1) 38 return; 39 40 texture->MakeCurrent(); 41 42 //深度写入禁止,但是深度比较还是需要的啦 43 glDepthMask(GL_FALSE); 44 glEnable(GL_BLEND); 45 glBlendFunc(GL_SRC_ALPHA, GL_ONE); 46 glBegin(GL_QUAD_STRIP); 47 48 for (i = 0; i < path.size(); i++) 49 { 50 z = pos - path[i]; 51 v3.x = v3.y = v3.z = 0.0f; 52 if (i > 0) 53 { 54 v1 = path[i] - path[i - 1]; 55 v2.cross(z, v1); 56 v2.normalize(); 57 v3 += v2; 58 } 59 if (i < (path.size() - 1)) 60 { 61 v1 = path[i + 1] - path[i]; 62 v2.cross(z, v1); 63 v2.normalize(); 64 v3 += v2; 65 } 66 v3.normalize(); 67 68 f = (float)i / (path.size() - 1); 69 v = path[i] + v3*width; 70 glTexCoord2f(0, f); 71 glVertex3fv(&v.x); 72 v = path[i] - v3*width; 73 glTexCoord2f(1, f); 74 glVertex3fv(&v.x); 75 } 76 glEnd(); 77 glDepthMask(GL_FALSE); 78 glDisable(GL_BLEND); 79 } 80 };
4、粒子系统(billboard另外一种运用)
1 struct glParticle 2 { 3 vec3 m_pos; 4 vec3 m_prevPos; 5 vec3 m_velocity; 6 vec3 m_acceleration; 7 float m_energy; 8 9 float m_size; 10 float m_sizeDelta; 11 12 float m_weight; 13 float m_weightDelta; 14 15 float m_color[4]; 16 float m_colorDelta[4]; 17 }; 18 19 20 class glParticleSystem 21 { 22 public: 23 24 glParticleSystem(int maxParticles, vec3 origin); 25 26 virtual ~glParticleSystem() { KillSystem(); } 27 28 virtual void Update(float elapsedTime) = 0; 29 virtual void Render() = 0; 30 31 virtual int Emit(int numParticles); 32 33 virtual void InitializeSystem(); 34 virtual void KillSystem(); 35 36 protected: 37 //纯虚函数,子类override 38 virtual void InitializeParticle(int index) = 0; 39 40 //指针指向glParticle数组首地址 41 //数量 = m_maxParticles 42 //由于粒子系统会产生大量的小对象,因此用预先分配内存方式提高效率 43 glParticle *m_particleList; 44 45 //最多可以产生的粒子数量 46 int m_maxParticles; 47 48 //当前的粒子数量 49 int m_numParticles; 50 51 //粒子发生的位置坐标 52 vec3 m_origin; 53 54 float m_accumulatedTime; 55 56 vec3 m_force; 57 }; 58 59 glParticleSystem::glParticleSystem(int maxParticles, vec3 origin) 60 { 61 //记录最大数量和原始坐标 62 m_maxParticles = maxParticles; 63 m_origin = origin; 64 m_particleList = NULL; 65 m_numParticles = 0; 66 m_accumulatedTime = 0.0f; 67 } 68 69 int glParticleSystem::Emit(int numParticles) 70 { 71 //粒子数量最多不能超过m_maxParticles 72 while (numParticles && (m_numParticles < m_maxParticles)) 73 { 74 75 InitializeParticle(m_numParticles++); 76 --numParticles; 77 } 78 79 return numParticles; 80 } 81 82 83 84 void glParticleSystem::InitializeSystem() 85 { 86 if (m_particleList) 87 { 88 delete[] m_particleList; 89 m_particleList = NULL; 90 } 91 92 m_particleList = new glParticle[m_maxParticles]; 93 94 m_numParticles = 0; 95 m_accumulatedTime = 0.0f; 96 } 97 98 void glParticleSystem::KillSystem() 99 { 100 if (m_particleList) 101 { 102 delete[] m_particleList; 103 m_particleList = NULL; 104 } 105 106 m_numParticles = 0; 107 m_accumulatedTime = 0.0f; 108 }
5、爆炸粒子系统
1 #include "glparticle.h" 2 3 const vec3 PARTICLE_VELOCITY (0.0f, 2.0f, 0.0f); 4 const vec3 VELOCITY_VARIATION (4.0f, 4.0f, 4.0f); 5 const vec3 PARTICLE_ACCELERATION (0.0f, -5.0f, 0.0f); 6 const float PARTICLE_SIZE = 3.0f;//5.0f; 7 const float SIZE_VARIATION = 0.3f;//2.0f; 8 #define FRAND (((float)rand()-(float)rand())/RAND_MAX) 9 10 class glExplosion : public glParticleSystem 11 { 12 public: 13 glExplosion(int maxParticles, vec3 origin, float spread, GLuint texture); 14 void Update(float elapsedTime); 15 void Render(); 16 bool IsDead() { return m_numParticles == 0; } 17 18 void InitializeParticle(int index); 19 float m_spread; 20 GLuint m_texture; 21 }; 22 23 glExplosion::glExplosion(int numParticles, vec3 origin, float spread, GLuint texture) 24 : m_texture(texture), m_spread(spread), glParticleSystem(numParticles, origin) 25 { 26 srand(timeGetTime()); 27 glParticleSystem::InitializeSystem(); 28 Emit(numParticles); 29 } 30 31 void glExplosion::InitializeParticle(int index)//爆炸初始化 32 { 33 m_particleList[index].m_pos.x = m_origin.x + FRAND * m_spread; 34 m_particleList[index].m_pos.y = m_origin.y + FRAND * m_spread; 35 m_particleList[index].m_pos.z = m_origin.z + FRAND * m_spread; 36 37 m_particleList[index].m_size = PARTICLE_SIZE + FRAND * SIZE_VARIATION; 38 39 m_particleList[index].m_velocity.x = PARTICLE_VELOCITY.x + FRAND * VELOCITY_VARIATION.x; 40 m_particleList[index].m_velocity.y = PARTICLE_VELOCITY.y + FRAND * VELOCITY_VARIATION.y; 41 m_particleList[index].m_velocity.z = PARTICLE_VELOCITY.z + FRAND * VELOCITY_VARIATION.z; 42 43 44 m_particleList[index].m_acceleration = PARTICLE_ACCELERATION; 45 m_particleList[index].m_color[0] = 1.0; 46 m_particleList[index].m_color[1] = 0.5f + FRAND * 0.5f; 47 m_particleList[index].m_color[2] = 0.01f; 48 m_particleList[index].m_color[3] = 1.0; 49 m_particleList[index].m_energy = 1.5f + FRAND / 2.0f; 50 m_particleList[index].m_colorDelta[0] = 0.0; 51 m_particleList[index].m_colorDelta[1] = -(m_particleList[index].m_color[1] / 2.0f) / m_particleList[index].m_energy; 52 m_particleList[index].m_colorDelta[2] = 0.0; 53 m_particleList[index].m_colorDelta[3] = -1.0f / m_particleList[index].m_energy; 54 m_particleList[index].m_sizeDelta = -m_particleList[index].m_size / m_particleList[index].m_energy; 55 } 56 void glExplosion::Update(float elapsedTime)//清除爆炸动画 57 { 58 for (int i = 0; i < m_numParticles;) 59 { 60 //更新位置s=vt; 61 m_particleList[i].m_pos = m_particleList[i].m_pos + m_particleList[i].m_velocity * elapsedTime; 62 //更新速度v=at; 63 m_particleList[i].m_velocity = m_particleList[i].m_velocity + m_particleList[i].m_acceleration * elapsedTime; 64 //能量随着时间流逝 65 m_particleList[i].m_energy -= elapsedTime; 66 67 //size以及颜色随着时间变换 68 m_particleList[i].m_size += m_particleList[i].m_sizeDelta * elapsedTime; 69 m_particleList[i].m_color[3] += m_particleList[i].m_colorDelta[3] * elapsedTime; 70 m_particleList[i].m_color[1] += m_particleList[i].m_colorDelta[1] * elapsedTime; 71 72 //如果当前粒子的能量<=0,说明没有了 73 //则将最后一个粒子放入当前位置 74 if (m_particleList[i].m_energy <= 0.0) 75 { 76 m_particleList[i] = m_particleList[--m_numParticles]; 77 } 78 else 79 { 80 ++i; 81 } 82 } 83 } 84 85 86 void glExplosion::Render()//爆炸动画 87 { 88 glPushAttrib(GL_CURRENT_BIT);//保存现有颜色属性 glPopAttrib();//恢复前一属性 89 90 float viewMatrix[16]; 91 glGetFloatv(GL_MODELVIEW_MATRIX, viewMatrix); 92 vec3 right(viewMatrix[0], viewMatrix[4], viewMatrix[8]); 93 vec3 up(viewMatrix[1], viewMatrix[5], viewMatrix[9]); 94 95 glDepthMask(GL_FALSE); 96 glEnable(GL_BLEND); 97 glBlendFunc(GL_SRC_ALPHA, GL_DST_ALPHA); 98 99 glEnable(GL_TEXTURE_2D); 100 glBindTexture(GL_TEXTURE_2D, m_texture); 101 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); 102 103 glBegin(GL_QUADS); 104 for (int i = 0; i < m_numParticles; ++i) 105 { 106 GLfloat size = m_particleList[i].m_size / 3; 107 vec3 pos = m_particleList[i].m_pos; 108 glColor4fv(m_particleList[i].m_color); 109 110 glTexCoord2f(0.0, 0.0); glVertex3fv((pos + (right + up) * -size).v); 111 glTexCoord2f(1.0, 0.0); glVertex3fv((pos + (right - up) * size).v); 112 glTexCoord2f(1.0, 1.0); glVertex3fv((pos + (right + up) * size).v); 113 glTexCoord2f(0.0, 1.0); glVertex3fv((pos + (up - right) * size).v); 114 } 115 glEnd(); 116 //glDisable(GL_TEXTURE_2D); 117 glDisable(GL_BLEND); 118 glDepthMask(GL_TRUE); 119 glPopAttrib();//恢复前一属性 120 }
6、由于整个系统大部分都是圆形以及像土星一样带光圈的图形,因此在opengl中,二次曲面对象最适合这种显示
1 void drawInit(); 2 void drawSphere(double radius , int slices, int stack,bool texture); 3 void drawDisk( GLdouble innerRadius, 4 GLdouble outerRadius, 5 GLint slices); 6 void drawDeInit(); 7 8 GLUquadricObj * m_quad = NULL; 9 10 void drawInit() 11 { 12 m_quad = gluNewQuadric(); 13 } 14 15 void drawDeInit() 16 { 17 gluDeleteQuadric(m_quad); 18 } 19 20 void drawSphere(double radius , int slices, int stack ,bool texture) 21 { 22 23 gluQuadricTexture(m_quad, true); 24 gluSphere(m_quad,radius,slices,stack); 25 } 26 27 void drawDisk(GLdouble innerRadius, 28 GLdouble outerRadius, 29 GLint slices ) 30 { 31 gluDisk(m_quad,innerRadius, 32 outerRadius, 33 slices, 34 true); 35 }
7、纹理载入,使用lodepng库读取png图像,该库最大的好处是只有单独一个文件,不需要依赖zlib和libpng等库就能惊醒png读写。
1 class glTexture 2 { 3 public: 4 GLuint m_tex; 5 glTexture(){m_tex=0;} 6 7 glTexture(const char* fname, 8 bool make_mipmaps=true); 9 10 ~glTexture(); 11 12 void MakeCurrent(); 13 }; 14 15 16 glTexture::glTexture(const char *fname, 17 bool make_mipmaps) 18 { 19 20 std::vector<unsigned char> image; 21 unsigned int width, height; 22 unsigned int error = lodepng::decode(image, width, height, fname); 23 24 if (error != 0) 25 { 26 std::cout << "error " << error << ": " << lodepng_error_text(error) << std::endl; 27 return; 28 } 29 30 m_tex = 0; 31 glEnable(GL_TEXTURE_2D); 32 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 33 34 //Get a texture space and make it active 35 glGenTextures(1, &m_tex); 36 glBindTexture(GL_TEXTURE_2D, m_tex); 37 38 //Set default(and fastest) texture propoties 39 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); 40 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 41 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); 42 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 43 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 44 45 //Determine if mipmaps are used 46 if (make_mipmaps) 47 { 48 gluBuild2DMipmaps(GL_TEXTURE_2D, 4, width, height, GL_RGBA, GL_UNSIGNED_BYTE, &image[0]); 49 } 50 else 51 { 52 53 double xPow2, yPow2; 54 int ixPow2, iyPow2; 55 int xSize2, ySize2; 56 unsigned char* pData = NULL; 57 58 GLint glMaxTexDim; 59 //Get the maximum texture size 60 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &glMaxTexDim); 61 //Get the powers of 2 that correspond to the width and height of the original 62 //or of the maxmaximum texture size if widthor height is larger than the maxmaximum texture size 63 if (width <= glMaxTexDim) 64 xPow2 = log((double)width) / log((double)2.0); 65 else 66 xPow2 = log((double)glMaxTexDim) / log((double)2.0); 67 68 if (height <= glMaxTexDim) 69 yPow2 = log((double)height) / log((double)2.0); 70 else 71 yPow2 = log((double)glMaxTexDim) / log((double)2.0); 72 73 //round the power of 2 up to the nearest power of 2 74 ixPow2 = (int)xPow2; 75 iyPow2 = (int)yPow2; 76 77 if (xPow2 != (double)ixPow2) 78 ixPow2++; 79 if (yPow2 != (double)iyPow2) 80 iyPow2++; 81 //convert power to actual value 82 xSize2 = 1 << ixPow2; 83 ySize2 = 1 << iyPow2; 84 //if the new sizes are different than the old ones 85 //resize and scale the "RGBAImage" 86 if (xSize2 != width || ySize2 != height) 87 { 88 pData = (unsigned char*)malloc(xSize2 * ySize2 * 4 * sizeof(unsigned char)); 89 90 if (!pData) 91 return; 92 93 gluScaleImage(GL_RGBA, 94 width, 95 height, 96 GL_UNSIGNED_BYTE, 97 &image[0], 98 xSize2, 99 ySize2, 100 GL_UNSIGNED_BYTE, 101 pData); 102 103 width = xSize2; 104 height = ySize2; 105 } 106 107 glTexImage2D(GL_TEXTURE_2D, 108 0, 4, width,height, 109 0, GL_RGB, GL_UNSIGNED_BYTE,pData); 110 111 if (pData) 112 { 113 free(pData); 114 pData = NULL; 115 } 116 } 117 } 118 119 120 void glTexture::MakeCurrent() 121 { 122 glBindTexture(GL_TEXTURE_2D, m_tex); 123 } 124 125 glTexture::~glTexture() 126 { 127 glDeleteTextures(1, &m_tex); 128 }
8、行星结构的定义
1 class planet 2 { 3 public: 4 float aroundRotatedSpeed;//公转 5 float selfRotatedSpeed;//自转 6 float radius;//行星的半径,影响绘制的大小啦 7 //下面这个变量代表当前行星离父亲之间的的距离拉 8 //1.太阳系以太阳为中心进行运动 9 //2.除地球外其他行星相对于太阳进行自转和公转,因此对于其他行星来说,太阳就是父亲,其他行星就是儿子 10 //3比较特殊的是地球,地球也是相对太阳进行自转和公转的,但是地球还有一个儿子,既月球,因此对于月球来说,他的父亲是地球,他的父亲的父亲是太阳 11 //层次关系总结如下: 12 // 太阳 13 // 除地球和月球外的其他行星 14 // 地球 15 // 月球 16 vec3 pos; 17 18 glTexture *texture; 19 public: 20 21 planet(const char* texname,float as,float ss,float radius,vec3 pos) 22 { 23 texture=new glTexture(texname,true); 24 this->aroundRotatedSpeed =as; 25 this->selfRotatedSpeed =ss; 26 this->radius =radius; 27 this->pos =pos; 28 29 } 30 31 ~planet() 32 { 33 if (!texture) 34 { 35 delete texture; 36 texture = NULL; 37 } 38 } 39 40 };
9、录制与回放,采取最简单的方式,记录当前的angle,所有的星球运动都是基于当前anlge变量,因此其他运动都是当前角度的某个映射关系,因此只要记录当前的angle,就能实现录制和回放功能(其实由上述代码可见,纯粹是为了完成任务,因此采取最简洁有效方式,哈哈哈)
1 int angle = 0; //核心变量,所有行星的移动和转动的速度是以angle为基础的啦,改变angle旋转速度会影响所有行星的运动速度,包括角速度和距离,所有行星都是按照angle相对比例进行运动 2 3 void record() 4 { 5 if (filesys.beginWrite("test.txt")) 6 { 7 filesys.writeInt(angle); 8 filesys.closeFile(); 9 } 10 } 11 12 void rePlay() 13 { 14 if (filesys.beginRead("test.txt")) 15 { 16 filesys.readInt(&angle); 17 filesys.closeFile(); 18 } 19 }
10、main.cpp
1 //全局变量声明 2 bool lighting = true; 3 fileSystem filesys;//record/replay系统使用 4 int frontViewOnOff;//开关变量,前视图和正视图转换 5 glTexture *boxtex;//天空盒纹理贴图,理论上天空盒需要六张无缝拍摄的纹理,现在就用一张贴在天空盒六个面上,简化一下 6 glTexture *parttex; 7 glExplosion * glexp = new glExplosion(1, vec3(0, 0, 0), 1.0f, 0); 8 bool isexp = true; 9 int numexp; 10 float px, py, pz; 11 glTrail* trail; 12 13 //行星系统 14 planet *sun; //太阳 15 planet *sx; //水星 16 planet *jx; //金星 17 planet *hx; //火星 18 planet *mx; //木星 19 planet *tx; //土星 20 planet *twx; //天王星 21 planet *hwx; //海王星 22 23 planet * earth; //地球 24 planet * moon; //月亮 25 26 glCamera camera(vec3(0.0f, 0.0f, 10.0f)); //摄像机初始位置,w/s键控制摄像机前后移动,a/d控制摄像机左右移动,鼠标左键按下拖动控制摄像机的pitch/yaw旋转 27 28 int angle = 0; //核心变量,所有行星的移动和转动的速度是以angle为基础的啦,改变angle旋转速度会影响所有行星的运动速度,包括角速度和距离,所有行星都是按照angle相对比例进行运动 29 30 void SetLight(bool b) 31 { 32 float amb[4] = { 1.0, 0.8, 0.8, 1 }; 33 float dif[4] = { 1.0, 1.0, 1.0, 1 }; 34 float pos[4] = { 0, 10, 0, 1 }; 35 glLightfv(GL_LIGHT0, GL_AMBIENT, amb); 36 glLightfv(GL_LIGHT0, GL_DIFFUSE, dif); 37 glLightfv(GL_LIGHT0, GL_SPECULAR, dif); 38 glLightfv(GL_LIGHT0, GL_POSITION, pos); 39 glColorMaterial(GL_FRONT, GL_DIFFUSE); 40 41 if (b) 42 { 43 glEnable(GL_LIGHTING); 44 glEnable(GL_LIGHT0); 45 } 46 else 47 { 48 glDisable(GL_LIGHTING); 49 glDisable(GL_LIGHT0); 50 } 51 52 glShadeModel(GL_SMOOTH); 53 } 54 55 void init() 56 { 57 boxtex = new glTexture("星空图.png", true); 58 59 sun = new planet("太阳.png", 0.0f, 1.0f, 1.0f, vec3(0.0f, 0.0f, 0.0f)); 60 sx = new planet("水星.png", 0.5f, 0.5f, 0.2f, vec3(1.4f, 0.4f, 0.0f)); 61 jx = new planet("金星.png", 0.5f, 0.5f, 0.2f, vec3(3.0f, -0.4f, 0.0f)); 62 earth = new planet("地球.png", 1.0f, 2.0f, 0.5f, vec3(5.0f, 2.0f, 8.0f)); 63 moon = new planet("月亮.png", 0.5f, 0.5f, 0.2f, vec3(1.5f, 0.0f, 0.0f)); 64 hx = new planet("火星.png", 0.2f, 0.3f, 0.3f, vec3(7.0f, 0.0f, 0.0f)); 65 mx = new planet("木星.png", 0.4f, 1.0f, 0.5f, vec3(10.0f, 0.0f, 0.0f)); 66 tx = new planet("土星.png", -0.4f, 0.2f, 1.0f, vec3(15.0f, 1.0f, 0.0f)); 67 twx = new planet("天王星.png", 0.8f, 0.5f, 0.3f, vec3(17.0f, 0.0f, 0.0f)); 68 hwx = new planet("海王星.png", 0.6f, 0.5f, 0.4f, vec3(19.0f, 0.8f, 0.0f)); 69 70 parttex = new glTexture("particle.png"); 71 72 trail = new glTrail("spawnflash.png"); 73 trail->setPath(vec3(0, 0, 0)); 74 75 glFrontFace(GL_CCW); 76 glCullFace(GL_BACK); 77 78 //初始化二次曲面对象 79 drawInit(); 80 } 81 82 void deinit() 83 { 84 delete boxtex; 85 delete sun; 86 delete sx; 87 delete jx; 88 delete earth; 89 delete moon; 90 delete hx; 91 delete mx; 92 delete tx; 93 delete twx; 94 delete hwx; 95 delete parttex; 96 delete trail; 97 delete glexp; 98 drawDeInit(); 99 } 100 101 void record() 102 { 103 if (filesys.beginWrite("test.txt")) 104 { 105 filesys.writeInt(angle); 106 filesys.closeFile(); 107 } 108 } 109 110 void rePlay() 111 { 112 if (filesys.beginRead("test.txt")) 113 { 114 filesys.readInt(&angle); 115 filesys.closeFile(); 116 } 117 } 118 119 static void DrawEarthAndMoon(planet *earth, planet *moon) 120 { 121 glPushMatrix();//地球公转+自转(围绕太阳) 122 earth->texture->MakeCurrent(); 123 124 glRotatef(angle*earth->aroundRotatedSpeed, 0.0f, 1.0f, 0.0f); 125 glTranslatef(earth->pos.x, earth->pos.y, earth->pos.z); 126 glRotatef(angle*earth->selfRotatedSpeed, 0.0f, 1.0f, 0.0f); 127 drawSphere(earth->radius, 20, 20, true); 128 129 glPushMatrix();//月球公转+自转(围绕地球) 130 moon->texture->MakeCurrent(); 131 glRotatef(angle*moon->aroundRotatedSpeed, 0.0f, 1.0f, 0.0f); 132 glTranslatef(moon->pos.x, moon->pos.y, moon->pos.z); 133 glRotatef(angle*moon->selfRotatedSpeed, 0.0f, 1.0f, 0.0f); 134 drawSphere(moon->radius, 20, 20, true); 135 glPopMatrix(); 136 137 glPopMatrix(); 138 } 139 static void DrawOtherPlanet(planet * p) 140 { 141 glPushMatrix(); 142 p->texture->MakeCurrent(); 143 glRotatef(angle*p->aroundRotatedSpeed, 0.0f, 1.0f, 0.0f); 144 glTranslatef(p->pos.x, p->pos.y, p->pos.z); 145 glRotatef(angle*p->selfRotatedSpeed, 0.0f, 1.0f, 0.0f); 146 drawSphere(p->radius, 20, 20, true); 147 glPopMatrix(); 148 } 149 150 static void DrawTrail(planet * p) 151 { 152 glPushMatrix(); 153 glRotatef(angle*p->aroundRotatedSpeed*2.0f, 0.0f, 1.0f, 0.0f); 154 glTranslatef(p->pos.x + 0.4f, p->pos.y + 0.3, p->pos.z); 155 glPushMatrix(); 156 glRotatef(-90.0f, 0.0f, 1.0f, 0.0f); 157 trail->draw(camera.pos); 158 glPopMatrix(); 159 glRotatef(angle*p->selfRotatedSpeed, 0.0f, 1.0f, 0.0f); 160 drawSphere(p->radius, 20, 20, true); 161 glPopMatrix(); 162 } 163 164 static void DrawOtherPlanet2(planet * p) 165 { 166 glPushMatrix(); 167 p->texture->MakeCurrent(); 168 169 glRotatef(angle*p->aroundRotatedSpeed, 0.0f, 1.0f, 0.0f); 170 171 glTranslatef(p->pos.x, p->pos.y, p->pos.z); 172 173 174 glRotatef(angle*p->selfRotatedSpeed, 0.0f, 1.0f, 0.0f); 175 176 drawSphere(p->radius, 20, 20, true); 177 178 glPushMatrix(); 179 glRotatef(85, 1.0f, 0.0f, 0.0f); 180 181 drawDisk(1.5, 3, 20); 182 183 glPopMatrix(); 184 glPopMatrix(); 185 186 } 187 void DrawJX() 188 { 189 glPushMatrix(); 190 jx->texture->MakeCurrent(); 191 192 glRotatef(angle*jx->aroundRotatedSpeed * 2, 1.0, 1.0, 1.0); 193 194 glTranslatef(5.0f, 0.0, 0.0f); 195 glRotatef(angle*jx->aroundRotatedSpeed * 2, 0.0f, 0.0f, 1.0f); 196 197 drawSphere(jx->radius, 20, 20, true); 198 glPopMatrix(); 199 } 200 void DrawHX() 201 { 202 glPushMatrix(); 203 hx->texture->MakeCurrent(); 204 205 glRotatef(angle*hx->aroundRotatedSpeed * 2, -1.0, -1.0, 0.0); 206 207 glTranslatef(5.0f, 0.0, 0.0f); 208 209 glRotatef(angle*hx->aroundRotatedSpeed * 2, 0.0f, 0.0f, 1.0f); 210 211 drawSphere(hx->radius, 20, 20, true); 212 213 glPopMatrix(); 214 215 } 216 void testdraw1(planet *p) 217 { 218 glPushMatrix(); 219 p->texture->MakeCurrent(); 220 221 glRotatef(45, 1.0, 0.0, 0.0); 222 glRotatef(angle*p->aroundRotatedSpeed * 2, 0.0f, 1.0f, 0.0f); 223 224 glTranslatef(5.0f, 0, 0.0f); 225 glRotatef(angle*p->aroundRotatedSpeed * 2, 0.0f, 0.0f, 1.0f); 226 227 drawSphere(p->radius, 20, 20, true); 228 glPopMatrix(); 229 } 230 231 void DrawSolarSystem(planet *sun) 232 { 233 sun->texture->MakeCurrent(); 234 235 SetLight(lighting); 236 glTranslatef(sun->pos.x, sun->pos.y, sun->pos.z); 237 glRotatef(angle*sun->selfRotatedSpeed, 0.0f, 1.0f, 0.0f); 238 drawSphere(sun->radius, 50, 50, true); 239 DrawEarthAndMoon(earth, moon);//地月绘制 240 DrawOtherPlanet(sx); 241 DrawOtherPlanet(jx); 242 DrawOtherPlanet(twx); 243 DrawOtherPlanet(hwx); 244 //带光圈绘制 245 DrawOtherPlanet2(mx); 246 DrawOtherPlanet2(tx); 247 DrawTrail(jx); 248 } 249 250 void myKeyboardFunc(unsigned char key, int x, int y) 251 { 252 switch (key) 253 { 254 case 27: //ESC 255 exit(0); //退出系统 256 break; 257 case ‘w‘://摄像机向前运动 258 259 camera.pos -= camera.forward*0.5; 260 glutPostRedisplay(); 261 break; 262 case ‘s‘://摄像机向后运动 263 camera.pos += camera.forward*0.5; 264 265 glutPostRedisplay(); 266 break; 267 case ‘a‘://摄像机向左运动 268 269 camera.pos -= camera.right *0.5; 270 glutPostRedisplay(); 271 break; 272 case ‘d‘://摄像机向右运动 273 274 camera.pos += camera.right*0.5; 275 glutPostRedisplay(); 276 break; 277 case ‘f‘://正视图和顶视图切换 278 279 frontViewOnOff ^= 1; 280 glutPostRedisplay(); 281 break; 282 case ‘r‘://记录 283 record(); 284 glutPostRedisplay(); 285 break; 286 case ‘p‘://回放 287 rePlay(); 288 glutPostRedisplay(); 289 break; 290 case ‘l‘://灯源开关 291 lighting = !lighting; 292 glutPostRedisplay(); 293 break; 294 } 295 296 } 297 298 299 void myReshape(int w, int h) 300 { 301 glViewport(0, 0, w, h); 302 glMatrixMode(GL_PROJECTION); 303 glLoadIdentity(); 304 gluPerspective(60, GLfloat(w) / h, 0.1, 1000); 305 glMatrixMode(GL_MODELVIEW); 306 glLoadIdentity(); 307 glClearColor(0.5f, 0.5f, 0.5f, 1.0f); 308 glClearDepth(1.0f); 309 glEnable(GL_DEPTH_TEST); 310 glDepthFunc(GL_LESS); 311 glShadeModel(GL_SMOOTH); 312 } 313 314 void creatExplosion(float x, float y, float z, int num, float spread) 315 { 316 if (glexp != NULL) { delete glexp; glexp = NULL; } 317 glexp = new glExplosion(num, vec3(0, 0, 0), spread, parttex->m_tex); 318 px = x, pz = z, py = y; 319 isexp = false; 320 numexp = 0; 321 } 322 323 void drawExplosion() 324 { 325 glPushMatrix(); 326 glTranslatef(px, py, pz); 327 if (isexp == false) 328 { 329 glexp->Render(); 330 isexp = true; 331 } 332 if (isexp) 333 { 334 glexp->Update(0.03f); 335 isexp = false; 336 } 337 glPopMatrix(); 338 } 339 340 void myDisplay(void) 341 { 342 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 343 344 camera.update(); 345 346 //如果顶视图的话,沿着x轴旋转90度 347 glRotatef(frontViewOnOff*90.0f, 1.0f, 0.0f, 0.0f); 348 349 //绘制天空盒 350 glDrawSkyBox(boxtex, 0.0f, 0.0f, 0.0f, 1000.0f, 1000.0f, 1000.0f); 351 352 DrawJX(); 353 DrawHX(); 354 DrawSolarSystem(sun); 355 356 if (numexp > 100) 357 { 358 creatExplosion(1.0f, 1.0f, 1.0f, 100, 1.5f); 359 } 360 361 drawExplosion(); 362 363 angle += 2; 364 numexp++; 365 366 glutSwapBuffers(); 367 } 368 369 void myTimerFunc(int val) 370 { 371 myDisplay(); 372 glutTimerFunc(25, myTimerFunc, 0); 373 } 374 375 int main(int argc, char *argv[]) 376 { 377 glutInit(&argc, argv); 378 glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH); 379 glutInitWindowPosition(100, 100); 380 glutInitWindowSize(800, 600); 381 glutCreateWindow("太阳系 w/s/a/d控制摄像机运动 r/录制 p/回放 f/切换正顶视图 l/光源开关"); 382 init(); 383 glutDisplayFunc(&myDisplay); 384 glutReshapeFunc(&myReshape); 385 glutKeyboardFunc(&myKeyboardFunc); 386 glutTimerFunc(25, myTimerFunc, 0); 387 glutMainLoop(); 388 deinit(); 389 return 0; 390 }
11、源码下载以及参考文档
完整的源代码可以到 https://github.com/jackyblf/SolarSystem-openGL- 进行下载。
源码中包含了billboardingtut.pdf的文档,讲解了所有的billboard类型以及适用范围,基于opengl描述。强烈推荐这篇文档
时间: 2024-10-18 12:07:09