[Java] gevulde ByteBuffer naar FloatBuffer converteren

Pagina: 1
Acties:

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Voor een Android applicatie probeer ik geometrie uit een binair bestand te lezen om vervolgens als buffers voor OpenGL ES (1.1) te gebruiken. Ik schrijf de getallen door middel van een DataOutputStream en writeFloat() naar het bestand.

Wanneer ik het bestand echter wil uitlezen loop ik tegen iets vreemd aan.

Wanneer ik een ByteBuffer maak en direct omzet naar een FloatBuffer waar ik vervolgens per float de waardes overzet gaat het goed. Ik kan de buffers netjes in OpenGL weergeven.
Java:
1
2
3
4
5
FloatBuffer vertexBuffer = ByteBuffer.allocateDirect(vertexCapacity)
                .order(ByteOrder.nativeOrder()).asFloatBuffer();
for(int i = 0; i < vertexFloatCount; i++)
    vertexBuffer.put(input.readFloat());
vertexBuffer.position(0);


Deze methode is echter vrij traag, zelfs wanneer mijn DataInputStream wrap met een BufferedInputStream. Wanneer ik alle waardes echter in een keer inlees gaat het veel sneller:
Java:
1
2
3
4
5
ByteBuffer buffer = ByteBuffer.allocateDirect(vertexCapacity).order(ByteOrder.nativeOrder);
byte[] values = new byte[vertexCapacity];
input.readFully(values);
buffer.put(values, 0, vertexCapacity);
FloatBuffer vb = buffer.asFloatBuffer();


Het probleem is echter dat OpenGL deze buffer niet weergeeft. Wanneer ik de individuele getallen bekijk dmv 'readFloat()' krijg ik de juiste waarden terug, OpenGL tekent echter niks.

Wat zie ik over het hoofd? Is het uberhaupt mogelijk om een byte[] om te zetten naar een FloatBuffer zonder het per waarde te doen?

Acties:
  • 0 Henk 'm!

  • user109731
  • Registratie: Maart 2004
  • Niet online
Is het probleem niet dat "put" de positie wijzigt en dat asFloatBuffer werkt vanaf die positie? Dat zou betekenen dat je een position(0) moet zetten tussen de put en de asFloatBuffer calls.

En misschien kun je iets met ByteBuffer.wrap zoals dit? :)
Java:
1
2
3
4
5
byte[] values = new byte[vertexCapacity];
input.readFully(values); 

ByteBuffer buffer = ByteBuffer.wrap(values);
FloatBuffer vb = buffer.asFloatBuffer();

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
JanDM schreef op zaterdag 13 augustus 2011 @ 17:13:
Is het probleem niet dat "put" de positie wijzigt en dat asFloatBuffer werkt vanaf die positie? Dat zou betekenen dat je een position(0) moet zetten tussen de put en de asFloatBuffer calls.

En misschien kun je iets met ByteBuffer.wrap zoals dit? :)
Java:
1
2
3
4
5
byte[] values = new byte[vertexCapacity];
input.readFully(values); 

ByteBuffer buffer = ByteBuffer.wrap(values);
FloatBuffer vb = buffer.asFloatBuffer();
Volgens mij kun je met wrap onmogelijk een direct buffer terug krijgen, dus dat gaat sowieso niet werken als je het wilt gebruiken voor OpenGL. Ik heb je position tip nog wel geprobeerd, maar dat bood ook geen soelaas.

Ik heb net nog even een usecase geschreven want ik was in mijn originele code al verder gegaan met individuele readFloat()'s. Het viel me op dat ik om nuttige floats in mijn FloatBuffer te krijgen ik wel BIG_ENDIAN ipv nativeOrder() moet gebruiken. Het probleem zit dus waarschijnlijk in endianess, ik zal nog wat verder in die hoek zoeken. Ik compileer mijn bestand op een 64 bit ubuntu machine en lees ze uit op een ARM device, maar toch vreemd dat het in het geval van readFloat() wél goed gaat.

[ Voor 3% gewijzigd door Verwijderd op 13-08-2011 19:03 ]


Acties:
  • 0 Henk 'm!

  • user109731
  • Registratie: Maart 2004
  • Niet online
Hm goed punt over wrap vs. allocateDirect...

Volgens de documentatie schrijft DataOutputStream altijd big endian, ongeacht de architectuur, en DataInputStream leest altijd big endian. Dat verklaart iig waarom readFloat wel werkt. Als je een aantal keer vb.get() aanroept, krijg je dan de juiste floats te zien?

Het is dan waarschijnlijk zo dat OpenGL direct naar de onderliggende buffer gaat en de data als little-endian interpreteert, terwijl het eigenlijk big endian is. Dat zou betekenen dat je toch ergens een conversie moet doen, maar ik heb geen idee wat daar de snelste methode voor is. Sneller is waarschijnlijk om het bestand op je Ubuntu machine in little endian weg te schrijven zodat je huidige aanpak wel werkt... :)

[ Voor 19% gewijzigd door user109731 op 13-08-2011 20:40 ]


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Heb het eindelijk voor elkaar :). Ik schrijf nu aan de export kant alles eerst weg in een Little Endian FloatBuffer, waarna ik die wegschrijf in het bestand. Als ik deze bytes vervolgens inlees in een Little Endian ByteBuffer werkt het in opengl. Dank je wel iig!