OpenGL ES

يدعم Android الرسومات ثنائية وثلاثية الأبعاد عالية الأداء من خلال Open Graphics Library (OpenGL®)، خاصّةً OpenGL ES API. OpenGL هو واجهة برمجة تطبيقات رسومات متعددة الأنظمة الأساسية تحدد واجهة برنامج قياسية لأجهزة معالجة الرسومات ثلاثية الأبعاد. ويضيف OpenGL ES لمسة لمواصفات OpenGL المخصصة للأجهزة المضمّنة. يدعم Android العديد من إصدارات OpenGL ES API:

  • OpenGL ES 1.0 و1.1 - تتوافق مواصفات واجهة برمجة التطبيقات هذه مع الإصدار Android 1.0 والإصدارات الأحدث.
  • OpenGL ES 2.0 - تتوافق مواصفات واجهة برمجة التطبيقات هذه مع الإصدار Android 2.2 (مستوى واجهة برمجة التطبيقات 8) والإصدارات الأحدث.
  • OpenGL ES 3.0 - تتوافق مواصفات واجهة برمجة التطبيقات هذه مع الإصدار Android 4.3 (مستوى واجهة برمجة التطبيقات 18) والإصدارات الأحدث.
  • OpenGL ES 3.1 - تتوافق مواصفات واجهة برمجة التطبيقات هذه مع الإصدار Android 5.0 (المستوى 21 من واجهة برمجة التطبيقات) والإصدارات الأحدث.

تنبيه: بغض النظر عن إصدار نظام Android الأساسي، لا يمكن للجهاز دعم OpenGL ES 3.0 API ما لم توفّر الشركة المصنّعة للجهاز مسارًا تنفيذيًا لهذه الرسومات. إذا حددت في البيان أن OpenGL ES 3.0 مطلوب، يمكنك التأكد من توفر هذا الإصدار على الجهاز. أما إذا حددت توفّر إصدار ذي مستوى أقل، ولكنك تريد استخدام ميزات الإصدار 3.0 في حال توفّرها، فيجب عليك التحقق في وقت التشغيل لمعرفة إصدار OpenGL الذي يتوافق مع الجهاز. وللحصول على معلومات عن كيفية إجراء ذلك، يمكنك الاطّلاع على التحقق من إصدار OpenGL ES.

ملاحظة: تشبه واجهة برمجة التطبيقات المحددة التي يوفرها إطار عمل Android واجهة برمجة التطبيقات J2ME JSR239 OpenGL ES، لكنّها ليست متطابقة. إذا كنت على دراية بمواصفات J2ME JSR239، يُرجى التنبّه إلى الاختلافات.

راجع أيضًا

الأساسيّات

يدعم Android كلاً من واجهة برمجة التطبيقات لإطار العمل ومجموعة أدوات التطوير الأصلية (NDK). يركِّز هذا الموضوع على واجهات إطار عمل Android. لمزيد من المعلومات حول NDK، يمكنك الاطلاع على Android NDK.

هناك فئتان أساسيتان في إطار عمل Android تتيحان لك إنشاء الرسومات ومعالجتها باستخدام OpenGL ES API، وهما: GLSurfaceView وGLSurfaceView.Renderer. إذا كان هدفك هو استخدام OpenGL في تطبيق Android، فيجب أن يكون هدفك الأول هو فهم كيفية تنفيذ هذه الفئات في نشاط ما.

GLSurfaceView
هذه الفئة هي View، حيث يمكنك رسم العناصر ومعالجتها باستخدام طلبات البيانات من واجهة برمجة تطبيقات OpenGL، وهي تشبه وظيفتها SurfaceView. يمكنك استخدام هذا الصف من خلال إنشاء مثيل GLSurfaceView وإضافة Renderer إليه. وإذا كنت تريد تسجيل أحداث الشاشة التي تعمل باللمس، عليك توسيع الصف GLSurfaceView لاستخدام أدوات معالجة اللمس، كما هو موضّح في درس 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 باستخدام الفئات التالية:

  • حزم OpenGL ES 1.0/1.1 API
  • فئة OpenGL ES 2.0 API
    • android.opengl.GLES20: توفّر هذه الحزمة واجهة OpenGL ES 2.0 وتتوفّر بدءًا من الإصدار Android 2.2 (المستوى 8 من واجهة برمجة التطبيقات).
  • حزم OpenGL ES 3.0/3.1 API
    • android.opengl: توفّر هذه الحزمة الواجهة لفئات OpenGL ES 3.0/3.1. يتوفّر الإصدار 3.0 بدايةً من Android 4.3 (المستوى 18 من واجهة برمجة التطبيقات). يتوفّر الإصدار 3.1 بدءًا من Android 5.0 (المستوى 21 من واجهة برمجة التطبيقات).

