Aggiornamento della memoria delle texture tramite shader?


8

Cosa dice il titolo: è possibile aggiornare una trama tramite uno shader glsl? Qualcosa di simile a :

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

??

Risposte:


6

Quello che vuoi è legare una trama a uno shader e quindi renderizzare quella trama. Potrei passare attraverso miglia di specifiche della documentazione di OpenGL, ma ho intenzione di dare la sensazione che il mio istinto mi dà:

Non penso sia possibile.

Quello che so è possibile, tuttavia, è che si crea un Frame Buffer Object (FBO) e lo si esegue il rendering. Innanzitutto, è necessario generare un FBO e collegarvi una trama con le stesse dimensioni di quella che si desidera aggiornare.

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 vuoi aggiornare la tua trama, devi seguire i seguenti passi.

Innanzitutto, allega l'FBO:

glBindFramebuffer(GL_FRAMEBUFFER, fbo_handle);

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

Ora puoi renderizzare un quad a schermo intero con uno shader che emette il colore aggiornato:

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 quindi devi copiare il framebuffer risultante sulla trama originale.

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

Tuttavia, è necessario considerare quanto segue:

  • Con quale frequenza aggiorni questa trama?
  • Se non è necessario aggiornarlo ogni fotogramma, questo metodo vale la penalità di velocità?
  • Puoi generare più versioni di questa trama e passare da una all'altra?
  • C'è un altro modo per ottenere lo stesso effetto?

Wow, grazie mille per l'aiuto! E per rispondere alle tue domande: 1. Ho una trama speciale per il mio eroe che devo aggiornare ogni volta che si verifica una collisione (con punti di sangue e altre cose). 2.Per via della natura del gioco vieni colpito o tocchi sempre cose piene di sporcizia (fango), quindi devo aggiornare quella trama molto frequentemente ... 3.È così che faccio adesso e non sono contento (ho bisogno di patch per la trama dinamica) 4.Non so: o
user1010005

4
Aha! Bene, questo aiuta a mettere a punto la mia risposta. Quello che probabilmente stai cercando è multi-texturing. Hai una trama per il tuo personaggio di gioco e hai una trama che mostra sporcizia, sangue e quant'altro. In uno shader, puoi combinarli per creare l'effetto desiderato. Questo è molto più economico rispetto al rendering continuo su un oggetto frame buffer e alla copia del risultato su una trama.
knight666,

Grazie ancora. Non sono del tutto sicuro di cosa intendi con multi texturing ma cercherò di cercare su stackexchange :))
user1010005

4

Se l'hardware lo supporta, l'estensione GL_ARB_shader_image_load_store consente di scrivere su una trama.


1
Posso dirti ora che la mia NVIDIA GeForce GTS 250 supporta OpenGL 3.3.0, ma non GL_EXT_shader_image_load_store. Ciò significa che la tua risposta è probabilmente corretta, ma non ancora pratica sul campo. Fa schifo. :(
knight666,

1
Sì, sembra che tu abbia bisogno di una serie GeForce 400 o superiore per il supporto (è una funzione GL4 / DX11).
elFarto,

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.