Windmill / fxconv : conversion obj en c
Posté le 08/01/2022 23:14
Bonjour à tous,
J'aimerai mettre les mains dans fxconv pour convertir un fichier 3d .obj en du code C. Je ne sais pas par où commencer ni qu'elle approche prendre.
Grosso modo j'ai un fichier 3D qui ressemble à ça :
v 0.000000 27.684446 72.248153
v -28.296346 27.684446 45.000000
v -28.296346 -27.684446 45.000000
v 0.000000 -27.684446 72.248153
v 28.296346 27.684446 45.000000
v 28.296346 -27.684446 45.000000
v -28.296346 -27.684446 0.000000
v 28.296346 -27.684446 0.000000
v -28.296346 27.684446 0.000000
v 28.296346 27.684446 0.000000
vt 3.928288 5.536889 0.000000
vt 0.000000 5.536889 0.000000
vt 3.928288 0.000000 0.000000
vt 0.000000 0.000000 0.000000
vt 3.928288 5.536889 0.000000
vt 0.000000 5.536889 0.000000
vt 3.928288 0.000000 0.000000
vt 0.000000 0.000000 0.000000
vt 0.000000 0.000000 0.000000
vt 5.659269 0.000000 0.000000
vt 0.000000 4.500000 0.000000
vt 5.659269 4.500000 0.000000
vt 2.829635 7.224815 0.000000
vt 0.000000 0.000000 0.000000
vt 5.536889 0.000000 0.000000
vt 0.000000 4.500000 0.000000
vt 5.536889 4.500000 0.000000
vt 0.000000 0.000000 0.000000
vt 5.659269 0.000000 0.000000
vt 0.000000 4.500000 0.000000
vt 5.659269 4.500000 0.000000
vt 2.829635 7.224815 0.000000
vt 0.000000 0.000000 0.000000
vt 5.536889 0.000000 0.000000
vt 0.000000 4.500000 0.000000
vt 5.536889 4.500000 0.000000
vt -2.829635 -2.768445 0.000000
vt 2.829635 -2.768445 0.000000
vt -2.829635 2.768445 0.000000
vt 2.829635 2.768445 0.000000
f 1/1/1 2/2/2 4/3/3
f 4/3/3 2/2/2 3/4/4
f 5/5/5 1/6/6 6/7/7
f 6/7/7 1/6/6 4/8/8
f 7/9/9 8/10/10 3/11/11
f 3/11/11 8/10/10 6/12/12
f 3/11/11 6/12/12 4/13/13
f 9/14/14 7/15/15 2/16/16
f 2/16/16 7/15/15 3/17/17
f 10/18/18 9/19/19 5/20/20
f 5/20/20 9/19/19 2/21/21
f 5/20/20 2/21/21 1/22/22
f 8/23/23 10/24/24 6/25/25
f 6/25/25 10/24/24 5/26/26
f 8/27/27 7/28/28 10/29/29
f 10/29/29 7/28/28 9/30/30
# 10 vertices
# 30 texture params
# 16 facets
Dans mon code C++ j'ai ceci :
const VertexPoint exemple_v[] = {
{0, -30, 0},
{0, 30, 0},
{0, -30, 60},
{0, 30, 60}};
const TexturePoint exemple_t[] = {
{0, 0},
{1, 0},
{0, 1},
{1, 1}};
const Face exemple_f[] = {
{&tex_brique, &tex_black, {0, 2, 1}, {0, 2, 1}},
{&tex_black, &tex_tuile, {1, 2, 3}, {1, 2, 3}}};
const Mesh exemple_m = {exemple_v, 4, exemple_t, 4, exemple_f, 2};
Tout les chiffres dans le code sont ceux que l'on retrouve dans le fichier obj à un endroit ou un autre.
Ce que j'aimerai, c'est générer ce code, ou générer ces variables pour els réutiliser dans mon code.
Est-ce faisable ?
Merci !
Citer : Posté le 09/01/2022 10:10 | #
Yup c'est faisable. Tu peux commencer par regarder le tutoriel d'utilisation de gint #3, qui explique les bases avec pas mal de détails. C'est pas tout à fait à jour, donc ne code pas tout de suite, mais tous les principes sont là.
Les aspects les plus modernes (pointeurs etc.) de l'API peuvent être trouvés dans ce changelog, qui te donne aussi un exemple assez parlant. Quelques fonctions ont été renommées au passage, d'où le côté pas tout à fait à jour du tutoriel.
Les convertisseurs les plus pétés à ma connaissance sont dans Rogue Life. Tu peux notamment voir un petit changement dans la fonction convert() où les fonctions individuelles pour les formats renvoient une structure (un fxconv.ObjectData() ou fxconv.Structure() selon comment tu veux l'appeler) et le fxconv.elf() est dans convert() directement, ce qui est un peu plus idiomatique. (De la même façon que fxconv.convert_bopti_fx() renvoie une structure que tu peux, du coup, réutiliser dans d'autres conversions plus compliquées.)
Pour ton fichier .obj, tu peux par exemple commencer comme suit. On se donne une fonction pour représenter un float en big-endian (ça pourrait être fourni par fxconv, mais actuellement non) :
def float_to_bytes(f):
return struct.pack('>f', f)
Ensuite tu peux te donner une fonction pour générer un tableau de sommets (représenté comme une liste de triplets) :
def vertex_array(vertices):
o = fxconv.Structure()
for x, y, z in vertices:
o += float_to_bytes(x)
o += float_to_bytes(y)
o += float_to_bytes(z)
De façon générale en lisant le tutoriel tu verras que la méthode est toujours la même, tu crées une fxconv.Structure() (ou un fxconv.ObjectData(), c'est un synonyme), et ensuite tu "ajoutes" les champs au fur et à mesure. Tu peux ajouter des bytes ou des bytearray directement, mais aussi des fxconv.ptr() (synonyme fxconv.ref()) qui ajoute des pointeurs vers des bytes, d'autres structures ou des variables. Il y a aussi pas mal de fonctions pour t'aider, du genre fxconv.u32() pour créer des entiers 32-bits ou fxconv.str() pour créer directement un pointeurs vers une chaîne de caractères choisie.
Avec ça tu peux créer exemple_v. Par défaut ta structure n'a pas de nom de variable, tu n'y accéderas que par le pointeur qui est dans exemple_m. Si ça te gêne, tu peux toujours mettre un nom dessus en ajoutant un fxconv.sybl() à la structure.
Pareil pour la texture, je te laisse deviner la forme que ça prend.
Pour ta face, ce n'est pas clair pour moi si le tex_brique est issu de la même conversion ou pas, alors je te donne les deux cas :
# Si tex_brique fait partie de la même conversion
o += fxconv.ptr(convert_texture(...))
# Si c'est une variable externe
o += fxconv.ptr("tex_brique")
# Pareil pour tex_black
# Ensuite les tableaux, eg. si c'est des int
o += fxconv.u32(0)
o += fxconv.u32(2)
o += fxconv.u32(1)
# Si t'as un tableau de Face tu peux juste continuer à ajouter
Attention si tu as du padding dans ta structure, c'est-à-dire des octets vides entre les champs. Ça peut se produire à cause de l'alignement, auquel cas il faut que tu ajoutes toi-même du padding quand tu convertis. C'est un coup à se faire avoir donc fais attention !
Note aussi que tout ça ça marche bien pour des structures, mais si tu as des classes virtuelles et des trucs compliqués ça ne marchera pas. Essaie de n'utiliser fxconv que pour créer des données brutes et tout ira bien.
Enfin pour le mesh :
o += fxconv.ptr(vertex_array(...))
o += fxconv.u32(4)
o += fxconv.ptr(texture_array(...))
o += fxconv.u32(4)
o += fxconv.ptr(face_array(...))
o += fxconv.u32(2)
return o
Ça devrait te donner les grandes lignes
Pour info dans Rogue Life ce type de niveau avec ce type de map est généré automatiquement avec fxconv, donc ton approche devrait largement le faire
Citer : Posté le 09/01/2022 13:11 | #
Ok merci Lephé pour ce message complet et pour les liens, je vais regarder tout ça, j'aurai sans doutes quelques questions