在 Haskell 中使用 OpenGL 渲染 PNG 图像

Posted

技术标签:

【中文标题】在 Haskell 中使用 OpenGL 渲染 PNG 图像【英文标题】:Render PNG images using OpenGL in Haskell 【发布时间】:2017-04-07 10:21:55 【问题描述】:

我是 Haskell 的新手,我正在为 UI 使用 OpenGL(使用 Graphics.UI.GLUT)构建一个国际象棋游戏。我正在尝试为棋子渲染 PNG 图像。

我读到图像可以转换为 TextureObject 然后渲染,但找不到任何有用的资源来知道如何做到这一点。

这就是我生成棋盘的代码

drawSquare :: BoardSquare -> IO ()
drawSquare ((x,y,z),(r,g,b)) = preservingMatrix $ do
    color $ Color3 r g b
    translate $ Vector3 x y z
    drawCube -- this will draw a square of appropriate size

-- Display Callback
display :: IORef GameState -> DisplayCallback
display gameState = do
    gstate <- get gameState
    clear [ColorBuffer]
    forM_ (getBoardPoints gstate) $ drawSquare -- drawing all 64 squares here
    flush

谁能帮我在给定文件路径的窗口的任何给定xy 坐标处渲染PNG 图像?

【问题讨论】:

也许不是针对您的问题,但是您是否看过 nehe 教程(Haskell 端口:hackage.haskell.org/package/nehe-tuts,C 中的原件可以在:nehe.gamedev.net 找到)?我不知道,但也许这会有所帮助...... 您希望它专门在 OpenGL 中,还是只想在屏幕上显示 2D 图形?如果是后者,SDL2 是一个非常简单的替代方案,并且有很好的 haskell 绑定。 具有键盘动作和游戏玩法的总棋盘已在 OpenGL 中准备就绪。任何可以与 OpenGL 一起渲染 PNG 图像的东西都应该没问题,不需要在 OpenGL 中。 【参考方案1】:

建议:由于您是 Haskell 的新手,因此您没有为您的国际象棋游戏直接投入原始的 OpenGL,您是否查看了可以帮助您简化 OpenGL 的库?我会推荐gloss,看起来gloss-game 有一个helper function 可以将.png 文件加载到准备用于您的游戏的内存中。祝你好运! :-)

【讨论】:

是的,光泽会更简单。但是我首先偶然发现了 OpenGL,并且除了图像渲染部分之外,整个游戏都已经准备好了,我现在无法迁移到它(或者更像,我不想)。是否可以在 OpenGL 中使用该辅助函数? 我自己对 OpenGL Haskell 绑定并不是很熟悉,这就是为什么我推荐像光泽这样的东西。经过一番谷歌搜索,看起来您需要加载 2D 纹理的函数是:texImage2D。这是非常低的级别(您必须将指针传递给图像在内存中的保存位置)。 Here 是我在网上找到的一个要点,用于从 .bmp 加载纹理。 JuicyPixels 可能能够帮助您从 .png 文件中获取位图。祝你好运! :-) 感谢您提供的资源 :) 希望这对其他人也有帮助。无论如何,我们决定通过给出顶点来绘制图形,这样我们就不会遇到屏幕闪烁的任何问题。【参考方案2】:

这是我使用的方式。

首先,使用包gl-capture。它很旧,但效果很好。它生成ppm 图像。

import           Graphics.Rendering.OpenGL.Capture (capturePPM)

您需要帮助来申请该软件包吗?你需要一个键盘回调。如有需要,我可以提供帮助,请尽管问。

现在,一旦你有一个ppm 图像,你有两个选择:用 ImageMagick 转换它,或者使用 Haskell 包来转换它。有一个很好的:它叫做hip。这是我使用的模块:

module Utils.ConvertPPM
  where
import           Control.Monad    (when)
import           Graphics.Image
import           System.Directory (removeFile)

convert :: FilePath -> FilePath -> Bool -> IO ()
convert input output remove = do
  ppm <- readImageRGBA VU input
  writeImage output ppm
  when remove $ removeFile input

如果您需要更多帮助,请不要犹豫。

这是我使用的键盘回调类型:

keyboard :: IORef GLfloat -> IORef GLfloat -> IORef GLfloat -> IORef GLint
         -> KeyboardCallback
keyboard rot1 rot2 rot3 capture c _ =
  case c of
    'r' -> rot1 $~! subtract 1
    't' -> rot1 $~! (+1)
    'f' -> rot2 $~! subtract 1
    'g' -> rot2 $~! (+1)
    'v' -> rot3 $~! subtract 1
    'b' -> rot3 $~! (+1)
    'c' -> do
      i <- get capture
      let ppm = printf "pic%04d.ppm" i
          png = printf "pic%04d.png" i
      (>>=) capturePPM (B.writeFile ppm)
      convert ppm png True
      capture $~! (+1)
    'q' -> leaveMainLoop
    _   -> return ()

然后按“c”来捕捉图像。请注意,从 ppmpng 的转换很慢。特别是如果你打算做一些动画。对于动画,我宁愿只使用ppm,然后使用 ImageMagick 进行转换。

【讨论】:

以上是关于在 Haskell 中使用 OpenGL 渲染 PNG 图像的主要内容,如果未能解决你的问题,请参考以下文章

Haskell 中的 OpenGL VBO

VBO/FBO/DisplayLists 如何在 Haskell 的 OpenGL 绑定中工作?

Haskell openGL 和 GLUT 在 Mac OS X 上冻结?我可以在 GLUT 上使用 GLFW 吗?

Haskell OpenGL 和 GLUT 不明确的发生

是否可以使用 Ghcjs、Haste、Elm 等在服务器端渲染 Haskell 前端?

在 Python 中使用 OpenGL 渲染纹理不是