[RESOLU]Crayonner pour révéler un dessin

Questions à propos du scripting. Hors Shader, GUI, Audio et Mobile.
Avatar de l’utilisateur
Alesk
Messages : 2303
Inscription : 13 Mars 2012 09:09
Localisation : Bordeaux - France
Contact :

Re: Crayonner pour révéler un dessin

Message par Alesk » 23 Déc 2019 01:52

Tes scripts n'ont rien à voir avec ce que j'ai expliqué...

EmileF
Messages : 673
Inscription : 18 Mars 2017 19:39

Re: Crayonner pour révéler un dessin

Message par EmileF » 23 Déc 2019 10:05

Si, enfin je crois

"Brush" est l'objet que je déplace sur la feuille "World" pour tracer mes traits

Quand je clique sur ma feuille, le brush se déplace à l'endroit du clic et il suit le curseur tant que je garde le bouton pressé.
C'est ce qui me permet de tracer mes traits, enfin mes taches.

En fait, Brush est la sphere dans le gif du tuto.
La différence entre l'intelligence et la stupidité est que l'intelligence est limitée.

Avatar de l’utilisateur
Alesk
Messages : 2303
Inscription : 13 Mars 2012 09:09
Localisation : Bordeaux - France
Contact :

Re: Crayonner pour révéler un dessin

Message par Alesk » 23 Déc 2019 10:49

Oui mais tu n'as pas du tout répercuté ça dans les fonctions qui servent à dessiner dans la texture, donc si tu bouges trop vite ta souris, tu auras des trainées de points et pas des lignes.

Il faut tenir compte du fait qu'entre deux update, ta souris peut avoir parcourue plus de distance que le diamètre de ta brush, c'est pour ça qu'il faut faire une boucle qui va forcer un tracé entre la dernière position connue et la nouvelle.

EmileF
Messages : 673
Inscription : 18 Mars 2017 19:39

Re: Crayonner pour révéler un dessin

Message par EmileF » 23 Déc 2019 21:00

Alesk a écrit :c'est pour ça qu'il faut faire une boucle qui va forcer un tracé entre la dernière position connue et la nouvelle.
J'ai essayé de mettre en place tes conseils mais je n'arrive encore pas à avoir un trait continu.
Je crois que je ne sais pas mettre en application la boucle dont tu parles.

Voilà la modification de mon script

Code : Tout sélectionner

    Vector3 pos;
    Vector3 Expos;
    public float speed =0.0001f;
    public float mini = 0.0001f;
    bool move;
    private void Update()
    {
        if (!move && Input.GetMouseButton(0))
        {
	    //J'ai modifié mon extension pour ne faire qu'un appel
            if (Camera.RaycastPos(World, out pos))
            {
                move = true;
            }
        }
        if (move)
        {
            Brush.position = Vector3.Lerp(pos, Expos, speed * Time.deltaTime);
            if (Vector3.SqrMagnitude(Brush.position - pos)< mini)
            {
                move = false;
                Expos = pos;
            }
        }
    }
La différence entre l'intelligence et la stupidité est que l'intelligence est limitée.

Avatar de l’utilisateur
Alesk
Messages : 2303
Inscription : 13 Mars 2012 09:09
Localisation : Bordeaux - France
Contact :

Re: Crayonner pour révéler un dessin

Message par Alesk » 23 Déc 2019 23:47

Bah y'a pas de boucle là ... Et c'est dans la fonction de dessin qu'elle doit être utilisée.

Là où tu passes les coordonnées pour tracer la brush sur la texture, tu dois utiliser cette boucle pour dessiner plusieurs fois la brush entre l'ancienne position et la nouvelle position de la souris.

EmileF
Messages : 673
Inscription : 18 Mars 2017 19:39

Re: Crayonner pour révéler un dessin

Message par EmileF » 24 Déc 2019 09:53

Alesk a écrit :Bah y'a pas de boucle là ... Et c'est dans la fonction de dessin qu'elle doit être utilisée.

Là où tu passes les coordonnées pour tracer la brush sur la texture, tu dois utiliser cette boucle pour dessiner plusieurs fois la brush entre l'ancienne position et la nouvelle position de la souris.
Bon bé écoute, là je ne comprends pas.
J'ai mis tous les scripts qui gère cette fonction.
Je pense que ce doit être dans la fonction DoPaint du script Painter peut-être.
Ce n'est pas moi qui l'ai créée, j'ai bien essayé de modifier quelques données mais j'avoue que je ne comprends pas tout dans ce script. Une petite précision serait la bien venue.

En tout cas, merci de te pencher sur mon cas, qui est sévère mais pas désespéré j'espère
La différence entre l'intelligence et la stupidité est que l'intelligence est limitée.

EmileF
Messages : 673
Inscription : 18 Mars 2017 19:39

