이전 강의에서 Open GL window 생성하는 것을 공부했는데, 이번 장에서는 삼각형과 사각형을 그려 보도록 하겠다. 화면 생성과 초기화 모두 해 놨기 때문에 도형을 그리는 것은 onDrawFrame() 에 넣으면 된다. 그런데 이전 강의에서 gl.glTranslatef(0.0f, 0.0f, -6.0f); 은 굳이 필요 없었는데 넣었다. 도형 그리는 것을 미리 생각하다 보니까 들어간 것 같다. 오늘은 onDrawFrame() 에 있는 glLoadIdentity() 부터 시작하겠다. 이 메소드를 실행하면 이전까지 해 놨던 좌표계 변환이 초기화 된다. 그래서 x 는 화면의 가로축, y 는 세로축, z 는 깊이 좌표를 나타내게 된다. 그래서 휴대폰 화면의 중앙점을 기준으로 왼쪽은 x 의 – 값을 갖고, 오른쪽은 +, 위쪽은 y 의 +, 아래쪽은 -, 화면 앞쪽은 z 의 +, 뒤쪽은 – 값을 갖게 되는 것이다.
먼저 gl.glTranslatef(0.0f, 0.0f, -6.0f); 를 추가한다. 어제 얘기한 것처럼 z 좌표를 뒤로 좀 밀어야 화면에 그림이 보이게 된다.
@Override
public void onDrawFrame(GL10 gl) {
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
gl.glLoadIdentity();
gl.glTranslatef(0.0f, 0.0f, -6.0f);
// mTriable.draw(gl);
// mQuad.draw(gl);
}
주석 처리한 부분은 각각 삼각형과 사각형을 그리는 코드이다. 이것을 지금부터 시작해 보려고 하는 것이다. 네헤의 사이트에 있는 설명을 보면 삼각형과 사각형 그리는 방법이 아주 간단하게 나와 있는데 Android 에서는 이 방법이 지원되지 않는 것 같다(glBegin(GL_TRIANGLES) 이라는 메소드가 없다 -,.-;;). 그래서 몇 가지 복잡한 단계가 추가된다.
(첨부 소스 참조할 것)
1) 삼각형 그리기 – 프로젝트에 아래의 클래스를 추가한다. Triangle 클래스 설명은 바로 이어서 나온다.
float[] mVertices = { 0.0f, 2.0f, 0.0f,
-0.5f, 1.0f, 0.0f,
0.5f, 1.0f, 0.0f };
Triangle() {
mVertexBuffer = getFloatBufferFromFloatArray(mVertices);
}
@Override
void draw(GL10 gl) {
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glFrontFace(GL10.GL_CW);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mVertexBuffer);
gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 3);
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
}
삼각형은 꼭지점 3개로 이뤄진 도형이기 때문에 그에 맞춰서 실행하는 메소드들이 있다. 처음에는 눈에 잘 안 들어 올 텐데 몇 번 하다 보면 익숙해 진다. 이해 안 되는 것은 외우다 보면 이해되는 것 같다.
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); 정점(꼭지점)값 배열을 이용한 도형을 그리도록 설정
gl.glFrontFace(GL10.GL_CW); 도형을 그릴 때 시계방향으로 돌면서 그리겠다는 의미. GL_CCW 는 반대 방향. 이 설정의 중요성에 대해서 잠깐 설명하자면.. 아래 그림처럼 그리는 방향이 시계 반대 방향과 시계 방향의 삼각형이 있을 때 CL_CCW 로 하면 왼쪽 삼각형이 앞면 오른쪽 삼각형이 뒷면이 되고 CL_CW 로 했을 때는 왼쪽이 뒷면 오른쪽이 앞면을 그리는 방식이 되는 것이다. 어려운가...그러니까 만약 GL_CCW 로 설정했을 때 시계 반대 방향으로 꼭지점 세개를 지정하고 종이에 그림을 그리고 난 후 종이를 뒤집으면 그려진 방향이 시계 방향이 되는 것이다. 다면체를 그릴 때 뒤쪽에 가려서 보이지 않는 면을 처리하는 방법을 고민할 때 확실하게 알게 될 것이다.
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mVertexBuffer); 꼭지점 값이 들어 있는 버퍼를 주고 버퍼에 들어 있는 값이 실수라는 것을 알려 준다. Open GL 은 다면체를 그리던 도형을 그리던 삼각형만 그릴 수 있기 때문에 3 이라는 size 를 주는 것 같다. (하다 보면 알게 되겄지..)
gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 3); 도형 내부가 채워진 삼각형을 그리겠다는 의미. GL_LINE_LOOP 은 테두리만 있는 삼각형을 그리겠다는 옵션이다. GL_POINTS 는 점만 찍겠다는 의미.
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); 삼각형을 그리고 난 뒤에는 이 기능을 정지 시킨다.
getFloatBufferFromFloatArray() 가 정의돼 있는 SmallGLUT 클래스를 선언한다. 클래스로 따로 빼 놓은 이유는 앞으로 여기에 메소드 몇 가지 추가할 것이고 도형을 그리는 클래스들에서 공통으로 상속 받아서 작업할 것이기 때문이다.
draw 메소드는 삼각형, 사각형 공통으로 쓰기 때문에 상위 class 에 정의한다.
abstract class Shape {
public FloatBuffer mVertexBuffer;
public ByteBuffer mIndexBuffer;
abstract void draw(GL10 gl);
FloatBuffer getFloatBufferFromFloatArray(float array[]) {
ByteBuffer tempBuffer = ByteBuffer.allocateDirect(array.length * 4);
tempBuffer.order(ByteOrder.nativeOrder());
FloatBuffer buffer = tempBuffer.asFloatBuffer();
buffer.put(array);
buffer.position(0);
return buffer;
}
}
책에서 본 기억으로는 float 배열을 Byte 배열로 만드는 이유는 Performance 향상을 위해서라고 했던 것 같은데 확실한 지 모르겠다. 암튼…버퍼를 만들어야 하는데 float 자료형은 4 byte 크기를 갖기 때문에 배열 크기에 4 를 곱해서 버퍼 크기를 잡아야 한다(참고, double 은 8 bytes). 위에 있는 코드의 내용은 그냥 눈으로 이해하면 될 것 같다. 어떤 자료를 봐도 똑 같은 내용이라서 수학 공식 같이 생각되기도 한다.
(float 배열 만큼 ByteBuffer 할당 -> ordering -> FloatBuffer 로 변환 -> float array 값 넣어 줌)
이렇게 코딩하고 ctrl + F11 키 누르면 다음과 같은 화면이 보일 것이다.
아래쪽에 네모를 그려야 하기에 y 좌표를 위로 좀 올렸다.
2) 네모 그리기 : Quad 라는 클래스 하나 만든다.
public class Quad extends Shape {
float[] mVertices = { -0.5f, 0.5f, 0.0f,
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.5f, 0.5f, 0.0f };
byte[] mIndices = { 0, 3, 2,
0, 2, 1 };
Quad () {
mVertexBuffer = getFloatBufferFromFloatArray(mVertices);
mIndexBuffer = getByteBufferFromByteArray(mIndices);
}
void draw(GL10 gl) {
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glFrontFace(GL10.GL_CW);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mVertexBuffer);
gl.glDrawElements(GL10.GL_TRIANGLES, mIndices.length, GL10.GL_UNSIGNED_BYTE, mIndexBuffer);
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
}
}
네모는 좀 더 복잡한 느낌이 드는 데 index buffer 라는 것이 추가되기 때문이다. 이전 페이지에서도 말했지만 Open gl 은 모든 도형을 삼각형을 모아서 그리기 때문에 사각형부터는 하나의 과정이 더 추가 되는 것이다.
사각형이기 때문에 좌표 값 4개가 필요하고 이 4개의 꼭지점을 어떤 순서로 그릴 것인지 정해 줘야 하는데 이때 필요한 것이 index buffer 다. 이제 Shape 클래스에 다음 메소드를 추가해 준다.
ByteBuffer getByteBufferFromByteArray( byte array[]) {
ByteBuffer buffer = ByteBuffer.allocateDirect(array.length);
buffer.put(array);
buffer.position(0);
return buffer;
}
index 값이 256 개 를 넘어간다면 ShortBuffer 라는 것을 리턴해 줘야 할 테지만 아직은 몇 개 없기 때문에 걍 ByteBuffer 를 리턴하면 된다.
gl.glDrawElements(GL10.GL_TRIANGLES, mIndices.length, GL10.GL_UNSIGNED_BYTE, mIndexBuffer); index 의
개수와 할당된 ByteBuffer 를 넣어서 네모를 그려주는 메소드. 삼각형은 gl.glDrawArray 를 써서 그렸지만
사각형은 이것을 써야 그릴 수 있다. (glDrawArray 를 쓰려면 index 개수만큼 vertex 설정해주면 된다)
저 위쪽에 있는
// mTriable.draw(gl);
// mQuad.draw(gl);
이 부분 주석을 풀고 실행하면 아래 화면과 같이 보일 것이다.
![](http://postfiles13.naver.net/20100616_252/gidools_1276638575676DtKFi_png/tri+quad_gidools.png?type=w2)
[출처] Android Open GL #2|작성자 이외수와베르나르