OpenGL ES

Android รองรับกราฟิก 2 และ 3 มิติประสิทธิภาพสูงด้วย Open Graphics Library (OpenGL®) โดยเฉพาะ OpenGL ES API OpenGL คือ API กราฟิกข้ามแพลตฟอร์ม ระบุ ของซอฟต์แวร์มาตรฐานสำหรับฮาร์ดแวร์ประมวลผลกราฟิก 3 มิติ OpenGL ES คือรสชาติของ OpenGL ที่มีไว้สำหรับอุปกรณ์แบบฝัง Android รองรับ OpenGL ES หลายเวอร์ชัน API:

  • OpenGL ES 2.0 - ข้อมูลจำเพาะของ API นี้รองรับโดย Android 2.2 (API ระดับ 8) ขึ้นไป
  • OpenGL ES 3.0 - ข้อมูลจำเพาะของ API นี้ได้รับการสนับสนุนใน Android 4.3 (API ระดับ 18) ขึ้นไป
  • OpenGL ES 3.1 - Android 5.0 (API ระดับ 21) ขึ้นไปรองรับข้อกำหนด API นี้
  • OpenGL ES 3.2 - ข้อมูลจำเพาะของ API นี้รองรับ Android 7.0 (API ระดับ 24) ขึ้นไป

ข้อควรระวัง: อุปกรณ์จะไม่สามารถรองรับได้ ไม่ว่าจะเป็นแพลตฟอร์ม Android เวอร์ชันใดก็ตาม OpenGL ES 3.0 API นอกจากว่าผู้ผลิตอุปกรณ์ได้ให้ การนำกราฟิกไปป์ไลน์นี้มาใช้งาน หากคุณระบุในไฟล์ Manifest ว่า ต้องใช้ OpenGL ES 3.0 คุณมั่นใจได้ว่าจะมีเวอร์ชันนั้นอยู่ ในอุปกรณ์ หากคุณระบุว่าจำเป็นต้องใช้เวอร์ชันระดับล่างแต่คุณ ต้องการใช้ฟีเจอร์ 3.0 หากมีให้ใช้งาน คุณควรตรวจสอบในเวลาที่แสดง เพื่อดูว่าอุปกรณ์รองรับ OpenGL เวอร์ชันไหน สำหรับข้อมูลเกี่ยวกับวิธี โปรดดูการตรวจสอบเวอร์ชัน OpenGL ES

หมายเหตุ Android มีการสนับสนุน OpenGL ES 1.0 และ 1.1 แต่ API เวอร์ชันเหล่านี้ เลิกใช้งานแล้ว และไม่ควรใช้กับแอปพลิเคชันสมัยใหม่

หมายเหตุ API เฉพาะที่เฟรมเวิร์ก Android มีให้นั้นคล้ายกับ J2ME JSR239 OpenGL ES API แต่ไม่ได้เหมือนกันทุกประการ หากคุณคุ้นเคยกับข้อกำหนดเฉพาะของ J2ME JSR239 โปรดรับการแจ้งเตือนสำหรับ รูปแบบต่างๆ

ดูเพิ่มเติมที่

ข้อมูลเบื้องต้น

Android รองรับ OpenGL ทั้งผ่าน API เฟรมเวิร์กและการพัฒนาแบบเนทีฟ ชุดอุปกรณ์ (NDK) หัวข้อนี้เน้นที่อินเทอร์เฟซเฟรมเวิร์ก Android ดูข้อมูลเพิ่มเติมเกี่ยวกับ NDK โปรดดู Android NDK

เฟรมเวิร์ก Android ประกอบด้วยชั้นเรียนพื้นฐาน 2 ชั้นที่ช่วยให้คุณสร้างและจัดการเนื้อหาได้ กราฟิกที่มี OpenGL ES API: GLSurfaceView และ GLSurfaceView.Renderer หากเป้าหมายคือการใช้ OpenGL ในแอปพลิเคชัน Android การทำความเข้าใจวิธีใช้ชั้นเรียนเหล่านี้ในกิจกรรมควรเป็นวัตถุประสงค์แรกของคุณ

