dimanche 26 septembre 2010

Les boites de dialogue, c'est long à faire

Mais ça serait encore plus long à coder directement en OpenGl (et probablement pas moins moche), donc je persiste.



La boite de dialogue des itinéraires avance gentiment, il est maintenant possible d'aller sélectionner des gares sur le terrain pour les ajouter à un itinéraire.

Il reste un peu de plomberie à faire pour relier les trains et les itinéraires. Peut-être qu'après cela, enfin, il sera possible de contrôler ses trains.

samedi 25 septembre 2010

Moi, une référence?

Et pourtant, on dirait que mon post sur les en-têtes précompilées a suffisamment plu pour se retrouver sur une page pour les TPs de l'université de Metz (que l'on peut voir ici après s'être connecté en tant qu'invité). Allez les jeunes, et bon courage!

mercredi 22 septembre 2010

Feed RSS du projet

Yay, que de fun! J'ai ajouté sur la droite un feed vers les news du projet Sourceforge. C'est plus facile de voir les derniers commits!

dimanche 19 septembre 2010

Interface pour les itinéraires

Et une petite capture pour vous prouver que le week-end n'a pas été que glande.



Voici donc la section de l'interface pour gérer les itinéraires. Remarquez les magnifiques icônes sur la partie droite, tous droits sortis d'Inkscape. A terme, cette interface permettra de créer des itinéraires, c'est à dire la liste des stations à visiter, avec potentiellement quelques informations supplémentaires tels le temps à attendre à une station donnée, ou l'ordre de s'arrêter ou pas dans les stations intermédiaires.

vendredi 17 septembre 2010

Cityscape

Quelques avancées sur le code de rendu de ville. Voici donc 10 000 "bâtiments" normalement distribués sur le terrain (et un peu à côté, aussi, mais bon...).



Pour maintenir des performances correctes, je découpe le monde en cellules de 100x100. Chaque cellule contient ensuite un osg::LOD, qui va gérer 3 niveaux de détails.

  • Les bâtiments détaillés, à proximité de la caméra

  • Les bâtiments peu détaillés, un peu plus loin

  • Un nombre limité de bâtiments peu détaillés (par exemple, 1/4 des bâtiments habituels, plus les batiments spéciaux), encore plus loin

Et bien sûr, ne rien afficher au delà d'une certaine distance.

L'intérêt du troisième niveau, dit "clairsemé", est qu'il donne une bonne impression de distance, tout en n'étant pas trop méchant pour les performances. Au fur et à mesure que l'on s'éloigne, l'on verra tout d'abord certains bâtiments disparaître, puis, plus tard, les autres, ce qui est moins brusque qu'une zone entière devenant vide d'un coup.

mercredi 15 septembre 2010

Tutorial - Gérer le passage high-poly à low-poly avec Blender pour OSG

Ce petit tutorial décrit la marche à suivre pour créer un objet high-poly dans Blender, puis d'en sauver les normales dans une texture pour un objet low-poly.

Commençons par créer un objet high-poly. J'ai démarré du cube de base, subdivisé, puis ajouté quelques reliefs intéressants.





Ensuite, créons le même cube, mais sans subdivisions, à l'endroit exact du premier cube. Pour éviter la confusion, appelons le cube détaillé "HighCube" et le cube simple "LowCube".

Créons ensuite la texture du LowCube. Sélectionnez en mode edit, tapez "u", et faites un unwrap (j'aime bien la smart projection, sans l'option "stretch to bound"). Créez l'image, et sauvez. Blender vous montre à peu près ça:



Remarquez le rendu moche du cube, dû au Z fighting des deux cubes superposés.

Maintenant, sélectionnez les deux cubes, et allez faire un coup de "bake" pour les normales, en object space, avec l'option "selected to active".



Le rendu de la texture donne ceci, qui correspond aux normales aux faces:



