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

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

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

Message par djulio74 » 30 Août 2018 12:33

Salut a tous. Cela faisait une éternité que je n'avais pas posté ici. ^^
Je me suis un peu remis sur Unity ces derniers temps, et pour changer je suis resté sur une idée fixe de base : la simulation auto. lol. Pour ceux qui se souviennent, javais déjà fait un post ou deux sur le sujet.
Mais je suis totalement reparti de zéro, avec pas mal d'ajout, mais pas que :

Info importante , je suis sous unity 4.0, et charpentier donc unity par loisir en autodidacte

1 - utilisation de la magic formule ( pacejka 2002) pour l'adhérence des pneu( +130 paramètres).
2 - Collider + raycast pour le contact au sol ( configurable)
3 - train roulant simulé complet ( triangles, amortisseurs, fusées... chaque axe, chaque pivot)
4 - gestion traction( couple, inertie, frein moteur, 4x2 , 4x4 , différentiel avant-arrière-central, antipatinage, ABS)
5 - shader carrosserie perso, avec un fake realtime global illumination.
6 - procédural circuit.
7 - fabrication Vollant FFB : retour de force
8- Et plus a venir... (procedural map entre autre)

1 - Les Pneu avec Pacejka :

Pour ceux qui ne connaissent pas, les formules pour simuler l'adhérence des pneu sont des formules empirique : avec de machines et nombres de capteurs, les ingénieurs ont relevé les mesures des forces appliqué à un pneu dans toute les situations possibles, et ont cherché les équations permettant d’approcher au mieux les valeurs relevées. Les plus connue etant la "magic formula" de Hans Pacejka. Exempe
C'est cette formule que j'utilise dans ce projet. J'ai crée des fichier texte pour différent type de pneu avec tout les paramètres. Un script ( sur chaque roue) extrait les données (dun fichier) et fait les calculs en fonction de la charge sur le pneu, l'inclinaison de la roue par rapport au sol, angle de dérive du pneu( dérapage latéral) et le slip ratio ( patinage de la roue). le fixed TimeStep est a 0.001 (oui, les calculs sont fait 1000x par seconde , ^^)
J'ai fait un petit projet unity pour visualiser les courbes et l'influence de chaque changement dans les parametres.Je peux ainsi modifier le fichier texte directement avec celui ci :

Image

2 - Contact au sol :

il y a quelques années, j'avais testé les wheelcollider, vraiment déçu car rien de réaliste a mon gout, ou pas trouvé la bonne façon de faire.. ils ne tenaient pas compte du poids de la voiture, les courbes de friction latéral et longitudinal etaient indépendante et non combinée, pas de retour de force...
Ensuite j'avais testé les raycast. un par roue, du centre de celle ci, vers le bas. C’était pas trop mal, ça me permettait les relevé qu'il me fallait ( distance du sol, détection contact...) pour la magic formula. C’était suffisant oui, mais sur une route assez plate. Mais dès qu'il y avait un obstacle "saillant" ça coinçait. Par exemple, monter un trottoir, détectant un seul point de contact, l'angle du trottoir "pénétrait" la roue avant que celle ci ne monte dessus.
J'ai Donc crée un système un peu plus complexe pour palier ce problème.
Une roue comporte plusieurs box collider ( trigger ) de la largeur du pneu, et définissant le contour de celui ci. chacun avec un OnTriggerStay renvoyant l'info de contact ou non au script de la roue. et au lieu de faire un seul Raycast, il y en a plusieurs couvrant la portion du pneu en contact avec un obstacle. Chacun renvoyant ses infos ( distance sol, angle..etc), je fais la moyenne et calcul la magic formula. Je peux donc gérer plusieur contact en simultané ( par exemple la route en bas de la roue ET l'angle du trottoir que je touche)
Voila a quoi ça ressemble : (la "résolution" de la détection et paramétrable, ici 20 collider, résolution de 4 sur la largeur )

Image

3 - Train Roulant
Bon Ok, tout ça c'est bien, Mais bon, les roues fixes a la voiture, le seul amortissement serait alors celui des pneu ( oui, l’élasticité des pneu est simulée), donc a moins de monter des pneu de monster-truc, c'est un peu tape cul a conduire et pas très stable.. ^^.
Avant, mon unique raycast vertical me permettait de simuler en même les couple ressort/amortisseur, avec un déplacement des roues uniquement dans le plan vertical de la voiture, sans inclinaison par rapport à celle ci. Pas très réaliste..
Simulons donc les train roulant, d'autant plus que dans mes recherches j'ai appris qu'a centre de gravité égal, qu'a amortissement égal et qu'a voie et empattement égal, la variation de position de chaque point d'ancrage des trains roulant pouvaient avoir un effet considérable sur la prise de roulis et de tangage de la voiture, et sur la variation de l'angle de la roue par rapport au sol, et donc de l'adhérence des pneu. Comme pour les paramètres des pneu, tout est inscrit dans un fichier texte lu par un script. au lancement d'unity, la voiture est juste composé de sa carrosserie et d'une roue a instancier. Les script génère chaque pièce mobile en fonction du fichier, les places, crée tout les joint nécessaire, les limites etc.. c'est pas très visible mais ça donne ça :

Image

on y voit les point de chaque configurable joint. il y en a 8 par demi train ( par roue)
Les barre anti-roulis sont aussi générées, porr limiter la prise de roulis de la voiture en virage.

4 - transmission :

Pas grand chose a développer la dessus. je gère le moteur ( couple, vitesse, inertie, frein moteur..etc), ensuite il y a l’embrayage ( phase embrayé, débrayé, patinage, auto ou manuel), le boite de vitesse à 6 rapport a changement auto ou manuel, la transmission se fait en 4x2 ( traction ou propulsion) ou 4x4 (intégrale) et en fonction possède 1 ou 3 différentiels à glissement ajustable( du totalement libre à fixe). L'antipatinage et l'ABS sont ajustable également. Je récupère les données des pneu pour savoir le niveau de glissement de chaque pneu.

5 - shader carrosse :

Bon OK, ça se conduit, voir pilote, pas trop mal a mon gout pour l'instant. Mais j'aime bien aussi quand c'est un peu plaisant a l’œil. ;) Pour la partie modèle, c'est une Lamborghini gallardo, et c'est la seul chose qui viens du net déjà tout fait, donc je ne l'ai pas modélisée. je l'ai un peu dépouillée pour ne garder que le plus important ( vitres et carrosserie). Juste la base pour m'essayer au shader. une cubeMap dynamique et une simple reflection ne me convenaient pas vraiment, ou pas assez plutôt. hormis pour un miroir, le reflection d'un objet n'est pas constante en fonction de l'angle de vue. J'ai alors ajouter a la reflection un Fresnel. plus l'angle de vue est tangent a la surface plus le reflet est important.
Tout objet capte la lumière ambiante, et ayant l'idée de faire route et map de façon procédurale, les light probe ne me convenaient pas. Alors hop les mains dans le cambouis, ajoutons un petit effet global illumination au shader. Vu que grâce au rendu HDR, on peu capter un niveau de couleur supérieur a 1, je m'en sert. le shader procède a plusieurs itérations de blur ( floue) de la cubeMap qui me servent a "éclairer" la voiture. Pas trop mal pour un débutant :

