Estranho contorno branco em torno do modelo

19

Estou trabalhando em um jogo no XNA 4 e recentemente mudei para uma implementação de sombreamento adiado seguindo este guia . Um estranho contorno branco está aparecendo nos meus modelos agora e não tenho certeza do que está causando isso. Eu pensei que talvez fosse uma falta de precisão no alvo de renderização normal ou no alvo de renderização em profundidade, mas aumentá-los para 64 bits (Rgba64) em vez de 32 (Cor) não ajudou. Também pensei que poderia haver algum problema com o cálculo especular, então tentei definir o especular como 0, mas isso também não ajudou. A depuração do pixel no PIX mostra que o valor difuso está sendo calculado como quase branco para esse pixel. Alguma ideia? Incluí uma imagem do problema abaixo; é mais fácil vê-la em tamanho real.

Pixel Shader:

float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
    input.ScreenPosition.xy /= input.ScreenPosition.w;

    float2 texCoord = 0.5f * (float2(input.ScreenPosition.x, -input.ScreenPosition.y) + 1) - halfPixel;

    float4 normalData = tex2D(normalSampler, texCoord);

    //Transform normal back into [-1, 1] range
    float3 normal = normalize(2.0f * normalData.xyz - 1.0f);

    float specularPower = normalData.a;
    float specularHardness = tex2D(colorSampler, texCoord).a * 255;
    float depthVal = tex2D(depthSampler, texCoord).r;

    //Compute screen-space position
    float4 position = float4(input.ScreenPosition.xy, depthVal, 1.0f);

    //Transform to world space
    position = mul(position, InvertViewProjection);
    position /= position.w;

    //Surface-to-light vector
    float3 lightVector = lightPosition - position;

    float3 projectedTexCoords = position - lightPosition;
    projectedTexCoords = mul(projectedTexCoords, float3x3(
                            float3(-1, 0, 0),
                            float3(0, 1, 0),
                            float3(0, 0, 1)));

    float distanceToLight = length(lightVector) / lightRadius;
    float shadow = ShadowContribution(projectedTexCoords, distanceToLight);

    float attenuation = saturate(1.0f - distanceToLight);

    lightVector = normalize(lightVector);

    //Compute diffuse light
    float normalDotLight = max(0, dot(normal, lightVector));
    float3 diffuseLight = normalDotLight * Color.rgb;

    float3 reflectionVector = normalize(reflect(-lightVector, normal));
    float3 directionToCamera = normalize(cameraPosition - position);
    float specularLight = specularPower * pow(saturate(dot(reflectionVector, directionToCamera)), specularHardness);

    return shadow * attenuation * lightIntensity * float4(diffuseLight.rgb, specularLight);
}

Edit : Desculpe pelo JPG, o uploader da stackexchange fez isso por conta própria. Roy T: Na verdade, fiz referência à sua conversão de XNA4 do tutorial para as partes que mudaram de XNA3. Como não fiz grandes alterações no código, pensei que talvez esse bug existisse no original, mas era impossível ver com tantas luzes se movendo, então removi todas, exceto uma, e o bug apareceu novamente (veja perto do cotovelo do lagarto)

Aqui estão os conteúdos do GBuffer para a minha cena:

Buffer de cores: Buffer de profundidade : Buffer normal: Renderização final:

Edit2 :

Estou começando a suspeitar que o problema é CombineFinal.fx quando ele mostra o mapa de cores. Este é o cálculo para um pixel adequadamente colorido ao lado de um pixel branco:

diffuseColor        : (0.435, 0.447, 0.412)
diffuseLight        : (1.000, 1.000, 0.902)
light               : (1.000, 1.000, 0.902, 0.000)
PixelShaderFunction : (0.435, 0.447, 0.371, 1.000)
specularLight       : 0.000

E esta é a saída de um pixel branco incorretamente colorido diretamente ao lado:

diffuseColor        : (0.824, 0.792, 0.741)
diffuseLight        : (1.000, 1.000, 0.902)
light               : (1.000, 1.000, 0.902, 0.000)
PixelShaderFunction : (0.824, 0.792, 0.669, 1.000)
specularLight       : 0.000