إذا كنت تريد البدء في إنشاء تطبيق باستخدام OpenGL ES على الفور، يُرجى اتّباع فئة عرض الرسومات باستخدام OpenGL ES.

بيان متطلبات OpenGL

إذا كان تطبيقك يستخدم ميزات OpenGL غير متوفّرة على جميع الأجهزة، يجب تضمين هذه المتطلبات في ملف AndroidManifest.xml. إليك أكثر بيانات بيان OpenGL شيوعًا:

  • متطلبات إصدار 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 مع الإصدارات القديمة مع 2.0 API، ما يعني أنّه يمكنك أن تكون أكثر مرونة في ما يتعلق بتنفيذ OpenGL ES في تطبيقك. ومن خلال تعريف OpenGL ES 2.0 API كشرط في ملف البيان، يمكنك استخدام إصدار واجهة برمجة التطبيقات هذا كإعداد تلقائي، والتأكّد من مدى توفّر واجهة برمجة التطبيقات 3.x في وقت التشغيل، ثم استخدام ميزات OpenGL ES 3.x إذا كان الجهاز يتيحها. لمزيد من المعلومات حول التحقُّق من إصدار OpenGL ES المتوافق مع الجهاز، يمكنك الاطّلاع على التحقق من إصدار OpenGL ES.

  • متطلبات ضغط القوام - إذا كان تطبيقك يستخدم تنسيقات ضغط القوام، يجب الإفصاح عن التنسيقات المتوافقة مع تطبيقك في ملف البيان باستخدام <supports-gl-texture>. ولمزيد من المعلومات حول تنسيقات ضغط البنية المتاحة، يمكنك الاطلاع على إتاحة ضغط الهيئة.

    يؤدي الإفصاح عن متطلبات ضغط البنية في ملف البيان إلى إخفاء تطبيقك عن المستخدمين الذين لا يستخدمون أجهزة لا تتوافق على الأقل مع نوع واحد على الأقل من أنواع الضغط التي تم تعريفها. للحصول على مزيد من المعلومات حول طريقة عمل الفلترة في Google Play مع ضغط البنية، يمكنك الرجوع إلى قسم Google Play وتصفية الضغط في Google Play في مستندات <supports-gl-texture>.

تعيين إحداثيات الكائنات المرسومة

من المشاكل الأساسية في عرض الرسومات على أجهزة Android هي أنّ الشاشات قد تختلف من حيث الحجم والشكل. يفترض OpenGL أن نظام الإحداثيات مربعًا موحدًا، وبشكل افتراضي، يرسم هذه الإحداثيات على نحو مثالي على شاشتك غير المربعة بشكل مثالي.

الشكل 1. تم تعيين نظام إحداثيات OpenGL التلقائي (اليسار) على شاشة جهاز Android عادية (يمين).

يوضح الرسم التوضيحي أعلاه نظام الإحداثيات الموحّد المُفترض لإطار OpenGL على اليسار، وكيف يتم تعيين هذه الإحداثيات فعليًا على شاشة جهاز نموذجية في الاتجاه الأفقي على اليمين. ولحل هذه المشكلة، يمكنك تطبيق أوضاع عرض OpenGL وعروض الكاميرا لتحويل الإحداثيات حتى تحصل الكائنات الرسومية على النسب الصحيحة على أي شاشة.

لتطبيق الإسقاط وطرق عرض الكاميرا، يمكنك إنشاء مصفوفة عرض ومصفوفة عرض الكاميرا وتطبيقهما على مسار عرض OpenGL. تعيد مصفوفة الإسقاط حساب إحداثيات الرسوميات لديك بحيث يتم ربطها بشكل صحيح مع شاشات جهاز Android. تنشئ مصفوفة عرض الكاميرا عملية تحويل تعرض الكائنات من موضع عين معين.

الإسقاط وعرض الكاميرا في OpenGL ES 1.0