Image Image Image Image

Ici la voiture est " a l'ombre" dans un tunnel, aucune source de lumière, juste quelques cubes au plafond avec un self Illumination diffuse.
et quelques autres vues :

Image Image Image

6 - La route :

Pour ne pas avoir a modéliser des km de route, je me suis dit que le procédurale pourrait m'aider. j'ai donc pris ce chemin, ou cette route. ^^
j'ai défini un profil pour le tracé (la route, trottoir, bas coté et mur) et le script génère aléatoirement des portions de route les un après les autres jusqu'a une certaines distance de la voiture, dans un sens comme dans l'autre. Plus on roule, plus la route se cré devant, mais aussi plus elle s'efface derrière. Ça peut aller de la petite courbe légère a l'épingle a demi tour, du plat comme de la cote, du vallonné ou champ de bosse ^^.
Du coup ce qui est fun est qu'on ne sait jamais a quoi s'attendre, comme une spéciale sans reconnaissance, et que même si on fait demi tour, la route ne sera jamais la même que celle qu'on a pris quelques secondes avant. ;)

Image Image

7 - Un volant home Made :

Jouer au clavier, pas toujours super simple, au gamePad, c'est déjà mieux, on se fait bien plaisir mais ça manque de réalisme, c'est pas un volant quoi! lol.
ah mais ça existe les volant pour jouer sur ordi, mais bon c'est du tout fait, cher pour moi et puis bon, faut avouer j'aime bien me compliquer la vie, et bricoler ailleurs que sur l'ordi. Quelques réflexion plus tard, le projet a murit dans ma tête, les idées sont la, il n'y a plus qu'a.. Je me met a la tache. Un petit a la casse du coin, je démonte et récupère un bloc de direction assisté de voiture (15€), ressort ma carte Arduino qui m'avait initié a la robotique mais laissé de coté par manque d'idées concrète. une bonne base déjà. Mince faut pouvoir récupérer la position du volant inGame, un petit tour sur le net, les vieilles imprimante sont source d’électronique parait-il. Un tout a la déchetterie et j'en ramène deux. démonte et récupère le encodeur rotatif a quadrature. Bon faut alimenter tout ça, je fouille et hop, retrouve une ancienne alim de PC, 12V 40A un peu faible mais devrait faire l'affaire en la modifiant un peu. Pour le Moteur, je désosse une visseuse 12V ramenée avec les imprimantes. Un bout d'aluminium et de tuyau pour le volant, quelques jours d'adaptations, de test et de code et voila un beau volant ( plus fonctionnel que beau.. ^^), utilisable avec unity et avec un couple de camion ( presque 80nM) et pour moins de 60€ :-D

Image Image Image

Image Image Image

Ça commence a faire une bonne tartine à lire pour un premier poste, J’espère qu'il y en aura quand même qui seront arrivé jusque là. ^^

attention spoiler :-D :
► Afficher le texte
:) :) Voilà pour aujourd'hui, pas mis d'exemple de code volontairement pour ne pas alourdir la chose. J’espère que le sujet vous intéressera. A vos Clavier!!!! ;-) ;-)

______________________________________________________________
\_______________________ Impossible is nothing _______________________/

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

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

Message par Alesk » 30 Août 2018 12:49

T'es un grand malade ! MERCI ! :super:

Avatar de l’utilisateur
db22
Messages : 742
Inscription : 31 Mars 2011 12:07

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

Message par db22 » 30 Août 2018 20:21

C'est juste énorme ! J'aime bravo ^ ^ tu es fou !Respect :merci:
Bienvenue !

Avatar de l’utilisateur
ZJP
Messages : 5745
Inscription : 15 Déc 2009 06:00

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

Message par ZJP » 31 Août 2018 03:41

Gros malade en effet. Chapeau bas!.

Le coup du bloc de direction assistée, je ne le connaissais pas. Génial. 8-)

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

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

Message par djulio74 » 31 Août 2018 08:52

Merci les coupains pour vos réponses. Oui je suis peut être malade en effet, j'adore me compliquer la vie. lol

Pour la direction assistée, c'est presque normal. J'ai fait vraiment beaucoup de recherche sur les volant DIY, pas tout écumé mais les principaux forum, site..etc et jamais vu de chose similaire. c'est une première mondiale ::d :hehe: :lol:

Même si c'est un projet que je traine de longue date et que certains point sont déjà bien avancé, j'ai bien conscience qu'il n'aboutira sans doute jamais. Pour un autodidacte et néophyte comme moi, j'ai sans doute visé trop haut, trop complexe, mais a vouloir faire compliqué, ça pousse a chercher, apprendre de nouvelles choses tout le temps, pis bon, en plus ça me permet d'entretenir ma "maladie", ma "folie" comme vous dites! :lol: :lol:

Je vais bientôt faire un petit recap sur ou j'en suis sur la création d'une map.

PS : il est pas un peu mort le forum? me suis baladé un peu partout et pas constaté de grande activité... C'est dommage ( remarque c'est un peu les vacances aussi.. lol)

______________________________________________________________
\_______________________ Impossible is nothing _______________________/

Avatar de l’utilisateur
Liven
Messages : 268
Inscription : 30 Nov 2017 01:48

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

Message par Liven » 01 Sep 2018 23:04

Sacré bouleau, j'ai hâte de voir tout ça en mouvement!

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

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

Message par djulio74 » 03 Sep 2018 09:43

Merci Liven. Je sais bien, faudrait que je fasse des vidéo. ça viendra t’inquiète. ;)

Bon, je vais tenter un peu d'expliquer la création de la map. du moins pour jusqu’où j'en suis. ^^.
L'idée est de faire une ile, assez grande. Ici la zone de travail de départ est un disque de 40 km de diamètre, sur laquelle l'ile peut être plus ou moins grande a la demande. J'utilise ici la triangulation de Delaunay pour créer tout ça.
Pourquoi? parce que je veux pouvoir choisir la densité du mesh en fonction des zones. pas besoin d'une grande résolution sous l'eau, et pouvoir augmenter la résolution autour des routes par exemple, et je ne voulais pas avoir de mesh style terrain d'unity qui est trop ordonné car je me servirais de vertex et edge pour tracer les routes.

pour la triangulation de Delaunay, ça deviens de plus en plus long a calculer plus on a de triangles. car pour chaque point qu'on ajoute, il faut vérifier dans les triangles existant ceux qui ne correspondent plus a loi de delaunay, les supprimer pour ajouter les nouveaux a la place. Avec plus d'un million de tri, je vous laisse imaginer le temps de génération de la map... :pleur4:
Au début je subdivisait la zone de travail en Rect, petit a petit par pallier, plus j’ajoutai de point. Mais ça me faisait encore quelques millier de triangle a vérifier pour chaque point ajouter. Déjà mieux certes. Je calculais les statistique pour chaque génération de map, et je tournait a environ 20k triangles de généré par seconde, et j'avais des erreur de topologie, de densité..etc. Aujourd'hui je suis a 110k tri/seconde sans aucune erreur.

