如何在OpenGL ES 1.1上用不同的纹理填充立方体的每一面?

时间:2011-10-14 12:10:26

标签: android opengl-es textures

请,我需要有关如何在OpenGL ES 1.1上用不同纹理填充多维数据集每一面的教程/代码示例

我发现了很多教程,但没有一个能够清楚地解释如何在每个面上放置不同的纹理,但没有一个能够提供简单的代码示例。

我的实际代码(来自示例)在每个面上绘制具有相同纹理的立方体:

public class Cube {

/** The buffer holding the vertices */
private FloatBuffer vertexBuffer;
/** The buffer holding the texture coordinates */
private FloatBuffer textureBuffer;
/** The buffer holding the indices */
private ByteBuffer indexBuffer;

/** Our texture pointer */
private int[] textures = new int[1];

/** 
 * The initial vertex definition
 * 
 * Note that each face is defined, even
 * if indices are available, because
 * of the texturing we want to achieve 
 */ 
private float vertices[] = {
                    //Vertices according to faces
                    -1.0f, -1.0f, 1.0f, //Vertex 0
                    1.0f, -1.0f, 1.0f,  //v1
                    -1.0f, 1.0f, 1.0f,  //v2
                    1.0f, 1.0f, 1.0f,   //v3

                    1.0f, -1.0f, 1.0f,  //...
                    1.0f, -1.0f, -1.0f,         
                    1.0f, 1.0f, 1.0f,
                    1.0f, 1.0f, -1.0f,

                    1.0f, -1.0f, -1.0f,
                    -1.0f, -1.0f, -1.0f,            
                    1.0f, 1.0f, -1.0f,
                    -1.0f, 1.0f, -1.0f,

                    -1.0f, -1.0f, -1.0f,
                    -1.0f, -1.0f, 1.0f,         
                    -1.0f, 1.0f, -1.0f,
                    -1.0f, 1.0f, 1.0f,

                    -1.0f, -1.0f, -1.0f,
                    1.0f, -1.0f, -1.0f,         
                    -1.0f, -1.0f, 1.0f,
                    1.0f, -1.0f, 1.0f,

                    -1.0f, 1.0f, 1.0f,
                    1.0f, 1.0f, 1.0f,           
                    -1.0f, 1.0f, -1.0f,
                    1.0f, 1.0f, -1.0f,
                                        };

/** The initial texture coordinates (u, v) */   
private float texture[] = {         
                    //Mapping coordinates for the vertices
                    0.0f, 0.0f,
                    0.0f, 1.0f,
                    1.0f, 0.0f,
                    1.0f, 1.0f, 

                    0.0f, 0.0f,
                    0.0f, 1.0f,
                    1.0f, 0.0f,
                    1.0f, 1.0f,

                    0.0f, 0.0f,
                    0.0f, 1.0f,
                    1.0f, 0.0f,
                    1.0f, 1.0f,

                    0.0f, 0.0f,
                    0.0f, 1.0f,
                    1.0f, 0.0f,
                    1.0f, 1.0f,

                    0.0f, 0.0f,
                    0.0f, 1.0f,
                    1.0f, 0.0f,
                    1.0f, 1.0f,

                    0.0f, 0.0f,
                    0.0f, 1.0f,
                    1.0f, 0.0f,
                    1.0f, 1.0f,

                                        };

/** The initial indices definition */   
private byte indices[] = {
                    //Faces definition
                    0,1,3, 0,3,2,           //Face front
                    4,5,7, 4,7,6,           //Face right
                    8,9,11, 8,11,10,        //... 
                    12,13,15, 12,15,14,     
                    16,17,19, 16,19,18,     
                    20,21,23, 20,23,22,     
                                        };

/**
 * The Cube constructor.
 * 
 * Initiate the buffers.
 */
public Cube() {
    //
    ByteBuffer byteBuf = ByteBuffer.allocateDirect(vertices.length * 4);
    byteBuf.order(ByteOrder.nativeOrder());
    vertexBuffer = byteBuf.asFloatBuffer();
    vertexBuffer.put(vertices);
    vertexBuffer.position(0);

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

    //
    indexBuffer = ByteBuffer.allocateDirect(indices.length);
    indexBuffer.put(indices);
    indexBuffer.position(0);
}

/**
 * The object own drawing function.
 * Called from the renderer to redraw this instance
 * with possible changes in values.
 * 
 * @param gl - The GL Context
 */
public void draw(GL10 gl) {
    //Bind our only previously generated texture in this case
    gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);

    //Point to our buffers
    gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
    gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

    //Set the face rotation
    gl.glFrontFace(GL10.GL_CCW);

