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.
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.
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.
Antworten:
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
Ein paar Dinge, die mir auffallen:
Aufgrund dieser Beobachtungen werden meines Erachtens zwei Effekte verwendet:
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!
quelle