Depuis quelque temps maintenant, je me suis remis à des expérimentations personnelles sur Unity et, plus précisément, dans le domaine de la programmation graphique : mon but étant d'explorer des techniques auxquelles je ne pouvais pas me consacrer auparavant.
On commence avec un effet de flou utilisant le filtre Kawase.
Je voulais depuis un moment en faire une implémentation dans Unity, d’une part, pour tester mes capacités et, d’autre part, pour être bien certain d’en comprendre le fonctionnement.
C’est une chose de comprendre la théorie, mais la pratique en est une autre.
Le filtre Kawase a été présenté pour la première fois en 2003 lors de la Game Developers Conference par Masaki Kawase[1].
En règle générale, rendre flou une image en temps réel est très coûteux.
Traditionnellement, on utilise un flou dit « gaussien », c’est-à-dire qui utilise comme fonction de distribution une fonction gaussienne, de son auteur Carl Friedrich Gauss, caractérisée par une courbe en cloche[2].
Malgré le fait qu'il soit assez coûteux, notamment pour un flou très large, il a un avantage : il est séparable, c’est-à-dire qu’on peut l’exécuter en deux fois, dans une direction puis dans l’autre. Cela permet de réduire la charge de calcul pour un même résultat contrairement à s'il avait été exécuté en une seule fois.
Par exemple, avec un kernel non-séparable de 5x5 donc 25 échantillonnages de textures, on passe, en séparable, à 5+5 donc 10 échantillonnages de textures. Cependant, on peut encore mieux faire, et c’est là que le filtre Kawase entre en scène.
À l’aide de plusieurs filtre « box » - un filtre dont tous les coefficients sont identiques et dont la somme de ces coefficients est égale à 1 -, on peut reproduire un flou gaussien, avec quelques erreurs, pour un coût bien inférieur[3].
L’idée est de filtrer plusieurs fois l’image source, de préférence réduite, à l’aide du filtre box tout en s’éloignant du centre à chaque itération jusqu’à obtenir le résultat qui nous convient. Après 9 itérations, on obtient le résultat suivant :
À titre de comparaison, l'image ci-dessous a été obtenue avec un filtre gaussien séparable linéaire[4] 5+5 après 57 itérations. Pour un résultat similaire, l'opération est plus coûteuse :
D’un côté, le filtre Kawase coûte environ 1 milliseconde pour 21 draw calls tandis que de l’autre, le filtre gaussien coûte 3.5 millisecondes pour 233 draw calls.
On peut encore davantage réduire le coût en appliquant un Dual filter[5] pour un résultat quasi identique :
On passe alors de 21 à 19 draw calls et d'environ 1 milliseconde à environ 0.85 milliseconde.
Pour conclure, comme on peut le constater ci-dessous, malgré un résultat analogue, le coût, quant à lui, diffère drastiquement en fonction de la méthode :
Test mesuré en 1080p à 60 fps avec une RTX 2080 TI.