OpenGL ES के साथ ग्राफ़िक कॉन्फ़िगर करें

अपने गेम में ऑब्जेक्ट और स्प्राइट ड्रॉ करने के लिए, आपको अपने डिसप्ले, सरफ़ेस, और कॉन्टेक्स्ट वैरिएबल के साथ-साथ अपने गेम लूप में रेंडरिंग सेट अप करना और हर सीन और ऑब्जेक्ट बना सकते हैं.

C या C++ गेम के लिए, स्क्रीन पर इमेज बनाने के दो तरीके हैं. उदाहरण के लिए, OpenGL ES या वल्कन.

शुरू करने से पहले

अगर आपने पहले से ऐसा नहीं किया है, तो अपने ऐप्लिकेशन में GameActivity ऑब्जेक्ट सेट अप करें Android प्रोजेक्ट.

OpenGL ES वैरिएबल सेट अप करना

  1. आपको डिसप्ले की ज़रूरत होगी, प्लैटफ़ॉर्म, संदर्भ, और config का इस्तेमाल करके अपने गेम को रेंडर करें. जोड़ें गेम इंजन की हेडर फ़ाइल में OpenGL ES वैरिएबल का इस्तेमाल करके:

    class NativeEngine {
     //...
     private:
      EGLDisplay mEglDisplay;
      EGLSurface mEglSurface;
      EGLContext mEglContext;
      EGLConfig mEglConfig;
    
      bool mHasFocus, mIsVisible, mHasWindow;
      bool mHasGLObjects;
      bool mIsFirstFrame;
    
      int mSurfWidth, mSurfHeight;
    }
    
  2. अपने गेम इंजन के कंस्ट्रक्टर में, वैरिएबल को हाइलाइट करें.

    NativeEngine::NativeEngine(struct android_app *app) {
      //...
      mEglDisplay = EGL_NO_DISPLAY;
      mEglSurface = EGL_NO_SURFACE;
      mEglContext = EGL_NO_CONTEXT;
      mEglConfig = 0;
    
      mHasFocus = mIsVisible = mHasWindow = false;
      mHasGLObjects = false;
      mIsFirstFrame = true;
    
      mSurfWidth = mSurfHeight = 0;
    }
    
  3. रेंडर करने के लिए डिसप्ले शुरू करें.

    bool NativeEngine::InitDisplay() {
      if (mEglDisplay != EGL_NO_DISPLAY) {
        return true;
      }
    
      mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
      if (EGL_FALSE == eglInitialize(mEglDisplay, 0, 0)) {
        LOGE("NativeEngine: failed to init display, error %d", eglGetError());
        return false;
      }
      return true;
    }
    
  4. सतह EGL से तय किया गया ऑफ़-स्क्रीन बफ़र (पीबफ़र) हो सकता है या Android OS की ओर से तय की गई विंडो में. इस सरफ़ेस को शुरू करें:

    bool NativeEngine::InitSurface() {
      ASSERT(mEglDisplay != EGL_NO_DISPLAY);
      if (mEglSurface != EGL_NO_SURFACE) {
        return true;
      }
    
      EGLint numConfigs;
      const EGLint attribs[] = {
        EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, // request OpenGL ES 2.0
        EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
        EGL_BLUE_SIZE, 8,
        EGL_GREEN_SIZE, 8,
        EGL_RED_SIZE, 8,
        EGL_DEPTH_SIZE, 16,
        EGL_NONE
      };
    
      // Pick the first EGLConfig that matches.
      eglChooseConfig(mEglDisplay, attribs, &mEglConfig, 1, &numConfigs);
      mEglSurface = eglCreateWindowSurface(mEglDisplay, mEglConfig, mApp->window,
                                           NULL);
      if (mEglSurface == EGL_NO_SURFACE) {
        LOGE("Failed to create EGL surface, EGL error %d", eglGetError());
        return false;
      }
      return true;
    }
    
  5. रेंडरिंग कॉन्टेक्स्ट शुरू करें. इस उदाहरण से OpenGL ES 2.0 कॉन्टेक्स्ट:

    bool NativeEngine::InitContext() {
      ASSERT(mEglDisplay != EGL_NO_DISPLAY);
      if (mEglContext != EGL_NO_CONTEXT) {
        return true;
      }
    
      // OpenGL ES 2.0
      EGLint attribList[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
      mEglContext = eglCreateContext(mEglDisplay, mEglConfig, NULL, attribList);
      if (mEglContext == EGL_NO_CONTEXT) {
        LOGE("Failed to create EGL context, EGL error %d", eglGetError());
        return false;
      }
      return true;
    }
    
  6. ड्रॉइंग करने से पहले, अपनी OpenGL ES सेटिंग कॉन्फ़िगर करें. यह उदाहरण यहां लागू किया गया है शामिल हैं. यह गहराई की जांच को चालू करता है, साफ़ रंग को काला है और रंग और गहराई के बफ़र को हटाता है.

    void NativeEngine::ConfigureOpenGL() {
      glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
      glEnable(GL_DEPTH_TEST);
      glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
    }
    

गेम लूप की मदद से रेंडर करें

  1. गेम लूप, किसी फ़्रेम को रेंडर करता है और उसे तब तक दोहराता रहता है, जब तक उपयोगकर्ता उसे छोड़ न दे. फ़्रेम के बीच, आपका गेम ये काम कर सकता है:

    डिसप्ले में फ़्रेम रेंडर करने के लिए, DoFrame तरीका गेम लूप में बिना किसी तय समयसीमा के:

    void NativeEngine::GameLoop() {
      // Loop indefinitely.
      while (1) {
        int events;
        struct android_poll_source* source;
    
        // If not animating, block until we get an event.
        while ((ALooper_pollAll(IsAnimating() ? 0 : -1, NULL, &events,
                                (void **) &source)) >= 0) {
          // Process events.
          ...
        }
    
        // Render a frame.
        if (IsAnimating()) {
            DoFrame();
        }
      }
    }
    
  2. DoFrame तरीके में, प्लैटफ़ॉर्म के मौजूदा डाइमेंशन के बारे में क्वेरी करें. इसके लिए, अनुरोध करें फ़्रेम रेंडर करने और डिसप्ले बफ़र को स्वैप करने के लिए SceneManager.

    void NativeEngine::DoFrame() {
      ...
      // Query the current surface dimension.
      int width, height;
      eglQuerySurface(mEglDisplay, mEglSurface, EGL_WIDTH, &width);
      eglQuerySurface(mEglDisplay, mEglSurface, EGL_HEIGHT, &height);
    
      // Handle dimension changes.
      SceneManager *mgr = SceneManager::GetInstance();
      if (width != mSurfWidth || height != mSurfHeight) {
        mSurfWidth = width;
        mSurfHeight = height;
        mgr->SetScreenSize(mSurfWidth, mSurfHeight);
        glViewport(0, 0, mSurfWidth, mSurfHeight);
      }
      ...
      // Render scenes and objects.
      mgr->DoFrame();
    
      // Swap buffers.
      if (EGL_FALSE == eglSwapBuffers(mEglDisplay, mEglSurface)) {
        HandleEglError(eglGetError());
      }
    }
    

सीन और ऑब्जेक्ट को रेंडर करें

  1. गेम लूप, रेंडर किए जाने वाले सीन और ऑब्जेक्ट की हैरारकी को प्रोसेस करता है. एंडलेस टनल के उदाहरण में, एक SceneManager कई सीन का ट्रैक रखता है, जिसमें एक बार में सिर्फ़ एक सीन चालू हो. इस उदाहरण में, मौजूदा सीन रेंडर किया गया:

    void SceneManager::DoFrame() {
      if (mSceneToInstall) {
        InstallScene(mSceneToInstall);
        mSceneToInstall = NULL;
      }
    
      if (mHasGraphics && mCurScene) {
        mCurScene->DoFrame();
      }
    }
    
  2. आपके गेम के हिसाब से, किसी सीन में बैकग्राउंड, टेक्स्ट, स्प्राइट, और गेम ऑब्जेक्ट. उन्हें अपने गेम के हिसाब से क्रम में लगाएं. यह उदाहरण बैकग्राउंड, टेक्स्ट, और विजेट को रेंडर करता है:

    void UiScene::DoFrame() {
      // clear screen
      glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
      glDisable(GL_DEPTH_TEST);
    
      RenderBackground();
    
      // Render the "Please Wait" sign and do nothing else
      if (mWaitScreen) {
        SceneManager *mgr = SceneManager::GetInstance();
        mTextRenderer->SetFontScale(WAIT_SIGN_SCALE);
        mTextRenderer->SetColor(1.0f, 1.0f, 1.0f);
        mTextRenderer->RenderText(S_PLEASE_WAIT, mgr->GetScreenAspect() * 0.5f,
                                  0.5f);
        glEnable(GL_DEPTH_TEST);
        return;
      }
    
      // Render all the widgets.
      for (int i = 0; i < mWidgetCount; ++i) {
        mWidgets[i]->Render(mTrivialShader, mTextRenderer, mShapeRenderer,
              (mFocusWidget < 0) ? UiWidget::FOCUS_NOT_APPLICABLE :
              (mFocusWidget == i) ? UiWidget::FOCUS_YES : UiWidget::FOCUS_NO,tf);
      }
      glEnable(GL_DEPTH_TEST);
    }
    

संसाधन

OpenGL ES और Vulkan के बारे में ज़्यादा जानकारी के लिए, यहां दी गई जानकारी पढ़ें:

  • OpenGL ES - Android में इमेज और ग्राफ़िक.

  • OpenGL ES - Android Source में खास जानकारी.

  • Vulkan - एनडीके (NDK) में शुरुआत करें.

  • Vulkan - खास जानकारी Android सोर्स में.

  • Android गेम लूप को समझना - रफ़्तार बढ़ाना सीखें फ़्रेम, क्यू बफ़र, VSYNC कॉलबैक को हैंडल करने, और थ्रेड मैनेज करने जैसे काम करते हैं.