본문 바로가기

GRAPHICS/OpenGL ES

[OPENGL ES] OpenGL ES 1.0, Batchinig으로 프레임 속도 압도적으로 개선하기

그동안 안드로이드에서 OpenGL ES 1.0 기반의 그래픽을 최적화하고, 프레임 속도를 개선하기 위해


참 다양한 작업들을 적용해 왔는데, 이번에 가장 월등한 해결책을 찾을 수 있었다.



여기까지 오기 위해 다양한 자료들을 참조하던 중에 통상적으로 쓰이는 그래픽 기술로 크게


Batching과 Culling이 있었다. (참조 : http://egloos.zum.com/littles/v/3440645 )



Batching은 쉽게 말해 픽셀을 모아찍는 것이고


Culling은 필요한 부분만을 드로잉하는 것이다.


Culling의 경우에는 개념으로 따졌을때나 실질적으로 활용할때나 사용하던 기술로


어느정도 한계점에 다다른 상황이었고


Batching의 경우에는 아직 사용하지 못한 영역이었다.




주안점은 이것이다. Draw call을 줄이는 것. 이것 하나만으로도 엄청난 속도 개선이 이루어질 수 있다.



(참조 : https://stackoverflow.com/questions/7537013/opengl-is-it-better-to-batch-draw-or-to-have-static-vbos)



위의 예시는 Batching을 활용하지 않았을때, Batching을 활용했을 때의 경우에 대해 알아보기 쉽게 설명해주고 있는


답변글이다. 


point를 계산하기 위한 작업은 두 경우 RAM에서 상등하게 이루어지지만


Batching의 경우 point 계산작업이 끝나면 Draw를 단 1번만 수행하는 반면에


Batching을 활용하지 않을 때는 10만개의 draw call을 수행해야 하는 점을 말해주고 있다.


이는 OpenGL ES에서 한 프레임을 보여주기 위해 필요한 작업들이다.


한 프레임을 위해 10만 draw를 수행하는 것과 단 한번의 draw를 수행하는 것.. 


지식없이 상식선만으로 따져봐도 너무 극심한 차이가 아닐 수가 없다.



윗부분에서 참조한 공돌이 옵빠님의  이글루 게시물에서는 모바일 디바이스의 경우 1프레임당 100~300 개의 draw call을 추천하고 있다.


기존의 방식에서는 약 8000개의 픽셀을 그리기 위해 각 픽셀마다 1 드로우, 즉 8000 draw를 수행하고 있던 것이었고


오버헤드, 프레임 저하가 당연스럽게 날 수 밖에 없는 것이었다.



서두는 이정도로 마무리하고, Batching을 러프하게 구현하기 위해 노력한 점들을 기록해두고자 한다.



// Before


(Batching 미사용, 1 pixel 1 draw)


1. 1개 픽셀을 그리기 위한 vertices를 설정한다. (4개의 포인트 설정)


2. 설정된 vertices로 FloatBuffer 생성


3. 지정한 순서 (0, 1, 2, 0, 2, 3) 로 Indicies 설정


4. 설정된 Indicies로 ShortBuffer 생성


5. glDrawElements를 활용, 두개의 TRIANGLE로 사각 polygon 구현 및 Draw

gl.glVertexPointer(3, GL10.GL_FLOAT, 0, float_vertexBuffer);
gl.glColorPointer(4, GL10.GL_FLOAT, 0, float_vertexBuffer_for_color);
gl.glDrawElements(GL10.GL_TRIANGLE_FAN, test_indicies.length, GL10.GL_UNSIGNED_SHORT, vertexBuffer);




// After


(Batching 사용, 1 frame 1 draw)


1. 1개 픽셀을 그리기 위한 verticies 좌표를 큰 사이즈의 배열에 순차적으로 저장.

  

  여기서 주안점은 기존 DrawElements에서 쓰던 방식처럼 verticies를 12개의 간격으로 설정(4개의 포인트를 가지기 때문에)


2. verticies 좌표 저장과 함께 드로잉에 필요한 color array 설정
public void batchPolygons(float centerX, float centerY, float[] colors, float Interval) {

saved_vertices[vertices_array_count] = centerX - Interval;
saved_vertices[vertices_array_count + 1] = centerY - Interval;

for (int i = 0; i < 16; i++) {
saved_color_array[color_array_count + i] = colors[i];
}

vertices_array_count += 12;
color_array_count += 16;
indices_array_count += 6;
indices_save_data += 4;
}


2. verticies 좌표 저장과 함께 드로잉에 필요한 color array 설정


3. 좌표 설정이 완료되면 glDrawElements가 아닌 glDrawArrays로 전체 verticiesBuffer Draw


gl.glVertexPointer(3, GL10.GL_FLOAT, 0, float_vertexBuffer);
gl.glColorPointer(4, GL10.GL_FLOAT, 0, float_vertexBuffer_for_color);
gl.glDrawArrays(GL10.GL_POINTS, 0, vertices_array_count / 3);


마지막 점은 전체 verticies 배열 사이즈의 3분의 1로 설정할 것.



OpenGL ES 2.0에서 Batching을 활용하는 방법은 많이 제시되어 있었는데, 1.0버전을 사용하던 터라


개념만을 따와 좀 더 커스텀하게 Batching을 활용해 봤다.


결과는 매우 성공적으로, 기존 방식에 비해서는 설명할 것도 없이 월등한 프레임 개선을 이룰 수 있었다. :)





< 추가 참조 >


http://gogorchg.tistory.com/entry/Android-Opengl-es-20-glDrawArrays-와-glDrawElements-사용법