13

私は若い頃からお気に入りのゲームの 1 つを「ハッキング」しており、opengl32.dll ラッパーを使用して OpenGL 呼び出しをインターセプトし、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 ...

これは、単一フレームの gl トレースです

これは 800 行近くありますが、訓練された OpenGL の目があれば、いつどのような呼び出しが行われたかを確認できるはずです。少なくとも理解できる数百行の描画呼び出しを削除しました。

4

3 に答える 3

2

あなたが何をしたいのか完全にはわかりません。ゲームを実行して fbo にレンダリングしますか? 上に物をレンダリングしますか?まず、すべての wgl および gl 呼び出しをフックしてみてください。http://research.microsoft.com/en-us/projects/detours/は、開始するのに適した場所です。

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

  • オーバーレイのレンダリング: SwapBuffers をフックし、そこで作業を行います
  • キャプチャ: 繰り返しますが、SwapBuffers をフックします。
  • テクスチャへのレンダリングとポスト エフェクトの実行: BindFramebuffer をフックします。ただし、落とし穴があります。フレーム バッファ 0 は起動時のデフォルトであるため、これを使用しないコードは BindFramebuffer を呼び出して起動せず、0 に戻すだけです。

詳細については、お気軽に私に連絡してください。私がお手伝いしたい楽しい教育プロジェクトのようですね :)

投稿する前にもう一度あなたの投稿を読んだだけで、あなたの問題はずっと簡単になるかもしれません. Windows プログラムとして、ターゲットは、フレームのレンダリングを開始するときに fbo 0 がバインドされていると想定します。それをするだけです。完了する前に、fbo 0 に戻ります。プッシュ/ポップ操作は行わないでください。あなたのfboが同じサイズであることを確認してください(Windowsではより大きなサイズでも問題ありません)。ただし、BindFramebuffer をフックする必要があります。ゲームが bind 0 を呼び出すたびに、代わりに自分のゲームをバインドする必要があります。しかし、ビューポートに触れるなど、他に何もする必要はありません。ゲームはそれを既に処理する必要があります。最終的に swapBuffers フックでレンダリングするときは、変更したものを必ず復元してください。

また、DrawBuffers 呼び出しは本当に必要ありません。それは私とおそらくあなたのターゲットのほくろを混乱させました. :) ターゲットは GL 1.2 コードを実行し、3...4... を実行しています。

于 2013-06-16T07:25:53.993 に答える