도형 정의

고급 그래픽 작품을 만드는 첫 단계는 OpenGL ES 보기의 컨텍스트에서 그릴 도형을 정의하는 것입니다. OpenGL ES에서 그래픽 객체를 정의하는 방법에 관한 기본 사항을 모르면 OpenGL ES로 그리기가 약간 까다로울 수 있습니다.

이 학습 과정에서는 Android 기기 화면을 기준으로 하는 OpenGL ES 좌표계 외에도 도형과 도형의 면을 정의하고 삼각형과 사각형을 정의하는 데 관한 기본 사항을 설명합니다.

삼각형 정의

OpenGL ES를 사용하면 3차원 공간에서 좌표를 사용하여 그린 객체를 정의할 수 있습니다. 따라서 삼각형을 그리려면 먼저 좌표를 정의해야 합니다. OpenGL에서는 일반적으로 부동 소수점 숫자로 된 꼭짓점 배열을 좌표로 정의합니다. 효율성을 극대화하려면 이 좌표를 ByteBuffer에 쓴 다음 OpenGL ES 그래픽 파이프라인에 전달하여 처리하게 합니다.

Kotlin

    // number of coordinates per vertex in this array
    const val COORDS_PER_VERTEX = 3
    var triangleCoords = floatArrayOf(     // in counterclockwise order:
            0.0f, 0.622008459f, 0.0f,      // top
            -0.5f, -0.311004243f, 0.0f,    // bottom left
            0.5f, -0.311004243f, 0.0f      // bottom right
    )

    class Triangle {

        // Set color with red, green, blue and alpha (opacity) values
        val color = floatArrayOf(0.63671875f, 0.76953125f, 0.22265625f, 1.0f)

        private var vertexBuffer: FloatBuffer =
                // (number of coordinate values * 4 bytes per float)
                ByteBuffer.allocateDirect(triangleCoords.size * 4).run {
                    // use the device hardware's native byte order
                    order(ByteOrder.nativeOrder())

                    // create a floating point buffer from the ByteBuffer
                    asFloatBuffer().apply {
                        // add the coordinates to the FloatBuffer
                        put(triangleCoords)
                        // set the buffer to read the first coordinate
                        position(0)
                    }
                }
    }
    

자바

    public class Triangle {

        private FloatBuffer vertexBuffer;

        // number of coordinates per vertex in this array
        static final int COORDS_PER_VERTEX = 3;
        static float triangleCoords[] = {   // in counterclockwise order:
                 0.0f,  0.622008459f, 0.0f, // top
                -0.5f, -0.311004243f, 0.0f, // bottom left
                 0.5f, -0.311004243f, 0.0f  // bottom right
        };

        // Set color with red, green, blue and alpha (opacity) values
        float color[] = { 0.63671875f, 0.76953125f, 0.22265625f, 1.0f };

        public Triangle() {
            // initialize vertex byte buffer for shape coordinates
            ByteBuffer bb = ByteBuffer.allocateDirect(
                    // (number of coordinate values * 4 bytes per float)
                    triangleCoords.length * 4);
            // use the device hardware's native byte order
            bb.order(ByteOrder.nativeOrder());

            // create a floating point buffer from the ByteBuffer
            vertexBuffer = bb.asFloatBuffer();
            // add the coordinates to the FloatBuffer
            vertexBuffer.put(triangleCoords);
            // set the buffer to read the first coordinate
            vertexBuffer.position(0);
        }
    }
    

기본적으로 OpenGL ES는 좌표계에서 [0,0,0](X,Y,Z)은 GLSurfaceView 프레임의 중심을 지정하고, [1,1,0]은 프레임의 오른쪽 상단을 지정하며, [-1,-1,0]은 프레임의 왼쪽 하단을 지정한다고 간주합니다. 이 좌표계 그림은 OpenGL ES 개발자 가이드를 참조하세요.

이 도형의 좌표는 시계 반대 방향으로 순서가 정의됩니다. 드로잉 순서는 일반적으로 그릴 모양의 앞면과 OpenGL ES 컬면 기능을 사용하여 그리지 않도록 선택할 수 있는 뒷면을 정의하기 때문에 중요합니다. 면과 컬링에 관한 자세한 내용은 OpenGL ES 개발자 가이드를 참조하세요.

