Konstante Randschattierung in Bildschirmbreite


7

In letzter Zeit habe ich ein paar Shader (in Unity) studiert und versuche, die "lichtbasierte Inline" nachzubilden, die in der neuesten Legende von Zelda zu beobachten ist. Aber vielleicht liegt die Aufgabe vorerst etwas über meinem Wissen.

Kommentiertes Referenzbild

Nach allem, was ich analysieren kann, scheint es sich (beim Bewegen) ähnlich zu verhalten wie eine "Randschattierung", außer dass es einen scharfen Cutoff hat (einfach zu machen), und - der Teil, mit dem ich zu kämpfen habe - es scheint eine konstante Breite haben, die unabhängig von der lokalen Krümmung des Netzes und dem Abstand von der Kamera ist und im wesentlichen eine konstante "Breite" in Bezug auf den Bildschirm aufweist. (Nun, es variiert tatsächlich ein wenig mit der Kameradistanz, aber meistens nicht, nehmen wir an, dass dies nicht der Fall ist.)

Es ist ein bisschen schwierig, in einem Standbild zu zeigen, aber Sie können viele Videos im Spiel finden, und der Effekt ist überall sichtbar.

Ich habe es geschafft, den einfacheren Teil zu machen, die abgeschnittene Randschattierung. Dies führt jedoch zu dem unangenehmen Effekt, dass die "Inline" je nach Ausrichtung der Kamera und der Geometriekrümmung mehr oder weniger Bildschirmfläche einnimmt. Unten sehen Sie ein Bild der aktuellen Ergebnisse, die ich mit verschiedenen Kamerawinkeln erhalte. Grüne Pfeile zeigen gute / akzeptable Bereiche und rote Pfeile zeigen Abweichungen vom beabsichtigten Effekt an.

Aktuelle Ausgabe mit kommentierten Gut / Schlecht

Dies ist meine aktuelle Implementierung als Referenz für ein Unity-Oberflächenlichtmodell:

half4 LightingToonPoster(SurfaceOutputStandard surf, float3 viewDir, UnityGI gi) {
    // Material properties
    half3 specular;
    half oneMinusReflectivity;
    DiffuseAndSpecularFromMetallic(surf.Albedo, surf.Metallic, /*out*/ specular, /*out*/ oneMinusReflectivity);
    float3 reflected = normalize(-reflect(gi.light.dir, surf.Normal));
    float specularity = dot(viewDir, reflected) * _Specularity;

    // Light setup
    float ndotl = dot(surf.Normal, gi.light.dir) * 0.5 + 0.5;
    float lightIncidence = gi.light.color * ndotl;
    float3 ramp = tex2D(_Ramp, lightIncidence.xx).rgb;
    float3 specularRamp = tex2D(_Ramp, specularity.xx).rgb;
    gi.light.color = ramp * _LightColor0.rgb;

    // Rim and camera-light convergence
    float rim = 1 - saturate(dot(surf.Normal, viewDir));
    float facing = -dot(viewDir, gi.light.dir) * 0.5 + 0.25;

    // sigmoid of rim for smooth falloff centered at _EdgeBias
    float outline = 1 / (1 + exp(-100 * (rim - _EdgeBias)));
    float highlight = _HighlightStrength * outline * facing * outline;

    float4 std = LightingStandard(surf, viewDir, gi);

    float3 toonDiffuse = surf.Albedo * (gi.light.color / 2 + ShadeSH9(float4(viewDir, 1)));
    float3 toonSpecular = specular * gi.indirect.specular * specularRamp;
    float4 toon = half4(toonDiffuse + toonSpecular, surf.Alpha);
    return lerp(std, toon, _UnshadeFactor) * half4(1 + highlight.xxx, 1);
}

Oder überprüfen Sie diese Liste auf die vollständige Shader-Datei

Die Frage ist nun, was ich anstelle der Randschattierung verwenden kann, um einen ähnlichen Effekt zu erzielen, bei dem die Krümmung nicht berücksichtigt wird und ich einen konstanten "Einschub" erhalte.


Ehrlich gesagt, ich mag den Look, den Sie besser erreicht haben!
user1118321

@ user1118321 Ich wäre auch zufrieden, wenn nicht die Tatsache, dass es jedes kleinere Problem mit den Modellen, auf die es angewendet wird, perfekt abbildet.
Kroltan

Antworten:


3

Gute Frage! Ich hatte das Spiel selbst nicht gesehen, aber diese Frage hat mich interessiert und ich habe mir einige Aufnahmen auf Youtube angesehen.

Dieser gibt zum Beispiel einen guten Überblick: https://youtu.be/Ktjdg3zgRzk?t=15m46s Geben Sie hier die Bildbeschreibung ein

Ein paar Dinge, die mir auffallen:

  • Haar und rechtes Bein: Beachten Sie, dass nur der diffus beleuchtete Teil eine Randbeleuchtung hat.
  • Linkes Handgelenk: Beachten Sie, wie die Breite im Winkel mit der Hand dünner wird.
  • Auf einer anderen Seite können Sie auch sehen, dass die Randbeleuchtung auch durch Schattenwurf beeinflusst wird.

Aufgrund dieser Beobachtungen werden meines Erachtens zwei Effekte verwendet:

  1. Eine diffuse Schattierung mit einem scharfen Übergang zwischen beleuchtetem und nicht beleuchtetem Licht, die irgendwo unter 0 auftritt, sodass das Licht ein wenig nachlässt.
  2. Die Randbeleuchtung, die, wie Sie bereits erwähnt haben, eine nahezu konstante Bildschirmbreite hat.

    Nach dem Aussehen und einigen Artefakten schätze ich, dass es sich tatsächlich um einen Kantenerkennungsfilter handelt, der auf der Tiefe basiert und dann in Kombination mit der diffusen Beleuchtung verwendet wird, damit die Randbeleuchtung die unbeleuchteten Teile nicht beeinträchtigt.

Es ist ein ziemlich cooler Effekt, danke, dass du darauf hingewiesen hast!


Ich dachte an die Kantenerkennung, aber wenn ich den gleichen Effekt im Gelände (mit ziemlich großen Dreiecken) beobachte, ist es möglich, den gleichen Übergang zwischen einem "breiten" Rand und der konstanten Breite zu sehen, wenn sich die Kamera zu einem schmaleren dreht Winkel. Welche Art der Kantenerkennung könnte hier verwendet werden? Ich habe tatsächlich versucht, Sobel für die Tiefe zu verwenden, aber dann habe ich keine Ahnung, wie ich die "Breite" anpassen kann, ohne interne Linien zu verwischen. (Obwohl ich mir vorstelle, dass dies eine separate Frage sein sollte)
Kroltan

Sie unterscheiden wahrscheinlich Charaktere und Gelände (ich dachte, der Effekt fehlt im Gelände, aber vielleicht habe ich ihn einfach verpasst). Skalieren Sie für Sobel einfach den Kernel auf die gewünschte Dicke: Anstatt die angrenzenden Pixel zu vergleichen, vergleichen Sie die Pixel etwas weiter.
Julien Guertault

Hmm, ich werde Sobel noch einmal
abtupfen
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.