3 Stimmen

Android OpenGL ES 2.0 schwarze Textur

Um dies vorwegzunehmen: Ja, ich habe mir die große Menge an zuvor auf dieser Website gestellten Fragen zu "Android OpenGL ES 2.0 schwarzen Texturen" angesehen. Nein, keine von ihnen war hilfreich für meine Situation. Nein, ich bin mir nicht sicher, ob ich den Titel in angemessener Anzahl von Zeichen besser formulieren kann.

Ich habe einer Reihe von Tutorials gefolgt und konnte eine sehr einfache Renderer-Klasse einrichten, die Texturen ordnungsgemäß geladen und gerendert hat (Projekt A). Ich habe dann versucht, dieses sehr einfache Rendering-System in eine Spiel-Engine zu implementieren (Projekt B). Alles funktioniert genau gleich, außer dass texture2D() aus irgendeinem Grund schwarz zurückgibt. Ich habe viel Debugging versucht und viel gegoogelt, alles vergebens. Deshalb bitte ich um Hilfe.

Meine Vertex- und Fragment-Shader. Sie haben in Projekt A einwandfrei funktioniert, daher glaube ich nicht, dass dies die Ursache des Problems ist, nur zur Vollständigkeit einschließend.

private static final String VERTEX_SHADER_SOURCE =
...
"attribute vec2 a_TexCoord;" +
"varying vec2 v_TexCoord;" +

"void main() {" +
"   v_TexCoord = a_TexCoord;" +
...
"}";

private static final String FRAGMENT_SHADER_SOURCE =
"precision mediump float;" +
"uniform sampler2D u_Texture;" +
"varying vec2 v_TexCoord;" +

"void main() {" +
"   gl_FragColor = texture2D(u_Texture, v_TexCoord);" +
"}";

Ich erstelle, kompiliere und füge diese Shader dem Programm ohne Fehler hinzu. Danach setze ich meine Handles entsprechend - ich setze auch u_Texture auf Textureinheit 0, weil sich das nicht ändert:

...
sTexUniformHandle = GLES20.glGetUniformLocation(sProgramHandle, "u_Texture");
sMVPHandle = GLES20.glGetUniformLocation(sProgramHandle, "u_MVPMatrix");
sPositionHandle = GLES20.glGetAttribLocation(sProgramHandle, "a_Position");
sTexCoordHandle = GLES20.glGetAttribLocation(sProgramHandle, "a_TexCoord");

GLES20.glUseProgram(sProgramHandle);
GLES20.glUniform1i(sTexUniformHandle, 0);
GLES20.glUseProgram(0);
...

Dann lade ich meine Textur:

...
int[] texData = Utils.createTexture(context, resId);
mTexDataHandle = texData[0];
...
public static int[] createTexture(Context context, int resId) { // gibt {TextureHandle, Breite, Höhe} zurück
    int width = -1;
    int height = -1;

    int[] texHandle = new int[1];
    GLES20.glGenTextures(1, texHandle, 0);

    if (texHandle[0] != 0) {
        BitmapFactory.Options opts = new BitmapFactory.Options();
        opts.inScaled = false;

        final Bitmap bm = BitmapFactory.decodeResource(context.getResources(), resId, opts);
        width = bm.getWidth();
        height = bm.getHeight();

        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texHandle[0]);

        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);

        GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bm, 0);

        bm.recycle();
    }

    if (texHandle[0] == 0) {
        throw new RuntimeException("Fehler beim Laden der Textur");
    }

    return new int[]{texHandle[0], width, height};
}

In Projekt A musste ich die Texturenwicklung nicht setzen, obwohl meine Textur 32 x 19 ist. Ich habe meine Textur auf 32 x 32 geändert und die Texturwicklung als Schutzmaßnahme auf clamp gesetzt, damit mir niemand sagen würde, dass das mein Fehler war. Das Bitmap wird geladen - ich habe Breite, Höhe und einige ausgewählte Pixel zum Debuggen geschrieben und sie waren genau richtig.

In meiner Draw-Methode aktiviere ich das Attribut a_TexCoord und zeige es auf die Daten:

...
GLES20.glEnableVertexAttribArray(sTexCoordHandle);
...
GLES20.glVertexAttribPointer(sTexCoordHandle, mTexCoordDataSize, GLES20.GL_FLOAT, false, 0, mTexCoordBuffer);
...

Ich habe den gesamten mTexCoordBuffer in eine Debug-Nachricht geschrieben und er ist korrekt mit den Texturkoordinatendaten geladen.

Zuletzt setze ich die aktive Textur-Einheit auf 0, binde meine Texturdaten daran und zeichne:

...
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTexDataHandle);

GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 6);
...

Ich bin ganz neu in Sachen Grafikbibliothek, aber ich habe mein Bestes getan, um zu verstehen, was hier eigentlich vor sich geht. Ich dachte, ich hätte alles verstanden, aber das ist offensichtlich nicht der Fall. Soweit ich erkennen kann, funktionieren die Shader ordnungsgemäß - das schwarze Rechteck erscheint genau dort, wo es sollte (und auch in Projekt A). Die Texturkoordinatendaten, die ich übergebe, sind genau die gleichen wie in Projekt A, und ich habe nichts daran geändert, wie das geladen wird. Dies lässt die eigentlichen Texturdaten als Hauptverdächtige zurück, jedoch habe ich versucht, sie genauso einzurichten wie in Projekt A, und es scheint korrekt zu sein. Ich würde es sehr begrüßen, wenn jemand erfahrener als ich meinen Fehler aufzeigen könnte.

4voto

pastrypuncher Punkte 115

Weh dem, ich wusste, es würde etwas sein, das eine Fläche wert ist. Allerdings sollte ich wohl froh sein, dass ich den Fehler so schnell gefunden habe und dass ich tatsächlich den GLES-Code verstanden habe, den ich verwendet habe. Andererseits verstehe ich anscheinend nicht die Grundlagen von Java.

Auf jeden Fall stellte sich heraus, dass ich eine Menge Dinge in den Konstruktoren meiner Renderer- und GameState-Klassen gemacht habe, die ich zu diesem Zeitpunkt nicht hätte tun sollen. Ich habe eine allocateGameState() Methode in GameState erstellt und sie im onSurfaceCreated() meines Renderers aufgerufen; Problem gelöst.

Was mich immer noch verwirrt, ist: Ich fand heraus, dass dies mein Fehler war, indem ich zu Projekt A zurückgegangen bin und den Code so geändert habe, dass er Projekt B emulierte. Am Ende hatte ich Glück und machte den gleichen Fehler, den Renderer-Konstruktor falsch zu verwenden, um Textur/Shader/Programmdaten zu instanziieren. Dieses Mal wurde ich jedoch mit folgendem Fehler bombardiert: "Aufruf der OpenGl ES API ohne aktuellen Kontext". Ich habe das schnell behoben und die gleiche Lösung auf Projekt B angewendet, aber es macht mich schon wundern, warum ich den gleichen Fehler nicht bei Projekt B bekommen habe.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X