我的大脑倾向于采用分层,面向对象,类似组件的方式来构建概念。不幸的是,这使我无法理解OpenGL - 我怀疑我的困惑的根源在于我对" OpenGL状态机"的误解。是。你得到了graphics pipeline,但这对于绘制用户图形组件的各个程序对象来说非常具体,对吧?
答案 0 :(得分:11)
这台状态机是什么?
想象一下配有几十个交换机拨号盘的交换机。该配电板连接到加工厂中的机器,并且根据开关的切换方式,在一侧进入加工厂的物料将以特定路径穿过工厂。改变其中一些开关的状态,事情将采取另一种方式。
还有状态机,当物料经过某个处理步骤时,开关和拨号盘会被改变; OpenGL不是那种。
OpenGL上下文就是这样一个交换机,后面有一个处理工厂。交换机是您通过API控制的,处理工厂是制作图片的原因。
它可以存在哪些不同的状态?
要列出的内容太多。对于每个开关,状态数乘以开关所在位置的数量。假设您有20个拨动开关,一个带5个位置的拨盘和一个带7个位置的拨盘,那么您已经{ {1}}可能的不同状态。某些版本的OpenGL有超过300个状态变量,其中许多不仅仅是布尔值。因此,尝试列出每个可能的状态是徒劳的努力。
是否也是事件驱动的?
没有!
哪些输入会影响机器可以处于的不同状态?
显式调用OpenGL API的状态更改函数;那个和默认的初始状态。
可以将分层的OOP概念应用于此状态机吗?
没有。或者更确切地说,您可以尝试,但事实是,只有一个OpenGL上下文类保存所有状态,唯一真实的表示形式。
OpenGL上下文中有一些东西,其行为类似于具有自己状态的单个对象。例如纹理,但是这些对象与OpenGL上下文本身密切相关,不能单独查看。
关于你的评论的个人说明
我的大脑倾向于支持以层次化,面向对象,类似组件的方式构建概念。
停止这样做!计算机不能这样做。 OOP是一种构建项目的方法,但它不是理解某些预先存在的系统的非常好的工具。特别是本质上非机械化的系统。
我强烈建议您通过学习构建项目的其他方法来拓展视野。学习函数式编程怎么样? Haskell现在是流行的FP语言之一,由于其专注于纯语言,因此学习体验非常好。这是一本非常好的在线图书/教程:http://learnyouahaskell.com/chapters - 准备好让自己的思想开始;有些东西可能看起来像是OOP,但它们并非如此;在这些墙壁上奔跑可能看起来令人沮丧,但是当它最终点击你的头脑并且#34;你得到它时,它会带来好处。 (=有顿悟)是值得的。
请注意,OpenGL既不是功能也不是真正的OOP。由于没有功能,它不能很好地映射到纯功能编程。 Haskell有OpenGL绑定,但它们是通过一个名为" monad&#34 ;; monads是功能程序用来与状态或甚至驱动环境联系的东西。
我推荐的另一个资源是https://mitpress.mit.edu/sicp/full-text/book/book.html - 那里的每个程序员都应该阅读它。
答案 1 :(得分:4)
这是一个非常广泛的问题,所以我只是给你概述。
状态机是完整OpenGL API和当前选定的渲染上下文的组合。渲染上下文包含构成状态机的所有状态,而OpenGL API提供了更改这些状态的输入。
列出的内容太多了。例如,glEnable
和glDisable
(例如GL_TEXTURE_2D
,GL_FOG
,GL_BLEND
)切换的功能是州的一部分。使用glBindTexture
设置的当前纹理的名称;来自glUseProgram
的当前着色器程序的名称;模型视图和投影矩阵的内容加上glMatrixMode
的状态,它告诉任何glMultMatrix
(等)调用将影响哪个矩阵;等等,都是国家的一部分
机器的初始状态由OpenGL规范给出,以GPU驱动程序为模。可以将机器置于不同状态的唯一输入是对OpenGL API的调用。
这个问题很模糊。什么是“分层,OOP概念”?
可以采用面向对象的方法来包装OpenGL API。您可以创建一个“Texture”对象类,在初始化时使用glGenTextures
分配纹理名称,并提供上载纹理图像或更改始终调用glBindTexture
的纹理参数的方法,然后再调用相关API。方法。这种方法通常很棘手,因为您仍然需要通过对象和子对象方法调用来跟踪当前状态。
OpenGL提供了几个“堆栈”(可见glPushMatrix
,glPushAttrib
),旨在帮助管理对象的层次结构。通过将当前状态的某些部分推送到堆栈,调用子对象的方法,然后将该状态从堆栈中弹出,可以将状态恢复为父对象所期望的状态。
使用OpenGL API的一般面向对象方法是通过场景图 - 对象的有向非循环图,其中每个对象代表状态机状态的一些变化。该对象推送到一个或多个OpenGL堆栈,使用OpenGL API调用应用其状态,调用其子对象的方法,然后弹出这些OpenGL堆栈以恢复先前的状态。
答案 2 :(得分:0)
从我的观点来看,“状态机”一词在这里令人误解。当我听到“状态机”时,我会自动想到具有少量已定义状态的有限自动机。它始终处于这些状态之一,并对某些输入做出反应以确定下一个状态和输出将是什么。
但是,这不是OpenGL所做的。 (从数学上讲,您可以将其视为这样的自动机,但如果这样做,则人为地创建了大量可能的状态,这是没有用的。)
是的,OpenGL API是“有状态” API。您告诉它在它的“状态”中记住的很多东西,它基本上是一组变量。然后,您要求它渲染某些东西,OpenGL将使用您先前设置的状态来确定要对要渲染的数据进行确切的处理。
顺便说一句:我发现Joey de Vries的教程对理解OpenGL的功能很有帮助。有关更多信息,请参见https://learnopengl.com/Getting-started/OpenGL。
答案 3 :(得分:-1)
老实说,我发现以你想要的方式理解它的最好方法是面向对象的编程
从我对opengl的理解,这是我对opengl api的最佳解释
首先,如果你将它与其他api(如SDL)进行比较,它可能会更复杂和不同,使用api来尝试描述它真的没有做到这一点
所以在面向对象的编程方面
想象一下,如果你有一个类,这个类是私有的,它的所有工作方法都不打算被用户查看,但它也有一个默认状态,所以如果你使用它“开箱即用” “它将完成它在默认状态下的作用(几乎没有任何东西)
当你创建一个上下文时,就像你创建了这个类的一个实例(并且你可以创建任意数量的这个类的实例,也就是你也可以创建多个上下文),这是运行opengl所必需的,并且OOP,因为你现在不能使用类,直到你从它创建一个对象/实例,唯一的区别是构造函数获取你的硬件/ os /其他api /硬件信息来完成实例/对象,以便它可用,或者把它插入一些“屏幕”
然而,这个类中包含的方法(函数)和字段(数据存储)使你有能力做你想做的一切并使用这个实例,当然你如何做某些事情是基于在这些方法上你不能改变这个类/实例/对象的任何东西而不使用它的方法/字段(你可以使用的那些,即公共的),你不能说我想这样做,所以我自己,或者选择存储字段的位置(外部等),所有这些都必须属于实例和类和方法,在这个实例/ object / class中有数百个方法和字段(opengl 4.5有超过500个命令(方法/字段) )影响这个实例/类)以及你对它做了什么,改变这个特定的实例/对象就好像你有一些粘土并将它塑造成你想要它的方式,当然你必须放置某些东西从外部插入此实例,例如具有其特定功能的着色器
所以它真的有点像电视屏幕的遥控器,它的方法/按钮会影响上下文(屏幕/电视/显示器),根据您在遥控器/实例/方法/功能上推送的内容进行显示与此类比的区别在于它只需要按钮按下,但数据也可以以及所有各种方式呈现它(这是您绘制到屏幕上的内容)