OpenGL ES

Android에는 Open Graphics Library(OpenGL®)를 사용한 고성능 2D 및 3D 그래픽, 특히 OpenGL ES API 지원이 포함되어 있습니다. 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) 이상에서 지원됩니다.

주의: Android 플랫폼 버전과 관계없이 기기 제조업체에서 이 그래픽 파이프라인의 구현을 제공하지 않으면 기기는 OpenGL ES 3.0 API를 지원할 수 없습니다. 매니페스트에서 OpenGL ES 3.0이 필요하다고 지정하면 이 버전이 기기에 있는지 확인할 수 있습니다. 하위 수준 버전이 필요하다고 지정했지만 3.0 기능이 있는 경우 이를 사용하고 싶다면 런타임에 기기에서 지원하는 OpenGL 버전을 확인해야 합니다. 자세한 방법은 OpenGL ES 버전 확인을 참조하세요.

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

참고 항목

기본사항

Android는 프레임워크 API와 네이티브 개발 키트 (NDK)를 통해 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가 필요한 경우 아래와 같이 매니페스트에 다음 설정을 추가하여 요구사항을 선언해야 합니다.

    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을 지원하는 기기 전용인 경우 매니페스트에서 이를 지정할 수도 있습니다.

    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를 매니페스트에서 요구사항으로 선언하면 이 API 버전을 기본으로 사용하고 런타임에 3.x API를 사용할 수 있는지 확인한 다음 기기에서 지원하는 경우 OpenGL ES 3.x 기능을 사용할 수 있습니다. 기기에서 지원하는 OpenGL ES 버전을 확인하는 방법에 관한 자세한 내용은 OpenGL ES 버전 확인을 참고하세요.

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

    매니페스트에서 텍스처 압축 요구사항을 선언하면 선언된 압축 유형을 하나 이상 지원하지 않는 기기를 사용하는 사용자에게 애플리케이션이 표시되지 않습니다. 텍스처 압축에 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
        }
    }
    

    Java

    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)
        ...
    }
    

    Java

    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"
    

    Java

    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")
        ...
    }
    

    Java

    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)
    }
    

    Java

    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
        ...
    }
    

    Java

    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의 기능과 관련이 있습니다. 면 컬링은 렌더링 파이프라인이 도형의 뒷면을 무시 (계산하거나 그리지 않음)할 수 있도록 하여 시간, 메모리, 처리 주기를 절약하는 OpenGL 환경의 한 옵션입니다.

Kotlin

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

Java

// 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은 OpenGL ES 3.0 API 구현을 제공하는 기기에서 Android 4.3(API 수준 18) 이상에서 지원됩니다. OpenGL ES의 특정 버전을 지원하는 Android 지원 기기의 상대적인 숫자에 관한 정보는 OpenGL ES 버전 대시보드를 참고하세요.

OpenGL ES 1.0/1.1 API를 사용한 그래픽 프로그래밍은 2.0 이상 버전을 사용하는 것과 크게 다릅니다. API의 1.x 버전에는 더 편리한 메서드와 고정 그래픽 파이프라인이 있는 반면 OpenGL ES 2.0 및 3.0 API는 OpenGL 셰이더를 사용하여 파이프라인을 더 직접적으로 제어합니다. 그래픽 요구사항을 신중하게 고려하고 애플리케이션에 가장 적합한 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(<sdk>/samples/<version>/ApiDemos/src/com/example/android/apis/graphics/)의 CompressedTextureActivity 코드 샘플을 참고하세요.

주의: 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 텍스처 압축 (3DC)은 알파 채널이 있는 RGB 텍스처를 지원하는 덜 널리 사용되는 형식입니다. 이 형식은 다음 OpenGL 확장 이름으로 표시됩니다.
    • GL_AMD_compressed_3DC_texture

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

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

OpenGL 확장 판별

지원되는 OpenGL ES API의 확장 측면에서 OpenGL 구현은 Android 기기에 따라 다릅니다. 이러한 확장에는 텍스처 압축이 포함되지만 일반적으로 OpenGL 기능 세트의 다른 확장도 포함됩니다.

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

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

    Kotlin

    var extensions = gl.glGetString(GL10.GL_EXTENSIONS)
    

    Java

    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)

Java

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

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

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

OpenGL ES 버전 확인

Android 기기에서 사용 가능한 OpenGL ES 버전은 여러 가지가 있습니다. 매니페스트에서 애플리케이션에 필요한 최소 API 버전을 지정할 수 있지만 동시에 최신 API의 기능도 활용할 수도 있습니다. 예를 들어 OpenGL ES 3.0 API는 API 2.0 버전과 하위 호환되므로 OpenGL ES 3.0 기능을 사용하지만 3.0 API를 사용할 수 없으면 2.0 API로 대체하도록 애플리케이션을 작성하는 것이 좋습니다.

애플리케이션 매니페스트에 필요한 최소 버전보다 높은 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
    }
}

Java

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.

Java

// 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 버전을 선택해야 합니다.