je ne génère que des liste au départ, les mesh n'arrivent qu'a la fin. j'ai :
- point : une liste de Vector3, position de chaque point.
- pointColor : liste de couleur, correpondant aux point
- pointNext, liste de liste de int. pour chaque point, une list de int, correspondant a un point dans "point", j'y stock tout les point directement lié a un point par un edge.
- tri : liste de vector3, x,y, et z étant des int, référant à un point dans "point".
- triNext : liste de int, chaque int réfère a un triangle dans "tri". pour chaque point j'y stock les triangles qui ont dans x,y ou z le point en question.

Chaque liste est mis a jour a chaque insertion de point. C'est un peu barbare mais ça marche plutôt bien.
Voila un peu les étapes :

- Étape 1 :
création un triangle englobant toute la zone de travail. Ajout de points un par un avec un Random.Circle. A la condition que chaque point crée ne soit pas plus proche d'une certaines distance d'un autre point (var : densité). Et la à l'ancienne, je teste chaque triangle pour la loi de Delaunay. Chaque nouveaux pointColor est white.
Image Image

- Étape 2 :
le forme de l'ile. je choisit aléatoirement quelques point, passe leur pointColor a red, et quelques autre a blue. Avec des condition de distance par rapport au centre, ou a la périphérie du disque. Vu que pour chaque point, je connais ceux directement connecté, je propage la les couleur jusqu’à ce qu'il n'y a plus de blanc. Chaque point qui a un couleur différente de la sienne dans pointNext est ajouté a une nouvelle liste : Cote.

cette fois, pour ajouter des points, pas de Random.Circle. pour chaque triangle, si composé uniquement de rouge, j'ajoute un point au barycentre de celui ci, et au lieu de tester tout les tri pour Delaunay, je récupère juste les triNext de chaque point du triangle. je ne densifie donc uniquement l'ile et non le fond des océan. chaque pointColor ajouté est red.
Image Image

- Étape 3 :
Je sauvegarde dans un nouvelle list " Origine" la liste pointNext. elle me servira plus tard.
Et je répète la deuxième partie de l’étape 2.
Image Image

- Étape 4 :
Je cré l’élévation de l'ile : pour chaque point de l'ile ( rouge), si son altitude est a 0, je cherche le point de la cote le plus proche, et utilise la distance avec celui ci dans une petite tambouille de mon cru à base de perlin noise, de sinus..etc pour calculer sa position en y, donc son élévation. pour chacun de pointNext de ce point, j'utilise le mème point de la cote pour calculer la distance et ma petite tambouille. ^^
Ensuite encore une petite itération de la deuxième partie de l’étape 2.
Image Image

J'ai alors en moyenne 1.2M triangle ( million oui), 600k point, une altitude pour chaque point de l'ile ( altitude max de 3500m en moyenne). et troi couleur :
Rouge : terre , Bleu : Eau et Blanc : Cote.

- Étape 5 :
Vous vous souvenez de " origine" stocké a l’étape 3? il va me servir a calculer les cours d'eau. pour chaque point de origine ( donc ceux de l’étape 2, donc environ 18k), je cherche le point le plus bas et suis ainsi de suite le parcours j'usqu'a l’océan.
ça me permet d'en définir une valeur de "flux" pour chacun des points. plus il est grand plus il a d'eau qui passe.
pour chaque point de "origine" encore je lui défini un biome ( 13 biomes au total) en fonction de ce flux et de son élévation, lui attribut une couleur bien spécifique. Je propage la couleur de chacun des points de "origine" au points de l’étape 4 jusqu’à ne plus avoir de rouge, et en m’arrêtant aux cotes.
Image

- Étape 6 :

c'est là que je crée les mesh. ( je les ai crées a chaque étape ici pour montrer les couleurs)
plusieurs car j'ai 1.2M de triangle et 600k points, hors la limite est a 65k vertices comme vous savez tous. je cré 36 zones (6x6). et assigne chaque triangle à sa zone en fonction de sa position.( Rect.Contains). Et pour chaque triangle je réorganise l'ordre des points pour qu’ils soient tous dans le même sens de rotation.
pour chaque zone, je cré un gameobject avec son mesh.les UV sont juste la position des points en x et z.

Après mon premier essai de Shader pour la voiture, je me suis senti le courage d'en écrire un autre pour la map. :-D
Vu que j'ai 13 biomes, j'ai 13 textures. Mince a force de recherche sur Google, il n'est apparemant possible de mixer( blend) que 4 texture en se servant uniquement des vertex color. une texture par composant ( r,g,b,a), ou alors d'avantage mais il faut je me serve d'asset, et ce n'est pas ma philosophie. lol. Mais b***** de m**** fais c**** comment je vais faire, p**** ça doit bien être possible d'y arriver. vais pas me retrouver bloqué ici!! :rougefaché: Je sors le tableur excel, petit tableu de couleurs avec juste 0 ou 1 pour chaque composant, cherches quelques formules et bingo!! j'arrive a 11 possibilité, 11 textures juste avec de 0 et des 1 ( pour r,g,b,a), et encore plus en utilisant -1 pour a.
et voila le résultat :
Image
Non ce nes pas juste des couleurs mais bien texture. en zoomant un peu :
Image Image Image.
Et quelques vue, caméra a 1m80 du sol :
Image Image Image




Le script COMPLET de la génaration de la map :

Code : Tout sélectionner

#pragma strict
import System.Collections.Generic;

var materials : Material;
private var CAM : Transform;

private var Rayon = 20000.0;
private var Densite = 500.0;
private var Taille = 1.0;
private var seuilRiver = 40.0;

private var ALT =  false;
private var MIN = 0.0;
private var k : int;
private var Rand = 0.0;
private var MaxDist = 0;
private var MaxHeight = 0;
private var S = 0;

private var triTEMP : List.<int>;
private var tri : List.<Vector3>;
private var point : List.<Vector3>;
private var triNext : List.<List.<int> >;
private var pointNext : List.<List.<int> >;
private var pointColor 	: List.<Color32>;
private var	Cote : List.<int>;
private var NewPoint = Vector3.zero;
private var TRI = Vector3.zero;
private var VoisinBas : List.<int>;
private var	River : List.<int>;
private var Flux	: List.<float>;
private var originNext  : List.<List.<int> >;
private var originDist 	: List.<int>;
private var originHeight: List.<int>;
private var origin 		: List.<int>;

