Solarysystem项目总结

一、汇总所用函数与知识

1.头文件:

#include<GL/glut.h>或#include<gl/glut.h>

2.openGL相关函数

(1)主函数创建窗口

glutInit();

glutInitDisplayMode();

glutInitWindowPosition();

glutinitwindowSize();

glutCreateWindow();

glutDisplayFunc();

glutIdleFunc();

glutKeyboardFunc();

glutMainLoop();

(2)绘制星球star

glEnable(GL_LINE_SMOOTH); glEnable(GL_BLEND);

glPushMatrix();

glRotatef();

glTranslatef();

glBegin(GL_LINES);

glVertex2f();

glEnd();

glColor3f();

glutSolidSphere();

gpPopMatrix();

(3)绘制地球类行星

glMaterialfv(GL_FRONT, GL_EMISSION, mat_emission); glMaterialf(GL_FRONT, GL_SHININESS, mat_shininess);

(4)显示onDisplay

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClearColor(.7f, .7f, .7f, .1f); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(75.0f, 1.0f, 1.0f, 40000000); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(viewX, viewY, viewZ, centerX, centerY, centerZ, upX, upY, upZ); glEnable(GL_LIGHT0); glEnable(GL_LIGHTING); glEnable(GL_DEPTH_TEST);

glutSwapBuffers();

3.其他编程相关知识

enum枚举

二、函数详解

1.主函数创建窗口

(1)glutinit();

(21条消息) 一. glutInit(argc, argv); glut初始化API_xianhua7877的博客-CSDN博客_glutinit

glutinit()用于初始化glut库,从main处获取两个参数

int main(int argc, char* argv[])
//对应: glutInit(&argc,argv);
//这是目前所用的,其它参考链接

(2)glutInitDisplayMode();

glutinitDisplayMode()函数的作用主要时在创建窗口时指定模式的类型。

函数的原型为:glutinitDisplayMode(unsigned int mode)

mode 包括集中可能的布尔组合,可以指定颜色模式,数量和缓冲区类型

颜色模式:

GLUT_RGBA GLUT_RGB GLUT_INDEX 三种 其中 GLUT_RGBA为默认的颜色模式,一般使用它即可(修改没有看出一二的区别)

GLUT_INDEX 是指定颜色索引模式的窗口,具体含义,未知。

缓冲区类型:

GLUT_DOUBLE GLUT_SINGLE两种,分别代表双缓冲窗口和单缓冲窗口

单缓冲,将所有的绘图指令在窗口上完成,绘图效率慢,如果电脑比较慢,屏幕会发生闪烁,一般只用于显示单独的一副非动态的图像;

双缓冲,绘图指令在一个缓冲区完成,绘图很快,在绘图指令完成后再通过交换完成的图形立即显示在屏幕上,避免绘图不完整,效率高,一般用于生成动画效果。

一般使用 GLUT_DOUBLE 即可

其它类型:(暂且不做深入探究)

(3)glutInitWindowPosition();

原始函数:void glutinitWindowPosition(int x,int y)

x,y的单位为像素,是确定窗口左上角出现在屏幕上的位置,屏幕左上角为(0,0)。

(4)glutinitwindowSize();

函数原型 void glutinitwindowSize(int width,int height) 设置窗口的初始大小

width 宽 height 长 单位是像素

(5)glutCreateWindow();

函数原型: int glutCreatWindow(char *name)

功能是创建一个以name命名的窗口 比如说:glutCreateWindow("solarysystem")

当窗口创建之后,窗口的环境状态改变可以很快的完成,但是只有glutMainloop()执行之后窗口显示状态才会执行,即窗口才会出现,否则窗口会闪现一瞬然后迅速消失。

返回值是窗口唯一的短整型标识符,范围从1开始,当调用glutSetWindow时可以使用这个窗口的标识符。

标识符的一部分应用:

(21条消息) OpenGL入门6——GLUT窗口demystify的博客-CSDN博客glutcreatewindow

(6)glutDisplayFunc();

函数原型:void glutDisplayFunc(void(*func)(void))

使用方式:glutDisplayFunc(&display) void display(void)是绘制函数

如:glutDisplayFunc(onDisplay);

该函数在程序运行时是自动调用的,调用的时机有:窗口内容绘制、窗口大小改变,窗口重绘。

作用就是绘制窗口

(7)glutIdleFunc();

函数原型:void glutidelFunc(void(*func)(void))

使用方法:glutidelFunc(&func)

如:glutidelFunc(onUpdate)

glut的空闲回调函数,意思是当没有其他操作时,就一直调用func函数,在例子中就是,如果没有其他事件比如扩大缩小窗口等等,那么就一直执行onUpdate函数,不断对窗口画面进行更新,从而实现一个动画效果。

代表了窗口空闲时哪个函数将要被调用

回调函数参考 知识集锦回调函数

(8)glutKeyboardFunc();