GLSurfaceView
คลาสนี้เป็น View ที่คุณสามารถวาดและดำเนินการกับวัตถุโดยใช้ การเรียก API ของ OpenGL และมีความคล้ายคลึงกับ SurfaceView คุณสามารถใช้ คลาสนี้โดยการสร้างอินสแตนซ์ของ GLSurfaceView และเพิ่ม Renderer ไปยังข้อความ แต่หากคุณต้องการจับภาพ คุณควรขยายคลาส GLSurfaceView เป็น ใช้ Listener แบบสัมผัส ดังที่แสดงในบทเรียนการฝึกอบรม OpenGL การตอบสนองต่อกิจกรรมการสัมผัส
GLSurfaceView.Renderer
อินเทอร์เฟซนี้กำหนดวิธีการที่จำเป็นสำหรับการวาดกราฟิกใน GLSurfaceView คุณต้องติดตั้งใช้งานอินเทอร์เฟซนี้เป็น แยกคลาสและแนบกับอินสแตนซ์ GLSurfaceView ของคุณโดยใช้ GLSurfaceView.setRenderer()

อินเทอร์เฟซ GLSurfaceView.Renderer กำหนดให้คุณต้องติดตั้งใช้งาน วิธีการต่อไปนี้

  • onSurfaceCreated(): ระบบเรียกสิ่งนี้ เพียงครั้งเดียวเมื่อสร้าง GLSurfaceView ใช้วิธีนี้เพื่อดำเนินการ การดำเนินการที่จำเป็นต้องทำเพียงครั้งเดียว เช่น การตั้งค่าพารามิเตอร์สภาพแวดล้อม OpenGL หรือ กำลังเริ่มต้นออบเจ็กต์กราฟิก OpenGL
  • onDrawFrame(): ระบบจะเรียกใช้เมธอดนี้ในการวาดซ้ำแต่ละครั้งของ GLSurfaceView ใช้วิธีนี้เป็นจุดดำเนินการหลักสำหรับ วาด (และวาดภาพซ้ำ) วัตถุกราฟิก
  • onSurfaceChanged(): ระบบจะเรียกใช้เมธอดนี้เมื่อเรขาคณิตของ GLSurfaceView มีการเปลี่ยนแปลง ซึ่งรวมถึงการเปลี่ยนแปลงขนาดของ GLSurfaceView หรือการวางแนวของหน้าจออุปกรณ์ ตัวอย่างเช่น การเรียกใช้ระบบ ด้วยวิธีนี้เมื่ออุปกรณ์เปลี่ยนจากแนวตั้งเป็นแนวนอน ใช้วิธีนี้เพื่อ ตอบสนองต่อการเปลี่ยนแปลงในคอนเทนเนอร์ GLSurfaceView

แพ็กเกจ OpenGL ES

เมื่อคุณสร้างมุมมองคอนเทนเนอร์สำหรับ OpenGL ES โดยใช้ GLSurfaceView และ GLSurfaceView.Renderer คุณสามารถเริ่ม การเรียกใช้ OpenGL API โดยใช้คลาสต่อไปนี้

  • คลาส API ของ OpenGL ES 2.0
    • android.opengl.GLES20 - แพ็กเกจนี้มอบ อินเทอร์เฟซสำหรับ OpenGL ES 2.0 และพร้อมใช้งานกับ Android 2.2 (API ระดับ 8)
  • แพ็กเกจ API ของ OpenGL ES 3.0/3.1/3.2
    • android.opengl - แพ็กเกจนี้มีอินเทอร์เฟซให้กับ OpenGL ES 3.0/3.1 ใหม่ เวอร์ชัน 3.0 จะมีให้ตั้งแต่ Android 4.3 (API ระดับ 18) เวอร์ชัน 3.1 พร้อมใช้งานแล้ว เริ่มจาก Android 5.0 (API ระดับ 21) เวอร์ชัน 3.2 มีให้บริการใน Android 7.0 (API) ระดับ 24)

หากคุณต้องการเริ่มต้นสร้างแอปด้วย OpenGL ES ทันที ให้ทำตาม การแสดงกราฟิกด้วย OpenGL ES

การประกาศข้อกำหนด OpenGL