private var TropicalRainForest		= Color(1,0,0,0);
private var TropicalSeasonForest 	= Color(0,1,0,0);
private var GrassLand 				= Color(0,0,1,0);
private var SubTropicalDesert 		= Color(0,0,0,1);
private var TemperateRainForest 	= Color(1,1,0,0);
private var TemperateDecidousForest	= Color(0,1,1,0);
private var TemperateDesert			= Color(0,0,1,1);
private var Taiga					= Color(1,0,0,1);
private var ShrubLand				= Color(0,0,0,0);
private var Snow 					= Color(0,1,0,1);
private var Tundra					= Color(1,0,1,0);
private var Bare					= Color(-1,0,0,0);
private var Scorched				= Color(0,-1,0,0);

private var ZoneCount = 6.0;
private var zone : List.<Rect>;
private var zoneTri : List.<List.<Vector3> >;
private var zoneSize = 0.0;

private var Blue = Color32(0,0,255,100);
private var Red = Color32(255,0,0,100);
private var Green = Color32(0,255,0,100);
private var White = Color32(255,255,255,100);

function Start () {



var TP = Time.realtimeSinceStartup;

	tri = new List.<Vector3>();
	point = new List.<Vector3>();
	triNext = new List.<List.<int> >();
	pointNext = new List.<List.<int> >();
	triTEMP = new List.<int>();
	pointColor 	= new List.<Color32>();
	
	CreateBase();
	
	for ( var m = 0 ; m < 15000 ; m++){		
		AddPoint();
	}
	PointNEXT();
	AddColor();
	PropageColor();
	Border();
	Smooth1();
	
	
	Iteration();
	originNext = pointNext;
				
	Iteration();
	S = 1;
	Iteration();
	elevation();
	Iteration();
	

	
	Voisin();
	ActuOrigin();
	Biomes();
	PropageColor1();
	
	initialiseZONE();


	
print( Time.realtimeSinceStartup-TP);
print( " ratio : " + Mathf.Round(tri.Count/(Time.realtimeSinceStartup-TP)/10.0) /100.0 + " kPoly/s");
print(  (Mathf.Round(tri.Count/1000.0) /1000.0) + " M tri");
print(  (Mathf.Round(point.Count/10.0) /100.0) + " k point");

CAM = Camera.mainCamera.transform;
CAM.position = point[Random.Range( 3,point.Count-1)]+Vector3.up*1.8;
}

function Iteration(){

	ALT = !ALT;
	Densite *=0.5;
	AddTerre();
	AddTerre();
	PointNEXT();
	if( S > 0){
		
		propageCote();	 
		if( ALT == true){			
			propageCote(); 
		
		}	
		RemoveIsolate();
		
	}
	Smooth1();
	
}

function CreateBase(){

	var dp : int = 3;
	var espace = 2* Mathf.PI /3.0;
	
	for ( var i = 0 ; i < dp ; i ++){
		point.Add(Vector3( Mathf.Sin(i*espace)*Rayon*2.5 ,0,  Mathf.Cos( i*espace)*Rayon*2.5) );
		triNext.Add(new List.<int>() );
		pointColor.Add(Blue);	
	}
	
	TRI = Vector3(0,1,2);
	tri.Add(TRI );	
	var temp = tri.Count-1;
	triNext[TRI.x].Add(temp); triNext[TRI.y].Add(temp); triNext[TRI.z].Add(temp);
}


function AddPoint(){

	var XY = Random.insideUnitCircle*Rayon;
	NewPoint = Vector3(XY.x,0,XY.y);	
	triTEMP = new List.<int>();
	
	var Min = Mathf.Infinity;	
	for ( var i = 0 ; i < point.Count ; i++){
		var dist = (point[i] - NewPoint).sqrMagnitude;		
		if( dist < Densite*Densite){  return; }		
		if( dist < Min ){
			Min = dist;
			triTEMP = new List.<int>();
			triTEMP.AddRange(triNext[i]);
		}
	}	
	point.Add(NewPoint);
	triNext.Add(new List.<int>() );
	pointColor.Add(White);
	
	var Plist = new List.<int>();
	
	for (  i = 0 ; i < triTEMP.Count ; i++){
		TRI = tri[triTEMP[i]];
		if ( Plist.Contains(TRI.x) == false){  Plist.Add(TRI.x); }
		if ( Plist.Contains(TRI.y) == false){  Plist.Add(TRI.y); }
		if ( Plist.Contains(TRI.z) == false){  Plist.Add(TRI.z); }
	}
	
	for ( var j = 0 ; j < Plist.Count ; j++){
		var NEXT = triNext[Plist[j]];
		for ( var k = 0 ; k < NEXT.Count ; k++){
			if( triTEMP.Contains(NEXT[k]) == false){
				triTEMP.Add(NEXT[k]);
			}			
		}		
	}
			
	Remove();
}

function Remove(){	

	var segment = new List.<Vector2>();
	var PointAdd = point[point.Count-1];
	var DeleteTri = new List.<int>() ;
		
	for ( var i  = 0 ; i < triTEMP.Count ; i++){
	
		TRI = tri[triTEMP[i]];		var A = point[TRI.x];		var B = point[TRI.y];		var C = point[TRI.z];										

		var 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));
		var 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));
		
		var midpoint = Vector2( Cx,Cy);		
		
		var dist  = ((midpoint-Vector2(A.x , A.z) ).sqrMagnitude - (midpoint -Vector2(PointAdd.x ,PointAdd.z) ).sqrMagnitude);				
		
		if( dist >= 0){
			DeleteTri.Add(triTEMP[i]);	
			segment.Add(Vector2( TRI.x , TRI.y)) ;
			segment.Add(Vector2( TRI.x , TRI.z)) ;
			segment.Add(Vector2( TRI.z , TRI.y)) ;	
		}
	}
	
	triTEMP = new List.<int>();
	triTEMP=(DeleteTri);
	
	var TriToAdd = new List.<Vector3>();	
	var angle = 0.0;
	
	for ( i = 0 ; i < segment.Count ; i++){	
		var Seg = segment[i];
		var seul = true;			
		for ( var l = 0 ; l < segment.Count ; l++){			
			if( Seg.sqrMagnitude == segment[l].sqrMagnitude && i!=l){
				seul = false;
				break;		
			}		
		}		
				
		if( seul ){
			var cA = point[Seg.x] - NewPoint;
			var cB = point[Seg.y] - NewPoint;
			
			angle += Vector2.Angle(Vector2(cA.x,cA.z) ,Vector2(cB.x , cB.z) );
			TriToAdd.Add( Vector3(Seg.x , Seg.y , point.Count-1));	
		}
	}
	
	if( Mathf.Approximately( 360.0 ,angle) ){
	
	
		for ( var t = 0 ; t < triTEMP.Count ; t++){		
		
			var TRI1 = tri[triTEMP[t]];		
			var temp = triTEMP[t];
			TRI = TriToAdd[t];
			tri[temp] = TRI;
			
			if( TRI.x != TRI1.x){ triNext[TRI1.x].Remove(triTEMP[t]); triNext[TRI.x].Add(temp); } 
			if( TRI.y != TRI1.y){ triNext[TRI1.y].Remove(triTEMP[t]); triNext[TRI.y].Add(temp); } 
			if( TRI.z != TRI1.z){ triNext[TRI1.z].Remove(triTEMP[t]); triNext[TRI.z].Add(temp); } 

		}
	
		for ( t = triTEMP.Count ; t < TriToAdd.Count ; t++){	
			TRI = TriToAdd[t];
			tri.Add(TRI );	
			temp = tri.Count-1;
			triNext[TRI.x].Add(temp); triNext[TRI.y].Add(temp); triNext[TRI.z].Add(temp);	
		}
	}
	else{
		point.RemoveAt(point.Count-1);
		triNext.RemoveAt(triNext.Count-1);
		pointColor.RemoveAt(pointColor.Count-1);
	
	}			
}