普通键盘输入-glutKeyboard()

函数原型:void glutKeyboardFunc(void(*Func)(unsigned char key,int x,int y));

用于处理可以用Ascii表示的键盘按下事件。

使用方法: glutKeyboardFunc(&ProcessKeyboard)

如:glutKeyboardFunc(onKeyboard);

其中key是指按下的键的ascii,对于字母数字可以直接用'x' 、'9'表示,对于esc、回车、delete等有ascii的就用对应的ascii数值表示,如esc的对应的是27

而x,y代表的是按下键盘时鼠标相当于窗口左上角所在的位置,以像素为单位,目前作用未知

给一个例子:

//main
void onKeyboard(unsigned char key, int x, int y)//键盘控制
{solarsystem.onKeyboard(key, x, y);
}
int main()
{glutKeyboardFunc(onKeyboard);
}
//solarysystem
void onKeyboard(unsigned char key, int x, int y){switch (key) {case 'w': viewY += OFFSET; break; // 摄像机Y 轴位置增加 OFFSETcase 's': viewZ += OFFSET; break;case 'S': viewZ -= OFFSET; break;case 'a': viewX -= OFFSET; break;case 'd': viewX += OFFSET; break;case 'x': viewY -= OFFSET; break;case 'r':viewX = 0; viewY = REST_Y; viewZ = REST_Z;centerX = centerY = centerZ = 0;upX = upY = 0; upZ = 1;break;case 27: exit(0); break;default: break;}}

特殊键盘输入处理函数:glutSpecialFunc();

用于处理不存在于ascii中的键盘输入

函数原型:void glutspecialFunc(void(*func)(int key,int x,int y));

key参数:

GLUT_KEY_F1:F1功能键 GLUT_KEY_F2:F2功能键

GLUT_KEY_F3:F3功能键 GLUT_KEY_F4:F4功能键

GLUT_KEY_F5:F5功能键 GLUT_KEY_F6:F6功能键

GLUT_KEY_F7:F7功能键 GLUT_KEY_F8:F8功能键

GLUT_KEY_F9:F9功能键 GLUT_KEY_F10:F10功能键

GLUT_KEY_F11:F11功能键 GLUT_KEY_F12:F12功能键

GLUT_KEY_LEFT:左方向键 GLUT_KEY_UP:上方向键

GLUT_KEY_RIGHT:右方向键 GLUT_KEY_DOWN:下方向键

GLUT_KEY_HOME:Home键 GLUT_KEY_END:End键

GLUT_KEY_INSERT:Insert键 GLUT_KEY_PAGE_UP:PageUp键

GLUT_KEY_PAGE_DOWN:PageDown键

(9)glutMainLoop();

开启glut事件处理循环,让所有与事件有关的函数调用无限循环。

在一个glut程序中,这个例程被调用一次,就不再返回,它将调用必要的任何已注册的回调。

所谓的事件就是比如安乐不同的键,进行了鼠标互动,进行了数据更新,甚至于每一次进行的刷新,就是例如以下的函数

glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
glutInitWindowPosition(WINDOW_X_POS, WINDOW_Y_POS);
glutInitWindowSize(WIDTH, HEIGHT);
glutCreateWindow("solarsystem by c++");
glutDisplayFunc(onDisplay);
glutIdleFunc(onUpdate);
glutKeyboardFunc(onKeyboard);

只有程序退出(如exit(0)出现)时才会跳出循环,否则就是无限循环,当没有其他操作时,进行的事件就是上面说过的空闲回调函数,在这里就是进行onUpdate更新。

(10)其他窗口函数--知识集锦glut窗口

(21条消息) OpenGL入门6——GLUT窗口demystify的博客-CSDN博客glutcreatewindow

(11)回调函数集锦

(21条消息) Glut 回调函数小结_xianhua7877的博客-CSDN博客

2.solarysystem.h—宏定义内容和全局变量

(1)定义多维数组的宏

功能:当很多不同的物品都有相同的数组,数组名相同而值不同那么就用它

#include<iostream>
using namespace std;
#define AVG_three(name,v1,v2,v3)((name[0])=(v1),(name[1])=(v2),(name[2])=(v3))
int main()
{int name[3]={0,0,0};AVG_three(name,2,3,4);cout<<name[1];AVG_three(name,2,5,3);cout<<name[1];return 0;
}

#define 名字(放数组名的地方(随意去一个例如name),值1,值2,值3。。。。)((数组名[0])=(值1),(数组名[1]=(值2).。。。。。。)

如果太长两部分之间可以用反斜杠连接,换到下一行,否则就要在一行内完成宏定义

#define AVG_three(name,v1,v2,v3)\
((name[0])=(v1),(name[1])=(v2),(name[2])=(v3))

(2)enum枚举数组

参见知识集锦-enum数组

3.绘制星球—drawStar

(1)glEnable()

glEnable(GL_LINE_SMOOTH)//执行后过滤线段的锯齿

glEnable(GL_BLEND)//启用颜色混合,例如实现半透明效果

其他glenable()相关参数和功能参照知识集锦--glenable

(2)glPushMatrix() glPopMatrix();

将平移变换等操作放在这两个函数之间可以保证操作时是以世界原点为基础的,可以使本次变换与上次变换独立

更多了解参考:

glPushMatrix_百度百科 (baidu.com)

(22条消息) glPushMatrix和glPopMatrix的作用passtome的博客-CSDN博客glpopmatrix

使用:

        glPushMatrix();//开始{//变换//处理卫星if (parentStar != 0 && parentStar->distance > 0){glRotatef(parentStar->alpha, 0, 0, 1);glTranslatef(parentStar->distance, 0.0, 0.0);}glBegin(GL_LINES);for (int i = 0; i < n; ++i)glVertex2f(distance * cos(2 * PI * i / n), distance * sin(2 * PI * i / n));glEnd();glRotatef(alpha, 0, 0, 1);glTranslatef(distance, 0.0, 0.0);glRotatef(alphaself, 0, 0, 1);glColor3f(rgbaColor[0], rgbaColor[1], rgbaColor[2]);glutSolidSphere(radius, 40, 32);}glPopMatrix();//结束

(3)glRotatef(alpha,x,y,z)

void WINAPI glRotatef(GLfloat angle,//角度  xyz为正则是逆时针旋转GLfloat x,GLfloat y,GLfloat z
);

angle:为旋转的角度,单位为度。 x,y,z:为对应xyz轴的布尔值变量。 x,y,z表示要围绕哪个坐标轴旋转,x,y,z值相当于一个布尔值,0.0表示假,而非零参数则表示真。 例如:

如果想让当前的几何图形围绕着z轴转,那么让x=0,y=0,而z设为非零值即可。

如果这里的x=0,y=0,z=0那么将围绕着x轴旋转。

如果设置的旋转值(x,y,z的值)为正数,那么旋转的方向是逆时针的,如果旋转值是负数,那么旋转的方向是顺时针的。

(4)glTranslatef(x,y,z)

glTranslated()和glTranslatef()这两个函数是定义一个平移矩阵,该矩阵与当前矩阵相乘,使后续的图形进行平移变换。

void glTranslated(GLdouble x,GLdouble y,GLdouble z);
​
void glTranslatef(GLdouble x,GLdouble y,GLdouble z);
//x,y,z:分别指定沿x,y,z轴方向的平移分量。重点就是沿着x,y,z轴移动。
//注意在glTranslatef(x, y, z)中,移动的时候,并不是相对屏幕中心移动,而是相对与当前所在的屏幕位置。作用是将绘点坐标的原点在当前原点的基础上平移一个(x,y,z)向量。

(5)glBegin()

glBegin(GL_LINES)以两个顶点为一组绘制线段

glBegin操作参考:

glBegin 函数 (Gl.h) - Win32 apps | Microsoft Docs

(22条消息) OpenGL 解析glBegin()Hi乌龟的博客-CSDN博客_glbegin函数

(22条消息) openGL学习笔记三 : 绘制点、线以及多边形天心fox的博客-CSDN博客

(6)glVertex2f()

绘制点的函数有很多,数字和符号不同数字代表几个参数,符号代表类型,2f表示两个32位浮点数(GLfloat和GLclampf)的参数,代表点的x y坐标

其他的:

(22条消息) openGL学习笔记三 : 绘制点、线以及多边形天心fox的博客-CSDN博客

(7)glEnd()

glBegin()和glEnd()结合限定了一组或多组图元的定点定义

他们之间可以调用的函数:

(22条消息) glBegin()和glEnd()之间可调用的函数PersonFly小逗的博客-CSDN博客

(8)glColor3f()

void WINAPI glColor3f(GLfloat red,GLfloat green,GLfloat blue
);

三个参数值的范围是[0.0,1.0],可以将这三个参数值视为颜色的成分。

0.0------>不使用该颜色

1.0------->使用该颜色的最大值

glColor3f(0.0, 0.0, 0.0);  --> 黑色
glColor3f(1.0, 0.0, 0.0);  --> 红色
glColor3f(0.0, 1.0, 0.0);  --> 绿色
glColor3f(0.0, 0.0, 1.0);  --> 蓝色
glColor3f(1.0, 1.0, 0.0);  --> 黄色
glColor3f(1.0, 0.0, 1.0);  --> 品红色
glColor3f(0.0, 1.0, 1.0);  --> 青色
glColor3f(1.0, 1.0, 1.0);  --> 白色

如果在glBegin()与glEnd()函数之间多次连续调用颜色函数,那么,只会显示出最后一次的颜色

例如:

glBegin(GL_POINTS)glColor3f(0.0, 1.0,  0.0);  //绿色glColor3f(1.0, 1.0,  0.0);  //黄色glVertex(0.25, 0.75, 0.0);
glEnd();

最终线的颜色是黄色。

其他opengl颜色的应用:

OpenGL(四)之颜色篇 - 马列神教 - 博客园 (cnblogs.com)

(9)glutSolidSphere()

函数原型:void glutSolidSphere(GLdouble radius , GLint slices , GLint stacks);

该函数用于渲染一个球体,球体球心位于原点,一般来说,后两个参数赋值越大,渲染花费的事件越长,效果越逼真。

radius---->球体半径 slices------>经线数 stacks----->纬线数

(10)drawStar总结

首先处理卫星,让其跟着母星进行大的运动,并移动到响应的初始位置。

如果不是卫星,那么就绘制公转轨道,进行公转和绘制公转半径,进行自转,绘制星球颜色,最后根据这些操作渲染出一个球体。

4.绘制地球类行星

(1)glMaterialfv()

函数原型

void WINAPI glMaterialfv(
GLenum face,
GLenum pname,
const GLfloat *params
);

指定用于光照计算的当前材质属性

face:取值为 GL_FRONT GL_BACK GL_FRONT和GL_BACK 代表属性将应用于物体的那一面,前后还是前和后

pname:指出要设置那种材质属性,属性一共有五种分别是

GL_AMBIENT 环境颜色
GL_GIFFUSE 散射颜色
GL_SPECULAR 镜面反射颜色
GL_EMISSION 材质的发光颜色
GL_SHININESS 镜面反射指数

params:要设置的属性值,是一个指向数组的指针(向量版本)或一个数值(非向量版本)。只有设置参数值是GL_SHININESS时,才能使用非向量版本。

下面为pname的可能取值和对应值的意义

参数值 默认值 意义
GL_AMBIENT (0.2,0.2,0.2,1.0) 材质的环境颜色
GL_DIFFUSE (0.8,0.8,0.8,1.0) 材质的散射颜色
GL_AMBIENT_AND_DIFFUSE 材质的环境颜色和散射颜色
GL_SPECULAR (0.0,0.0,0.0,1.0) 材质的镜面反射颜色
GL_SHININESS 0.0 镜面反射指数
GL_EMISSION (0.0,0.0,0.1,1.0) 材质的发射光颜色
GL_COLOR_INDEXES (0, 1, 1) 环境颜色索引、散射颜色索引和镜面反射颜色索引

目前属性如何取值找不到太多的参考,但GL_AMBIENT和GL_DIFFUSE尽量相同会更贴合实际并且

以下为材质表四组值分别指GL_AMBIENT   GL_DIFFUSE  GL_SPECULAR GL_SHININESS
​
//黄铜
​0.329412, 0.223529, 0.027451, 1.000000,
​0.780392, 0.568627, 0.113725, 1.000000,
​0.992157, 0.941176, 0.807843, 1.000000,
​27.897400,
​//青铜
​0.212500, 0.127500, 0.054000, 1.000000,
​0.714000, 0.428400, 0.181440, 1.000000,
​0.393548, 0.271906, 0.166721, 1.000000,
​25.600000,
​//亮青铜
​0.250000, 0.148000, 0.064750, 1.000000,
​0.400000, 0.236800, 0.103600, 1.000000,
​0.774597, 0.458561, 0.200621, 1.000000,
​76.800003,
​//铬
​0.250000, 0.250000, 0.250000, 1.000000,
​0.400000, 0.400000, 0.400000, 1.000000,
​0.774597, 0.774597, 0.774597, 1.000000,
​76.800003,
​
//铜
​0.191250, 0.073500, 0.022500, 1.000000,
​0.703800, 0.270480, 0.082800, 1.000000,
​0.256777, 0.137622, 0.086014, 1.000000,
​12.800000,
​
//亮铜
​0.229500, 0.088250, 0.027500, 1.000000,
​0.550800, 0.211800, 0.066000, 1.000000,
​0.580594, 0.223257, 0.069570, 1.000000,
​51.200001,
​
//金
​0.247250, 0.199500, 0.074500, 1.000000,
​0.751640, 0.606480, 0.226480, 1.000000,
​0.628281, 0.555802, 0.366065, 1.000000,
​51.200001,
​
//亮金
​0.247250, 0.224500, 0.064500, 1.000000,
​0.346150, 0.314300, 0.090300, 1.000000,
​0.797357, 0.723991, 0.208006, 1.000000,
​83.199997,
​
//白蜡
​0.105882, 0.058824, 0.113725, 1.000000,
​0.427451, 0.470588, 0.541176, 1.000000,
​0.333333, 0.333333, 0.521569, 1.000000,
​9.846150,
​
//银
​0.192250, 0.192250, 0.192250, 1.000000,
​0.507540, 0.507540, 0.507540, 1.000000,
​0.508273, 0.508273, 0.508273, 1.000000,
​51.200001,
​
//亮银色
​0.231250, 0.231250, 0.231250, 1.000000,
​0.277500, 0.277500, 0.277500, 1.000000,
​0.773911, 0.773911, 0.773911, 1.000000,
​89.599998,
​
//翡翠、祖母绿
​0.021500, 0.174500, 0.021500, 0.550000,
​0.075680, 0.614240, 0.075680, 0.550000,
​0.633000, 0.727811, 0.633000, 0.550000,
​76.800003,
​
//碧玉
​0.135000, 0.222500, 0.157500, 0.950000,
​0.540000, 0.890000, 0.630000, 0.950000,
​0.316228, 0.316228, 0.316228, 0.950000,
​12.800000,
​
//黑曜石
​0.053750, 0.050000, 0.066250, 0.820000,
​0.182750, 0.170000, 0.225250, 0.820000,
​0.332741, 0.328634, 0.346435, 0.820000,
​38.400002,
​
//珍珠
​0.250000, 0.207250, 0.207250, 0.922000,
​1.000000, 0.829000, 0.829000, 0.922000,
​0.296648, 0.296648, 0.296648, 0.922000,
​11.264000,
​
//红宝石
​0.174500, 0.011750, 0.011750, 0.550000,
​0.614240, 0.041360, 0.041360, 0.550000,
​0.727811, 0.626959, 0.626959, 0.550000,
​76.800003,
​
//绿宝石、绿松石
​0.100000, 0.187250, 0.174500, 0.800000,
​0.396000, 0.741510, 0.691020, 0.800000,
​0.297254, 0.308290, 0.306678, 0.800000,
​12.800000,
​
//黑塑料
​0.000000, 0.000000, 0.000000, 1.000000,
​0.010000, 0.010000, 0.010000, 1.000000,
​0.500000, 0.500000, 0.500000, 1.000000,
​32.000000,
​
//黑橡胶
​0.020000, 0.020000, 0.020000, 1.000000,
​0.010000, 0.010000, 0.010000, 1.000000,
​0.400000, 0.400000, 0.400000, 1.000000,
​10.000000,
​
//紫罗兰
​0.110000, 0.060000, 0.090000, 1.000000,
​0.430000, 0.470000, 0.540000, 1.000000,
​0.330000, 0.330000, 0.520000, 1.000000,
​22.000000
​

按照例子推测 GL_EMISSION的四个值应该是RGBA颜色设置的四个值

GLfloat mat_emission[] = { rgbaColor[0],rgbaColor[1],rgbaColor[2],rgbaColor[3] };

使用案例:

        GLfloat mat_ambient[] = { 0.0f,0.0f,0.5f,1.0f };
//环境颜色GLfloat mat_diffuse[] = { 0.0f,0.0f,0.5f,1.0f };
//散射颜色GLfloat mat_specular[] = { 0.0f,0.0f,1.0f,1.0f };
//镜面反射颜色GLfloat mat_emission[] = { rgbaColor[0],rgbaColor[1],rgbaColor[2],rgbaColor[3] };
//材质的发光颜色GLfloat mat_shininess = 90.0f;
//镜面反射指数glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);glMaterialfv(GL_FRONT, GL_EMISSION, mat_emission);glMaterialf(GL_FRONT, GL_SHININESS, mat_shininess);

上面四个带向量的用glMaterialfv()

GL_SHININESS用glMaterialf()

5.绘制发光星球

(1)glLightfv()

函数原型:

void WINAPI glLightfv(GLenum  light,GLenum  pname,const GLfloat *params
);

使用样例:

        GLfloat light_position[] = { 0.0f,0.0f,0.0f,1.0f };GLfloat light_ambient[] = { 0.0f,0.0f,0.0f,1.0f };GLfloat linght_diffuse[] = { 1.0f,1.0f,1.0f,1.0f };GLfloat light_specular[] = { 1.0f,1.0f,1.0f,1.0f };glLightfv(GL_LIGHT0, GL_POSITION, light_position);glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);glLightfv(GL_LIGHT0, GL_DIFFUSE, linght_diffuse);glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);

