GLSurfaceView交换正在绘制的2D位图

时间:2010-09-08 20:18:37

标签: java android graphics opengl-es

我有一个从数据库接收信息的应用程序,用于将2D位图可视化到GLSurfaceView上。收到的信息将决定位图的x位置,以及要使用的位图图像(我的res文件夹中有4个不同的位图可供选择)。

以下是正在使用的三个类。 Activity通过将ArrayList传递给GLLayer类来设置需要绘制的Shapes对象。此ArrayList通过另一个setList方法传递给ShapeStorage类的实例。这个班负责收到它们时的绘图。

我遇到的问题如下。假设我收到一个对象(让我们说它是位于x = 1处的正方形)。一段时间过去了,我收到另一个形状(这次,它是一个三角形,它位于x = -1)。但是,当这个新形状出现在屏幕上时,旧位图的外观会变为三角形,而新的位图会变成正方形。换句话说,对象本身处于它们应该处于的正确位置,但与它们相关联的位图已经改变。有谁知道这可能是什么原因造成的?我仍然是OpenGL-ES的新手,虽然这段代码看起来很复杂,但它只涉及为View设置一堆不同的属性。请帮帮我,StackOverflow!你是我唯一的希望。

public class GLLayer extends GLSurfaceView implements Renderer {
    int onDrawFrameCounter=1;
    int[] cameraTexture;
    byte[] glCameraFrame=new byte[256*256]; //size of a texture must be a power of 2
    private Context context;
    FloatBuffer cubeBuff;
    FloatBuffer texBuff;
    ShapeStorage shapes;
    ArrayList<Shapes> shapereceptionbuffer;

    public GLLayer(Context c) {
        super(c);
        this.context=c;
        //Initiate our stars class with the number of stars
        shapes = new ShapeStorage();
        shapereceptionbuffer=new ArrayList<Shapes>();

        this.setEGLConfigChooser(5, 6, 5, 8, 16, 0);
        this.setRenderer(this); //set the following class as a GLSurfaceView renderer
        this.getHolder().setFormat(PixelFormat.TRANSPARENT); //makes the GLSurfaceView translucent

    }

    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        try {       
            gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
            gl.glShadeModel(GL10.GL_SMOOTH);                    //Enable Smooth Shading
            gl.glEnable(GL10.GL_TEXTURE_2D);                    //Enable Texture Mapping
            gl.glEnable(GL10.GL_BLEND);                         //Enable blending
            gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);            //Black Background
            gl.glClearDepthf(1.0f);                             //Depth Buffer Setup
            gl.glDisable(GL10.GL_DEPTH_TEST);                   //Disable depth test
            gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE);     //Set The Blending Function For Translucency
            shapes.setTextures(gl,context);



        } catch (Exception e) {
            // TODO Auto-generated catch block
            Log.d("Created",e.getMessage());
        }
    }//end of surfacecreated    

    public void setList(ArrayList<Shapes> receivedList){
        synchronized(this.shapereceptionbuffer){
            shapereceptionbuffer=receivedList;

        }
    }

    public void onSurfaceChanged(GL10 gl, int width, int height) {  
        try {

            if(height == 0) {                       //Prevent A Divide By Zero By
                height = 1;                         //Making Height Equal One
            }

            gl.glViewport(0, 0, width, height);//specifies transformation from normalized device coordinates to window coordinates
            float ratio = (float) width / height;
            gl.glMatrixMode(GL11.GL_PROJECTION); //Select The Projection Matrix
            gl.glLoadIdentity();//Reset The Projection Matrix
            GLU.gluPerspective(gl, 45.0f, ratio, 0.1f, 100.0f);
            gl.glMatrixMode(GL11.GL_MODELVIEW);//Select The Modelview Matrix
            gl.glLoadIdentity();//Reset The Modelview Matrix
        } catch (Exception e) {
            // TODO Auto-generated catch block
            Log.d("Changed",e.getMessage());
        }
        //GLU.gluLookAt(gl, 0, 0, 4.2f, 0, 0, 0, 0, 1, 0);//eye-point location, center of the scene and an UP vector        
    }//end of surfacechanged

    public void onDrawFrame(GL10 gl) {
        try {
            gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); //Clear Screen And Depth Buffer
            Log.d("Buffer Size", String.valueOf(shapereceptionbuffer.size()));
            synchronized(this.shapereceptionbuffer){

                shapes.setShapes(shapereceptionbuffer);
                shapes.draw(gl, this.context);
            }

        } catch (Exception e) {
            Log.d("Draw",e.getMessage());
        }   
    }//end of ondrawframe
}

此类负责绘制从外部数据库接收的每个形状。

/**
 * This class contains, loads, initiates textures and draws our Shapes
 */
public class ShapeStorage {
    private ArrayList<Shapes> shapestoragebuffer;
    private Random rand = new Random(); // Initiate Random for random values of
                                        // stars

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

    /**
     * Constructor for our holder
     */
    public ShapeStorage() {
        shapestoragebuffer = new ArrayList<Shapes>();
    }

    public void setShapes(ArrayList<Shapes> receivedlist) {
        shapestoragebuffer = receivedList;
    }

