在OpenGL中绘制太阳、地球和月亮的运动模型。 当按下键盘“E”或“e”时,地球将实现自转;按下键盘“S”或“s”时,地球将绕太阳旋转。按下键盘“Y”或“y”时,月球将绕地球旋转,按下“l(L)”键显示线框模型,按下“F”或“f”键显示带光照的实体模型,三种天体在不同材质(反射率)下的光照效果 ,假设太阳不动,地球和月亮运动到不同位置的光照效果
时间: 2023-07-16 18:14:24 浏览: 183
这是一个比较复杂的问题,需要使用OpenGL进行建模和渲染,以及键盘事件处理。以下是代码的主要框架和思路:
1. 初始化OpenGL窗口和场景,包括视角、光照、材质等设置。
2. 创建太阳、地球和月亮的3D模型,包括几何形状、纹理贴图等。
3. 在每一帧中,更新天体的位置和旋转角度,并根据按键事件进行相应的操作。
4. 根据当前位置和光照设置计算每个天体的颜色和亮度,并进行渲染。
以下是可能的代码实现,仅供参考:
```c++
#include <GL/glut.h>
#include <cmath>
// 天体半径和距离比例
const float SUN_RADIUS = 6.96e8;
const float EARTH_RADIUS = 6.371e6;
const float MOON_RADIUS = 1.737e6;
const float EARTH_ORBIT = 1.496e11;
const float MOON_ORBIT = 3.844e8;
// 天体材质和光照设置
const GLfloat SUN_AMBIENT[] = { 1.0, 1.0, 0.0, 1.0 };
const GLfloat SUN_DIFFUSE[] = { 1.0, 1.0, 0.0, 1.0 };
const GLfloat SUN_SPECULAR[] = { 1.0, 1.0, 1.0, 1.0 };
const GLfloat SUN_SHININESS = 100.0;
const GLfloat EARTH_AMBIENT[] = { 0.0, 0.5, 1.0, 1.0 };
const GLfloat EARTH_DIFFUSE[] = { 0.0, 0.5, 1.0, 1.0 };
const GLfloat EARTH_SPECULAR[] = { 1.0, 1.0, 1.0, 1.0 };
const GLfloat EARTH_SHININESS = 50.0;
const GLfloat MOON_AMBIENT[] = { 0.7, 0.7, 0.7, 1.0 };
const GLfloat MOON_DIFFUSE[] = { 0.7, 0.7, 0.7, 1.0 };
const GLfloat MOON_SPECULAR[] = { 1.0, 1.0, 1.0, 1.0 };
const GLfloat MOON_SHININESS = 10.0;
const GLfloat LIGHT_POSITION[] = { 0.0, 0.0, 0.0, 1.0 };
const GLfloat LIGHT_AMBIENT[] = { 0.2, 0.2, 0.2, 1.0 };
const GLfloat LIGHT_DIFFUSE[] = { 1.0, 1.0, 1.0, 1.0 };
const GLfloat LIGHT_SPECULAR[] = { 1.0, 1.0, 1.0, 1.0 };
// 天体的位置和旋转角度
float sunAngle = 0.0;
float earthAngle = 0.0;
float moonAngle = 0.0;
bool earthRotation = false;
bool earthOrbit = false;
bool moonOrbit = false;
bool wireframe = false;
bool lighting = true;
// 创建天体的3D模型
void createSphere(float radius, int slices, int stacks) {
GLUquadricObj* quadric = gluNewQuadric();
gluQuadricTexture(quadric, GL_TRUE);
gluSphere(quadric, radius, slices, stacks);
gluDeleteQuadric(quadric);
}
void createSun() {
if (wireframe) {
glutWireSphere(SUN_RADIUS, 32, 32);
} else {
glMaterialfv(GL_FRONT, GL_AMBIENT, SUN_AMBIENT);
glMaterialfv(GL_FRONT, GL_DIFFUSE, SUN_DIFFUSE);
glMaterialfv(GL_FRONT, GL_SPECULAR, SUN_SPECULAR);
glMaterialf(GL_FRONT, GL_SHININESS, SUN_SHININESS);
createSphere(SUN_RADIUS, 32, 32);
}
}
void createEarth() {
if (wireframe) {
glutWireSphere(EARTH_RADIUS, 32, 32);
} else {
glMaterialfv(GL_FRONT, GL_AMBIENT, EARTH_AMBIENT);
glMaterialfv(GL_FRONT, GL_DIFFUSE, EARTH_DIFFUSE);
glMaterialfv(GL_FRONT, GL_SPECULAR, EARTH_SPECULAR);
glMaterialf(GL_FRONT, GL_SHININESS, EARTH_SHININESS);
createSphere(EARTH_RADIUS, 32, 32);
}
}
void createMoon() {
if (wireframe) {
glutWireSphere(MOON_RADIUS, 16, 16);
} else {
glMaterialfv(GL_FRONT, GL_AMBIENT, MOON_AMBIENT);
glMaterialfv(GL_FRONT, GL_DIFFUSE, MOON_DIFFUSE);
glMaterialfv(GL_FRONT, GL_SPECULAR, MOON_SPECULAR);
glMaterialf(GL_FRONT, GL_SHININESS, MOON_SHININESS);
createSphere(MOON_RADIUS, 16, 16);
}
}
// 更新天体的位置和旋转角度
void updateSun() {
// 太阳不动
}
void updateEarth() {
if (earthRotation) {
earthAngle += 0.5;
if (earthAngle > 360.0) {
earthAngle -= 360.0;
}
}
if (earthOrbit) {
earthAngle += 0.1;
if (earthAngle > 360.0) {
earthAngle -= 360.0;
}
}
}
void updateMoon() {
if (moonOrbit) {
moonAngle += 1.2;
if (moonAngle > 360.0) {
moonAngle -= 360.0;
}
}
}
// 根据当前位置和光照设置计算颜色和亮度
void computeColor(float radius, GLfloat* ambient, GLfloat* diffuse, GLfloat* specular, GLfloat* shininess) {
GLfloat distance = sqrtf(LIGHT_POSITION[0] * LIGHT_POSITION[0] + LIGHT_POSITION[1] * LIGHT_POSITION[1] + LIGHT_POSITION[2] * LIGHT_POSITION[2]);
GLfloat attenuation = 1.0 / (1.0 + 0.0001 * distance + 0.00000001 * distance * distance);
GLfloat intensity = attenuation * LIGHT_DIFFUSE[0];
GLfloat angle = acosf(LIGHT_POSITION[2] / distance);
GLfloat height = radius * sinf(angle);
GLfloat slope = height / radius;
GLfloat aspect = LIGHT_POSITION[0] / LIGHT_POSITION[1];
GLfloat azimuth = atanf(aspect);
GLfloat orientation = LIGHT_POSITION[1] > 0 ? 1.0 : -1.0;
GLfloat rotation = (azimuth + orientation * slope) / M_PI;
if (rotation < 0.0) {
rotation += 2.0;
}
GLfloat r = 0.8 + 0.2 * rotation;
GLfloat g = 0.5 + 0.5 * sinf(height / 1000.0);
GLfloat b = 0.2 + 0.8 * sinf(height / 5000.0);
ambient[0] = diffuse[0] = specular[0] = intensity * r;
ambient[1] = diffuse[1] = specular[1] = intensity * g;
ambient[2] = diffuse[2] = specular[2] = intensity * b;
*shininess = 10.0 + 90.0 * sinf(height / 10000.0);
}
void computeSunColor() {
computeColor(SUN_RADIUS, SUN_AMBIENT, SUN_DIFFUSE, SUN_SPECULAR, &SUN_SHININESS);
}
void computeEarthColor() {
computeColor(EARTH_RADIUS, EARTH_AMBIENT, EARTH_DIFFUSE, EARTH_SPECULAR, &EARTH_SHININESS);
}
void computeMoonColor() {
computeColor(MOON_RADIUS, MOON_AMBIENT, MOON_DIFFUSE, MOON_SPECULAR, &MOON_SHININESS);
}
// 渲染场景
void display() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// 设置视角和光照
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0.0, 0.0, 5.0e11, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
glLightfv(GL_LIGHT0, GL_POSITION, LIGHT_POSITION);
if (lighting) {
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glLightfv(GL_LIGHT0, GL_AMBIENT, LIGHT_AMBIENT);
glLightfv(GL_LIGHT0, GL_DIFFUSE, LIGHT_DIFFUSE);
glLightfv(GL_LIGHT0, GL_SPECULAR, LIGHT_SPECULAR);
} else {
glDisable(GL_LIGHTING);
}
// 绘制太阳、地球和月亮
glPushMatrix();
computeSunColor();
glRotatef(sunAngle, 0.0, 1.0, 0.0);
createSun();
glPopMatrix();
glPushMatrix();
computeEarthColor();
glRotatef(earthAngle, 0.0, 1.0, 0.0);
glTranslatef(EARTH_ORBIT, 0.0, 0.0);
createEarth();
glPushMatrix();
computeMoonColor();
glRotatef(moonAngle, 0.0, 1.0, 0.0);
glTranslatef(MOON_ORBIT, 0.0, 0.0);
createMoon();
glPopMatrix();
glPopMatrix();
glutSwapBuffers();
}
// 处理键盘事件
void keyboard(unsigned char key, int x, int y) {
switch (key) {
case 'e':
case 'E':
earthRotation = !earthRotation;
break;
case 's':
case 'S':
earthOrbit = !earthOrbit;
break;
case 'y':
case 'Y':
moonOrbit = !moonOrbit;
break;
case 'l':
case 'L':
wireframe = !wireframe;
break;
case 'f':
case 'F':
lighting = !lighting;
break;
}
}
// 初始化OpenGL窗口和场景
void init() {
glClearColor(0.0, 0.0, 0.0, 0.0);
glShadeModel(GL_SMOOTH);
glEnable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
glEnable(GL_NORMALIZE);
glEnable(GL_COLOR_MATERIAL);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, 1.0, 0.1, 1.0e15);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMaterialfv(GL_FRONT, GL_SPECULAR, SUN_SPECULAR);
glMaterialf(GL_FRONT, GL_SHININESS, SUN_SHININESS);
}
// 主函数
int main(int argc, char* argv[]) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowSize(800, 800);
glutCreateWindow("Solar System");
glutDisplayFunc(display);
glutIdleFunc(display);
glutKeyboardFunc(keyboard);
init();
glutMainLoop();
return 0;
}
```
注意,这只是一个简单的实现,并没有考虑到很多细节,比如天体的轨道形状、倾斜角度等,还有光照计算的精度和效率问题。实际上,这个问题可以拆分成多个子问题,每个子问题都需要更加详细的实现和调试。但是,这个代码可以作为一个基础框架,供进一步学习和改进。
阅读全文