Atualizando a memória de textura via sombreador?

8

O que o título diz: É possível atualizar uma textura por meio de um glsl shader? 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; 

??

user1010005
fonte

Respostas:

6

O que você deseja é vincular uma textura a um sombreador e renderizar nessa textura. Eu poderia cuspir por quilômetros de especificação de documentação do OpenGL, mas vou dar a sensação que meu instinto me dá:

Eu não acho isso possível.

O que eu sei é possível, no entanto, é que você crie um objeto de buffer de quadro (FBO) e processe-o. Primeiro, você deve gerar um FBO e anexar uma textura a ele com o mesmo tamanho que você deseja atualizar.

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

Quando você quiser atualizar sua textura, siga as etapas abaixo.

Primeiro, você anexa o FBO:

glBindFramebuffer(GL_FRAMEBUFFER, fbo_handle);

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

Agora você pode renderizar um quad em tela cheia com um sombreador que produz a cor atualizada:

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;

E então você deve copiar o buffer de moldura resultante para a 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();

No entanto, você deve considerar o seguinte:

  • Com que frequência você atualiza essa textura?
  • Se você não precisar atualizá-lo a cada quadro, esse método vale a pena de velocidade?
  • Você pode gerar várias versões dessa textura e alternar entre elas?
  • Existe outra maneira de obter o mesmo efeito?
knight666
fonte
Uau, muito obrigado pela ajuda! E para responder às suas perguntas: 1.Tenho uma textura especial para o meu herói que preciso atualizar sempre que ocorre uma colisão (com pontos de sangue e outras coisas). 2. Devido à natureza do jogo, você é atingido ou toca em coisas cheias de sujeira (lama) o tempo todo, então eu tenho que atualizar essa textura com muita frequência ... 3. É assim que eu faço agora e não estou feliz com -lo (eu preciso de patching textura dinâmico) 4.Don't saber: o
user1010005
4
Aha! Bem, isso ajuda a ajustar minha resposta. O que você provavelmente está procurando é a texturização múltipla. Você tem uma textura para o seu personagem do jogo e uma textura que mostra sujeira, sangue e outros enfeites. Em um shader, você pode combiná-los para criar o efeito desejado. Isso é muito mais barato do que renderizar continuamente em um objeto de buffer de quadro e copiar o resultado em uma textura.
knight666
Obrigado mais uma again.I'm não tem certeza que você quer dizer com Multi texturização, mas eu vou tentar procurar em Stackexchange :))
user1010005
4

Se o seu hardware suportar, a extensão GL_ARB_shader_image_load_store permite gravar em uma textura.

elFarto
fonte
11
Eu posso lhe dizer agora que minha NVIDIA GeForce GTS 250 suporta OpenGL 3.3.0, mas não GL_EXT_shader_image_load_store. Isso significa que sua resposta provavelmente está correta, mas ainda não é prática em campo. É uma merda. :(
knight666
11
Sim, parece que você precisa de uma série GeForce 400 ou superior para suporte (é um recurso GL4 / DX11).
elFarto 26/06