سؤال

يستخدم تطبيقي حاليًا Direct3D9 فقط للرسومات، ولكن في المستقبل أخطط لتوسيع هذا إلى D3D10 وربما OpenGL.السؤال هو كيف يمكنني القيام بذلك بطريقة مرتبة؟

توجد حاليًا طرق عرض مختلفة في الكود الخاص بي

void Render(boost::function<void()> &Call)
{
    D3dDevice->BeginScene();
    Call();
    D3dDevice->EndScene();
    D3dDevice->Present(0,0,0,0);
}

تعتمد الوظيفة التي تم تمريرها بعد ذلك على الحالة الدقيقة، على سبيل المثال MainMenu->Render، Loading->Render، وما إلى ذلك.ستقوم هذه غالبًا باستدعاء أساليب الكائنات الأخرى.

void RenderGame()
{
    for(entity::iterator it = entity::instances.begin();it != entity::instance.end(); ++it)
        (*it)->Render();
    UI->Render();
}

وفئة عينة مشتقة من الكيان::Base

class Sprite: public Base
{
    IDirect3DTexture9 *Tex;
    Point2 Pos;
    Size2 Size;
public:
    Sprite(IDirect3DTexture9  *Tex, const Point2 &Pos, const Size2 &Size);
    virtual void Render();
};

تهتم كل طريقة بعد ذلك بأفضل طريقة للعرض في ضوء الإعدادات الأكثر تفصيلاً (على سبيل المثال، هل تظليلات البكسل مدعومة أم لا).

المشكلة هي أنني لست متأكدًا حقًا من كيفية توسيع هذا حتى أتمكن من استخدام أحد أوضاع العرض التي قد تكون مختلفة بعض الشيء (D3D v OpenGL) ...

هل كانت مفيدة؟

المحلول

حدد واجهة كافية لمتطلبات الإخراج الرسومي لتطبيقك.ثم قم بتنفيذ هذه الواجهة لكل عارض تريد دعمه.

class IRenderer {
  public:
    virtual ~IRenderer() {}
    virtual void RenderModel(CModel* model) = 0;
    virtual void DrawScreenQuad(int x1, int y1, int x2, int y2) = 0;
    // ...etc...
};

class COpenGLRenderer : public IRenderer {
  public:
    virtual void RenderModel(CModel* model) {
      // render model using OpenGL
    }
    virtual void DrawScreenQuad(int x1, int y1, int x2, int y2) {
      // draw screen aligned quad using OpenGL
    }
};

class CDirect3DRenderer : public IRenderer {
  // similar, but render using Direct3D
};

ومع ذلك، فإن تصميم هذه الواجهات وصيانتها بشكل صحيح قد يكون أمرًا صعبًا للغاية.

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

class IRenderer {
  //...
    virtual ITexture* CreateTexture(const char* filename) = 0;
  //...
};

class COpenGLRenderer : public IRenderer {
  //...
    virtual ITexture* CreateTexture(const char* filename) {
      // COpenGLTexture is the OpenGL specific ITexture implementation
      return new COpenGLTexture(filename);
    }
  //...
};

أليست فكرة النظر إلى المحركات (ثلاثية الأبعاد) الموجودة؟في تجربتي، فإن تصميم هذا النوع من الواجهات يصرف انتباهك عما تريد فعله بالفعل :)

نصائح أخرى

أود أن أقول إذا كنت تريد إجابة كاملة حقًا، فاذهب لإلقاء نظرة على الكود المصدري لـ Ogre3D.لديهم على حد سواء D3D و OpenGL نهايات خلفية.ينظر الى : http://www.ogre3d.orgيفرض عليك نوع API الخاص بهم بشكل أساسي العمل بطريقة D3D، وإنشاء كائنات عازلة وحشوها بالبيانات، ثم إصدار مكالمات السحب على تلك المخازن المؤقتة.هذه هي الطريقة التي تفضلها الأجهزة على أي حال، لذا فهي ليست طريقة سيئة.

وبعد ذلك، بمجرد أن ترى كيف يقومون بالأشياء، يمكنك أيضًا المضي قدمًا واستخدامه وتوفير نفسك عناء الاضطرار إلى إعادة تنفيذ كل ما يوفره بالفعل.:-)

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top