light: 光线标识符/光源编号,可取GL_LIGHT0、GL_LIGHT1、……、GL_LIGHT7共8个值,分别代表八个不同的光源。

pname:光源属性

GL_AMBIENT(设置光源的环境光属性,默认值(0,0,0,1))

GL_DIFFUSE(设置光源的散射光属性,默认值(1,1,1,1))

GL_SPECULAR(设置光源的镜面反射光属性,默认值(1,1,1,1))

GL_POSITION(设置光源的位置,默认值(0,0,1,0))

注意:对于GL_POSITION,(x,y,z,w)定义了光源在空间中的位置。

当w≠0时,它表示光源处于空间中(x,y,z)处,这时的光源称为定点光源;

当w=0时,根据齐次坐标的性质,它表示光源位于无穷远处,此时光源称

为定向光源,其所有光线几乎是相互平等的,如太阳。其光线方向由点

(x,y,z)指向(0,0,0)。

params:光源属性的值,由数组指定

光照设置好后还要启动光照,就像手电筒组装好之后还要打开开关一样,后续会介绍。

6.绘制太阳系—solarsystem

(1)视角

我们定义九个成员变量:

​
GLdouble viewX, viewY, viewZ;
GLdouble centerX, centerY, centerZ;
GLdouble upX, upY, upZ;

