2

我正在尝试使用 opengl ES 2.0 创建纹理图集。我想将许多小图像绑定在一个大图像中。它在模拟器中运行良好,但不适用于设备。这是我的代码:

gl.glGenTextures(1, textureID, 0);
gl.glBindTexture(GL10.GL_TEXTURE_2D, textureID);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bmp, 0);

Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.block);
ByteBuffer pixels   = ByteBuffer.allocate(bitmap.getWidth() * bitmap.getHeight() * 4);
bitmap.copyPixelsToBuffer(pixels);

gl.glTexSubImage2D(GL10.GL_TEXTURE_2D, 0, 0, 0, bitmap.getWidth(), bitmap.getHeight(), GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, pixels);

第一个 Bitmap (bmp) 是 256x256 红色图像,第二个 Bitmap(bitmap) 是 16x16 白色图像。在模拟器中,我看到一个红色矩形,里面有一个小白色图像,但使用设备我只能看到大红色矩形。

4

2 回答 2

1

您正在使用二次幂纹理,这很好,因为 OpenGL ES 2.0 的大多数实现不支持npot纹理。现在,因为您能够在模拟器上看到纹理,所以您似乎没有使用投影矩阵( MVP矩阵)变换对象(要渲染)。这个例子展示了如何做到这一点 -

public class GLES20Renderer implements Renderer {
private int _planeProgram;
private int _planeAPositionLocation;
private int _planeACoordinateLocation;
private int _planeUMVPLocation;
private int _planeUSamplerLocation;
private FloatBuffer _planeVFB;
private FloatBuffer _planeTFB;
private ShortBuffer _planeISB;

private float[] _ViewMatrix         = new float[16];
private float[] _ProjectionMatrix   = new float[16];
private float[] _MVPMatrix          = new float[16];

private int _textureId;
public Context _context;

public GLES20Renderer(Context context) {
    _context = context;
}

public void onSurfaceCreated(GL10 gl, EGLConfig config) {
    GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1);
}

public void onSurfaceChanged(GL10 gl, int width, int height) {
    GLES20.glViewport(0, 0, width, height);
    initplane();

    float ratio = (float) width / height;
    float zNear = 0.1f;
    float zFar = 1000;
    float fov = 0.95f; // 0.2 to 1.0
    float size = (float) (zNear * Math.tan(fov / 2));
    Matrix.setLookAtM(_ViewMatrix, 0, 0, 0, 50, 0, 0, 0, 0, 1, 0);
    Matrix.frustumM(_ProjectionMatrix, 0, -size, size, -size / ratio, size / ratio, zNear, zFar);

    _planeProgram = loadProgram(_planeVertexShaderCode, _planeFragmentShaderCode);

    _planeAPositionLocation = GLES20.glGetAttribLocation(_planeProgram, "aPosition");
    _planeACoordinateLocation = GLES20.glGetAttribLocation(_planeProgram, "aCoord");
    _planeUMVPLocation = GLES20.glGetUniformLocation(_planeProgram, "uMVP");
    _planeUSamplerLocation = GLES20.glGetUniformLocation(_planeProgram, "uSampler");

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

    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, _textureId);
    InputStream is1 = _context.getResources().openRawResource(R.drawable.brick);
    Bitmap img1;
    try {
        img1 = BitmapFactory.decodeStream(is1);
    } finally {
        try {
            is1.close();
        } catch(IOException e) {
            //e.printStackTrace();
        }
    }
    GLES20.glPixelStorei(GLES20.GL_UNPACK_ALIGNMENT, 1);
    GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST); // GL_LINEAR
    GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);
    GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, img1, 0);
}

public void onDrawFrame(GL10 gl) {
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
    Matrix.multiplyMM(_MVPMatrix, 0, _ProjectionMatrix, 0, _ViewMatrix, 0);

    GLES20.glUseProgram(_planeProgram);

    GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, _textureId);
    GLES20.glUniform1i(_planeUSamplerLocation, 0);

    GLES20.glUniformMatrix4fv(_planeUMVPLocation, 1, false, _MVPMatrix, 0);
    GLES20.glVertexAttribPointer(_planeAPositionLocation, 3, GLES20.GL_FLOAT, false, 12, _planeVFB);
    GLES20.glEnableVertexAttribArray(_planeAPositionLocation);
    GLES20.glVertexAttribPointer(_planeACoordinateLocation, 2, GLES20.GL_FLOAT, false, 8, _planeTFB);
    GLES20.glEnableVertexAttribArray(_planeACoordinateLocation);
    GLES20.glDrawElements(GLES20.GL_TRIANGLES, 6, GLES20.GL_UNSIGNED_SHORT, _planeISB);
    System.gc();
}

