哪种更改多边形纹理的正确方法?

时间:2012-02-24 13:11:57

标签: android opengl-es

我需要一点帮助来实现OpenGL ES 1.1

我有一个带纹理的简单方形多边形(来自nehe教程)。

多边形有一个位图,当创建多边形时,方法loadGLTexture(GL10 gl,Context context)被调用一次,以加载纹理。

我需要在我的应用中添加功能以更改方块的纹理。

哪种更改多边形纹理的最佳方法?在谷歌找不到合适的方式...

感谢所有

编辑:

public class Square {
    //Buffer de vertices
    public FloatBuffer vertexBuffer;
    //Buffer de coordenadas de texturas
    private FloatBuffer textureBuffer;
    //Puntero de texturas
    private int[] textures = new int[3];
    //El item a representar
    private Bitmap bitmap; //image with POT dimensions
    //size of the polygon:
    public float w;
    public float h;
    //size of the texture
    private float textureX;
    private float textureY; 
    //Definición de vertices    
    public float vertices[] = new float[12];
    private float vertices_transformed[] = new float[12];
    //Coordenadas (u, v) de las texturas    
    private float texture[];    
    // Image ratio
    float ratio;

    public int id;

    Context context;

    //Inicializamos los buffers
    public Square(Bitmap image, Context context) {      
        int bitmapW=image.getWidth();
        int bitmapH=image.getHeight();

            w=1.00f;
            h=(float)bitmapH/bitmapW;       


        float vertices2[] = { 
            -w, -h, 0.0f,   //Bottom Left
            w, -h, 0.0f,    //Bottom Right
            -w, h, 0.0f,    //Top Left
            w, h, 0.0f      //Top Right
        };
        vertices=vertices2;

        //calculamos la siguiente potencia de 2 del lado mas largo del bitmap, alto o ancho.
        int nextPOT; 
        if (bitmapW>bitmapH)
            nextPOT=getNextPOT(bitmapW);
        else
            nextPOT=getNextPOT(bitmapH);

        //creamos un nuevo bitmap cuadrado con dimensiones potencia de 2, y dentro de el metemos la imagen
        bitmap = Bitmap.createBitmap(nextPOT, nextPOT, Bitmap.Config.ARGB_8888); //crea un bitmap transparente gracias al ARGB_8888
        Canvas comboImage = new Canvas(bitmap);
        comboImage.drawBitmap(image, 0, 0, null);
        comboImage.save();      

        //calculamos las coordenadas de la textura dentro del bitmap que es potencia de 2
        textureX = (float)bitmapW / nextPOT;
        textureY = (float)bitmapH / nextPOT;

        //creamos el array de la textura, pasándole las coordenadas ya obtenidos
        float texture2[] ={
                0.0f,textureY,
                textureX, textureY,
                0.0f, 0.0f,
                textureX,0.0f
            };

        System.out.println("bw:"+bitmapW+"   nextPOT:"+nextPOT+"   texX:"+textureX);

        texture=texture2;   


        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);      

        //setPosition(0,0);

        ratio = (float)image.getWidth() / image.getHeight();