O diffuseColor é a única diferença, e essa cor é obtida diretamente do mapa de cores. Talvez exista um pequeno erro no cálculo da coordenada de textura para a amostra?

Passe de iluminação:

Telanor
fonte
4
O JPEG não comprime uma captura de tela mostrando uma falha gráfica sutil. As pessoas vão querer ver o problema em perfeita reprodução.
Aaaaaaaaaaaa
Bem, a compressão jpeg realmente deixa a falha bem, eu acho, apenas um pixel e somente quando certas coisas são reunidas (grande diferença na profundidade de Z e a iluminação é (bastante) alta em todos os pixels). Boa sorte, a renderização adiada é bastante técnica.
Valmond
2
Não tenho certeza se isso ajuda, mas você está usando uma versão muito antiga do código / tutorial, o código / tutorial real do Catalin Zima agora está em: catalinzima.com/tutorials/deferred-rendering-in-xna e um XNA4.0 sancionado versão está localizado aqui: roy-t.nl/index.php/2010/12/28/...
Roy T.
Além disso, como sempre, com a depuração da renderização adiada, você pode publicar capturas de tela de todos os buffers? Provavelmente está no buffer de iluminação, mas poderia ser outra coisa.
Roy T.
Meu instinto é que será um problema com a maneira como parte do algoritmo lida com um ângulo de exatamente 90 graus, mas terei que brincar com o ode depois do trabalho para analisá-lo mais.
Jordaan Mylonas

Respostas:

4

Eu também tinha esse contorno branco ou "auréola" nos meus modelos quando comecei no meu próprio renderizador diferido. O problema era que o valor do deslocamento da textura para sobrepor os destinos de renderização não estava configurado corretamente. Algumas texturas precisavam ser definidas como +0,5 pixels para o deslocamento, em vez de -0,5 pixels.

Foi somente após ajustar os valores de algumas das compensações de textura que os contornos desapareceram. Provavelmente está em um dos shaders de iluminação.

Edit: a propósito, eu também aprendi com o tutorial de Catalin Zima, que é um ramo do seu exemplo, então deve funcionar.

ChrisC
fonte
Sim, foi isso. Eu mudei para + halfPixel para todas as amostras de coordenadas no sombreador de luz e o halo desapareceu agora.
Telanor 23/09/11
0

Não sei exatamente o que está acontecendo, mas algumas coisas para verificar:

  1. Verifique se a filtragem de textura está desativada ao amostrar os buffers G - não bilinear, anisotrópico ou qualquer coisa.

  2. Vejo que você está adicionando um deslocamento de meio pixel às coordenadas da textura; verifique novamente se está certo. Eu não estou familiarizado o suficiente com o XNA para saber qual deve ser o deslocamento certo, mas você deve poder verificá-lo escrevendo um sombreador que faz a amostragem de um dos buffers G e apenas gera a amostra. Depois, alterne entre isso e exiba o buffer G diretamente na tela. Se você tiver o deslocamento correto, não verá diferenças, nem mesmo um único pixel.

Nathan Reed
fonte
Eu mudei tudo relacionado ao GBuffer para POINT (presumo que desabilite a filtragem?) E ainda é o mesmo. Sobre o seu segundo ponto, a saída direta do GBuffer não seria exatamente a mesma: criar um sombreador que apenas produza os dados? Você pode falar um pouco mais sobre isso?
Telanor 19/09/11
Bem, como você gerou as capturas de tela do buffer G acima? Presumo que você chame algum tipo de função API integrada, para copiar os pixels um a um do buffer G para a tela (buffer traseiro)? (Não conheço o XNA, portanto não sei como seria chamado.) Estou dizendo, compare a saída da função de cópia individual um-para-a com a saída de um pixel shader gravado para fazer uma cópia individual ... dessa forma, você pode ter certeza de que as coordenadas da textura estão exatamente corretas e você realmente está obtendo uma amostra individual.
Nathan Reed