2013-04-05 7 views
11

私は若い頃から好きなゲームを "ハッキング"していましたが、OpenGL呼び出しを傍受してopengl32.dllラッパーを使ってC++コードを挿入することができました。私はこのためにいくつかのクールな使い方を考え出すことができましたが、私の現在の目標は、この古いゲームにglslシェーダーをポスト処理してよりモダンなものにすることです。ゲームはもともと90年代後半にリリースされたので、OpenGLとそのレンダリングコードの使用は限定的/プリミティブ/時代遅れです。フレームバッファーを注入する

私はglslシェーダプログラムを初期化して使用するコードを注入することで頂点シェーダとフラグメントシェーダを正常に作成できましたが、フレームバッファを作成する/テクスチャにシーンをレンダリングするという問題がサンプラとしてフラグメントシェーダに送信されます。私が知る限り、私が作り出すテクスチャは、通常はすべて黒です。

私がやっていることに関連するリソースを見つけて、未処理のopengl呼び出しを調べることは難しいです(私は、ゲームプレイの単一フレームのOpenGLトレースを読み込んでコードを挿入する場所を決定しようとしています)。私が間違ってやっていることの周りに私の頭を包み込むことができなかった。

私は多くの場所にコードを入れようとしましたが、ゲームコールがwglSwapBuffers()のコールの後にバインドしています。次のglFlush()コールの直前にバインドを解除していますが、わかりません複数のビューポートの設定や行列操作、またはこれらの時間の間に作成されたその他のものが何らかの形でフレームバッファを使いこなしている場合。

これはフレームバッファを初期化するコードです:

void initFB() 
{ 
    /* Texture */ 
    glActiveTexture(GL_TEXTURE0); 
    glGenTextures(1, &fbo_texture); 
    glBindTexture(GL_TEXTURE_2D, fbo_texture); 

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1920, 1080, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); 

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 

    glBindTexture(GL_TEXTURE_2D, 0); 

    /* Depth buffer */ 
    glGenRenderbuffers(1, &fbo_depth); 
    glBindRenderbuffer(GL_RENDERBUFFER, fbo_depth); 
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, 1920, 1080); 
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fbo_depth); 
    glBindRenderbuffer(GL_RENDERBUFFER, 0); 

    /* Framebuffer to link everything together */ 
    glGenFramebuffers(1, &fbo); 
    glBindFramebuffer(GL_FRAMEBUFFER, fbo); 

    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo_texture, 0); 
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fbo_depth); 

    GLenum status; 
    if ((status = glCheckFramebufferStatus(GL_FRAMEBUFFER)) != GL_FRAMEBUFFER_COMPLETE) { 
    fprintf(stderr, "glCheckFramebufferStatus: error %p", status); 
    } 

    glBindFramebuffer(GL_FRAMEBUFFER, 0); 
} 

これはwglSwapBuffers後に呼び出さコードです:

GLenum fboBuff[] = { GL_COLOR_ATTACHMENT0 }; 
glBindFramebuffer(GL_FRAMEBUFFER, fbo); 
glDrawBuffers(1, fboBuff); 
glPushAttrib(GL_VIEWPORT_BIT | GL_ENABLE_BIT); 

これはglFlush()前に呼び出さコードです:

glBindFramebuffer(GL_FRAMEBUFFER, 0); 
glPopAttrib(); // Restore our glEnable and glViewport states 

... Draw an Overlay containing with fbo texture binded ... 

Hereは単一フレームのglトレースです。

これはほぼ800行ですが、訓練されたOpenGLの眼では、いつどのような呼び出しが行われているか見ることができます。私は少なくとも何百行もの描画呼び出しを削除しました。

+0

おそらく、残りのコードが正しいかどうかを確認するためにglReadPixelsでテクスチャを更新してみてください。 –

答えて

0

私が理解しているように、あなたは古いゲームのグラフィカルな面を更新しようとしていますが、必要な部分を改造できないようなオリジナルのコードには限界があります。

私は関連するゲームコーディングの経験はありませんが、私が改造しようとしていたアプリケーションを持っていたら、その構造を調べるためにアプリケーションを分解し、メモリ内パッチを選択的に適用して、私が提供した代替品へのコードのセグメント。

私は、プログラムのメモリの特定の部分を条件付き/無条件のジャンプ/コール命令で上書きし、コードがプログラムの不可欠な部分となるように選択的にNOPするプリロードライブラリを事前にロードします。それは間違いなくエレガントではありませんでしたが、元のコードの不備を素早く回避することができました。

2

あなたがしたいことは完全にはわかりません。ゲームを実行してfboにレンダリングしますか?上のものをレンダリングする? 開始するには、すべてのwglとglコールをフックしてみてください。 http://research.microsoft.com/en-us/projects/detours/は良い出発点です。

