OpenGL ES ile grafikleri yapılandırma

Oyununuzda nesne ve imge çizmek için görüntüleme, yüzey ve bağlam değişkenleri, oyun döngünüzde oluşturmayı ayarlama her sahneyi ve nesneyi çizer.

C veya C++ oyunlarında ekrana resim çizmenin iki yolu vardır. Diğer bir deyişle, OpenGL ES veya Vulkan'dan daha fazla bilgi edinebilirsiniz.

ziyaret edin.

Başlamadan önce

Henüz yapmadıysanız bir GameActivity nesnesi ayarlayıp Android projesi.

OpenGL ES değişkenlerini ayarlama

  1. Bir ekrana ihtiyacınız olacaktır, surface bağlam ve config'i kullanarak oyununuzu oluşturun. URL'yi oyun motorunuzun başlık dosyasına aşağıdaki OpenGL ES değişkenlerini ekleyin:

    class NativeEngine {
     //...
     private:
      EGLDisplay mEglDisplay;
      EGLSurface mEglSurface;
      EGLContext mEglContext;
      EGLConfig mEglConfig;
    
      bool mHasFocus, mIsVisible, mHasWindow;
      bool mHasGLObjects;
      bool mIsFirstFrame;
    
      int mSurfWidth, mSurfHeight;
    }
    
  2. Oyun motorunuzun oluşturucusunda, ilk kullanıma hazırlayıp kontrol edebilirsiniz.

    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. Oluşturmak için ekranı başlatın.

    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. Yüzey, EGL tarafından ayrılmış bir ekran dışı arabellek (pbubellek) veya Android OS tarafından ayrılmış pencere olarak düşünebilirsiniz. Bu yüzeyi başlatın:

    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. Oluşturma bağlamını başlatın. Bu örnek, OpenGL ES 2.0 bağlamı:

    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. Çizimden önce OpenGL ES ayarlarınızı yapılandırın. Bu örnek, şurada yürütülür: her karenin başlangıcını belirler. Derinlikli test sağlar, net rengi siyah beyaz yapar ve renk ve derinlik arabelleklerini temizler.

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

Oyun döngüsüyle oluştur

  1. Oyun döngüsü, bir kare oluşturur ve kullanıcı oyundan çıkana kadar süresiz olarak yinelenir. Oyununuz, kareler arasında şunları yapabilir:

    • Aşağıdakiler gibi etkinlikleri işleme: giriş, ses çıkışı ve ağ etkinlikleri.

    • Oyun mantığını ve kullanıcı arayüzünü güncelleyin.

    • Ekran için bir çerçeve oluşturun.

    Ekranda bir kare oluşturmak için DoFrame yöntemi çağrılır. süresiz olarak devam edecek:

    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 yönteminde mevcut yüzey boyutlarını sorgulayın, SceneManager tuşlarına basarak çerçeve oluşturun ve ekran arabelleklerini değiştirin.

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

Sahne ve nesne oluşturma

  1. Oyun döngüsü, oluşturulacak görünür sahnelerin ve nesnelerin hiyerarşisini işler. Sonsuz Tünel örneğinde, SceneManager birden çok sahneyi izler, tek bir sahnede aynı anda etkin olarak ayarlayabilirsiniz. Bu örnekte, mevcut sahne oluşturulma tarihi:

    void SceneManager::DoFrame() {
      if (mSceneToInstall) {
        InstallScene(mSceneToInstall);
        mSceneToInstall = NULL;
      }
    
      if (mHasGraphics && mCurScene) {
        mCurScene->DoFrame();
      }
    }
    
  2. Oyununuza bağlı olarak bir sahnede arka plan, metin, sprite görsel ve nesneleri. Bunları oyununuz için uygun olacak şekilde oluşturun. Bu örnek arka planı, metni ve widget'ları oluşturur:

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

Kaynaklar

OpenGL ES ve Vulkan hakkında daha fazla bilgi için aşağıdakileri okuyun:

  • OpenGL ES: Android'de resimler ve grafikler.

  • OpenGL ES: Android Kaynağında Genel Bakış.

  • Vulkan - NDK'yı kullanmaya başlama.

  • Vulkan - Genel Bakış .

  • Android oyun döngülerini anlama: Tempoyu ayarlamayı öğrenin arabellekleri sıraya alabilir, VSYNC geri çağırmalarını yönetebilir ve ileti dizilerini yönetebilirsiniz.