في ES 1.0 API، يمكنك تطبيق الإسقاط وعرض الكاميرا من خلال إنشاء كل مصفوفة ثم إضافتها إلى بيئة OpenGL.

  1. مصفوفة إسقاط: يمكنك إنشاء مصفوفة إسقاط باستخدام هندسة شاشة الجهاز لإعادة حساب إحداثيات الكائنات لرسمها بالنسب الصحيحة. يوضح الرمز في المثال التالي كيفية تعديل طريقة onSurfaceChanged() لتنفيذ GLSurfaceView.Renderer لإنشاء مصفوفة عرض بناءً على نسبة العرض إلى الارتفاع للشاشة وتطبيقها على بيئة عرض 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. مصفوفة تحويل الكاميرا - بعد ضبط نظام الإحداثيات باستخدام مصفوفة إسقاط، يجب أيضًا تطبيق عرض الكاميرا. يوضِّح الرمز في المثال التالي كيفية تعديل طريقة onDrawFrame() في تنفيذ GLSurfaceView.Renderer لتطبيق عرض نموذج واستخدام أداة 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، يمكنك تطبيق الإسقاط والكاميرا من خلال إضافة عضو مصفوفة أولاً إلى وحدات تظليل الرأس لكائنات الرسومات. مع إضافة عضو المصفوفة هذا، يمكنك بعد ذلك إنشاء وتطبيق مصفوفات عرض الكاميرا والإسقاط على الكائنات لديك.

  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. الوصول إلى مصفوفة أدوات التظليل - بعد إنشاء عنصر جذب في أدوات تظليل الرأس لتطبيق العرض وعرض الكاميرا، يمكنك الوصول إلى ذلك المتغير لتطبيق مصفوفات العرض وإسقاط الكاميرا. يوضّح الرمز التالي كيفية تعديل طريقة onSurfaceCreated() لتنفيذ GLSurfaceView.Renderer للوصول إلى متغيّر المصفوفة المحدّد في أداة تظليل الرأس أعلاه.

    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، تكون واجهة الشكل عبارة عن سطح يتم تحديده بثلاث نقاط أو أكثر في مساحة ثلاثية الأبعاد. تحتوي مجموعة من النقاط الثلاثية الأبعاد أو أكثر (تسمى الرؤوس في 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 (المستوى 8 من واجهة برمجة التطبيقات)، يتوافق إطار العمل مع مواصفات واجهة برمجة التطبيقات OpenGL ES 2.0. يتوافق OpenGL ES 2.0 على معظم أجهزة Android ويُنصح به للتطبيقات الجديدة التي يتم تطويرها باستخدام OpenGL. يتوافق OpenGL ES 3.0 مع نظام التشغيل Android 4.3 (المستوى 18 من واجهة برمجة التطبيقات) والإصدارات الأحدث على الأجهزة التي توفّر OpenGL ES 3.0 API. للحصول على معلومات حول العدد النسبي للأجهزة التي تعمل بنظام التشغيل Android والتي تتوافق مع إصدار معيّن من OpenGL ES، يُرجى الاطّلاع على لوحة بيانات إصدار OpenGL ES.

تختلف برمجة الرسومات مع OpenGL ES 1.0/1.1 API بشكل كبير عن استخدام الإصدار 2.0 والإصدارات الأحدث. يحتوي الإصدار 1.x من واجهة برمجة التطبيقات على المزيد من الطرق السهلة ومسارًا ثابتًا للرسومات، في حين توفّر واجهات برمجة التطبيقات OpenGL ES 2.0 و3.0 إمكانية التحكم المباشر بشكل أكبر في مسار التعلّم من خلال استخدام أدوات تظليل OpenGL. يجب مراعاة متطلبات الرسومات بعناية واختيار إصدار واجهة برمجة التطبيقات الذي يناسب تطبيقك بشكل أفضل. لمزيد من المعلومات، يُرجى الاطِّلاع على اختيار إصدار 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 إمكانية دعم تنسيق ضغط ETC1 كميزة عادية، بما في ذلك فئة الأدوات المساعدة ETC1Util وأداة الضغط etc1tool (المتوفّرة في حزمة تطوير البرامج (SDK) لنظام التشغيل Android) على <sdk>/tools/). للحصول على مثال على تطبيق Android يستخدم ضغط النص، يُرجى الاطّلاع على نموذج رمز CompressedTextureActivity في حزمة تطوير البرامج (SDK) لنظام التشغيل Android (<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 دعمًا متنوّعًا لضغط الهيئة استنادًا إلى شرائح وحدة معالجة الرسومات وعمليات تنفيذ OpenGL. يجب التحقق من استخدام ضغط المظهر على الأجهزة التي تستهدفها لتحديد أنواع الضغط التي يجب أن يتوافق معها تطبيقك. لتحديد تنسيقات الزخرفة المتوافقة على جهاز معيّن، يجب إجراء طلب بحث عن الجهاز ومراجعة أسماء إضافات OpenGL، التي تحدّد تنسيقات ضغط البنية (وميزات OpenGL الأخرى) التي يتوافق معها الجهاز. في ما يلي بعض تنسيقات ضغط البنية المتوافقة بشكل عام:

  • ATITC (ATC) - يتوفر ضغط بنية ATI (ATITC أو ATC) على مجموعة متنوعة من الأجهزة ويتوافق مع ضغط المعدل الثابت لمظاهر نموذج أحمر أخضر أزرق مع قناة ألفا أو بدونها. يمكن تمثيل هذا التنسيق بعدة أسماء إضافات 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 بت. ويتم تمثيل هذه التنسيقات باسم إضافة OpenGL التالي:
    • GL_EXT_texture_compression_s3tc
    لا تتوافق بعض الأجهزة إلا مع صيغة تنسيق DXT1، ويتم تمثيل هذا الدعم المحدود باسم إضافة OpenGL التالي:
    • GL_EXT_texture_compression_dxt1
  • 3DC - ضغط الهيئة ثلاثي الأبعاد (3DC) هو تنسيق غير متاح على نطاق واسع يتوافق مع زخارف نموذج أحمر أخضر أزرق مع قناة ألفا. ويتم تمثيل هذا التنسيق باسم إضافة OpenGL التالي:
    • GL_AMD_compressed_3DC_texture

تحذير: غير متوافقة مع تنسيقات ضغط البنية هذه على جميع الأجهزة. وقد يختلف توافق هذه التنسيقات حسب الشركة المصنّعة والجهاز. للحصول على معلومات حول كيفية تحديد تنسيقات ضغط البنية على جهاز معين، اطلع على القسم التالي.

ملاحظة: بعد تحديد تنسيقات ضغط المظهر التي سيستخدمها تطبيقك، تأكد من توضيحها في البيان باستخدام <supports-gl-texture> . يؤدي استخدام هذا البيان إلى تفعيل الفلترة حسب الخدمات الخارجية مثل Google Play، بحيث لا يتم تثبيت تطبيقك إلا على الأجهزة التي تتوافق مع التنسيقات التي يتطلبها تطبيقك. لمعرفة التفاصيل، يُرجى الاطّلاع على بيانات بيان 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. يؤدي تجميع هذه الإضافات معًا إلى تشجيع مجموعة متسقة من الوظائف عبر الأجهزة، مع السماح للمطوّرين في الوقت نفسه بالاستفادة الكاملة من أحدث مجموعة من أجهزة وحدة معالجة الرسومات للجوّال.

يحسّن AEP أيضًا إمكانية استخدام الصور ومخازن أدوات التخزين المؤقتة والعدادات البسيطة في أدوات تظليل الأجزاء.

ولكي يتمكّن تطبيقك من استخدام AEP، يجب أن يذكر ملف بيان التطبيق أنّ AEP مطلوب. بالإضافة إلى ذلك، يجب أن يتوافق هذا الإصدار مع إصدار النظام الأساسي.

يُرجى تعريف مطلب 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 Registry.

التحقُّق من إصدار OpenGL ES

تتوفّر العديد من إصدارات OpenGL ES على أجهزة Android. يمكنك تحديد الحد الأدنى من إصدار واجهة برمجة التطبيقات التي يتطلبها تطبيقك في بيانك، ولكنك قد تحتاج أيضًا إلى الاستفادة من ميزات واجهة برمجة تطبيقات أحدث في الوقت نفسه. على سبيل المثال، تتوافق واجهة برمجة التطبيقات OpenGL ES 3.0 مع الأنظمة القديمة مع الإصدار 2.0 من واجهة برمجة التطبيقات، لذا قد تحتاج إلى كتابة تطبيقك بحيث يستخدم ميزات OpenGL ES 3.0، إلا أنّه يعود إلى واجهة برمجة التطبيقات 2.0 API في حال عدم توفّر واجهة برمجة التطبيقات 3.0 API.

قبل استخدام ميزات OpenGL ES من إصدار أحدث من الحد الأدنى المطلوب في بيان التطبيق، يجب أن يتحقّق تطبيقك من إصدار واجهة برمجة التطبيقات المتاحة على الجهاز. يمكنك القيام بذلك بإحدى الطريقتين التاليتين:

  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() أعلاه قيمة فارغة، يجب أن يُنشئ الرمز الخاص بك سياق OpenGL ES 2.0 بدلاً من ذلك وأن يعود لاستخدام واجهة برمجة التطبيقات هذه فقط.

يوضح مثال الرمز التالي كيفية التحقق من إصدار 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.

بهذه الطريقة، إذا اكتشفت أنّ الجهاز يتوافق مع إصدار أعلى من واجهة برمجة التطبيقات، عليك إتلاف الحد الأدنى لسياق OpenGL ES وإنشاء سياق جديد باستخدام إصدار واجهة برمجة التطبيقات المتوفّر الأعلى.

اختيار إصدار OpenGL API

يوفّر إصدار OpenGL ES 1.0 API (والإضافات 1.1) والإصدار 2.0 والإصدار 3.0 واجهات رسومات عالية الأداء لإنشاء ألعاب ثلاثية الأبعاد وعروض مرئية وواجهات مستخدم. تتشابه عملية تطوير الرسومات لـ OpenGL ES 2.0 و3.0 إلى حد كبير، حيث يمثل الإصدار 3.0 مجموعة شاملة من واجهة برمجة التطبيقات 2.0 API مع ميزات إضافية. تختلف برمجة OpenGL ES 1.0/1.1 API مقابل OpenGL ES 2.0 و3.0 بشكل كبير، لذا على المطوّرين مراعاة العوامل التالية بعناية قبل بدء التطوير باستخدام واجهات برمجة التطبيقات هذه:

  • الأداء: بوجهٍ عام، يوفّر OpenGL ES 2.0 و3.0 أداء رسومات أسرع من واجهات برمجة التطبيقات ES 1.0/1.1. ومع ذلك، يمكن أن يختلف الفارق في الأداء حسب جهاز Android الذي يعمل عليه تطبيق OpenGL، وذلك بسبب الاختلافات في طريقة تنفيذ الشركة المصنّعة للجهاز لمسار رسومات OpenGL ES.
  • التوافق مع الجهاز: على المطوّرين مراعاة أنواع الأجهزة وإصدارات Android وإصدارات OpenGL ES المتوفّرة لعملائهم. لمزيد من المعلومات حول توافق OpenGL على جميع الأجهزة، يُرجى مراجعة القسم إصدارات OpenGL وتوافق الجهاز.
  • سهولة الترميز: توفّر واجهة برمجة التطبيقات OpenGL ES 1.0/1.1 API مسارًا ثابتًا للوظائف ووظائف ملائمة غير متوفّرة في واجهات برمجة التطبيقات OpenGL ES 2.0 أو 3.0. بالنسبة إلى المطوّرين الذين يستخدمون OpenGL ES للمرة الأولى، قد يجدون ترميزًا للإصدار 1.0 أو 1.1 أسرع وأسهل.
  • التحكّم في الرسومات: توفّر واجهات برمجة التطبيقات OpenGL ES 2.0 و3.0 درجة أعلى من التحكّم من خلال توفير مسار قابل للبرمجة بالكامل باستخدام أدوات التظليل. مع المزيد من التحكّم المباشر في مسار معالجة الرسومات، يمكن للمطوّرين إنشاء تأثيرات يصعب إنشاؤها باستخدام واجهة برمجة التطبيقات 1.0/1.1.
  • دعم الهيئة: توفّر واجهة برمجة التطبيقات OpenGL ES 3.0 أفضل دعم لضغط الهيئة لأنّها تضمن توفّر تنسيق ضغط ETC2 الذي يتوافق مع الشفافية. عادةً ما تتضمن عمليات تنفيذ واجهة برمجة التطبيقات 1.x و2.0 إمكانية استخدام ETC1، إلا أنّ تنسيق المظهر هذا لا يتيح الشفافية، لذا عليك عادةً توفير الموارد بتنسيقات ضغط أخرى متوافقة مع الأجهزة التي تستهدفها. ولمزيد من المعلومات، يُرجى الاطّلاع على إتاحة ضغط الهيئة.

على الرغم من أنّ الأداء والتوافق والراحة والتحكم وعوامل أخرى قد تؤثر في قرارك، عليك اختيار إصدار OpenGL API بناءً على ما تعتقد أنّه يوفّر أفضل تجربة للمستخدمين.