あなたの投稿をもう一度読んで、あなたはすでにそれを知っていると思います。あなたが何をしたいのかを知るのに役立ちます。

  • オーバーレイをレンダリング:、再びフックSwapBuffers
  • テクスチャへのレンダリングとやってポストエフェクト:フックSwapBuffersは、自分のものにあっ
  • キャプチャを行うフックBindFramebuffer。しかし、キャッチがあります:フレームバッファ0は起動時のデフォルトですので、それを使用しないコードはBindFramebufferを起動しません.0に戻すようにしてください。glClearを呼び出すか最初に呼び出すかを試してみてください。

さらに詳しい情報は私には無料です。私が手助けしたいと思う楽しい教育プロジェクトのように聞こえます:)

投稿する前にあなたの投稿をもう一度読むだけで、あなたの問題はもっと簡単になるかもしれません。 Windowsプログラムでは、ターゲットは、フレームのレンダリングを開始するときにfbo 0がバインドされていることを前提としています。ちょうどそれを行う。それが終わる前に、それはfbo 0に戻ってきます。プッシュ/ポップのことをしないでください。ちょうどあなたのfboが同じ大きさであることを確認してください(それより大きなウィンドウでもOKです)。あなたはBindFramebufferをフックする必要があります。あなたのゲームコールが0をバインドするときは、あなたの代わりにバインドする必要があります。しかし、ビューポートに触れるような何かをする必要はありません。ゲームはすでにそれを処理しなければなりません。最後にあなたのswapBuffersフックをレンダリングするときは、変更したものを復元するようにしてください。

また、実際にはDrawBuffersコールは必要ありません。それは私とおそらくあなたの目標のモルを混同しました。 :)あなたの目標は、GL 1.2のコードを実行し、あなたが私の経験から3 ... 4 ...

1

を行っている、あなたがやろうとしている事がshaderless GL1.xアプリケーションのGL傍受アプローチでかなり可能です。

FBOを今のところ忘れて、元のアプリケーションがバッファを交換したときにFBOを忘れて、レンダリングされたコンテンツをテクスチャにコピーし、ポストプロセッシング機能にテキストを付けることができます。

いくつかのもの、あなたはの世話をする必要があり、そのようGL注入アプローチを行うとき:

  • 古いGL(これは典型的なゲームよりもCADアプリケーションのための可能性が高いですが)異なるGLコンテキストがあるかもしれませんユーザーがObject IDを直接管理できるようにしました - 必要なところでglGen*への呼び出しは機能しませんでした。自分で新しいオブジェクトを作成した場合、元のアプリはそれらのIDを認識せず、再利用する可能性があります。この権利を取得したい場合は、オブジェクトIDを透過的に再マップする必要があります(ハッシュテーブルを使用する可能性があります)。多くのGL関数が含まれているため、多くの作業が必要です。別の悪質なハックは、あなた自身ではありえないオブジェクトIDを自分で使うことです。あなたは(可能な限り)ゲームが期待されている状態を復元することは非常に注意する必要がありますので
  • GLは、ステートマシンです。大藤の手は、あなたも、あなたがそれを傍受するために変更を得たとき、元のアプリケーションは、任意のGLの状態が設定されている可能性があることを準備する必要があります - あなたは多くのことをリセットする必要があります。

古いGLアプリケーションにテクスチャにレンダリングを挿入することが可能であることを私は確信できます。 Quake3と他の有名な時代のゲームでとてもうまくいった。私はあなたの現在のアプローチでobviuosエラーが表示されません。しかし、私はいくつかのこと:またglDrawBuffer()を傍受し、任意のアプリがあなたの色の添付ファイルに(ここでは、ダブルバッファのアプリケーションを想定)GL_BACKに何をするつもりされた図面を中継する必要があります。あなたが投稿したログはこの機能をトレースしていないので、起動時に一度設定されている可能性があります。

glFlushを使用する理由もわかりません。それは特に何かの良いマーカーではありません。ゲームでダブルバッファリングが使用されている場合、SwapBuffersは得られる "フレーム"の最善の近似値になります。コンテキストの作成直後に独自のinitオブジェクトの作成物を挿入するだけで(wglCreateCintext()とfriendsも傍受できます)、 はすでにFBOへのレンダリングを設定しています。 SwapBuffersでは、シェーダを使ってテクスチャの内容を実際のバックバッファに描画し、実際のバッファスワップを行い、レンダリングをFBO設定に復元します。

あなたがすでにそれを認識しているかどうかわかりませんが、オープンソースプロジェクトChromiumは、OpenGLインターセプトのために素晴らしいfframeworkを提供しています。これは分散クラスタリングに焦点を絞っていますが、ローカルセットアップでも機能し、SPU(ストリーム処理ユニット)を書くことができます。ここでは、接続するGL関数のC関数を単純に指定できます。プロジェクトは古く、5年ほど前から積極的に開発されていません。GLストリーム操作の種類は、より現代的なプログラマブルパイプラインでは機能しません。 x fixed-function pipeline ...

関連する問題