オフスクリーン・レンダリング¶
ビューを表示しないでバックグラウンドで描画処理を行う方法について説明します。
MGL.CreateOffscreenContext による方法¶
LINQPad を立ち上げ、次の設定をします。
- 参照設定に MoNo.dll, MoNo.OpenGL.dll を加える。
- インポートする namespace に MoNo, MoNo.OpenGL を加える。
- Language を F# Expression にする。
次のコードを実行すると直線が描画されたビットマップが保存されます。
let con, hbmp = MGL.CreateOffscreenContext (256, 128)
MGL.ClearBuffers (Color4f(0.5f, 0.5f, 0.5f, 1.0f), 1.0, 0)
MGL.DrawArrays (GLPrimType.Lines, [| Point3d.Zero; Point3d(0.5, 0.7, 0.) |])
GL.glFlush()
let bmp = System.Drawing.Image.FromHbitmap(hbmp)
bmp.Save(@"c:\...\test.bmp")
この方法では投影行列もモデルビュー行列も設定されません。 これらの設定が必要な場合は、全て自前で設定コードを記述する必要があります。
このAPIは内部でFBO(Framebuffer object)を利用しません。
CreateCompatibleDC(NULL)
によって作成したデバイスコンテキストをビットマップに関連付け、そこに OpenGL 描画を行います。
この方法では、グラフィックボードのアクセラレーション機能が利用できません。
弊社の環境で glGetString
によって検証すると、次の結果が得られます。
Key | value |
---|---|
GL_VERSION | 1.1.0 |
GL_VENDOR | Microsoft Corporation |
GL_RENDERER | GDI Generic |
GraphicsUT.CreateOffscreenSceneContext による方法¶
LINQPad を立ち上げ、次の設定をします。
- 参照設定に MoNo.dll, MoNo.OpenGL.dll, MoNo.Basics.dll, MoNo.Framework.dll を加える。
- インポートする namespace に MoNo, MoNo.OpenGL を加える。
- Language を F# Expression にする。
次のコードを実行すると直線が描画されたビットマップが保存されます。
let sc, hbmp = GraphicsUT.CreateOffscreenSceneContext(Sphere3d.Unit, Size2i (300, 200))
sc.InitProjection() // 投影行列の設定
use scope = sc.BeginWorldScene() // モデルビュー行列の設定等
MGL.ClearBuffers (Color4f(0.5f, 0.5f, 0.5f, 1.0f), 1.0, 0)
MGL.DrawArrays (GLPrimType.Lines, [| Point3d.Zero; Point3d(0.5, 0.7, 0.) |])
GL.glFlush()
let bmp = System.Drawing.Image.FromHbitmap(hbmp)
bmp.Save(@"c:\...\test.bmp")
この方法では投影行列およびモデルビュー行列が sc.Camera
に沿って設定されます。
MGL.IFramebuffer による方法¶
次のコードを実行すると直線が描画されたビットマップが保存されます。
if MGL.FBOIsAvailable then
let fb = MGL.GenFramebuffer(Size2i (256, 128))
fb.AssignRenderBuffer (OpenGL.GLAttachment.Depth) |> ignore
fb.AssignTexture (OpenGL.GLAttachment.Color00, OpenGL.GLTextureType.RGBA8) |> ignore
let sc = fb.CreateSceneContext(Sphere3d.Unit)
sc.Camera.ViewingPos <- CodSys3d (-Vector3d.Ey, Vector3d.Ex)
let bmp =
use __ = fb.Bind()
sc.InitProjection() // 投影行列の設定
use scope = sc.BeginWorldScene() // モデルビュー行列の設定等
MGL.ClearBuffers (Color4f(0.5f, 0.5f, 0.7f, 1.0f), 1.0, 0)
MGL.DrawArrays (GLPrimType.Lines, [| Point3d.Zero; Point3d(-0.5, 0.7, 0.) |])
GL.glFlush()
MGL.ReadColorPixelsToBitmap24bppRgb()
bmp.Save @"c:\...\test.bmp"
ただし、LINQPad やコンソールアプリケーションでは FBOIsAvailable
が false
となってしまい正常に動作しないようです。
通常の MoNo.RAIL のウィンドウが起動した状態で上記コードを実行すると、意図したとおりに動作しました。
現状では、FBO が動作する条件についてきちんと絞り込めていません(申し訳ありません)。
FbArgs による方法¶
MoNo.Framework.FSharp.dll に定義されている
MoNo.Graphics.FbArgs
を利用する方法です。
次のコードを実行すると直線が描画されたビットマップが保存されます。
open MoNo
...
let bmp =
let fba = Graphics.FbArgs.New (Size2i (256, 128), Sphere3d.Unit)
use con = fba.Bind ()
con.Scope.Color <- Drawing.Color.YellowGreen
con.Scope.Lighting <- false
MGL.DrawArrays (GLPrimType.Lines, [| Point3d.Zero; Point3d(0.5, 0.7, 0.) |])
MGL.ReadColorPixelsToBitmap24bppRgb()
bmp.Save @"c:\...\test.bmp"
FbArgs
は内部でMGL.IFramebuffer
を使用します。- 投影行列やモデルビュー行列などが
FbArgs
の値に従って自動的に設定されます。
FramebufferImage による方法¶
MoNo.Framework.FSharp.dll に定義されている
MoNo.Graphics.FramebufferImage
を利用する方法です。
次のコードを実行すると直線が描画されたビットマップが保存されます。
open MoNo
...
let args = Graphics.FbArgs.New (Size2i (256, 128), Sphere3d.Unit)
let image = Graphics.FramebufferImage.ofColor args (fun sc ->
sc.Color <- Drawing.Color.Yellow
MGL.DrawArrays (GLPrimType.Lines, [| Point3d.Zero; Point3d(0.5, 0.7, 0.) |]))
let bmp = Graphics.FramebufferImage.toBitmap image
bmp.Save @"c:\...\test.bmp"
FramebufferImage<'T>
は次のように定義されています。
type FramebufferImage<'T when 'T : equality> = {
Camera : ICamera
Image : Immutarray<'T>
} with
member this.At (x, y) = this.Image.[x + this.Camera.ScreenSize.X * (this.Camera.ScreenSize.Y - 1 - y)]
member this.At (p : Point2i) = this.At (p.X, p.Y)
member this.At (p : System.Drawing.Point) = this.At (p.X, p.Y)
member this.Items =
seq {
let size = this.Camera.ScreenSize
for y = 0 to size.Y - 1 do
let index = size.X * (size.Y - 1 - y)
for x = 0 to size.X - 1 do
yield Point2i (x, y), this.Image.[x + index]
}
この定義からわかるように、FramebufferImage
を使うと FBO に描画して得られた画像を配列データとして取り出すことができます。
サンプルコードではカラーバッファの画像を取り出していますが、デプスバッファやステンシルバッファの画像を取り出すことも可能です。
描画結果をテクスチャとして取り出す¶
これまでのサンプルでは描画結果をビットマップ画像として取り出していました。
テクスチャオブジェクトとして取り出したい場合は、次のように MGL.IFramebuffer
の DetachTexture
メソッドを使用します。
let tex =
let fba = Graphics.FbArgs.New (Size2i (512, 256), Sphere3d(2.0), Vector3d (1.0, 2.0, 3.0))
use con = fba.Bind()
con.Scope.Color <- Drawing.Color.Orange
Cube3d(Point3d.Zero, 1.0).Draw con.SceneContext
con.Framebuffer.DetachTexture GLAttachment.Color00