OpenGL ES

Android에서는 Open Graphic Library(OpenGL®), 특히 OpenGL ES API가 포함된 고성능 2D 및 3D 그래픽을 지원합니다. OpenGL은 3D 그래픽 처리 하드웨어의 표준 소프트웨어 인터페이스를 지정하는 크로스 플랫폼 그래픽 API입니다. OpenGL ES는 삽입 기기용 OpenGL 사양의 특성입니다. Android에서는 다음과 같은 여러 버전의 OpenGL ES API를 지원합니다.

  • OpenGL ES 1.0 및 1.1 - 이 API 사양은 Android 1.0 이상에서 지원됩니다.
  • OpenGL ES 2.0 - 이 API 사양은 Android 2.2(API 레벨 8) 이상에서 지원됩니다.
  • OpenGL ES 3.0 - 이 API 사양은 Android 4.3(API 레벨 18) 이상에서 지원됩니다.
  • OpenGL ES 3.1 - 이 API 사양은 Android 5.0(API 레벨 21) 이상에서 지원됩니다.

주의: 기기에서 OpenGL ES 3.0 API를 지원하려면 기기 제조업체에서 제공하는 이 그래픽 파이프라인이 구현되어 있어야 합니다. Android 4.3 이하를 실행 중인 기기에서는 OpenGL ES 3.0 API를 지원하지 않을 수 있습니다. 런타임 시 지원되는 OpenGL ES 버전을 확인하는 데 관한 내용은 OpenGL ES 버전 확인을 참조하세요.

참고: Android 프레임워크에서 제공하는 특정 API는 J2ME JSR239 OpenGL ES API와 비슷하지만 동일하지는 않습니다. J2ME JSR239 사양을 잘 알고 있는 경우 유사 콘텐츠를 주의하세요.

참고 항목

기본 사항

Android에서는 프레임워크 API와 NDK(Native Development Kit)를 통해 OpenGL을 지원합니다. 이 주제에서는 Android 프레임워크 인터페이스를 집중적으로 다룹니다. NDK에 관한 자세한 내용은 Android NDK를 참조하세요.

Android 프레임워크에는 OpenGL ES API로 그래픽을 만들고 조작할 수 있는 두 가지 기본 클래스, GLSurfaceViewGLSurfaceView.Renderer가 있습니다. Android 애플리케이션에서 OpenGL을 사용하는 것이 목표라면 활동에서 이 클래스를 구현하는 방법을 먼저 숙지해야 합니다.

GLSurfaceView
이 클래스는 OpenGL API 호출을 사용하여 객체를 그리고 조작할 수 있는 View이며 SurfaceView와 기능이 비슷합니다. GLSurfaceView의 인스턴스를 만들고 여기에 Renderer를 추가하여 이 클래스를 사용할 수 있습니다. 그러나 터치 스크린 이벤트를 캡처하려면 OpenGL 학습 과정 터치 이벤트에 응답에 표시된 대로 GLSurfaceView 클래스를 확장하여 터치 리스너를 구현해야 합니다.
GLSurfaceView.Renderer
이 인터페이스를 통해서는 GLSurfaceView에 그래픽을 그리는 데 필요한 메서드를 정의합니다. 개별 클래스로 구현된 이 인터페이스를 제공하고 GLSurfaceView.setRenderer()를 사용하여 GLSurfaceView 인스턴스에 연결해야 합니다.

GLSurfaceView.Renderer 인터페이스를 사용하려면 다음 메서드를 구현해야 합니다.

  • onSurfaceCreated(): GLSurfaceView를 만들 때 시스템에서 이 메서드를 한 번 호출합니다. 이 메서드를 사용하여 OpenGL 환경 매개변수 설정 또는 OpenGL 그래픽 객체 초기화와 같이 한 번만 실행해야 하는 작업을 완료합니다.
  • onDrawFrame(): 시스템에서 GLSurfaceView를 다시 그릴 때마다 이 메서드를 호출합니다. 이 메서드를 그래픽 객체 그리기(및 다시 그리기)의 기본 실행 지점으로 사용합니다.
  • onSurfaceChanged(): GLSurfaceView의 크기 변경 또는 기기 화면의 방향 변경을 비롯하여 GLSurfaceView 도형이 변경될 때 시스템에서 이 메서드를 호출합니다. 예를 들어 기기가 세로 모드에서 가로 모드로 방향을 변경하면 시스템에서 이 메서드를 호출합니다. 이 메서드를 사용하여 GLSurfaceView 컨테이너의 변경사항에 맞게 대응합니다.

OpenGL ES 패키지

GLSurfaceViewGLSurfaceView.Renderer를 사용하여 OpenGL ES의 컨테이너 보기를 설정하고 나면 다음 클래스를 사용하여 OpenGL API 호출을 시작할 수 있습니다.