หากแอปพลิเคชันของคุณใช้ฟีเจอร์ OpenGL ที่ไม่พร้อมใช้งานในบางอุปกรณ์ คุณต้องใส่ ข้อกำหนดเหล่านี้ใน AndroidManifest.xml ของคุณ การประกาศไฟล์ Manifest ของ OpenGL ที่ใช้กันมากที่สุดมีดังนี้

  • ข้อกำหนดเวอร์ชัน 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.2:

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

    หมายเหตุ OpenGL ES 3.x API นี้สามารถเข้ากันได้แบบย้อนหลังกับ API 2.0 ซึ่งหมายความว่าคุณสามารถ มีความยืดหยุ่นในการใช้งาน OpenGL ES ในแอปพลิเคชันของคุณ โดยการประกาศ OpenGL ตามข้อกําหนดในไฟล์ Manifest ของ ES 2.0 API ของคุณ คุณสามารถใช้เวอร์ชัน API นั้นเป็นค่าเริ่มต้นได้ เพื่อดูความพร้อมใช้งานของ 3.x API ขณะทำงาน แล้วใช้ฟีเจอร์ OpenGL ES 3.x หาก อุปกรณ์ของคุณรองรับ สำหรับข้อมูลเพิ่มเติมเกี่ยวกับการตรวจสอบเวอร์ชัน OpenGL ES ที่รองรับโดย โปรดดูการตรวจสอบเวอร์ชัน OpenGL ES

  • ข้อกำหนดการบีบอัดพื้นผิว - หากแอปพลิเคชันของคุณใช้พื้นผิว คุณต้องประกาศรูปแบบที่แอปพลิเคชันรองรับในไฟล์ Manifest ด้วย <supports-gl-texture> ดูข้อมูลเพิ่มเติมเกี่ยวกับการบีบอัดพื้นผิวที่มีอยู่ โปรดดูการรองรับการบีบอัดพื้นผิว

    การประกาศข้อกำหนดการบีบอัดพื้นผิวในไฟล์ Manifest จะเป็นการซ่อนแอปพลิเคชันไม่ให้ผู้ใช้เห็น กับอุปกรณ์ที่ไม่รองรับการบีบอัดประเภทที่คุณประกาศไว้อย่างน้อย 1 ประเภท สำหรับข้อมูลเพิ่มเติม ข้อมูลเกี่ยวกับวิธีการทำงานของการกรองของ Google Play สำหรับการบีบอัดพื้นผิว โปรดดู ส่วนการกรองของ Google Play และการบีบอัดพื้นผิวในเอกสารประกอบ <supports-gl-texture>

พิกัดแผนที่สำหรับวัตถุที่วาด

ปัญหาพื้นฐานอย่างหนึ่งในการแสดงกราฟิกบนอุปกรณ์ Android คือหน้าจอสามารถ มีขนาดและรูปร่างแตกต่างกัน OpenGL จะถือว่าระบบพิกัดแบบสี่เหลี่ยมจัตุรัสเป็นแบบเดียวกันและโดยค่าเริ่มต้น จะดึงพิกัดเหล่านั้นลงบนหน้าจอที่โดยปกติแล้วไม่ใช่สี่เหลี่ยมจัตุรัส ราวกับว่าเป็นรูปสี่เหลี่ยมจัตุรัสที่เหมาะสม

รูปที่ 1 ระบบพิกัด OpenGL เริ่มต้น (ซ้าย) ที่แมปกับ Android ทั่วไป หน้าจออุปกรณ์ (ขวา)

ภาพด้านบนแสดงระบบพิกัดแบบเดียวกันที่สมมติไว้สำหรับเฟรม OpenGL บน ด้านซ้าย และการจับคู่พิกัดเหล่านี้กับหน้าจออุปกรณ์ทั่วไปในแนวนอนได้อย่างไร ทางด้านขวา ในการแก้ปัญหานี้ คุณสามารถใช้โหมดการฉายภาพ OpenGL และมุมมองกล้องกับ แปลงพิกัดเพื่อให้วัตถุกราฟิกของคุณมีสัดส่วนที่ถูกต้องบนจอแสดงผล

หากต้องการใช้มุมมองการฉายภาพและมุมมองกล้อง คุณต้องสร้างเมทริกซ์การฉายภาพและมุมมองกล้อง แล้วนำไปใช้กับไปป์ไลน์การแสดงผล OpenGL เมทริกซ์การฉายภาพจะคำนวณ พิกัดของกราฟิกเพื่อให้แมปกับหน้าจออุปกรณ์ Android ได้อย่างถูกต้อง มุมมองกล้อง เมทริกซ์สร้างการแปลงที่แสดงวัตถุจากตำแหน่งดวงตาที่เฉพาะเจาะจง

