Как я могу визуализировать 2D-график / рисунок, используя OpenGL на Android? - PullRequest
0 голосов
/ 18 ноября 2011

Я делаю простое приложение для просмотра фракталов для Android, просто для удовольствия. Я также использую его как возможность изучать OpenGL, так как никогда раньше не работал с ним. Используя порт Android из учебников NeHe в качестве отправной точки, мой подход состоит в том, чтобы иметь один класс (FractalModel), который выполняет всю математику для создания фрактала, и FractalView, который выполняет весь рендеринг.

Сложность в том, чтобы заставить работать рендеринг. Поскольку я по сути строю график точек разных цветов, где каждая точка должна соответствовать 1 пикселю, я подумал, что справлюсь с этим, отрисовав прямоугольники 1x1 по всему экрану, используя размеры для вычисления смещений, чтобы было 1 : 1 соответствие между прямоугольниками и физическими пикселями. Поскольку цвет каждого пикселя будет рассчитываться независимо, я могу повторно использовать один и тот же код рендеринга для рендеринга различных частей фрактала (позже я хочу добавить панорамирование и масштабирование).

Вот класс представления, который я написал:

public class FractalView extends GLSurfaceView implements Renderer {

private float[] mVertices;
private FloatBuffer[][] mVBuffer;
private ByteBuffer[][] mBuffer;
private int mScreenWidth;
private int mScreenHeight;
private float mXOffset;
private float mYOffset;
private int mNumPixels;

//references to current vertex coordinates
private float xTL;
private float yTL;
private float xBL;
private float yBL;
private float xBR;
private float yBR;
private float xTR;
private float yTR;


public FractalView(Context context, int w, int h){
    super(context);
    setEGLContextClientVersion(1);
    mScreenWidth = w;
    mScreenHeight = h;
    mNumPixels = mScreenWidth * mScreenHeight;
    mXOffset = (float)1.0/mScreenWidth;
    mYOffset = (float)1.0/mScreenHeight;
    mVertices = new float[12];
    mVBuffer = new FloatBuffer[mScreenHeight][mScreenWidth];
    mBuffer = new ByteBuffer[mScreenHeight][mScreenWidth];
}


public void onDrawFrame(GL10 gl){
    int i,j;    
    gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);    
    gl.glLoadIdentity();
    mapVertices();  
    gl.glColor4f(0.0f,1.0f, 0.0f,.5f);
    for(i = 0; i < mScreenHeight; i++){
        for(j = 0; j < mScreenWidth; j++){
            gl.glFrontFace(GL10.GL_CW);
            gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mVBuffer[i][j]);
            gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
            gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, mVertices.length / 3);
            gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
        }
    }




}

public void onSurfaceChanged(GL10 gl, int w, int h){
    if(h == 0) {                        //Prevent A Divide By Zero By
        h = 1;                      //Making Height Equal One
    }

    gl.glViewport(0, 0, w, h);  //Reset The Current Viewport
    gl.glMatrixMode(GL10.GL_PROJECTION);    //Select The Projection Matrix
    gl.glLoadIdentity();                    //Reset The Projection Matrix

    //Calculate The Aspect Ratio Of The Window
    GLU.gluPerspective(gl, 45.0f, (float)w / (float)h, 0.1f, 100.0f);

    gl.glMatrixMode(GL10.GL_MODELVIEW);     //Select The Modelview Matrix
    gl.glLoadIdentity();

}

public void onSurfaceCreated(GL10 gl, EGLConfig config){
    gl.glShadeModel(GL10.GL_SMOOTH);            //Enable Smooth Shading
    gl.glClearColor(0.0f, 0.0f, 0.0f, 0.5f);    //Black Background
    gl.glClearDepthf(1.0f);                     //Depth Buffer Setup
    gl.glEnable(GL10.GL_DEPTH_TEST);            //Enables Depth Testing
    gl.glDepthFunc(GL10.GL_LEQUAL);             //The Type Of Depth Testing To Do

    //Really Nice Perspective Calculations
    gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST); 
}

