dimanche 21 juin 2020

Dans l'espace

Je suis d'une humeur très spatiale, ces temps-ci. Voici deux rendus, tout d'abord d'une planète de type Saturne, avec des anneaux de gaz et de roche, et ensuite d'un astéroïde construit sur le même modèle que ceux de l'anneau, mais avec plus de détails.

L’astéroïde est fait à partir d'un cube très lourdement subdivisé, auquel on a ajouté un modificateur "displace" avec une texture Voronoi. Tout d'abord, on créé une texture avec une taille assez élevée, afin d'avoir un objet avec pas trop d'arêtes, qui soit bien découpé. Ensuite, l'on peut ajouter des détails. Je trouve que le 4ème niveau de poids donne un effet particulièrement intéressant. Et finalement, on rajoute une texture normale avec un bête bruit très détaillé.

Pour le fond étoilé, voici mes nœuds "world". Je créé une texture de bruit très fine, que je passe à travers une color ramp pour ne garder que des points éparpillés. Voici mes étoiles. Ensuite, j'aimerais bien leur donner des couleurs différentes, alors je créé une autre texture de bruit, fine aussi, mais moins, histoire que des étoiles proches aient des teintes proches, parce que pourquoi pas, et je la passe à travers une color ramp qui contient toutes les teintes qui m'intéressent : du rouge, du jaune, du blanc, du bleu. Ensuite, je combine ces deux textures à travers un nœud "hue saturation value", pour utiliser les couleurs de la deuxième texture, mais avec la luminosité contrôlée par la première texture. Et voilà, des étoiles gentiment colorées !

Notez également dans la deuxième image, un "glare" assez fort, contrôlé via le compositeur, et qui donne un aspect "spatial". Les lumières sont fortes (100 000 W pour la lumière mon soleil) pour avoir de beaux contrastes.

L'on notera à quel point on peut faire de fort jolies choses avec Eevee : c'est typiquement le genre de scènes où ce moteur temps réel donne de très belles choses. En revanche, quelques tests d'animation montrent ses limites: avec une forme compliquée comme celle de mon astéroïde, les ombres sont finalement assez imprécises, ce qui n'est pas gênant pour une image seule, mais provoque des sauts intempestifs quand elles sont animées.

Maintenant, reste à améliorer les vaisseaux, et à animer le tout un minimum, histoire de profiter des jeux de lumière.

jeudi 11 juin 2020

C++14 - std::string_view veut jouer avec std::set

Petite expérience du matin (chagrin ?) : Comment faire un find sur un std::set en utilisant string_view ?

Revenons en arrière. Tout d'abord, qu'est-ce que std::string_view, et pourquoi voudrait-on l'utiliser pour faire un find ?