사각형 정의

OpenGL에서 삼각형을 정의하기는 매우 쉽습니다. 하지만 조금 더 복잡한 사항을 정의하게 되면 어떨까요? 예를 들어 사각형이 있습니다. 여러 방법으로 사각형을 정의할 수 있지만, 일반적으로 OpenGL ES에서 이러한 도형을 그리는 방법은 함께 그린 두 개의 삼각형을 사용하는 것입니다.

그림 1. 두 개의 삼각형을 사용하여 사각형 그리기.

다시 이 도형을 나타내는 두 삼각형의 꼭짓점을 각각 시계 반대 방향 순서대로 정의한 다음 값을 ByteBuffer에 두어야 합니다. 각 삼각형에서 두 번 공유하는 두 개의 좌표를 정의하지 않도록 드로잉 목록을 사용하여 OpenGL ES 그래픽 파이프라인에 이 꼭짓점을 그리는 방법을 지시합니다. 이 도형을 그리기 위한 코드는 다음과 같습니다.

Kotlin

    // number of coordinates per vertex in this array
    const val COORDS_PER_VERTEX = 3
    var squareCoords = floatArrayOf(
            -0.5f,  0.5f, 0.0f,      // top left
            -0.5f, -0.5f, 0.0f,      // bottom left
             0.5f, -0.5f, 0.0f,      // bottom right
             0.5f,  0.5f, 0.0f       // top right
    )

    class Square2 {

        private val drawOrder = shortArrayOf(0, 1, 2, 0, 2, 3) // order to draw vertices

        // initialize vertex byte buffer for shape coordinates
        private val vertexBuffer: FloatBuffer =
                // (# of coordinate values * 4 bytes per float)
                ByteBuffer.allocateDirect(squareCoords.size * 4).run {
                    order(ByteOrder.nativeOrder())
                    asFloatBuffer().apply {
                        put(squareCoords)
                        position(0)
                    }
                }

        // initialize byte buffer for the draw list
        private val drawListBuffer: ShortBuffer =
                // (# of coordinate values * 2 bytes per short)
                ByteBuffer.allocateDirect(drawOrder.size * 2).run {
                    order(ByteOrder.nativeOrder())
                    asShortBuffer().apply {
                        put(drawOrder)
                        position(0)
                    }
                }
    }
    

자바

    public class Square {

        private FloatBuffer vertexBuffer;
        private ShortBuffer drawListBuffer;

        // number of coordinates per vertex in this array
        static final int COORDS_PER_VERTEX = 3;
        static float squareCoords[] = {
                -0.5f,  0.5f, 0.0f,   // top left
                -0.5f, -0.5f, 0.0f,   // bottom left
                 0.5f, -0.5f, 0.0f,   // bottom right
                 0.5f,  0.5f, 0.0f }; // top right

        private short drawOrder[] = { 0, 1, 2, 0, 2, 3 }; // order to draw vertices

        public Square() {
            // initialize vertex byte buffer for shape coordinates
            ByteBuffer bb = ByteBuffer.allocateDirect(
            // (# of coordinate values * 4 bytes per float)
                    squareCoords.length * 4);
            bb.order(ByteOrder.nativeOrder());
            vertexBuffer = bb.asFloatBuffer();
            vertexBuffer.put(squareCoords);
            vertexBuffer.position(0);

            // initialize byte buffer for the draw list
            ByteBuffer dlb = ByteBuffer.allocateDirect(
            // (# of coordinate values * 2 bytes per short)
                    drawOrder.length * 2);
            dlb.order(ByteOrder.nativeOrder());
            drawListBuffer = dlb.asShortBuffer();
            drawListBuffer.put(drawOrder);
            drawListBuffer.position(0);
        }
    }
    

이 예에서는 OpenGL을 사용하여 더 복잡한 도형을 만드는 데 필요한 사항을 간단히 살펴보았습니다. 일반적으로 삼각형 모음을 사용하여 객체를 그립니다. 다음 과정에서는 이 도형을 화면에 그리는 방법을 알아봅니다.