function AddColor(){	
	
	for ( var i = 0 ; i < 35.0*Taille ; i++){			AddRed();	}
	for ( var j = 0 ; j < 10.0* (1.0-Taille) ; j++){	AddBlue();	}		
}

function AddRed(){

	var RD = Random.Range(0, point.Count-1);	
	if( point[RD].magnitude > Rayon* Taille){
		AddRed();
		return;
	}	
	pointColor[RD] = Red;
}

function AddBlue(){

	var RD = Random.Range(0, point.Count-1);	
	if( point[RD].magnitude < Rayon * Taille*0.9){
		AddBlue();
		return;
	}	
	pointColor[RD] = Blue;
}

function PropageColor(){

	for ( var i = 0 ; i < point.Count  ; i ++){	
		var next = pointNext[i];		
		for ( var j = 0 ; j < next.Count ; j++){	
			if( pointColor[next[j]].g == 255){			
				pointColor[next[j]] = pointColor[i];
			}				
		}	 
	}
	
	for ( var k = 0 ; k < point.Count ; k ++){
		if ( pointColor[k].g == 255){		
		PropageColor();
		return;		
		}	
	}
	
	for (  i = 0 ; i < point.Count  ; i ++){
		var Max = Mathf.Min(Rayon *0.9,  Rayon * Taille * 1.2);
		if( point[i].sqrMagnitude > (Max*Max)){
			pointColor[i] = Blue;
		}	
	}		
}

function Border(){

	Cote = new List.<int>();

	for ( var i = 0 ; i < point.Count ; i ++){	
		if( pointColor[i].r == 0){		
			for ( var k = 0 ; k < pointNext[i].Count ; k++){			
				if( pointColor[pointNext[i][k]].b == 0){
				pointColor[i] = White;
				Cote.Add(i);
				break;
				}
			}								
		}	
	}	
	RemoveIsolate();
		
}
function RemoveIsolate(){

	for ( var i = 0 ; i < Cote.Count ; i++){	
		var nb = 0;					
		for ( var j = 0 ; j <  pointNext[Cote[i]].Count ; j++){	
			
			if( pointColor[ pointNext[Cote[i]][j]].b == 0){
			nb = 1;
			break;
			}		
		}		
		if( nb == 0){
			pointColor[Cote[i]] = Blue;
		}			
	}	
	var TMP = new List.<int>();	
	for (  i = 0 ; i < Cote.Count ; i++){
		if( pointColor[Cote[i]] == White ){ TMP.Add(Cote[i]); }
	}	
	Cote = TMP;	
}

function propageCote(){	

	var TMP = new List.<int>();	
	for (var n = 0 ; n < Cote.Count ; n ++){	
			var TEMP = 	 pointNext[Cote[n]] ;	
		for ( var b = 0 ; b < TEMP.Count ; b ++){		
			if( pointColor[ TEMP[b]].b == 0){			
				 pointColor[TEMP[b]] = White;
				 point[TEMP[b]] = Vector3(point[TEMP[b]].x , 0 , point[TEMP[b]].z);
				 TMP.Add(TEMP[b]);
			}	
		}		
		pointColor[Cote[n]] = Blue;				
	}	
	Cote = TMP ;
}

function AddTerre(){


	var triCount = tri.Count;
	
	var MOY = Densite * Densite*3.0;	
	
	for ( var i = 0 ; i < triCount ; i++){
	
		TRI = tri[i];
				
		var Col = pointColor[TRI.x].b + pointColor[TRI.y].b + pointColor[TRI.z].b; 
		
		if( Col == 0){
					
			NewPoint = (point[TRI.x] + point[TRI.y] + point[TRI.z])/3.0;			
			var dist1 = (point[TRI.x] - NewPoint);
			var dist2 = (point[TRI.y] - NewPoint);
			var dist3 = (point[TRI.z] - NewPoint);
			
			if( (dist1.sqrMagnitude +dist2.sqrMagnitude + dist3.sqrMagnitude) > MOY){			

				var triTEMP1 = new List.<int>();
				triTEMP1.AddRange(triNext[TRI.x]);
				triTEMP1.AddRange(triNext[TRI.y]);
			
				triTEMP = new List.<int>();
				for ( var j = 0 ; j < triTEMP1.Count ; j++){
					if( triTEMP.Contains(triTEMP1[j]) == false){
						triTEMP.Add(triTEMP1[j]);
					}			
				}
						
				point.Add(NewPoint);
				triNext.Add(new List.<int>() );
				pointColor.Add(Red);		
				Remove();
			}
			
		}
	}
}

function Smooth(){

var Se = Rayon*Rayon*0.9;

	for ( var l = 0 ; l < point.Count  ; l ++ ){
	
		var PL = point[l];		
				
		if(pointColor[l].g == 0 && PL.sqrMagnitude < Se){
		
			var mul = 0.5 ;
		
			var POINT = PL*mul;
			var Next = 	pointNext[l];
					
			for ( var j = 0 ; j < Next.Count ; j ++){
				POINT +=  point[Next[j]] ;
			}			
			POINT /= Next.Count+mul;
			point[l] = POINT ;		
		}		
	}
}

function Smooth1(){	
	for ( var l = 0 ; l < Cote.Count  ; l ++ ){	
		var dist = Vector3.zero;
		var next = pointNext[Cote[l]];	
		for( var i = 0 ; i < next.Count ; i++){											
			dist += (point[Cote[l]] - point[next[i]]) * (pointColor[next[i]].g/255) ;			
		}		
		point[Cote[l]] -= dist *0.35;
	}	
	Smooth();	
}

function PointNEXT(){

	pointNext = new List.<List.<int> >();
	
	for ( var j = 0 ; j < point.Count ; j++){		
		pointNext.Add(new List.<int>() );	
	}
	for ( var i = 0 ; i < tri.Count ; i++){	
		var TRI = tri[i];
		var X = pointNext[TRI.x];	var Y = pointNext[TRI.y];	var Z = pointNext[TRI.z];			
		if( X.Contains(TRI.y) == false){	pointNext[TRI.x].Add( TRI.y);	}		
		if( Y.Contains(TRI.x) == false){	pointNext[TRI.y].Add( TRI.x);	}		
		if( X.Contains(TRI.z) == false){	pointNext[TRI.x].Add( TRI.z);	}
		if( Z.Contains(TRI.x) == false){	pointNext[TRI.z].Add( TRI.x);	}
		if( Z.Contains(TRI.y) == false){	pointNext[TRI.z].Add( TRI.y);	}
		if( Y.Contains(TRI.z) == false){	pointNext[TRI.y].Add( TRI.z);	}				
	}	
}