Vous avez peut-être remarqué que l'objet std::string est loin d'être gratuit. Non seulement les copies peuvent être chères (modulo COW et SSO, m'enfin bref), mais en plus le reste du monde conspire contre nous entre les chaînes codées en dur qui sont des const char *, et de nombreuses bibliothèques ne veulent pas en entendre parler. Voyez par exemple cette recherche dans un std::set : en passant un paramètre const char *, il se cache en fait la construction d'un objet std::string, et donc une allocation.

#include <set>
#include <string>
#include <iostream>

#include <stdlib.h>

int number_of_allocs = 0;

void* operator new(std::size_t size) {
  ++number_of_allocs;
  void *p = malloc(size);
  if(!p) throw std::bad_alloc();
  return p;
}

void* operator new  [](std::size_t size) {
  ++number_of_allocs;
  void *p = malloc(size);
  if(!p) throw std::bad_alloc();
  return p;
}

void* operator new  [](std::size_t size, const std::nothrow_t&) throw() {
  ++number_of_allocs;
  return malloc(size);
}
void* operator new   (std::size_t size, const std::nothrow_t&) throw() {
  ++number_of_allocs;
  return malloc(size);
}


void operator delete(void* ptr) throw() { free(ptr); }
void operator delete (void* ptr, const std::nothrow_t&) throw() { free(ptr); }
void operator delete[](void* ptr) throw() { free(ptr); }
void operator delete[](void* ptr, const std::nothrow_t&) throw() { free(ptr); }

int main()
{
  std::cout << number_of_allocs << std::endl;
  
  std::set<std::string> str({"a", "b", "c"});
  
  std::cout << number_of_allocs << std::endl;
  
  // Longue chaine pour éviter le SSO
  str.find("abceuhaoeuhaotuhaoutnohusaocamhamknomhucra,huh");
  
  std::cout << number_of_allocs << std::endl;

  return 0;
}

La punition est immédiate, le programme affiche 0, 3 et 4, parce que la chaîne dans le find a été convertie en std::string et a provoqué une allocation.

Si l'on s'amuse plutôt à passer un std::string_view, dans ce cas, le programme ne compile pas, car il n'y a pas de création implicite de std::string d'après une std::string_view.

  str.find(std::string_view("abceuhaoeuhaotuhaoutnohusaocamhamknomhucra,huh"));

Entre en scène la nouvelle surcharge de la fonction find, datant du C++14, qui prend un paramètre template qui doit être comparable avec une clé "de manière transparente", sans conversion nécessaire. Ah ah! Pile ce qu'il nous faut. Il faut juste donner au std::set un comparateur transparent, comme std::less, et cela fonctionne.

[...]
int main()
{
  std::cout << number_of_allocs << std::endl;
  
  std::set<std::string, std::less<> > str({"a", "b", "c"});
  
  std::cout << number_of_allocs << std::endl;
  
  str.find(std::string_view("abceuhaoeuhaotuhaoutnohusaocamhamknomhucra,huh"));
  
  std::cout << number_of_allocs << std::endl;

  return 0;
}

Victoire, le programme affiche 0, 3, 3, et a donc économisé l'allocation ! Mieux encore, la version où l'on passe juste la chaîne en const char * a également économisé son allocation, le std::string_view n'étant là que pour empêcher la conversion implicite.

Première conclusion : ajoutez des std::less<> à vos std::set et std::map prenant des chaînes !

Deuxième conclusion : pensez à creer un comparateur manuel si vous faites ce genre de magie avec vos propres objets

Troisème conclusion : passez à C++20 pour faire la même chose avec std::unordered_set et std::unordered_map. Je vous en recauserai peut-être quand j'aurai mis à jour mon compilo.

Références:
https://en.cppreference.com/w/cpp/string/basic_string_view
https://en.cppreference.com/w/cpp/container/unordered_set/find
https://stackoverflow.com/questions/9927856/how-to-use-operator-new-to-count-number-of-times-of-dynamic-memory-allocation
https://stackoverflow.com/questions/35525777/use-of-string-view-for-map-lookup

jeudi 7 mai 2020

Lanternes en vidéo

Une lanterne posée sur le sol, c'est rigolo, mais une lanterne qui tombe du plafond, c'est encore mieux ! Voici un rendu rapide (enfin, c'était la modélisation qui était rapide, le rendu, lui, a quand même pris 6 heures) de la lanterne du post précédent qui chute et rebondit sur le sol. Il a suffi de laisser faire le moteur physique de Blender, et le tour était joué. On admirera les effets de lumière sur le sol quand la lanterne le percute.

Une lanterne

Petite scène rapide avec une lanterne. C'était finalement beaucoup plus facile que prévu : simplement se mettre une petite loupiote dans le cube (aïe !) et utiliser pour le cube un shader translucide coloré. Le tour est joué !

Il y a probablement moyen d'en faire une vidéo...

dimanche 3 mai 2020

Ça y'est, j'ai mis le truc dans le machin !

C'était sport, mais j'ai enfin réussi à ravitailler en vol avec DCS World et le Mirage 2000 ! Comme quoi, l'entraînement finit par porter ses fruits. Les trucs qui m'ont bien aidé :

  • Le trim ! Quand l'avion est bien trimé horizontalement, les corrections sur le manche se font à peu près autour de la zone neutre, ce qui est bien plus reposant pour le bras, et semble plus intuitif.
  • Gérer sa manette des gaz en pompant autour d'un point d'équilibre correspondant à peu près à la vitesse cible. Pour accélérer, ajouter un filet de gaz, puis revenir au point d'équilibre. Pour ralentir, réduire un peu puis remettre les gaz. Cela aide à garder un petit différentiel de vitesse, et accessoirement à éviter de se prendre un réacteur en pleine poire.

Dans la petite dizaine de secondes pendant laquelle j'ai réussi à rester connecter, j'ai pu pomper environ 400 kg de fuel, ce qui est vachement généreux de la part de DCS. Dans la réalité, c'est plutôt 10 minutes pour faire le plein, et rester stable tout ce temps me semble bien au dessus de mes forces !

mercredi 29 avril 2020

Inverse kinematics et tourelle de tank

Petite démo d'une simulation inverse kinematics pour préparer ma tourelle de tank. Par rapport à mes précédents essais, j'ai ajouté des contraintes de rotation afin que la tourelle ne puisse que tourner sur l'axe Z, tandis que le canon est limité a 40° dans l'axe Y. Je peux ensuite animer l'ensemble à l'aide d'une contrainte IK qui va faire pointer le canon vers un os (que je fais marcher sur un chemin). Le résultat, une belle (enfin, une moche) tourelle !

Prochaine étape : lui faire tirer des projectiles.

lundi 27 avril 2020

Encore 7 jours pour essayer tout un tas de modules gratuits sur DCS World

Depuis 1 semaine, DCS propose la plus grande partie de ses modules gratuitement, pour 2 semaines (ce qui nous laisse donc 1 semaine, si mes calculs sont justes). C'est l'occasion de tester tout un tas de modules pour lesquels on n'aurait pas forcément cassé sa tirelire, mais également pour la petite minorité qui fait tourner DCS sous Linux de vérifier si le module fonctionne avant de l'acheter.

J'avais donc l’œil fermement dirigé vers le JF-17, apparemment particulièrement bien modélisé, et je me suis empressé de le télécharger. Petite déception: autant l'avion fonctionne impeccable, autant j'ai chez moi des freezes systématiques dès que je veux quitter la mission, ce qui est un petit peu gonflant. Exit donc le JF-17.

Je zieutais également la carte Normandie, malgré des avis plutôt mitigés, histoire de donner un peu vie au P-51D. Là encore, déception : non seulement la carte (vendue 8 balles) ne suffit pas car il faut également le pack WW2 (hop, 25 balles supplémentaires), mais surtout, chez moi encore (ne généralisons pas!), impossible de charger la carte au sein du jeu, j'ai un freeze. Exit donc la carte Normandie, comme quoi j'ai bien fait d'essayer avant d'acheter.

Un autre module que je voulais essayer, c'est le FW-109, avion de la 2ème guerre mondiale, côté Allemand. Une fois passé la gêne de combattre pour les Nazis, le fait est que c'est un très bel avion, probablement bien plus aisé à prendre en main que le Mustang, ce qui ne m'empêche pas par ailleurs de me faire descendre en moins de 2. Belle bête donc, mais Nazi + 40 balles = grosse hésitation quand j'ai déjà le Mustang pour jouer. Ceci dit, pour quelqu'un qui n'aurait pas encore de warbird mais qui voudrait en faire, très bonne option.

Avec également des problèmes de chargement au niveau de l'A-10 et du F-16, c'est finalement assez décevant ! J'ai l'impression d'avoir eu beaucoup de chance que les modules que j'ai achetés sans avoir testé avant, soit le M-2000, le F-18 et le P-51D, fonctionnent très bien.