Re: Crayonner pour révéler un dessin

Message par EmileF » 24 Déc 2019 11:33

Grâce aux patientes explications d'Alesk, j'ai enfin trouvé une solution qui me parait acceptable et avec laquele j'obtiens à peu près le résultat escompté.
J'ai donc modifié le script Painter de cette façon:

Code : Tout sélectionner

        
        Vector3 expos;
        void Update()
        {
            //pour n'exécuter la boucle que si le brush est déplacé
            if (expos != Brush.transform.position)
            {
                Vector3 position = expos;
                for (float i = 0; i < 1f; i += 0.1f)
                {
                    position = Vector3.Lerp(expos, Brush.transform.position, i);
                    DoPaint(position);
                }
                expos = Brush.transform.position;
            }
        }

        // Mise à jour du Splat Map en fonction de la position de l'objet Brush
        public void DoPaint(Vector3 position)
        {

            Vector4 worldToRtx = new Vector4(
                map(position.x, WorldBounds.center.x - WorldBounds.size.x / 2, WorldBounds.center.x + WorldBounds.size.x / 2, 0, 1),
                map(position.z, WorldBounds.center.z - WorldBounds.size.z / 2, WorldBounds.center.z + WorldBounds.size.z / 2, 0, 1),
                0,
                0
            );
            drawMaterial.SetVector(rtxCoord, worldToRtx);
            drawMaterial.SetFloat(rtxStrength, BrushStrength);
            drawMaterial.SetFloat(rtxSize, map(BrushSize, 0, 1, 1, 0));
            drawMaterial.SetFloat(rtxFade, FadeSpeed);
            RenderTexture temp = RenderTexture.GetTemporary(splatmap.width, splatmap.height, 0, RenderTextureFormat.ARGBFloat);
            Graphics.Blit(splatmap, temp);
            Graphics.Blit(temp, splatmap, drawMaterial);
            RenderTexture.ReleaseTemporary(temp);
        }

Merci encore Alesk pour tes conseils. Il faut dire qu'il sont succinct, mais ils te mettent sur la voie pour trouver la solution par toi même et c'est très enrichissant.
La différence entre l'intelligence et la stupidité est que l'intelligence est limitée.

Avatar de l’utilisateur
Alesk
Messages : 2303
Inscription : 13 Mars 2012 09:09
Localisation : Bordeaux - France
Contact :

Re: Crayonner pour révéler un dessin

Message par Alesk » 24 Déc 2019 12:09

EmileF a écrit :
24 Déc 2019 11:33
Merci encore Alesk pour tes conseils. Il faut dire qu'il sont succinct, mais ils te mettent sur la voie pour trouver la solution par toi même et c'est très enrichissant.
C'est exactement ce que je cherchais à faire ;)

Maintenant que tu as trouvé, et pour aller plus loin, je peux te donner plus de détails pour essayer d'optimiser un peu le code, si jamais il ne s'exécute pas assez vite :

Au lieu de faire la boucle dans la fonction update, il faudrait la déplacer dans la fonction DoPaint().
En effet : RenderTexture.GetTemporary() et RenderTexture.ReleaseTemporary() peuvent être des fonctions coûteuses en performances, l'idéal est de limiter lors utilisation au maximum.

Donc l'idée ici est de mettre la boucle de dessin dans la fonction DoPaint, entre l'appel à RenderTexture.GetTemporary et celui à RenderTexture.ReleaseTemporary

en gros :
1) RenderTexture.GetTemporary
2) blit blit blit blit blit blit blit blit blit blit blit blitblit blit blit blit
3) RenderTexture.ReleaseTemporary

Il faut donc envoyer deux positions à DoPaint au lieu d'une seule, et y faire le lerp.

Pour le step de la boucle for, actuellement tu utilises une valeur fixe (0.1), il faudrait aussi essayer de la rendre proportionnelle au diametre de ton objet brush, pour faire en sorte qu'il y ait le moins possible d'itérations de la boucle... c'est toujours ça de gagné.

Bon courage !

EmileF
Messages : 673
Inscription : 18 Mars 2017 19:39

Re: Crayonner pour révéler un dessin

Message par EmileF » 24 Déc 2019 12:56

Alesk a écrit :Maintenant que tu as trouvé, et pour aller plus loin, je peux te donner plus de détails pour essayer d'optimiser un peu le code, si jamais il ne s'exécute pas assez vite :

Au lieu de faire la boucle dans la fonction update, il faudrait la déplacer dans la fonction DoPaint().
En effet : RenderTexture.GetTemporary() et RenderTexture.ReleaseTemporary() peuvent être des fonctions coûteuses en performances, l'idéal est de limiter lors utilisation au maximum.
C'est pour ça que j'ai mis la condition :

Code : Tout sélectionner

