整个天体系统中,他们都是一颗星球(Star),区别行星和恒星只需要通过它们是否具有父节点即可;其次,对于不同的星球而言,它们通常具有自身的材质,并且不同的材质会表现出自身是否发光,由此我们有了初步的对象模型。故我们将星球分为:普通能够自转并绕某个点公转的星球(Star), 具有特殊材质的星球(Planet), 能够发光的星球(LightPlanet)。
一、编程模型假设:
- 星球的运行轨道为圆形;
- 自转速度保持相同;
- 每次刷新绘制的时候假设时间经过了一天。
- 初始化星球对象;
- 初始化 OpenGL 引擎, 实现 onDraw 和 onUpdate;
- 星球应该自己负责处理自己的属性、绕行关系、变换相关绘制,因此在设计星球的类时应该提供一个绘制 draw() 方法;
- 星球也应该自己处理自己自转公转等更新显示的绘制,因此在设计星球类时候也应该提供一个更新方法 update();
- 在 onDraw() 中应调 用星球的 draw() 方法;
- 在 onUpdate() 中调用星球的 update() 方法;
- 在 onKeyboard() 键盘调整整个太阳系的显示.
- 颜色 color
- 公转半径 radius
- 自转速度 selfSpeed
- 公转速度 speed
- 距离太阳中心的距离 distance
- 绕行的星球 parentStar
- 当前的自转的角度 alphaSelf
- 当前的公转角度 alpha
class Star {
public:
// 星球的运行半径
GLfloat radius;
// 星球的公转、自传速度
GLfloat speed, selfSpeed;
// 星球的中心与父节点星球中心的距离
GLfloat distance;
// 星球的颜色
GLfloat rgbaColor[4];
// 父节点星球
Star* parentStar;
// 构造函数,构造一颗星球时必须提供
// 旋转半径、旋转速度、自转速度、绕行(父节点)星球
Star(GLfloat radius, GLfloat distance,
GLfloat speed, GLfloat selfSpeed,
Star* parent);
// 对一般的星球的移动、旋转等活动进行绘制
void drawStar();
// 提供默认实现,负责调用 drawStar()
virtual void draw() { drawStar(); }
// 参数为每次刷新画面时的时间跨度
virtual void update(long timeSpan);
protected:
Float alphaSelf, alpha;
};
class Planet : public Star {
public:
// 构造函数
Planet(GLfloat radius, GLfloat distance,
GLfloat speed, GLfloat selfSpeed,
Star* parent, GLfloat rgbColor[3]);
// 增加对具备自身材质的行星绘制材质
void drawPlanet();
// 继续向其子类开放重写功能
virtual void draw() { drawPlanet(); drawStar(); }
};
class LightPlanet : public Planet {
public:
LightPlanet(GLfloat Radius, GLfloat Distance,
GLfloat Speed, GLfloat SelfSpeed,
Star* Parent, GLfloat rgbColor[]);
// 增加对提供光源的恒星绘制光照
void drawLight();
virtual void draw() { drawLight(); drawPlanet(); drawStar(); }
};
在太阳系中,太阳系显然是由各个行星组成的;并且,对于太阳系而言,太阳系中行星运动后的视图刷新应该由太阳系来完成。据此太阳系成员变量应为包含行星的变量,成员函数应作为处理太阳系内的视图刷新及键盘响应等事件,所以,我们可以设计
SolarSystem
类:
class SolarSystem {
public:
SolarSystem();
~SolarSystem();
void onDisplay();
void onUpdate();
void onKeyboard(unsigned char key, int x, int y);
private:
Star *stars[STARS_NUM];
// 定义观察视角的参数
GLdouble viewX, viewY, viewZ;
GLdouble centerX, centerY, centerZ;
GLdouble upX, upY, upZ;
};
程序的基本框架:main.cpp
// main.cpp
#include <GL/glut.h>
#include "solarsystem.hpp"
#define WINDOW_X_POS 50
#define WINDOW_Y_POS 50
#define WIDTH 700
#define HEIGHT 700
SolarSystem solarsystem;//实例化一个太阳系
void onDisplay(void) {
solarsystem.onDisplay();
}
void onUpdate(void) {
solarsystem.onUpdate();
}
void onKeyboard(unsigned char key, int x, int y) {
solarsystem.onKeyboard(key, x, y);
}
int main(int argc, char* argv[]) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
glutInitWindowPosition(WINDOW_X_POS, WINDOW_Y_POS);
glutCreateWindow("SolarSystem at Shiyanlou");
glutDisplayFunc(onDisplay);
glutIdleFunc(onUpdate);
glutKeyboardFunc(onKeyboard);
glutMainLoop();
return 0;
}
本实验框架及思路来自实验楼,运行的效果如下图所示: