Обновление текстуры памяти через шейдер?

8

О чем говорит заголовок. Можно ли обновить текстуру с помощью шейдера GLSL? Что-то вроде :

//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
источник

Ответы:

6

То, что вы хотите, это связать текстуру с шейдером, а затем визуализировать эту текстуру. Я мог бы плевать сквозь мили спецификации документации OpenGL, но я собираюсь дать ощущение, что моя интуиция дает мне:

Я не думаю, что это возможно.

То, что я знаю, возможно, однако, это то, что вы создаете объект буфера кадров (FBO) и визуализируете его. Сначала вы должны сгенерировать FBO и прикрепить к нему текстуру того же размера, который вы хотите обновить.

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

Если вы хотите обновить текстуру, вы должны выполнить следующие шаги.

Сначала вы прикрепляете FBO:

glBindFramebuffer(GL_FRAMEBUFFER, fbo_handle);

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

Теперь вы можете отобразить полноэкранный квад с помощью шейдера, который выводит обновленный цвет:

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;

И тогда вы должны скопировать полученный кадровый буфер в исходную текстуру.

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

Тем не менее, вы должны учитывать следующее:

  • Как часто вы обновляете эту текстуру?
  • Если вам не нужно обновлять его каждый кадр, стоит ли этот метод снижения скорости?
  • Можете ли вы создать несколько версий этой текстуры и циклически переключаться между ними?
  • Есть ли другой способ добиться того же эффекта?
knight666
источник
Вау, большое спасибо за помощь! И чтобы ответить на ваши вопросы: 1. У меня есть специальная текстура для моего героя, которую я должен обновлять каждый раз, когда происходит столкновение (с точками крови и другими вещами). 2. Из-за характера игры вас постоянно бьют или трогают вещи, полные грязи (грязи), поэтому мне приходится очень часто обновлять эту текстуру ... 3. Вот как я делаю это прямо сейчас, и я не доволен это (мне нужно динамическое исправление текстуры) 4. Не знаю: o
user1010005
4
Ага! Хорошо, это помогает в уточнении моего ответа. То, что вы, вероятно, ищете, это мультитекстурирование. У вас есть текстура для вашего игрового персонажа, и у вас есть текстура, которая показывает грязь, кровь и еще много чего. В шейдере вы можете комбинировать их, чтобы создать нужный эффект. Это намного дешевле, чем непрерывный рендеринг в объект буфера кадров и копирование результата в текстуру.
knight666
Спасибо еще раз. Я не совсем уверен, что вы имеете в виду под многоструктурированием, но я постараюсь найти на stackexchange :))
user1010005
4

Если ваше оборудование поддерживает это, расширение GL_ARB_shader_image_load_store позволяет вам писать в текстуру.

elFarto
источник
1
Я могу сказать вам прямо сейчас, что мой NVIDIA GeForce GTS 250 поддерживает OpenGL 3.3.0, но не поддерживает GL_EXT_shader_image_load_store. Это означает, что ваш ответ, вероятно, правильный, но пока не практичный в данной области. Отстой. :(
knight666
1
Да, похоже, вам нужна серия GeForce 400 или выше для поддержки (это функция GL4 / DX11).
elFarto