接下来了解三维编程中摄像机视角的变化:

如果我们把摄像机想象成我们自己的头,那么:

  • viewX, viewY, viewZ 就相当于头(摄像机)在 世界坐标中的坐标位置;

  • centerX, centerY, centerZ 则相当于头所看(摄像机所拍)物体的坐标位置;

  • upX, upY, upZ 则相当于头顶(摄像机顶部)朝上的方向向量(因为我们可以歪着头观察一个物体)。

所观察物体(太阳)的位置在 (0,0,0),则在SolarSystem类中的构造函数将视角初始化为:

#define REST 700
#define REST_Y (-REST)
#define REST_Z (REST)
​
viewX = 0;
viewY = REST_Y;
viewZ = REST_Z;
centerX = centerY = centerZ = 0;
upX = upY = 0;
upZ = 1;

则可以通过 gluLookAt 函数来设置视角的九个参数:

gluLookAt(viewX, viewY, viewZ, centerX, centerY, centerZ, upX, upY, upZ);

(2)onDisplay

<1>glClear() glClearColor()

函数原型:

void WINAPI glClear(GLbitfield mask
);

GLbitfield:可以使用 | 运算符组合不同的缓冲标志位,表明需要清除的缓冲

  • GL_COLOR_BUFFER_BIT: 当前可写的颜色缓冲

  • GL_DEPTH_BUFFER_BIT: 深度缓冲

  • GL_ACCUM_BUFFER_BIT: 累积缓冲

  •  GL_STENCIL_BUFFER_BIT: 模板缓冲

