[WIP] Simu Course réaliste + Map + Volant

Modérateur : Administrateurs Suppléants

djulio74
Messages : 432
Inscription : 19 Déc 2009 22:55
Contact :

Re: [WIP] Simu Course réaliste + Map + Volant

Message par djulio74 » 04 Sep 2018 20:15

Merci pour vos retour! :) ;-)

le problème que j'ai ( ou avais plutôt) avec le C# c'est que je le trouvais mois " francisé" par rapport au JS, d’où mon choix de départ. Le C# me paraissait comme une autre langue très différente. Mais comme pour l'exemple d'Alesk ou même le lien de ZJP, je commence a bien comprendre le C#, la porte est bien ouverte maintenant. ::d il y a plus qu'a!

pour le Count dans mon exemple, c’était avant justement que je comprenne que ces variable partagé entre thread posaient problème. J'avais implanté cette histoire de thread dans ma génération de map. Au début me manquait plein de tri, normal j’attendais pas la fin de tout les threads avant de passer a la suite. ^^ et après même avec le thread.Join(); , il m'en manquait, du a des variables partagées. je voulais incrémenté le Count pour vérifier que les threads arrivaient bien au bout.
ZJP a écrit :
04 Sep 2018 18:31
Oui, pas évident.

D'où la solution sur laquelle j'avais travaillé....
j’étais tombé sur ce lien déjà, mais au tout début de mes recherches sur les threads, je n'y comprenait rien. :hehe: Maintenant me suis familiarisé, vais retenter.

______________________________________________________________
\_______________________ Impossible is nothing _______________________/

djulio74
Messages : 432
Inscription : 19 Déc 2009 22:55
Contact :

Re: [WIP] Simu Course réaliste + Map + Volant

Message par djulio74 » 05 Sep 2018 08:20

Bon vu que vous m'avez conseillé, recommandé, supplier de passer en C#, limite menacé de mort mon âme si e ne le faisais pas, je me lance! ::d

cela dit ça attaque par une question.
Avec mon script JS j'utilise pas mal de "list" (voir page 1). j'ai par exemple pour chacun des points ( vertex)
- pointPos : List<Vector3> => position.
- pointColor : List<Color32> => Couleur.
- VoisinBas : List<int> => index du voisin le plus bas,
- triNext : List<int> => les triangles utilisant ce point,
- pointNext : List<int> => les points adjacent,
- Flux : List<float> => quantité d'eau.

chaque list est séparée, quand je veux ajouter un point, j'ajoute un item a chacun d'elles. comme ça tout les index se correspondent.
En C#, est-il préférable niveau perf ou pour d'autres raisons de rester sur ce mode de fonctionnement à nombreuse liste?
ou je voyais sinon plutôt une seule list de struct. la struct composée de tout ces élément (position, couleur..etc)?
une autre solution plus performante / pratique?
Sachant que je dois pouvoir ajouter, supprimer et modifier chaque entrée.

Vais faire des test de mon coté, c'était surtout pour savoir si une solution était préférable, ou un autre a proscrire.
Merci

( PS : bon anni Alesk, j'ai vu ça hier! ^^)

______________________________________________________________
\_______________________ Impossible is nothing _______________________/

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

Re: [WIP] Simu Course réaliste + Map + Volant

Message par Alesk » 05 Sep 2018 10:46

djulio74 a écrit :
05 Sep 2018 08:20
Bon vu que vous m'avez conseillé, recommandé, supplier de passer en C#, limite menacé de mort mon âme si e ne le faisais pas, je me lance! ::d
Tu as pris la bonne décision, je peux retourner ranger ma hache dans son placard. :diable:
djulio74 a écrit :
05 Sep 2018 08:20
cela dit ça attaque par une question.
[...]
Alors...

Un Array est plus "rapide" qu'une List, mais l'array ne peut pas être redimensionné à la volée.
Si tu connais ton nombre max de valeurs à l'avance, opte pour l'array.

Ensuite, en théorie, et pour des raisons hardware, il est plus optimal d'avoir des arrays de valeurs "basiques" (des floats, des ints, etc...) plutôt que des structs (sachant qu'un Vector est un struct)

Donc pour stocker une liste de Vector3, il te faudrait 3 arrays, un pour chaque axe.

Mais c'est moins pratique à utiliser évidemment... après ça reste de la théorie, il faudrait donc faire des tests approfondis pour vérifier que c'est bien le cas, car ensuite en fonction des langages et des compilateurs on a des surprises.

Autre détail important, au niveau de la gestion mémoire : lorsque tu as une structure à utiliser "en masse" ou "souvent" privilégie la forme "struct" à la forme "class"
On ne peut pas faire de pointeur vers un struct, contrairement à une classe, par contre un struct ne vient pas s'accumuler dans le garbage collector alors qu'une classe oui.
Mais d'une manière générale, il vaut mieux faire du pooling sur les classes, donc les recycler au lieu de les détruire pour en recréer d'autres derrière.



