OpenGL: Effizientester Weg Text darzustellen?

  • Antworten:7
Mathias Wittig
  • Forum-Beiträge: 24

31.08.2016, 13:01:26 via Website

Hi zusammen.

Ich bin neu bei OpenGL und will ein kleines 2D Game umsetzen (enthält relativ viele Texturen). Dabei will ich auch Text einbauen.

Mein Ansatz bisher:

Für jeden Buchstaben eine eigene Textur als Bitmap (mit Alphakanal, 128px * 128 px) speichern. Und dann für jeden Buchstaben ein Quadrat mit der jeweiligen Textur zeichnen.

Ich hab aber bemerkt, dass bereits bei ca. 1000 dieser Buchstaben die Framerate bereits dramatisch einbricht (~10FPS).

Wie kann ich das verbessern?

Spritesheets ? Wenn ja über ein Canvas oder die TextureCoords in OpenGL?

Kleinere PNGs f. Buchstaben und dann einen Filter anwenden um die Details hochzuhalten?

Danke für jede Hilfe !!! (lightbulb):)

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

31.08.2016, 18:16:39 via Website

Ich bin jetzt in der Spiele entwicklung mit Grafik etc. nicht so drin, aber ich würde sagen, per Canvas müsste das eigentlich gut und schnell gehen:
http://stackoverflow.com/a/2657684
Mit openGl kenne ich mich nicht aus.

PS: Für jeden Buchstaben ein Bitmap ist aber eine ziemliche Ressourcenverschwendung oder nicht? ;)
Wahrscheinlich auch deswegen so langsam??

LG Pascal //It's not a bug, it's a feature. :) ;)

Mathias Wittig

Antworten
swa00
  • Forum-Beiträge: 3.704

31.08.2016, 19:43:32 via Website

PS: Für jeden Buchstaben ein Bitmap ist aber eine ziemliche Ressourcenverschwendung oder nicht? ;)
Wahrscheinlich auch deswegen so langsam??

Nabend ,

ich habe mich damit schon lange nicht mehr beschäftigt , aber soweit ich mich erinnern kann, nimmt man für ein Characterset nur eine einzige Texture auf dem alle Elemente drauf sind.

Liebe Grüße - Stefan
[ App - Entwicklung ]

Mathias Wittig

Antworten
Mathias Wittig
  • Forum-Beiträge: 24

31.08.2016, 19:51:14 via Website

Danke für deinen Rat. Ich hab davor eine 2048*2048 PNG Datei ausprobiert und das hat auch sehr geruckelt. Liegt aber auch möglicherweise daran, dass ich das nicht mit der Canvas sondern so gemacht hab, dass ich ein Quadrat mit der ganzen Textur belegt hab und diese Textur nur gezoomt hab. Ich werds mal ausprobieren.(cool)

Antworten
Mathias Wittig
  • Forum-Beiträge: 24

31.08.2016, 19:55:26 via Website

Ok werd ich ausprobieren. Danke (cool)

Übrigends auch mal ein großes Lob an die Community hier. Man bekommt um einiges schneller, präziser und auch noch auf Deutsch die Antworten auf seine Fragen als bei Stackoverflow !

Probs an euch alle (laughing)

Antworten
swa00
  • Forum-Beiträge: 3.704

31.08.2016, 20:05:08 via Website

Mathias,

Danke für deinen Rat. Ich hab davor eine 2048*2048 PNG Datei ausprobiert .....

Probiere mal bitte den Weg , indem du diese große Datei im /res/drawable-nodpi ordner anstatt drawabel speicherst .....
(Den Ordner händisch anlegen)

Übrigends auch mal ein großes Lob an die Community hier. Man bekommt um einiges schneller, präziser und auch noch auf Deutsch die Antworten auf seine Fragen als bei Stackoverflow !

Dafür darfst du gerne den kleinen "Danke" Button unter jedem Beiträgen drücken ..
Pascal und ich wollen nämlich den Monatspreis gewinnen :-) (Was immer das auch sein soll)

— geändert am 31.08.2016, 20:28:22

Liebe Grüße - Stefan
[ App - Entwicklung ]

Mathias Wittig

Antworten
Mathias Wittig
  • Forum-Beiträge: 24

04.09.2016, 10:30:05 via Website

Probiere mal bitte den Weg , indem du diese große Datei im /res/drawable-nodpi ordner anstatt drawabel speicherst .....
(Den Ordner händisch anlegen)

Gut. Werd ich machen.

Dafür darfst du gerne den kleinen "Danke" Button unter jedem Beiträgen drücken ..
Pascal und ich wollen nämlich den Monatspreis gewinnen :-) (Was immer das auch sein soll)

Ist schon geschehen :D

Antworten
Mathias Wittig
  • Forum-Beiträge: 24