同时用两个就用|间隔

glClear()函数的作用是用当前缓冲区清除值,也就是glClearColor、glClearDepth、glClearIndex、glClearStencil、glClearAccum等函数所指定的值来清除指定的缓冲区,也可以使用glDrawBuffer一次清除多个颜色缓存。比如:

  glClearColor(0.0,0.0,0.0,0.0);glClear(GL_COLOR_BUFFER_BIT);

  第一条语句表示清除颜色设为黑色,第二条语句表示实际完成了把整个窗口清除为黑色的任务,glClear()的唯一参数表示需要被清除的缓冲区。

<2>glMatrixMode()

函数原型:void glMatrixMode(GLenum mode)

mode指定接下来矩阵操作的目标

  • GL_MODELVIEW,对模型视图矩阵堆栈应用随后的矩阵操作。可以在执行此命令后,输出自己的物体图形了。

  • GL_PROJECTION,对投影矩阵堆栈应用随后的矩阵操作。可以在执行此命令后,为我们的场景增加透视。

  • GL_TEXTURE,对纹理矩阵堆栈应用随后的矩阵操作。可以在执行此命令后,为我们的图形增加纹理贴图。

glMatrixMode(GL_PROJECTION);

代表接下来要对投影进行相关操作。

<3>glLoadIdentity();

