Estou com problemas para processar um monte de valores para um rendertarget. Os valores nunca acabam no intervalo exato que eu quero. Basicamente, eu uso um quad de tela cheia e um sombreador de pixel para renderizar a textura do meu alvo de rendert e, em seguida, pretendo usar as coordenadas da textura como base para alguns cálculos no sombreador. As coordenadas de textura do quad variam de (0,0) no canto superior esquerdo a (1,1) no canto inferior direito ... o problema é que, após a interpolação, esses valores não chegam ao sombreador de pixels. .
Um exemplo: renderizo para uma textura 4x4 e o sombreador, neste caso, simplesmente gera as coordenadas da textura (u, v) nos canais vermelho e verde:
return float4(texCoord.rg, 0, 1);
O que eu quero tirar disso é uma textura em que o pixel no canto superior esquerdo é RGB (0,0,0) e, portanto, preto, o pixel no canto superior direito é RGB (255,0,0) e, portanto, um brilho vermelho e o pixel no canto inferior esquerdo é RGB (0,255,0) - um verde brilhante.
No entanto, em vez disso, recebo isso aqui à direita:
(renderização em linha reta, sem correção)
O pixel superior esquerdo é preto, mas só recebo um vermelho relativamente escuro e um verde escuro nos outros cantos. Seus valores RGB são (191,0,0) e (0,191,0). Eu suspeito fortemente que isso tenha a ver com os locais de amostragem do quad: o pixel superior esquerdo mostra corretamente o canto superior esquerdo do quad e recebe (0,0) como coordenadas UV, mas os outros pixels do canto não amostram de os outros cantos do quad. Ilustrei isso na imagem à esquerda com a caixa azul representando o quadrilátero e os pontos brancos nas coordenadas de amostragem superiores.
Agora eu sei sobre o deslocamento de meio pixel que você deve aplicar às suas coordenadas ao renderizar quads alinhados à tela no Direct3D9. Vamos ver que tipo de resultado eu recebo disso:
(quad renderizado com deslocamento de meio pixel do DX9)
Vermelho e verde ficaram mais brilhantes, mas ainda não estão corretos: 223 é o máximo que recebo no canal de cores vermelho ou verde. Mas agora, eu nem tenho mais preto puro, mas um cinza amarelado escuro com RGB (32,32,0)!
O que eu realmente preciso seria esse tipo de renderização:
(renderização alvo, tamanho reduzido do quad)
Parece que eu tenho que mover a borda direita e inferior do meu quad exatamente um pixel para cima e para a esquerda, em comparação com a primeira figura. Em seguida, a coluna direita e a linha inferior de pixels devem obter corretamente as coordenadas UV diretamente da borda do quad:
VertexPositionTexture[] quad = new VertexPositionTexture[]
{
new VertexPositionTexture(new Vector3(-1.0f, 1.0f, 1f), new Vector2(0,0)),
new VertexPositionTexture(new Vector3(1.0f - pixelSize.X, 1.0f, 1f), new Vector2(1,0)),
new VertexPositionTexture(new Vector3(-1.0f, -1.0f + pixelSize.Y, 1f), new Vector2(0,1)),
new VertexPositionTexture(new Vector3(1.0f - pixelSize.X, -1.0f + pixelSize.Y, 1f), new Vector2(1,1)),
};
No entanto, isso não deu certo e fez com que os pixels inferior e direito não fossem renderizados. Suponho que os centros desses pixels não sejam mais cobertos pelo quad e, portanto, não serão processados pelo shader. Se eu mudar o cálculo do pixelSize em uma quantidade minúscula para aumentar o tamanho do quad, ele meio que funciona ... pelo menos em uma textura 4x4. Ele não funciona em texturas menores e eu temo que distorça sutilmente a distribuição uniforme de valores uv em texturas maiores também:
Vector2 pixelSize = new Vector2((2f / textureWidth) - 0.001f, (2f / textureHeight) - 0.001f);
(Modifiquei o cálculo pixelSize em 0,001f - para texturas menores, por exemplo, tabelas de pesquisa 1D, isso não funciona e preciso aumentá-lo para 0,01f ou algo maior)
É claro que este é um exemplo trivial e eu poderia fazer esse cálculo com muito mais facilidade na CPU sem ter que me preocupar em mapear UVs para centros de pixels ... ainda assim, é preciso haver uma maneira de renderizar um completo e completo [0, 1] alcance de pixels em um rendertarget !?