OpenGL在绘制三角形之前我该做什么?

Sho*_*hoe 0 c++ opengl

我在那里发现的大部分教程,指南和书籍都与OpenGL有关,解释了如何绘制三角形并初始化OpenGL.没关系.但当他们试图解释它时,他们只列出了一堆函数和参数,如:

glClear()
glClearColor()
glBegin()
glEnd()
...
Run Code Online (Sandbox Code Playgroud)

由于我不擅长通过记忆学习东西,我总是需要回答"为什么我们这样做?" 所以我会编写那么多函数,因为我记得在做其他事情之前我必须先设置一些东西,所以不要因为教程告诉了我.

可以请有人向我解释一下,在开始使用glBegin()和绘制内容之前,我需要为OpenGL定义什么(只有纯OpenGL,我使用SFML作为背景库,但这无关紧要)glEnd().

示例答案:

您必须首先告诉OpenGL清除屏幕所需的颜色.因为在我们开始绘制当前帧之前需要先清除每个帧...

dat*_*olf 8

首先你应该知道,OpenGL是一个状态机.这意味着,除了创建OpenGL上下文(由SFML完成)之外,没有初始化这样的东西!

因为我不太善于通过记忆学习东西,

这很好......

我总是需要回答"为什么我们这样做?"

这太棒了!

可以请有人向我解释在开始用glBegin()和glEnd()绘制内容之前,我需要为OpenGL定义什么(只有纯OpenGL,我使用SFML作为后台库,但这无关紧要)?

正如我已经说过的:OpenGL是一个状态机.这基本上意味着,您可以执行两种调用:设置状态和执行操作.

例如,glClearColor设置一个状态变量,即清除颜色的状态变量,当glClearGL_COLOR_BUFFER_BIT标志设置调用时,该值用于清除活动的帧缓冲颜色.glClearDepth深度值(GL_DEPTH_BUFFER_BITflag to glClear)存在类似的功能.

glBegin并且glEnd属于OpenGL的即时模式,已被弃用.所以没有理由学习它们.您应该使用Vertex Arrays,最好使用Vertex Buffer Objects.

但是在这里:glBegin将OpenGL设置为现在应该绘制几何形状的状态,选择作为参数的原始类型glBegin.GL_TRIANGLES例如,意味着OpenGL现在将每3个调用解释glVertex为形成一个三角形.glEnd告诉OpenGL你已经完成了批三角形.在glBegin ... glEnd块中,不允许某些状态更改.其中包括转换几何图形和生成图像的所有内容,包括矩阵,着色器,纹理和其他一些图形.

一个常见的误解是,初始化OpenGL.这是由于编写错误的教程有一个initGL功能或类似的功能.在开始渲染场景时,从头开始设置所有状态是一种很好的做法.但由于单帧可能包含多个场景(想想HUD或分屏游戏),这种情况会发生几次.


更新:

那你怎么画三角形?嗯,这很简单.首先,您需要几何数据.例如:

GLfloat triangle[] = {
    -1, 0, 0,
    +1, 0, 0,
     0, 1, 0
};
Run Code Online (Sandbox Code Playgroud)

在render函数中,我们告诉OpenGL下一次调用glDrawArrays或glDrawElements应该从那里获取数据(为了简单起见,我将在这里使用OpenGL-2函数):

glVertexPointer(3, /* there are three scalars per vertex element */
                GL_FLOAT, /* element scalars are float */
                0, /* elements are tightly packed (could as well be sizeof(GLfloat)*3 */
                trignale /* and there you find the data */ );
/* Note that glVertexPointer does not make a copy of the data! 
   If using a VBO the data is copied when calling glBufferData. */

/* this switches OpenGL into a state that it will
   actually access data at the place we pointed it
   to with glVertexPointer */
glEnableClientState(GL_VERTEX_ARRAY);

/* glDrawArrays takes data from the supplied arrays and draws them
   as if they were submitted sequentially in a for loop to immediate
   mode functions. Has some valid applications. Better use index
   based drawing for models with a lot of shared vertices. */
glDrawArrays(Gl_TRIANGLE, /* draw triangles */
             0, /* start at index 0 */
             3, /* process 3 elements (of 3 scalars each) */ );
Run Code Online (Sandbox Code Playgroud)

我还没有包括的是设置转换和视口映射.

视口定义了如何将容易投影和标准化的几何体放置在窗口中.使用此状态设置glViewport(pos_left, pos_bottom, width, height).

今天的变换发生在顶点着色器中.本质上,顶点着色器是用特殊语言(GLSL)编写的小程序,它接受顶点属性并计算结果顶点的剪辑空间位置.通常的方法是模拟固定功能管道,这是一个两阶段过程:首先将几何转换为视图空间(一些计算,如在这个空间中照明更容易),然后将其投影到剪辑空间,这是一种渲染器的镜头.在固定功能管道中,有两个转换矩阵:Modelview和Projection.您可以将它们设置为所需结果所需的任何内容.在仅仅是三角形的情况下,我们保留模型视图标识并使用任一维度中-1到1的正投影.

glMatrixMode(GL_PROJECTION);
/* the following function multiplies onto what's already on the stack,
   so reset it to identity */
glLoadIdentity(); 

/* our clip volume is defined by 6 orthogonal planes with normals X,Y,Z
   and ditance 1 from origin into each direction */
glOrtho(-1, 1, -1, 1, -1, 1); 

glMatrixMode(GL_MODELVIEW);
/* now a identity matrix is loaded onto the modelview */
glLoadIdentity();
Run Code Online (Sandbox Code Playgroud)

设置转换后,我们现在可以绘制如上所述的三角形:

draw_triangle();
Run Code Online (Sandbox Code Playgroud)

最后我们需要告诉OpenGL我们完成了发送命令,它应该完成它的渲染.

if(singlebuffered)
    glFinish();
Run Code Online (Sandbox Code Playgroud)

但是大多数情况下你的窗口是双缓冲的,所以你需要交换它以使事物成为可见的.由于交换没有任何意义,如果没有完成交换意味着完成

else
    SwapBuffers();
Run Code Online (Sandbox Code Playgroud)

  • @Jeffrey:不是*每个*OpenGL功能.但是所有与获得所需结果相关的东西,这意味着设置所有必需的状态,更重要的是确保以前的OpenGL调用没有干扰状态搞乱你的绘图.包括OpenGL-2.1在内,这是一项相当繁琐的工作.现在使用OpenGL-3核心配置文件,它已经弃用了许多恼人的东西,状态空间已经减少到一个小得多,易于管理的维度. (2认同)