Como posso armazenar valores positivos e negativos em uma textura?

Dec 03 2020

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

1 httpdigest Dec 03 2020 at 15:04

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_SNORMou 16 bits GL_RGBA16Fou 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.