Primeros pasos con OpenGL ES fácilmente: hable nuevamente sobre el mecanismo de trabajo de OpenGL

Para más publicaciones en el blog, consulte el catálogo general del carruaje romántico para el aprendizaje del sistema de audio y video.

Proyecto práctico: presente un proyecto de código abierto de reproducción y grabación de audio y video de Android recientemente lanzado

Base teórica del video:
conocimiento básico de alfabetización
en video Conceptos básicos de desarrollo de audio y video:
análisis de codificación de color YUV del principio de codificación de video H264, a partir de la película de Sun Yizhen (1)
Análisis del principio de codificación de video H264, a partir de la película de Sun Yizhen (2)
H264 A una mirada más cercana a la estructura del flujo de código

Plataforma Android Serie MediaCodec:
Herramienta de códec duro de Android Análisis de MediaCodec: de la historia del restaurante de cerdo (1)
Herramienta de códec duro de Android Análisis de MediaCodec: de la historia del restaurante de cerdo (2)
Herramienta de códec duro de Android Análisis de MediaCodec ——De la historia del restaurante chicharron (3)

Entrada fácil a la serie OpenGL
Entrada fácil a OpenGL ES: esas cosas sobre la canalización de representación de gráficos
Entrada fácil a OpenGL ES: para hablar sobre el mecanismo de trabajo de OpenGL

Revisa el artículo anterior

El artículo anterior Primeros pasos con OpenGL ES - Canal de procesamiento de gráficos describió principalmente el mecanismo de trabajo del canal de procesamiento de gráficos, pero simplemente conocer el mecanismo del canal de procesamiento de gráficos puede no ser suficiente para que los desarrolladores controlen realmente el gran OpenGL, todavía necesitamos OpenGL desde una posición más alta, aún necesita aprender algunos mecanismos de trabajo antes de que realmente pueda escribir un buen código.

Por lo tanto, este artículo todavía no habla sobre el código, para evitar que los principiantes caigan en el bosque de detalles y no puedan liberarse. El enfoque está en el mecanismo de trabajo macro. Después de dominar el mecanismo de trabajo, escribir un buen código es una cuestión de curso _ La siguiente parte comenzará a explicar el contenido de OpenGL ES.

1658027123297.png

客户端-服务端模型

首先要提到的第一个,就是开发者和图形渲染管线如何交互的问题。看了上一篇文章,可能有些读者会误以为写OpenGL程序就是在写图形渲染管线,其实不是,图形感染管线整个流程的处理是在硬件(一般是gpu)内部处理的,整个流程是我们无法改变的,只是为了扩展灵活性,图形渲染管线对开发者暴露了其中若干个处理步骤交由我们灵活处理,让我们得以通过写代码的方式,也就是着色器程序,以满足我们天花乱坠的各种需求。

图形渲染管线就像手机生产的流水线,整个流水线大部分流程都是对我们封闭的,只是暴露了若干个流程得以让我们操作,比如**只暴露了手机壳的形状和颜色(着色器)**让我们自主DIY。

而我们写的程序,除了着色器这种运行在gpu中的特殊程序之外,其余代码都是运行在cpu的,可以看做是对于gpu进行传输数据并发令施号,所以这里也就可以将整个图形渲染管线看作一个服务端(server),我们写在cpu中运行的代码当做客户端(clinet),于是整个模型类似:

cb2dcd005e24b5ab1e0741907d1196b.png

我们一部分一部分地看:

1657982200764.png

可以看到,处于Client端的就是我们写的C/C++程序,这里主要是调用OpenGL的Api,向Server端传输指令。Server端主要指的是图形渲染管线。Client端和Server端是独立运行,互相不干涉,有点类似线程池,也有点上次MediaCodec中描述的猪肉餐馆的那味道。

1658027021981.png

在这里我们会通过OpenGL的Api向Server端,即图形渲染管线传递顶点数据、颜色数据、以及自定义的着色器需要的一些数据(比如含有变化的滤镜需要变化频率时间相关的参数)。相当于将加工手机的原材料传入了图形渲染管线的入口

因为OpenGL是一个没有感情的图形数据处理机器人,在传输数据的同时,我们会通过相应的指令告诉OpenGL要如何使用这些数据

