Onverwachte output in Python/Blender

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Voor een projectje op Android ben ik bezig met Blender modellen importeren en te tonen in OpenGL. Ik ben begonnen met een zelfgeschreven .obj parser, maar dit leverde bij alleen vertex en face data al laadtijden van enkele seconden op. Na wat zoeken kwam ik een blogpost van een iPhone ontwikkelaar tegen die zijn eigen binaire formaat gebruikt om de overhead minimaal te houden.
Omdat ik toch al met Blender werk leek dit een goede optie. Ik ken nog geen Python maar met de bovenstaande tutorial (en het vervolg) kan ik prima uit de voeten.
Het binaire formaat komt hier op neer:
code:
1
2
3
4
5
6
7
8
9
#Header
[4bytes] int vertexCount
[4bytes] int faceCount
#Vertices
[vertexCount * 3 * 4 bytes] floats coordinaten in x1,y1,z1, x2,y2,z2
#Normals
[vertexCount * 3 * 4 bytes] floats coordinaten in x1,y1,z1, x2,y2,z2
#Triangle vertex indices
[faceCount * 3 * 2 bytes] shorts vertex indexen

Helaas gaat het ondanks het relatief straight forward scriptje toch fout bij het exporteren. Een klein model met beperkt aantal vertices gaat goed; een cube van 8 vertices en 12 triangles word perfect weergegeven. Probeer ik echter meer dan 10 vertices (dus 30 floats) weg te schrijven dan lopen de waarden ineens van 1E-35 tot 1E35, terwijl de vertices nooit verder dan -5 tot 5 komen. Ook mijn triangle indexen die na de floats als integer worden weggeschreven hebben waarden die simpelweg niet mogelijk zijn (onder nul) of vér boven het aantal vertices uitkomen.
Het probleem kwam als eerste na voren in mijn Android applicatie (OpenGL gaat onderuit vanwege de niet bestaande vertexen (en mogelijk de bereiken van de vertices?)), maar bij het nakijken in een hex editor kwam ik dezelfde waarden tegen als in de java debugger.

De relevante Python code voor het exporteren:
Python:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
mesh = Blender.Object.Get().getData();

file = open(filename, "w")
    
# First 4 bytes is the vertex count as a signed int
file.write(struct.pack(">i", len(mesh.verts)))
    
# Second 4 bytes is the triangle count
file.write(struct.pack(">i", len(mesh.faces)))

# Vertex coordinates are saved as 4 byte floating points (3 * vertex count * 4 bytes)
for vertex in mesh.verts:
    file.write(struct.pack(">fff", *vertex.co))

# Normal coordinates are saved as 4 byte floating points (3 * vertex count * 4 bytes)
for vertex in mesh.verts:
     file.write(struct.pack(">fff", *vertex.no))
    
# Save triangle vertex indices as signed shorts (3 * face count * 2 bytes)
for face in mesh.faces:
    for vertex in face.v:
        file.write(struct.pack(">h", vertex.index))

Ik lijk iets over het hoofd te zien, maar wat?

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Ik ben weer aan de slag gegaan met Blender, en loop alweer tegen hetzelfde probleem aan. Ik heb de zaak terug gebracht tot de volgende test:

In Python exporteer ik een list van 15 floats (stellen coordinaten voor, maar dat is niet relevant verder) naar een binair bestand. Dit doe ik met het volgende script: (de getallen zijn zo gekozen omdat deze voor mij al problemen opleverden)
Python:
1
2
3
4
5
import struct
l = [0.42168998718261719, 0.21920998394489288, 0.13494700193405151, 0.096524998545646667, 0.23634999990463257, 0.073962002992630005, 0.062020000070333481, 0.20687998831272125, 0.1316169947385788, 0.1932699978351593, -0.2354000061750412, 0.050567001104354858, 0.13358400762081146, -0.064419999718666077, 0.10855699330568314];
f = open("floats.pack", "w")
for n in l:
    f.write(struct.pack(">f", n));


Wanneer ik ze echter vervolgens importeer met de volgende Java:
Java:
1
2
3
4
5
6
7
FileInputStream fileStream = new FileInputStream("floats.pack");
DataInputStream stream = new DataInputStream(fileStream);
            //int vertexCount = stream.readInt();
for(int i = 0; i < 5; i++)
    System.out.println(String.format("%f, %f, %f", stream.readFloat(),
                                                    stream.readFloat(),
                                                    stream.readFloat()));


Ik krijg de volgende getallen terug van Java:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
In Java console:
0,421690, 0,219210, 0,137734
-0,000000, -224838230214401420000000,000000, -0,011572
13982064554318791000000,000000, -0,000000, 3342980815519744,000000
-0,000000, -0,000000, -0,000000
835779832053760,000000, 1,480589, -0,000000

