2011-04-18 12 views
10

Tengo una aplicación que he estado jugando repetidamente en Android, usa opengl-es.Android Opengl-es cargando un no poder de 2 textura

Actualmente Cómo cargo texturas de un mapa de bits, así:

//Load up and flip the texture - then dispose the temp 
    Bitmap temp = BitmapFactory.decodeResource(Deflecticon.getContext().getResources(), resourceID); 
    Bitmap bmp = Bitmap.createBitmap(temp, 0, 0, temp.getWidth(), temp.getHeight(), flip, true); 
    temp.recycle(); 

    //Bind the texture in memory 
    gl.glBindTexture(GL10.GL_TEXTURE_2D, id); 

    //Set the parameters of the 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_LINEAR); 

    //On to the GPU 
    GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bmp, 0); 

La cuestión obvia es que la textura que estoy usando tiene que ser una potencia de 2. Por el momento estoy pre-edición de la texturas en photoshop para ser un poder de 2 y simplemente tienen bordes vacíos. Sin embargo, esto es un poco tedioso y quiero poder cargarlos tal como están. Reconocer que no son un poder de 2 y cargarlos en una textura que sea.

Sé que podría escalar el mapa de bits para convertirme en una potencia de 2 tamaños y simplemente estirar la textura, pero no deseo estirar la textura y en algunos casos podría querer poner varias texturas en un "atlas".

Sé que puedo usar glTexSubImage2D() para pegar en la textura los datos que deseo en el origen que deseo. ¡Esto es genial!

Sin embargo, no sé cómo en Android para inicializar una textura sin datos?

En esta pregunta previously asked la sugerencia fue llamar a glTexImage2D() sin datos y luego llenarlo.

Sin embargo, en Android cuando llamas "GLUtils.texImage2D (GL10.GL_TEXTURE_2D, 0, bmp, 0);" usted no especifica un ancho/alto. Lo lee del mapa de bits que supongo.

¿Cuál es la mejor manera de hacerlo? ¿Puedo crear un nuevo mapa de bits con la potencia correcta de 2 tamaños solo en blanco y sin rellenar con ningún dato y usar esto para inicializar la textura y luego pegarla con subimágenes? ¿O debería hacer un nuevo mapa de bits de alguna manera para copiar los píxeles que quiero (no estoy seguro si puedes hacer esto fácilmente) en este nuevo mapa de bits (dejando bordes) y luego simplemente usar esto?

Editar: Aclaró que estoy usando OpenGL.

Respuesta

4

Creo que si trataste de crear un mapa de bits con la potencia de 2 tamaños de ejes y luego agregar tu mapa de bits debería funcionar bien. tal vez algo así como

Bitmap.createBitmap(notPowerOf2Bitmap, offx, offy, xsize, ysize, bitmapFlag) 

aparte de eso, yo diría sufrir a través del proceso de photoshop. ¿Cuántas fotos tienes?

+0

No hay muchos, solo esperamos poder cambiarlos en una fecha posterior y hace que sea más fácil si el cambio de tamaño se hace muy bien! Este método dice que toma un subconjunto del no POTBitmap. ¿Significa esto que si el mapa de bits del subconjunto es más pequeño que el especificado xSize e ySize tendría bordes en blanco? ¿O lo estiraría? (Experimentaría pero, lamentablemente, no en mi PC de codificación). – iexus

+0

Los mapas de bits no deben estirarse a menos que se arrojen a un método createScaledBitmap. El espacio restante estará vacío. – AedonEtLIRA

+0

Lo siento por la respuesta tardía, he estado saliendo con otras cosas, sin embargo, llegué a implementar esto y no funciona a través de este método. No se puede sub mapa de bits en un mapa de bits con un tamaño más grande que la fuente que parece ... Ahora estoy un poco perdido. – iexus

2