OpenGL ES를 사용하여 바로 앱을 빌드하기 시작하려면 OpenGL ES로 그래픽 표시 클래스를 따르세요.

OpenGL 요구사항 선언

애플리케이션에서 일부 기기에서 사용 가능하지 않은 OpenGL 기능을 사용하는 경우 이 요구사항을 AndroidManifest.xml 파일에 포함해야 합니다. 다음은 가장 일반적인 OpenGL manifest 선언입니다.

  • OpenGL ES 버전 요구사항 - 애플리케이션에 특정 버전의 OpenGL ES가 필요한 경우 아래 표시된 대로 다음 설정을 manifest에 추가하여 요구사항을 선언해야 합니다.

    OpenGL ES 2.0:

        <!-- Tell the system this app requires OpenGL ES 2.0. -->
        <uses-feature android:glEsVersion="0x00020000" android:required="true" />
        

    이 선언을 추가하면 Google Play에서 OpenGL ES 2.0을 지원하지 않는 기기에 애플리케이션이 설치되지 못하게 제한합니다. 애플리케이션이 OpenGL ES 3.0을 지원하는 기기 전용이면 manifest에서 다음도 지정할 수 있습니다.

    OpenGL ES 3.0:

        <!-- Tell the system this app requires OpenGL ES 3.0. -->
        <uses-feature android:glEsVersion="0x00030000" android:required="true" />
        

    OpenGL ES 3.1:

        <!-- Tell the system this app requires OpenGL ES 3.1. -->
        <uses-feature android:glEsVersion="0x00030001" android:required="true" />
        

    참고: OpenGL ES 3.x API는 2.0 API와 역호환되므로 애플리케이션에서 OpenGL ES를 더욱 유연하게 구현할 수 있습니다. OpenGL ES 2.0 API를 manifest에서 요구사항으로 선언하면 이 API 버전을 기본으로 사용하고, 런타임 시 3.x API를 사용할 수 있는지 확인한 다음, 기기에서 지원하는 경우 OpenGL ES 3.x 기능을 사용할 수 있습니다. 기기에서 지원하는 OpenGL ES 버전을 확인하는 데 관한 자세한 내용은 OpenGL ES 버전 확인을 참조하세요.

  • 텍스처 압축 요구사항 - 애플리케이션에서 텍스처 압축 형식을 사용하면 <supports-gl-texture>를 사용하여 manifest 파일에 애플리케이션이 지원하는 형식을 선언해야 합니다. 사용 가능한 텍스처 압축 형식에 관한 자세한 내용은 텍스처 압축 지원을 참조하세요.

    manifest에 텍스처 압축 요구사항을 선언하면 선언된 압축 유형 중 하나 이상을 지원하지 않는 기기의 사용자로부터 애플리케이션을 숨깁니다. 텍스처 압축 시 Google Play 필터링이 작동하는 방식에 관한 자세한 내용은 <supports-gl-texture> 문서의 Google Play 및 텍스처 압축 필터링 섹션을 참조하세요.

그린 객체의 좌표 매핑

Android 기기에서 그래픽을 표시할 때 기본 문제 중 하나는 화면의 크기와 모양이 다양할 수 있다는 점입니다. OpenGL에서는 정사각형의 균일 좌표계를 가정하며, 대체로 정사각형이 아닌 화면에서 완전히 정사각형인 것처럼 좌표를 그립니다.

그림 1. 일반적인 Android 기기 화면(오른쪽)에 매핑된 기본 OpenGL 좌표계(왼쪽)

위의 그림에서는 OpenGL 프레임에 사용하는 것으로 간주된 균일 좌표계를 왼쪽에 표시하고, 이 좌표가 가로 모드 방향으로 일반 기기 화면에 실제로 매핑되는 방식을 오른쪽에 보여줍니다. 이 문제를 해결하려면 OpenGL 투영 모드와 카메라 보기를 적용하여 좌표를 변환함으로써 화면에서 그래픽 객체의 비율을 정확하게 맞출 수 있습니다.

투영 및 카메라 보기를 적용하려면 투영 행렬과 카메라 보기 행렬을 만들어 OpenGL 렌더링 파이프라인에 적용합니다. Android 기기 화면에 올바르게 매핑되도록 투영 행렬을 통해 그래픽 좌표를 다시 계산합니다. 카메라 보기 행렬을 통해서는 특정 눈 위치에서 객체를 렌더링하는 변환을 만듭니다.

OpenGL ES 1.0의 투영 및 카메라 보기

ES 1.0 API에서는 각 행렬을 만든 다음 OpenGL 환경에 추가하여 투영 및 카메라 보기를 적용합니다.

  1. 투영 행렬 - 정확한 비율로 그리도록 객체 좌표를 다시 계산하기 위해 기기 화면의 도형을 사용하여 투영 행렬을 만듭니다. 다음 예제 코드에서는 GLSurfaceView.Renderer 구현의 onSurfaceChanged() 메서드를 수정하여 화면의 가로세로 비율에 따라 투영 행렬을 만들고 OpenGL 렌더링 환경에 적용하는 방법을 보여줍니다.

    Kotlin

        override fun onSurfaceChanged(gl: GL10, width: Int, height: Int) {
            gl.apply {
                glViewport(0, 0, width, height)
    
                // make adjustments for screen ratio
                val ratio: Float = width.toFloat() / height.toFloat()
    
                glMatrixMode(GL10.GL_PROJECTION)            // set matrix to projection mode
                glLoadIdentity()                            // reset the matrix to its default state
                glFrustumf(-ratio, ratio, -1f, 1f, 3f, 7f)  // apply the projection matrix
            }
        }
        

    자바

        public void onSurfaceChanged(GL10 gl, int width, int height) {
            gl.glViewport(0, 0, width, height);
    
            // make adjustments for screen ratio
            float ratio = (float) width / height;
            gl.glMatrixMode(GL10.GL_PROJECTION);        // set matrix to projection mode
            gl.glLoadIdentity();                        // reset the matrix to its default state
            gl.glFrustumf(-ratio, ratio, -1, 1, 3, 7);  // apply the projection matrix
        }
        
  2. 카메라 변환 행렬 - 투영 행렬을 사용하여 좌표계를 조정하고 나면 카메라 보기도 적용해야 합니다. 다음 예제 코드에서는 GLSurfaceView.Renderer 구현의 onDrawFrame() 메서드를 수정하여 모델 보기를 적용하고 GLU.gluLookAt() 유틸리티를 사용하여 카메라 위치를 시뮬레이션하는 보기 변환을 만드는 방법을 보여줍니다.

    Kotlin

        override fun onDrawFrame(gl: GL10) {
            ...
            gl.apply {
                // Set GL_MODELVIEW transformation mode
                glMatrixMode(GL10.GL_MODELVIEW)
                glLoadIdentity()                     // reset the matrix to its default state
            }
    
            // When using GL_MODELVIEW, you must set the camera view
            GLU.gluLookAt(gl, 0f, 0f, -5f, 0f, 0f, 0f, 0f, 1.0f, 0.0f)
            ...
        }
        

    자바

        public void onDrawFrame(GL10 gl) {
            ...
            // Set GL_MODELVIEW transformation mode
            gl.glMatrixMode(GL10.GL_MODELVIEW);
            gl.glLoadIdentity();                      // reset the matrix to its default state
    
            // When using GL_MODELVIEW, you must set the camera view
            GLU.gluLookAt(gl, 0, 0, -5, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
            ...
        }
        

OpenGL ES 2.0 이상의 투영 및 카메라 보기

ES 2.0 및 3.0 API에서 먼저 그래픽 객체의 꼭짓점 셰이더에 행렬 멤버를 추가하여 투영 및 카메라 보기를 적용합니다. 이 행렬 멤버를 추가하면 투영 및 카메라 보기 행렬을 생성하여 객체에 적용할 수 있습니다.

  1. 꼭짓점 셰이더에 행렬 추가 - 보기 투영 행렬의 변수를 생성하고 셰이더 위치의 승수로 포함시킵니다. 다음 예제 꼭짓점 셰이더 코드에서 포함된 uMVPMatrix 멤버를 사용하면 이 셰이더를 사용하는 객체의 좌표에 투영 및 카메라 보기 행렬을 적용할 수 있습니다.

    Kotlin

        private val vertexShaderCode =
    
            // This matrix member variable provides a hook to manipulate
            // the coordinates of objects that use this vertex shader.
            "uniform mat4 uMVPMatrix;   \n" +
    
            "attribute vec4 vPosition;  \n" +
            "void main(){               \n" +
            // The matrix must be included as part of gl_Position
            // Note that the uMVPMatrix factor *must be first* in order
            // for the matrix multiplication product to be correct.
            " gl_Position = uMVPMatrix * vPosition; \n" +
    
            "}  \n"
        

    자바

        private final String vertexShaderCode =
    
            // This matrix member variable provides a hook to manipulate
            // the coordinates of objects that use this vertex shader.
            "uniform mat4 uMVPMatrix;   \n" +
    
            "attribute vec4 vPosition;  \n" +
            "void main(){               \n" +
            // The matrix must be included as part of gl_Position
            // Note that the uMVPMatrix factor *must be first* in order
            // for the matrix multiplication product to be correct.
            " gl_Position = uMVPMatrix * vPosition; \n" +
    
            "}  \n";
        

    참고: 위의 예에서는 결합된 투영 행렬과 카메라 보기 행렬을 적용하는 꼭짓점 셰이더에 단일 변환 행렬 멤버를 정의합니다. 애플리케이션 요구사항에 따라 독립적으로 변경할 수 있도록 꼭짓점 셰이더에 개별 투영 행렬과 카메라 보기 행렬 멤버를 정의할 수 있습니다.

  2. 셰이더 행렬에 액세스 - 꼭짓점 셰이더에 후크를 만들어 투영 및 카메라 보기를 적용한 후 해당 변수에 액세스하여 투영 및 카메라 보기 행렬을 적용할 수 있습니다. 다음 코드에서는 위의 꼭짓점 셰이더에 정의된 행렬 변수에 액세스하기 위해 GLSurfaceView.Renderer 구현의 onSurfaceCreated() 메서드를 수정하는 방법을 보여줍니다.

    Kotlin

        override fun onSurfaceCreated(gl: GL10, config: EGLConfig) {
            ...
            muMVPMatrixHandle = GLES20.glGetUniformLocation(program, "uMVPMatrix")
            ...
        }
        

    자바

        public void onSurfaceCreated(GL10 unused, EGLConfig config) {
            ...
            muMVPMatrixHandle = GLES20.glGetUniformLocation(program, "uMVPMatrix");
            ...
        }
        
  3. 투영 및 카메라 보기 행렬 만들기 - 그래픽 객체에 적용할 투영 및 보기 행렬을 생성합니다. 다음 예제 코드에서는 GLSurfaceView.Renderer 구현의 onSurfaceCreated()onSurfaceChanged() 메서드를 수정하여 기기의 화면 가로세로 비율에 따라 카메라 보기 행렬과 투영 행렬을 만드는 방법을 보여줍니다.

    Kotlin

        override fun onSurfaceCreated(gl: GL10, config: EGLConfig) {
            ...
            // Create a camera view matrix
            Matrix.setLookAtM(vMatrix, 0, 0f, 0f, -3f, 0f, 0f, 0f, 0f, 1.0f, 0.0f)
        }
    
        override fun onSurfaceChanged(gl: GL10, width: Int, height: Int) {
            GLES20.glViewport(0, 0, width, height)
    
            val ratio: Float = width.toFloat() / height.toFloat()
    
            // create a projection matrix from device screen geometry
            Matrix.frustumM(projMatrix, 0, -ratio, ratio, -1f, 1f, 3f, 7f)
        }
        

    자바

        public void onSurfaceCreated(GL10 unused, EGLConfig config) {
            ...
            // Create a camera view matrix
            Matrix.setLookAtM(vMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
        }
    
        public void onSurfaceChanged(GL10 unused, int width, int height) {
            GLES20.glViewport(0, 0, width, height);
    
            float ratio = (float) width / height;
    
            // create a projection matrix from device screen geometry
            Matrix.frustumM(projMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
        }
        
  4. 투영 및 카메라 보기 행렬 적용 - 투영 및 카메라 보기 변환을 적용하려면 두 행렬을 곱한 다음 꼭짓점 셰이더에 설정합니다. 다음 예제 코드에서는 GLSurfaceView.Renderer 구현의 onDrawFrame() 메서드를 수정하여 위의 코드에서 만든 투영 행렬과 카메라 보기를 결합한 다음 OpenGL에서 렌더링할 그래픽 객체에 적용하는 방법을 보여줍니다.

    Kotlin

        override fun onDrawFrame(gl: GL10) {
            ...
            // Combine the projection and camera view matrices
            Matrix.multiplyMM(vPMatrix, 0, projMatrix, 0, vMatrix, 0)
    
            // Apply the combined projection and camera view transformations
            GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, vPMatrix, 0)
    
            // Draw objects
            ...
        }
        

    자바

        public void onDrawFrame(GL10 unused) {
            ...
            // Combine the projection and camera view matrices
            Matrix.multiplyMM(vPMatrix, 0, projMatrix, 0, vMatrix, 0);
    
            // Apply the combined projection and camera view transformations
            GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, vPMatrix, 0);
    
            // Draw objects
            ...
        }
        

OpenGL ES 2.0에서 투영 및 카메라 보기를 적용하는 방법에 관한 전체 예는 OpenGL ES로 그래픽 표시 클래스를 참조하세요.

도형 면 및 권선

OpenGL에서 도형의 면은 3차원 공간에서 3개 이상의 점으로 정의되는 표면입니다. 3개 이상의 3차원 점 조합(OpenGL의 꼭짓점이라고 함)에는 앞면과 뒷면이 있습니다. 앞면과 뒷면은 어떻게 구분하나요? 좋은 질문입니다. 답은 권선, 즉 도형의 점을 정의하는 방향과 관련이 있습니다.

삼각형의 꼭짓점 좌표

그림 1. 시계 반대 방향 그리기 순서로 변환되는 좌표 목록

이 예에서 삼각형의 점은 시계 반대 방향으로 그리는 순서로 정의됩니다. 이 좌표를 그리는 순서에 따라 도형의 권선 방향이 정의됩니다. 기본적으로 OpenGL에서는 시계 반대 방향으로 그린 면이 앞면입니다. 그림 1에 표시된 삼각형은 사용자에게 도형의 앞면이 표시되도록(OpenGL로 해석함) 정의되며 다른 면은 뒷면입니다.

도형의 앞면이 어떤 면인지를 아는 것이 왜 중요한가요? 그 이유는 일반적으로 사용되는 면 선별이라고 하는 OpenGL의 기능과 관련됩니다. 면 선별은 렌더링 파이프라인에서 도형의 뒷면을 무시(계산하거나 그리지 않음)하도록 하여 시간과 메모리를 절약하고 처리 주기를 단축하는 Open GL 환경의 한 옵션입니다.

Kotlin

    gl.apply {
        // enable face culling feature
        glEnable(GL10.GL_CULL_FACE)
        // specify which faces to not draw
        glCullFace(GL10.GL_BACK)
    }
    

자바

    // enable face culling feature
    gl.glEnable(GL10.GL_CULL_FACE);
    // specify which faces to not draw
    gl.glCullFace(GL10.GL_BACK);
    

도형의 앞면과 뒷면을 모르는 상태에서 면 선별 기능을 사용하면 OpenGL 그래픽이 약간 얇게 보이거나 전혀 표시되지 않을 수 있습니다. 따라서 항상 시계 반대 방향 그리기 순서로 OpenGL 도형의 좌표를 정의합니다.

참고: 시계 방향 면을 앞면으로 삼도록 OpenGL 환경을 설정할 수 있지만, 그러면 코드가 더 많이 필요하며 노련한 OpenGL 개발자에게 도움을 요청할 때 혼란을 줄 가능성이 큽니다. 따라서 위와 같이 설정하지 마세요.

OpenGL 버전 및 기기 호환성

OpenGL ES 1.0 및 1.1 API 사양은 Android 1.0부터 지원됩니다. Android 2.2(API 레벨 8)부터 프레임워크에서 OpenGL ES 2.0 API 사양을 지원합니다. OpenGL ES 2.0은 대부분의 Android 기기에서 지원되며 OpenGL로 개발 중인 새로운 애플리케이션에 사용하는 것이 좋습니다. OpenGL ES 3.0은 Android 4.3(API 레벨 18) 이상을 통해 OpenGL ES 3.0 API 구현을 제공하는 기기에서 지원됩니다. OpenGL ES의 특정 버전을 지원하는 Android 구동 기기의 상대적인 수에 관한 자세한 내용은 OpenGL ES 버전 대시보드를 참조하세요.

OpenGL ES 1.0/1.1 API를 사용한 그래픽 프로그래밍은 2.0 이상 버전을 사용할 때와 크게 다릅니다. OpenGL ES 2.0 및 3.0 API에서는 OpenGL 셰이더를 사용하여 더 직접적인 파이프라인 제어를 제공하지만 API의 1.x 버전에는 더 편리한 메서드와 고정 그래픽 파이프라인이 포함되어 있습니다. 그래픽 요구사항을 신중히 고려하고 애플리케이션에 가장 적합한 API 버전을 선택해야 합니다. 자세한 내용은 OpenGL API 버전 선택을 참조하세요.

OpenGL ES 3.0 API에서는 추가 기능을 제공하고 2.0 API보다 성능이 뛰어나며 이전 버전과의 호환성도 제공합니다. 즉, OpenGL ES 2.0을 대상으로 애플리케이션을 작성하고 OpenGL ES 3.0 그래픽 기능이 있으면 조건부로 포함시킬 수 있습니다. 3.0 API의 가용성을 확인하는 데 관한 자세한 내용은 OpenGL ES 버전 확인을 참조하세요.

텍스처 압축 지원

텍스처 압축은 메모리 요구사항을 줄이고 메모리 대역폭을 더 효율적으로 사용하여 OpenGL 애플리케이션의 성능을 크게 향상시킬 수 있습니다. Android 프레임워크에서는 ETC1Util 유틸리티 클래스와 etc1tool 압축 도구(<sdk>/tools/의 Android SDK에 있음) 등의 표준 기능으로 ETC1 압축 형식을 지원합니다. 텍스처 압축을 사용하는 Android 애플리케이션의 예는 Android SDK의 CompressedTextureActivity 코드 샘플(<sdk>/samples/<version>/ApiDemos/src/com/example/android/apis/graphics/)을 참조하세요.

주의: ETC1 형식은 대부분의 Android 기기에서 지원되지만 확실히 사용할 수 있는 것은 아닙니다. 기기에서 ETC1 형식이 지원되는지 확인하려면 ETC1Util.isETC1Supported() 메서드를 호출합니다.

참고: ETC1 텍스처 압축 형식에서는 투명한(알파 채널) 텍스처를 지원하지 않습니다. 애플리케이션에 투명한 텍스처가 필요하면 대상 기기에서 사용할 수 있는 기타 텍스처 압축 형식을 조사해야 합니다.

ETC2/EAC 텍스처 압축 형식은 OpenGL ES 3.0 API를 사용하면 확실히 사용할 수 있습니다. 이 텍스처 형식에서는 높은 압축률과 높은 화질을 제공하며 투명도(알파 채널)도 지원합니다.

ETC 형식 외에도 Android 기기에서는 GPU 칩셋 및 OpenGL 구현을 기반으로 텍스처 압축을 다양하게 지원합니다. 애플리케이션에서 지원해야 하는 압축 유형을 결정하기 위해 타겟팅하는 기기에서 텍스처 압축 지원을 조사해야합니다. 지정된 기기에서 지원되는 텍스처 형식을 판별하려면 기기를 쿼리하고 OpenGL 확장 이름을 검토해야 합니다. 이 이름은 기기에서 지원되는 텍스처 압축 형식(및 기타 OpenGL 기능)을 식별하는 데 사용합니다. 일반적으로 지원되는 텍스처 압축 형식은 다음과 같습니다.

  • ATITC(ATC) - ATI 텍스처 압축(ATITC 또는 ATC)은 다양한 기기에서 사용할 수 있고, 알파 채널이 있거나 없는 RGB 텍스처의 고정 비율 압축을 지원합니다. 이 형식은 여러 OpenGL 확장 이름으로 표시될 수 있습니다. 예를 들면 다음과 같습니다.
    • GL_AMD_compressed_ATC_texture
    • GL_ATI_texture_compression_atitc
  • PVRTC - PowerVR 텍스처 압축(PVRTC)은 다양한 기기에서 사용할 수 있고 알파 채널이 있거나 없는 픽셀당 2비트 및 4비트 텍스처를 지원합니다. 이 형식은 다음 OpenGL 확장 이름으로 표시됩니다.
    • GL_IMG_texture_compression_pvrtc
  • S3TC(DXTn/DXTC) - S3 텍스처 압축(S3TC)에는 다양한 형식 변형(DXT1 ~ DXT5)이 있으며 덜 광범위하게 사용 가능합니다. 이 형식에서는 4비트 알파 또는 8비트 알파 채널이 있는 RGB 텍스처를 지원합니다. 이 형식은 다음과 같은 OpenGL 확장 이름으로 표시됩니다.
    • GL_EXT_texture_compression_s3tc
    일부 기기에서는 DXT1 형식 버전만 지원합니다. 이 제한된 지원은 다음 OpenGL 확장 이름으로 표시됩니다.
    • GL_EXT_texture_compression_dxt1
  • 3DC - 3DC 텍스처 압축은 알파 채널이 있는 RGB 텍스처를 지원하는 덜 널리 사용되는 형식입니다. 이 형식은 다음 OpenGL 확장 이름으로 표시됩니다.
    • GL_AMD_compressed_3DC_texture

경고: 이 텍스처 압축 형식은 일부 기기에서는 지원되지 않습니다. 이러한 형식에 관한 지원은 제조업체 및 기기에 따라 다를 수 있습니다. 특정 기기의 텍스처 압축 형식을 확인하는 방법은 다음 섹션을 참조하세요.

참고: 애플리케이션에서 지원할 텍스처 압축 형식을 결정한 다음 <supports-gl-texture>를 사용하여 manifest에 선언해야 합니다. 이 선언을 사용하면 Google Play와 같은 외부 서비스에서 필터링할 수 있으므로, 앱에 필요한 형식을 지원하는 기기에만 앱이 설치됩니다. 자세한 내용은 OpenGL manifest 선언을 참조하세요.

OpenGL 확장 판별

지원되는 OpenGL ES API 확장에 있어, OpenGL 구현은 Android 기기에 따라 달라집니다. 이러한 확장에는 텍스처 압축이 포함되지만 일반적으로 OpenGL 기능 조합의 다른 확장도 포함됩니다.

특정 기기에서 지원되는 텍스처 압축 형식 및 기타 OpenGL 확장을 확인하려면 다음 단계를 따르세요.

  1. 대상 기기에서 다음 코드를 실행하여 지원되는 텍스처 압축 형식을 확인합니다.

    Kotlin

        var extensions = gl.glGetString(GL10.GL_EXTENSIONS)
        

    자바

        String extensions = gl.glGetString(GL10.GL_EXTENSIONS);
        

    경고: 이 호출 결과는 기기 모델별로 다양합니다! 일반적으로 지원되는 압축 유형을 확인하려면 여러 대상 기기에서 이 호출을 실행해야 합니다.

  2. 이 메서드의 출력을 검토하여 기기에서 지원되는 OpenGL 확장을 확인합니다.

AEP(Android Extension Pack)

AEP를 사용하면 애플리케이션에서 OpenGL 3.1 사양에 설명된 핵심 조합 이상의 표준 OpenGL 확장 조합을 지원합니다. 이러한 확장을 함께 패키징하면 여러 기기에서 일관된 기능 조합을 사용할 수 있으며 최신 모바일 GPU 기기를 최대한 활용할 수 있습니다.

AEP를 사용하면 조각 셰이더에서 이미지, 셰이더 저장소 버퍼 및 원자 계수기의 지원도 개선됩니다.

앱에서 AEP를 사용할 수 있으려면 앱 manifest에서 AEP가 필수임을 선언해야 합니다. 플랫폼 버전에서도 지원해야 합니다.

manifest에서 다음과 같이 AEP 요구사항을 선언합니다.

    <uses feature android:name="android.hardware.opengles.aep"
                  android:required="true" />
    

플랫폼 버전에서 AEP를 지원하는지 확인하려면 hasSystemFeature(String) 메서드를 사용하여 FEATURE_OPENGLES_EXTENSION_PACK을 인수로 전달합니다. 다음 코드 스니펫에서는 이 방법의 예를 보여줍니다.

Kotlin

    var deviceSupportsAEP: Boolean =
            packageManager.hasSystemFeature(PackageManager.FEATURE_OPENGLES_EXTENSION_PACK)
    

자바

    boolean deviceSupportsAEP = getPackageManager().hasSystemFeature
         (PackageManager.FEATURE_OPENGLES_EXTENSION_PACK);
    

메서드에서 true를 반환하면 AEP가 지원되는 것입니다.

AEP에 관한 자세한 내용은 Khronos OpenGL ES 레지스트리를 참조하세요.

OpenGL ES 버전 확인

Android 기기에서 사용 가능한 OpenGL ES 버전은 여러 가지가 있습니다. 애플리케이션에 필요한 최소 API 버전을 manifest에 지정할 수 있지만, 동시에 새로운 API의 기능도 활용할 수 있습니다. 예를 들어 OpenGL ES 3.0 API는 API 2.0 버전과 역호환되므로, OpenGL ES 3.0 기능을 사용하되 3.0 API를 사용할 수 없으면 2.0 API로 돌아가도록 애플리케이션을 작성할 수 있습니다.

애플리케이션 manifest에 필요한 최소 버전보다 높은 OpenGL ES 기능을 사용하려면 애플리케이션이 기기에서 사용할 수 있는 API 버전을 확인해야 합니다. 다음 두 가지 방법 중 하나로 이 작업을 실행할 수 있습니다.

  1. 상위 레벨의 OpenGL ES 컨텍스트(EGLContext)를 만들고 결과를 확인합니다.
  2. 최소 지원 OpenGL ES 컨텍스트를 만들고 버전 값을 확인합니다.

다음 예제 코드에서는 EGLContext를 만들고 결과를 확인하여 사용 가능한 OpenGL ES 버전을 확인하는 방법을 보여줍니다. 이 예에서는 OpenGL ES 3.0 버전을 확인하는 방법을 보여줍니다.

Kotlin

    private const val EGL_CONTEXT_CLIENT_VERSION = 0x3098
    private const val glVersion = 3.0
    private class ContextFactory : GLSurfaceView.EGLContextFactory {

        override fun createContext(egl: EGL10, display: EGLDisplay, eglConfig: EGLConfig): EGLContext {

            Log.w(TAG, "creating OpenGL ES $glVersion context")
            return egl.eglCreateContext(
                    display,
                    eglConfig,
                    EGL10.EGL_NO_CONTEXT,
                    intArrayOf(EGL_CONTEXT_CLIENT_VERSION, glVersion.toInt(), EGL10.EGL_NONE)
            ) // returns null if 3.0 is not supported
        }
    }
    

자바

    private static double glVersion = 3.0;

    private static class ContextFactory implements GLSurfaceView.EGLContextFactory {

      private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098;

      public EGLContext createContext(
              EGL10 egl, EGLDisplay display, EGLConfig eglConfig) {

          Log.w(TAG, "creating OpenGL ES " + glVersion + " context");
          int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, (int) glVersion,
                  EGL10.EGL_NONE };
          // attempt to create a OpenGL ES 3.0 context
          EGLContext context = egl.eglCreateContext(
                  display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list);
          return context; // returns null if 3.0 is not supported;
      }
    }
    

위의 createContext() 메서드에서 null을 반환하면 코드에서 대신 OpenGL ES 2.0 컨텍스트를 만들고 API만 사용하도록 대체합니다.

다음 코드 예제에서는 지원되는 최소 컨텍스트를 먼저 만들고 버전 문자열을 확인하여 OpenGL ES 버전을 확인하는 방법을 보여줍니다.

Kotlin

    // Create a minimum supported OpenGL ES context, then check:
    gl.glGetString(GL10.GL_VERSION).also {
        Log.w(TAG, "Version: $it")
    }
     // The version format is displayed as: "OpenGL ES <major>.<minor>"
     // followed by optional content provided by the implementation.
    

자바

    // Create a minimum supported OpenGL ES context, then check:
    String version = gl.glGetString(GL10.GL_VERSION);
    Log.w(TAG, "Version: " + version );
    // The version format is displayed as: "OpenGL ES <major>.<minor>"
    // followed by optional content provided by the implementation.
    

이 방법을 사용하면 기기에서 상위 레벨 API 버전을 지원하는 경우 최소 OpenGL ES 컨텍스트를 삭제하고 사용 가능한 상위 API 버전으로 새 컨텍스트를 만들어야 합니다.

OpenGL API 버전 선택

OpenGL ES 1.0 API 버전(및 1.1 확장), 2.0 버전 및 3.0 버전에서는 모두 3D 게임, 시각화 및 사용자 인터페이스를 만드는 데 사용할 고성능 그래픽 인터페이스를 제공합니다. OpenGL ES 2.0 및 3.0용 그래픽 프로그래밍은 대부분 비슷하며, 버전 3.0은 2.0 API의 상위 집합으로 추가 기능이 포함되어 있습니다. OpenGL ES 1.0/1.1 API와 OpenGL ES 2.0 및 3.0의 프로그래밍 방식은 상당히 다르므로 개발자는 이 API를 사용하여 개발을 시작하기 전에 다음 요소를 신중하게 고려해야 합니다.

  • 성능 - 일반적으로 OpenGL ES 2.0 및 3.0은 ES 1.0/1.1 API보다 빠른 그래픽 성능을 제공합니다. 하지만 하드웨어 제조업체마다 OpenGL ES 그래픽 파이프라인을 서로 다르게 구현하므로, 성능 차이는 OpenGL 애플리케이션이 실행되는 Android 기기에 따라 달라질 수 있습니다.
  • 기기 호환성 - 개발자는 기기 유형, Android 버전, 고객이 사용할 수 있는 OpenGL ES 버전을 고려해야 합니다. 기기 간 OpenGL 호환성에 관한 자세한 내용은 OpenGL 버전 및 기기 호환성 섹션을 참조하세요.
  • 코딩 편의성 - OpenGL ES 1.0/1.1 API에서는 OpenGL ES 2.0 또는 3.0 API에서 사용할 수 없는 고정 함수 파이프라인 및 편의 함수를 제공합니다. OpenGL ES를 처음 사용하는 개발자는 버전 1.0/1.1 코딩이 더 빠르고 편리하다고 생각할 수 있습니다.
  • 그래픽 제어 - OpenGL ES 2.0 및 3.0 API에서는 셰이더를 사용하여 프로그래밍이 가능한 파이프라인을 제공함으로써 향상된 수준의 제어를 제공합니다. 그래픽 처리 파이프라인을 보다 직접적으로 제어함으로써 개발자는 1.0/1.1 API를 사용해서는 생성하기 매우 어려운 효과를 만들 수 있습니다.
  • 텍스처 지원 - OpenGL ES 3.0 API에서는 투명도를 지원하는 ETC2 압축 형식의 가용성을 보장하기 때문에 최고의 텍스처 압축을 지원합니다. 1.x 및 2.0 API 구현에서는 일반적으로 ETC1의 지원을 포함하지만 이 텍스처 형식에서는 투명도를 지원하지 않으므로, 일반적으로 타겟팅하는 기기에서 지원하는 다른 압축 형식으로 리소스를 제공해야 합니다. 자세한 내용은 텍스처 압축 지원을 참조하세요.

성능, 호환성, 편의성, 제어 및 기타 요인이 결정에 영향을 미칠 수 있지만 사용자에게 가장 좋은 환경을 제공하는 OpenGL API 버전을 선택해야 합니다.