    //Enable the vertex and texture state
    gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
    gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);

    //Draw the vertices as triangles, based on the Index Buffer information
    gl.glDrawElements(GL10.GL_TRIANGLES, indices.length, GL10.GL_UNSIGNED_BYTE, indexBuffer);

    //Disable the client state before leaving
    gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
    gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
}

/**
 * Load the textures
 * 
 * @param gl - The GL Context
 * @param context - The Activity context
 */
public void loadGLTexture(GL10 gl, Context context) {
    //Get the texture from the Android resource directory
    InputStream is = context.getResources().openRawResource(R.drawable.nehe);
    Bitmap bitmap = null;
    try {
        //BitmapFactory is an Android graphics utility for images
        bitmap = BitmapFactory.decodeStream(is);

    } finally {
        //Always clear and close
        try {
            is.close();
            is = null;
        } catch (IOException e) {
        }
    }

    //Generate one texture pointer...
    gl.glGenTextures(1, textures, 0);
    //...and bind it to our array
    gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);

    //Create Nearest Filtered Texture
    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);

    //Different possible texture parameters, e.g. GL10.GL_CLAMP_TO_EDGE
    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_REPEAT);
    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_REPEAT);

    //Use the Android GLUtils to specify a two-dimensional texture image from our bitmap
    GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);

    //Clean up
    bitmap.recycle();
}
}

2 个答案:

答案 0 :(得分:12)

要使每个面具有不同的纹理,您需要单独渲染立方体的每个面。这意味着您需要为每个面设置纹理,然后渲染面部(使用glDrawArraysglDrawElements)。所以它看起来像:

glEnable(GL_TEXTURE_2D);
...                        //maybe other state setup (like buffer bindings)
glVertexPointer(...);
glEnableClientState(GL_VERTEX_ARRAY);
...

for each(face of cube)
{
    glBindTexture(GL_TEXTURE_2D, <face_texture>);
    glDrawArrays(...) or glDrawElements(...);      //draw only a single face
}

glDisableClientState(GL_VERTEX_ARRAY);
...
glDisable(GL_TEXTURE_2D);
...                         //maybe other state cleanup

如果需要不同的纹理,则无法在一次调用中渲染多维数据集的所有面。但是你当然可以将它们全部放在一个数组/ VBO中,只需使用glDrawArraysglDrawElements的参数来选择相应的面,就像上面所做的那样。

这是一个相当简化的伪代码示例,如果所有这些对你来说都很陌生,你应该深入研究一下OpenGL,并在立方体的每个面上应用不同的纹理是最不容易的问题。

编辑:好的,根据您更新的代码:首先,由于您所有顶点的位置和texCoords都存储在相同的数组中,因此我们无需更改每个面。此外,您的索引数组似乎包含所有面孔,每个面都有6个索引(2个三角形)。所有这些使整个情况变得非常容易。只需在所有面孔上使用此循环替换现有的glDrawElements调用:

for(i=0; i<6; ++i)
{
    gl.glBindTexture(GL10.GL_TEXTURE_2D, texture[i]);   //use texture of ith face
    indexBuffer.position(6*i);                          //select ith face

    //draw 2 triangles making up this face
    gl.glDrawElements(GL10.GL_TRIANGLES, 6, GL10.GL_UNSIGNED_BYTE, indexBuffer);
}

因此,对于每个面,我们选择其纹理并仅绘制与该面相对应的2个三角形。

通常,在从代码示例中学习而不是书本或类似内容时,您至少应该确保理解每行代码和每个函数参数的含义。只有这样,您才能根据自己的需求自由调整代码,并为问题制定解决方案。

答案 1 :(得分:3)

我设法将基督徒的答案拼凑起来,对于那些感兴趣的人,这里是完整的Cube.java代码:

public class Cube {

/** The buffer holding the vertices */
private FloatBuffer vertexBuffer;
/** The buffer holding the texture coordinates */
private FloatBuffer textureBuffer;
/** The buffer holding the indices */
private ByteBuffer indexBuffer;

/** Our texture pointer */
private int[] textures = new int[6];

/** Textures */
private int[] resourceIds = new int[]{
        R.drawable.img1,
        R.drawable.img2,
        R.drawable.img3,
        R.drawable.img4,
        R.drawable.img5,
        R.drawable.img6};

/**
 * The initial vertex definition
 *
 * Note that each face is defined, even
 * if indices are available, because
 * of the texturing we want to achieve
 */
private float vertices[] = {
        //Vertices according to faces
        -1.0f, -1.0f, 1.0f, //Vertex 0
        1.0f, -1.0f, 1.0f,  //v1
        -1.0f, 1.0f, 1.0f,  //v2
        1.0f, 1.0f, 1.0f,   //v3

        1.0f, -1.0f, 1.0f,  //...
        1.0f, -1.0f, -1.0f,
        1.0f, 1.0f, 1.0f,
        1.0f, 1.0f, -1.0f,

        1.0f, -1.0f, -1.0f,
        -1.0f, -1.0f, -1.0f,
        1.0f, 1.0f, -1.0f,
        -1.0f, 1.0f, -1.0f,

        -1.0f, -1.0f, -1.0f,
        -1.0f, -1.0f, 1.0f,
        -1.0f, 1.0f, -1.0f,
        -1.0f, 1.0f, 1.0f,

        -1.0f, -1.0f, -1.0f,
        1.0f, -1.0f, -1.0f,
        -1.0f, -1.0f, 1.0f,
        1.0f, -1.0f, 1.0f,

        -1.0f, 1.0f, 1.0f,
        1.0f, 1.0f, 1.0f,
        -1.0f, 1.0f, -1.0f,
        1.0f, 1.0f, -1.0f,
};

/** The initial texture coordinates (u, v) */
private float texture[] = {
        //Mapping coordinates for the vertices

        0.0f, 1.0f,
        1.0f, 1.0f,
        0.0f, 0.0f,
        1.0f, 0.0f,

        0.0f, 1.0f,
        1.0f, 1.0f,
        0.0f, 0.0f,
        1.0f, 0.0f,

        0.0f, 1.0f,
        1.0f, 1.0f,
        0.0f, 0.0f,
        1.0f, 0.0f,

        0.0f, 1.0f,
        1.0f, 1.0f,
        0.0f, 0.0f,
        1.0f, 0.0f,

        0.0f, 1.0f,
        1.0f, 1.0f,
        0.0f, 0.0f,
        1.0f, 0.0f,

        0.0f, 1.0f,
        1.0f, 1.0f,
        0.0f, 0.0f,
        1.0f, 0.0f,

};

/** The initial indices definition */
private byte indices[] = {
        //Faces definition
        0,1,3, 0,3,2,           //Face front
        4,5,7, 4,7,6,           //Face right
        8,9,11, 8,11,10,        //...
        12,13,15, 12,15,14,
        16,17,19, 16,19,18,
        20,21,23, 20,23,22,
};

/**
 * The Cube constructor.
 *
 * Initiate the buffers.
 */
public Cube() {
    //
    ByteBuffer byteBuf = ByteBuffer.allocateDirect(vertices.length * 4);
    byteBuf.order(ByteOrder.nativeOrder());
    vertexBuffer = byteBuf.asFloatBuffer();
    vertexBuffer.put(vertices);
    vertexBuffer.position(0);

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

    //
    indexBuffer = ByteBuffer.allocateDirect(indices.length);
    indexBuffer.put(indices);
    indexBuffer.position(0);
}

/**
 * The object own drawing function.
 * Called from the renderer to redraw this instance
 * with possible changes in values.
 *
 * @param gl - The GL Context
 */
public void draw(GL10 gl) {

    //Point to our buffers
    gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
    gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

    //Set the face rotation
    gl.glFrontFace(GL10.GL_CCW);

    //Enable the vertex and texture state
    gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
    gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);

    for (int i=0;i<6;i++){
        //Bind our only previously generated texture in this case
        gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[i]);
        indexBuffer.position(6*i);
        //Draw the vertices as triangles, based on the Index Buffer information
        gl.glDrawElements(GL10.GL_TRIANGLES, 6, GL10.GL_UNSIGNED_BYTE, indexBuffer);
    }

    //Disable the client state before leaving
    gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
    gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
}

/**
 * Load the textures
 *
 * @param gl - The GL Context
 * @param context - The Activity context
 */
public void loadGLTexture(GL10 gl, Context context) {

    //Generate a 6 texture pointer...
    gl.glGenTextures(6, textures, 0);

    Bitmap bitmap = null;

    for (int i=0;i<6;i++)
    {
        // Create a bitmap
        bitmap = BitmapFactory.decodeResource(context.getResources(), resourceIds[i]);

        //...and bind it to our array
        gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[i]);

        //Create Nearest Filtered Texture
        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_NEAREST);

        //Different possible texture parameters, e.g. GL10.GL_CLAMP_TO_EDGE
        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_REPEAT);
        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_REPEAT);

        //Use the Android GLUtils to specify a two-dimensional texture image from our bitmap
        GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);

        //Clean up
        bitmap = null;
    }
}