        image.recycle();
    } 

    //Funcion de dibujado
    public void draw(GL10 gl) {
        gl.glFrontFace(GL10.GL_CCW);
        //gl.glEnable(GL10.GL_BLEND);
        //Bind our only previously generated texture in this case
        gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
        //Point to our vertex buffer
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
        gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);
        //Enable vertex buffer
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
        gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
        //Set The Color To Blue
        //gl.glColor4f(0.5f, 0.5f, 1.0f, 1.0f); 
        //Draw the vertices as triangle strip
        gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, vertices.length / 3);
        //Disable the client state before leaving
        gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
        gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
        //gl.glDisable(GL10.GL_BLEND);      
    }

    //Carga de texturas
    public void loadGLTexture(GL10 gl, Context context) {       
        //Generamos un puntero de texturas
        gl.glGenTextures(1, textures, 0);       
        //y se lo asignamos a nuestro array
        gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
        //Creamos filtros de texturas
        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);
        //Diferentes parametros de textura posibles 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);     

        //Usamos Android GLUtils para espcificar una textura de 2 dimensiones para nuestro bitmap
        GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0); 

        //Checkeamos si el GL context es versión 1.1 y generamos los Mipmaps por Flag. Si no, llamamos a nuestra propia implementación
        if(gl instanceof GL11) {
            gl.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_GENERATE_MIPMAP, GL11.GL_TRUE);
            GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
        } else {
            buildMipmap(gl, bitmap);
        }   
        //Limpiamos los bitmaps
        bitmap.recycle();       
    }

    //Nuestra implementación de MipMap. Escalamos el bitmap original hacia abajo por factor de 2 y lo asignamos como nuevo nivel de mipmap
    private void buildMipmap(GL10 gl, Bitmap bitmap) {
        int level = 0;
        int height = bitmap.getHeight();
        int width = bitmap.getWidth();
        while(height >= 1 || width >= 1) {
            GLUtils.texImage2D(GL10.GL_TEXTURE_2D, level, bitmap, 0);
            if(height == 1 || width == 1) {
                break;
            }
            level++;
            height /= 2;
            width /= 2;
            Bitmap bitmap2 = Bitmap.createScaledBitmap(bitmap, width, height, true);
            bitmap.recycle();
            bitmap = bitmap2;
        }
    }

    //returns the next POT
    public static int getNextPOT(int n){
        int i = 1;
        while(i < n)
            i *= 2;      
        return i;
    }

    public void setPosition( float x , float y ){
        vertexBuffer.put( 0 ,  vertices[0]+x );
        vertexBuffer.put( 3 ,  vertices[3]+x );
        vertexBuffer.put( 6 ,  vertices[6]+x );
        vertexBuffer.put( 9 ,  vertices[9]+x );

        vertexBuffer.put( 1 ,  vertices[1]+y );
        vertexBuffer.put( 4 ,  vertices[4]+y );
        vertexBuffer.put( 7 ,  vertices[7]+y );
        vertexBuffer.put( 10 ,  vertices[10]+y );       
    }

    public void move( float dx , float dy ){
        vertexBuffer.put( 0 ,  vertexBuffer.get(0)+dx );
        vertexBuffer.put( 3 ,  vertexBuffer.get(3)+dx );
        vertexBuffer.put( 6 ,  vertexBuffer.get(6)+dx );
        vertexBuffer.put( 9 ,  vertexBuffer.get(9)+dx );

        vertexBuffer.put( 1 ,  vertexBuffer.get(1)+dy );
        vertexBuffer.put( 4 ,  vertexBuffer.get(4)+dy );
        vertexBuffer.put( 7 ,  vertexBuffer.get(7)+dy );
        vertexBuffer.put( 10 ,  vertexBuffer.get(10)+dy );          
    }

    //CARGA DE TEXTURAS DIFERENTES PARA EL POLÍGONO
    static int[] mTextureNameWorkspace= new int[1];
    static int[] mCropWorkspace=new int[4];

    public int loadBitmap(Context context, GL10 gl, String imageName) {
        BitmapFactory.Options sBitmapOptions  = new BitmapFactory.Options();
        sBitmapOptions.inPreferredConfig = Bitmap.Config.RGB_565;
        sBitmapOptions.inScaled=false;

        int textureName = -1;
        if (context != null && gl != null) {
            gl.glGenTextures(1, mTextureNameWorkspace, 0);
            textureName = mTextureNameWorkspace[0];
            gl.glBindTexture(GL10.GL_TEXTURE_2D, textureName);
            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);

            gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE);
            gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE);

            //gl.glTexEnvf(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE, GL10.GL_REPLACE);
            gl.glTexEnvf(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE, GL10.GL_MODULATE);

            Bitmap bitmap = loadImage(imageName, context);

            GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);

            mCropWorkspace[0] = 0;
            mCropWorkspace[1] = bitmap.getHeight();
            mCropWorkspace[2] = bitmap.getWidth();
            mCropWorkspace[3] = -bitmap.getHeight();

            bitmap.recycle();

            ((GL11) gl).glTexParameteriv(GL10.GL_TEXTURE_2D, GL11Ext.GL_TEXTURE_CROP_RECT_OES, mCropWorkspace, 0);
            textures[0]=textureName;
        }
        return textureName;
    }

    public static Bitmap loadImage( String imageName, Context context){
        if( imageName.charAt(0) == '/' ) {
            imageName = imageName.substring(1);
        }
        imageName = imageName + ".png";
        Bitmap image = BitmapFactory.decodeStream(getResourceAsStream(imageName, context));
        return image;
    }
    public static InputStream getResourceAsStream( String resourceName, Context context) {
        if( resourceName.charAt(0) == '/' ) {
            resourceName = resourceName.substring(1);
        }

        InputStream is = null;
        try {
            is = context.getAssets().open( resourceName );
        } catch (IOException e) {e.printStackTrace();}
        return is;
    }


}

