Как заполнить каждую сторону куба различными текстурами на OpenGL ES 1.1?
Пожалуйста, мне нужны учебники/примеры кода, как заполнить каждую сторону куба различными текстурами на 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();
}
}
Ответы
Ответ 1
Чтобы каждая сторона имела другую текстуру, вам нужно визуализировать каждую грань куба индивидуально. Это означает, что для каждого лица вам необходимо установить текстуру, а затем визуализировать лицо (используя glDrawArrays
или glDrawElements
). Таким образом, это будет выглядеть примерно так:
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 и просто использовать аргументы glDrawArrays
или glDrawElements
, чтобы выбрать соответствующую грань, как это сделано выше.
Это довольно упрощенный пример псевдокода, и если все это звучит очень чуждо вам, вы должны углубиться в OpenGL немного глубже, и применение любой другой текстуры к каждой грани куба - это ваша наименьшая проблема.
EDIT: Хорошо, в соответствии с вашим обновленным кодом: во-первых, поскольку все позиции ваших вершин и текс-кодов хранятся в тех же массивах, нам не нужно менять их на лицо. Кроме того, ваш индексный массив, как представляется, содержит все грани, хранящиеся на грани, как 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
Мне удалось собрать ответ от христиан, для тех, кого это интересует, вот полный код 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;
}
}