通俗来说,就是我们把一堆原材料数据丢进OpenGL中,OpenGL就会启动图形渲染管线噼里啪啦将数据按照我的输入的指令进行加工,最后将加工好的图像数渲染到一个特定缓冲区中(帧缓冲,frame buffer),然后我们再调用指令,让缓冲区的数据渲染到屏幕上

这场景,是不是有点像我们小时候最熟悉的玩意...

e8e1fbe843b82fd4e7620989210bd0b7.jpeg

我们小时候也是不断发出指令,控制屏幕渲染出我们想要的一些效果。。

再看箭头旁边的单词,表示的是传递的数据,这个将在下一篇具体讲解着色器的时候细想叙述,这次我们先忽略。

1658025600406.png

接下来就是最令初学者兴奋又痛苦的着色器了:

aa47309585b4a7779b444aec58ebd50e.jpeg

1658027988699.png

这是图形渲染管线能够让我们尽情发挥想象力的地方,一旦掌握了它,你可能会对它如痴如醉。这里还是啰嗦一下,着色器这个重头戏是下一篇博文的主要内容,这里先卖关子不细讲了,这里你要知道的有2点:

1. 着色器是在我们传输入原始数据和指令之后,一个在gpu内部我们可以自由处理数据的地方。(又有点啰嗦,因为其实上面已经有提到了)

2. 顶点着色器输出的数据并不是直接传给片段着色器的,由上篇文章和上图可知,中间还有图元装配和光栅化,所以这里数据的传输会有一些微妙的关系,这也是很多初学者容易搞混的地方

1658027123297.png

状态机

我们已经大致了解了OpenGL的工作流程了,还有一个概念还需要掌握,那就是OpenGL状态机,很多初学者之所以看到OpenGL的代码一脸懵逼的原因之一,在于他们没有理解OpenGL是一个状态机,比如很多初学者看到OpenGL常见的以下代码内心是崩溃的:

unsigned int VBO, VAO; 
glGenVertexArrays(1, &VAO);
// bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s). 
glGenBuffers(1, &VBO); 
glBindVertexArray(VAO); 
glBindBuffer(GL_ARRAY_BUFFER, VBO); 
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); 
 // note that this is allowed, the call to glVertexAttribPointer registered VBO as the vertex attribute's bound vertex buffer object so afterwards we can safely unbindglEnableVertexAttribArray(0); 
 // You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, but this rarely happens. Modifying other // VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs (nor VBOs) when it's not directly necessary.
 glBindBuffer(GL_ARRAY_BUFFER, 0); 
 glBindVertexArray(0);

看一遍之后,脑海中似乎只有一堆“bindXX”。。

32147a3a6835b7e02e3af5c6e5d7b1ab.jpeg

所以,首先,什么是状态机?查一下无所不知的百科:

状态机由状态寄存器和组合逻辑电路构成,能够根据控制信号按照预先设定的状态进行状态转移,是协调相关信号动作、完成特定操作的控制中心。有限状态机简写为FSM(Finite State Machine),主要分为2大类:

第一类,若输出只和状态有关而与输入无关,则称为Moore状态机

第二类,输出不仅和状态有关而且和输入有关系,则称为Mealy状态机

36f547d2b4335680e12ddab8dc3ca5f2.jpeg

还是讲点大众易懂的话把,举个栗子:

相信我们都坐过电梯吧,那么电梯有几个常见的状态呢,一般来说有以下几个:

开门关门运动(上升/下降)静止

它们有什么特点呢?

电梯只有静止的时候才能开门,只有开门之后才能关门,只有关门之后才可以运动,只有运动之后才可以静止,所以,可以说电梯的各个状态是有依赖关系的,换种更专业的说法,就是各种状态可以通过有向图来表示。

stateDiagram-v2


静止 --> 开门
开门 --> 关门
关门 --> 运动
运动 --> 静止
复制代码

是的,电梯不能随意从一个状态跳转到另一个状态,总不能运动过程中开门吧。。

1658032138279.png

关于OpenGL状态机,Learn OpenGL中的叙述如下:

OpenGL自身是一个巨大的状态机(State Machine):一系列的变量描述OpenGL此刻应当如何运行。OpenGL的状态通常被称为OpenGL上下文(Context)。我们通常使用如下途径去更改OpenGL状态:设置选项,操作缓冲。最后,我们使用当前OpenGL上下文来渲染。

