¿Actualizar la memoria de textura a través del sombreador?

8

Lo que dice el título ¿Es posible actualizar una textura a través de un sombreador glsl? Algo como :

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

??

usuario1010005
fuente

Respuestas:

6

Lo que quieres es unir una textura a un sombreador y luego renderizar a esa textura. Podría escupir miles de especificaciones de documentación de OpenGL, pero voy a dar la sensación que me da mi instinto:

No creo que sea posible.

Sin embargo, lo que sí sé es que puede crear un objeto Frame Buffer (FBO) y renderizarlo. Primero, debe generar un FBO y adjuntarle una textura con el mismo tamaño que el que desea actualizar.

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

Cuando desee actualizar su textura, debe seguir los siguientes pasos.

Primero, adjuntas el FBO:

glBindFramebuffer(GL_FRAMEBUFFER, fbo_handle);

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

Ahora puede renderizar un quad de pantalla completa con un sombreador que genera el color actualizado:

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;

Y luego tienes que copiar el framebuffer resultante a la textura original.

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

Sin embargo, debe considerar lo siguiente:

  • ¿Con qué frecuencia actualiza esta textura?
  • Si no tiene que actualizarlo cada cuadro, ¿vale la pena la penalización de este método?
  • ¿Puedes generar múltiples versiones de esta textura y alternar entre ellas?
  • ¿Hay otra forma de lograr el mismo efecto?
caballero666
fuente
Wow muchas gracias por la ayuda! Y para responder a sus preguntas: 1. Tengo una textura especial para mi héroe que tengo que actualizar cada vez que se produce una colisión (con puntos de sangre y otras cosas). 2.Debido a la naturaleza del juego, te golpean o tocas cosas llenas de suciedad (barro) todo el tiempo, así que tengo que actualizar esa textura con mucha frecuencia ... 3.Así es como lo hago ahora y no estoy contento con (necesito un parche de textura dinámico) 4. No lo sé: o
user1010005
44
¡Ajá! Bueno, eso ayuda a afinar mi respuesta. Lo que probablemente esté buscando es texturizado múltiple. Tienes una textura para tu personaje del juego y tienes una textura que muestra suciedad, sangre y demás. En un sombreador, puede combinarlos para crear el efecto que desee. Esto es mucho más barato que renderizar continuamente a un objeto de frame buffer y copiar el resultado a una textura.
knight666
Gracias una vez más. No estoy muy seguro de lo que quiere decir con texturizado múltiple, pero intentaré buscar en stackexchange :))
user1010005
4

Si su hardware lo admite, la extensión GL_ARB_shader_image_load_store le permite escribir en una textura.

elFarto
fuente
1
Te puedo decir ahora que mi NVIDIA GeForce GTS 250 es compatible con OpenGL 3.3.0, pero no GL_EXT_shader_image_load_store. Eso significa que su respuesta es probablemente correcta, pero aún no es práctica en el campo. Apesta :(
knight666
1
Sí, parece que necesita una serie GeForce 400 o superior para soporte (es una función GL4 / DX11).
elFarto