การฉายภาพและมุมมองกล้องใน OpenGL ES 2.0 ขึ้นไป

ใน API ES 2.0 และ 3.0 คุณสามารถใช้มุมมองการฉายภาพและกล้องได้โดยเพิ่มสมาชิกเมทริกซ์ก่อน ไปยังตัวปรับแสงเงายอดมุมของวัตถุกราฟิกของคุณ เมื่อเพิ่มสมาชิกเมทริกซ์นี้ แล้ว คุณสามารถ สร้างและใช้เมทริกซ์การดูของกล้องและใช้การฉายภาพกับวัตถุ

  1. เพิ่มเมทริกซ์ไปยังตัวปรับแสงเงา Vertex - สร้างตัวแปรสำหรับเมทริกซ์การฉายภาพมุมมอง และรวมไว้เป็นตัวคูณของตำแหน่งตัวปรับแสงเงา ในตัวอย่าง Vertex Shaดร่วงต่อไปนี้ โค้ด สมาชิก 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";
    

    หมายเหตุ: ตัวอย่างด้านบนกำหนดเมทริกซ์การเปลี่ยนรูปแบบเดียว สมาชิกในตัวปรับแสงเงา Vertex ที่คุณใช้เมทริกซ์การฉายภาพและมุมมองกล้องรวมกัน เมตริกซ์ คุณอาจต้องกำหนดการฉายภาพแยกกัน ทั้งนี้ขึ้นอยู่กับข้อกำหนดของแอปพลิเคชันของคุณ เมทริกซ์และกล้องถ่ายรูปของสมาชิกเมทริกซ์ในเครื่องมือปรับเฉดสียอดมนุษย์เพื่อให้คุณสามารถเปลี่ยนได้ ได้อย่างอิสระ

  2. เข้าถึงเมทริกซ์ตัวปรับแสงเงา - หลังจากสร้างฮุกในตัวให้เฉดสี Vertex เพื่อ ใช้การฉายภาพและมุมมองกล้อง จากนั้นเข้าถึงตัวแปรดังกล่าวเพื่อใช้การฉายภาพและ เมทริกซ์การดูของกล้อง โค้ดต่อไปนี้แสดงวิธีแก้ไขเมธอด onSurfaceCreated() ของการใช้งาน GLSurfaceView.Renderer เพื่อเข้าถึงเมทริกซ์ ที่กำหนดในตัวปรับแสงเงา Vertex ด้านบน

    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. สร้างการฉายภาพและเมทริกซ์การดูของกล้อง - สร้างการฉายภาพและ การดูเมทริกซ์ที่จะนำไปใช้กับวัตถุกราฟิก โค้ดตัวอย่างต่อไปนี้จะแสดงวิธีแก้ไข onSurfaceCreated() และ onSurfaceChanged()เมธอดของ การใช้ GLSurfaceView.Renderer เพื่อสร้างเมทริกซ์มุมมองกล้องและ เมทริกซ์การฉายภาพโดยอิงตามสัดส่วนภาพบนหน้าจอของอุปกรณ์

    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. ใช้การฉายภาพและเมทริกซ์การดูของกล้อง - เพื่อใช้การฉายภาพและ การแปลงมุมมองกล้อง นําเมทริกซ์มาคูณกันแล้ววางไว้ในจุดยอดมุม ตัวปรับแสงเงา โค้ดตัวอย่างต่อไปนี้แสดงวิธีแก้ไขเมธอด onDrawFrame() ของการใช้งาน GLSurfaceView.Renderer เพื่อรวม เมทริกซ์การฉายภาพและมุมมองกล้องที่สร้างในโค้ดด้านบน แล้วนำไปใช้กับกราฟิก ที่จะแสดงผลโดย 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 การเขียนโปรแกรมกราฟิกด้วย OpenGL ES 1.0/1.1 API แตกต่างจากการใช้ 2.0 อย่างมาก และเวอร์ชันที่สูงกว่านี้ OpenGL ES 2.0 ได้รับการสนับสนุนโดยอุปกรณ์ Android ทั้งหมดตั้งแต่ Android 2.2 (API ระดับ 8) และ เวอร์ชันแรกสุดที่แนะนำสำหรับแอปพลิเคชันใหม่ที่พัฒนาด้วย OpenGL ES OpenGL ES 3.0 ได้รับการสนับสนุนใน Android 4.3 (API ระดับ 18) ขึ้นไป ในอุปกรณ์ที่มี การใช้งาน API ของ OpenGL ES 3.0 สำหรับข้อมูลเกี่ยวกับจำนวนสัมพัทธ์ของอุปกรณ์ที่ใช้ Android ที่สนับสนุน OpenGL ES เวอร์ชันที่กำหนด โปรดดู แดชบอร์ดเวอร์ชัน OpenGL ES

