【OpenGL】太阳、地球、月亮实例(一)

您所在的位置:网站首页 用地球仪模拟地球公转的实验 【OpenGL】太阳、地球、月亮实例(一)

【OpenGL】太阳、地球、月亮实例(一)

2023-12-16 02:38| 来源: 网络整理| 查看: 265

准备把自己这几天的学习opengl的经验写下来,自己是这方面的小白,希望大神可以对有问题以及可以优化的地方提出来。也欢迎指出不足和吐槽。希望帮到小白。

自己参考得比较多的网站是这个: http://www.cppblog.com/doing5552/archive/2009/01/08/71532.html 第一个实例也是上面的网站给出来的,但是进行了一点点优化。

所有代码都可以去github免费下载(不怎么喜欢CSDN的积分下载): https://github.com/Iamttp/OpenGLTest

我一直比较推崇实例学习,并且网上opengl的实例比较少,所以会一直用实例。好先上这一节的效果图。

在这里插入图片描述

先把基本的框架弄出来,功能就是画一个白色的矩形,然后空闲时调用,会一直更新my_angle,如果不理解这里,可以查看刚刚提到的网站:http://www.cppblog.com/doing5552/archive/2009/01/08/71532.html

#include #include #include #include // 表示旋转的角度 static int my_angle = 0; void myDisplay(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glRectf(-0.5f, -0.5f, 0.5f, 0.5f); glutSwapBuffers(); } /** * 计时增加角度 */ void myIdle(void) { static int mm = 0; mm++; if (mm % 300000 == 0) { ++my_angle; if (my_angle >= 360) my_angle = 0; myDisplay(); } } int main(int argc, char* argv[]) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA); glutInitWindowPosition(100, 100); glutInitWindowSize(1000, 1000); glutCreateWindow("太阳,地球和月亮"); // 改了窗口标题 // glutDisplayFunc(&myDisplay); glutIdleFunc(&myIdle); // 表示在CPU空闲的时间调用某一函数 // 在OpenGL中,默认是没有开启深度检测的,后绘制的物体覆盖先绘制的物体。 // GL_DEPTH_TEST 用来开启更新深度缓冲区的功能 glEnable(GL_DEPTH_TEST); glutMainLoop(); return 0; }

然后就可以更改myDisplay函数,来渲染地球月亮和太阳,这里太阳是静止的,地球就先调用函数:glTranslatef(0.5, 0.5, -0.5); //平移,参数分别表示平移的坐标xyz。

那为什么是0.5呢? OpenGL仅当3D坐标在3个轴(x、y和z)上都为-1.0到1.0的范围内时才处理它。所有在所谓的标准化设备坐标(Normalized Device Coordinates)范围内的坐标才会最终呈现在屏幕上(在这个范围以外的坐标都不会显示)。

那为什么是0.5, 0.5, -0.5呢? 因为我想呈现三维效果,然后就假设旋转的轴是1,1,1,对着屏幕的右边为x正向,上边为y正向,屏幕朝外为z正向。

然后就是月亮,对于月亮,先假设原点为地球,让月亮绕着原点旋转,然后在平移到地球周围。注意渲染顺序是从下往上。

glRotated(my_angle, 1.0, 1.0, 1.0); //然后移动到地球旁边旋转 glTranslatef(0.5, 0.5, -0.5); //平移 glRotated(my_angle, 1.0, 1.0, 1.0); //先假设原点为地球旋转 glTranslatef(-0.15, -0.15, 0.15); //平移

然后总的代码就是:

#include #include #include #include // 表示旋转的角度 static int my_angle = 0; void myDisplay(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 太阳 glPushMatrix(); glColor3f(1.0, 1.0, 0.0); glutSolidSphere(0.15, 200, 200); glPopMatrix(); // 地球 glPushMatrix(); glColor3f(0.0, 0.0, 1.0); glRotated(my_angle, 1.0, 1.0, 1.0); //公转 glTranslatef(0.5, 0.5, -0.5); //平移 glutSolidSphere(0.1, 200, 200); glPopMatrix(); // 月亮 glPushMatrix(); glColor3f(1.0, 1.0, 1.0); glRotated(my_angle, 1.0, 1.0, 1.0); //然后移动到地球旁边旋转 glTranslatef(0.5, 0.5, -0.5); //平移 glRotated(my_angle, 1.0, 1.0, 1.0); //先假设原点为地球旋转 glTranslatef(-0.15, -0.15, 0.15); //平移 glutSolidSphere(0.05, 200, 200); //绘制月亮 glPopMatrix(); glutSwapBuffers(); } /** * 计时增加角度 */ void myIdle(void) { static int mm = 0; mm++; if (mm % 300000 == 0) { ++my_angle; if (my_angle >= 360) my_angle = 0; myDisplay(); } } int main(int argc, char* argv[]) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA); glutInitWindowPosition(100, 100); glutInitWindowSize(1000, 1000); glutCreateWindow("太阳,地球和月亮"); // 改了窗口标题 // glutDisplayFunc(&myDisplay); glutIdleFunc(&myIdle); // 表示在CPU空闲的时间调用某一函数 // 在OpenGL中,默认是没有开启深度检测的,后绘制的物体覆盖先绘制的物体。 // GL_DEPTH_TEST 用来开启更新深度缓冲区的功能 glEnable(GL_DEPTH_TEST); glutMainLoop(); return 0; }

这里有一个奇怪的地方就是深度(z方向上)有问题,月亮有时候本应该被遮挡却会在地球上面。解决方法是在glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);后面添加代码

glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(75, 1, 0.001f, 1000000000000.0f); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(0, 0, 3, 0, 0, -1, 0.0f, 1.0f, 0.0f);

这样你的太阳、地球、月亮有“近大远小”的透视效果。并启动了深度测试(解决深度(z方向上)的问题)。

OpenGL专栏: https://blog.csdn.net/qq_40515692/article/details/103938499



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3