04.09.2016, 22:01:37 via Website

Also Schrift über Canvas hat funktioniert. Danke für den Tipp.

Ich hab aber die Befürchtung, dass das Framerateproblem an meiner Art die Texturen dazustellen liegt. Ich hab das mit dem Spritesheet schon mal früher ausprobiert (mit Zuschneiden des Bitmaps über die Texturenkoordinaten, was wohl eher nicht so effizient war), aber ich glaube dass das mein Problem nicht lösen würde, weil die Ressourcenverschwendung besteht doch eigentlich nur beim decodieren des Bitmaps. Ob ich ein 2048*2048 png decodiere und einen 128*128 Anteil ausschneide, oder halt mehrere 128*128 png's decodiere sollte doch eigentlich das selbe Resultat haben ( = man hat ein 128*128 bitmap) mit dem einzigen Unterschied, dass die Decodierphase unterschiedlich lange dauert / effizient ist. Da die Decodierphase bei mir aber recht flott ist, sollte das nicht das Problem sein, oder?

Mein generelles Vorgehen:


· in onSurfaceCreated():

  • alle pngs einzeln (ohne Spritesheet) decodieren und an das zugehörige textureHandle binden
  • alle textureHandles in einem Feld speichern, um später einfach darauf zugreifen zu können

· ich habe eine Klasse SpriteUnit:

  • ich erzeuge für jedes Objekt das ich später zeichnen will eine "Registerkarte" in der ich x&y Koordinate, die Breite des Bitmaps und welches Bitmap gezeichnet werden soll (nicht das Bitmap selbst, nur in Form eines Integers, speichere

  • Alle SpriteUnits speichere ich in einer List

· in onDrawFrame()

  • Hier gehe ich meine ganze SpriteUnit-List durch
  • Zu jeder SpriteUnit lese ich die Werte wie welches Bitmap gemalt werden soll (im Code das "mTextureDataHandle[spriteUnit.resPackID]") und die Position (im Code unten "Matrix.translateM(mModelMatrix, 0, spriteUnit.dx, spriteUnit.dy, spriteUnit.dz);").

        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureDataHandle[spriteUnit.resPackID]);
        GLES20.glUniform1i(mTextureUniformHandle, 0);
    
        Matrix.multiplyMV(mLightPosInWorldSpace, 0, mLightModelMatrix, 0, mLightPosInModelSpace, 0);
        Matrix.multiplyMV(mLightPosInEyeSpace, 0, mViewMatrix, 0, mLightPosInWorldSpace, 0);
    
    
        Matrix.setIdentityM(mModelMatrix, 0);
        Matrix.translateM(mModelMatrix, 0, spriteUnit.dx, spriteUnit.dy, spriteUnit.dz);
        Matrix.rotateM(mModelMatrix, 0, 1f, 1f, 1f, 0.0f);            
        drawSquare();
    

Ist meine Vorgehensweise sinnvoll, v.a. bei jedem Frame die Matrix bei jedem Sprite zu ändern?
In drawSquare() wird nur noch ein Quadrat mit der Textur gezeichnet:

private void drawSquare()
{
    mSquarePositions.position(0);
    GLES20.glVertexAttribPointer(mPositionHandle, mPositionDataSize, GLES20.GL_FLOAT, false,0, mSquarePositions);
    GLES20.glEnableVertexAttribArray(mPositionHandle);


    mSquareColors.position(0);
    GLES20.glVertexAttribPointer(mColorHandle, mColorDataSize, GLES20.GL_FLOAT, false,0, mSquareColors);
    GLES20.glEnableVertexAttribArray(mColorHandle);


    mSquareNormals.position(0);
    GLES20.glVertexAttribPointer(mNormalHandle, mNormalDataSize, GLES20.GL_FLOAT, false,0, mSquareNormals);
    GLES20.glEnableVertexAttribArray(mNormalHandle);


    mSquareTextureCoordinates.position(0);
    GLES20.glVertexAttribPointer(mTextureCoordinateHandle, mTextureCoordinateDataSize, GLES20.GL_FLOAT, false,0, mSquareTextureCoordinates);
    GLES20.glEnableVertexAttribArray(mTextureCoordinateHandle);


    Matrix.multiplyMM(mMVPMatrix, 0, mViewMatrix, 0, mModelMatrix, 0);
    GLES20.glUniformMatrix4fv(mMVMatrixHandle, 1, false, mMVPMatrix, 0);

    Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mMVPMatrix, 0);
    GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mMVPMatrix, 0);

    GLES20.glUniform3f(mLightPosHandle, mLightPosInEyeSpace[0], mLightPosInEyeSpace[1], mLightPosInEyeSpace[2]);
    GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 6);
}

swa00

Antworten