Finalisation avec le Shader Graphe du shader de transition de textures.
Lors de la première partie, nous avions posé les bases du shader permettant une transition de textures.
Nous allons désormais finir le shader tout en ajoutant un script C# dans Unity, nous permettant de gérer la transition au runtime.
Pré-requis: Bases de l'utilisation de Unity . Bases du Shader Graphe (Playlist dans le bas de la page en suivant le dernier lien). Bases du C# . Utilisation des Coroutines .
Depuis la première partie nous avions résumé notre effet de transition de texture en 3 étapes:
- Disposer de 2 textures et pouvoir en changer - step 1
- Utiliser un paramètre pour piloter le changement de Texture (0 à 100%) - step 2
- Ajouter du bruit pour rendre le changement moins abrupte - step 3
Les étapes (steps) 1 et 2, nous ont permis de s'assurer que le shader crée fonctionne correctement. Nous pouvons donc passer d'une texture à l'autre grâce au paramètre transitionCoeff, ou plus exactement grâce à la propriété du shader.
Mais le résultat visuel n'est pas encore très abouti, car il nous manque l'étape 3, celle de l'ajout de bruit !
En effet, avec la propriété transitionCoeff à 0.5f (cf capture ci-dessus), on a bien le mix des textures, mais l'effet désiré n'est pas atteint.
Ajouter un noeud Noise
Passez en édition le shader avec le Shader Graphe, et ajoutez un Simple Noise Node.
Puis connectez maintenant le noeud de la propriété transitionCoeff avec le noeud noise , à l'aide d'un autre noeud Add . Le tout sera connecté au slot T du noeud LERP ... là où avant il n'y avait que le noeud de la propriété. La capture ci-dessus indique le Shader Graphe après les ajouts et connections.
L'idée derrière tout cela, c'est que le coefficient de transition (pouvant aller de 0 à 1) soit mixé avec des valeurs de bruits, afin d'avoir une répartition non uniforme de la seconde texture lors de la transition.
Malheureusement certaines valeurs sont trop fortes et nous obtenons au final de la saturation de valeur (cf capture c-dessous)... coupant tout espoir d'y voir clair sur l'effet de l'ajout de notre noeud Noise.
Ajoutons alors un noeud Clamp après le noeud Add, permettant de limiter les valeurs finales entre 0 et 1, évitant ainsi la saturation.
Sauvez le shader et observez dans la scène, lorsque vous changez la valeur du transitionCoeff, que la transition de texture a bien lieu.
De plus vous avez sûrement remarqué que maintenant notre effet commence à bien prendre forme . En effet non seulement nous avons bien le mix des textures, mais en plus il ya des zones ou la seconde texture (vert) est complètement absente .. c'est là l'effet de notre noeud noise.
On progresse !
Pour autant on peut encore améliorer l'effet afin de donner plus d'intensité à la seconde texture lors de la transition.
Remaper les valeurs du bruit
En effet la seconde texture est trop transparente. Nous allons donc remaper les valeurs de sorties du noeud noise.
Ajoutez donc un noeud remap entre le noeud Simple Noise et le noeud Add.
Comme vous pouvez le voir sur la capture ci-dessous, en remapant les valeurs, on obtient un résultat plus tranché. Les textures ne sont plus vraiment mixées, mais plutôt en mode on/off. Le noise, lui, permet de répartir les zones de manière aléatoire et plus naturelle.
Le shader est désormais terminé, passons maintenant au script C# pour contrôler l'effet de transition au runtime.
Au final vous devriez avoir le Shader Graphe suivant.
Coder la transition de textures en C#
Le principe est très simple en réalité, car il suffit d'indiquer par script les nouvelles valeurs de propriétés de la texture, ou plus exactement de son shader. Et ici la seule propriété qui nous intéresse, c'est transitionCoeff.
Créez un script C# ...
Asset -> Clic droit - > Create C# script
Nommez le par exemple TransitionPrinciple, et donnez le à un GameObject de votre scène, comme le cube de la première partie . Ce cube possède en effet déjà le material (avec son shader associé) sur lequel nous travaillons.
Le plan d'attaque
Afin de pouvoir changer dynamiquement les valeurs des propriétés du shader, nous devons avoir une instance du composant Renderer du GameObject (ie notre cube). Il suffira alors d'utiliser la méthode MaterialPropertyBlock.SetFloat("popertyName",value):
mpb.SetFloat ("_transitionCoeff", transitionCoeff);
La valeur sera alors mise à jour au niveau du shader lorsque nous lui passerons le composant MaterialPropertyBlock, définissant les propriétés du Material (ie shader) à utiliser.
renderer.SetPropertyBlock (mpb);
Concernant l'évolution automatique de la valeur de la propriété transitionCoeff, nous allons utiliser ici une coroutine , permettant de passer progressivement d'une texture à l'autre selon le temps qui s'écoule.
IEnumerator launchTransition () {
startTime = Time.time;
effectOn = true;
Debug.Log ("Start coroutine ");
while (effectOn) {
//increment transitionCoeff
transitionCoeff += deltaInc;
//clamp final value
transitionCoeff = Mathf.Clamp (transitionCoeff, -10f, 10f);
//change the Material properties
renderer.GetPropertyBlock (mpb);
mpb.SetFloat ("_transitionCoeff", transitionCoeff);
renderer.SetPropertyBlock (mpb);
//need to stop effect ?
if ((Time.time - startTime) > effectDuration) {
effectOn = false;
}
yield return new WaitForSeconds (0.1f);
}
Debug.Log ("End coroutine ");
}
Le script nouvellement crée possèdera alors les variables de classe principales suivantes:
- effectDuration : temps de l'effet de transition en secondes
- effectOn: booléen permettant de savoir si l'effet est activé ou non
- deltaInc: le paramètre d'incrémentation
- transitionCoeff: le fameux paramètre permettant de changer la valeur de la propriété du shader
[Range (-10f, 10f)]
[SerializeField] float transitionCoeff;
[SerializeField] float effectDuration = 2f;
[SerializeField] bool effectOn;
[SerializeField] float deltaInc = 1f;
Ce seront les paramètres de ce script. Cela nous permettra d'affiner l'effet de transition sans devoir toucher directement les paramètres de la Texture.
Pour finir et afin de tester notre script, nous allons ajouter un input clavier, permettant de lancer la coroutine launchTransition
void Update () {
if (Input.GetKeyDown (KeyCode.Space)) {
Debug.Log ("space (increment): " + transitionCoeff);
//launch Effect
StartCoroutine (launchTransition (true));
}
}
Ainsi la boucle est bouclée : un input touche espace qui déclenche l'effet ... la coroutine se lance et incrémente progressivement la valeur de transitionCoeff. A chaque incrémentation le shader est mis à jour, assurant une transition au runtime.
Implémentation et test de l'effet de transition
Mettons tous les ingrédients ensemble !
Voici le script complet qui doit être placé sur chaque GameObject de votre scène à qui vous souhaitez donner cet effet de transition de textures.
public class TransitionPrinciple : MonoBehaviour {
[SerializeField] private Renderer renderer;
[SerializeField] private MaterialPropertyBlock mpb;
[Range (-10f, 10f)]
[SerializeField] float transitionCoeff;
[SerializeField] float effectDuration = 2f;
[SerializeField] bool effectOn;
[SerializeField] float deltaInc = 1f;
//public for debug
public float startTime;
void OnEnable () {
renderer = GetComponent<Renderer> ();
mpb = new MaterialPropertyBlock ();
}
void Update () {
if (Input.GetKeyDown (KeyCode.Space)) {
Debug.Log ("space (increment): " + transitionCoeff);
//launch Effect
StartCoroutine (launchTransition ());
}
}
IEnumerator launchTransition () {
startTime = Time.time;
effectOn = true;
Debug.Log ("Start coroutine ");
while (effectOn) {
//increment transitionCoeff
transitionCoeff += deltaInc;
//clamp final value
transitionCoeff = Mathf.Clamp (transitionCoeff, -10f, 10f);
//change the Material properties
renderer.GetPropertyBlock (mpb);
mpb.SetFloat ("_transitionCoeff", transitionCoeff);
renderer.SetPropertyBlock (mpb);
//need to stop effect ?
if ((Time.time - startTime) > effectDuration) {
effectOn = false;
}
yield return new WaitForSeconds (0.1f);
}
Debug.Log ("End coroutine ");
}
}
Notez bien que, dans le script, le nom de la propriété est "_transitionCoeff", or dans notre shader graphe, ce n'est pas son nom ... En effet pour le shader, la propriété se nomme "Vector1_4D4B30CC" !
Si on ne fait rien, le script tentera de mettre à jour une propriété qui n'existe pas au niveau de notre shader.
Changez donc pour le bon nom !
Il ne reste plus qu'a tester la scène pour pouvoir profiter, en appuyant sur la touche espace, de l'effet de transition de textures.
Si vous avez bien tout suivi, vous devriez observer la transition se faire ...
Pour finir vous pouvez retrouver la vidéo associée sur youtube
Nous voici arrivés au terme de ce tutoriel sur la création d'un shader, permettant un effet de transition progressive de textures.