Текстуры в OpenGL ES 2.0 для Android - PullRequest
7 голосов
/ 01 июня 2011

Я новичок в OpenGL и учу себя созданию 2D-игры для Android с ES 2.0.Я начинаю с создания класса «Sprite», который создает плоскость и отображает текстуру.На практике у меня есть два объекта Sprite, которые чередуются в одном и том же месте.У меня все отлично работает с ES 1.0, но теперь, когда я перешел на 2.0, я получаю черный экран без ошибок .Я устал, пытаясь понять, что я делаю неправильно, но у меня есть сильное чувство, что это связано с моими шейдерами.Я собираюсь сбросить весь соответствующий код здесь и, надеюсь, кто-нибудь может дать мне ответ или несколько советов относительно того, что я делаю неправильно.И если не сразу видно, что я делаю не так, может быть, какой-нибудь совет, как это выяснить?Заранее благодарим за просмотр всего кода, который я собираюсь опубликовать.

Я публикую три класса:
GameRenderer - средство визуализации для моего шейдера GLSurfaceView
- создает программу шейдераобъект
Sprite - создает квадрат и рисует на нем текстуру
Кроме того, я опубликую свой источник вершинного и фрагментного шейдера.

Связанные классы, которые я не считаю достаточно релевантными для публикации:
GameActivity
GameView - GLSurfaceView
GameLoopThread - Мой основной игровой цикл
FPSCounter - выводит среднее FPS для logcat каждые 100 кадров.

Класс GameRender:

package com.detour.raw;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import android.content.Context;
import android.graphics.Bitmap;
import android.opengl.GLES20;
import android.opengl.GLU;
import android.opengl.Matrix;
import android.opengl.GLSurfaceView;

public class GameRenderer implements GLSurfaceView.Renderer{

private static final String LOG_TAG = GameRenderer.class.getSimpleName();
Context mContext;
Bitmap bitmap;

private float red = 0.0f;
private float green = 0.0f;
private float blue = 0.0f;

Shader shader;
FPSCounter fps;
Sprite sprite;
Sprite sprite2;
int x = 0;
private float[] mProjMatrix = new float[16];
private float[] mVMatrix = new float[16];

//int[] vertexShader;
//int[] fragmentShader;
//int program;
//String vShaderSource = "";
//String fShaderSource = "";


public GameRenderer(Context context){
    mContext = context;

    //create objects/sprites
    sprite = new Sprite(mContext);
    sprite2 = new Sprite(mContext);
    fps = new FPSCounter();
}

@Override
public void onDrawFrame(GL10 gl) {

    GLES20.glClearColor(red, green, blue, 1.0f);
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);

    if(x>3){
        x=0;
    }
    if(x%2==0){
        sprite.draw(gl);
    }else{
        sprite2.draw(gl);
    }
    x++;

    fps.calculate();
    //fps.draw(gl);
}

@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {

    GLES20.glViewport(0, 0, width, height);
    float ratio = (float)(width/height);
    Matrix.frustumM(mProjMatrix, 0, -ratio, ratio, -1, 1, 0.5f, 10);
}

@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
    // TODO Auto-generated method stub

    GLES20.glEnable(GLES20.GL_TEXTURE_2D);
    GLES20.glEnable(GLES20.GL_DEPTH_TEST);
    GLES20.glClearDepthf(1.0f);
    GLES20.glDepthFunc(GLES20.GL_LEQUAL);
    GLES20.glDepthMask(true);
    GLES20.glEnable(GLES20.GL_CULL_FACE);
    GLES20.glCullFace(GLES20.GL_BACK);
    GLES20.glClearColor(red, green, blue, 1.0f);

    //load sprite/object textures (preferably loop through an array of all sprites).
    sprite.loadGLTexture(gl, mContext, R.drawable.raw1);
    sprite2.loadGLTexture(gl, mContext, R.drawable.raw2);

    Matrix.setLookAtM(mVMatrix, 0, 0, 0, -5.0f, 0.0f, 0f, 0f, 0f, 0.0f, 0.0f);

    System.gc();
}

}

Класс шейдера:

package com.detour.raw;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;

import android.content.Context;
import android.opengl.GLES20;
import android.util.Log;