คุณควรพิจารณาข้อกำหนดของกราฟิกอย่างละเอียดและเลือก API ที่เหมาะสำหรับแอปพลิเคชันของคุณที่สุด สำหรับข้อมูลเพิ่มเติม โปรดดู เลือกเวอร์ชัน OpenGL API

OpenGL ES 3.0 API มีคุณลักษณะเพิ่มเติมและประสิทธิภาพที่ดีกว่า API 2.0 และ ที่เข้ากันได้แบบย้อนหลังด้วย ซึ่งหมายความว่าคุณสามารถเขียนการกำหนดเป้าหมายแอปพลิเคชันได้ OpenGL ES 2.0 และมีฟีเจอร์กราฟิก OpenGL ES 3.0 อย่างมีเงื่อนไข หากพร้อมใช้งาน สำหรับ ข้อมูลเพิ่มเติมเกี่ยวกับการตรวจสอบความพร้อมใช้งานของ API 3.0 โปรดดู การตรวจสอบเวอร์ชัน OpenGL ES

การรองรับการบีบอัดพื้นผิว

การบีบอัดพื้นผิวสามารถเพิ่มประสิทธิภาพของแอปพลิเคชัน OpenGL ของคุณได้อย่างมากโดย ช่วยลดข้อกำหนดด้านหน่วยความจำและช่วยให้ใช้แบนด์วิดท์หน่วยความจำได้อย่างมีประสิทธิภาพมากยิ่งขึ้น Android ของเฟรมเวิร์กให้การสนับสนุนรูปแบบการบีบอัด ETC1 เป็นฟีเจอร์มาตรฐาน ซึ่งรวมถึง คลาสยูทิลิตี ETC1Util และเครื่องมือบีบอัด etc1tool (อยู่ใน Android SDK ที่ <sdk>/tools/) ตัวอย่างเช่น แอปพลิเคชัน Android ที่ใช้ การบีบอัดพื้นผิว โปรดดูตัวอย่างโค้ด CompressedTextureActivity ใน Android SDK (<sdk>/samples/<version>/ApiDemos/src/com/example/android/apis/graphics/)

รูปแบบ ETC1 ได้รับการรองรับในอุปกรณ์ Android ทั้งหมดที่รองรับ OpenGL ES 2.0 ขึ้นไป

หมายเหตุ: รูปแบบการบีบอัดพื้นผิว ETC1 ไม่รองรับพื้นผิวที่มี ความโปร่งใส (ช่องสีอัลฟา) หากแอปพลิเคชันของคุณต้องการพื้นผิวที่โปร่งใส คุณควร ให้ตรวจสอบรูปแบบการบีบอัดพื้นผิวอื่นๆ ที่มีในอุปกรณ์เป้าหมาย ต ในการแสดงผลพื้นผิวช่องทางอัลฟ่าโดยใช้ ETC1 คือการเชื่อมโยงวัตถุพื้นผิว ETC1 2 ชิ้น นั่นคือ อันแรกมีข้อมูลสี รายการที่สองมีข้อมูลช่องสีอัลฟา แล้วรวมค่าจากสองข้อมูล พื้นผิวของตัวแปร ในโปรแกรมปรับแสงเงา

รูปแบบการบีบอัดพื้นผิว ETC2/EAC รับประกันได้ว่าจะพร้อมใช้งานเมื่อใช้ OpenGL ES 3.0 API รูปแบบพื้นผิวนี้มีอัตราส่วนการบีบอัดยอดเยี่ยมพร้อมด้วยคุณภาพของภาพสูง รูปแบบนี้ยังรองรับความโปร่งใส (ช่องอัลฟ่า) ด้วย