private void mapVertices(){
    int i,j;
    xTL = -1;
    yTL = 1;
    xTR = -1 + mXOffset;
    yTR = 1;
    xBL = -1;
    yBL = 1 - mYOffset;
    xBR = -1 + mXOffset;
    yBR = 1 - mYOffset;
    for(i = 0; i < mScreenHeight; i++){
        for (j = 0; j < mScreenWidth; j++){
            //assign coords to vertex array         
            mVertices[0] = xBL;
            mVertices[1] = yBL;
            mVertices[2] = 0f;
            mVertices[3] = xBR;
            mVertices[4] = xBR;
            mVertices[5] = 0f;
            mVertices[6] = xTL;
            mVertices[7] = yTL;
            mVertices[8] = 0f;
            mVertices[9] = xTR;
            mVertices[10] = yTR;
            mVertices[11] = 0f;
            //add doubleBuffer
            mBuffer[i][j] = ByteBuffer.allocateDirect(mVertices.length * 4);
            mBuffer[i][j].order(ByteOrder.nativeOrder());
            mVBuffer[i][j] = mBuffer[i][j].asFloatBuffer();
            mVBuffer[i][j].put(mVertices);
            mVBuffer[i][j].position(0);
            //transform right
            transformRight();
        }
        //transform down
        transformDown();
        //reset x
        xTL = -1;
        xTR = -1 + mXOffset;
        xBL = -1;
        xBR = -1 + mXOffset;
    }



}

//transform all the coordinates 1 "pixel" to the right
private void transformRight(){
    xTL = xTL + mXOffset; //TL            
    xBL = xBL + mXOffset; //BL
    xBR = xBR + mXOffset; //BR
    xTR = xTR + mXOffset; //TR;
}

//transform all of the coordinates 1 pixel down;
private void transformDown(){
    yTL = yTL - mYOffset;                        
    yBL = yBL - mYOffset;            
    yBR = yBR - mYOffset;           
    yTR = yTR - mYOffset;
}
}

В основном я пытаюсь сделать это так же, как это (квадрат в уроке 2), но с гораздо большим количеством объектов. Я предполагаю, что 1 и -1 примерно соответствуют краям экрана (я знаю, что это не совсем так, но я не совсем понимаю, как использовать проекционные матрицы, и хочу сделать это как можно более простым, если нет хорошего ресурса). там я могу учиться) но я понимаю, что координаты OpenGL отделены от реальных координат экрана. Когда я запускаю свой код, я просто получаю черный экран (он должен быть зеленым), но LogCat показывает, что сборщик мусора работает, поэтому я знаю, что что-то происходит. Я не уверен, является ли это просто ошибкой, вызванной тем, что я просто что-то не сделал правильно, или это действительно ДЕЙСТВИТЕЛЬНО медленно. В любом случае, что я должен делать по-другому? Я чувствую, что, может быть, я поступаю неправильно Я посмотрел вокруг, и большинство уроков и примеров основаны на ссылке выше.

Редактировать: я знаю, что я мог бы пойти на это, сгенерировав текстуру, которая заполняет весь экран, и просто нарисовав ее, хотя ссылка, которую я читал, в которой упоминалось, говорит, что это будет медленнее, так как вы не должны перерисовывать текстуру каждый кадр. Тем не менее, мне действительно нужно перерисовывать текстуру только тогда, когда меняется перспектива, поэтому я мог написать свой код, чтобы принять это во внимание. Основная сложность, которую я испытываю в настоящее время, заключается в рисовании растрового изображения и его правильном отображении.

1 Ответ

1 голос
/ 18 ноября 2011

Я бы предположил, что пустой экран связан с тем, что вы меняете буферы так много раз, а также с тем, что вы генерируете все свои буферы вершин в каждом кадре. Тысячи замен буферов И тысячи созданий буферов в одном кадре были бы невероятно медленными.

Стоит упомянуть, что устройства Android имеют ограниченную память, поэтому работа сборщика мусора, вероятно, свидетельствует о том, что ваш код создания буфера поглощает много доступной памяти, и устройство пытается освободить часть для создание новых буферов.

Я бы предложил создать текстуру, которую вы заполняете данными о пикселях в каждом кадре, а затем визуализируете в один квадрат, который заполняет экран. Это значительно увеличит вашу скорость, а также сделает вашу программу более гибкой.

Edit: Посмотрите учебник здесь: http://www.nullterminator.net/gltexture.html, чтобы получить представление о том, как создавать текстуры и загружать их. В основном вам нужно будет заполнить данные BYTE * вашими собственными данными.

Если вы изменяете данные динамически, вам необходимо обновить данные текстуры. Используйте информацию здесь: http://www.opengl.org/wiki/Texture: в разделе о модификации изображения текстуры.

...