public class Shader {

public static final String TAG = Shader.class.getSimpleName();  
int program;
int vertexShader;
int fragmentShader;

String vShaderSource;
String fShaderSource;

public Shader(){
    //blank constructor
    //createProgram();
}

public Shader(String vs_source, String fs_source){
    this.vShaderSource = vs_source;
    this.fShaderSource = fs_source;

    createProgram();
}

public Shader(int vs_source_id, int fs_source_id, Context context) {

    StringBuffer vs = new StringBuffer();
    StringBuffer fs = new StringBuffer();

    try{
        InputStream inputStream = context.getResources().openRawResource(vs_source_id);
        BufferedReader in = new BufferedReader(new InputStreamReader(inputStream));

        String read = in.readLine();
        while (read != null) {
            vs.append(read + "\n");
            read = in.readLine();
        }
        vs.deleteCharAt(vs.length() - 1);

        inputStream = context.getResources().openRawResource(fs_source_id);
        in = new BufferedReader(new InputStreamReader(inputStream));

        read = in.readLine();
        while (read != null) {
            fs.append(read + "\n");
            read = in.readLine();
        }
        fs.deleteCharAt(fs.length() - 1);
    }catch (Exception e){
        Log.d("ERROR-readingShader", "Could not read shader: " + e.getLocalizedMessage());
    }

    this.vShaderSource = vs.toString();
    this.fShaderSource = fs.toString();

    createProgram();
}

private void createProgram(){

    program = GLES20.glCreateProgram();
    if(program!=0){
        vertexShader = createShader(GLES20.GL_VERTEX_SHADER, vShaderSource);
        fragmentShader = createShader(GLES20.GL_FRAGMENT_SHADER, fShaderSource);

        GLES20.glAttachShader(program, vertexShader);
        GLES20.glAttachShader(program, fragmentShader);
        GLES20.glLinkProgram(program);
    }else{
        Log.e(TAG, "Couldn't create program.");
    }


}

private int createShader(int type, String source){
    int shader = GLES20.glCreateShader(type);
    if(shader!=0){
        GLES20.glShaderSource(shader, source);
        GLES20.glCompileShader(shader);
    }

    return shader;
}

public int getProgram(){
    return program;
}

Класс спрайта:

package com.detour.raw;

import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;

import javax.microedition.khronos.opengles.GL10;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLES20;
import android.opengl.GLUtils;

public class Sprite {

//public static final int FRAME_WIDTH = 64;
//public static final int FRAME_HEIGHT = 64;
private static final String LOG_TAG = Sprite.class.getSimpleName();
Context mContext;
Bitmap bitmap;

private int textureLoc;
private int vertexLoc;
private int[] textures = new int[1];
//private int[] pixels;

/*private float textureCoordinates[] = {
        0.0f, 0.0f,
        0.0f, 1.0f,
        1.0f, 1.0f,
        1.0f, 0.0f};*/

private float vertices[] = {
          -1.0f,  1.0f,// 0.0f,
          -1.0f, -1.0f,// 0.0f,
           1.0f, -1.0f,// 0.0f,
           1.0f,  1.0f// 0.0f
           };

private short[] indices = {
        0, 1, 2,
        0, 2, 3};

private FloatBuffer vertexBuffer;
//private IntBuffer textureBuffer;
private ShortBuffer indexBuffer;

Shader shader;
int program;
String vShaderSource = "";
String fShaderSource = "";

public Sprite(Context context){

    mContext = context;

    ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
    vbb.order(ByteOrder.nativeOrder());
    vertexBuffer = vbb.asFloatBuffer();
    vertexBuffer.put(vertices);
    vertexBuffer.position(0);



    ByteBuffer ibb = ByteBuffer.allocateDirect(indices.length * 2);
    ibb.order(ByteOrder.nativeOrder());
    indexBuffer = ibb.asShortBuffer();
    indexBuffer.put(indices);
    indexBuffer.position(0);

}

public void draw(GL10 gl) {

    GLES20.glDrawElements(GLES20.GL_TRIANGLES, indices.length, GLES20.GL_FLOAT, indexBuffer);

}

public void loadGLTexture(GL10 gl, Context context, int id){

    shader = new Shader(R.raw.sprite_vs, R.raw.sprite_fs, mContext);
    program = shader.getProgram();

    GLES20.glUseProgram(program);

    vertexLoc = GLES20.glGetAttribLocation(program, "a_position");
    textureLoc = GLES20.glGetUniformLocation(program, "u_texture"); //texture

    InputStream is = context.getResources().openRawResource(id);
    try {
        bitmap = BitmapFactory.decodeStream(is);
    } finally {
        try {
            is.close();
            is = null;
        } catch (IOException e) {
        }
    }

    //pixels = new int[(bitmap.getWidth()*bitmap.getHeight())];
    //bitmap.getPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());

    /*ByteBuffer byteBuf = ByteBuffer.allocateDirect(pixels.length * 4);
    byteBuf.order(ByteOrder.nativeOrder());
    textureBuffer = byteBuf.asIntBuffer();
    textureBuffer.put(pixels);
    textureBuffer.position(0);*/

    GLES20.glDeleteTextures(1, textures, 0);
    GLES20.glGenTextures(1, textures, 0);
    GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]);
    GLES20.glUniform1i(textureLoc, 0);

    GLES20.glEnableVertexAttribArray(vertexLoc);
    GLES20.glVertexAttribPointer(vertexLoc, 2, GLES20.GL_FLOAT, false, 0, vertexBuffer);

    GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
    GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
    GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
    GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);

    //GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, FRAME_WIDTH, FRAME_HEIGHT, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, byteBuf);//(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
    GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);

    bitmap.recycle();
}

}

Вершинный шейдер(sprite_vs.txt):

#version 110

attribute vec2 a_position;

varying vec2 v_texcoord;

void main()
{
    gl_Position = vec4(a_position, 0.0, 1.0);
    v_texcoord = a_position * vec2(0.5) + vec2(0.5);
}

Фрагмент (пиксель) шейдера (sprite_fs.txt):

#version 110

uniform sampler2D u_texture;

varying vec2 v_texcoord;

void main()
{
    gl_FragColor = texture2D(u_texture, v_texcoord);
}

Большое спасибо, если вына самом деле нашли время, чтобы просмотреть это!Надеюсь, что кто-то еще может использовать это как ресурс для себя в будущем.

1 Ответ

4 голосов
/ 14 июня 2011

Несколько замечаний / вопросов:

  1. Я не знаю, как вы изменили фрагментный шейдер, но версия, которая публикуется в данный момент, требует спецификатора точности.Просто добавьте:

    precision mediump float;
    

    наверх, и оно должно работать.Что касается черного экрана, вот несколько вопросов:

  2. Когда вы изменяете glClearColor на что-то не черное и закомментируете все команды рисования, он все еще выглядит черным?Если это так, то у вас есть большая проблема, чем текстуры.

  3. Во-вторых, если вы проигнорируете вывод текстуры и попытаетесь нарисовать каждый спрайт как простой цветной прямоугольник без данных текстуры, что делать?ты получаешь?Вы должны увидеть какой-то цветной прямоугольник на экране.

  4. Наконец, вам необходимо связать текстуру перед вызовом glDrawElements.(Хотя это не должно иметь значения в этом примере, так как вы еще не изменили состояние.)

...