function elevation(){

	var RAYON = Rayon * Rayon;
	Rand = Random.Range(10.0,500.0);	

	for ( var i = 0 ; i < point.Count ; i++){	
		var Pi = point[i];
		if( pointColor[i].b ==0 && Pi.y == 0){
			var Min = RAYON;
			var proche : int;	
			
			for ( var j = 0 ; j < Cote.Count ; j+= 5){			
				var dist = (Pi - point[Cote[j]]).sqrMagnitude;
				if( dist < Min){ Min = dist; proche = Cote[j]; }			
			}
			
			MIN = Min;
			k = i;
			elevation1();
			
			
			var Next = pointNext[i];
			for ( j = 0 ; j < Next.Count ; j ++){
				k = Next[j];
				if( pointColor[k].b == 0 && point[k].y ==0 ){
					MIN = (point[proche]-point[k]).sqrMagnitude;					
					elevation1();
				}			
			}
			
		}
	}
}

function elevation1(){
	
	var TEMP = point[k];
	MIN = Mathf.Sqrt(MIN);
			
	var Perlin = 0.0;			
	var prev = 1.0;
	var tot = 0.0;
	var X = (TEMP.x/16000+ Rand);
	var Z = (TEMP.z/16000+ Rand);
	
	var inv = 1.0;
				
	for ( var p = 1.0 ; p < 60; p*=2.4){
				
		var P = 1.0/(p -0.15);
		var test = Mathf.PerlinNoise(X*p * inv , Z*p *inv )*prev   ;				
		test = (0.5-Mathf.Abs( test-0.5) )*(2.1+0.5*P)  ;						
		prev = Perlin*P + test ;				
		Perlin += (test*test)*P;				
		tot += P;	
		
		inv = -inv;					
	}	
				
	Perlin /= tot;					
	MIN *=0.000055;	
				
	if( MIN< 0.155){
		point[k] = Vector3( TEMP.x ,Perlin* MIN*MIN*20000.0 , TEMP.z);			
	}
	else{
		point[k] = Vector3( TEMP.x ,Perlin* (Mathf.Sqrt(MIN*1.5)-0.36205) *4000.0, TEMP.z);		
	}
}

function Voisin(){

	Flux = new List.<float>();
	VoisinBas =  new List.<int>();
		
	for( var i = 0 ; i < originNext.Count ; i++){		
		var NEXT = originNext[i];
		var bas = i;		
		for ( var j = 0 ; j < NEXT.Count ; j ++){
			if( point[NEXT[j]].y < point[bas].y){
				bas = NEXT[j];			
			}	
		}
		VoisinBas.Add(bas);
		Flux.Add(1.0);
	}
	
	for(  i = 0 ; i < Flux.Count ; i++){
		k = i;
		FluxAdd();			
	}
	River = new List.<int>();
	for(  i = 0 ; i < Flux.Count ; i++){
		if( Flux[i] > seuilRiver){
			River.Add(i);
		}
	}			
}

function FluxAdd(){	
	
	if( k != VoisinBas[k]){
		Flux[VoisinBas[k]] += 1.0;
		k = VoisinBas[k];
		FluxAdd();
	}
}

function ActuOrigin(){

	MaxDist = 0;
	MaxHeight = 0;	
	
	var newOrigin =  new List.<int>();
	originDist =  new List.<int>();
	originHeight =  new List.<int>();
	
	var MIN = Rayon*Rayon;
	
	for ( var i = 0 ; i < originNext.Count ; i++){
	
		if( point[i].y > 0){
						
			newOrigin.Add(i);
			var POINT = point[i];
			
			var Min = MIN;
			
			for ( var j = 0 ; j < Cote.Count ; j+=20 ){
				
				var dist = (point[Cote[j]] - POINT).sqrMagnitude;					
				if ( dist < Min){ Min = dist;}						
			}			
			
			for (  j = 0 ; j < River.Count ; j++ ){
				
				dist = (point[River[j]] - POINT).sqrMagnitude*0.6;					
				if ( dist < Min){ Min = dist;}	
									
			}
			originDist.Add(Mathf.Sqrt(Min));
			var height = point[i].y;
			originHeight.Add(height);			
			if( height> MaxHeight){ MaxHeight = height;}
			if( Min> MaxDist){ MaxDist = Min;}		
		}
	}	
	origin = newOrigin;
	print( MaxHeight + " m");
	
}

function Biomes(){
	
	MaxHeight = Mathf.Max( MaxHeight, 2800.0);
	MaxDist = Mathf.Sqrt(MaxDist);

	for ( var i = 0 ; i < origin.Count ; i++){
	
		var heigh = originHeight[i];
		var dist = originDist[i];
	
		var POINT = origin[i];
			
		if( heigh < MaxHeight/4){			
			if( dist < MaxDist/3){				pointColor[POINT] = TropicalRainForest;		}
			else if( dist < MaxDist/3*2){		pointColor[POINT] = TropicalSeasonForest;	}
			else if( dist < MaxDist/6*5){		pointColor[POINT] = GrassLand ;				}
			else{								pointColor[POINT] = SubTropicalDesert;		}		
		}
			
		else if( heigh < MaxHeight/2){		
			if( dist < MaxDist/6){				pointColor[POINT] = TemperateRainForest;	}
			else if( dist < MaxDist/2.0){		pointColor[POINT] = TemperateDecidousForest;}
			else if( dist < MaxDist/6*5){		pointColor[POINT] = GrassLand;				}
			else{								pointColor[POINT] = TemperateDesert;		}				
		}
			
		else if( heigh < MaxHeight/4*3){
			if( dist < MaxDist/3){				pointColor[POINT] = Taiga;					}
			else if( dist < MaxDist/3*2){		pointColor[POINT] = ShrubLand;				}
			else{								pointColor[POINT] = TemperateDesert;		}
		}
			
		else if( heigh < MaxHeight/4*3.8){
			if( dist < MaxDist/1.5){			pointColor[POINT] = Snow;					}
			else if(  dist < MaxDist/3*2.2){	pointColor[POINT] = Tundra;					}
			else if(  dist < MaxDist/6*5){		pointColor[POINT] = Bare;					}
			else{								pointColor[POINT] = Scorched;				}	
		}		
		else{
			pointColor[POINT] = Snow;
		}		
	}
	
	var COUNT = Cote.Count*3;
	
	for ( var c = 0 ; c < COUNT ; c++){
	
		pointColor[Cote[c]] = SubTropicalDesert;
		
		var NEXT = pointNext[Cote[c]];
		var col = SubTropicalDesert;
		
		for ( var j = 0 ; j < NEXT.Count ; j++ ){
			var J = NEXT[j];
			if( pointColor[J].r == 255){
				pointColor[J] = col;
				Cote.Add(J);
			}	
		}	
	}
}