函数原型:void glLoadIdentity(void)

功能是对当前矩阵进行初始化,将当前矩阵变成单位矩阵

单位矩阵就是对角线上都是1,其余元素皆为0的矩阵。

调用glLoadIdentity()之后,实际上将当前点移到了屏幕中心:类似于一个复位操作 1.X坐标轴从左至右,Y坐标轴从下至上,Z坐标轴从里至外。 2.OpenGL屏幕中心的坐标值是X和Y轴上的0.0f点。 3.中心左面的坐标值是负值,右面是正值。 移向屏幕顶端是正值,移向屏幕底端是负值。 移入屏幕深处是负值,移出屏幕则是正值。

<4>gluPerspective()

函数原型:

void gluPerspective (GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar)  //视角   横纵比  近距离  远距离

OpenGL有两种投影:正射投影(垂直投影)和透视投影。透视投影通过指定一个平截头体来定义视见体的范围

fovy:视角,代表眼睛睁开的角度,越大则视野范围越宽阔,物体距离越远(0~180)

aspect:表示剪裁面的宽高比,影响到截面的大小。

zNear:近剪裁面到眼睛的位置(非负)

zFar:远剪裁面到眼睛的位置(非负)

zNear的值可以设置的很小,zFar的值可以设置的很大,这样看的范围更深一些

如果一个模型的z坐标为ptz,ptz大于zFar或者ptz小于zNear你都将看不到改模型;

