{"id":645,"date":"2019-01-29T21:33:32","date_gmt":"2019-01-29T20:33:32","guid":{"rendered":"http:\/\/oneiricworlds.com\/fr\/?p=645"},"modified":"2019-01-29T22:18:35","modified_gmt":"2019-01-29T21:18:35","slug":"shader-semi-procedural-decume","status":"publish","type":"post","link":"https:\/\/oneiricworlds.com\/fr\/2019\/01\/shader-semi-procedural-decume\/","title":{"rendered":"Shader d&rsquo;\u00e9cume semi-proc\u00e9dural"},"content":{"rendered":"<p>Bonjour \u00e0 tous,<\/p>\n<p>Comme d&rsquo;hab, \u00e7a fait un moment que je n&rsquo;ai pas post\u00e9 de tutoriel technique, donc en voici enfin un! Aujourd&rsquo;hui, on s&rsquo;int\u00e9resse \u00e0 la cr\u00e9ation de l&rsquo;\u00e9cume sur les rivages. Je d\u00e9taillerai ici mon approche et les diff\u00e9rents choix que j&rsquo;ai faits pour cr\u00e9er \u00e7a:<\/p>\n<p><a href=\"http:\/\/oneiricworlds.com\/en\/wp-content\/uploads\/2019\/01\/20190114_finalMixing.gif\" rel=\"attachment wp-att-642\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-642\" src=\"http:\/\/oneiricworlds.com\/en\/wp-content\/uploads\/2019\/01\/20190114_finalMixing.gif\" alt=\"20190114_finalMixing\" width=\"596\" height=\"373\" \/><\/a><\/p>\n<p style=\"text-align: center;\"><em>Le rendu final de l&rsquo;\u00e9cume dans le jeu.<\/em><\/p>\n<p>J&rsquo;utilise Unity comme moteur de jeu, Blender pour la mod\u00e9lisation et le texturing, et Krita pour peindre les textures.<\/p>\n<h3>I &#8211; Probl\u00e8me<\/h3>\n<p>Mon jeu se d\u00e9roule dans un monde recouvert d&rsquo;oc\u00e9an; avoir de l&rsquo;\u00e9cume sur les rivages para\u00eet donc assez indispensable. Mon plus gros soucis est que mon jeu est encore en cours de modification et je peux rajouter ou modifier des \u00eeles assez r\u00e9guli\u00e8rement. Donc, il me faut trouver une m\u00e9thode simple et efficace, pour ne pas avoir \u00e0 tout refaire \u00e0 partir de z\u00e9ro \u00e0 chaque it\u00e9ration.<\/p>\n<p>&nbsp;<\/p>\n<p>Il y a quelques temps, des amis m&rsquo;ont conseill\u00e9 la <a href=\"https:\/\/www.youtube.com\/watch?v=fwKQyDZ4ark\" target=\"_blank\">vid\u00e9o d&rsquo;explication des effets graphiques de Rime<\/a>, de Simon Tr\u00fcmpler. Il y a des techniques excellentes dans cette pr\u00e9sentation. L&rsquo;\u00e9cume en particulier et tr\u00e8s bien con\u00e7ue et le rendu est vraiment impressionnant (pour qui cherche un visuel stylis\u00e9 \u00e9videment).<\/p>\n<p>Le seul probl\u00e8me que je vois dans cette m\u00e9thode est le temps n\u00e9cessaire pour cr\u00e9er les uv maps \u00ab\u00a0seamless\u00a0\u00bb (=r\u00e9p\u00e9tables=sans bords=cycliques) pour les maillages d&rsquo;\u00e9cume. En effet, dans Blender, si l&rsquo;on veut un maillage circulaire avec un texturing sans \u00ab\u00a0cassure\u00a0\u00bb, il faut parfaitement aligner les bords de l&rsquo;uv-map. C&rsquo;est tout \u00e0 fait acceptable pour un seul ou quelques objets, mais j&rsquo;ai \u00e9norm\u00e9ment d&rsquo;\u00eeles et de rochers dans mon jeu, trop pour pouvoir utiliser cette m\u00e9thode. En plus de \u00e7a, avec un uv mapping cyclique, il est difficile d&rsquo;ajuster l&rsquo;\u00e9chelle des textures apr\u00e8s coup, car on est limit\u00e9 \u00e0 des multiples entiers. Je dois donc trouver une autre approche.<\/p>\n<p><a href=\"http:\/\/oneiricworlds.com\/en\/wp-content\/uploads\/2019\/01\/20190113_scalingUV.gif\" rel=\"attachment wp-att-591\"><img decoding=\"async\" class=\"size-large wp-image-591 aligncenter\" src=\"http:\/\/oneiricworlds.com\/en\/wp-content\/uploads\/2019\/01\/20190113_scalingUV.gif\" alt=\"20190113_scalingUV\" width=\"800\" \/><\/a><\/p>\n<p style=\"text-align: center;\"><em>Processus de mise \u00e0 l&rsquo;\u00e9chelle de l&rsquo;uv map pour supprimer la cassure du texturing. R\u00e9ussir un alignement parfait peut \u00eatre un peu long si l&rsquo;on a beaucoup d&rsquo;objets \u00e0 traiter..<\/em><\/p>\n<h3>II &#8211; Objectif<\/h3>\n<p>Id\u00e9alement, mon objectif est:<\/p>\n<ul>\n<li>d&rsquo;avoir une m\u00e9thode facile de cr\u00e9ation d&rsquo;\u00e9cume dans Blender, avec aussi peu de clics que possible. Dans le meilleur des cas, j&rsquo;aimerais n&rsquo;avoir \u00e0 me pr\u00e9occuper que de la mod\u00e9lisation et pas de l&rsquo;uv mapping.<\/li>\n<li>d&rsquo;avoir des vagues qui bougent sans un motif r\u00e9p\u00e9t\u00e9 de mani\u00e8re trop \u00e9vidente<\/li>\n<li>d&rsquo;avoir plusieurs param\u00e8tres pour modifier facilement la longueur d&rsquo;onde des vagues, leur vitesse ou leur apparence<\/li>\n<li>Graphiquement, comme j&rsquo;utilise du deferred shading qui est souvent un peu complexe \u00e0 combiner avec de la transparence, je veux une couleur pure pour l&rsquo;\u00e9cume avec des bords nets. J&rsquo;utiliserai donc du clipping en fonction de la valeur de mes textures. Voici ce que j&rsquo;aimerai avoir:<\/li>\n<\/ul>\n<p><a href=\"http:\/\/oneiricworlds.com\/en\/wp-content\/uploads\/2019\/01\/20190113_foamGoal2.jpg\" rel=\"attachment wp-att-606\"><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-606 aligncenter\" src=\"http:\/\/oneiricworlds.com\/en\/wp-content\/uploads\/2019\/01\/20190113_foamGoal2.jpg\" alt=\"20190113_foamGoal2\" width=\"512\" height=\"512\" \/><\/a><\/p>\n<h3>III &#8211; Texture de base et coordonn\u00e9es dans le rep\u00e8re monde<\/h3>\n<p>Comme d&rsquo;habitude, mon approche est loin d&rsquo;\u00eatre parfaite et consiste en un compromis entre ce qui me tient \u00e0 c\u0153ur et ce qui est techniquement atteignable.<\/p>\n<p>Ma 1\u00e8re id\u00e9e est d&rsquo;utiliser des coordonn\u00e9es de texturing automatiques, comme la position des sommets dans le rep\u00e8re monde. \u00c7a marche d\u00e9j\u00e0 plut\u00f4t bien pour mon rendu de terrain (j&rsquo;esp\u00e8re que je trouverai le temps d&rsquo;en parler plus longuement un de ces jours), mais les coordonn\u00e9es \u00ab\u00a0monde\u00a0\u00bb ne portent aucune information sur une direction privil\u00e9gi\u00e9e. Cela signifie que je ne peux pas utiliser une texture d&rsquo;\u00e9cume \u00ab\u00a0classique\u00a0\u00bb avec des lignes qui suivent le rivage (comme ci-dessous). L&rsquo;effet pourrait effectivement marcher sur un c\u00f4t\u00e9 de l&rsquo;\u00eele mais pas de tous les c\u00f4t\u00e9s en m\u00eame temps.<\/p>\n<div style=\"text-align: center;\"><a href=\"http:\/\/oneiricworlds.com\/en\/wp-content\/uploads\/2019\/01\/uvFoam.jpg\" rel=\"attachment wp-att-596\"><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-596\" src=\"http:\/\/oneiricworlds.com\/en\/wp-content\/uploads\/2019\/01\/uvFoam.jpg\" alt=\"uvFoam\" width=\"256\" height=\"256\" \/><\/a> <a href=\"http:\/\/oneiricworlds.com\/en\/wp-content\/uploads\/2019\/01\/20190113_foamWorldCoordsUnity.jpg\" rel=\"attachment wp-att-598\"><img loading=\"lazy\" decoding=\"async\" class=\"size-large wp-image-598\" src=\"http:\/\/oneiricworlds.com\/en\/wp-content\/uploads\/2019\/01\/20190113_foamWorldCoordsUnity.jpg\" alt=\"20190113_foamWorldCoordsUnity\" width=\"540\" height=\"403\" \/><\/a><\/div>\n<p style=\"text-align: center;\"><em>Dans cette texture, il y a une direction principale forte (horizontale). L&rsquo;image du rendu dans le jeu n&rsquo;est pas tr\u00e8s convaincante.<\/em><\/p>\n<p>Si j&rsquo;utilise du mapping automatique, il faut une texture relativement neutre\/uniforme en terme de directions, par exemple:<\/p>\n<div style=\"text-align: center;\"><a href=\"http:\/\/oneiricworlds.com\/en\/wp-content\/uploads\/2019\/01\/uvFoamWorld.jpg\" rel=\"attachment wp-att-597\"><img loading=\"lazy\" decoding=\"async\" class=\"size-large wp-image-597\" src=\"http:\/\/oneiricworlds.com\/en\/wp-content\/uploads\/2019\/01\/uvFoamWorld.jpg\" alt=\"uvFoamWorld\" width=\"256\" height=\"256\" \/><\/a> <a href=\"http:\/\/oneiricworlds.com\/en\/wp-content\/uploads\/2019\/01\/20190113_foamWorldCoordsUnityBetter.jpg\" rel=\"attachment wp-att-599\"><img loading=\"lazy\" decoding=\"async\" class=\"size-large wp-image-599\" src=\"http:\/\/oneiricworlds.com\/en\/wp-content\/uploads\/2019\/01\/20190113_foamWorldCoordsUnityBetter.jpg\" alt=\"20190113_foamWorldCoordsUnityBetter\" width=\"540\" height=\"403\" \/><\/a><\/div>\n<p style=\"text-align: center;\"><em>Une texture d&rsquo;\u00e9cume relativement simple sans direction privil\u00e9gi\u00e9e. Le rendu dans le jeu est un peu mieux&#8230;&#8230;<\/em><\/p>\n<p>OK, c&rsquo;est mieux, mais encore un peu d\u00e9cevant. C&rsquo;est le prix \u00e0 payer avec une approche automatique; il va donc falloir ajouter autre chose.<\/p>\n<h3>IV &#8211; Vagues proc\u00e9durales sur la coordonn\u00e9e v<\/h3>\n<p>Si je veux des vagues le long du rivage, ou de l&rsquo;\u00e9cume qui se rapproche (ou s&rsquo;\u00e9loigne) du rivage, il est n\u00e9cessaire d&rsquo;avoir une information suppl\u00e9mentaire sur la \u00ab\u00a0direction\u00a0\u00bb principale, et cette information doit \u00eatre contenue dans le maillage (le mesh). J&rsquo;en ai \u00e9galement besoin pour faire dispara\u00eetre les vagues au fur et \u00e0 mesure qu&rsquo;elle s&rsquo;\u00e9loignent. Cette direction change pour chaque triangle affich\u00e9, il faut donc la stocker au niveau des sommets.<\/p>\n<p>On dirait que je n&rsquo;ai pas le choix, je vais quand m\u00eame devoir faire un uv mapping basique pour stocker cette \u00ab\u00a0direction\u00a0\u00bb du rivage. Mais je n&rsquo;ai besoin que d&rsquo;une seule coordonn\u00e9e de texture; et je choisis arbitrairement <strong>v<\/strong> (voir image ci-dessous). L&rsquo;id\u00e9e est d&rsquo;avoir <strong>v<\/strong>=0 sur la ligne d&rsquo;ar\u00eate ext\u00e9rieure (du c\u00f4t\u00e9 de l&rsquo;oc\u00e9an), <strong>v<\/strong>=1 sur la ligne centrale (du c\u00f4t\u00e9 du rivage) et <strong>v<\/strong>=2 \u00e0 l&rsquo;int\u00e9rieur de l&rsquo;\u00eele.<\/p>\n<p><a href=\"http:\/\/oneiricworlds.com\/en\/wp-content\/uploads\/2019\/01\/20190113_foamVMapping2.jpg\" rel=\"attachment wp-att-608\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-large wp-image-608\" src=\"http:\/\/oneiricworlds.com\/en\/wp-content\/uploads\/2019\/01\/20190113_foamVMapping2-1024x428.jpg\" alt=\"20190113_foamVMapping2\" width=\"840\" height=\"351\" \/><\/a><\/p>\n<p style=\"text-align: center;\"><em>Le mapping que j&rsquo;ai choisi: ici, je ne me pr\u00e9occupe pas du probl\u00e8me de \u00ab\u00a0cout\u00fbre\u00a0\u00bb (en bas du mesh). Seul le mapping sur <strong>v<\/strong> m&rsquo;importe.<\/em><\/p>\n<p>Gr\u00e2ce \u00e0 cette coordonn\u00e9e, je vais pouvoir construire le mouvement des vagues. L&rsquo;approche la plus simple pour cr\u00e9er ces vagues et d&rsquo;utilise un <strong>sinus<\/strong> de <strong>v<\/strong>. Pour le faire bouger, j&rsquo;y ajoute un offset d\u00e9pendant du <strong>temps<\/strong> et de la <strong>vitesse<\/strong> des vagues.<\/p>\n<div style=\"text-align: center;\"><a href=\"http:\/\/oneiricworlds.com\/en\/wp-content\/uploads\/2019\/01\/20190116_sinus.jpg\" rel=\"attachment wp-att-671\"><img loading=\"lazy\" decoding=\"async\" class=\"size-medium wp-image-671\" src=\"http:\/\/oneiricworlds.com\/en\/wp-content\/uploads\/2019\/01\/20190116_sinus-300x300.jpg\" alt=\"20190116_sinus\" width=\"300\" height=\"300\" \/><\/a> <a href=\"http:\/\/oneiricworlds.com\/en\/wp-content\/uploads\/2019\/01\/20190113_movingSinus.gif\" rel=\"attachment wp-att-615\"><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-615\" src=\"http:\/\/oneiricworlds.com\/en\/wp-content\/uploads\/2019\/01\/20190113_movingSinus.gif\" alt=\"20190113_movingSinus\" width=\"488\" height=\"356\" \/><\/a><\/div>\n<p style=\"text-align: center;\"><em><strong>sinus(fr\u00e9quence*v + vitesse*temps)<\/strong> ; <strong>clipp\u00e9<\/strong> \u00e0 0<\/em><\/p>\n<p>Gardons \u00e0 l&rsquo;esprit que pour avoir des contours nets, je \u00ab\u00a0clippe\u00a0\u00bb (cache) chaque \u00ab\u00a0fragment\u00a0\u00bb (pixel) en dessous d&rsquo;un certain seuil.<\/p>\n<p><a href=\"http:\/\/oneiricworlds.com\/en\/wp-content\/uploads\/2019\/01\/20190114_movingSinusLoweredThresholdChange.gif\" rel=\"attachment wp-att-619\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-619\" src=\"http:\/\/oneiricworlds.com\/en\/wp-content\/uploads\/2019\/01\/20190114_movingSinusLoweredThresholdChange.gif\" alt=\"20190114_movingSinusLoweredThresholdChange\" width=\"596\" height=\"373\" \/><\/a><\/p>\n<p style=\"text-align: center;\"><em>Changer le seuil de <strong>clipping<\/strong> g\u00e9n\u00e8re des vagues plus ou moins grosses<\/em><\/p>\n<p><a href=\"http:\/\/oneiricworlds.com\/en\/wp-content\/uploads\/2019\/01\/20190114_sinusGlobalFrequencyChangePrinciple.gif\" rel=\"attachment wp-att-630\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-630\" src=\"http:\/\/oneiricworlds.com\/en\/wp-content\/uploads\/2019\/01\/20190114_sinusGlobalFrequencyChangePrinciple.gif\" alt=\"20190114_sinusGlobalFrequencyChangePrinciple\" width=\"596\" height=\"373\" \/><\/a><\/p>\n<p style=\"text-align: center;\"><em>Changer la\u00a0<strong>fr\u00e9quence<\/strong> g\u00e9n\u00e8re plus ou moins de vagues<\/em><\/p>\n<p>Si je veux que l&rsquo;\u00e9cume disparaisse progressivement dans la mer, il me suffit d&rsquo;ajouter la coordonn\u00e9e v au sinus, comme ceci:<\/p>\n<div style=\"text-align: center;\"><a href=\"http:\/\/oneiricworlds.com\/en\/wp-content\/uploads\/2019\/01\/20190116_sinusPlusV.jpg\" rel=\"attachment wp-att-665\"><img loading=\"lazy\" decoding=\"async\" class=\"size-medium wp-image-665\" src=\"http:\/\/oneiricworlds.com\/en\/wp-content\/uploads\/2019\/01\/20190116_sinusPlusV-300x300.jpg\" alt=\"20190116_sinusPlusV\" width=\"300\" height=\"300\" \/><\/a> <a href=\"http:\/\/oneiricworlds.com\/en\/wp-content\/uploads\/2019\/01\/20190113_movingSinusLowered.gif\" rel=\"attachment wp-att-616\"><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-616\" src=\"http:\/\/oneiricworlds.com\/en\/wp-content\/uploads\/2019\/01\/20190113_movingSinusLowered.gif\" alt=\"20190113_movingSinusLowered\" width=\"488\" height=\"356\" \/><\/a><\/div>\n<p style=\"text-align: center;\"><em><strong>sinus(fr\u00e9quence*v + vitesse*temps)+v<\/strong> ; <strong>clipp\u00e9<\/strong> au bon seuil <strong>s<\/strong>. Les vagues deviennent de plus en plus fines au fur et \u00e0 mesure qu&rsquo;elles avancent dans la mer<\/em><\/p>\n<p>Maintenant, on peut s&rsquo;amuser \u00e0 rajouter du bruit sur ce shader de base, pour le rendre un peu plus \u00ab\u00a0naturel\u00a0\u00bb. Comme base de bruit, j&rsquo;utilise une simple texture r\u00e9p\u00e9table faite dans GIMP gr\u00e2ce au filtre \u00ab\u00a0solid noise\u00a0\u00bb:<\/p>\n<p><a href=\"http:\/\/oneiricworlds.com\/en\/wp-content\/uploads\/2019\/01\/tileable2DWave.png\" rel=\"attachment wp-att-715\"><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-715 aligncenter\" src=\"http:\/\/oneiricworlds.com\/en\/wp-content\/uploads\/2019\/01\/tileable2DWave.png\" alt=\"tileable2DWave\" width=\"256\" height=\"256\" \/><\/a><\/p>\n<p style=\"text-align: center;\"><em>Bruit r\u00e9p\u00e9table fait avec GIMP.<\/em><\/p>\n<p>A partir de \u00e7a, on peut alt\u00e9rer la <strong>vitesse<\/strong>,\u00a0la <strong>fr\u00e9quence<\/strong>\u00a0ou tout autre param\u00e8tre du sinus. Bruiter la fr\u00e9quence est particuli\u00e8rement int\u00e9ressant puisque \u00e7a permet de rajouter localement plus ou moins de vagues, comme ceci:<\/p>\n<p><a href=\"http:\/\/oneiricworlds.com\/en\/wp-content\/uploads\/2019\/01\/20190113_movingSinusLoweredFrequencyChange.gif\" rel=\"attachment wp-att-617\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-617\" src=\"http:\/\/oneiricworlds.com\/en\/wp-content\/uploads\/2019\/01\/20190113_movingSinusLoweredFrequencyChange.gif\" alt=\"20190113_movingSinusLoweredFrequencyChange\" width=\"588\" height=\"356\" \/><\/a><\/p>\n<p style=\"text-align: center;\"><em>Ajoutons un bruit (en coordonn\u00e9es monde) \u00e0 la fr\u00e9quence: <strong>sinus((fr\u00e9quence+bruit(xz))*v + vitesse*temps)+v;<\/strong>\u00a0o\u00f9\u00a0<strong>xz<\/strong> sont les coordonn\u00e9es monde horizontales. Certaines zones se retrouvent ainsi avec plus de vagues que d&rsquo;autres.<\/em><\/p>\n<p>Ces vagues proc\u00e9durales ont l&rsquo;air d&rsquo;\u00eatre une bonne base, mais je trouve qu&rsquo;il manque quelques \u00ab\u00a0connections\u00a0\u00bb entre les diff\u00e9rentes lignes, et, si je veux les rajouter, je dois exploiter les coordonn\u00e9es \u00ab\u00a0monde\u00a0\u00bb. Je pourrai aussi utiliser un bruit pour les g\u00e9n\u00e9rer, mais j&rsquo;ai envie d&rsquo;essayer une approche un peu plus \u00ab\u00a0contr\u00f4l\u00e9e\u00a0\u00bb en y superposant une texture d&rsquo;\u00e9cume peinte \u00e0 la main.<\/p>\n<p><a href=\"http:\/\/oneiricworlds.com\/en\/wp-content\/uploads\/2019\/01\/20190114_movingSinusLoweredPlusBaseTex.gif\" rel=\"attachment wp-att-620\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-620\" src=\"http:\/\/oneiricworlds.com\/en\/wp-content\/uploads\/2019\/01\/20190114_movingSinusLoweredPlusBaseTex.gif\" alt=\"20190114_movingSinusLoweredPlusBaseTex\" width=\"596\" height=\"373\" \/><\/a><\/p>\n<p style=\"text-align: center;\"><em>M\u00e9lange des vagues proc\u00e9durales (\u00e0 base de sinus) et de texture peinte \u00e0 la main.<\/em><\/p>\n<p>Mais si j&rsquo;utilise une texture binaire, je n&rsquo;ai aucun contr\u00f4le sur son att\u00e9nuation progressive. Je vais donc utiliser des textures de \u00ab\u00a0transformation en distance\u00a0\u00bb (\u00ab\u00a0distance transform\u00a0\u00bb en anglais).<\/p>\n<h3>V &#8211; Texture \u00ab\u00a0Distance transform\u00a0\u00bb<\/h3>\n<p>Une image de transform\u00e9e en distance est habituellement cr\u00e9\u00e9e \u00e0 partir d&rsquo;un motif noir et blanc. Chaque pixel de l&rsquo;image \u00ab\u00a0distance transform\u00a0\u00bb repr\u00e9sente la distance \u00e0 un pixel blanc dans le motif original, comme ceci:<\/p>\n<p><a href=\"http:\/\/oneiricworlds.com\/en\/wp-content\/uploads\/2019\/01\/20190114_distanceTransformExplained.jpg\" rel=\"attachment wp-att-625\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-large wp-image-625\" src=\"http:\/\/oneiricworlds.com\/en\/wp-content\/uploads\/2019\/01\/20190114_distanceTransformExplained-1024x608.jpg\" alt=\"20190114_distanceTransformExplained\" width=\"840\" height=\"499\" \/><\/a><\/p>\n<p style=\"text-align: center;\"><em>Bon, en fait, j&rsquo;utilise une transform\u00e9e en distance invers\u00e9e ici, car c&rsquo;est plus pratique pour l&rsquo;\u00e9tape de clipping, mais vous saisissez l&rsquo;id\u00e9e. Et oui, j&rsquo;ai utilis\u00e9 un motif diff\u00e9rent de celui du d\u00e9but de cet article.<\/em><\/p>\n<p>Les images de transform\u00e9e en distance sont juste une mani\u00e8re de voir les donn\u00e9es. On peut aussi les interpr\u00e9ter comme des \u00ab\u00a0cartes de hauteur\u00a0\u00bb (m\u00eame si la signification est un peu diff\u00e9rente, mais \u00e7a aide \u00e0 saisir le concept). L&rsquo;id\u00e9e de base est d&rsquo;avoir une image qui incorpore une forme d&rsquo; \u00ab\u00a0\u00e9volution\u00a0\u00bb \/ \u00ab\u00a0animation\u00a0\u00bb du motif initial.<\/p>\n<p>Les images de transform\u00e9e en distance sont g\u00e9n\u00e9ralement cr\u00e9\u00e9e au travers de filtres, mais g\u00e9n\u00e9ralement ces filtres ne g\u00e8rent pas tr\u00e8s bien (voire pas du tout) les images r\u00e9p\u00e9tables. Une approche pour cr\u00e9er ce genre d&rsquo;images consiste \u00e0 les peindre directement. Bien s\u00fbr elles sont rarement exactes math\u00e9matiquement dans ce cas l\u00e0, mais en contrepartie, on peut cr\u00e9er des animations plus vari\u00e9es\/originales. Une m\u00e9thode que j&rsquo;ai fini par adopter dans Krita (le logiciel de peinture num\u00e9rique que j&rsquo;utilise) est la suivante:<\/p>\n<ul>\n<li>Utiliser le mode de peinture \u00ab\u00a0Build-up\u00a0\u00bb (par opposition \u00e0 \u00ab\u00a0Wash\u00a0\u00bb par d\u00e9faut), pour que chaque coup de brosse puisse s&rsquo;intersecter lui m\u00eame correctement<\/li>\n<li>Utiliser le mode de fusion de brosse \u00ab\u00a0Greater\u00a0\u00bb, pour peindre uniquement les valeurs plus grandes que celles d\u00e9j\u00e0 existantes (c&rsquo;est d&rsquo;ailleurs la vraie mani\u00e8re de fusionner 2 images de transform\u00e9e en distance)<\/li>\n<li>Utiliser une brosse aux bords flous avec une pente lin\u00e9aire de 100% \u00e0 0%, pour exploiter la plus grande plage de valeurs possibles. Cela permet d&rsquo;avoir les animations les plus lisses possibles. En fait, le profil de la brosse agit directement comme les param\u00e8tres \u00ab\u00a0ease in\u00a0\u00bb et \u00ab\u00a0ease out\u00a0\u00bb d&rsquo;une animation..<\/li>\n<li>Pas de sensibilit\u00e9 \u00e0 la pression (mais c&rsquo;est plut\u00f4t un choix personnel)<\/li>\n<li>Activer l&rsquo;option \u00ab\u00a0Wrap Around\u00a0\u00bb qui permet de cr\u00e9er des textures r\u00e9p\u00e9tables (je peins beaucoup de textures dans Krita, et c&rsquo;est clairement mon option favorite).<\/li>\n<\/ul>\n<p>Voil\u00e0 ce que \u00e7a donne en cours d&rsquo;utilisation:<\/p>\n<p><a href=\"http:\/\/oneiricworlds.com\/en\/wp-content\/uploads\/2019\/01\/20190114_drawingDistanceTransform.gif\" rel=\"attachment wp-att-633\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-633\" src=\"http:\/\/oneiricworlds.com\/en\/wp-content\/uploads\/2019\/01\/20190114_drawingDistanceTransform.gif\" alt=\"20190114_drawingDistanceTransform\" width=\"596\" height=\"373\" \/><\/a><\/p>\n<p style=\"text-align: center;\"><em>Peinture directe d&rsquo;une image de transform\u00e9e en distance. Le motif en croix au niveau de l&rsquo;intersection est typique d&rsquo;une image transform\u00e9e en distance.<\/em><\/p>\n<p>&nbsp;<\/p>\n<p>Bien s\u00fbr, ceci est une mani\u00e8re assez \u00ab\u00a0math\u00e9matique\u00a0\u00bb d&rsquo;aborder la chose. On peut \u00e9videmment utiliser une brosse douce par d\u00e9faut et obtenir quelque chose de tout \u00e0 fait correct (et s\u00fbrement plus naturel), mais il faut toujours garder \u00e0 l&rsquo;esprit que l&rsquo;on \u00ab\u00a0peint l&rsquo;animation\u00a0\u00bb (je ne pensais pas qu&rsquo;on pouvait dire \u00e7a&#8230;)<\/p>\n<h3>VI &#8211; M\u00e9lange des textures et r\u00e9glages<\/h3>\n<p>Maintenant, j&rsquo;ai un peu plus de contr\u00f4le sur ma texture faite \u00e0 la main:<\/p>\n<p><a href=\"http:\/\/oneiricworlds.com\/en\/wp-content\/uploads\/2019\/01\/20190114_movingFoamThreshold2.gif\" rel=\"attachment wp-att-624\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-624\" src=\"http:\/\/oneiricworlds.com\/en\/wp-content\/uploads\/2019\/01\/20190114_movingFoamThreshold2.gif\" alt=\"20190114_movingFoamThreshold2\" width=\"596\" height=\"373\" \/><\/a><\/p>\n<p style=\"text-align: center;\"><em><strong>tex(xz)<\/strong>; <strong>clipp\u00e9<\/strong> \u00e0 un certain seuil <strong>s<\/strong>; Maintenant, je peux choisir la largeur des vagues en changeant le seuil de clipping.<\/em><\/p>\n<p>De plus, j&rsquo;ai utilis\u00e9 quelques trucs pour rendre le visuel un peu plus int\u00e9ressant:<\/p>\n<ul>\n<li>Ajouter la coordonn\u00e9e <strong>v<\/strong> (pour avoir une \u00e9cume plus large pr\u00e8s de la c\u00f4te et plus fine c\u00f4t\u00e9 oc\u00e9an), comme pour le sinus<\/li>\n<li>Un param\u00e8tre de vitesse <strong>vitesseTexture<\/strong> pour faire bouger la texture doucement<\/li>\n<li>Un peu de <strong>bruit<\/strong> anim\u00e9 en coordonn\u00e9es monde pour cr\u00e9er un effet de d\u00e9formation<\/li>\n<\/ul>\n<p><a href=\"http:\/\/oneiricworlds.com\/en\/wp-content\/uploads\/2019\/01\/20190114_finalHandMadeFoam.gif\" rel=\"attachment wp-att-647\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-647\" src=\"http:\/\/oneiricworlds.com\/en\/wp-content\/uploads\/2019\/01\/20190114_finalHandMadeFoam.gif\" alt=\"20190114_finalHandMadeFoam\" width=\"596\" height=\"373\" \/><\/a><\/p>\n<p style=\"text-align: center;\"><strong><em>tex(xz + bruit(xz+vitesseBruit*temps)+vitesseTexture*temps)+v<\/em><\/strong><em>;<\/em><strong><em> clipp\u00e9 <\/em><\/strong><em>\u00e0<\/em><strong><em> s<\/em><\/strong><\/p>\n<p>Et finalement, je peux m\u00e9langer la texture proc\u00e9durale et la texture peinte. Apr\u00e8s pas mal de r\u00e9glages et de test, on aboutit \u00e0 \u00e7a:<\/p>\n<p><a href=\"http:\/\/oneiricworlds.com\/en\/wp-content\/uploads\/2019\/01\/20190114_finalMixing.gif\" rel=\"attachment wp-att-642\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-642\" src=\"http:\/\/oneiricworlds.com\/en\/wp-content\/uploads\/2019\/01\/20190114_finalMixing.gif\" alt=\"20190114_finalMixing\" width=\"596\" height=\"373\" \/><\/a><\/p>\n<p style=\"text-align: center;\"><em>Le r\u00e9sultat final m\u00e9langeant texture peinte et texture proc\u00e9durale:<br \/>\n<strong>ratioSinus * [sinus((fr\u00e9quence+bruit(xz))*v + vitesse*temps)+v] +<br \/>\nratioTex * [tex(xz + bruit(xz+vitesseBruit*temps)+vitesseTexture*temps)+v];<br \/>\nclipp\u00e9 <\/strong>\u00e0<strong> s<\/strong>.<\/em><\/p>\n<p>Enfin, j&rsquo;ai \u00e9galement ajout\u00e9 quelques param\u00e8tres pour contr\u00f4ler l&rsquo;amplitude et la fr\u00e9quence des bruits. Donc chaque <strong>bruit(xz&#8230;)<\/strong> est en r\u00e9alit\u00e9 <strong>amplitudeBruit*bruit(fr\u00e9quenceBruit*xz&#8230;)<\/strong>. Cela permet un meilleur r\u00e9glage des d\u00e9formations. J&rsquo;ai aussi remplac\u00e9 le simple \u00ab\u00a0<strong>+v<\/strong>\u00a0\u00bb par la fonction affine \u00ab\u00a0<strong>+a*v+b<\/strong>\u00a0\u00bb plus g\u00e9n\u00e9rique.<\/p>\n<h3>VII &#8211; Cr\u00e9ation dans Blender<\/h3>\n<p>Au final, je dois toujours faire un uv mapping (enfin plut\u00f4t un v mapping). Mais la bonne nouvelle, c&rsquo;est que je ne dois le faire qu&rsquo;<strong>UNE SEULE FOIS<\/strong> pour <strong>tout le jeu<\/strong>. En effet, pour chaque nouvelle \u00eele (ou objet immerg\u00e9), il me suffit de copier le mod\u00e8le de base qui a d\u00e9j\u00e0 un uv mapping correct, et je n&rsquo;ai qu&rsquo;\u00e0 modifier le maillage:<\/p>\n<ul>\n<li>Si je bouge des sommets, le mapping sera toujours correct.<\/li>\n<li>Si je supprime une ligne d&rsquo;ar\u00eates, le mapping des voisins n&rsquo;est pas affect\u00e9.<\/li>\n<li>Si je rajoute une ligne d&rsquo;ar\u00eates, l&rsquo;uv mapping de ces nouveaux sommets sera automatiquement interpol\u00e9 depuis les voisins, ce qui donnera une coordonn\u00e9e v correcte.<\/li>\n<\/ul>\n<p>\u00c7a n&rsquo;aurait pas \u00e9t\u00e9 le cas si j&rsquo;avais aussi utilis\u00e9 la coordonn\u00e9e u via un uv mapping plus classique, car le fait de bouger les sommets aurait \u00e9tir\u00e9 la texture associ\u00e9e (et j&rsquo;aurais eu le probl\u00e8me des \u00ab\u00a0coutures\u00a0\u00bb sur chaque nouvelle \u00eele).<\/p>\n<h3>VIII &#8211; Pour aller plus loin&#8230;<\/h3>\n<p>On pourrait travailler quelques pistes pour am\u00e9liorer tout \u00e7a:<\/p>\n<ul>\n<li>Empiler 2 couches (ou +) de textures faites \u00e0 la main, avec diff\u00e9rentes vitesses et fr\u00e9quence pour cr\u00e9er un motif global encore plus unique partout<\/li>\n<li>Bruiter la vitesse du sinus pour avoir des variations locales de flux<\/li>\n<li>Bruiter le seuil ou la fonction affine (<strong>\u00ab\u00a0+v\u00a0\u00bb<\/strong>\/<strong>\u00ab\u00a0+a*v+b\u00a0\u00bb<\/strong>) pour qu&rsquo;il y ait de l&rsquo;\u00e9cume sur une zone plus ou moins avanc\u00e9e dans la mer<\/li>\n<li>Bruiter les coordonn\u00e9es monde pour encore plus de d\u00e9formations<\/li>\n<li>Utiliser un sinus sur l&rsquo;offset de temps pour faire en sorte que les vagues aillent et viennent dans les 2 sens (\u00e0 l&rsquo;heure actuelle, elles vont juste vers l&rsquo;oc\u00e9an)<\/li>\n<\/ul>\n<p>Au passage, je n&rsquo;ai pas du tout parl\u00e9 d&rsquo;optimisation ici, il y aurait surement un gros travail \u00e0 faire (notamment sur les textures de bruit qui pourraient exploiter moins de canaux que le classique RGB).<\/p>\n<p>En tout cas, cette exp\u00e9rience aura \u00e9t\u00e9 tr\u00e8s int\u00e9ressante pour moi, et m\u00eame si le r\u00e9sultat n&rsquo;est pas exceptionnel, j&rsquo;ai vraiment appr\u00e9ci\u00e9 de m\u00e9langer une approche math\u00e9matique avec des consid\u00e9rations plus artistiques.<\/p>\n<p>Merci d&rsquo;avoir lu!<\/p>\n<p>Paix!<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Bonjour \u00e0 tous, Comme d&rsquo;hab, \u00e7a fait un moment que je n&rsquo;ai pas post\u00e9 de tutoriel technique, donc en voici enfin un! Aujourd&rsquo;hui, on s&rsquo;int\u00e9resse \u00e0 la cr\u00e9ation de l&rsquo;\u00e9cume sur les rivages. Je d\u00e9taillerai ici mon approche et les diff\u00e9rents choix que j&rsquo;ai faits pour cr\u00e9er \u00e7a: Le rendu final de l&rsquo;\u00e9cume dans le [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":699,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[7,10],"tags":[],"class_list":["post-645","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dev","category-tutorial"],"_links":{"self":[{"href":"https:\/\/oneiricworlds.com\/fr\/wp-json\/wp\/v2\/posts\/645","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/oneiricworlds.com\/fr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/oneiricworlds.com\/fr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/oneiricworlds.com\/fr\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/oneiricworlds.com\/fr\/wp-json\/wp\/v2\/comments?post=645"}],"version-history":[{"count":38,"href":"https:\/\/oneiricworlds.com\/fr\/wp-json\/wp\/v2\/posts\/645\/revisions"}],"predecessor-version":[{"id":700,"href":"https:\/\/oneiricworlds.com\/fr\/wp-json\/wp\/v2\/posts\/645\/revisions\/700"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/oneiricworlds.com\/fr\/wp-json\/wp\/v2\/media\/699"}],"wp:attachment":[{"href":"https:\/\/oneiricworlds.com\/fr\/wp-json\/wp\/v2\/media?parent=645"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/oneiricworlds.com\/fr\/wp-json\/wp\/v2\/categories?post=645"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/oneiricworlds.com\/fr\/wp-json\/wp\/v2\/tags?post=645"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}