Vous devrez rendre l'objet deux fois à un moment donné. Vous pouvez vous en tirer avec le rendu des visages face à la caméra une seule fois et des visages opposés à la caméra une fois, mais il a ses compromis.
La solution commune la plus simple consiste à rendre l'objet deux fois dans la même passe:
- Vous utilisez un vertex shader pour inverser les normales de l'objet et le "gonfler" par la taille du contour et un fragment shader pour le rendre dans la couleur du contour
- Sur ce rendu de contour, vous rendez l’objet normalement. L'ordre z est généralement automatiquement correct, plus ou moins, car le contour est fait par les visages qui sont à l'arrière de l'objet tandis que la figure elle-même est composée de visages face à la caméra.
C'est assez simple à construire et à implémenter et évite toutes les astuces de rendu à la texture, mais présente quelques inconvénients notables:
- La taille du contour, si vous ne la mettez pas à l'échelle par rapport à la caméra, variera. Les objets plus éloignés auront un contour plus petit que ceux à proximité. Bien sûr, c'est peut-être ce que vous voulez réellement .
- Le vertex shader "blow up" ne fonctionne pas très bien pour des objets complexes comme le squelette dans votre exemple, introduisant facilement des artefacts de combat z dans le rendu. Le corriger nécessite que vous rendiez l'objet en deux passes, mais vous évite d'inverser les normales.
- Le contour et l'objet peuvent ne pas fonctionner très bien lorsque d'autres objets occupent le même espace et sont généralement pénibles à bien combiner avec des shaders de réflexion et de réfraction.
L'idée de base pour un tel shader ressemble à ceci (Cg, pour Unity - le code est un shader toon légèrement modifié que j'ai trouvé quelque part et je n'ai pas noté la source, c'est donc une preuve de concept plus mal écrite qu'un ready- shader à utiliser):
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"
}
L'autre méthode courante rend également l'objet deux fois, mais évite complètement le vertex shader. D'un autre côté, cela ne peut pas être fait facilement en une seule passe, et nécessite un rendu en texture: rendez l'objet une fois avec un shader de fragment de contour "plat" et utilisez un flou (pondéré) sur ce rendu dans l'espace d'écran , puis restituer l'objet comme d'habitude au-dessus.
Il existe également une troisième méthode, et peut-être la plus simple à mettre en œuvre, bien qu'elle taxe un peu plus le GPU et donnera envie à vos artistes de vous assassiner dans votre sommeil, sauf si vous les facilitez à générer: Demandez aux objets d'avoir le contour comme un élément distinct maillage tout le temps, juste totalement transparent ou déplacé quelque part où il n'est pas vu (comme profondément sous terre) jusqu'à ce que vous en ayez besoin