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...
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.
- É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.
- É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.
- É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.
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.
- É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.
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!!
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 :
Non ce nes pas juste des couleurs mais bien texture. en zoomant un peu :
.
Et quelques vue, caméra a 1m80 du sol :
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.
en espérant avoir été asse clair.
principal source d'inspiration