Fovy值在180-360的范围内,你会发现渲染的图像反转了过来(不是镜像),就相当于你和你看到的东西一起倒了过来(脑补一下你眼前的东西跟你一起头朝地,脚朝上);

<5>gluLookAt()

函数原型:

void gluLookAt(GLdouble eyex,GLdouble eyey,GLdouble eyez,GLdouble centerx,GLdouble centery,GLdouble centerz,GLdouble upx,GLdouble upy,GLdouble upz);

该 函数定义一个视图 矩阵,并与当前矩阵相乘。 第一组eyex, eyey,eyez 相机在世界坐标的位置 第二组centerx,centery,centerz 相机镜头对准的物体在世界坐标的位置 第三组upx,upy,upz 相机向上的方向在世界坐标中的方向 你把相机想象成为你自己的脑袋: 第一组数据就是脑袋的位置 第二组数据就是眼睛看的物体的位置 第三组就是头顶朝向的方向(因为你可以歪着头看同一个物体) 同视角

gluLookAt(viewX, viewY, viewZ, centerX, centerY, centerZ, upX, upY, upZ);

头--物---头顶

<6>开启光照

    glEnable(GL_LIGHT0);//打开光源0glEnable(GL_LIGHTING);//打开光照

GL_LIGHT0比较特殊是白光,其他光都是没有颜色的即黑色

OpenGL可以同时为我们提供8个有效的光源。也就是说,我们最多同时启用8个光源。它们分别是GL_LIGHT0 , GL_ LIGHT1,GL_ LIGHT2......*
​
*其中,GL_LIGHT0是最特殊的一个光源,我们可以为GL_ LIGHT0指定环境光成分。在默认情况下,GL_LIGHT0 光源的颜色为白色,其他7个光源在默认情况下是没有颜色的,也即是黑色。*

<7>glEnable(GL_DEPTH_TEST);

glEnable(GL_DEPTH_TEST): 用来开启更新[深度](https://so.csdn.net/so/search?q=深度&spm=1001.2101.3001.7020)缓冲区的功能,也就是,如果通过比较后深度值发生变化了,会进行更新深度缓冲区的操作。启动它,OpenGL就可以跟踪再Z轴上的像素,这样,它只会再那个像素前方没有东西时,才会绘画这个像素。
在做绘画3D时,这个功能最好启动,视觉效果比较真实。

<8>双缓冲交换两个缓冲区指针

glutSwapBuffers();

   glutSwapBuffers函数是 OpenGL中 GLUT工具包中用于实现 双缓冲技术的一个重要函数。该函数的功能是交换两个缓冲区 指针。通常, 我们所看到的窗体、文字、图像,从根本上来说都是“画”出来的。比如,制作一个简单的五子棋, 我们可能先要绘制棋盘,然后绘制棋子,我们可能还要绘制一些提示信息。虽然这些绘制操作有一定的先后顺序,通常情况下,操作系统的这些绘制速度非常的快,使人眼误认为这些绘制操作是同时完成的。但当我们进行复杂的绘图操作时,画面便可能有明显的闪烁。解决这个问题的关键在于使绘制的东西同时出现在 屏幕上。所谓 双缓冲技术, 是指使用两个缓冲区: 前台缓冲和后台缓冲。前台缓冲即我们看到的屏幕,后台缓冲则在内存当中,对我们来说是不可见的。每次的所有绘图操作都在后台缓冲中进行, 当绘制完成时, 把绘制的最终结果复制到 屏幕上, 这样, 我们看到所有GDI元素同时出现在屏幕上,从而解决了频繁刷新导致的画面闪烁问题。在OpenGL中实现 双缓冲技术的一种简单方法:1.在调用 glutInitDisplayMode函数时, 开启GLUT_DOUBLE,即 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);。这里将我们惯用的GLUT_SINGLE替换为GLUT_DOUBLE,意为要使用 双缓冲而非单缓冲。2.调用 glutDisplayFunc(display)注册 回调函数时, 在回调函数中所有绘制操作完成后调用glutSwapBuffers()交换两个缓冲区指针。3.调用 glutIdleFunc注册一个空闲时绘制操作函数, 注册的这个函数再调用display函数。

<9>onDisplay总结:

首先进行清缓存(颜色和深度,并定义清缓存的颜色)

然后设置投影视图,开启投影,清空矩阵,最后设置参数

第三步进行模型处理,设置模型视图,清空矩阵,定义摄像机视角

打开光照、开启更新深度

绘制图形

最后双缓冲区交换指针

项目学习参考链接为:

(22条消息) C++ 实现太阳系行星系统(OpenGL)_git1314的博客-CSDN博客_c++实现太阳系行星系统

