============================================== オフスクリーン・レンダリング ============================================== ビューを表示しないでバックグラウンドで描画処理を行う方法について説明します。 MGL.CreateOffscreenContext による方法 --------------------------------------------------------------- LINQPad を立ち上げ、次の設定をします。 * 参照設定に MoNo.dll, MoNo.OpenGL.dll を加える。 * インポートする namespace に MoNo, MoNo.OpenGL を加える。 * Language を F# Expression にする。 次のコードを実行すると直線が描画されたビットマップが保存されます。 .. code-block:: fsharp 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 にする。 次のコードを実行すると直線が描画されたビットマップが保存されます。 .. code-block:: fsharp 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 による方法 --------------------------------------------------------------- 次のコードを実行すると直線が描画されたビットマップが保存されます。 .. code-block:: fsharp 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`` を利用する方法です。 次のコードを実行すると直線が描画されたビットマップが保存されます。 .. code-block:: fsharp 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`` を利用する方法です。 次のコードを実行すると直線が描画されたビットマップが保存されます。 .. code-block:: fsharp 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>`` は次のように定義されています。 .. code-block:: fsharp 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`` メソッドを使用します。 .. code-block:: fsharp 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