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

时间:2012-08-05 06:58:45

标签: c++ opengl

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

glClear()
glClearColor()
glBegin()
glEnd()
...

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

在开始使用glBegin()glEnd()

示例答案:

  

你必须首先告诉OpenGL清除它需要什么颜色   屏幕。因为每个帧都需要被前一个清除   在我们开始绘制当前的...之前...

2 个答案:

答案 0 :(得分:8)

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

  

因为我不太擅长通过记忆学习东西,

这很好......

  

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

这太棒了!

  

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

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

例如glClearColor设置状态变量,即清除颜色的状态变量,当使用glClear标志调用GL_COLOR_BUFFER_BIT时,该值用于清除活动的帧缓冲颜色组。深度值(glClearDepth标志为GL_DEPTH_BUFFER_BIT)存在类似的函数glClear

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

但是在这里:glBegin将OpenGL设置为一个状态,它现在应该绘制几何图形,选择作为glBegin参数的图元。例如,GL_TRIANGLES意味着,OpenGL现在将每次调用glVertex解释为形成三角形。 glEnd告诉OpenGL你已经完成那批批次的三角形。在glBegin ... glEnd块中,不允许某些状态更改。在那些与变换几何体和生成图片有关的所有事情中,包括矩阵,着色器,纹理和其他一些。

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


更新

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

GLfloat triangle[] = {
    -1, 0, 0,
    +1, 0, 0,
     0, 1, 0
};

在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) */ );

我还没有包括设置转换和视口映射。

视口定义了如何在窗口中放置易于投影和标准化的几何体。此状态使用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();

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

draw_triangle();

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

if(singlebuffered)
    glFinish();

然而,大多数情况下,您的窗口是双缓冲的,因此您需要交换它以使视图生效。因为交换没有意义而没有完成交换意味着完成

else
    SwapBuffers();

答案 1 :(得分:0)

您正在使用API​​来设置和更改OpenGL状态机。

您实际上并没有直接编程到GPU,而是在应用程序和GPU之间使用介质来执行您尝试做的任何操作。

它是这样的并且与CPU和内存的工作方式不同的原因是因为openGL旨在运行在独立于OS /系统的硬件上,因此您的代码可以在任何操作系统上运行在任何硬件上运行,而不仅仅是您编程的硬件。

因此,正因为如此,您需要学会使用他们的预设代码,以确保无论您尝试做什么,都能够在合理范围内的所有系统/ OS /硬件上运行。

例如,如果您要在带有某个图形卡的Windows 8.1上创建应用程序(例如amd' s),您仍然希望您的应用程序能够在Andoird / iOS / Linux /其他Windows系统上运行/其他硬件(gpus),如Nvidia。

因此,为什么Khronos,当他们创建API时,他们使其尽可能独立于系统/硬件,以便它可以在所有内容上运行并成为每个人的标准。

这是我们必须支付的价格,我们必须学习他们的API,而不是学习如何直接写入gpu内存并直接利用GPU来处理信息/数据。

虽然随着Vulkan的推出,它的发布可能会有所不同(也来自khronos),我们会发现它将如何运作。