Memperbarui memori tekstur melalui shader?

8

Apa judulnya. Apakah mungkin memperbarui tekstur melalui glsl shader? Sesuatu seperti :

//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; 

??

pengguna1010005
sumber

Jawaban:

6

Yang Anda inginkan adalah mengikat tekstur ke shader dan kemudian membuat tekstur itu. Saya bisa meludahi mil dari spesifikasi dokumentasi OpenGL, tapi saya akan memberikan perasaan yang diberikan oleh saya:

Saya pikir itu tidak mungkin.

Apa yang saya tahu adalah mungkin, namun, adalah bahwa Anda membuat Frame Buffer Object (FBO) dan membuat itu. Pertama, Anda harus membuat FBO dan melampirkan tekstur dengan ukuran yang sama dengan yang ingin Anda perbarui.

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);

Ketika Anda ingin memperbarui tekstur Anda, Anda harus mengambil langkah-langkah berikut.

Pertama, Anda lampirkan FBO:

glBindFramebuffer(GL_FRAMEBUFFER, fbo_handle);

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

Sekarang Anda dapat membuat quad layar penuh dengan shader yang menampilkan warna yang diperbarui:

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;

Dan kemudian Anda harus menyalin framebuffer yang dihasilkan ke tekstur asli.

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();

Namun, Anda harus mempertimbangkan hal berikut:

  • Seberapa sering Anda memperbarui tekstur ini?
  • Jika Anda tidak harus memperbarui setiap frame, apakah metode ini sepadan dengan penalti kecepatan?
  • Bisakah Anda menghasilkan beberapa versi dari tekstur dan siklus di antara mereka?
  • Apakah ada cara lain untuk mencapai efek yang sama?
knight666
sumber
Wow terima kasih banyak atas bantuannya! Dan untuk menjawab pertanyaan Anda: 1. Saya memiliki tekstur khusus untuk pahlawan saya sehingga saya harus memperbarui setiap kali tabrakan terjadi (dengan titik-titik darah dan hal-hal lain). 2.Karena sifat permainan Anda mendapatkan hit atau menyentuh hal-hal yang penuh dengan kotoran (lumpur) sepanjang waktu jadi saya harus memperbarui tekstur itu sangat sering ... 3. Begitulah cara saya melakukannya sekarang dan saya tidak senang dengan itu (saya perlu patch tekstur dinamis) 4.Tidak tahu: o
user1010005
4
Aha! Nah itu membantu dalam menyempurnakan jawaban saya. Yang mungkin Anda cari adalah multi-tekstur. Anda memiliki tekstur untuk karakter permainan Anda dan Anda memiliki tekstur yang menunjukkan kotoran dan darah dan yang lainnya. Dalam shader, Anda dapat menggabungkannya untuk menciptakan efek yang Anda inginkan. Ini jauh lebih murah daripada terus-menerus merender ke objek penyangga bingkai dan menyalin hasilnya ke tekstur.
knight666
Terima kasih sekali lagi. Saya tidak yakin apa yang Anda maksud dengan multi texturing tetapi saya akan mencoba mencari di
stackexchange
4

Jika perangkat keras Anda mendukungnya, ekstensi GL_ARB_shader_image_load_store memungkinkan Anda menulis ke suatu tekstur.

elFarto
sumber
1
Saya dapat memberi tahu Anda sekarang bahwa NVIDIA GeForce GTS 250 mendukung OpenGL 3.3.0, tetapi tidak GL_EXT_shader_image_load_store. Itu artinya jawaban Anda mungkin benar, tetapi belum praktis di lapangan. Menyebalkan. :(
knight666
1
Yap, sepertinya Anda membutuhkan seri GeForce 400 atau lebih besar untuk dukungan (ini adalah fitur GL4 / DX11).
elFarto