OpenGL状态机/变换堆栈/基本类型和函数

一、状态机理解

Opengl是一个状态机,当你 设置一个命令状态进去了以后会一直是这个状态,直到改变这个状态为止,实际中需要检查下当前状态再设置进去效率会高些,避免产生很多的OGL comand,这点和D3D一样。

二、变换堆栈理解

    Opengl矩阵堆栈变换类型分为模型视图变换GL_MODELVIEW堆栈和投影变换GL_PROJECTION堆栈等, 在指定的变换堆栈中,当前的变换都是右乘该堆栈顶部矩阵,复杂模型的 连续变换经常需要对当前顶部矩阵压栈glPushMatrix(),这时最顶部的两个矩阵一样,然后继续操作(右乘)顶部矩阵,变换完后再进行glPopMatrix()丢弃当前顶部堆栈返回原先压栈矩阵在顶部,如果还要基于现在返回的顶部矩阵操作,还要再压栈当前顶部矩阵,在进行操作...。这种矩阵压栈式的变换在空间效率和时间效率(现在都是硬件实现)都有很明显的优势,但是实现时候操作比较繁琐;实际图形引擎中却是倾向用场景节点和骨骼节点的方式来维护连续嵌套的变换;D3D中没有压栈出栈的方式就是直接组合出物体的空间位置然后设置世界变换视图变换投影变换。
    Opengl中常用两个变换堆栈,一个是glMatrixMode(GL_MODELVIEW),它一开始时候栈顶是一个单位矩阵,一般堆栈大小是32个矩阵。一个是glMatrixMode(GL_PROJECTION),正交或者透视投影,一开始时候没有栈顶单位矩阵所以需要glLoadIdentity()单位矩阵到栈顶,投影堆栈大小一般是2个,要2个目的是一个程序中既可以实现透视投影,也可以切换到正交投影(例如绘制文本)。 如果glPushMatrix()太多大于堆栈容量那么会报错,如果glPopMatrix()小于等于一个那么也会报错。glMatrixMode(GL_TEXTURE)是纹理堆栈,也有相应的变换矩阵。
    测试发现值:
GLint nModelMatrixCount = 0;
glGetIntegerv(GL_MAX_MODELVIEW_STACK_DEPTH, &nModelMatrixCount);// 32
GLint nPerspectiveMatrixCount = 0;
glGetIntegerv(GL_MAX_PROJECTION_STACK_DEPTH, &nPerspectiveMatrixCount); // 4
GLint nTextureMatrixCount = 0;
glGetIntegerv(GL_MAX_TEXTURE_STACK_DEPTH, &nTextureMatrixCount);// 10

三、OPENGL基础类型和函数

1.数据类型

GLbyte、GLubyte/GLboolean
GLshort、GLushort
GLint/GLsizei、GLunit/GLenum/GLbitfield
GLfloat/GLclampf
GLdouble/GLclampd
命名规则:库前缀 命令 参数个数 参数类型
例如:glColor3f

2.glClear函数

// 清空后台颜色缓存和深度缓存,还有GL_ACCUM_BUFFER_BIT累计缓存,GL_STENCIL_BUFFER_BIT模板缓存
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

3.glLoadIdentity设置当前矩阵为单位矩阵

// glLoadIdentity该函数的功能是重置当前指定的矩阵为单位矩阵.
    // The glLoadIdentity function replaces the current matrix with the identity matrix.
    // It is semantically equivalent to calling glLoadMatrix with the identity matrix
    // 部分撤销之前的变换需要glPushMatrix()命令压栈,接着用glPopMatrix()出栈得到之前的变换矩阵作为当前变换
    glLoadIdentity();    
        

4.glMatrixMode函数,设置接下来进行的矩阵变换