2 个答案:

答案 0 :(得分:0)

使用glTexSubImage2D

答案 1 :(得分:0)

事情比你想象的更复杂。 当你使用loadGLTexture(GL10 gl,Context context)时,opengl会加载你的纹理并将其id保存到int然后在render(多边形)函数中你使用这个id来指定这是你想要绘制的纹理。 您需要先加载纹理,将id保存在diferents int's上,然后使用您想要的纹理ID渲染多边形;

首先加载纹理:

int txDog=loadBitmap(context,gl,R.drawable.dog);//This generetes an opengl texture id with the given image
int txCat=loadBitmap(context,gl,R.drawable.cat);

接下来在多边形的渲染函数中添加一个名为texid的附加参数

public void Render(GL10 gl,int texid);

然后在渲染函数中搜索如下行:

gl.glBindTexture(GL10.GL_TEXTURE_2D, thetexturenameid);

用texid

替换thetexturenameid(或任何已命名的)

结束为此绘制多边形:

public void Render(gl,txDog);//if you want the dog texture
public void Render(gl,txCat);//if you want the cat texture




static int[] mTextureNameWorkspace= new int[1];
static int[] mCropWorkspace=new int[4];
public static int loadBitmap(Context context, GL10 gl, int resourceId) {
    BitmapFactory.Options sBitmapOptions  = new BitmapFactory.Options();
    sBitmapOptions.inPreferredConfig = Bitmap.Config.RGB_565;
    sBitmapOptions.inScaled=false;


    int textureName = -1;
    if (context != null && gl != null) {
        gl.glGenTextures(1, mTextureNameWorkspace, 0);

        textureName = mTextureNameWorkspace[0];
        gl.glBindTexture(GL10.GL_TEXTURE_2D, textureName);
        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);

        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE);
        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE);

      //  gl.glTexEnvf(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE, GL10.GL_REPLACE);
        gl.glTexEnvf(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE,GL10.GL_MODULATE);


        InputStream is = context.getResources().openRawResource(resourceId);
        Bitmap bitmap;

        bitmap = BitmapFactory.decodeStream(is, null, sBitmapOptions);


        GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);

        mCropWorkspace[0] = 0;
        mCropWorkspace[1] = bitmap.getHeight();
        mCropWorkspace[2] = bitmap.getWidth();
        mCropWorkspace[3] = -bitmap.getHeight();

        bitmap.recycle();

        ((GL11) gl).glTexParameteriv(GL10.GL_TEXTURE_2D, 
                GL11Ext.GL_TEXTURE_CROP_RECT_OES, mCropWorkspace, 0);




    }

    return textureName;
}

这是我能解释的最简单方法