function PropageColor1(){
	
	for ( var i = 0 ; i < origin.Count ; i++ ){
		 
		var NEXT = pointNext[origin[i]];
		var col = pointColor[origin[i]];
		
		for ( var j = 0 ; j < NEXT.Count ; j++ ){
			var J = NEXT[j];
			if( pointColor[J].a == 100){
				pointColor[J] = col;
				origin.Add(J);
			}	
		}
	}

}

function initialiseZONE(){

	zoneSize = (Rayon*2.0/ZoneCount);
	zone = new List.<Rect>();	
	zoneTri = new List.<List.<Vector3> >();

	for ( var i = 0 ; i < ZoneCount ; i++){	
		zone.Add( new Rect(-Rayon + zoneSize*i, -Rayon ,  zoneSize,zoneSize));
		zoneTri.Add( new List.<Vector3>() );
	}
	
	for ( var j = ZoneCount ; j < ZoneCount*ZoneCount ; j++){
		zone.Add( new Rect( zone[j-ZoneCount].x , zone[j-ZoneCount].y + zoneSize , zoneSize , zoneSize));
		zoneTri.Add( new List.<Vector3>() );
	}	
	
	for ( var m = 0 ; m < tri.Count ; m++){		
		var TR = tri[m];
		var A = point[TR.x] ; 
		
		if( TR.x < 3 || TR.y < 3 || TR.z < 3){ continue; }
														
		for ( var a = 0 ; a < zone.Count ; a++){						
			if ( zone[a].Contains(Vector2(A.x , A.z))){	
 				zoneTri[a].Add(TR);
	 			break;			
			}							
		}
	}
	
	for ( k = 0 ; k < zone.Count ; k++){
		Finalzone();
	}
	
}

function Finalzone(){


	
	var GO = new GameObject();
	GO.transform.position = Vector3.zero;
	GO.name = "parcel " + k;
   	GO.AddComponent("MeshFilter");
    GO.AddComponent("MeshRenderer");
    GO.renderer.material = materials;
    var mesh : Mesh = GO.GetComponent(MeshFilter).mesh;

    mesh.Clear();

	var ZP = new List.<Vector3>() ;
	var zoneColor = new List.<Color32>() ;
	var ZT = zoneTri[k];
	var Tri = new int[ZT.Count*3];
	var Corr = new Dictionary.<int,int>() ;

	
	for ( var i = 0 ; i < ZT.Count ; i++){
		var TR = ZT[i];
		var A = point[TR.y] ;
		var B = point[TR.z] ;
		var C = point[TR.x] ;
		
		if( Corr.ContainsKey(TR.x) == false){		
			zoneColor.Add(pointColor[TR.x]);
			ZP.Add(C);
			Corr[TR.x] = ZP.Count -1;			
		}		
		
		if( Corr.ContainsKey(TR.y) == false){		
			zoneColor.Add(pointColor[TR.y]);
			ZP.Add(A);
			Corr[TR.y] = ZP.Count -1;			
		}
		
		if( Corr.ContainsKey(TR.z) == false){		
			zoneColor.Add(pointColor[TR.z]);
			ZP.Add(B);
			Corr[TR.z] = ZP.Count -1;	
		}				
		
		var zt = Vector3( Corr[TR.x] , Corr[TR.y] , Corr[TR.z]);
   		var Va = ZP[zt.x]; var Vb = ZP[zt.y]; 	var Vc = ZP[zt.z];
   		
   		TR = Vector3(zt.z,zt.x,zt.y); 
   		  		
   		if( Va.x> Vb.x && Va.x > Vc.x){ 			TR = Vector3(zt.x,zt.y,zt.z); 	}    		
   		else if( Vb.x> Va.x && Vb.x > Vc.x){ 		TR = Vector3(zt.y,zt.z,zt.x); 	}
	
   		var dirY = ZP[TR.y] - ZP[TR.x];   	var dirZ = ZP[TR.z] - ZP[TR.x];   		
   		var angleY = Vector2.Angle(Vector2(0,1) , 	Vector2(dirY.x , dirY.z) );
   		var angleZ = Vector2.Angle(Vector2(0,1) , 	Vector2(dirZ.x , dirZ.z) );
   		
   		if( angleY > angleZ){	Tri[i*3] = TR.x;	Tri[i*3 +1] = TR.y;   	Tri[i*3 +2] = TR.z;	}
   		else{   				Tri[i*3] = TR.x;   Tri[i*3 +1] = TR.z;	Tri[i*3 +2] = TR.y;	}						
	}
	
	var Vert = new Vector3[ZP.Count];
	var UV = new Vector2[ZP.Count];
    var Col = new Color32[ZP.Count];    
    
    for ( i = 0 ; i < ZP.Count ; i++){
    	Vert[i] = ZP[i]; 
    	UV[i] = Vector2(ZP[i].x , ZP[i].z)/20000.0; 
    	Col[i] = zoneColor[i]; 
    }
    
    mesh.vertices = Vert;
  	mesh.colors32 = Col;
  	mesh.uv = UV;
  	mesh.triangles = Tri;    
   	mesh.Optimize();
   	mesh.RecalculateNormals();
	
	
}

Le shader basique mixant 11 couleurs :