นอกเหนือจากรูปแบบ ETC แล้ว อุปกรณ์ Android ยังรองรับการบีบอัดพื้นผิวหลากหลายตาม ชิปเซ็ต GPU และการใช้งาน OpenGL คุณควรตรวจสอบการรองรับการบีบอัดพื้นผิวใน อุปกรณ์ที่คุณกำลังกำหนดเป้าหมายเพื่อกำหนดประเภทการบีบอัดที่แอปพลิเคชันของคุณควร การสนับสนุน หากต้องการดูว่าอุปกรณ์หนึ่งๆ รองรับรูปแบบพื้นผิวแบบใด คุณต้อง ค้นหาอุปกรณ์และตรวจสอบชื่อส่วนขยาย OpenGL ซึ่งใช้ระบุรูปแบบการบีบอัดพื้นผิว (และฟีเจอร์ OpenGL อื่นๆ) ที่รองรับโดย อุปกรณ์ รูปแบบการบีบอัดพื้นผิวที่รองรับโดยทั่วไปมีดังนี้

  • Adaptable Scalable Text Compression (ASTC) - รูปแบบการบีบอัดพื้นผิว ที่ออกแบบมาเพื่อแทนที่รูปแบบก่อนหน้านี้ ยืดหยุ่นกว่ารูปแบบก่อนหน้านี้เนื่องจากรองรับ ขนาดบล็อก
    • GL_KHR_texture_compression_astc_ldr
    • GL_KHR_texture_compression_astc_hdr(ช่วงไดนามิกสูง)
  • S3TC (DXTn/DXTC) - การบีบอัดพื้นผิว S3 (S3TC) มีหลายรูปแบบ รูปแบบต่างๆ (DXT1 ถึง DXT5) และมีให้ใช้อย่างแพร่หลายน้อยกว่า รูปแบบรองรับพื้นผิว RGB ที่มี ช่องอัลฟ่า 4 บิตหรือ 8 บิต รูปแบบเหล่านี้แสดงด้วยส่วนขยาย OpenGL ต่อไปนี้ ชื่อ:
    • GL_EXT_texture_compression_s3tc
    อุปกรณ์บางรุ่นรองรับเฉพาะรูปแบบ DXT1 เท่านั้น การสนับสนุนแบบจำกัดนี้จะแสดงด้วย ชื่อส่วนขยาย OpenGL ต่อไปนี้
    • GL_EXT_texture_compression_dxt1

รูปแบบการบีบอัดพื้นผิวต่อไปนี้ถือเป็นรูปแบบเดิมและไม่แนะนำให้ใช้ เพื่อนำไปใช้ในแอปพลิเคชันใหม่:

  • 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
  • 3DC - การบีบอัดพื้นผิว 3DC (3DC) เป็นรูปแบบที่ใช้งานได้อย่างแพร่หลายน้อยกว่า สนับสนุนพื้นผิว RGB ที่มีช่องสีอัลฟา รูปแบบนี้แสดงด้วย OpenGL ต่อไปนี้ ชื่อส่วนขยาย:
    • GL_AMD_compressed_3DC_texture

คำเตือน: รูปแบบการบีบอัดพื้นผิวเหล่านี้ไม่ใช่ รองรับในอุปกรณ์ทุกเครื่อง การรองรับรูปแบบเหล่านี้อาจแตกต่างกันไปตามผู้ผลิตและอุปกรณ์ สำหรับ ข้อมูลเกี่ยวกับวิธีระบุว่ารูปแบบการบีบอัดพื้นผิวแบบใดบนอุปกรณ์หนึ่งๆ โปรดดู หัวข้อถัดไป

หมายเหตุ: เมื่อเลือกรูปแบบการบีบอัดพื้นผิวแล้ว แอปพลิเคชันจะสนับสนุน ตรวจสอบให้แน่ใจว่าคุณได้ประกาศไฟล์ Manifest ของคุณโดยใช้ <supports-gl-texture> การใช้การประกาศนี้จะเปิดใช้การกรองโดยบริการภายนอก เช่น Google Play ดังนั้น แอปของคุณจะติดตั้งเฉพาะในอุปกรณ์ที่รองรับรูปแบบที่แอปของคุณต้องการเท่านั้น โปรดดูรายละเอียดที่หัวข้อ การประกาศไฟล์ Manifest ของ OpenGL

