Como posso armazenar valores positivos e negativos em uma textura?
Estou criando um programa onde estou usando a GPU para fazer cálculos (por meio de shaders de fragmento) e preciso armazenar valores assinados dentro de texturas.
Minha textura é inicializada com GL_FLOAT, assim:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_FLOAT, nullptr);
E pelo que eu entendo sobre opengl, texels individuais devem estar na faixa [0,1] quando GL_FLOAT é usado (quando eu experimentei com glClear, meus valores seriam cortados nesta faixa). Então, o que tenho feito até agora é reduzir meus valores para o intervalo [-1,1] com base no intervalo real e, em seguida, converter para [0,1] antes de escrever de volta na textura. O próximo sombreador que precisa trabalhar com os dados lê o valor texel e o move para [-1,1] antes de continuar e assim por diante ...
Minha pergunta é: essa é a maneira certa de lidar com valores negativos? Tenho certeza de que as conversões repetidas estão causando o acúmulo de erros de fp, o que obviamente não é bom para a precisão.
Obrigado
Respostas
Veja também: Diferença entre formato e formato interno
O formato interno (terceiro parâmetro de glTexImage2D
) decide como a GPU armazena e interpreta esses valores, não o parâmetro de tipo de glTexImage2D
(penúltimo parâmetro). Esse parâmetro decide como o driver deve interpretar sua memória do lado do cliente / host ao fazer upload para a textura, que você não usa atualmente nullptr
.
Você pode usar o formato interno com tamanho de ponto flutuante de 8 bits GL_RGBA8_SNORM
ou 16 bits GL_RGBA16F
ou de ponto flutuante de 32 bits para a textura.GL_RGBA32F
Geralmente, você deve sempre usar um formato interno dimensionado para ser explícito sobre o que deseja e obtém.
Veja a tabela sobre: https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glTexImage2D.xhtml
Portanto, se você só precisa de resolução de 8 bits e valores no intervalo [-1, 1], você pode usar:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8_SNORM, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
O penúltimo argumento é realmente irrelevante, porque não estamos carregando nenhum dado texel para a textura.