Ajoutez maintenant un material par défaut à LowCube, et exportez le. En le passant dans Shadedit avec notre shader standard (à peine modifié pour ne pas s'embêter avec la texture de couleur), l'on a bien le cube simple, mais avec les normales déplacées comme pour le cube détaillé!

lundi 6 septembre 2010

Oh le beau bruit!



Une texture de bruit utilisée comme normal map. J'aime beaucoup les reflets obtenus, et c'est encore mieux quand ça bouge. Je posterais bien une vidéo si seulement kdenlive acceptait de les exporter sans planter lamentablement...

samedi 4 septembre 2010

Un shader plus complet


varying vec3 v;
varying vec2 t0;

void main()
{
gl_Position = ftransform();
v = vec3(gl_ModelViewMatrix * gl_Vertex);
t0 = gl_MultiTexCoord0.xy;
}



varying vec3 v;
varying vec2 t0;

uniform sampler2D textureMap;
uniform sampler2D normalMap;

void main()
{
vec3 lightVec = normalize(gl_LightSource[0].position.xyz - v);

vec3 normal =
gl_NormalMatrix *
(vec3(-1, 1, -1) *
normalize(texture2D(normalMap, t0).rgb * 2 - 1));

vec4 base = texture2D(textureMap, t0);

vec4 ambiantTerm =
gl_LightSource[0].ambient *
gl_FrontMaterial.ambient;

float diffuse = max(dot(normal, lightVec), 0.0);
vec4 diffuseTerm =
diffuse *
gl_LightSource[0].diffuse *
gl_FrontMaterial.diffuse;

float specular = pow(max(dot(reflect(lightVec, normal * 0.8), v), 0.0),
gl_FrontMaterial.shininess);
vec4 specularTerm =
specular *
gl_FrontMaterial.specular *
gl_LightSource[0].specular;

gl_FragColor =
ambiantTerm * base +
diffuseTerm * base +
specularTerm;
}


Un shader pour les normal maps de Blender

Après une après-midi à me battre avec mon shader, j'ai enfin réussi à maîtriser la bête. Il reste encore beaucoup pour obtenir le shader ultime, mais au vu de la complexité du processus, je vais commencer par un petit tutorial simple sur la manière d'obtenir des normal maps dans OpenSceneGraph.

La plupart des shaders que l'on trouve sur le net sont des shaders en tangent space, est à dire qu'ils correspondent aux normales, ou au déplacement de normales, tangentiellement à la surface au point appliqué. L'intérêt de ces shaders est multiple, entre autres, ils fonctionnent sur des objets déformables, et ils peuvent être appliqués localement pour perturber les normales, permettant ainsi d'avoir par exemple une petite texture de sable appliquée à l'ensemble de la plage.

Je n'ai rien contre le tangent space, mais malheureusement, OSG et Blender si. Blender ne sait pas exporter les tangentes, et OSG ne sait pas les importer. Je pourrais en théorie les calculer pour chaque objet, nécessitant soit de créer mon propre format au sein d'OSG, ou d'aller méchamment tripatouiller les modèles. Mon plan est donc d'utiliser une alternative en attendant qu'une bonne âme fournisse un worflow Blender OSG complet.

En attendant, je m'intéresse aux normales en object space, qui sont très proches des normales aux faces. La différence, c'est qu'au lieu de définir une normale par face ou par vertex, on définit la normale dans la texture.

Démarrons donc Blender, et tentons de créer un objet qui ait une surface intéressante.



Supprimons le cube de départ, et ajoutons une bête UV sphère, que l'on étirera dans la direction z. Un petit coup de "Set smooth" pour faire joli. Et c'est maintenant que tout démarre. Ajoutons un material et sa texture. Je choisis par exemple du Voronoï:



De retour dans les matériaux, sélectionnons notre texture comme étant appliquée aux normales. Renforçons également la valeur "Nor" à 5, afin d'avoir un relief plus profond.



Il est maintenant temps de créer la texture. Sélectionnons l'objet, et déroulons sa texture: (Tab) pour passer en mode édition, (u) pour le dérouler, choisir "Unwrap - Smart projection", déselectionner "Stretch to boun" pour éviter les distorsions.



En changeant la fenêtre à "UV/Image editor", l'on peut voir notre modèle tout aplati. L'on peut maintenant créer l'image qui va contenir la texture, en choisissant dans ce menu (Image) -> (New). Allons y franchement pour ce modèle, avec une texture en 1024x1024.



Effectuons le rendu: dans le menu de rendu, choisir (Bake), sélectionner (Normals) pour rendre uniquement les normales, et changez le normal space vers (Object). Clic sur Bake, et voilà, la texture est complétée! Sauvez là, et admirez:



L'on remarque que les couleurs dominantes changent, car elles correspondent aux directions des normales depuis l'objet. Par comparaison, la texture en espace tangent ressemble à ça:



Ensuite, l'on peut exporter l'objet, par exemple au format Open Inventor (.iv).

J'ai créé une petite application qui me permet d'ajuster l'objet et les shaders en temps réel. Je charge l'objet, ajuste mes shaders, et voilà, un bel œuf de dinosaure!



Voici le code pour le vertex shader:


varying vec3 v;
varying vec3 n;
varying vec2 t0;

void main()
{
gl_Position = ftransform();
v = vec3(gl_ModelViewMatrix * gl_Vertex);
n = normalize(gl_Normal);
t0 = gl_MultiTexCoord0.xy;
}

et le fragment shader:

varying vec3 v;
varying vec3 n;
varying vec2 t0;

uniform sampler2D normalMap;

void main()
{
vec3 lightVec = normalize(gl_LightSource[0].position.xyz - v);
vec3 normal =
gl_NormalMatrix *
(vec3(-1, 1, -1) * normalize(texture2D(normalMap, t0).rgb * 2 - 1));
float diffuseTerm = max(dot(normal, lightVec), 0.0);
gl_FragColor = vec4(1, 1, 1, 1) * diffuseTerm;
}


Je vais maintenant affiner le shader:

  • Passage au multitexturing, pour avoir à la fois les normales et les couleurs

  • Gestion de la lumière spéculaire, pour permettre par exemple un rendu "mouillé"

  • Amélioration du pipeline, et résolution des quelques points bizarres, telle la multiplication par (-1, 1, -1)