假设当我们想告诉OpenGL去画线段而不是三角形的时候,我们通过改变一些上下文变量来改变OpenGL状态,从而告诉OpenGL如何去绘图。一旦我们改变了OpenGL的状态为绘制线段,下一个绘制命令就会画出线段而不是三角形。

当使用OpenGL的时候,我们会遇到一些状态设置函数(State-changing Function),这类函数将会改变上下文。以及状态使用函数(State-using Function),这类函数会根据当前OpenGL的状态执行一些操作。只要你记住OpenGL本质上是个大状态机,就能更容易理解它的大部分特性。

再回到刚才这段代码:

unsigned int VBO, VAO; 
glGenVertexArrays(1, &VAO);
// bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s). 
glGenBuffers(1, &VBO); 
glBindVertexArray(VAO); 
glBindBuffer(GL_ARRAY_BUFFER, VBO); 
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); 
 // note that this is allowed, the call to glVertexAttribPointer registered VBO as the vertex attribute's bound vertex buffer object so afterwards we can safely unbindglEnableVertexAttribArray(0); 
 // You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, but this rarely happens. Modifying other // VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs (nor VBOs) when it's not directly necessary.
 glBindBuffer(GL_ARRAY_BUFFER, 0); 
 glBindVertexArray(0);

其中各种BindXX方法调用是对某个事物(比如顶点数组对象、顶点缓冲对象等,这些概念将在后面博文会详细解读的内容)的绑定用状态机的方式去理解就是进入了某个状态,不过这里与电梯状态有所不同的是,它的状态是存在某种绑定关系的,某个时间段内一种状态会以类似属于另一种状态之中的方式存在。用状态图的方式来表示上面的代码就是:

stateDiagram-v2
[*] --> 绑定VAO(后面的操作都关联当前VAO)
解绑VAO(后面的操作都与当前VAO无关了) --> [*]

绑定VAO(后面的操作都关联当前VAO) --> 绑定VBO(后面的操作都关联当前VBO)
绑定VBO(后面的操作都关联当前VBO) --> 解绑VBO(后面的操作都和当前VBO无关)
解绑VBO(后面的操作都和当前VBO无关) --> 解绑VAO(后面的操作都与当前VAO无关了)
复制代码

不过这里状态存在包含关系,因为一个VBO会被绑定于一个VAO中,所以用下图来看会更加直观:

1658054991067.png

En términos sencillos, cualquier operación entre la vinculación de XX y la desvinculación de XX afectará a XX . ~Al igual que el comportamiento de las personas durante el período de tiempo después de entrar en el ascensor y antes de salir del ascensor, todos se realizan en el ascensor y pueden afectar al ascensor. Por ejemplo, sabotaje en un ascensor.

1658056196172.png

Por lo tanto, el código no se puede ver en unas pocas líneas, sino más y más lejos, como el bindxx antes y después.

Después de tal explicación, ¿veré las diversas funciones bindXX de OpenGL en el futuro? Por supuesto, no solo se aplican la función bindXX, sino también varias funciones de configuración de estado. (Puedes ver la publicación posterior del blog si no la has leído)

1658027123297.png

Resumir

El contenido de hoy es relativamente pequeño en mi publicación de blog, porque este artículo es un complemento del artículo anterior sobre cómo comenzar con OpenGL ES: canalización de representación de gráficos fácilmente A través de la descripción del modelo de trabajo del servidor de cliente OpenGL y la máquina de estado, dejemos los principiantes tienen además una comprensión macro del mecanismo de trabajo de OpenGL y sientan una base sólida para los enlaces de codificación específicos más adelante.

Referirse a

"Documento de especificación de OpenGL"
learn opengl
"OpenGL Super Book 5.ª edición"
"Guía de programación de OpenGL 8.ª edición"

No es fácil ser original. Si crees que este artículo es útil para ti, no olvides darle me gusta y seguir. Esta es también la mayor motivación para mi creación ~

Estoy participando en el reclutamiento del programa de firma de creadores de la Comunidad Tecnológica de Nuggets, haga clic en el enlace para registrarse y enviar .

Supongo que te gusta

Origin juejin.im/post/7121525553491869703
Recomendado
Clasificación