In origineel:
0.42168998718261719, 0.21920998394489288, 0.13494700193405151,
0.096524998545646667, 0.23634999990463257, 0.073962002992630005,
0.062020000070333481, 0.20687998831272125, 0.1316169947385788,
0.1932699978351593, -0.2354000061750412, 0.050567001104354858,
0.13358400762081146, -0.064419999718666077, 0.10855699330568314


Ik snap er echt werkelijk geen fluit van. De eerste 3 coordinaten komen netjes terug, maar daarna loopt het helemaal in de soep. Het gaat echter niet altijd op fout, dit zijn een aantal willekeurige coordinaten waar Python/Java over viel. Bij andere meshes (en sets coordinaten) gaat het wel goed.

Acties:
  • 0 Henk 'm!

  • bindsa
  • Registratie: Juli 2009
  • Niet online
Hmm dat is inderdaad raar. Wat staat er in de file floats.pack? (Als daar al de foute waarden zijn, dan ligt de fout by Python, anders bij de Java import)

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
L0calh0st schreef op woensdag 16 juni 2010 @ 12:16:
Hmm dat is inderdaad raar. Wat staat er in de file floats.pack? (Als daar al de foute waarden zijn, dan ligt de fout by Python, anders bij de Java import)
Als ik met een hex editor kijk dan staan de foute waarden al in de floats.pack. Waarschijnlijk Python dus. Ik kan me haast niet voorstellen dat het een bug is, want dan is het wel een gigantische. Maar wat is het dan wel :X

Acties:
  • 0 Henk 'm!

  • bindsa
  • Registratie: Juli 2009
  • Niet online
Verwijderd schreef op woensdag 16 juni 2010 @ 12:31:
[...]

Als ik met een hex editor kijk dan staan de foute waarden al in de floats.pack. Waarschijnlijk Python dus. Ik kan me haast niet voorstellen dat het een bug is, want dan is het wel een gigantische. Maar wat is het dan wel :X
Wat gebeurt er als je het volgende doet:
Python:
1
2
3
4
import struct
l = "0.42168998718261719, 0.21920998394489288, 0.13494700193405151, 0.096524998545646667, 0.23634999990463257, 0.073962002992630005, 0.062020000070333481, 0.20687998831272125, 0.1316169947385788, 0.1932699978351593, -0.2354000061750412, 0.050567001104354858, 0.13358400762081146, -0.064419999718666077, 0.10855699330568314";
f = open("floats.pack", "w")
f.write(l);

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
L0calh0st schreef op woensdag 16 juni 2010 @ 12:35:
[...]
Wat gebeurt er als je het volgende doet:
In dit geval worden de floats wel correct als string ge-export, fout lijkt bij struct.pack te zitten. Vorige keer heb ik het idd 'opgelost' door een ASCII tussenformaat te maken die vervolgens verder werd verwerkt met een C# applicatie. Maar ik wil het gewoon direct met een Python script in Blender doen, want dat 2 staps proces is niet te onderhouden.

Acties:
  • 0 Henk 'm!

  • Oguz286
  • Registratie: Juni 2002
  • Laatst online: 23-02 10:10
Als ik het goed lees wil je het binair opslaan, maar je opent de file met argument 'w'. Dan zou je moeten openen met 'wb'. Stuct zorgt ervoor dat strings (in dit geval stringrepresentaties van je floats e.d.) in binaire vorm gepackt worden, en daarom moet je 'wb' gebruiken.

Ik heb zelf laatst ook een eigen bestandsformaat bedacht waarbij ik struct heb gebruikt en dat werkt prima, maar het was ook even uitvogelen hoe dat allemaal moest :)

Acties:
  • 0 Henk 'm!

  • user109731
  • Registratie: Maart 2004
  • Niet online
Wat Oguz286 zegt.

Het probleem is dat een bestand in Windows als tekst of binair geopend kan worden. Tekst-modus past automatisch de newlines aan van \n naar \r\n. Als we kijken naar het derde getal:
code:
1
2
3
4
>>> struct.pack(">f", 0.13494700193405151)
'>\n/\x8c'
>>> struct.unpack(">f", ">\n/\x8c")
(0.13494700193405151,)

Dit gaat goed. De \n is echter een regeleinde en wordt veranderd in \r\n:
code:
1
2
>>> struct.unpack(">f", ">\r\n/")
(0.13773415982723236,)

En dit is precies het derde getal die je in Java kreeg :)

[ Voor 5% gewijzigd door user109731 op 16-06-2010 15:08 ]


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Ah super heren! Ik wist écht niet meer waar ik het moest zoeken. Bedankt!
Pagina: 1