public static void setZAngle(float angle) {
    GLES20Renderer._zAngle = angle;
}

public static float getZAngle() {
    return GLES20Renderer._zAngle;
}

private void initplane() {
    float[] planeVFA = {
            10.000000f,-10.000000f,0.000000f,
            -10.000000f,-10.000000f,0.000000f,
            10.000000f,10.000000f,0.000000f,
            -10.000000f,10.000000f,0.000000f,
    };

    float[] planeTFA = {
            // 1,0, 0,0, 1,1, 0,1
            1,1, 0,1, 1,0, 0,0
    };

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

    ByteBuffer planeVBB = ByteBuffer.allocateDirect(planeVFA.length * 4);
    planeVBB.order(ByteOrder.nativeOrder());
    _planeVFB = planeVBB.asFloatBuffer();
    _planeVFB.put(planeVFA);
    _planeVFB.position(0);

    ByteBuffer planeTBB = ByteBuffer.allocateDirect(planeTFA.length * 4);
    planeTBB.order(ByteOrder.nativeOrder());
    _planeTFB = planeTBB.asFloatBuffer();
    _planeTFB.put(planeTFA);
    _planeTFB.position(0);

    ByteBuffer planeIBB = ByteBuffer.allocateDirect(planeISA.length * 2);
    planeIBB.order(ByteOrder.nativeOrder());
    _planeISB = planeIBB.asShortBuffer();
    _planeISB.put(planeISA);
    _planeISB.position(0);
}

private int loadShader(int type, String source)  {
    int shader = GLES20.glCreateShader(type);
    GLES20.glShaderSource(shader, source);
    GLES20.glCompileShader(shader);
    return shader;
}

private int loadProgram(String vertexShaderCode, String fragmentShaderCode) {
    int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
    int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
    int program = GLES20.glCreateProgram();
    GLES20.glAttachShader(program, vertexShader);
    GLES20.glAttachShader(program, fragmentShader);
    GLES20.glLinkProgram(program);
    return program;
}

private final String _planeVertexShaderCode = 
        "attribute vec4 aPosition;          \n"
    +   "attribute vec2 aCoord;             \n"
    +   "varying vec2 vCoord;               \n"
    +   "uniform mat4 uMVP;                 \n"
    +   "void main() {                      \n"
    +   " gl_Position = uMVP * aPosition;   \n"
    +   " vCoord = aCoord;                  \n"
    +   "}                                  \n";

private final String _planeFragmentShaderCode = 
        "#ifdef GL_FRAGMENT_PRECISION_HIGH              \n"
    +   "precision highp float;                         \n"
    +   "#else                                          \n"
    +   "precision mediump float;                       \n"
    +   "#endif                                         \n"
    +   "varying vec2 vCoord;                           \n"
    +   "uniform sampler2D uSampler;                    \n"
    +   "void main() {                                  \n"
    +   " gl_FragColor = texture2D(uSampler,vCoord);    \n"
    +   "}                                              \n";

}

更多这些在 - http://www.apress.com/9781430250531

于 2013-08-02T21:04:10.997 回答
0

如果您的代码真的是 OpenGL ES 2.0,那么您不应该使用 GL10 包装类。我认为 1.0 不支持 2 纹理大小的非幂次,不使用扩展,但我猜你已经处理了?您可能在您的设备的 OpenGL ES 驱动程序中发现了一个错误,因为它适用于 AVD 模拟器。尝试使用不同类型的 GPU 的不同设备。这篇文章将有助于:

http://software.intel.com/en-us/articles/porting-opengl-games-to-android-on-intel-atom-processors-part-1

于 2013-08-02T17:20:38.260 回答