[MY - AL] Subdivision de mesh en zones

Pour les scripts écrits en C#
Règles du forum
Merci de respecter la NOMENCLATURE suivante pour vos TITRES de messages :

Commencez par le niveau de vos scripts
DB = Débutant
MY = Moyen
CF = Confirmé

Puis le domaine d'application
-RS = Réseau
-AL = Algorithmie

Exemple :

[DB-RS] Mouvement perso multijoueur
Avatar de l’utilisateur
Sebela
Messages : 141
Inscription : 25 Juin 2014 21:39

Re: [MY - AL] Subdivision de mesh en zones

Message par Sebela » 30 Nov 2018 16:53

Re !

Bon, j'ai avancé pour mon histoire de "connexion" des mesh, mais j'ai trouvé une méthode qui marche seulement partiellement.

En gros, pour chaque vertice, je cherche la zone la plus proche et la deuxième zone la plus proche. Ensuite, j'attribue le vertex à ces deux zones si la différence de distance avec les deux zones est inférieure à une certaine valeur.

Code : Tout sélectionner

for (int i = 0; i < _nbVertex; i++)
        {
            float distMin = Mathf.Infinity;
            Zone tempZone = null;
            Zone secondZone = null;
            float dist = 0, dist2 = 0;
            foreach (Zone z in _zones)
            {
                dist = (_vertices[i] - z.CenterZone).sqrMagnitude;
                if (dist < distMin)
                {
                    if (tempZone != null)
                    {
                        if (dist2 < distMin)
                        {
                            dist2 = distMin;
                            secondZone = tempZone;
                        }
                    }
                    distMin = dist;
                    tempZone = z;
                }
                else if (dist2 > dist)
                {
                    dist2 = dist;
                    secondZone = z;
                }

            }
            tempZone.Vertices.Add(transform.TransformPoint(_vertices[i]));
            if (secondZone != null) {
                if (Mathf.Abs(distMin-dist2) < .5f)
                    secondZone.Vertices.Add(transform.TransformPoint(_vertices[i]));
            }
        }
Du coup j'essaye de récupérer les vertices qui sont le plus possible "à mi-chemin" entre deux zones, ce qui souvent veut dire qu'il s'agit des bordures de zones. Mais le résultat est hasardeux ^^

Sans connexion :
Image