openGL实现太阳系行星系统相关推荐

  1. OpenGL/C++实战——C++实现太阳系行星系统

    注:本教程版权归实验楼所有,有兴趣的同学也可点进官网蓝桥网课:C++实现太阳系行星系统学习(免费课程) 文章目录 框架设计 认识 OpenGL 和 GLUT 类设计 stars.hpp solarsy ...

  2. C++ 实现太阳系行星系统(OpenGL)

    基本框架设计 一.介绍 本次实验将使用 OpenGL GLUT 编写一个简单的太阳系运行系统. 实验涉及的知识点 C++ 语言基础 基本的 Makefile 基本的 OOP 编程思想 OpenGL G ...

  3. 基于C++和OpenGL (GLUT) 实现太阳系行星系统

    基于C++和OpenGL (GLUT) 实现太阳系行星系统 效果图: 分析与设计 OpenGL 包含了很多渲染函数,但是他们的设计目的是独立于任何窗口系统或操作系统的.因此,它自身并没有包含创建打开窗 ...

  4. OpenGL太阳系行星系统简单实现

    一.项目简介 使用OpenGL(glfw, glad)模拟太阳系(地球.月球.太阳)系统,涉及三维图形变换.坐标系统,光照模型(待添加).键盘鼠标事件处理等内容,在main函数中封装了绝大部分的Ope ...

  5. C++实现太阳系行星系统

    实验楼项目:C++实现太阳系行星系统 关于详细知识跟着实验做比较好 基础知识 做这个项目需要知道一些基础知识: OpenGL GLUT 类设计 main.cpp #include<GL/glut ...

  6. C++ 实现太阳系行星系统

    整个天体系统中,他们都是一颗星球(Star),区别行星和恒星只需要通过它们是否具有父节点即可:其次,对于不同的星球而言,它们通常具有自身的材质,并且不同的材质会表现出自身是否发光,由此我们有了初步的对 ...

  7. C/C++编程日记:C++ 实现太阳系行星项目系统

    项目简介:使用 C++实现 OpenGL GLUT 实现一个简单的太阳系行星系统,将涉及一些三维图形技术的数学基础.OpenGL 里的三维坐标系.OpenGL 里的光照模型.GLUT 的键盘事件处理. ...

  8. C/C++编程分享:C++ 实现太阳系行星项目系统

    项目简介:使用 C++实现 OpenGL GLUT 实现一个简单的太阳系行星系统,将涉及一些三维图形技术的数学基础.OpenGL 里的三维坐标系.OpenGL 里的光照模型.GLUT 的键盘事件处理. ...

  9. OpenGL学习10_绘制行星系统

    下面的Demo还使用了多种组合变换来实现地球绕太阳公转和自转的实现,还是直接看代码,有详细的注释. <span style="font-size:12px;">// / ...

  10. OpenGL实现太阳系模型 —— Juwend

    OpenGL实现太阳系模型 发表于 2012 年 12 月 30 日 由 Juwend OpenGL是一个非常强大的图形引擎.传说当下最流行的图形引擎有两套,其中之一就是Windows平台上最常用的D ...

最新文章

  1. 解决Eclipse中文乱码
  2. andiod 导入工程 报错
  3. 如何处理Android Studio 上面关于 update 和 commit 小箭头的消失
  4. java 只显示文本文件_Java设计并实现一个应用程序,能够读取一个文本文件中的内容并显示,同时能够计算出文本中的行数。...
  5. defer 被调用时机
  6. canvas绘制图像image
  7. YouTube深度学习推荐系统的十大工程问题
  8. 一款猥琐的PHP后门分析
  9. git强行覆盖master分支
  10. rust大油田分解机_辽河油田曙光采油厂:智慧党建建强战斗堡垒
  11. Codeforces.100633J.Ceizenpok's formula(扩展Lucas)
  12. 单片机课程设计:基于STM32智能交通灯的设计
  13. android 进入页面隐藏输入法
  14. Vue设计模式,发布订阅,响应式原理(简略版)
  15. 最近做到的一些有意思的数学题目(博弈,双人玩游戏)
  16. 《机器学习实战》学习笔记(八)
  17. 2022办公企业邮箱申请流程,总结申请公司电子邮箱的步骤是什么?
  18. win10 1903 1909 Realtek 声卡均衡器 调节失效 解决
  19. 从2019看2020前端发展趋势
  20. 5-4 区块链与药品溯源

热门文章

  1. 【雕爷学编程】Arduino动手做(59)---RS232转TTL串口模块
  2. 如何提高下载速度(校园网怎么提高下载速度)
  3. 如何提高BT的下载速度?
  4. 超参数自动优化方法PBT(Population Based Training)
  5. 企业部署信息安全等级保护的重要性
  6. 基于Html的个人展示网站设计与实现
  7. 东田纳西州立大学计算机排名,东田纳西州立大学排名在2020年USNEWS美国最佳综合大学排名第293-381...
  8. 如何免费在本地播放flv格式的视频
  9. 边界值分析法用例设计
  10. C语言课程设计大作业——学生管理系统(详细含报告和源码)