2

複雑な 2D シーンを OpenGL ウィンドウに描画します。ユーザーがシーンのスクリーンショットを撮り、JPG として保存できるようにしたいと考えています。ただし、シーンを画面よりも大きく描画できることを指定できるようにしてほしいです (これにより、より多くの詳細を見ることができるようになります)。

画面に収まるビューポートより大きい数値を指定すると、見えないものはすべてビットマップに描画されません。追跡できなかったこれらの OpenGL 関数のいくつかの動作について、誤った理解をしているように感じます。

renderSize以下のコードは、プログラムを開始するデフォルトのビューポートよりも小さい場合、完全に正常に動作します。が大きい場合renderSize、適切なサイズの JPG が作成されますが、画面の表示領域を超えた右側/上部のセクションは単に空白になります。ビューポートをクリックして 2 番目のモニターにドラッグすると、より多くの画像が描画されますがrenderSize、両方のモニターよりも大きい場合はすべてではありません。画面に表示されるビューポートとは無関係に、この図面を作成するにはどうすればよいですか?

( 7000 x 2000 のような大きな数値で、この関数が呼び出されたときに正しく設定されているrenderLocationことを確認できます)renderSizerenderSize

public Bitmap renderToBitmap(RenderMode mode)
    {
        // load a specific ortho projection that will contain the entire graph
        GL.MatrixMode(MatrixMode.Projection);
        GL.PushMatrix();
        GL.LoadIdentity();

        GL.Ortho(0, renderSize.Width, 0, renderSize.Height, -1, 1);
        GL.Viewport(0, 0, renderSize.Width, renderSize.Height);

        GL.MatrixMode(MatrixMode.Modelview);
        GL.PushMatrix();
        GL.LoadIdentity();


        // move the graph so it starts drawing at 0, 0 and fills the entire viewport
        GL.Translate(-renderLocation.X, -renderLocation.Y, 0);

        GL.ClearColor(Color.White);
        GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);

        // render the graph
        this.render(mode);

        // set up bitmap we will save to
        Bitmap bitmap = new Bitmap(renderSize.Width, renderSize.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
        BitmapData bData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat);

        // read the data directly into the bitmap's buffer (bitmap is stored in BGRA)
        GL.ReadPixels(0, 0, renderSize.Width, renderSize.Height, OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, bData.Scan0);

        bitmap.UnlockBits(bData);
        bitmap.RotateFlip(RotateFlipType.RotateNoneFlipY); // compensate for openGL/GDI y-coordinates being flipped

        // revert the stuff about openGL we changed
        GL.MatrixMode(MatrixMode.Projection);
        GL.PopMatrix();
        GL.MatrixMode(MatrixMode.Modelview);
        GL.PopMatrix();

        return bitmap;
    }

そして、GLウィンドウが発生した場合に備えて、GLウィンドウを初期化する方法を次に示します。

private void initGL()
    {
        GL.ClearColor(Color.AntiqueWhite);
        GL.Disable(EnableCap.Lighting);

        GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);

        resetCamera();
    }

    private void resetCamera()
    {
        offsetX = offsetY = 0; // Bottom-left corner pixel has coordinate (0, 0)
        zoomFactor = 1;
        setupViewport();
        glWindow.Invalidate();
    }

    private void setupViewport()
    {
        int w = glWindow.Width;
        int h = glWindow.Height;
        GL.MatrixMode(MatrixMode.Projection);
        GL.LoadIdentity();
        GL.Ortho(0 + offsetX, w + offsetX, 0 + offsetY, h + offsetY, -1, 1);
        GL.Viewport(0, 0, w, h); // Use all of the glControl painting area
    }
4

1 に答える 1

1

ピクセルの所有権の問題が発生しているようです:

14.070 ウィンドウの一部が別のウィンドウに重なっている場所で glReadPixels() を呼び出すと、重なっている領域の有効なピクセル データが得られないのはなぜですか?

これは、ピクセル所有権テストと呼ばれる OpenGL 仕様の一部によるものです。ウィンドウが別のウィンドウによって隠されている場合、隠されている領域のピクセル データを格納する必要はありません。したがって、glReadPixels() 呼び出しは、隠蔽された領域に対して未定義のデータを返す可能性があります。

ピクセル所有権テストは、OpenGL の実装ごとに異なります。一部の OpenGL 実装では、ウィンドウの隠れた領域またはウィンドウ全体をオフスクリーン バッファーに格納します。このような実装は、隠蔽されたウィンドウの有効なピクセル データを返すことができます。ただし、多くの OpenGL 実装では、画面上のピクセルを 1 対 1 でフレーム バッファーの格納場所にマップし、ウィンドウの隠れた領域のピクセル データを格納しません (また、返すこともできません)。

1 つの戦略は、ウィンドウをウィンドウ スタックの一番上に移動し、レンダリングしてから、glReadPixels() 呼び出しを実行するようにウィンドウ システムに指示することです。ただし、このような方法でも、ソース ウィンドウがわかりにくくなる可能性があるユーザーの介入のリスクは依然としてあります。

一部のアプリケーションで有効なアプローチは、X Windows での Pixmap などの非表示ウィンドウにレンダリングすることです。このタイプの描画面は、ユーザーが隠すことはできず、そのコンテンツは常にピクセル所有権テストに合格する必要があります。このような描画面から読み取ると、常に有効なピクセル データが生成されます。残念ながら、このような描画面へのレンダリングは、グラフィック ハードウェアによって高速化されないことがよくあります。

ウィンドウより大きいレンダリングやオフスクリーン レンダリングについては、 FBOまたは PBuffer を調べてください。

libtrFBOまたはPBufferを使用できない/使用しない場合もあります。

于 2013-02-20T00:25:41.083 に答える