Avec connexion à 0.5f (tout le monde n'est pas connecté) :
Image

Avec connexion à 1f (certains meshs sont trop connectés) :
Image

djulio74
Messages : 682
Inscription : 19 Déc 2009 22:55

Re: [MY - AL] Subdivision de mesh en zones

Message par djulio74 » 30 Nov 2018 17:22

Je vois ton probleme. En fait quand tu fais ta recherche par vertex de zone, et que tu crée ensuite ton meshCollider avec ces vertex de chaque zone, tu te retrouve immanquablement avec un manque de triangle, ceux qui sont adjacent a plusieurs zone.
Un autre idée :
au lieu de cherche la zone de chaque vertex, cherche la zone de chaque triangle.
En gros pour chaque triangle, défini un point médian ( somme des trois vertex du triangle, divisé par 3), pour chacun de ses points, tu cherche la zone qui lui correspond ( sur la base du script que je t'avais fait, celui pour le vertex). une fois la zone trouvé, tu vérifie si la zone ne contiens pas déjà les points du triangle pour l'ajouter (sinon tout tes point y seront plusieurs fois).

Quand tu fais un mesh.triangle, tu as un array de int, d'une longueur multiple de 3, chaque élément étant un index d'un point dans mesh.vertices. Chaque groupe de 3 élément constitue un triangle (0,1,2),(3,4,5),(6,7,8) ..etc.
En pseudo Code :

Code : Tout sélectionner

struce zone[
Vector3 centre;
List<int> point;
}
struce POINT[
List<int> zone;
}

Vertex = mesh.vertices;
Triangles = mesh.triangles;

for ( int i = 0 ; i < triangles.Length, i+=3){
Vector3 point A =vertices[triangle[i]];
Vector3 point B =vertices[triangle[i+1]];
Vector3 point C =vertices[triangle[i+2]];

Vector3 Center = (A+B+C)/3
recherche-zone-Z-proche-center()
une fois trouvé : 
si zone[Z] ne contiens pas triangle[i] : 
	zone[Z].point.add(triangle[i])
	POINT[triangle[i]].add(Z)
si zone[Z] ne contiens pas triangle[i+1] : 
	zone[Z].point.add(triangle[i+1])
	POINT[triangle[i+1]].add(Z)
si zone[Z] ne contiens pas triangle[i+2] : 
	zone[Z].point.add(triangle[i+2])
	POINT[triangle[i+2]].add(Z)
	
tu te retrouve avec des points partagé pour chaque zone, et lorsque tu generera tes mesh avec les points de chaque zone, tu n'aura plus de trou entre chacune. En plus pour chaque élément de POINT ( donc des vertex de planeteMesh ), tu aura la liste des zones auxquels il appartiens

EDIT : tu pourrais aussi avoir dans la struct zone une liste de Vector3 au lieu des int, mais ça serait plus long quand tu recherchera s'il contiens deja un certain point. Vaux mieux rechercher parmis de int, donc avoir une liste de int.
seulement une fois les zone complétée, tu peux ajouter une liste de Vector3 par zone, chaqun correspondant au vertex designé par chaque élément de la liste de int.

______________________________________________________________
\_______________________ Impossible is nothing _______________________/

Avatar de l’utilisateur
Sebela
Messages : 141
Inscription : 25 Juin 2014 21:39

[Résolu] [MY - AL] Subdivision de mesh en zones

Message par Sebela » 30 Nov 2018 18:15

au lieu de cherche la zone de chaque vertex, cherche la zone de chaque triangle.
Yes, bien vu !! :taré1: C'est exactement ça la bonne méthode ! Merci d'avoir pris le temps de détailler :cote:

J'ai implémenté ça, ça marche très bien !

Image

ps : ça donne l'impression que les zones se superposent mais je crois que c'est juste la transparence qui fait cet effet.

Un grand merci Djulio, on peut dire que tu m'as donné un sacré coup de main ::d (je passe le sujet à résolu)

[EDIT] ps2 : J'ai re-testé ton code en passant le paramètre à 28, et effectivement ça marche ;) 3,9 pour le CPU vs 0,01 pour le GPU ^^
Dernière édition par Sebela le 30 Nov 2018 19:07, édité 3 fois.

djulio74
Messages : 682
Inscription : 19 Déc 2009 22:55

Re: [MY - AL] Subdivision de mesh en zones

Message par djulio74 » 30 Nov 2018 18:47

Yes Cool!!! :super: :super:

Mince moi qui avait aussi fait un script pour te montrer ^^
Pour l'impression quelles se superposent, regarde ta scène ( en pause) en mode shaded wireframe tu sera fixé ;)
Ils elles croisent, ça viens peut être du fait de la façon dont tu donne l'épaississeur a tes meshCollider ( sans doute en fonction de leurs centres respectif différent au lieu d'un centre commun ( celui de la planète)

Allez pour pas l'avoir fait pour rien, je te met mon scipt :

Code : Tout sélectionner

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class AssignZone: MonoBehaviour
{
	public struct ZONE
	{
		public Vector3 Center;
		public List<int> index;
		public List<Vector3> point;
		public Color Col;

		public ZONE (Vector3 Center, List<int> index, List<Vector3> point, Color Col)
		{
			this.Center = Center;
			this.index = index;
			this.point = point;
			this.Col = Col;
		}
	}
	// liste de toutes les zones
	List<ZONE> zone;

	// les vertex du mesh
	Vector3[] vertex;
	// les triangles du mesh
	int[] triangles;
	// la distance minimum a laquelle doivent etre 2 centre
	float MinDist = 0.15f;

	// bool pour affiche le debug
	public bool IsDebug;

	void Start ()
	{

		// on recherche le mesh du gameobject et assigne  vertices et triangle
		Mesh mf = GetComponent<MeshFilter> ().mesh;
		vertex = mf.vertices;
		triangles = mf.triangles;

		// on initialise la liste de zone
		zone = new List<ZONE> ();

		// on fait un certain nombre de recherche de centre
		// il faut beaucoup d'itération pour etre sur que la densité des zone soitent le plus uniforme possible
		// a ajuster en fonction de la taille désiré de chaque zone
		for (int c = 0; c < 3500; c++) {
			FindCenter ();
		}

		// on note le temps actuel, pour savoir la durée de la fonction
		float TP = Time.realtimeSinceStartup;

		// la fonction qui sers a dispatcher les vertex dans les zones
		dispatchVertex ();

		// on debug le temps mis a dispatcher
		print (" temps CPU : " + (Time.realtimeSinceStartup - TP));
	}

	void FindCenter ()
	{
		// on defini aléatoirement un centre, parmis les Vertex du mesh
		Vector3 CenterToAdd = vertex [Random.Range (0, vertex.Length - 1)];

		// on test avec les autre centre deja présent dans la liste
		for (int i = 0; i < zone.Count; i++) {
			float dist = (CenterToAdd - zone [i].Center).magnitude;
			// si celui qu'on a choisis est trop proche d'un autre, on s'arrete la pour celui la
			// on passe a l'itération suivante en stoppant la fonction en cours
			if (dist < MinDist) {				
				return;
			}
		}
		// si la fonction arrive jusqu'ici, c'est qu'aucun autre centre n'est trop proche
		// on ajoute donc CenterToAdd a la liste. Et on passer a l'itération suivante.
		zone.Add (new ZONE (CenterToAdd, new List<int> (), new List<Vector3> (), new Color (Random.value, Random.value, Random.value, 1)));

	}

	void dispatchVertex ()
	{
		// pour chacun des triangles du mesh, groupé par 3 vertex :
		for (int i = 0; i < triangles.Length; i += 3) {
			Vector3 A = vertex [triangles [i]];
			Vector3 B = vertex [triangles [i + 1]];
			Vector3 C = vertex [triangles [i + 2]];
			// calcul d'un centre au triangle
			Vector3 Center = (A + B + C) / 3.0f;

			int temp = 0;
			float distMin = Mathf.Infinity;

			// pour chacune des zones, recherche de la plus proche
			for (int j = 0; j < zone.Count; j++) {				
				float dist = (Center - zone [j].Center).sqrMagnitude;
				if (dist < distMin) {
					temp = j;
					distMin = dist;
				}
			}
			// pour chacun des points du triangle
			for (int j = 0; j < 3; j++) {

				// si la zone ne contiens pas son index
				if (!zone [temp].index.Contains (triangles [i + j])) {
					// on ajoute son index a la liste
					zone [temp].index.Add (triangles [i + j]);
					//on ajoute les coordonnée correpondante au vertex
					// l'ajout du Random est la uniquement pour le Debug, pour pas que les ray se supperposent
					zone [temp].point.Add (vertex [triangles [i + j]] + Random.insideUnitSphere * 0.001f);
				}
			}
		}
	}

	void Update ()
	{
		if ( IsDebug){
			DebugZone();
		}
	}

	void DebugZone()
	{
		for ( int i = 0 ; i < zone.Count ; i++){
			Color Col = zone[i].Col;

			for ( int j = 0 ; j < zone[i].point.Count ; j++){
				Vector3 point = zone[i].point[j];
				Vector3 direction = point.normalized*0.02f;
				Debug.DrawRay(point, direction, Col);
			}
		}
	}
}

______________________________________________________________
\_______________________ Impossible is nothing _______________________/

djulio74
Messages : 682
Inscription : 19 Déc 2009 22:55

Re: [Résolu] [MY - AL] Subdivision de mesh en zones

Message par djulio74 » 30 Nov 2018 18:50

Sebela a écrit :
30 Nov 2018 18:15
[EDIT] ps2 : J'ai re-testé ton code en passant le paramètre à 28, et effectivement ça marche ;) 3,9 pour le CPU vs 0,01 pour le GPU ^^
héhé t'as vu le temps que tu peux gagner! ^^,
Plus qu'a essayer d'adapter pour mettre ça en place dans ton projet, ::d

______________________________________________________________
\_______________________ Impossible is nothing _______________________/

Répondre

Revenir vers « (C#) CSharp »