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.