Dziwny biały kontur wokół modelu

19

Pracuję nad grą w XNA 4 i niedawno przeszedłem na implementację odroczonego cieniowania zgodnie z tym przewodnikiem . Na moich modelach pojawia się dziwny biały kontur i nie jestem pewien, co to powoduje. Pomyślałem, że może to brak precyzji w normalnym celu renderowania lub celu renderowania głębokości, ale zwiększenie ich do 64 bitów (Rgba64) zamiast 32 (Kolor) nie pomogło. Pomyślałem również, że może to być problem z obliczeniami zwierciadlanymi, więc spróbowałem ustawić zwierciadło na 0, ale to też nie pomogło. Debugowanie piksela w systemie PIX pokazuje, że wartość rozproszona jest obliczana jako prawie biała dla tego piksela. Jakieś pomysły? Poniżej zamieściłem zdjęcie problemu, łatwiej zobaczyć go w pełnym rozmiarze.

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

Edycja : Przepraszamy za plik JPG, program do przesyłania Stackexchange zrobił to sam. Roy T: Właściwie odniosłem się do twojej konwersji XNA4 samouczka dla części, które zmieniły się z XNA3. Ponieważ nie wprowadziłem żadnych dużych zmian w kodzie, pomyślałem, że może ten błąd istniał w oryginale, ale było po prostu niemożliwe do zobaczenia z tyloma światłami, które się poruszały, więc usunąłem wszystkie oprócz jednego światła i błąd pojawił się ponownie (patrz w pobliżu łokcia jaszczurki)

Oto zawartość GBuffer dla mojej sceny:

Bufor kolorów: Bufor głębi: Bufor normalny: Ostateczne renderowanie:

Edycja2 :

Zaczynam podejrzewać, że problemem jest CombineFinal.fx podczas próbkowania mapy kolorów. To jest obliczenie prawidłowo kolorowego piksela tuż obok białego piksela:

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

I to jest wynik z niewłaściwie zabarwionego białego piksela bezpośrednio obok niego:

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

DiffuseColor jest jedyną różnicą, a ten kolor jest pobierany bezpośrednio z mapy kolorów. Być może podczas obliczania współrzędnej tekstury, z której pobierana jest próbka, występuje niewielki błąd?

Karnet oświetleniowy:

Telanor
źródło
4
Proszę nie kompresuj jpeg zrzutu ekranu przedstawiającego subtelną usterkę graficzną. Ludzie będą chcieli zobaczyć problem w doskonałej reprodukcji.
aaaaaaaaaaaa
Cóż, kompresja jpeg pozwala na całkiem nieźle przepuszczanie usterki, myślę, tylko jeden piksel i tylko wtedy, gdy pewne rzeczy zostaną ponownie połączone (duża różnica w głębokości Z i oświetlenie jest (całkiem) wysokie na wszystkich pikselach). Powodzenia, odroczone renderowanie jest dość techniczne.
Valmond,
2
Nie jestem pewien, czy to pomaga, ale używasz bardzo starej wersji kodu / samouczka, rzeczywisty kod / samouczek Catalin Zima znajduje się teraz na stronie: catalinzima.com/tutorials/deferred-rendering-in-xna i usankcjonowany XNA4.0 wersja znajduje się tutaj: roy-t.nl/index.php/2010/12/28/…
Roy T.
Jak zawsze przy debugowaniu odroczonego renderowania, czy możesz publikować zrzuty ekranu ze wszystkich buforów? Prawdopodobnie jest w buforze oświetlenia, ale może to być coś innego.
Roy T.
Instynktownie myślę, że będzie to problem ze sposobem, w jaki część algorytmu obsługuje kąt dokładnie 90 stopni, ale będę musiał bawić się odą po pracy, aby przyjrzeć się jej dalej.
Jordaan Mylonas,

Odpowiedzi:

4

Miałem też ten biały kontur lub „aureolę” wokół moich modeli, kiedy zacząłem na własnym odroczonym rendererze. Problem polegał na tym, że wartość przesunięcia tekstury dla nakładania celów renderowania nie została poprawnie skonfigurowana. Niektóre tekstury musiały być ustawione na +0,5 pikseli dla przesunięcia zamiast -0,5 pikseli.

Dopiero po poprawieniu wartości niektórych przesunięć tekstur kontury zniknęły. Najprawdopodobniej jest w jednym z shaderów oświetlenia.

Edycja: przy okazji nauczyłem się również z samouczka Catalin Zima, który jest gałęzią twojego przykładu, więc powinien działać.

ChrisC
źródło
Tak, to było to. Zmieniłem to na + halfPixel dla całego próbkowania współrzędnych w cieniowaniu światła, a halo już nie ma.
Telanor,
0

Nie jestem pewien, co się właściwie dzieje, ale kilka rzeczy do sprawdzenia:

  1. Upewnij się, że masz wyłączone filtrowanie tekstur podczas próbkowania buforów G - bez dwuliniowych, anizotropowych ani nic.

  2. Widzę, że dodajesz przesunięcie o pół piksela do współrzędnych tekstury; dokładnie sprawdź, czy to prawda. Nie znam wystarczająco XNA, aby wiedzieć, jakie powinno być właściwe przesunięcie, ale powinieneś być w stanie to sprawdzić, pisząc moduł cieniujący, który próbkuje jeden z buforów G i po prostu wysyła próbkę. Następnie przewijaj w tę iz powrotem, wyświetlając bufor G bezpośrednio na ekranie. Jeśli masz prawidłowe przesunięcie, nie powinieneś widzieć żadnych różnic, nawet jednego piksela.

Nathan Reed
źródło
Poszedłem i zmieniłem wszystko związane z GBuffer na POINT (zakładam, że wyłącza filtrowanie?) I nadal jest tak samo. Jeśli chodzi o twój drugi punkt, czy wyjście GBuffera nie byłoby dokładnie takie samo: stworzyć moduł cieniujący, który po prostu wyprowadza dane? Czy możesz coś więcej rozwinąć?
Telanor,
Jak wygenerowałeś zrzuty ekranu z bufora G powyżej? Zakładam, że wywołujesz jakąś wbudowaną funkcję API, aby skopiować piksele jeden do jednego z bufora G na ekran (bufor tylny)? (Nie znam XNA, więc nie wiem, jak by to się nazywało). Mówię, porównaj wyjście wbudowanej funkcji kopiowania jeden do jednego z wyjściem shadera pikseli napisanego do zrobienia kopia jeden do jednego ... w ten sposób możesz mieć pewność, że współrzędne tekstury są dokładnie prawidłowe i naprawdę otrzymujesz próbkowanie jeden do jednego.
Nathan Reed,