Seltsame weiße Kontur um das Modell

19

Ich arbeite an einem Spiel in XNA 4 und bin kürzlich auf eine verzögerte Shading-Implementierung umgestiegen, die diesem Handbuch folgt . Auf meinen Modellen ist jetzt ein seltsamer weißer Umriss zu sehen, und ich bin nicht sicher, was dies verursacht. Ich dachte, es sei ein Mangel an Präzision beim normalen Rendern oder beim Tiefenrendern, aber die Erhöhung auf 64 Bit (Rgba64) anstelle von 32 Bit (Farbe) hat nicht geholfen. Ich dachte auch, es könnte ein Problem mit der Spiegelberechnung sein, also habe ich versucht, das Spiegelbild auf 0 zu setzen, aber das hat auch nicht geholfen. Das Debuggen des Pixels in PIX zeigt, dass der diffuse Wert für dieses Pixel als nahezu weiß berechnet wird. Irgendwelche Ideen? Ich habe unten ein Bild des Problems eingefügt. Es ist einfacher, es in voller Größe zu sehen.

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 : Sorry für das JPG, der Uploader von stackexchange hat das alleine gemacht. Roy T: Ich habe tatsächlich auf Ihre XNA4-Konvertierung des Tutorials für die Teile verwiesen, die von XNA3 geändert wurden. Da ich keine großen Änderungen am Code vorgenommen habe, dachte ich, dass dieser Fehler im Original existiert, aber bei so vielen Lichtern, die sich alle bewegen, einfach nicht zu sehen war. Also entfernte ich alle außer einem Licht und der Fehler tauchte wieder auf (siehe unten) in der Nähe des Ellbogens der Eidechse)

Hier sind die GBuffer-Inhalte für meine Szene:

Farbpuffer: Tiefenpuffer: Normalpuffer: Endpuffer:

Edit2 :

Ich beginne zu vermuten, dass das Problem CombineFinal.fx ist, wenn es die Farbkarte abtastet. Dies ist die Berechnung für ein richtig gefärbtes Pixel direkt neben einem weißen Pixel:

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

Und dies ist die Ausgabe eines falsch gefärbten weißen Pixels direkt daneben:

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

Die diffuseColor ist der einzige Unterschied, und diese Farbe wird direkt aus der Farbkarte übernommen. Möglicherweise liegt ein kleiner Fehler bei der Berechnung der Texturkoordinate vor, aus der abgetastet werden soll.

Lichtpass:

Telanor
quelle
4
Bitte nicht jpeg komprimieren einen Screenshot mit einem subtilen Grafikfehler. Die Leute werden das Problem in perfekter Reproduktion sehen wollen.
aaaaaaaaaaa
Nun, die JPEG-Komprimierung lässt den Fehler tatsächlich ziemlich gut durch, denke ich, nur ein Pixel und nur dann, wenn bestimmte Dinge wieder vereint sind (großer Unterschied in der Z-Tiefe und die Beleuchtung ist bei allen Pixeln (ziemlich) hoch). Viel Glück, verzögertes Rendern ist ziemlich technisch.
Valmond,
2
Nicht sicher, ob es hilft, aber Sie verwenden eine sehr alte Version des Codes / Tutorials. Der aktuelle Code / Tutorial von Catalin Zima befindet sich jetzt unter: catalinzima.com/tutorials/deferred-rendering-in-xna und einem genehmigten XNA4.0 Die Version befindet sich hier: roy-t.nl/index.php/2010/12/28/…
Roy T.
Können Sie, wie immer beim Debuggen von verzögertem Rendern, Screenshots aus allen Puffern veröffentlichen? Es liegt wahrscheinlich im Lichtpuffer, aber es könnte auch etwas anderes sein.
Roy T.
Mein Instinkt ist, dass es ein Problem mit der Art und Weise gibt, wie ein Teil des Algorithmus mit einem Winkel von genau 90 Grad umgeht, aber ich muss nach der Arbeit mit der Ode spielen, um es weiter zu untersuchen.
Jordaan Mylonas

Antworten:

4

Ich hatte auch diesen weißen Umriss oder "Heiligenschein" um meine Modelle, als ich meinen eigenen verzögerten Renderer startete. Das Problem bestand darin, dass der Texturversatzwert zum Überlagern der Renderziele nicht korrekt eingerichtet wurde. Einige Texturen mussten für den Versatz auf +0,5 Pixel anstatt auf -0,5 Pixel eingestellt werden.

Erst nach dem Ändern der Werte einiger Textur-Offsets waren die Konturen verschwunden. Höchstwahrscheinlich ist es in einem der Lichtshader.

Bearbeiten: Übrigens habe ich auch aus Catalin Zimas Tutorial gelernt, das ein Zweig von Ihrem Beispiel ist, also sollte es funktionieren.

ChrisC
quelle
Ja, das war es. Ich habe es für alle Koordinatenabtastungen im Lichtshader auf + halfPixel geändert und der Lichthof ist jetzt verschwunden.
Telanor
0

Ich bin mir nicht sicher, was genau los ist, aber ich muss ein paar Dinge überprüfen:

  1. Stellen Sie sicher, dass die Texturfilterung deaktiviert ist, wenn Sie die G-Puffer abtasten - keine bilinearen oder anisotropen oder irgendetwas.

  2. Ich sehe, dass Sie den Texturkoordinaten einen halben Pixelversatz hinzufügen. Überprüfen Sie noch einmal, ob das stimmt. Ich bin nicht mit XNA vertraut genug, um zu wissen, wie der richtige Versatz sein sollte, aber Sie sollten in der Lage sein, dies zu überprüfen, indem Sie einen Shader schreiben, der einen der G-Puffer abtastet und nur das Beispiel ausgibt. Blättern Sie dann zwischen diesen hin und her und zeigen Sie den G-Buffer direkt auf dem Bildschirm an. Wenn Sie den richtigen Versatz haben, sollten Sie keine Unterschiede sehen, nicht einmal ein einziges Pixel.

Nathan Reed
quelle
Ich habe alles, was mit dem GBuffer zu tun hat, in POINT geändert (ich gehe davon aus, dass das Filtern deaktiviert ist?) Und es ist immer noch dasselbe. Wäre die Ausgabe des GBuffers in Bezug auf Ihren zweiten Punkt nicht genau gleich: Erstellen Sie einen Shader, der nur die Daten ausgibt? Können Sie das etwas näher erläutern?
Telanor
Nun, wie haben Sie die Screenshots des obigen G-Puffers erstellt? Ich nehme an, Sie rufen eine Art integrierte API-Funktion auf, um die Pixel eins zu eins vom G-Buffer auf den Bildschirm zu kopieren (Back Buffer). (Ich kenne XNA nicht, also weiß ich nicht, wie es heißen würde.) Ich sage, vergleiche die Ausgabe der eingebauten Eins-zu-Eins-Kopierfunktion mit der Ausgabe eines dafür geschriebenen Pixel-Shaders eine Eins-zu-Eins-Kopie ... auf diese Weise können Sie sicher sein, dass die Texturkoordinaten genau korrekt sind und Sie wirklich eine Eins-zu-Eins-Abtastung erhalten.
Nathan Reed