การพิจารณาส่วนขยาย OpenGL

การใช้งาน OpenGL อาจแตกต่างกันไปตามอุปกรณ์ Android ในแง่ของส่วนขยายสำหรับ OpenGL ES API ที่รองรับ ส่วนขยายเหล่านี้รวมถึงการบีบอัดพื้นผิว แต่โดยทั่วไปแล้วยังรวมถึง ไปยังชุดฟีเจอร์ OpenGL

หากต้องการทราบรูปแบบการบีบอัดพื้นผิวและส่วนขยาย OpenGL อื่นๆ ที่รองรับไฟล์ อุปกรณ์หนึ่งๆ:

  1. เรียกใช้โค้ดต่อไปนี้บนอุปกรณ์เป้าหมายเพื่อระบุการบีบอัดพื้นผิว รูปแบบที่รองรับ ได้แก่

    Kotlin

    var extensions = gl.glGetString(GL10.GL_EXTENSIONS)
    

    Java

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

    คำเตือน: ผลลัพธ์ของการโทรนี้จะแตกต่างกันไปตามรุ่นอุปกรณ์ คุณ ต้องเรียกใช้การเรียกนี้ในอุปกรณ์เป้าหมายหลายประเภทเพื่อระบุประเภทการบีบอัดโดยทั่วไป ที่รองรับ

  2. ตรวจสอบเอาต์พุตของเมธอดนี้เพื่อดูว่าส่วนขยาย OpenGL ใดบ้างที่รองรับ อุปกรณ์

แพ็กส่วนขยายของ Android (AEP)

AEP ช่วยให้มั่นใจได้ว่าแอปพลิเคชันของคุณรองรับชุดส่วนขยาย OpenGL มาตรฐานด้านบน และอื่นๆ ชุดหลักที่อธิบายไว้ในข้อกำหนด OpenGL 3.1 การรวมส่วนขยายเหล่านี้เข้าด้วยกัน ส่งเสริมให้เกิดชุดฟังก์ชันการทำงานที่สอดคล้องกันในทุกอุปกรณ์ ในขณะเดียวกันก็ช่วยให้นักพัฒนาซอฟต์แวร์ใช้ ประโยชน์จากการครอบตัดล่าสุดของอุปกรณ์ GPU บนอุปกรณ์เคลื่อนที่

นอกจากนี้ AEP ยังปรับปรุงการรองรับรูปภาพ บัฟเฟอร์ที่เก็บข้อมูลของตัวปรับแสงเงา และตัวนับแบบอะตอมใน ตัวปรับแสงเงา Fragment

ไฟล์ Manifest ของแอปต้องประกาศว่าต้องมี AEP เพื่อให้แอปใช้ AEP ได้ นอกจากนี้ เวอร์ชันแพลตฟอร์มต้องรองรับด้วย

ฟีเจอร์เพิ่มเติมทั้งหมดที่ระบุใน AEP จะรวมอยู่ใน OpenGL ES 3.2 หากแอปของคุณต้องใช้ OpenGL ES 3.2 คุณไม่จำเป็นต้องใช้ AEP

ประกาศข้อกำหนด AEP ในไฟล์ Manifest ดังนี้

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

หากเมธอดแสดงผลเป็น "จริง" แสดงว่าระบบรองรับ AEP

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับ AEP โปรดไปที่หน้าเว็บของ AEP ที่ Khronos OpenGL ES Registry

การตรวจสอบเวอร์ชัน OpenGL ES

OpenGL ES พร้อมใช้งานในอุปกรณ์ Android หลายเวอร์ชัน คุณสามารถระบุ เวอร์ชันต่ำสุดของ API ที่แอปพลิเคชันต้องการในไฟล์ Manifest แต่ คุณยังอาจใช้ประโยชน์จากฟีเจอร์ต่างๆ ใน API ที่ใหม่กว่าไปพร้อมกันได้ด้วย ตัวอย่างเช่น API ของ OpenGL ES 3.0 นั้นสามารถทำงานร่วมกับ API เวอร์ชัน 2.0 ได้ย้อนหลัง ดังนั้นคุณอาจต้องดำเนินการต่อไปนี้ เขียนแอปพลิเคชันของคุณเพื่อให้ใช้ฟีเจอร์ OpenGL ES 3.0 ได้ แต่กลับไปใช้ API เวอร์ชัน 2.0 หาก API 3.0 ไม่พร้อมใช้งาน

