I. Introduction▲
Alexander Birke (fondateur du studio Out Of Bounds Games) a donné une conférence lors du Unite Europe 2016 sur la génération procédurale de modèle 3D.
II. Vidéo▲
Unite Europe 2016 - La puissance des modèles procéduraux
III. Résumé▲
Au cours de cette conférence, Alexander Birke montre la puissance de la génération procédurale de modèle 3D. En effet, son jeu (premier jeu du studio Out Of Bounds Games) utilise grandement cette technique.
III-A. Pourquoi choisir la génération procédurale de modèle ?▲
Alexander Birke présente les intérêts de la génération procédurale de modèle en trois catégories :
- le contenu généré par le joueur (Spore) ;
- des mécanismes de jeu unique ;
- la génération procédurale de niveau/monde.
III-B. Les bases▲
Un modèle est constitué de points (sommets) connectés en triangles. Suivant le matériel que vous voulez appliquer sur votre modèle, vous devez aussi fournir des informations pour les normales, les coordonnées de textures… pour chaque sommet.
Dans Unity, vous avez des composants MeshFilter (stockage du modèle) et MeshRenderer (affichage du modèle), et un script pour générer le modèle.
III-B-1. Créer un triangle▲
Voici le code pour générer un triangle :
void
Start
(
)
{
Mesh mesh =
new
Mesh
(
);
// assigner les sommets
Vector3[]
vertices =
new
Vector3[
3
];
vertices[
0
]
=
new
Vector3
(-
1
,
-
1
,
0
);
vertices[
1
]
=
new
Vector3
(
0
,
0
.
8f
,
0
);
vertices[
2
]
=
new
Vector3
(
1
,
-
1
,
0
);
mesh.
vertices =
vertices;
// assigner les triangles
int
[]
triangles =
new
int
[
3
]
{
0
,
1
,
2
};
mesh.
triangles =
triangles;
GetComponent<
MeshFilter>(
).
mesh =
mesh;
}
Ensuite, si vous souhaitez indiquer au moteur quelle est l'orientation de votre modèle (utile pour l'ombrage), vous devez lui indiquer les normales des sommets :
Vector3[]
normals =
new
Vector3[
3
];
normals[
0
]
=
Vector3.
back;
normals[
1
]
=
Vector3.
back;
normals[
2
]
=
Vector3.
back;
mesh.
normals =
normals;
Évidemment, vous pouvez rajouter des couleurs :
void
Update
(
)
{
Color[]
colors =
new
Color[
3
];
float
offset =
Time.
time *
speed;
colors[
0
]
=
ColorFromHue
(
0
+
offset);
colors[
1
]
=
ColorFromHue
(
120
+
offset);
colors[
2
]
=
ColorFromHue
(
240
+
offset);
mesh.
colors =
colors;
}
Vous pouvez aussi utiliser des octets à la place des nombres flottants. Cela peut vous permettre d'améliorer les performances en compactant les données à envoyer au GPU.
Toutefois, les couleurs de sommets ne sont pas courantes. On préférera certainement utiliser des textures. Pour cela, il faut indiquer à Unity comment appliquer la texture à notre modèle :
// assigner des coordonnées de texture
Vector2[]
uvs =
new
Vector2[
4
];
uvs[
0
]
=
new
Vector2
(
0
,
0
);
uvs[
1
]
=
new
Vector2
(
0
,
1
);
uvs[
2
]
=
new
Vector2
(
1
,
1
);
uvs[
3
]
=
new
Vector2
(
1
,
0
);
mesh.
uv =
uvs;
Finalement, votre modèle sera constitué de plusieurs triangles. Pour cela, il faut indiquer comment les sommets sont connectés pour former des triangles à l'aide des indices. Voici le code pour générer les indices d'un plan :
void
GenerateTriangles
(
)
{
int
[]
triangles =
new
int
[(
width -
1
) *
(
width -
1
) *
6
];
int
triangleIndex =
0
;
for
(
int
x =
0
;
x <
width -
1
;
x++
)
{
for
(
int
y =
0
;
y <
width -
1
;
y++
)
{
int
vertexIndex =
x *
width +
y;
triangles[
triangleIndex +
0
]
=
vertexIndex;
triangles[
triangleIndex +
1
]
=
vertexIndex +
width;
triangles[
triangleIndex +
2
]
=
vertexIndex +
width +
1
;
triangles[
triangleIndex +
3
]
=
vertexIndex;
triangles[
triangleIndex +
4
]
=
vertexIndex +
width +
1
;
triangles[
triangleIndex +
5
]
=
vertexIndex +
1
;
triangleIndex +=
6
;
}
}
mesh.
triangles =
triangles;
}
III-C. Exemples de génération procédurale▲
À l'aide de la génération procédurale, vous pouvez :
- créer un monde 2D (jeu de plates-formes) s'enroulant sur lui-même ;
- dessiner des lasers qui rebondissent sur les murs ;
- gérer des lumières à travers un modèle et une texture ;
- générer des niveaux aléatoirement (triangulation de Delaunay).
III-D. Débogage▲
Pour déboguer votre modèle, faites en sorte que vous puissiez le voir dans le moteur. Pour cela, vous pouvez utiliser les classes Gizmos et Debug. Aussi, il est probable que si vous ne voyez pas votre modèle, c'est qu'il n'est pas positionné là où vous le souhaitez : tournez la caméra. Finalement, passez en mode fil de fer.
III-E. Optimisation▲
III-E-1. Modèle statique▲
La fonction Mesh.Optimize n'a aucun effet. Vous devez gérer vous-même l'optimisation du modèle.
Une technique pour optimiser le rendu est d'utiliser le batching à travers StaticBatchingUtility. Ainsi vous rassemblerez le rendu de plusieurs modèles en un appel de rendu.
De même, si vos modèles ne se cachent pas les uns des autres, vous pouvez combiner vos modèles en un seul avec Mesh.CombineMeshes.
III-E-2. Modèle dynamique▲
Avec la fonction Mesh.MarkDynamic, vous pouvez indiquer à la couche de rendu bas niveau que vos modèles vont souvent être modifiés.
Aussi, il est possible d'accélérer le rendu en créant un double tampon pour les modèles. En contrepartie, cela utilise plus de mémoire.
Il est possible d'envoyer directement des Lists au travers de Mesh.SetVertices pour définir les propriétés des modèles. Cela est plus rapide que d'utiliser des tableaux.
N'oubliez pas le frustum culling : n'affichez pas les choses hors de l'écran.
Si vos modèles se déplacent beaucoup, il peut être préférable d'utiliser un skinned modèle.
Avec les CPU multicœurs, il est évident de penser à générer les modèles en utilisant l'ensemble des cœurs de la machine. Toutefois, la bibliothèque Unity n'est pas fiable en multithread. Mais, il est possible de contourner cela pour la génération des sommets et des informations associées. Ensuite, vous renvoyez les données au thread principal afin que celui-ci les envoie à la classe Mesh de Unity.
Les plates-formes modernes (OpenGL 4.3, DirectX 11, OpenGL ES 3.1, PS4, XBone) supportent les compute shaders et peuvent être utilisés pour des tâches parallèles exécutées sur le GPU.
IV. Ressources▲
- « Essential Mathematics for Games - A programmers guide » par James M. Van Verth & Lars M. Bishop ;
- Exemples de génération procédurale de modèle ;
- Exemples de génération procédurale de modèle par les développeurs de Unity ;
- Triangle.NET pour Unity.
V. Commenter▲
Vous pouvez commenter et donner vos avis dans la discussion associée sur le forum.