    public void setupTextures(GL10 gl, Context context) {
        // Get the texture from the Android resource directory
        InputStream is = null;
        gl.glGenTextures(4, textures, 0);
        for (int i = 2; i < 6; i++) {
            switch (i) {
            case 2:
                is = context.getResources().openRawResource(R.drawable.square);
                break;
            case 3:
                is = context.getResources().openRawResource(R.drawable.circle);
                break;

            case 4:
                is = context.getResources().openRawResource(R.drawable.hexagon);
                break;

            case 5:
                is = context.getResources()
                        .openRawResource(R.drawable.triangle);
                break;
            }

            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 the texture pointer

            // Create Linear Filtered Texture and bind it to texture
            GLUtils.texImage2D(GL11.GL_TEXTURE_2D, 0, bitmap, 0);
            gl.glBindTexture(GL11.GL_TEXTURE_2D, textures[i - 2]);
            gl.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER,
                    GL11.GL_LINEAR);
            gl.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER,
                    GL11.GL_LINEAR);

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

    /**
     * The drawing function.
     * 
     * @param gl
     *            - The GL Context
     * @param twinkle
     *            - Twinkle on or off
     */
    public void draw(GL10 gl, Context context) {
        // Bind the icon texture for all Shapes



        for (int loop = 0; loop < shapestoragebuffer.size(); loop++) {
            // Recover the current star into an object
            Shapes shape = shapestoragebuffer.get(loop);

            gl.glLoadIdentity(); // Reset The Current Modelview Matrix
            // gl.glRotatef(180.0f, -1.0f, 0.0f, 0.0f);
            float x = shape.get_Offset_from_center();
            gl.glTranslatef(x, 0.0f, -40.0f);

            // Draw
            switch (victim.getType()) {
            // green
            case 2:
                shape.draw(gl, textures[0]);
                break;
            // red
            case 3:
                shape.draw(gl, textures[1]);
                break;
            // yellow
            case 4:
                shape.draw(gl, textures[2]);
                break;

            case 5:
                shape.draw(gl, textures[3]);
                break;
            }

        }
    }
}

这是定义绘制到GLSurfaceView的每个对象的类;每个正在绘制的形状。

public class Shapes {


    private int _Offset_from_center;
    private int type;

    Context c;
    /** The buffer holding the vertices */
    private FloatBuffer vertexBuffer;
    /** The buffer holding the texture coordinates */
    private FloatBuffer textureBuffer;

    /** The initial vertex definition */
    private float vertices[] = {
                                -1.0f, -1.0f, 0.0f,     //Bottom Left
                                1.0f, -1.0f, 0.0f,      //Bottom Right
                                -1.0f, 1.0f, 0.0f,      //Top Left
                                1.0f, 1.0f, 0.0f        //Top Right
                                                    };

    /** The initial texture coordinates (u, v) */   
    private float texture[] = {
                                0.0f, 0.0f, 
                                1.0f, 0.0f, 
                                0.0f, 1.0f, 
                                1.0f, 1.0f,
                                            };
    public Shapes() {
        //
        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);
    }


    public int get_Offset_from_center() {
        return _Offset_from_center;
    }

    public void set_Offset_from_center(int _Offset_from_center) {
        this._Offset_from_center = _Offset_from_center;
    }

    public int getType() {
        return type;
    }

    public void setType(int type) {
        this.type = type;
    }

    /**
     * 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,int texture) {
        gl.glBindTexture(GL11.GL_TEXTURE_2D, texture);
        //Enable the vertex, texture and normal state
        gl.glEnableClientState(GL11.GL_VERTEX_ARRAY);
        gl.glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY);

        //Point to our buffers
        gl.glVertexPointer(3, GL11.GL_FLOAT, 0, vertexBuffer);
        gl.glTexCoordPointer(2, GL11.GL_FLOAT, 0, textureBuffer);

        //Draw the vertices as triangle strip
        gl.glDrawArrays(GL11.GL_TRIANGLE_STRIP, 0, vertices.length / 3);

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


    }


} 

1 个答案:

答案 0 :(得分:4)

你正在用纹理做一些非常奇怪的事情。为什么要为每一帧上传每个形状的纹理图像数据,为什么在渲染形状之后

以下是OpenGL中常用的纹理流程:

在应用初始化时间:

  1. 使用glGenTextures生成纹理ID。
  2. 使用glBindTexture将该ID设为当前纹理。
  3. 设置纹理参数。
  4. 使用texImage2D或类似内容上传图片数据。
  5. 然后,每次你需要用纹理渲染东西时:

    1. 使用与上面使用的ID相同的glBindTexture绑定纹理。
    2. 渲染使用纹理的东西。
    3. 我建议的是:

      当您开始活动时(根据Android OpenGL的工作原理,从onCreateonResume间接调用):

      1. textures设为5个元素的数组,并将5传递给glGenTextures
      2. 循环浏览,对于您的五个资源中的每一个,绑定上述四个资源中的一个,并使用texImage2D上传您的图片,就像您一样。
      3. 然后,当你真的需要画一个形状时:

        1. 传入纹理的int,而不是int [];根据你想要的形状选择合适的。
        2. 首先使用该值在绘图功能中调用glBindTexture
        3. 在渲染过程中对texImage2D进行任何调用。
        4. 致电glDrawArrays以使用glBindTexture绘制您选择的形状。
        5. 另请注意,所有形状都可以共享相同的顶点和纹理缓冲区,因为它们的内容相同;这只是一种效率的事情。