ก่อนที่จะใช้ฟีเจอร์ OpenGL ES จากเวอร์ชันที่สูงกว่าขั้นต่ำที่จำเป็นใน ไฟล์ Manifest ของแอปพลิเคชัน แอปพลิเคชันของคุณควรตรวจสอบรุ่นของ API ที่มีอยู่ในอุปกรณ์ คุณสามารถทำได้ด้วยวิธีใดวิธีหนึ่งใน 2 วิธีต่อไปนี้

  1. พยายามสร้างบริบท OpenGL ES ระดับที่สูงขึ้น (EGLContext) และ ตรวจสอบผลลัพธ์
  2. สร้างบริบท OpenGL ES ที่รองรับขั้นต่ำและตรวจสอบค่าเวอร์ชัน

โค้ดตัวอย่างต่อไปนี้แสดงวิธีตรวจสอบเวอร์ชัน OpenGL ES ที่มีอยู่โดยการสร้าง EGLContext และดูผลลัพธ์ ตัวอย่างนี้แสดงวิธีตรวจหา เวอร์ชัน 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 เวอร์ชัน 2.0 และเวอร์ชัน 3.0 ต่างก็ให้ประสบการณ์สูง อินเทอร์เฟซกราฟิกสำหรับการแสดงประสิทธิภาพสำหรับการสร้างเกม 3 มิติ การแสดงข้อมูลผ่านภาพ และอินเทอร์เฟซผู้ใช้ กราฟิก โปรแกรมโปรแกมสำหรับ OpenGL ES 2.0 และ 3.0 มีความคล้ายคลึงกันเป็นส่วนใหญ่ โดยเวอร์ชัน 3.0 จะแสดงซูเปอร์เซ็ต ของ API 2.0 พร้อมด้วยฟีเจอร์เพิ่มเติม การเขียนโปรแกรมสำหรับ API ของ OpenGL ES 1.0/1.1 เทียบกับ OpenGL ES 2.0 และ 3.0 มีความแตกต่างกันอย่างมาก และไม่แนะนำให้ใช้สำหรับแอปพลิเคชันใหม่ นักพัฒนาแอปควรพิจารณาปัจจัยต่อไปนี้อย่างรอบคอบก่อนที่จะเริ่มพัฒนา API เหล่านี้

  • ความเข้ากันได้ของอุปกรณ์ - นักพัฒนาซอฟต์แวร์ควรพิจารณาประเภทอุปกรณ์ เวอร์ชัน Android และเวอร์ชัน OpenGL ES ที่พร้อมให้บริการแก่ลูกค้า หากต้องการดูข้อมูลเพิ่มเติม เกี่ยวกับความเข้ากันได้ของ OpenGL ระหว่างอุปกรณ์ต่างๆ โปรดดูเวอร์ชัน OpenGL และ ความเข้ากันได้ของอุปกรณ์
  • การรองรับพื้นผิว - OpenGL ES 3.0 API รองรับพื้นผิวได้ดีที่สุด เพราะเป็นการรับประกันว่ารูปแบบการบีบอัด ETC2 จะพร้อมใช้งาน ซึ่งรองรับ ความโปร่งใส การใช้ API 2.0 จะมีการรองรับ ETC1 แต่ รูปแบบพื้นผิวนี้ไม่รองรับความโปร่งใส ใช้ความโปร่งใสด้วยการบีบอัด คุณต้องใช้พื้นผิว ETC1 2 แบบ (แบ่งระหว่างสีและอัลฟ่า) หรือให้แหล่งข้อมูล ในรูปแบบการบีบอัดอื่นๆ ที่อุปกรณ์ที่คุณกำหนดเป้าหมายรองรับ สำหรับข้อมูลเพิ่มเติม ดูการรองรับการบีบอัดพื้นผิว

แม้ว่าความเข้ากันได้และการรองรับพื้นผิวอาจส่งผลกระทบต่อ คุณควรเลือกเวอร์ชัน OpenGL API ตามสิ่งที่คุณคิดว่ามอบประสบการณ์ที่ดีที่สุด สำหรับผู้ใช้ของคุณ