La bibliothèque geos permet de gérer des objets géométriques en vue d'une intégration avec divers logiciels de gestion de données géographiques. L'on remarquera en particulier le support du format WKB (pour Well Known Binary) qui le rend donc compatible (efficacement!) avec Postgresql/Postgis.
J'étudie actuellement la possibilité d'utiliser ces outils pour gérer mes mondes OpenRailz. Le gros intérêt est d'avoir déjà tout un tas d'opérations sur les géométries. Les défauts sont tout une plus grande difficulté d'intégration (pas de visiteurs, donc probablement besoin de faire de moches dynamic_cast pour afficher la géométrie, par exemple), des std::auto_ptr un peu partout qui vont faire hurler mon compilo C++0x, et enfin probablement des soucis pour gérer les objets 3D correctement.
J'imagine qu'en considérant un certain nombre de couches horizontales dans le monde, l'on peut se ramener à des problèmes en 2D dans chaque couche.
Première étape, pondre un schéma de BDD qui tienne la route.
vendredi 3 juin 2011
La lib geos
vendredi 18 février 2011
Brain overload
Entre d'épineux problèmes de design au boulot, et d'épineux problèmes de design sur OpenRailz, on ne peut pas dire que je code beaucoup, à mon grand regret.
C'est que maintenant qu'OpenRailz permet de créer des gares, des rails, des trains, et d'assigner des itinéraires, il est temps de commencer à créer de vraies villes. Pour ce faire, je pense pour l'instant à effectuer un pavage du plan à l'aide de polygones, pour en faire des routes et des zones constructibles. Il serait probablement raisonnablement aisé de créer ainsi une ville complétement procédurale, mais je me heurte cependant aux difficultés d'interface: comment fournir au joueur les outils pour créer ses routes, sans affoler le générateur de ville, et sans causer des mini-trous moches au niveau du pavage?
Labels: monde
samedi 2 octobre 2010
GUI - Itinéraires et propriétés
Le système d'itinéraires commence à tenir la route. J'ai également rajouté un autre panneau pour afficher les propriétés de l'objet courant, comme une gare ou un train.
Ces nouveaux panneaux réduisent la partie 3D à sa portion congrue (et encore, question gui, vous n'avez rien vu!), mais c'est heureusement là que la possibilité de déplacer et de cacher certaines sections va être fondamentale.
Labels: monde
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.
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.
Labels: monde
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.
dimanche 29 août 2010
dimanche 15 août 2010
Niveaux aléatoires
Je regardais cette question sur stack exchange gamedev, ce qui m'a ramené quelques années en arrière lorsqu'il avait fallu que je génère des niveaux aléatoires pour mon projet de fin d'études. Mon algorithme de génération était probablement la meilleure partie du projet, et j'avais été agréablement surpris du look de mes niveaux.
L'algorithme, basé sur une grille, était le suivant:
- Générer aléatoirement des pièces rectangulaires, en précisant leur nombre, et les limites de largeur et de longueur
- Utiliser un algorithme de recherche de chemin (mettons, A*), pour tracer des couloirs de chaque pièce à chaque autre pièce. En fonction des poids que l'on donne aux endroits déjà creusés (les pièces et les couloirs existants) par rapport reste du monde, l'on obtient un univers plus ou moins biscornu: un poids très élevé pour les zones non creusées va pousser l'algorithme à passer par les pièces et les couloirs déjà existants, ce qui génère des couloirs rares, mais très irréguliers. En revanche, un poids plus bas permet à l'algo de creuser plus de nouveaux couloirs, et l'on se retrouve avec des mondes plus labyrinthiques, avec de nombreuses façons d'aller d'un endroit à un autre.
Ce qui était plaisant, c'est qu'à partir de quelques paramètres de base, il était possible de générer des niveaux très différents, et le résultat (en terme de disposition du niveau, hein, pas en terme de qualité graphique!) n'était pas si loin des ténors du genre, type Diablo ou assimilés.
lundi 9 août 2010
Tickets s'il vous plait!
Moi qui aime les structures monumentales, je vais être servi! Voici, tirés via quelques polygones grossiers, une gare ferroviaire. Si j'avais le courage, je me lancerais dans des textures semi-transparentes pour l'arche, mais pour l'instant, le gris souris sera de mise!
Modéliser un prototype sous Blender, c'est probablement l'aspect le plus amusant: avec quelques commandes de base, on tripatouille quelques volumes simples en essayant de trouver les éléments qui vont faire reconnaître le modèle du premier coup d'œil. Ici, des quais, des petits ponts, et une grande arche, hop, c'est une gare!
Le deuxième aspect, qui est l'effet d'échelle, est généralement facile à obtenir par l'ajout de quelques éléments qui donnent immédiatement une comparaison avec une taille humaine. Ansi, un petit rebord transforme tout de suite un gros pavé en un immeuble, et, ici, le petit pont par comparaison donne de l'ampleur à la longueur des quais.
dimanche 11 juillet 2010
Des trains qui foncent
Enfin! Après une semaine à coder toute l'infrastructure autour du déplacement des trains sans rien pouvoir tester (enfin, autrement que par mes tests unitaires, bien sûr!), mon petit train galope sur son chemin de fer (à cheval?).
Ni une, ni deux, j'en ai fait une vidéo, que je m'empresse de faire partager:
Ainsi qu'une image, pour voir le train d'un peu plus près (c'est du programmer's art, vous êtes prévenus!).
Ah, et le nom (temporaire?) du projet devient "OpenRailz".
Labels: 3d, c++, monde, programmation
mardi 29 juin 2010
Gestion des véhicules
Enfin, le problème de la gestion des véhicules est résolu!
Enfin, quand j'aurais implémenté mon design que voici:
En effet, le souci, c'est que, comme beaucoup de gens, j'imagine, j'ai mes idées dans les endroits les plus ésotériques (c'est à dire dans les endroits où réfléchir est la chose la plus intéressante disponible). Je me précipite dès que possible donc sur un papelard pour fixer tout cela au clair.
L'idée principale, ici, c'est que chaque véhicule possède un chemin, et suit ce chemin sans discuter. Le chemin permet donc d'abstraire tout ce qui est en dessous: vitesse max, arrêts nécessaires, position des wagons pour les trains. Lorsque le véhicule arrive au bout du chemin, il peut alors demander au réseau (ferré ou routier, hein, pas le réseau de communications. Quoique...) comment, à partir de sa position actuelle, aller à sa prochaine destination. Le réseau fait tourner son petit Dijkstra (que je vais probablement préférer à A*, mais j'en recauserai), et renvoie un nouveau chemin que le véhicule peut apposer à son chemin courant. Et c'est reparti!
Labels: humeur, monde, programmation
samedi 5 juin 2010
C'est comme si c'était fait!
C'est le truc avec les abstractions: quand elles sont bien faites, tout se met à marcher tout seul. Voilà donc un rail qui ressemble enfin à un rail.
(Même si la musique de Michel Legrand sur "The Go-Between", reprise dans l'émission "Faites entrer l'accusé", a beaucoup aidé).
Sniffe moi ce rail!
C'est très moche, mais les principes fondamentaux sont là: je peux afficher mon rail. Je suis satisfait de l'abstraction autour de mes sections: une section abstraite renvoie sa matrice de transformation pour une longueur donnée, et j'en dérive les sections droites et courbes. C'est là que mes vieux souvenirs sur les matrices de changement de base se sont rendus utiles!
Je peux donc diviser ma section abstraite et appliquer la transformation en chacun des points que j'ai choisi à la traverse, et au profil de mon rail. J'enfile ensuite les profils, et créé la boite correspondante.
Une fois que le rail aura la bonne taille, et tournera gentiment sur ses traverses, il va falloir trouver une texture qui ne soit pas trop moche, et tripatouiller les reflets pour obtenir un effet métallique.
jeudi 3 juin 2010
Courbes
Enfin, mes traverses suivent une voie courbée. Magique!
Le premier essai était plutôt bizarre:
Mais après quelques inversions aléatoires de produits vectoriels, les traverses s'alignent beaucoup plus gentiment:
C'est pas tout, mais maintenant, il va falloir y mettre des rails!
dimanche 16 mai 2010
Textures combinées
J'ai souvent eu des soucis à rendre mes textures de terrain jolies. Mon plus gros problème, généralement, est l'effet de répétition. Surtout avec les textures moches du genre de celles que je créé moi-même. Prenons par exemple cette simple texture d'herbe.
On applique la texture à ce terrain, et hop, l'effet de répétition prend toute sa mesure. C'est moche!
En même temps, si l'on réduit la répétition de la texture, c'est moche aussi, car la texture semble grossière et peu détaillée.
Mais si l'on calcule la moyenne des deux, avec un facteur qui évite la répétition, comme par exemple 16 et 3.44 (!), tout d'un coup, ça rend beaucoup mieux! Pas d'artefacts de répétition, mais la texture maintient l'impression de détail.
En plus, ce genre de calcul est trivial à effectuer avec le petit shader:
gl_FragColor =
diffuse
* (texture2D(grassTex, t * 16)
+ texture2D(grassTex, t * 3.44)) / 2;
L'on multiplie la couleur diffuse calculée à partir de l'éclairement par la moyenne des textures, en multipliant les coordonnées de la texture par nos facteurs.
dimanche 14 février 2010
Accès concurrent aux listes de propriétés
Je n'allais quand même pas laisser de côté un tel sujet! Récapitulons. Nous avons:
- Une base de données contenant les listes
- Un serveur de listes (unique), qui fournit l'interface vers la base
- Les serveurs, qui communiquent avec le serveur de listes pour récupérer et sauver les listes
- Les clients
- L'interface d'administration Web, qui cause directement à la base de données.
Les clients ne doivent pas modifier les listes directement, mais indiquer leurs actions aux serveurs, qui modifient les listes en fonction. Les serveurs possèdent un cache des listes, et récupèrent auprès du serveur de listes celles dont ils ont besoin. Tentons de dérouler un exemple pour voir comment tout ceci peut fonctionner.
Le Roi Minablos se connecte sur un serveur. Le serveur récupère auprès du serveur de listes l'ensemble des listes dont il aura besoin, c'est à dire la liste du personnage, les listes parentes, les sous-listes référencées dans la liste (par exemple l'inventaire), et ainsi de suite (encore un diagramme, je suis chaud sur Dia, là!).
Les premières fois, l'on aura probablement une bonne partie du monde à télécharger depuis le serveur de liste, mais, le cache aidant, les serveurs seront rapidement à jour. Pour chaque liste, le serveur détermine s'il a besoin d'un accès en lecture seule, ou d'un accès en écriture, en différenciant les listes correspondant à des objets réels, qu'il gère (le Roi Minablos, une bouteille d'huile d'olive), et les objets virtuels, qui correspondent à des attributs et des propriétés générales du monde (ainsi, la liste "huile d'olive", dont dérive la bouteille, contient les propriétés générale de l'huile d'olive, et n'est accessible qu'en lecture seule).
Le Roi Minablos se saisit d'une bouteille d'huile d'olive, et envoie la requête correspondante au serveur. Le serveur modifie la liste du Roi Minablos, en y référençant la bouteille, et sauve les nouvelles listes auprès du serveur de liste.
Plus compliqué: le Roi Minablos fait pousser un olivier. C'est un cas à part, puisque le serveur doit créer une nouvelle liste. Plutôt que de gérer un long appel au serveur de listes, l'idée est pour le serveur de demander au démarrage un grand nombre de listes vides, dont il peut user comme bon lui semble, et d'en demander d'autres, de manière asynchrone, quand sa réserve s'épuise. Dans le cas de notre olivier, le serveur assigne une de ses listes vides, la fait dériver de l'objet olivier, lui met le Roi Minablos comme propriétaire, puis la référence auprès du serveur de liste.
Encore plus compliqué! Le maître de jeu gère une malédiction lancée par un sorcier maléfique, qui a rendu toutes les pommes empoisonnées. Il modifie dans son interface d'administration les propriétés des pommes. L'interface modifie la base, qui réveille le serveur de listes, lequel rafraîchit ses listes, et envoie des notifications à tous les serveurs qui avaient dans leur cache la liste des pommes. La prochaine fois qu'un joueur voudra croquer dedans, ça fera mal aux gencives!
Labels: adh, humeur, mmorpg, monde, programmation
dimanche 13 décembre 2009
mardi 24 novembre 2009
Rails et routes
J'ai passé un peu de temps à chercher à comment modéliser des routes et des rails, et j'ai trouvé un post très intéressant ici. Ça cause courbes de Bézier et arcs de cercle, et j'ai déjà commencé à gribouiller quelques feuilles pour tenter de gérer mes courbes.
A voir également, la manière dont Cities XL gère la chose, s'affranchissant complètement (du moins en apparence) des grilles.
À ruminer!
samedi 14 novembre 2009
Enfin, le bump mapping!
C'est avec l'aide de cette page, de nombreuses simplifications, et beaucoup de bidouillages, que j'ai enfin réussi à faire du bump mapping qui ressemble à quelque chose.
L'ensemble de la scène est assez complexe.
- Tout d'abord, il y a l'élévation, générée à partir d'une texture, au niveau du vertex shader
- Ensuite, il y a l'ombrage général de la scène, généré également avec une texture, mais au niveau du fragment
- Ensuite, il y a le calcul de la tangente, au niveau du vertex shader, qui est ensuite passée au fragment pour générer le bump mapping, à la fois en diffus, et en reflets, pour donner les effets "mouillés"
L'ensemble tourne à un très correct 1700 images par secondes en 1280x1024 plein écran.




Dans la dernière image, la couleur diffuse est en rose, afin que les reflets soient encore plus visibles.
Labels: 3d, c++, glsl, monde, programmation
samedi 18 juillet 2009
Création dynamique des îles
C'est fait, l'on peut maintenant créer les îles dynamiquement! Dans la console, l'on tape par exemple:
/island create here 1457 Minoset l'île Minos, créée à partir de la racine 1457, apparaît sous vos pieds.
Il me reste cependant à gérer l'UTF-8, car pour l'instant, l'on ne peut pas créer l'île de Ré!

