我在那里发现的大部分教程,指南和书籍都与OpenGL有关,解释了如何绘制三角形并初始化OpenGL.没关系.但当他们试图解释它时,他们只列出了一堆函数和参数,如:
glClear()
glClearColor()
glBegin()
glEnd()
...
Run Code Online (Sandbox Code Playgroud)
由于我不擅长通过记忆学习东西,我总是需要回答"为什么我们这样做?" 所以我会编写那么多函数,因为我记得在做其他事情之前我必须先设置一些东西,所以不要因为教程告诉了我.
可以请有人向我解释一下,在开始使用glBegin()和绘制内容之前,我需要为OpenGL定义什么(只有纯OpenGL,我使用SFML作为背景库,但这无关紧要)glEnd().
示例答案:
您必须首先告诉OpenGL清除屏幕所需的颜色.因为在我们开始绘制当前帧之前需要先清除每个帧...
首先你应该知道,OpenGL是一个状态机.这意味着,除了创建OpenGL上下文(由SFML完成)之外,没有初始化这样的东西!
因为我不太善于通过记忆学习东西,
这很好......
我总是需要回答"为什么我们这样做?"
这太棒了!
可以请有人向我解释在开始用glBegin()和glEnd()绘制内容之前,我需要为OpenGL定义什么(只有纯OpenGL,我使用SFML作为后台库,但这无关紧要)?
正如我已经说过的:OpenGL是一个状态机.这基本上意味着,您可以执行两种调用:设置状态和执行操作.
例如,glClearColor设置一个状态变量,即清除颜色的状态变量,当glClear用GL_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)