Mise à jour de la mémoire de texture via un shader?

8

Que dit le titre, est-il possible de mettre à jour une texture via un shader glsl? Quelque chose comme :

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

??

user1010005
la source

Réponses:

6

Ce que vous voulez, c'est lier une texture à un shader, puis effectuer un rendu sur cette texture. Je pourrais cracher des kilomètres de spécifications de documentation d'OpenGL, mais je vais donner l'impression que mon instinct me donne:

Je ne pense pas que ce soit possible.

Ce que je sais est possible, cependant, c'est que vous créez un Frame Buffer Object (FBO) et que vous le restituez. Tout d'abord, vous devez générer un FBO et y attacher une texture de la même taille que celle que vous souhaitez mettre à jour.

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

Lorsque vous souhaitez mettre à jour votre texture, vous devez suivre les étapes suivantes.

Tout d'abord, vous attachez le FBO:

glBindFramebuffer(GL_FRAMEBUFFER, fbo_handle);

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

Vous pouvez maintenant rendre un quadruple plein écran avec un shader qui produit la couleur mise à jour:

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;

Et puis vous devez copier le framebuffer résultant dans la texture d'origine.

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

Cependant, vous devez considérer les éléments suivants:

  • À quelle fréquence mettez-vous à jour cette texture?
  • Si vous n'avez pas à le mettre à jour à chaque image, cette méthode vaut-elle la peine de vitesse?
  • Pouvez-vous générer plusieurs versions de cette texture et alterner entre elles?
  • Existe-t-il une autre manière d'obtenir le même effet?
chevalier666
la source
Wow merci beaucoup pour l'aide! Et pour répondre à vos questions: 1.J'ai une texture spéciale pour mon héros que je dois mettre à jour chaque fois qu'une collision se produit (avec des points de sang et d'autres choses). 2.En raison de la nature du jeu, vous êtes touché ou touchez des choses pleines de saleté (boue) tout le temps, donc je dois mettre à jour cette texture très fréquemment ... 3.C'est comme ça que je le fais en ce moment et je ne suis pas satisfait (j'ai besoin de patchs de texture dynamique) 4.Je ne sais pas: o
user1010005
4
Aha! Eh bien, cela aide à affiner ma réponse. Ce que vous recherchez probablement, c'est la multi-texturation. Vous avez une texture pour votre personnage de jeu et vous avez une texture qui montre la saleté et le sang et ainsi de suite. Dans un shader, vous pouvez les combiner pour créer l'effet souhaité. C'est beaucoup moins cher que de rendre continuellement un objet de tampon d'image et de copier le résultat dans une texture.
knight666
Je vous remercie encore une fois, je ne sais pas trop ce que vous voulez dire avec la texturation multiple, mais j'essaierai de rechercher sur stackexchange :))
user1010005
4

Si votre matériel le prend en charge, l'extension GL_ARB_shader_image_load_store vous permet d'écrire sur une texture.

elFarto
la source
1
Je peux vous dire dès maintenant que mon NVIDIA GeForce GTS 250 prend en charge OpenGL 3.3.0, mais pas GL_EXT_shader_image_load_store. Cela signifie que votre réponse est probablement correcte, mais pas encore pratique sur le terrain. Suce. :(
knight666
1
Oui, il semble que vous ayez besoin d'une série GeForce 400 ou supérieure pour le support (c'est une fonctionnalité GL4 / DX11).
elFarto