if (expos != Brush.transform.position)
pour que ça ne s'exécute que quand le brush se déplace.
Alesk a écrit :Donc l'idée ici est de mettre la boucle de dessin dans la fonction DoPaint, entre l'appel à RenderTexture.GetTemporary et celui à RenderTexture.ReleaseTemporary

en gros :
1) RenderTexture.GetTemporary
2) blit blit blit blit blit blit blit blit blit blit blit blitblit blit blit blit
3) RenderTexture.ReleaseTemporary
blit blit blit ... super
mais si je comprends bien la position du point dans la texture est calculée dans ces ligne là:

Code : Tout sélectionner

            Vector4 worldToRtx = new Vector4(
                map(position.x, WorldBounds.center.x - WorldBounds.size.x / 2, WorldBounds.center.x + WorldBounds.size.x / 2, 0, 1),
                map(position.z, WorldBounds.center.z - WorldBounds.size.z / 2, WorldBounds.center.z + WorldBounds.size.z / 2, 0, 1),
                0,
                0
            );
            drawMaterial.SetVector(rtxCoord, worldToRtx);
donc, il faut que je les déplace, je crois entre les lignes "GetTemporary" et "ReleaseTemporary".
Voilà ce que j'obtiens, et ça marche, est-ce bien ça que tu voulais ?
J' ai regroupé aussi le script qui déplace le brush car je ne vois pas l'intérêt d'un script séparé.

Code : Tout sélectionner

       
        Vector3 expos;
        void Update()
        {
            //ceci pour replacer le brush sans faire de trace
            if (Input.GetMouseButtonDown(0))
            {
                if (Camera.RaycastPos(Feuille, out expos))
                {
                    Brush.position = expos;
                }
            }
            if (Input.GetMouseButton(0))
            {
                if (Camera.RaycastPos(Feuille, out Vector3 pos))
                {
                    Brush.position = pos;
                    if (expos != Brush.position)
                    {
                       //si clic sur la feuille et si déplacement
                        DoPaint(expos, Brush.position);
                        expos = Brush.position;
                    }
                }
            }
        }

        public void DoPaint(Vector3 expos, Vector3 newpos)
        {
            RenderTexture temp = RenderTexture.GetTemporary(splatmap.width, splatmap.height, 0, RenderTextureFormat.ARGBFloat);

            for (float i = 0; i < 1f; i += 0.1f)
            {
                Vector3 position = Vector3.Lerp(expos, newpos, i);

                Vector4 worldToRtx = new Vector4(
                    map(position.x, WorldBounds.center.x - WorldBounds.size.x / 2, WorldBounds.center.x + WorldBounds.size.x / 2, 0, 1),
                    map(position.z, WorldBounds.center.z - WorldBounds.size.z / 2, WorldBounds.center.z + WorldBounds.size.z / 2, 0, 1),
                    0,
                    0
                );
                drawMaterial.SetVector(rtxCoord, worldToRtx);
                drawMaterial.SetFloat(rtxStrength, BrushStrength);
                //0.1 pour diminuer l'épaisseur du trait
                drawMaterial.SetFloat(rtxSize, map(BrushSize, 0, 1, 1, 0.1f));
                drawMaterial.SetFloat(rtxFade, FadeSpeed);
                Graphics.Blit(splatmap, temp);
                Graphics.Blit(temp, splatmap, drawMaterial);
            }
            RenderTexture.ReleaseTemporary(temp);
        }
Alesk a écrit :Pour le step de la boucle for, actuellement tu utilises une valeur fixe (0.1), il faudrait aussi essayer de la rendre proportionnelle au diametre de ton objet brush, pour faire en sorte qu'il y ait le moins possible d'itérations de la boucle... c'est toujours ça de gagné.
J'avoue que là ça coince, (si pour le reste j'ai bien compris).
Dans ma boucle il ne fait que 10 itérations en fait. J'obtiens un bon résultat. C'est trop?.
La différence entre l'intelligence et la stupidité est que l'intelligence est limitée.

Avatar de l’utilisateur
Alesk
Messages : 2303
Inscription : 13 Mars 2012 09:09
Localisation : Bordeaux - France
Contact :

Re: Crayonner pour révéler un dessin

Message par Alesk » 24 Déc 2019 13:24

Tu as parfaitement compris pour la boucle ! :)

Pour la taille de la brush, 10 iterations, ça ira dans la plupart des cas je pense, mais essaye avec moins, pour voir ... ça dépend beaucoup de la distance à parcourir.

En fait il faut diviser la distance entre les deux points du tracé par le rayon de la brush pour obtenir le nombre de répétitions nécessaires (et ajuster ensuite en fonction de la forme de la brush, en ajoutant une ou deux répétitions peut-être).

Répondre

Revenir vers « Scripting »