// 改变窗口设置,会影响到投影变换(透视或者正交)和视口变换。
/** 当窗口大小改变时,通知OpenGL调整大小 */
void GLWindow::ReshapeGL()
{
    GLsizei width = GetWidth();
    GLsizei height = GetHeight();
    glViewport(0, 0, width, height);/**< 重新设置视口 */
    glMatrixMode(GL_PROJECTION);    // glMatrixMode设置矩阵变换的类型,这里是透视投影,后面可以进行透视投影的设置                            
    glLoadIdentity();                                               
    gluPerspective(45.0f, (GLfloat)width / (GLfloat)height, 1.0f, 100.0f);    
    glMatrixMode(GL_MODELVIEW);      // 后面可以进行视图投影的设置,    gluLookAt()这样的函数;如果是GL_TEXTURE后面就是纹理相关的变换
    // 设置来设置去,很麻烦,所以需要glPushMatrix() 保存当前矩阵
    glLoadIdentity();                                               
}

5.OPENGL也是要绘制后交换后台缓存和前台缓存

DWORD tickCount = GetTickCount();/**< 返回计时器的当前值 */
Update(tickCount - m_LastTickCount);/**< 调用用户自定义的更新函数 */
m_LastTickCount = tickCount;    /**< 重新设置上一次,计数器的值 */
Draw();                   /**< 调用用户自定义的绘制函数 */
m_Window.SwapBuffers();        /**< 交换前后帧缓存 */
void    SwapBuffers() { ::SwapBuffers(m_hDC); }
如果要用Glut就不会需要这么详细的设置:
init();
glutDisplayFunc(lineSegment);
glutMainLoop();
这样既可。

6.glTranslate 产生一个平移矩阵,且将当期矩阵乘以平移矩阵作为当期矩阵

如果当前矩阵模式是GL_PROJECTION或GL_MODELVIEW,那么所有当前绘制的物体都会受到变换作用。
// 会产生一个平移矩阵 第四个向量为(x,y,z,1),会用当前矩阵乘以平移矩阵。
    // glTranslate — multiply the current matrix by a translation matrix
    // if M is the current matrix and T is the translation matrix, then M is replaced with M*T.
    glTranslatef(0.0f, 0.0f, -6.0f);        

7.glRotatef产生一个绕轴进行angle角度旋转的矩阵,且将当期矩阵乘以旋转矩阵作为当期矩阵

如果当前矩阵模式是GL_PROJECTION或GL_MODELVIEW,那么所有当前绘制的物体都会受到变换作用。
// glRotate produces a rotation of angle degrees around the vector(x,y,z)
    // glRotate — multiply the current matrix by a rotation matrix
    glRotatef(m_Angle, 0.0f, 1.0f, 0.0f);

8.glBegin和glEnd之间调用的函数

glBegin和glEnd函数限定了一组或多组图元的定点定义。

glBegin(GL_TRIANGLES);                                
glColor3f(1.f, 0.f, 0.f);glVertex3f( 0.0f,  1.0f, 0.0f);
glColor3f(0.f, 1.f, 0.f);glVertex3f(-1.0f, -1.0f, 1.0f);
glColor3f(0.f, 0.f, 1.f);glVertex3f( 1.0f, -1.0f, 1.0f);
glEnd();
在glBegin和glEnd之间可以调用的函数:
  glVertex*() 设置顶点坐标
 glColor*() 设置当前颜色
 glIndex*() 设置当前颜色表
 glNormal*() 设置法向坐标
 glEvalCoord*() 产生坐标

 glCallList(),glCallLists() 执行显示列表
  glEdgeFlag*() 控制边界绘制
 
  glTexCoord*() 设置纹理坐标

 glMaterial*() 设置材质

9.glFlush()强制发送到驱动程序commandbuffer里面执行命令

简单地说glFlush()就是强制刷新,OpenGL是使用一条渲染管线[3] 线性处理命令的,一般情况下,我们提交给OpenGL的指令并不是马上送到驱动程序[4] 里执行的,而是放到一个缓冲区里面,等这个缓冲区满了再一次过发到驱动程序里执行;很多时候只有几条指令是填充不满那个缓冲区的,就是说这些指令根本没有被发送到驱动里,所以我们要调用glFlush来强制把这些指令送到驱动里进行处理。

       

你可能感兴趣的:(OpenGL图形学)