Los mapas de bits sin alimentación de dos (NPOT) son compatibles con algunas plataformas GLES, pero debe verificar si existe la extensión adecuada. Sin embargo, tenga en cuenta que, al menos en PowerVR SGX, aunque se admite NPOT, todavía existen otras restricciones bastante arbitrarias; por ejemplo, el ancho de su textura debe ser un múltiplo de 2 (si no es una potencia de 2). Además, la renderización de NPOT tiende a ser un poco más lenta en muchas GPU.

Una cosa que puede hacer es simplemente crear una textura de envoltura que sea un tamaño de potencia de dos y luego usar glTexSubimage2D para cargar la textura para cubrir solo parte de eso, y luego ajustar las coordenadas de su textura en consecuencia. El inconveniente obvio de esto es que no puede usar envoltura de texturas en esa circunstancia. Si es absolutamente necesario admitir el ajuste, puede escalar su textura al tamaño más cercano de poder de dos antes de llamar a glTexImage2D, aunque esto normalmente introduce artefactos de muestreo y hace que las cosas se vean borrosas, especialmente si está tratando de hacer píxeles precisos en 2D trabajo.

Otra cosa que podría considerar, si no necesita admitir el ajuste, es hacer un "atlas de textura", en el que condensa todas sus texturas en unas pocas texturas grandes, y haga que sus polígonos se asignen a solo algunas porciones de los atlas de textura. Debe tener cuidado al generar MIPmaps, pero aparte de eso, generalmente proporciona un beneficio de rendimiento bastante bueno, así como un uso más eficiente de la memoria de textura, ya que no está desperdiciando tanto en imágenes acolchadas o escaladas.

+0

Como mi pregunta dice, ¿cómo se hace una textura de envoltura en Android que se muestrea? ¿Cuál es el mejor método para hacer esto? – iexus

+0

Mire la documentación para glTexSubimage2D. – fluffy

0

Uh ¿por qué no creas dos mapas de bits? Cargue el primero como lo hace y luego use createBitmapScaled para convertir ese bitmap en una potencia de dos. En cuanto al rendimiento, no sé si es el método más rápido posible, pero funciona.

2

Tengo 2 soluciones que he empleado para este problema. Puedo ser más específico si es necesario, pero conceptualmente es posible: -

  1. que la imagen sea una potencia de 2, y la sección para recortar de llenar con el canal alfa del 100% y cargar las imágenes con alfa activado.

  2. Ajusta tu vector de textura/buffer para que no cargue esa sección. Así que en lugar de utilizar el valor por defecto

    float texture[] = { 
        0.0f, 1.0f, // 
        1.0f, 1.0f, // 
        0.0f, 0.0f, // 
        1.0f, 0.0f, // 
    }; 
    

como la matriz (obviamente esto es para cargar una imagen a un 2 plaza triangulada), factor de nuevo por la relación de la zona a recortar, por ejemplo.

float texture[] = { 
     0.0f, 0.75f, // 
     0.9f, 0.75f, // 
     0.0f, 0.0f, // 
     0.9f, 0.0f, // 
    }; 

por supuesto, ser preciso con su matemáticas o el bit deseado puede hacer sangrar, o tendrá que cortar parte de la imagen real. Obviamente, este conjunto se calcula sobre la marcha y no está codificado como lo he demostrado aquí.

0

Puede usar GLES20.glTexImage2D() para crear una textura vacía con ancho y alto especificados. El código de ejemplo es public static int genTexture (int texWidth, int texHeight) { int [] textureIds = new int [1]; GLES20.glGenTextures (1, textureIds, 0); assertNoError(); int textureId = textureIds [0]; texWidth = Utils.nextPowerOf2 (texWidth); texHeight = Utils.nextPowerOf2 (texHeight);

GLES20.glBindTexture(GL11.GL_TEXTURE_2D, textureId); 
    GLES20.glTexParameteri(
      GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); 
    GLES20.glTexParameteri(
      GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR); 
    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.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, 
      texWidth, texHeight, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null); 

    return textureId; 
} 
Cuestiones relacionadas