Sie wird das Objekt zweimal an einem gewissen Punkt machen müssen. Sie können mit Rendering nur die Gesichter vor der Kamera einmal und die Gesichter mit Blick weg weg einmal von der Kamera, aber es hat seine Kompromisse.
Die einfachste gängige Lösung besteht darin, das Objekt in einem Durchgang zweimal zu rendern:
- Sie verwenden einen Vertex-Shader, um die Normalen des Objekts umzukehren und um die Größe des Umrisses zu "sprengen", und einen Fragment-Shader, um es in der Umrissfarbe zu rendern
- Über diesem Umriss rendern Sie das Objekt normal. Die Z-Reihenfolge ist in der Regel mehr oder weniger automatisch richtig, da der Umriss durch die Gesichter auf der "Rückseite" des Objekts erstellt wird, während die Figur selbst aus Gesichtern besteht, die der Kamera zugewandt sind.
Dies ist einfach genug zu erstellen und zu implementieren und vermeidet Tricks beim Rendern von Texturen, weist jedoch einige auffällige Nachteile auf:
- Die Umrissgröße variiert, wenn Sie sie nicht anhand des Abstands von der Kamera skalieren. Weiter entfernte Objekte haben einen kleineren Umriss als die in der Nähe befindlichen. Dies könnte natürlich das sein, was Sie tatsächlich wollen .
- Der Vertex-Shader "Aufblasen" funktioniert bei komplexen Objekten wie dem in Ihrem Beispiel gezeigten Skelett nicht besonders gut, da Z-Fighting-Artefakte problemlos in das Rendering eingefügt werden können. Wenn Sie das Problem beheben möchten, müssen Sie das Objekt in zwei Durchgängen rendern, können jedoch die Normalen nicht umkehren.
- Der Umriss und das Objekt funktionieren möglicherweise nicht sehr gut, wenn andere Objekte denselben Raum belegen und es im Allgemeinen schwierig ist, in Kombination mit Reflexions- und Brechungsshadern die richtigen Ergebnisse zu erzielen.
Die Grundidee für einen solchen Shader sieht wie folgt aus (Cg, for Unity - der Code ist ein leicht modifizierter Toon-Shader, den ich irgendwo gefunden habe und der die Quelle nicht notiert hat. zu verwendender Shader):
Shader "Basic Outline" {
Properties {
_Color ("Main Color", Color) = (.5,.5,.5,1)
_OutlineColor ("Outline Color", Color) = (1,0.5,0,1)
_Outline ("Outline width", Range (0.0, 0.1)) = .05
_MainTex ("Base (RGB)", 2D) = "white" { }
}
SubShader {
Tags { "RenderType"="Opaque" }
Pass {
Name "OUTLINE"
Tags { "LightMode" = "Always" }
CGPROGRAM
#pragma exclude_renderers gles
#pragma exclude_renderers xbox360
#pragma vertex vert
struct appdata {
float4 vertex;
float3 normal;
};
struct v2f
{
float4 pos : POSITION;
float4 color : COLOR;
float fog : FOGC;
};
float _Outline;
float4 _OutlineColor;
v2f vert(appdata v)
{
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
float3 norm = mul ((float3x3)UNITY_MATRIX_MV, v.normal);
norm.x *= UNITY_MATRIX_P[0][0];
norm.y *= UNITY_MATRIX_P[1][1];
o.pos.xy += norm.xy * _Outline;
o.fog = o.pos.z;
o.color = _OutlineColor;
return o;
}
ENDCG
Cull Front
ZWrite On
ColorMask RGB
Blend SrcAlpha OneMinusSrcAlpha
SetTexture [_MainTex] { combine primary }
}
Pass {
Name "BASE"
Tags {"LightMode" = "Always"}
CGPROGRAM
#pragma fragment frag
#pragma vertex vert
#pragma fragmentoption ARB_fog_exp2
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
struct v2f {
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
float3 viewDir : TEXCOORD1;
float3 normal : TEXCOORD2;
};
v2f vert (appdata_base v)
{
v2f o;
o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
o.normal = v.normal;
o.uv = TRANSFORM_UV(0);
o.viewDir = ObjSpaceViewDir( v.vertex );
return o;
}
uniform float4 _Color;
uniform sampler2D _MainTex;
float4 frag (v2f i) : COLOR
{
half4 texcol = tex2D( _MainTex, i.uv );
half3 ambient = texcol.rgb * (UNITY_LIGHTMODEL_AMBIENT.rgb);
return float4( ambient, texcol.a * _Color.a );
}
ENDCG
}
}
FallBack "Diffuse"
}
Die andere gebräuchliche Methode rendert das Objekt ebenfalls zweimal, vermeidet jedoch den Vertex-Shader vollständig. Auf der anderen Seite ist dies nicht einfach in einem Durchgang möglich und erfordert das Rendern in eine Textur: Rendern Sie das Objekt einmal mit einem "flachen", konturfarbenen Fragment-Shader und verwenden Sie eine (gewichtete) Unschärfe für dieses Rendern Platz auf dem Bildschirm , und rendern Sie das Objekt wie gewohnt darüber.
Es gibt auch eine dritte und möglicherweise am einfachsten zu implementierende Methode, die jedoch die GPU ein wenig belastet und Ihre Künstler dazu bringt, Sie im Schlaf zu ermorden, es sei denn, Sie erleichtern ihnen das Generieren: Lassen Sie die Objekte die Gliederung als separate haben Masche die ganze Zeit, nur vollständig transparent oder an einen Ort verschoben, an dem sie nicht zu sehen ist (wie tief im Untergrund), bis Sie sie brauchen
Neben Martin Sojkas Antwort können Sie für statische Objekte (oder Sprites) etwas Einfacheres finden.
Sie können dasselbe Sprite aber mit dem Umriss in Ihrem Texturatlas oder einer anderen Textur vollständig speichern, was das Umschalten vereinfacht. Auf diese Weise können Sie auch benutzerdefinierte Konturen erstellen, die optisch ansprechender sind oder einfach anders aussehen.
Die andere Methode besteht darin, das Sprite als eine einfarbige Form zu speichern, die etwas größer ist, und diese zu rendern, bevor das Sprite selbst gerendert wird. Dies gibt Ihnen die Möglichkeit, die Farbe der Auswahl einfach zu ändern, und Sie benötigen möglicherweise nicht so viele verschiedene Farbformen, wie Sie mit Methode 1 Gliederungs-Sprites benötigen würden.
Beides erhöht jedoch Ihren Speicherbedarf.
quelle
Wie in den Kommentaren zu Martin Sojkas Antwort ausgeführt, kann ein ähnlicher Effekt auch durch Verwendung der Schablone oder des Tiefenpuffers erzielt werden, wie von Max McGuire auf FlipCode ausgeführt:
http://www.flipcode.com/archives/Object_Outlining.shtml
Grundsätzlich wird eine Drahtmodellversion des gewünschten Modells mit vergrößerter Linienbreite gezeichnet (oder falls dies nicht möglich ist, wie beispielsweise in D3D, wenn Quads mit Kameraausrichtung für Linien verwendet werden), während der Schablonenpuffer auf einen konstanten Wert eingestellt wird.
Dieser Ansatz ist unter Verwendung der heutigen OpenGL-Technologie möglicherweise ein wenig veraltet. Damit der Objektumriss-Applear unscharf wird, ist das Rendern in die Textur weiterhin erforderlich.
quelle