Introduction
HLSL est le langage de shaders de Microsoft utilisé dans Unity via le pipeline Built-in ou HDRP. À un niveau intermédiaire, il permet de créer des effets visuels personnalisés comme du lighting avancé ou des distorsions. Comprendre la séparation vertex/fragment et l'utilisation des sémantiques est essentiel pour des performances optimales sur GPU. Ce tutoriel vous guide pas à pas avec des exemples concrets et compilables directement dans Unity 2023+.
Prérequis
- Unity 2023.3 ou supérieur
- Connaissances de base en C# et shaders
- Visual Studio ou Rider pour l'édition
- Un projet 3D avec un modèle simple
Structure de base du shader
Shader "Custom/IntermediateLighting" {
Properties {
_MainTex ("Texture", 2D) = "white" {}
_Color ("Color", Color) = (1,1,1,1)
}
SubShader {
Tags { "RenderType"="Opaque" }
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; };
struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; };
sampler2D _MainTex; float4 _Color;
v2f vert (appdata v) {
v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = v.uv; return o;
}
fixed4 frag (v2f i) : SV_Target { return tex2D(_MainTex, i.uv) * _Color; }
ENDCG
}
}
}Ce shader de base définit les propriétés, le vertex shader et le fragment shader. Les sémantiques POSITION et SV_POSITION sont obligatoires pour le pipeline graphique.
Ajout de normales et éclairage simple
struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; float3 normal : NORMAL; };
struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; float3 normal : TEXCOORD1; };
v2f vert (appdata v) {
v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = v.uv;
o.normal = UnityObjectToWorldNormal(v.normal); return o;
}
fixed4 frag (v2f i) : SV_Target {
float3 lightDir = _WorldSpaceLightPos0.xyz;
float diff = max(0, dot(i.normal, lightDir));
fixed4 col = tex2D(_MainTex, i.uv) * _Color;
return col * diff;
}On ajoute les normales pour calculer un éclairage diffus basique. Cela illustre la transformation des normales de l'espace objet vers l'espace monde.
Shader avec texture et attenuation
fixed4 frag (v2f i) : SV_Target {
float3 lightDir = _WorldSpaceLightPos0.xyz;
float diff = max(0, dot(normalize(i.normal), normalize(lightDir)));
fixed4 tex = tex2D(_MainTex, i.uv);
float atten = 1.0 - length(_WorldSpaceLightPos0.xyz - i.vertex.xyz) * 0.1;
return tex * _Color * diff * atten;
}Ajout d'une attenuation linéaire basée sur la distance à la lumière. Évitez les calculs coûteux dans le fragment shader quand c'est possible.
Pass multiple pour outline
Pass { /* Premier pass lighting principal */ }
Pass {
Cull Front
CGPROGRAM
#pragma vertex vertOutline
#pragma fragment fragOutline
v2f vertOutline(appdata v) {
v2f o; float3 norm = normalize(v.normal);
v.vertex.xyz += norm * 0.02; o.vertex = UnityObjectToClipPos(v.vertex); return o;
}
fixed4 fragOutline(v2f i) : SV_Target { return fixed4(0,0,0,1); }
ENDCG
}Un second pass avec Cull Front permet de créer un outline simple en décalant les vertices le long des normales.
Inclusion d'un fichier .cginc custom
#ifndef LIGHTING_UTILS_INCLUDED
#define LIGHTING_UTILS_INCLUDED
float3 CalculateDiffuse(float3 normal, float3 lightDir) {
return max(0, dot(normalize(normal), normalize(lightDir)));
}
#endifCréer un fichier .cginc réutilisable permet de partager du code entre plusieurs shaders et d'améliorer la maintenabilité.
Bonnes pratiques
- Préférez les calculs dans le vertex shader quand possible pour économiser les ressources GPU
- Utilisez des sémantiques correctes (SV_Target, TEXCOORDn)
- Testez toujours sur plusieurs plateformes (DirectX, Vulkan)
- Évitez les branches dynamiques dans le fragment shader
- Profilez avec le Frame Debugger de Unity
Erreurs courantes
- Oublier de normaliser les vecteurs avant le dot product
- Mauvaise transformation des normales (utiliser UnityObjectToWorldNormal)
- Dépasser la limite de 8 interpolateurs TEXCOORD sans optimisation
- Ne pas gérer les variantes de shader pour les différentes qualités graphiques
Pour aller plus loin
Approfondissez vos compétences avec nos formations avancées sur les shaders.