シェーダー経由でテクスチャメモリを更新しますか?


8

タイトルは何を言っています。GLSLシェーダーを介してテクスチャを更新することは可能ですか?何かのようなもの :

//Read
vec4 Pixel = texture2D(TextureID,gl_TexCoord[TextureIndex].st);

//Write to texture memory ?
vec4 NewPixel = Pixel + vec4(0.0,0.0,0.0,AlphaPatch);

// ?? How to write back to texture memory ??
texture2D(TextureID,gl_TexCoord[TextureIndex].st) = NewPixel; 

??

回答:


6

必要なのは、テクスチャをシェーダーにバインドしてから、そのテクスチャにレンダリングすることです。私は何マイルものOpenGLのドキュメント仕様を吐き出すことができましたが、私の直感が私に与える感覚を与えます。

それは可能ではないと思います。

私が知っていることは可能ですが、フレームバッファオブジェクト(FBO)を作成し、それにレンダリングすることです。まず、FBOを生成し、更新するテクスチャと同じサイズのテクスチャをFBOにアタッチする必要があります。

GLuint fbo_handle, fbo_texture_handle;

GLuint texture_width = GetTextureWidth();
GLuint texture_height = GetTextureWidth();

// generate texture

glGenTextures(1, &fbo_texture_handle);
glBindTexture(GL_TEXTURE_2D, fbo_texture_handle);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, texture_width, texture_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);

// generate framebuffer

glGenFrameBuffers(1, &fbo_handle);
glBindFrameBuffer(GL_FRAMEBUFFER, fbo_handle);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo_texture_handle, 0);

GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE)
{
    LOG_ERROR("Could not validate framebuffer);
}

glBindFramebuffer(GL_FRAMEBUFFER, 0);

テクスチャを更新する場合は、次の手順を実行する必要があります。

まず、FBOを接続します。

glBindFramebuffer(GL_FRAMEBUFFER, fbo_handle);

glPushAttrib(GL_VIEWPORT_BIT);
glViewport(0, 0, texture_width, texture_height);

これで、更新された色を出力するシェーダーを使用してフルスクリーンクワッドをレンダリングできます。

vec4 frag_texture = texture2D(TextureID, gl_TexCoord[TextureIndex].st);

vec4 frag_updated = frag_texture + vec4(0.0, 0.0, 0.0, AlphaPatch);

gl_FragData[0] = frag_updated;

そして、結果のフレームバッファを元のテクスチャにコピーする必要があります。

glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo_handle);
glBindTexture(GL_TEXTURE_2D, original_texture_handle);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, texture_width, texture_height);

glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);

glPopAttrib();

ただし、次の点を考慮する必要があります。

  • どのくらいの頻度でこのテクスチャを更新しますか?
  • フレームごとに更新する必要がない場合、この方法は速度ペナルティの価値がありますか?
  • このテクスチャの複数のバージョンを生成し、それらの間を循環できますか?
  • 同じ効果を達成する別の方法はありますか?

わぁ助けてくれてありがとう!そして、あなたの質問に答えるために:1.衝突が発生するたびに更新する必要があるヒーローのための特別なテクスチャーがあります(血のドットなどで)。2.ゲームの性質上、常に汚れ(泥)でいっぱいになっているものに触れたり触れたりするので、テクスチャを頻繁に更新する必要があります...それ(私は動的テクスチャパッチが必要です)4.わからない:o
user1010005

4
ああ!まあそれは私の答えを微調整するのに役立ちます。おそらく探しているのはマルチテクスチャリングです。ゲームキャラクターのテクスチャがあり、汚れや血などを示すテクスチャがあります。シェーダーでは、それらを組み合わせて目的の効果を作成できます。これは、フレームバッファオブジェクトに継続的にレンダリングして、結果をテクスチャにコピーするよりもはるかに安価です。
knight666

もう一度ありがとう。マルチテクスチャリングの意味がよくわかりませんが、stackexchangeで検索してみます:))
user1010005

4

ハードウェアがサポートしている場合は、GL_ARB_shader_image_load_store拡張機能を使用して、テクスチャに書き込むことができます。


1
私のNVIDIA GeForce GTS 250がOpenGL 3.3.0をサポートしているが、サポートしていないことを今すぐに言えますGL_EXT_shader_image_load_store。つまり、あなたの答えはおそらく正しいですが、フィールドではまだ実用的ではありません。吸います。:(
knight666

1
はい、サポートにはGeForce 400シリーズ以上が必要なようです(これはGL4 / DX11の機能です)。
elFarto

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.