djulio74 a écrit :
05 Sep 2018 08:20
( PS : bon anni Alesk, j'ai vu ça hier! ^^)
(Merci ! ^^)

djulio74
Messages : 432
Inscription : 19 Déc 2009 22:55
Contact :

Re: [WIP] Simu Course réaliste + Map + Volant

Message par djulio74 » 05 Sep 2018 11:08

Merci.
Un Array est plus "rapide" qu'une List, mais l'array ne peut pas être redimensionné à la volée.
Si tu connais ton nombre max de valeurs à l'avance, opte pour l'array.
Bah justement, je ne sais pas quel sera le nombre final de Vertex. Il varie a chaque fois, et non prévisible, vu que la création est procédural et paramétrable ( taille, forme de l'ile par exemple). A moins peut être de prendre une valeur inférieur à la moyenne que j’obtiens jusque là et de limiter l'ajout de point si cette limite est atteinte.
Autre détail important, au niveau de la gestion mémoire : lorsque tu as une structure à utiliser "en masse" ou "souvent" privilégie la forme "struct" à la forme "class"
On ne peut pas faire de pointeur vers un struct, contrairement à une classe, par contre un struct ne vient pas s'accumuler dans le garbage collector alors qu'une classe oui.
Si je comprend/déduis bien , pour mon cas ( modification fréquente d'un index) l'idéal serait un array<struct>, ou à défaut un list<struct> en tant que variable. et je pourrais accéder à la struct de array[n] ou list[n]?
toujours est-il qu'il faille que je vois par moi même comment faire tel ou tel façon. et un petit bench pour comparer les perfs. (liste ou array de 1 a 2 million d'item jusque là, sans route, sans detail...)

Merci de ces éclaircissement. :super:

______________________________________________________________
\_______________________ Impossible is nothing _______________________/

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

Re: [WIP] Simu Course réaliste + Map + Volant

Message par Alesk » 05 Sep 2018 11:39

Tu peux tout faire uniquement avec des arrays de taille fixe, même sans connaitre le total à l'avance.

Il suffit de trouver la taille minimale idéale et de ne bosser qu'avec des blocs/arrays de cette taille.

Par exemple, disons qu'on parte sur un array de 1000 valeurs (donc indexé de 0 à 999).
Lorsque tu as besoin de créer la valeur à l'index 1000 et les suivantes, tu créés un nouvel array fixe avec 1000 nouveaux emplacements.
Et ainsi de suite...
ça permet d'avoir en mémoire le plus possible de blocs contigus de données, et donc un accès plus rapide.

Il te faudra bien entendu une petite formule pour passer d'un array à l'autre en fonction de l'index auquel tu souhaites accéder.
Et là tu peux utiliser une List pour stocker ces arrays (mais tu pourrais tout aussi bien utiliser aussi un array :p )

djulio74
Messages : 432
Inscription : 19 Déc 2009 22:55
Contact :

Re: [WIP] Simu Course réaliste + Map + Volant

Message par djulio74 » 05 Sep 2018 13:08

J'ai tout a fais compris ! ;)
d'ailleurs pas bête l'histoire de plusieurs blocs, j'y avais pensé une fois pour limiter la taille des listes a modifier, puis abandonné l'idée. lol

Alors, l'occasion de me faire la main en C# avec pour commencer des fonctions basiques, pour la grammaire on va dire, un petit bench, au résultat sans appel .
Comparaison des temps de calcul entre :

Methode 1-1 list<struct> : struct( float, float, float, color) ===> 1.116s
Methode 2- 4 list<> : list<float>, list<float>, list<float>, list<color> ===> 0.574s
Methode 3- 4 array<> : array<float>, array<float>, array<float>, array<color> ===> 0.291s
Methode 4- 1 array<struct> : struct( float, float, float, color); ===> 0.288s

le Code:

Code : Tout sélectionner

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

public class Map : MonoBehaviour {
	
	public struct point {
        public float X;
        public float Y;
	public float Z;
	public Color color;

        public point(float X , float Y ,  float Z , Color color) {
          	this.X = X;
          	this.Y = Y;
		this.Z = Z;
		this.color = Color.red;
        }
    }
	
	private int COUNT = 50000;
	
	private List<point> POINT = new List<point>();
	private point[] POINT1;
	
	private List<float> X1 = new List<float>(); 
	private List<float> Y1 = new List<float>(); 
	private List<float> Z1 = new List<float>(); 
	private List<Color> C1 = new List<Color>(); 
	
	private float[] X2;
	private float[] Y2;
	private float[] Z2;
	private Color[] C2;
	

	void Start () {
		
		ListStruct();
		ListSimple();
		Arraysimple();
		ArrayStruct();
	
	}

	void ListStruct(){
		
		float temps = Time.realtimeSinceStartup;		
			
		for ( int i = 0 ; i < COUNT ; i++){
			point ToAdd = new point();
			ToAdd.X = i;
			ToAdd.Y = i*2;
			ToAdd.Z = i*3;
			ToAdd.color = Color.red;
			POINT.Add(ToAdd);				
		}
		
		for ( int j = 0 ; j < 100 ; j++){
			
			for ( int i = 0 ; i < COUNT ; i++){
				
				point temp = POINT[i];
				temp.X = Mathf.Sqrt(temp.X);
				temp.Y = Mathf.Sqrt(temp.Y);
				temp.Z = Mathf.Sqrt(temp.Z);
				temp.color += Color.red*0.1f;
				
				POINT[i] = temp;		
			}
		}		
		Debug.Log( "ListStruct : " + ( Time.realtimeSinceStartup - temps).ToString("f3") + " s");
		
	}
	void ListSimple(){

		float temps = Time.realtimeSinceStartup;	
			
		for ( int i = 0 ; i < COUNT ; i++){				
			X1.Add( i);
			Y1.Add( i*2);
			Z1.Add( i*3);
			C1.Add (Color.red);				
		}
		
		for ( int j = 0 ; j < 100 ; j++){
			
			for ( int i = 0 ; i < COUNT ; i++){

				X1[i] = Mathf.Sqrt(X1[i]);
				Y1[i] = Mathf.Sqrt(Y1[i]);
				Z1[i] = Mathf.Sqrt(Z1[i]);
				C1[i] += Color.red*0.1f;	
			}
		}		
		Debug.Log( "ListSimple : " + ( Time.realtimeSinceStartup - temps).ToString("f3") + " s");		
		
	}

	void ArrayStruct(){

		float temps = Time.realtimeSinceStartup;
		
		POINT1 = new point[COUNT];		
			
		for ( int i = 0 ; i < COUNT ; i++){				
			POINT1[i].X = i;
			POINT1[i].Y = i*2;
			POINT1[i].Z = i*3;
			POINT1[i].color = Color.red;				
		}
		
		for ( int j = 0 ; j < 100 ; j++){
			
			for ( int i = 0 ; i < COUNT ; i++){
				
				POINT1[i].X = Mathf.Sqrt(POINT1[i].X);
				POINT1[i].Y = Mathf.Sqrt(POINT1[i].Y);
				POINT1[i].Z = Mathf.Sqrt(POINT1[i].Z);
				POINT1[i].color += Color.red*0.1f;	
			}
		}		
		Debug.Log( "ArrayStruct : " + ( Time.realtimeSinceStartup - temps).ToString("f3") + " s");		
	}
	
	void Arraysimple(){

		float temps = Time.realtimeSinceStartup;
		
		X2 = new float[COUNT];
		Y2 = new float[COUNT];
		Z2 = new float[COUNT];
		C2 = new Color[COUNT];		
			
		for ( int i = 0 ; i < COUNT ; i++){				
			X2[i] = i;
			Y2[i] = i*2;
			Z2[i] = i*3;
			C2[i] = Color.red;				
		}
		
		for ( int j = 0 ; j < 100 ; j++){
			
			for ( int i = 0 ; i < COUNT ; i++){
				X2[i] = Mathf.Sqrt(X2[i]);
				Y2[i] = Mathf.Sqrt(Y2[i]);
				Z2[i] = Mathf.Sqrt(Z2[i]);
				C2[i] += Color.red*0.1f;	
			}
		}		
		Debug.Log( "Arraysimple : " + ( Time.realtimeSinceStartup - temps).ToString("f3") + " s");		
	}
}

Au moins maintenant je suis fixé, même si tu l'avais déjà dit Alesk. j'hésite un peu entre les méthode 3 et 4, les temps de calculs sont similaire mais peut être un meilleur feeling avec la 4.

______________________________________________________________
\_______________________ Impossible is nothing _______________________/

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

Re: [WIP] Simu Course réaliste + Map + Volant

Message par Alesk » 05 Sep 2018 13:15

Ouep, avec si peu de différence, mieux vaut opter pour la solution 4 :mrgreen:

djulio74
Messages : 432
Inscription : 19 Déc 2009 22:55
Contact :

Re: [WIP] Simu Course réaliste + Map + Volant

Message par djulio74 » 12 Sep 2018 12:01

Me revoilà! :-D
j'ai enfin réussi à convertir tout mon script JS de la map en C#. Ça n'as pas été de tout repos, mais ça valais le coup, un bon apprentissage.
j'en ai profité pour revoir quelques unes des fonctions, optimisé d'autres et le résultat est là. Je suis passé de 85 kTri/s à plus de 120kTri/s. (kTri/s => milliers de triangle en une seconde). le tout en plus pour un maillage bien plus propre et régulier, plus de triangles (1,0M a 1.5M) et plus de mesh créés ( 36 => 64).

le script pour les curieux et courageux! ^^

Code : Tout sélectionner

// Pour utiliser le script, créer une scene avec une directional light
// une caméra et un GameObject Empty.
// Droper ce script sur le GameObject
// creer un GameObject "plane" de unity, avec shader reflection. Dropper le dans "Eau".
// creer un nouveaux material avec le shader dispo page 1. ajouter y autant de textures que le shader nécéssite. 
// Dropper le materail crée dans "mat"
// == PLAY == //



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



public class Map : MonoBehaviour {	
	
	// stock les infos de chaque point
	// position, couleur, points adjacents, triangles adjacent
	private struct POINT { 
        public float x;
        public float y;
		public float z;
		public Color32 color;
		public List<int> pointNext;
		public List<int> triNext;

        public POINT(float x , float y ,  float z , Color32 color , List<int> pointNext , List<int> triNext ) {
            this.x = x;
			this.y = y;
			this.z = z;
			this.color = color;
			this.pointNext = pointNext; 
			this.triNext = triNext;  
        }		
    }
	
	// mise de coté des premiers points crées, pour calculer le taux humidité des points 
	private struct ORIGIN {
		public List<int> Next;
		public int bas;
		public float flux;
		public float ToCote;
		
		public ORIGIN ( List<int> Next, int bas, float flux, float ToCote){
			this.Next = Next;
			this.bas = bas;
			this.flux = flux;
			this.ToCote = ToCote;
		}	
	}
	
	// index des points pour chaque triangle
	// P1, P2, P3 => point[x], point[y], point[z]
	private struct TRI {
		public int P1;
		public int P2;
		public int P3;
		
		public TRI ( int P1 , int P2 , int P3){
			this.P1 = P1;
			this.P2 = P2;
			this.P3 = P3;			
		}	
	}
	
	private struct SEG {
		public int x;
		public int y;
		public SEG ( int x, int y){
			this.x = x;
			this.y = y;
		}
	}
	
	// données calculées en MultiThread pour créer les mesh en MainThread
	private struct ZONE {
		public Rect R;
		public int[] tri;
		public int triCount;
		public Vector3[] Vert;
		public Color32[] Col;
		public Vector2[] UV;
		
		public ZONE (Rect R , int[] tri, int triCount ,Vector3[] Vert , Color32[] Col,Vector2[] UV){
			this.R = R;
			this.tri = tri;
			this.triCount = triCount;
			this.Vert = Vert;
			this.Col = Col;
			this.UV = UV;
		
			
		}	
	}
	
	private POINT[] point ;		private int PointCount ;
	private TRI[] tri ;			private int TriCount ;
	private int[] Cote ;		private int CoteCount;
	private int[] River;		private int RiverCount;
		
	private TRI[] TriToAdd = new TRI[15];		
	private int[] DeleteTri = new int[10];
	private SEG[] segment = new SEG[30];
	
	private TRI TRI1;
	
	private List<int> triTEMP;
	private ORIGIN[] origin;
	
	private int MaxPoint ;
	private int MaxTri ;		
	Vector3 NewPoint;	
	private ZONE[] zone;
	
	// les trois couleur de bases, utilisées jusqu'a
	// l'utilisation des biomes.
	private Color32 Blue = new Color32(0,0,255,100);
	private Color32 Red = new Color32(255,0,0,100);
	private Color32 White = new Color32(255,255,255,100);
	
	private int Rayon = 20000;
	private float Densite = 1000.0f;
	private float Taille = 1.0f;
	private int seuilRiver = 50;
	
	
	//couleur a utiliser pour shader mixant 13 textures
	private Color TropicalRainForest		= new Color(1,0,0,0);
	private Color TropicalSeasonForest 		= new Color(0,1,0,0);
	private Color GrassLand 				= new Color(0,0,1,0);
	private Color SubTropicalDesert 		= new Color(0,0,0,1);
	private Color TemperateRainForest 		= new Color(1,1,0,0);
	private Color TemperateDecidousForest	= new Color(0,1,1,0);
	private Color TemperateDesert			= new Color(0,0,1,1);
	private Color Taiga						= new Color(1,0,0,1);
	private Color ShrubLand					= new Color(0,0,0,0);
	private Color Snow 						= new Color(0,1,0,1);
	private Color Tundra					= new Color(1,0,1,0);
	private Color Bare						= new Color(-1,0,0,0);
	private Color Scorched					= new Color(0,-1,0,0);	
	
	//Couleur a utiliser pour shader sans texture, juste vertex Color
	//private Color TropicalRainForest			= new Color(0.60f,0.73f,0.66f,1.0f);
	//private Color TropicalSeasonForest 		= new Color(0.66f,0.79f,0.64f,1.0f);
	//private Color GrassLand 					= new Color(0.76f,0.82f,0.66f,1.0f);
	//private Color SubTropicalDesert  			= new Color(0.91f,0.86f,0.78f,1.0f);
	//private Color TemperateRainForest 		= new Color(0.64f,0.76f,0.65f,1.0f);
	//private Color TemperateDecidousForest		= new Color(0.70f,0.78f,0.66f,1.0f);
	//private Color TemperateDesert				= new Color(0.89f,0.90f,0.78f,1.0f);
	//private Color Taiga						= new Color(0.79f,0.82f,0.73f,1.0f);
	//private Color ShrubLand					= new Color(0.76f,0.79f,0.73f,1.0f);
	//private Color Snow 						= new Color(0.96f,0.96f,0.96f,1.5f);
	//private Color Tundra						= new Color(0.86f,0.86f,0.73f,1.0f);
	//private Color Bare						= new Color(0.73f,0.73f,0.73f,1.0f);
	//private Color Scorched					= new Color(0.59f,0.59f,0.59f,1.0f);
	
	private Transform Cam;
	public Material mat;
	public Transform Eau;
	public bool ShowZone;
	public bool ShowFluxWater;
	public bool ShowRiver;
	
	void Start () {			
		
		
		float TP = Time.realtimeSinceStartup;
		
		MaxPoint = 750000;
		MaxTri = 1500000;
		TriCount = -1;
		PointCount = -1;
		
		point = new POINT[MaxPoint];
		tri = new TRI[MaxTri];
		Cote = new int[7500];
		CoteCount = 0;
		
		CreateBase();
		
		for ( int i = 1 ; i < 14 ; i++){			
			AddPoint1(i*2,i/11.0f);			
		}

		AddTerre(White);
		Densite = 500.0f;

		PointNEXT();
		AddColor();
		Border();
		Smooth1();		
		
		Iteration(false);
		
		//Instantiate origin NEXT //
		origin = new ORIGIN[PointCount+1];
		for ( int i = 0 ; i < origin.Length ; i++){
			origin[i].Next = point[i].pointNext;
		}
		//================= //
		
		Iteration(false);		
		propageCote();		
		RemoveIsolate();
		elevation();
		
		//Instantiate origin dist To COTE //
		for ( int i = 0 ; i < origin.Length ; i++){
			origin[i].ToCote = point[i].y*10.0f;
		}
		//================= //
		
		Iteration(true);
		elevation1();		
		Iteration(true);
		
		Voisin();
		Biome();
		initialiseZONE();
		CreateEau();
		
		int RD = UnityEngine.Random.Range(3, PointCount);
		Vector3 A = new Vector3( point[RD].x, point[RD].y , point[RD].z);
		
		
		if( Camera.mainCamera){	
			Cam = Camera.mainCamera.transform;
			Cam.position = A + Vector3.up*1.8f;	
		}
		else{ print (" !! aucune camera !!"); }
		
		
		print( " temps : " + ( Time.realtimeSinceStartup-TP) + "s  ,   PointCount : " + PointCount + "  ,   triCount : " + TriCount);
		print( " ratio : " + Mathf.Round(TriCount/(Time.realtimeSinceStartup-TP)/10.0f) /100.0f + " kPoly/s");
			
	}

	void Update () {
		
		// Drop la caméra à un nouvel emplacement
		if( Input.GetKeyDown("a") && Cam){

			int RD = UnityEngine.Random.Range(3, PointCount);
			Vector3 A = new Vector3( point[RD].x, point[RD].y , point[RD].z);
			Cam.position = A + Vector3.up*1.8f;

		}
		
		
		// afficher/cacher l'écoulement de l'eau => touche "e"
		if ( Input.GetKeyDown("e")){ ShowFluxWater = !ShowFluxWater;}
		for ( int i = 3 ; i < origin.Length ; i++){
			
			if( ShowFluxWater){
				int J = origin[i].bas;			
				if( J >2 && point[i].y >0 && point[J].y > 0){
					Vector3 A = new Vector3( point[i].x, point[i].y , point[i].z);
					Vector3 B = new Vector3( point[J].x, point[J].y , point[J].z);					
					Debug.DrawLine( A+Vector3.up*10.0f, B +Vector3.up*10.0f,new Color(1.0f,1.0f,1.0f,0.4f) );
				}
			}	
		}
		// afficher/cacher les rivvieres retenues => touche "r"
		if ( Input.GetKeyDown("r")){ ShowRiver = !ShowRiver;}
		for ( int i = 0 ; i < RiverCount ; i++){
			
			if( ShowRiver){
				int I = River[i];
				int J = origin[River[i]].bas;			
				if( point[I].y >0 && point[J].y > 0){
					Vector3 A = new Vector3( point[I].x, point[I].y , point[I].z);
					Vector3 B = new Vector3( point[J].x, point[J].y , point[J].z);					
					Debug.DrawLine( A+Vector3.up*10.0f, B +Vector3.up*10.0f,Color.blue );
				}
			}	
		}
		
		// afficher/cacher les zones => touche "z"
		if ( Input.GetKeyDown("z")){ ShowZone = !ShowZone;}
		for ( int i = 0 ; i < zone.Length ; i++){
			
			if( zone[i].triCount != 0 && ShowZone){ 
			
				Vector3 A = new Vector3(zone[i].R.xMin, 0, zone[i].R.yMin);
				Vector3 B = new Vector3(zone[i].R.xMax, 0, zone[i].R.yMax);
				Vector3 C = new Vector3(zone[i].R.xMin, 0, zone[i].R.yMax);
				Vector3 D = new Vector3(zone[i].R.xMax, 0, zone[i].R.yMin);
				
				Debug.DrawLine(A,B);
				Debug.DrawLine(C,D);
				Debug.DrawLine(A,C);
				Debug.DrawLine(A,D);
				Debug.DrawLine(C,B);
				Debug.DrawLine(D,B);
			}
		}
	}
	
	
	void CreateBase() { 
		
		//création tout premier triangle, 
		//doit pouvoir contenir TOUT les point qui seront crées.
		
		float espace = 2* Mathf.PI /3;	
		for ( int i = 0 ; i < 3 ; i ++){			
			PointCount += 1;
			point[PointCount].x = Mathf.Sin(i*espace)*Rayon*3.5f;
			point[PointCount].z =  Mathf.Cos( i*espace)*Rayon*3.5f;
			point[PointCount].color = Blue;	
			point[PointCount].triNext = new List<int>();
		}
	
		TriCount +=1;
		TRI1 = new TRI(0,1,2);
		tri[TriCount] = TRI1;
		
		point[TRI1.P1].triNext.Add(TriCount);
		point[TRI1.P2].triNext.Add(TriCount);
		point[TRI1.P2].triNext.Add(TriCount);

	}
	
	void AddPoint1( int NB, float ray) {
		
		// création de cercle concentriques de points
		// ray => rayon du cercle sur lequel placer les points.
		// NB => nombre de points sur ce cercle.

		float espace = 2.0f* Mathf.PI /NB;		
		for ( int p = 0 ; p < NB ; p ++){
			
			NewPoint = new Vector3(Mathf.Sin(p*espace)*Rayon*ray,0,Mathf.Cos( p*espace)*Rayon*ray);
			
			// recherche du point le plus proche de celui crée.
			float Min = Mathf.Infinity;
			for ( int i = 0 ; i < PointCount+1 ; i++){
				float dist = ( new Vector3(point[i].x,point[i].y,point[i].z) - NewPoint).sqrMagnitude;		
				if( dist < Densite*Densite){  return; }		
				if( dist < Min ){
					Min = dist;	
					triTEMP=(point[i].triNext);					
				}
			}
			
			PointCount += 1;			
			point[PointCount].x = NewPoint.x;
			point[PointCount].z = NewPoint.z;
			point[PointCount].color = White;
			point[PointCount].triNext = new List<int>();
			
			// définir les triangle éxistant pouvant etre modifier
			// parmis les triangles proches au point le plus proche.
			// triTEMP => les index des triangles trouvés.
			
			List<int> Plist = new List<int>();			
			
			for ( int i = 0 ; i < triTEMP.Count ; i++){
				TRI1 = tri[triTEMP[i]];
				if ( Plist.Contains(TRI1.P1) == false){  Plist.Add(TRI1.P1); }
				if ( Plist.Contains(TRI1.P2) == false){  Plist.Add(TRI1.P2); }
				if ( Plist.Contains(TRI1.P3) == false){  Plist.Add(TRI1.P3); }
			}		
			
			triTEMP = new List<int>();
			
			for ( int j = 0 ; j < Plist.Count ; j++){
				List<int> NEXT = point[Plist[j]].triNext;
				for ( int k = 0 ; k < NEXT.Count ; k++){
					if( triTEMP.Contains(NEXT[k]) == false){
						triTEMP.Add(NEXT[k]);
					}			
				}		
			}			
			Remove();
		}
	}
	
	void Remove(){
		
		// test des triangles => garder/modifier
		// en utilisant la methode de Delaunay
		
		int SegCount = 0;		
		int DeleteCount = 0;
		
		Vector2 NewPointXZ = new Vector2(NewPoint.x ,NewPoint.z);

		for ( int i  = 0 ; i < triTEMP.Count ; i++){
			
			int I = triTEMP[i];		
			TRI1 = tri[I];
			
			Vector3 A = new Vector3( point[TRI1.P1].x ,point[TRI1.P1].y, point[TRI1.P1].z);	
			Vector3 B = new Vector3( point[TRI1.P2].x ,point[TRI1.P2].y, point[TRI1.P2].z);	
			Vector3 C = new Vector3( point[TRI1.P3].x ,point[TRI1.P3].y, point[TRI1.P3].z);									
	
			float Cx = -((C.x*C.x - B.x*B.x + C.z*C.z-B.z*B.z)/(2*(C.z-B.z))-(B.x*B.x - A.x*A.x + B.z*B.z-A.z*A.z)/(2*(B.z-A.z)))/((B.x-A.x)/(B.z-A.z) - (C.x-B.x)/(C.z-B.z));
			float Cy = -(B.x-A.x)/(B.z-A.z)*Cx + (B.x*B.x - A.x*A.x + B.z*B.z-A.z*A.z)/(2*(B.z-A.z));
			
			Vector2 midpoint = new Vector2( Cx , Cy);
			
			float dist  = ((midpoint- new Vector2(A.x , A.z) ).sqrMagnitude - (midpoint - NewPointXZ ).sqrMagnitude);				
			
			if( dist >= 0){
				
				DeleteTri[DeleteCount] = I;
				DeleteCount +=1;
				
				segment[SegCount].x =  TRI1.P1; 	segment[SegCount].y =  TRI1.P2;
				segment[SegCount+1].x =  TRI1.P1; 	segment[SegCount+1].y =  TRI1.P3;
				segment[SegCount+2].x =  TRI1.P3; 	segment[SegCount+2].y =  TRI1.P2;				
				SegCount += 3;
			}
		}

		int TriToAddCount = 0;		
		float angle = 0.0f;
		
		for ( int i = 0 ; i < SegCount ; i++){
			SEG S = segment[i];
			Vector2 Seg = new Vector2(S.x,S.y);
			bool seul = true;			
			for ( int l = 0 ; l < SegCount ; l++){	
				Vector2 Seg1 = new Vector2(segment[l].x,segment[l].y);
				if( Seg.sqrMagnitude == Seg1.sqrMagnitude && i!=l){
					seul = false;
					break;		
				}		
			}		
					
			if( seul ){
				
				Vector2 cA = new Vector2(point[S.x].x,point[S.x].z ) - NewPointXZ;
				Vector2 cB = new Vector2(point[S.y].x,point[S.y].z ) - NewPointXZ;
				
				angle += Vector2.Angle(cA ,cB );
				TriToAdd[TriToAddCount].P1 = S.x ;
				TriToAdd[TriToAddCount].P2 = S.y ;
				TriToAdd[TriToAddCount].P3 = PointCount ;
				TriToAddCount += 1;

			}
		}
		
		if( Mathf.Approximately( 360 ,angle) ){			
		
			for ( int t = 0 ; t < DeleteCount ; t++){		
			
				TRI1 = tri[DeleteTri[t]];		
				int temp = DeleteTri[t];
				TRI TRI2 = TriToAdd[t];
				tri[temp] = TRI2;
				
				if( TRI2.P1 != TRI1.P1){ point[TRI1.P1].triNext.Remove(DeleteTri[t]); point[TRI2.P1].triNext.Add(temp); } 
				if( TRI2.P2 != TRI1.P2){ point[TRI1.P2].triNext.Remove(DeleteTri[t]); point[TRI2.P2].triNext.Add(temp); } 
				if( TRI2.P3 != TRI1.P3){ point[TRI1.P3].triNext.Remove(DeleteTri[t]); point[TRI2.P3].triNext.Add(temp); } 	
			}
		
			for ( int t = DeleteCount ; t < TriToAddCount ; t++){	

				TriCount +=1;
				tri[TriCount] = TriToAdd[t] ;	
				int temp = TriCount;				
				
				point[TriToAdd[t].P1].triNext.Add(temp); 
				point[TriToAdd[t].P2].triNext.Add(temp); 
				point[TriToAdd[t].P3].triNext.Add(temp); 
			}			
		}
		else{
			PointCount -= 1;		
		}		
	}
	
	void PointNEXT(){
		
		// pour chaque point, lister les ponts adjacent
		// pour chaque triangle, chaque point est adjacent aux deux autres
				
		for ( int j = 0 ; j < PointCount+1 ; j++){
			point[j].pointNext = new List<int>();
		}		

		for ( int i = 0 ; i < TriCount+1 ; i++){
				
			TRI TRI = tri[i];			
			List<int> x = point[TRI.P1].pointNext;	List<int> y = point[TRI.P2].pointNext;	List<int> z = point[TRI.P3].pointNext;			
				
			if( x.Contains(TRI.P2) == false){	x.Add( TRI.P2);	}		
			if( y.Contains(TRI.P1) == false){	y.Add( TRI.P1);	}		
			if( x.Contains(TRI.P3) == false){	x.Add( TRI.P3);	}
			if( z.Contains(TRI.P1) == false){	z.Add( TRI.P1);	}
			if( z.Contains(TRI.P2) == false){	z.Add( TRI.P2);	}
			if( y.Contains(TRI.P3) == false){	y.Add( TRI.P3);	}	
			
			point[TRI.P1].pointNext = x;	point[TRI.P2].pointNext = y;	point[TRI.P3].pointNext = z;
		}
	}
	
	void AddColor(){
		
		// jusque la, tout les points sont blanc
		// en passer aléatoirement certains en rouge => terre
		// et d'autre en bleu => eau
	
		for ( int i = 0 ; i < 20.0f*Taille ; i++){			ChangeColor(Red);	}
		for ( int i = 0 ; i < 20.0f* (1.0f-Taille) ; i++){	ChangeColor(Blue);	}		
		PropageColor();
	}
	
	void ChangeColor(Color Col){
	
		int RD = UnityEngine.Random.Range(3, PointCount);	
		Vector2 P = new Vector2( point[RD].x, point[RD].z);
		
		
		if( P.magnitude > Rayon * Taille && Col == Red){
			ChangeColor(Col);
			return;
		}
		if( P.magnitude < Rayon*0.9f * Taille && Col == Blue){
			ChangeColor(Col);
			return;
		}
		point[RD].color = Col;
	}
	
	void PropageColor(){
		
		// propagation des couleur rouge et bleu
		// pour chaque point bleu ou rouge, assigner sa couleur a tout ses adjacents
		// reommencer tant qu'il reste du blanc.

		for ( int i = 0 ; i < PointCount+1  ; i ++){	
			List<int> next = point[i].pointNext;	
			for ( int j = 0 ; j < next.Count ; j++){	
				if( point[next[j]].color.g == 255){			
					point[next[j]].color = point[i].color;
				}				
			}	 
		}
		
		for ( int k = 0 ; k < PointCount+1 ; k ++){
			if ( point[k].color.g == 255){		
			PropageColor();
			return;		
			}	
		}
		
		// prevenir la propagation
		// maintenir la terre a un rayon donné
		
		float Max = Mathf.Min(Rayon ,  Rayon * Taille * 1.2f);
		Max *= Max;
		
		for ( int i = 0 ; i < PointCount+1  ; i ++){			
			Vector3 P = new Vector3( point[i].x, point[i].y , point[i].z);
			if(P.sqrMagnitude > Max){
				point[i].color = Blue;
			}	
		}		
	}
		
	void Border(){
		
		// création des cote, si un point
		// a un voisin pas de sa propre couleur, il est
		// entre terre et eau => cote.
		
		CoteCount = 0;
	
		for ( int i = 0 ; i < PointCount ; i ++){	
			if( point[i].color.r == 0){		
				for ( int k = 0 ; k < point[i].pointNext.Count ; k++){	
					int N = point[i].pointNext[k];
					if( point[N].color.b == 0){
					point[i].color = White;
					Cote[CoteCount] = i;	
					CoteCount +=1;
					break;
					}
				}								
			}	
		}	
		RemoveIsolate();
			
	}
	
	void RemoveIsolate(){
		
		// si un point de cote a des adjacent uniquement 
		// de la meme couleur, il n'est plus Cote.		

		for ( var i = 0 ; i < CoteCount+1 ; i++){	
			int nb = 0 ;					
			for ( int j = 0 ; j <  point[Cote[i]].pointNext.Count ; j++){	
				int P = point[Cote[i]].pointNext[j];
				if( point[P].color.b == 0){
				nb = 1;
				break;
				}		
			}		
			if( nb == 0){
				point[Cote[i]].color = Blue;
			}			
		}
		
		int[] tempCote = Cote;
		int CoteCount1 = 0;	
		for ( int i = 0 ; i < CoteCount+1 ; i++){
			if( point[Cote[i]].color.g == 255 ){ 
				tempCote[CoteCount1] = Cote[i];
				CoteCount1 +=1;
			}
		}
		CoteCount = CoteCount1;
		Cote = tempCote;

	}
	
	void Smooth1(){
		
		// lisser le contour des cotes
		// adoucir les angles
	
		for ( int l = 0 ; l < CoteCount+1  ; l ++ ){	
			Vector3 dist = new Vector3(0,0,0);
			int L = Cote[l];
			List<int>  next = point[L].pointNext;
			
			for( int i = 0 ; i < next.Count ; i++){	
				int I = next[i];
				if(point[I].color.g == 255){
					dist += (new Vector3(point[L].x, point[L].y, point[L].z) - new Vector3(point[I].x, point[I].y, point[I].z))  ;		
				}
			}	

			point[L].x -= dist.x *0.15f;
			point[L].y = 0.0f;
			point[L].z -= dist.z *0.15f;
		}	
		Smooth();	
	
	}
	
	void Smooth(){
		
		// positionner chaque point au barycentre de 
		// tout ses points adjacent => maillage plus régulier.
	
		float Se = Rayon*Rayon*1.3f;
		float mul = 0.5f ;
	
		for ( int l = 0 ; l < PointCount+1  ; l ++ ){			
			Vector3 PL = new Vector3(point[l].x , point[l].y , point[l].z);						
			if(point[l].color.g == 0 && PL.sqrMagnitude < Se){				
			
				Vector3 P1 = PL*mul;
				List<int> Next = point[l].pointNext;
						
				for ( int j = 0 ; j < Next.Count ; j ++){
					int J = Next[j];
					
					P1 +=   new Vector3(point[J].x , point[J].y ,point[J].z);;
				}			
				P1 /= Next.Count+mul;
				point[l].x = P1.x ;	
				point[l].y = P1.y ;	
				point[l].z = P1.z ;	
			}
		}
	}
	
	void Iteration(bool divide){
		
		if( divide){
			DivideCote();
		}
		Densite *=0.5f;
		AddTerre(Red);
		PointNEXT();
		propageCote();
		RemoveIsolate();
		Smooth1();		
	}
	
	void AddTerre( Color32 COL ){
		
		// pour chaque triangle, ajouter un point au barycentre
		// de ses trois sommets.
				
		float MOY = Densite * Densite*3.0f;
		float R = Rayon*Rayon*1.2f;
		float Div3 = 1.0f/3.0f;
		
		for ( int i = 0 ;  i < TriCount ; i++){
		
			TRI1 = tri[i];				
			float Col = (point[TRI1.P1].color.b + point[TRI1.P2].color.b + point[TRI1.P3].color.b)*Div3; 
			
			if( Col == COL.b){
				
				Vector3 A = new Vector3(point[TRI1.P1].x, point[TRI1.P1].y, point[TRI1.P1].z);
				Vector3 B = new Vector3(point[TRI1.P2].x, point[TRI1.P2].y, point[TRI1.P2].z);
				Vector3 C = new Vector3(point[TRI1.P3].x, point[TRI1.P3].y, point[TRI1.P3].z);
				
				NewPoint = ( A + B + C)*Div3;
				
				if( ( (A - NewPoint).sqrMagnitude +(B - NewPoint).sqrMagnitude + (C - NewPoint).sqrMagnitude)   > MOY && NewPoint.sqrMagnitude < R) {
				
				triTEMP = new List<int>();					
					
				int[] tr = new int[2];
				tr[0] = TRI1.P1; tr[1] = TRI1.P2; 
					
				for ( int j = 0 ; j < tr.Length ; j ++){
					for ( int k = 0 ; k < point[tr[j]].triNext.Count ; k++){
						int K =  point[tr[j]].triNext[k];
						if( triTEMP.Contains(K) == false){
							triTEMP.Add(K);	
						}
					}					
				}					
					
				PointCount += 1;

				point[PointCount].x = NewPoint.x;
				point[PointCount].y = NewPoint.y;
				point[PointCount].z = NewPoint.z;
				point[PointCount].color = COL;
				point[PointCount].triNext = new List<int>();
	
				Remove();
				}				
			}
		}	
	}
	
	void propageCote(){
		
		// deplace les cote d'un voisin sur la terre
		// réduction legere de la surface terre
		// mais augmentation de la densité du maillage
		// de la cote partie eau.

		int CoteC = CoteCount+1;		
		for (var n = 0 ; n < CoteC ; n ++){
			
			List<int> TEMP = point[Cote[n]].pointNext ;			
			for ( int b = 0 ; b < TEMP.Count ; b ++){		
				if( point[TEMP[b]].color.b == 0){			
					point[TEMP[b]].color = White;
					Cote[CoteCount] = TEMP[b];
					CoteCount +=1;
				}	
			}		
			point[Cote[n]].color = Blue;				
		}
	}
	
	void elevation(){
		
		// pour chaque point, trouver le point de la 
		// la cote le plus proche, calculer la distance
		// hauteur du point = distance a la cote.
		// l'ile est connique, les versans sont reguliers.

		float RAYON = Rayon * Rayon;
		
		for ( int i = 3 ; i < PointCount+1 ; i++){
			
			Vector2 P1 = new Vector2( point[i].x, point[i].z);
			
			if( point[i].y == 0 && point[i].color.g == 0){
				float Min = RAYON;
				int proche = 0; 	
				
				for ( int j = 0 ; j < CoteCount ; j+=5){		
					Vector2 P2 = new Vector2( point[Cote[j]].x, point[Cote[j]].z);
					float dist = (P1 - P2).sqrMagnitude;
					if( dist < Min){ Min = dist ; proche = Cote[j]; }			
				}

				point[i].y = Mathf.Sqrt(Min)*0.5f * Mathf.Sign(1-point[i].color.b ) ; 					
				Vector2 P3 = new Vector2(point[proche].x,point[proche].z);
				
				if( point[i].color.r == 0 ){ continue;}
						
				for ( int j = 0 ; j < point[i].pointNext.Count ; j ++){
					int k = point[i].pointNext[j];
					if( point[k].y == 0 && point[k].color.g == 0){
						Min = (  P3  -new Vector2(point[k].x,point[k].z)).sqrMagnitude;	
						point[k].y = Mathf.Sqrt(Min)*0.5f * Mathf.Sign(1-point[k].color.b );
					}

					for ( int l= 0;  l< point[k].pointNext.Count ; l ++){
							
						int k1 = point[k].pointNext[l];										
						if( point[k1].y == 0 && point[k1].color.g == 0 ){
							Min = (  P3  -new Vector2(point[k1].x,point[k1].z)).sqrMagnitude;
							point[k1].y = Mathf.Sqrt(Min)*0.5f * Mathf.Sign(1-point[k1].color.b ) ;
		
						}							
					}					
				}
			}				
		}
	}
	
	
	void elevation1(){
		
		// pour chaque point, calcul d'un mix de Perlin noise en fonction de sa position
		// sa hauteur est multipliée a ce perlin
		// l'ile est valonnée, escaprée.
		
		float Rand = UnityEngine.Random.Range(10.0f,500.0f);
		
		for ( int k = 0 ; k < PointCount+1 ; k++){			
			
			float Min = point[k].y*2.0f;

			float Perlin = 0.0f;			
			float prev = 1.0f;
			float tot = 0.0f;
			float X = (point[k].x/16000.0f+ Rand);
			float Z = (point[k].z/16000.0f+ Rand);				
			float inv = 1.0f;
							
			for ( float p = 1.0f ; p < 60; p*=2.4f){
							
				float P = 1.0f/(p -0.15f);
				float test = Mathf.PerlinNoise(X*p * inv , Z*p *inv )*prev   ;				
				test = (0.5f-Mathf.Abs( test-0.5f) )*(2.1f+0.5f*P)  ;						
				prev = Perlin*P + test ;				
				Perlin += (test*test)*P;				
				tot += P;	
					
				inv = -inv;					
			}	
							
			Perlin /= tot;
			Min *=0.000055f;
			
			if( Min > 0){							
				if( Min< 0.155f){	point[k].y = Perlin* Min*Min*20000.0f+Min*10.0f ;	}
				else{				point[k].y = Perlin* (Mathf.Sqrt(Min*1.5f)-0.36205f) *4000.0f+Min*10.0f;		}		
			}
			else{
				if( Min>-0.155f){	point[k].y = -Perlin* Min*Min*20000.0f +Min*10.0f;	}
				else{				point[k].y = -Perlin* (Mathf.Sqrt(-Min*1.5f)-0.36205f) *4000.0f+Min*10.0f;		}
			}
		}		
	}
	
	void Voisin(){
		
		// pour chaque point de origin (points crée jusque la
		// deuxieme itération), definir le point le plus bas
		// ou l'eau coulera. 
					
		for( int i = 0 ; i < origin.Length ; i++ ){

			int bas = i;		
			for ( int j = 0 ; j < origin[i].Next.Count ; j ++){
				int K =  origin[i].Next[j];
				if( point[K].y < point[bas].y){
					bas = K;	
				}	
			}
			origin[i].bas = bas;
			origin[i].flux = 1.0f;
		}
		
		// pour chaque point, suivre le chemin de point le plus bas en 
		// point le plus bas, c'est le parcours de l'eau 
		
		for( int i = 0 ; i < origin.Length ; i++){
			FluxAdd(i);			
		}
		
		River = new int[10000];
		RiverCount = 0;
		for (int i = 0 ; i < origin.Length ; i++){
			if( origin[i].flux> seuilRiver){
				River[RiverCount] = i;
				RiverCount +=1;				
			}
		}
	}	
	
	void FluxAdd(int k){

		if( k != origin[k].bas){
			origin[origin[k].bas].flux += 1;
			FluxAdd(origin[k].bas);
		}
	}
	
	void DivideCote(){
		
		// entre deux point de cote adjacent, inserer un 
		// nouveau point cote. => subdivision de la cote.
					
		for ( int i = 0 ; i < CoteCount ; i++){
			int a = Cote[i];
			for ( int j = 0 ; j < point[a].pointNext.Count ; j++){
				int b = point[a].pointNext[j];
				
				if( a > b &&  point[b].color.g != 0){
					
					Vector3 A = new Vector3(point[a].x, point[a].y, point[a].z);
					Vector3 B = new Vector3(point[b].x, point[b].y, point[b].z);
					
					NewPoint = ( A + B )*0.5f;
					
					triTEMP = new List<int>();					
					
					int[] tr = new int[2];
					tr[0] = a; tr[1] = b; 
					
					for ( int l = 0 ; l < tr.Length ; l ++){
						for ( int k = 0 ; k < point[tr[l]].triNext.Count ; k++){
							int K =  point[tr[l]].triNext[k];
							if( triTEMP.Contains(K) == false){
								triTEMP.Add(K);	
							}
						}					
					}					
					
					PointCount += 1;
					point[PointCount].x = NewPoint.x;
					point[PointCount].y = NewPoint.y;
					point[PointCount].z = NewPoint.z;
					point[PointCount].color = Red;
					point[PointCount].triNext = new List<int>();					
	
					Remove();					
				}				
			}			
		}
		
		for ( int i = 0 ; i < CoteCount ; i ++){
			point[Cote[i]].color = Red;	
		}		
		
		Border();
	}

	void Biome(){
		
		// en fonction du flux et de l'altitude de chaque point de origin
		// assignation d'un biome représenté part un couleur 
		
		float MaxDist = 0.0f;
		float MaxHeight = 0.0f;	
		
		for ( int i = 0 ; i < origin.Length; i++){			
			
			Vector2 A = new Vector2(point[i].x, point[i].z);
			float TOCOTE = origin[i].ToCote;
			TOCOTE *=TOCOTE;
			for ( int j = 0 ; j < RiverCount ; j++ ){
				
				Vector2 B = new Vector2(point[River[j]].x, point[River[j]].z);				
				float dist = (A - B).sqrMagnitude*1.3f;					
				if ( dist < TOCOTE){ 	TOCOTE =dist;	}
								
			}		
			
			if( point[i].y > MaxHeight){ MaxHeight = point[i].y;}	
			if( TOCOTE > MaxDist){ MaxDist = TOCOTE;}
			origin[i].ToCote = Mathf.Sqrt(TOCOTE);
			
		}
		
		MaxDist = Mathf.Sqrt(MaxDist);		
		MaxHeight = Mathf.Max( MaxHeight, 3500.0f);		
		
		for ( int i = 0 ; i < origin.Length ; i++){
			
			float heigh = point[i].y;
			float dist = origin[i].ToCote;			
			
			if( heigh < 0.0f){ point[i].color = SubTropicalDesert;}
			
			else if ( heigh < MaxHeight/4.0f){			
				if( dist < MaxDist/3.0f){				point[i].color = TropicalRainForest;		}
				else if( dist < MaxDist/3.0f*2.0f){		point[i].color = TropicalSeasonForest;		}
				else if( dist < MaxDist/6.0f*5.0f){		point[i].color = GrassLand ;				}
				else{									point[i].color = SubTropicalDesert;			}		
			}
				
			else if( heigh < MaxHeight/2.0f){		
				if( dist < MaxDist/6.0f){				point[i].color = TemperateRainForest;		}
				else if( dist < MaxDist/2.0f){			point[i].color = TemperateDecidousForest;	}
				else if( dist < MaxDist/6.0f*5.0f){		point[i].color = GrassLand;					}
				else{									point[i].color = TemperateDesert;			}				
			}
				
			else if( heigh < MaxHeight/4.0f*3.0f){
				if( dist < MaxDist/3.0f){				point[i].color = Taiga;						}
				else if( dist < MaxDist/3.0f*2.0f){		point[i].color = ShrubLand;					}
				else{									point[i].color = TemperateDesert;			}
			}
				
			else if( heigh < MaxHeight/4.0f*3.8f){
				if( dist < MaxDist/1.5f){				point[i].color = Snow;						}
				else if(  dist < MaxDist/3.0f*2.2f){	point[i].color = Tundra;					}
				else if(  dist < MaxDist/6.0f*5.0f){	point[i].color = Bare;						}
				else{									point[i].color = Scorched;					}	
			}		
			else{
				point[i].color = Snow;
			}			
		}
		
		int[] ORI = new int[PointCount+1];
		int oriCount = origin.Length;
		
		for ( int i = 0 ; i < origin.Length ; i++){
			ORI[i] = i;			
		}
		
		// idem propageColor(), pour chaque point, propagation
		// de sa coulur, donc son biome, aux points adjacent
		
		for ( int i = 0 ; i < oriCount ; i++ ){				
			for ( int j = 0 ; j < point[ORI[i]].pointNext.Count ; j++ ){
				int J = point[ORI[i]].pointNext[j];
				if( point[J].color.a == 100){
					if( point[J].y < 0.0f){
						point[J].color = SubTropicalDesert;
					}
					else{
						point[J].color = point[ORI[i]].color;
					}
					ORI[oriCount] = J;
					oriCount +=1;
				}	
			}
		}
		
		for ( int i = 0 ; i < CoteCount; i++){
			for ( int j = 0 ; j < point[Cote[i]].pointNext.Count ; j++ ){
				point[point[Cote[i]].pointNext[j]].color = SubTropicalDesert ;				
			
			}		
		}
	}
	
	void initialiseZONE(){
		
		// subdivise/quadrille l'iles en zones. 
		// chaque zone correspondra a un gameObjet
		
		int ZoneCount = 8;
		float RAYON = Rayon*1.2f;
		float zoneSize = (RAYON*2.0f/ZoneCount);
		zone = new ZONE[ZoneCount*ZoneCount+1];

		for ( int i = 0 ; i < ZoneCount ; i++){	
			zone[i].R =  new Rect(-RAYON + zoneSize*i, -RAYON ,  zoneSize,zoneSize) ;
			zone[i].tri = new int[200000];
		}
		
		for ( int j = ZoneCount ; j < ZoneCount*ZoneCount ; j++){
			zone[j].R =  new Rect( zone[j-ZoneCount].R.x , zone[j-ZoneCount].R.y + zoneSize , zoneSize , zoneSize);
			zone[j].tri = new int[200000];
		}
		
		zone[zone.Length-1].R = new Rect( 0, 0, 0, 0);
		zone[zone.Length-1].tri = new int[200000];
		
		// assigne chaque triangle a une zone
		// si la zone contiens le premier point du triangle.
		// en repartissant les zone sur plusieurs Threads
					
		Thread[] tache = new Thread[8];		

		for ( int k = 0 ; k < 8; k++){			
			int K = k;
			tache[K] = new Thread(LaunchFin);
			tache[K].Start(K);
		}
		
		for ( int i = 0 ; i < 8 ; i++){
			tache[i].Join();			
		}
		createParcel();			
	
	}
	
	void LaunchFin(object K){
		
		int k = Convert.ToInt16(K);
		int start = k*8;
		int end = (k+1)*8 ;
		if( end == zone.Length-2){
			end +=1;
		}
		
		for ( int i = 0; i < TriCount; i++){
			
			if( tri[i].P1 < 3 || tri[i].P2 < 3 || tri[i].P3 < 3){  continue; }			
			
			if( point[tri[i].P1].y < 0 || point[tri[i].P2].y < 0 || point[tri[i].P3].y < 0){
				if( end == zone.Length-1){
					zone[zone.Length-1].tri[zone[zone.Length-1].triCount] = i;
					zone[zone.Length-1].triCount +=1;
				}
				continue; 			
			}
			
			Vector2 A = new Vector2(point[tri[i].P1].x,point[tri[i].P1].z)  ;			
			for ( int j = start ; j < end; j++){
				
				if ( zone[j].R.Contains(A)){	
	 				zone[j].tri[zone[j].triCount] = i;
					zone[j].triCount +=1;
		 			break;			
				}			
			}			
		}		
		
		for ( int i = start ; i < end ; i++){			
			
			Finalzone(i);
			if( i == zone.Length-2){
			Finalzone(i+1);	
			}			
		}	
	}
	
	void createParcel(){
		
		// création d'un gameobject par zone
		
		for ( int i = 0 ; i < zone.Length; i++){
			
		if( zone[i].triCount != 0){
			
			GameObject GO = new GameObject();
			GO.transform.position = Vector3.zero;			
			GO.name = "parcel " + i;
			GO.AddComponent("MeshFilter");
			GO.AddComponent("MeshRenderer");
			GO.renderer.material = mat;	
			Mesh mesh = GO.GetComponent<MeshFilter>().mesh;		
		  	mesh.Clear();	
				
			mesh.vertices = zone[i].Vert;
	  		mesh.colors32 = zone[i].Col;
	  		mesh.uv = zone[i].UV;
	  		mesh.triangles = zone[i].tri;    
	   		mesh.Optimize();
	   		mesh.RecalculateNormals();
			}	
		}		
	}
	
	void Finalzone(int k){
		
		// apres assignation des triangles a chaque zone
		// pour chaque tri réagence les points
		// pour qu'ils tournent tous dans le même sens
		// => chaque tri visble du même coté.
	
		int zpCount = 0;
		int ztCount = zone[k].triCount;
		int[] Tri = new int[ztCount*3];
		Vector3[] ZP = new Vector3[ztCount*3] ;
		Color32[] color = new Color32[ztCount*3]  ;
		Dictionary<int,int> Corr = new Dictionary<int,int>() ;
	
		for ( int i = 0 ;  i < ztCount ; i++){
			
			int I = zone[k].tri[i];
			
			int a = tri[I].P1;
			int b = tri[I].P2;
			int c = tri[I].P3;
			
			TRI triangle = new TRI(c,b,a);
			
			if( point[a].x> point[b].x && point[a].x > point[c].x){ 		triangle = new TRI(a,b,c);	}    		
   			else if( point[b].x> point[a].x && point[b].x > point[c].x){ 	triangle = new TRI(b,a,c);	}
			
			Vector2 A = new Vector2( point[triangle.P1].x ,point[triangle.P1].z);
			Vector2 B = new Vector2( point[triangle.P2].x ,point[triangle.P2].z);
			Vector2 C = new Vector2( point[triangle.P3].x ,point[triangle.P3].z);			
			Vector2 dirY = (B-A);   Vector2 dirZ = (C-A);			
			
   			float angleY = Vector2.Angle(new Vector2(0,1) , dirY );
   			float angleZ = Vector2.Angle(new Vector2(0,1) , dirZ );
			
			if( angleY > angleZ){	a = triangle.P1; b = triangle.P2 ; c = triangle.P3;	}
			else{					a = triangle.P1; b = triangle.P3 ; c = triangle.P2;	}				

			if( Corr.ContainsKey(a) == false){		
				color[zpCount] = point[a].color;
				ZP[zpCount] = new Vector3( point[a].x, point[a].y, point[a].z);
				Corr[a] = zpCount;	
				zpCount +=1;
			}		
			
			if( Corr.ContainsKey(b) == false){		
				color[zpCount] = point[b].color;
				ZP[zpCount] =  new Vector3( point[b].x, point[b].y, point[b].z);
				Corr[b] = zpCount;	
				zpCount +=1;			
			}
			
			if( Corr.ContainsKey(c) == false){		
				color[zpCount] = point[c].color;
				ZP[zpCount] =  new Vector3( point[c].x, point[c].y, point[c].z);
				Corr[c] = zpCount;	
				zpCount +=1;	
			}
			
			Tri[i*3] = Corr[a];	 	Tri[i*3 +1] = Corr[b] ;   	Tri[i*3 +2] = Corr[c];
			
		}		
		
		zone[k].tri = Tri;
		zone[k].triCount = ztCount*3;
		zone[k].Vert = new Vector3[zpCount];
		zone[k].Col = new Color32[zpCount]; 
		zone[k].UV = new Vector2[zpCount];
		
		for ( int i = 0 ; i < zpCount ; i++){
			
			if( ZP[i].y <0){ ZP[i].y -= 1.0f;}
			else if(ZP[i].y > 0) { ZP[i].y += 1.0f;}
			
			zone[k].Vert[i] = ZP[i] ;
			zone[k].Col[i] = color[i];
			zone[k].UV[i] = new Vector2(ZP[i].x , ZP[i].z)/20000.0f; 
		}	
	}
	
	void CreateEau(){
		
		// la derniere Zone contiens les points sous le niveaux de l'eau
		// dupliquer le mesh au gameObject Eau
		// Eau.scale.y = 0 ou deplacer chaque point a y = 0;
		
		if( Eau == null){ return;}
		int i = zone.Length-1;
		Mesh mesh = Eau.GetComponent<MeshFilter>().mesh;
				
		mesh.vertices = zone[i].Vert;
	  	mesh.colors32 = zone[i].Col;
	  	mesh.uv = zone[i].UV;
	  	mesh.triangles = zone[i].tri;    
	   	mesh.Optimize();
	   	mesh.RecalculateNormals();		
		
	}	
}
J'ai tenter de le commenter histoire d’indiquer le proces des fonctions ;-)
Image Image
------ Avant V.1 ----------- Apres V.2 ----

Image Image
------ Avant V.1 ----------- Apres V.2 ----

Image Image Image Image
-- affichage normal ------ affichage de zone ----- affichage parcours eau --- affichage rivière

Si vous avez des idées sur quoi ajouter/modifier/enlever je suis preneur. Avant de m'attaquer aux routes. :-D ::d
Vais voir aussi pour ajouter de l'érosion, pour gagner un peu en réalisme de topologie peut être.

______________________________________________________________
\_______________________ Impossible is nothing _______________________/

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

Re: [WIP] Simu Course réaliste + Map + Volant

Message par Alesk » 12 Sep 2018 12:13

Excellent ! Bravo :)

T'as beau dire être un "débutant", tu réalises des trucs vraiment complexes !
Je jette un oeil à ton code d'ici la fin de la semaine pour voir si j'y trouve des optimisations possibles ;)

djulio74
Messages : 432
Inscription : 19 Déc 2009 22:55
Contact :

Re: [WIP] Simu Course réaliste + Map + Volant

Message par djulio74 » 12 Sep 2018 18:05

Merci beaucoup Alesk. :-D :super:

bah écoute avec plaisir si tu veux y jeter un œil. il y a au début du script des petites consignes pour lui assigner ce qu'il a besoin. Mais j'ai tout de même ajouter des consigne en cas de manquant, pour pas avoir d'erreur.
Par contre ça presse pas, je vais m'absenter une quinzaine de jours alors t'as largement le temps.

Je viens de tester le truc en standAlone ( build .exe) plutôt que direct via unity, et c'est encore mieux niveaux perf. ça tourne dans les 160 kTri/s chez moi. Et dire qu'au tout début je me fixait 1 minute max pour la génération des poly, là ça fait du 7a 8 secondes. ::d

D'ailleurs si il y en a qui veulent bien tester sur leur machines pour un retour de perf, juste un mail en MP en j'envoi le standAlone ( 41 Mo)?

______________________________________________________________
\_______________________ Impossible is nothing _______________________/

Répondre

Revenir vers « Vos créations, jeux, démos... »