OpenGL ES দিয়ে গ্রাফিক্স কনফিগার করুন

আপনার গেমে বস্তু এবং স্প্রাইটগুলি আঁকতে, আপনাকে প্রদর্শন, পৃষ্ঠ এবং প্রসঙ্গ ভেরিয়েবলগুলি কনফিগার করতে হবে, আপনার গেম লুপে রেন্ডারিং সেট আপ করতে হবে এবং প্রতিটি দৃশ্য এবং অবজেক্ট আঁকতে হবে৷

একটি C বা C++ গেমের জন্য পর্দায় ছবি আঁকার দুটি উপায় আছে, যেমন OpenGL ES , বা Vulkan

আপনি শুরু করার আগে

আপনি যদি ইতিমধ্যে এটি না করে থাকেন তবে আপনার অ্যান্ড্রয়েড প্রকল্পে একটি গেম অ্যাক্টিভিটি অবজেক্ট সেট আপ করুন

OpenGL ES ভেরিয়েবল সেট আপ করুন

  1. আপনার গেম রেন্ডার করার জন্য আপনার একটি প্রদর্শন , পৃষ্ঠ , প্রসঙ্গ এবং কনফিগার প্রয়োজন হবে। আপনার গেম ইঞ্জিনের হেডার ফাইলে নিম্নলিখিত 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 দ্বারা বরাদ্দ করা অফ-স্ক্রিন বাফার (pbuffer), অথবা 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 - অ্যান্ড্রয়েডে ছবি এবং গ্রাফিক্স।

  • OpenGL ES - অ্যান্ড্রয়েড সোর্সে ওভারভিউ।

  • Vulkan - NDK তে শুরু করা।

  • ভলকান - অ্যান্ড্রয়েড সোর্সে ওভারভিউ।

  • অ্যান্ড্রয়েড গেম লুপগুলি বুঝুন - ফ্রেমের গতি, সারি বাফার, VSYNC কলব্যাকগুলি পরিচালনা করতে এবং থ্রেডগুলি পরিচালনা করতে শিখুন৷