Code : Tout sélectionner

  
  Shader "Example/Custom Vertex Data" {
    Properties {
    	_Phong ("Phong Strengh", Range(0,1)) = 0.5
    	 _EdgeLength ("Edge length", Range(2,50)) = 5
		_MainTex1 ("TropicalRainForest", 2D) = "white" {}
		_MainTex2 ("TropicalSeasonForest", 2D) = "white" {}
		_MainTex3 ("GrassLand", 2D) = "white" {}
		_MainTex4 ("SubTropicalDesert", 2D) = "white" {}
		_MainTex5 ("TemperateRainForest", 2D) = "white" {}
		_MainTex6 ("TemperateDecidousForest", 2D) = "white" {}
		_MainTex7 ("TemperateDesert", 2D) = "white" {}
		_MainTex8 ("Taiga", 2D) = "white" {}
		_MainTex9 ("ShrubLand", 2D) = "white" {}
		_MainTex10 ("Snow", 2D) = "white" {}
		_MainTex11 ("Tundra", 2D) = "white" {}

    }
    SubShader {    

      	Tags { "RenderType" = "Opaque" }
      	
      	 LOD 300
      	CGPROGRAM
      	#pragma surface surf Lambert vertex:vert 
     	#pragma target 5.0
            
      struct Input {
          float2 uv_MainTex1;                    
          half4 COL;   
          half4 COL1;  
          half4 COL2;  
          half4 COL3;     
          half4 couleur; 
      }; 
           
            
      void vert (inout appdata_full v, out Input o) {
          UNITY_INITIALIZE_OUTPUT(Input,o);
          o.COL.r = max(v.color.r-v.color.b*v.color.b-v.color.g*v.color.g-v.color.a*v.color.a ,0.0) ;
          o.COL.g = max(v.color.b-v.color.r*v.color.r-v.color.g*v.color.g-v.color.a*v.color.a ,0.0) ;
          o.COL.b = max(v.color.g-v.color.r*v.color.r-v.color.b*v.color.b-v.color.a*v.color.a ,0.0) ;
          o.COL.a = max(v.color.a-v.color.r*v.color.r-v.color.g*v.color.g-v.color.b*v.color.b ,0.0) ;
          o.COL1.r = v.color.r * v.color.g;
          o.COL1.g = v.color.g * v.color.b;
          o.COL1.b = v.color.b * v.color.a;
          o.COL1.a = v.color.r * v.color.a;
          o.COL2.r = max(1.0-v.color.r*v.color.r-v.color.b*v.color.b-v.color.g*v.color.g-v.color.a*v.color.a ,0.0) ;
          o.COL2.g = v.color.g * v.color.a;
          o.COL2.b = v.color.r * v.color.b;
          o.couleur = v.color;
      }      
      
      sampler2D _MainTex1;
      sampler2D _MainTex2;
      sampler2D _MainTex3;
      sampler2D _MainTex4;
      sampler2D _MainTex5;
      sampler2D _MainTex6;
      sampler2D _MainTex7;
      sampler2D _MainTex8;
      sampler2D _MainTex9;
      sampler2D _MainTex10;
      sampler2D _MainTex11;
      
      void surf (Input IN, inout SurfaceOutput o) {
      
		half3 Col1 = (IN.COL.r) * tex2D (_MainTex1, IN.uv_MainTex1).rgb;
		half3 Col2 = (IN.COL.g) * tex2D (_MainTex2, IN.uv_MainTex1).rgb;
		half3 Col3 = (IN.COL.b) * tex2D (_MainTex3, IN.uv_MainTex1).rgb;
		half3 Col4 = (IN.COL.a) * tex2D (_MainTex4, IN.uv_MainTex1).rgb;
		half3 Col5 = (IN.COL1.r) * tex2D (_MainTex5, IN.uv_MainTex1).rgb;
		half3 Col6 = (IN.COL1.g) * tex2D (_MainTex6, IN.uv_MainTex1).rgb;
		half3 Col7 = (IN.COL1.b) * tex2D (_MainTex7, IN.uv_MainTex1).rgb;
		half3 Col8 = (IN.COL1.a) * tex2D (_MainTex8, IN.uv_MainTex1).rgb;
		half3 Col9 = (IN.COL2.r) * tex2D (_MainTex9, IN.uv_MainTex1).rgb;
		half3 Col10 = (IN.COL2.g) * tex2D (_MainTex10, IN.uv_MainTex1).rgb;
		half3 Col11 = (IN.COL2.b) * tex2D (_MainTex11, IN.uv_MainTex1).rgb;
		
		// pour afficher les textures : //
		o.Albedo = Col1 + Col2 + Col3 + Col4 + Col5 + Col6 + Col7 + Col8 + Col9 + Col10 + Col11;
		
		// pour afficher les Vertex  Color : //
		//o.Albedo = IN.couleur;

      }
      ENDCG
    }
    
    Fallback "Diffuse"
  }

  
To Do List :
- faire l'élévation pour le fond des océans;
- ajouter l'eau;
- travailler les textures;
- mixer plusieurs textures par biome avec masque par exemple;
- tracer-modéliser des routes;
- ajouter des détails;
- réussir à ajouter la tesselation a mon shader.
- ETC etc..

Oh bah en voilà encore une bonne tartine d'écrite. ::d ::d
en espérant avoir été asse clair.


principal source d'inspiration

______________________________________________________________
\_______________________ Impossible is nothing _______________________/

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

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

Message par Alesk » 03 Sep 2018 09:58

ça déchire tout !
Je vais créer une nouvelle religion et recruter des adeptes pour te vénérer :super:

Pour ce qui est de la vitesse de calcul, tu devrais jeter un oeil du côté des threads et/ou des job systems présents dans la dernière version d'unity.

https://unity3d.com/fr/unity/features/job-system-ECS

Je suis sûr qu'il y a moyen de diviser par 3 ou 4 le temps de génération de ton île.

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

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

Message par djulio74 » 03 Sep 2018 10:06

:hehe: :hehe: ::d ::d Ah ouais une religion carrément!! ^^

pour les threads je suis justement en train de regarder. Je suis sur la version 4.0 de unity mais il y a déjà les threads.
Les soucis c'est que presque jusqu'a la fin, le script marche de façon incrémental, j'ajoute un à un des points et vérifie avec ce qui existe déjà, et que chaque donnée est modifiée a chaque création de point. Faut je test mais j'ai peur que si un threads ajoute un point et qu'un autre est en train d'utiliser ds données modifiées par le premier threads ça fasse conflit..
La au final je suis vers 85k tri/seconde, mais avant la création des mesh je suis a plus de 100.. Mais les threads ne permettent pas l'instanciation, ni la modification de mesh..
Faut creuser.

D'ailleurs je crois c'est un de tes posts ici qui m'as mis sur la voie des threads.

edit : de plus comme tu peux le voir je code en javascript..
edit : 86k tri.sec ça me donne un temps de 13-14seconde de génération pour 1.2M tri..

______________________________________________________________
\_______________________ Impossible is nothing _______________________/

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

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

Message par Alesk » 03 Sep 2018 10:13

Oui j'avais déjà posté au sujet des threads, faut que je fouille.

Pour en tirer partie dans le cas qui t'intéresse, il ne faut pas essayer de bosser en parallèle sur les mêmes données, car oui il peut il y avoir des conflits d'accès... mais plutôt segmenter chaque étape du traitement sur plusieurs thread.

Exemple : tu as une boucle qui fait un traitement "simple" sur un tableau de 1000 éléments, et 4 threads à ta disposition.

Le premier thread traitera les éléments de 0 à 249, le second de 250 à 499, le troisième de 500 à 749 et le dernier de 750 à 999.
Et bim, tu as divisé ton temps de traitement par 4 ;)
Ainsi, chaque thread ne touche qu'à sa portion du tableau, sans aller taper chez le voisin.

J'avais utilisé cette technique pour mon asset de fumée, où j'avais dû créer mon propre moteur de particules.

ça ne peut pas s'appliquer partout, mais quand c'est possible autant en profiter. Et dans les cas où ce n'est pas possible, une fois qu'on a cette méthode en tête, ça permet d'éventuellement aborder le problème sous un autre angle, et finalement le rendre compatible avec les threads ;)

Bon courage !

Sinon, pourquoi rester sur Unity 4 ?

Répondre

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