gpt4 book ai didi

opengl - 这个 OpenGL Haskell 代码是如何工作的?

转载 作者:行者123 更新时间:2023-12-02 07:18:53 25 4
gpt4 key购买 nike

我正在通过直接跳入 OpenGL 来学习 Haskell,但我似乎无法破译这段代码:

display :: DisplayCallback
display = do
let color3f r g b = color $ Color3 r g (b :: GLfloat)
vertex3f x y z = vertex $ Vertex3 x y (z :: GLfloat)

clear [ColorBuffer]
renderPrimitive Quads $ do
color3f 1 0 0
vertex3f 0 0 0
vertex3f 0 0.2 0
vertex3f 0.2 0.2 0
vertex3f 0.2 0 0

color3f 0 1 0
vertex3f 0 0 0
vertex3f 0 (-0.2) 0
vertex3f 0.2 (-0.2) 0
vertex3f 0.2 0 0

color3f 0 0 1
vertex3f 0 0 0
vertex3f 0 (-0.2) 0
vertex3f (-0.2) (-0.2) 0
vertex3f (-0.2) 0 0

color3f 1 0 1
vertex3f 0 0 0
vertex3f 0 0.2 0
vertex3f (-0.2) 0.2 0
vertex3f (-0.2) 0 0
flush

到目前为止我的理解:

  1. display 是一个函数。 问题:什么是 DisplayCallback?
  2. do 表示计算链接,与 IO monad 有关
  3. color3fvertex3f 是本地函数,具有使用 let 关键字在 do 中定义的三个参数
  4. 我假设 colorvertexglColor*glVertex* 的 openGL 包装函数。

现在这就是令人困惑的地方:

  • Color3Vertex3 似乎是某种由三个参数组成的数据结构。 问题:为什么这里需要使用数据结构?为什么API的设计者选择在这里使用它?

  • color3f 函数调用 color 函数并传入单个参数 - 带有数据 r g b 的数据结构 Color3。由于某种原因,这里的数据类型只为最后一个参数指定(b::GLfloat) 问题:为什么只为最后一个参数指定数据类型,为什么呢?到底在这里指定了什么?

  • 问题:为什么在调用color函数时使用美元符号color $ Color3 r g (b::GLfloat)

继续:

  1. clear 是 opengl glClear 的包装器,并接受一个列表作为参数,在本例中仅包含单个元素 [ColorBuffer]
  2. renderPrimitive 似乎是 opengl glBegin 的包装函数,Quads 似乎是数据类型。 问题:接下来会发生什么? $ do 表示什么? (一系列计算?某事,某事 IO monad?)。
  3. flushglFlush 的包装器。

最佳答案

1. DisplayCallbackIO () 的类型同义词。您可以使用 hoogle 进行查找,或输入 :i DisplayCallback在 ghci 中。

原因是IO ()被赋予一个特殊的名字是因为GLUT基于回调:注册函数来处理特定事件,例如显示、输入事件、调整大小事件等。有关完整列表,请参阅 docs 。显然,您不需要类型同义词,但提供它们是为了清晰和更好的沟通。

2. “我假设颜色和顶点是 glColor* 和 glVertex* 的 openGL 包装函数。”不完全是-OpenGL是更基本的 OpenGLRaw 的包装,这是 c opengl 库到 haskell 的 1:1 映射。 vertexcolorglColor 稍微复杂一些和glVertex ,但您可能可以假设大多数用途它们是相同的。

更具体地说,vertexVertex 的成员有 4 个实例的类 Vertex4 , Vertex3 ,和Vertex2

3. Color3定义为data Color3 a = Color3 !a !a !aThe exclamation indicates that the fields are strict. 。为什么这是必要的?好吧,他们可以轻松使用 (a,a,a) -> IO ()a -> a -> a -> IO ()但是,采用颜色的函数与采用向量的函数无法区分,它们在“意识形态上”是不同的对象,即使它们由完全相同的数据表示(顶点为 data Vertex3 a = Vertex3 !a !a !a )。因此,您不希望能够将顶点传递给需要颜色的函数。此外,由于严格性,这些数据类型在理想情况下可以提供更好的性能。

4.为什么要指定类型?简而言之,是类型系统需要它。文字的类型是 Num a => a这对于需要具体类型的数据类型来说太多态了。因此,您可以使用类型注释来选择所述具体类型。

为什么只在一处需要它?编译器可以推断其他字段的类型。回顾一下数据类型声明——所有三个字段必须具有相同的类型。如果对一个字段进行了注释,则可以轻松推断出其余字段。您也可以写Color3 r (g :: GLfloat) bColor3 (r :: GLfloat) g b或者给出函数 vertex3f类型签名。

5. $只是低优先级的函数应用,定义为 f $ a = f a; infixr $ 0 。您也可以写color (Color3 r g (b :: GLfloat))所以这纯粹是风格问题。

6. Perhaps the docs will again best explain what renderPrimitive is doing.但简短的版本是这样的:而不是在 glBegin 里面写东西。 -glEnd block ,你把它写在 renderPrimitive 里面。你不需要写glEnd因为它隐藏在 renderPrimitive 里面。所以你的代码相当于:

glBegin (GL_QUADS); 
// All the stuff inside goes here ...
glEnd ();

OpenGL为了将 c 中的异常正确地引入 haskell 宇宙,做了一些魔法,但你实际上不必担心这一点。

最后评论:如果您打算使用 haskell 进行图形处理,那么编写实际的 openGL 代码可能不是最好的主意。毕竟,如果您要使用 openGL,为什么不直接使用 c 呢?那里有无数的图形库。您应该浏览 hackage 寻找适合您的软件包。恐怕我无法推荐任何东西,因为我不熟悉可用的软件包。

关于opengl - 这个 OpenGL Haskell 代码是如何工作的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21929222/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com