API สะพานที่ไม่เชื่อเรื่องพระเจ้า (เช่น OpenGL / D3D / อะไรก็ตาม) คุณใช้มันอย่างไรคุณสร้างมันขึ้นมา Pro's and Con's [ปิด]


12

คุณกำลังสร้างเอนจิ้น 3 มิติ คุณต้องการโลกที่หลากหลายที่สุด ทันใดนั้นคุณก็รู้ว่าถ้าคุณต้องการใช้ Direct3D บนเครื่อง Windows และ OpenGL บน OSX / Linux คุณจะต้องเสียสละคุณสมบัติที่รองรับของตัวหารที่ใช้ร่วมกันให้น้อยที่สุด

บางคนอาจใช้ OpenGL ในสามระบบปฏิบัติการ 'เพราะมันดูเหมือนจะเป็นตัวหารร่วมน้อยที่สุดด้วยตัวเอง ทั้งหมดเป็นสิ่งที่ดี. จากนั้นคุณต้องพอร์ตกราฟิก API ของคุณไปที่ GX ของ Nintendo คุณต้องสร้างเส้นทาง PS3 และ Xbox360 ด้วย

คุณทำอะไร? คุณออกแบบ API ของคุณเองซึ่งเป็นตัวหารน้อยที่สุดในตัวเองและเขียนการใช้งานแบ็กเอนด์สำหรับแต่ละแพลตฟอร์มหรือคุณเขียนสำหรับแต่ละแพลตฟอร์มเป็นสาขาของตัวเองหรือไม่?

หากคุณเลือกที่จะออกแบบ API ของคุณเองคุณใช้รูปแบบบริดจ์หรือวูดูของคุณเองหรือไม่ ความบ้าคลั่งหยุดอยู่ที่ไหนที่คุณตระหนักถึงทุกสิ่งและวิธีการอ่างล้างจานในครัวจะต้องหยุดและคุณมีเครื่องมือแยกต่างหากสำหรับแต่ละแพลตฟอร์มเป็นสาขา หรือคุณยึดติดกับทุกอย่างและอ่างล้างจานในครัวและเก็บเฉพาะแพลตฟอร์มไว้ในความเชี่ยวชาญของโมดูลแบ็กเอนด์สำหรับแต่ละแพลตฟอร์ม

คำตอบ:


9

ฉันไม่ใช่แฟนตัวยงของวิธีการหารน้อยที่สุด หากคุณทำเช่นนั้นคุณอาจท้ายด้วยคุณสมบัติที่พิการและประสิทธิภาพที่ไม่ดี

สิ่งที่ฉันทำไปแล้วในอดีตคือการจัดหาฟังก์ชั่นระดับสูงขึ้นเล็กน้อยในห้องสมุด ไลบรารีนั้นเป็น API ส่วนใหญ่ที่ไม่เชื่อเรื่องพระเจ้าและสามารถใช้งานได้ทุกที่ ตัวอย่างเช่นแทนที่จะมีฟังก์ชัน SetStateX () คุณจะมีฟังก์ชันที่สูงกว่าเช่น RenderMesh () หรือ CreateRenderTarget ()

มันจะทำงานได้ดีกว่าเลเยอร์ที่บางมาก ๆ ทุกครั้งที่คุณย้ายไปยังแพลตฟอร์มใหม่ แต่มันจะคุ้มค่าอย่างสมบูรณ์เพราะคุณจะสามารถใช้สิ่งต่าง ๆ ในวิธีที่เหมาะสมที่สุดสำหรับแพลตฟอร์มนั้นและคุณจะสามารถใช้งานได้ ข้อได้เปรียบของคุณสมบัติที่เป็นเอกลักษณ์ดั้งเดิม

อีกสิ่งหนึ่ง: อย่ากลัวที่จะทำลาย encapsulation เล็กน้อย ไม่มีอะไรน่าผิดหวังยิ่งไปกว่าการรู้ว่าคุณอยู่ในแพลตฟอร์มที่มีความสามารถบางอย่างและไม่สามารถใช้งานได้ การปล่อยแบ็คดอร์บางอย่างเพื่อให้โค้ดระดับสูงสามารถใช้ประโยชน์จากแพลตฟอร์มนั้นมีประโยชน์มาก (เช่นสามารถดึงอุปกรณ์ D3D หรือบริบท OpenGL)


3
ฉันคิดว่าคุณพูดในสิ่งที่ฉันพยายามจะพูดเท่านั้นดีกว่า
AShelly

6

ทั้งหมดที่ฉันสามารถพูดได้ก็คือดูที่Ogre3D มันเขียนด้วยภาษา C ++, โอเพ่นซอร์ส (MIT License ตอนนี้) และรันบนทุกแพลตฟอร์มที่สำคัญนอกกรอบ มันสรุปการแสดงผล API และสามารถเปลี่ยนจากการใช้ DirectX เป็น OpenGL ด้วยการตั้งค่าเพียงไม่กี่ อย่างไรก็ตามฉันไม่ทราบเกี่ยวกับความแตกต่างระหว่างชุดคุณลักษณะของ DirectX และ OpenGL มากพอที่จะบอกว่ามันไม่รองรับหรือไม่รองรับคุณสมบัติเฉพาะ

Torchlightโดย Runic Games เขียนขึ้นโดยใช้ Ogre และฉันเคยเล่นมันใน Mac และ PC และมันก็ทำงานได้ดีทั้งบน


2
+1 สำหรับวิธีอสูร ฉันรู้เกี่ยวกับมันได้อ่านบางส่วนของรหัส ฉันสนใจที่จะฟังเรื่องราวส่วนตัวเกี่ยวกับวิธีการและสิ่งที่คนอื่นทำในสถานการณ์เช่นนั้น
คีย์เฟรม

2
ขอบคุณ! ฉันจะทำส่วนใหญ่ตามวิธีที่ Ogre ทำ ฉันใช้วิธี Interface / Factory ในการพัฒนาข้ามแพลตฟอร์มจำนวนมากและจริง ๆ แล้วฉันไม่แน่ใจว่าจะทำอย่างอื่นได้อย่างไร ฉันจะบอกว่าคุณจำเป็นต้องทำงานบนหลาย ๆ แพลตฟอร์มในเวลาเดียวกัน อย่าพยายามและรหัสทุกอย่างใน Windows และกว่าลองพอร์ตไปยัง Mac เช่น
Casey

ใช่ ฉันเริ่มเบื่อหน่ายกับการห่อหุ้ม cross-API ของฉันเองแล้วฉันก็เริ่มใช้ Ogre ยังไม่ได้ดู :)
jacmoe

1

ฉันไม่ได้ทำสิ่งนี้เพื่อกราฟิก แต่ฉันสร้างชุดเครื่องมือเสียงข้ามแพลตฟอร์ม (PC / XBOX / PS2) เราไปตามเส้นทางของการสร้าง API ของเราเองด้วยความสามารถน้อยที่สุดที่เป็นตัวหารร่วมกันรวมถึงความสามารถเฉพาะแพลตฟอร์มที่เป็นตัวเลือก นี่คือบทเรียนบางส่วนที่ได้เรียนรู้:

กุญแจสำคัญคือการกำหนดเส้นทางการประมวลผลที่ห่อหุ้มความสามารถหลักของแต่ละแพลตฟอร์มและช่วยให้การเจริญเติบโต ในการทำเช่นนี้คุณต้องเข้าใจ API ระดับต่ำของแต่ละแพลตฟอร์มเพื่อให้คุณสามารถระบุนามธรรมที่ถูกต้องได้ ตรวจสอบให้แน่ใจว่าเชนทำงานสำหรับแพลตฟอร์มที่มีความสามารถน้อยที่สุดในขณะที่ให้การเข้าถึงคุณลักษณะขั้นสูงของ patform ที่มีความสามารถมากที่สุด ทำงานให้ถูกต้องและคุณจะประหยัดความพยายามได้ในภายหลัง

SoundSources -> [Decoders] -> Buffers -> [3D Positioner] ->[Effects] -> Playersสำหรับเสียงโซ่เป็นสิ่งที่ชอบ

Model -> Shapes -> Positioner -> Texturer -> [Lighting] -> [Particle Effects] -> Rendererสำหรับกราฟิกมันอาจจะเป็น (นี่อาจเป็นชุดที่ผิดอย่างสมบูรณ์ฉันไม่ใช่คนกราฟิก)

เขียน API ส่วนหน้าซึ่งจัดการกับวัตถุหลักของคุณและส่วนหลังเฉพาะแพลตฟอร์มที่จับคู่ API กับความสามารถระดับต่ำ ให้ความพยายามอย่างดีที่สุดสำหรับความสามารถแต่ละอย่าง ตัวอย่างเช่นบนพีซีและ XBOX การวางตำแหน่งเสียงแบบ 3D ทำได้โดยใช้ความสามารถ HRTF ของชิปเสียงในขณะที่ PS2 ใช้การแพนและเฟดอย่างง่าย เอ็นจิ้นกราฟิกอาจทำบางสิ่งที่คล้ายกับแสง

ใช้ส่วนหน้าให้มากที่สุดด้วยรหัสที่เป็นกลางของแพลตฟอร์ม รหัสที่จะแนบวัตถุพัดโบกกับวัตถุเสียงหรือสินทรัพย์พื้นผิวให้กับวัตถุรูปร่างควรเป็นเรื่องปกติอย่างสมบูรณ์เช่นรหัสที่จะวนซ้ำผ่านและประมวลผลวัตถุที่ใช้งานอยู่ ในทางตรงกันข้ามวัตถุระดับต่ำสามารถเป็นแพลตฟอร์มที่สมบูรณ์โดยเฉพาะยกเว้นสำหรับส่วนต่อประสานทั่วไป

ตรวจสอบให้แน่ใจว่า API หรือไฟล์การกำหนดค่าอนุญาตให้ผู้ใช้ระบุตัวเลือกเฉพาะแพลตฟอร์ม เราพยายามหลีกเลี่ยงการกดรหัสเฉพาะแพลตฟอร์มไปที่ระดับเกมโดยเก็บไว้ในไฟล์กำหนดค่า: ไฟล์กำหนดค่าของแพลตฟอร์มหนึ่งสามารถระบุ "เอฟเฟกต์: SuperDuperParticleGenerator" ในขณะที่อีกตัวระบุว่า "เอฟเฟกต์: SoftGlow"

พัฒนาแพลตฟอร์มอย่างแน่นอน ตรวจสอบให้แน่ใจว่าอินเทอร์เฟซเฉพาะแพลตฟอร์มนั้นถูกกำหนดอย่างดีและสามารถทดสอบได้ด้วยตนเอง วิธีนี้ช่วยป้องกัน "เป็นระดับแพลตฟอร์มหรือระดับ API" ปัญหาเมื่อตรวจแก้จุดบกพร่อง


0

ฉันกำลังเขียนเอ็นจิ้นเกมโอเพนซอร์ซชื่อ YoghurtGum สำหรับแพลตฟอร์มมือถือ (Windows Mobile, Android) นี่เป็นหนึ่งในปัญหาใหญ่ของฉัน แรกฉันแก้ไขมันเช่นนี้

class RenderMethod
{

public:

  virtual bool Init();
  virtual bool Tick();
  virtual bool Render();

  virtual void* GetSomeData(); 

}

คุณไม่ได้จุดvoid*? นั่นเป็นเพราะRenderMethodDirectDrawส่งกลับพื้นผิว DirectDraw ในขณะที่RenderMethodDirect3Dส่งกลับจุดยอด ทุกอย่างอื่นก็ถูกแยกออกเช่นกัน ฉันมีSpriteคลาสที่มีทั้งSpriteDirectDrawตัวชี้หรือSpriteDirect3Dตัวชี้ มันดูดไปเลย

เมื่อเร็ว ๆ นี้ฉันได้เขียนสิ่งต่าง ๆ มากมาย สิ่งที่ฉันมีอยู่ในขณะนี้และRenderMethodDirectDraw.dll RenderMethodDirect3D.dllในความเป็นจริงคุณสามารถลองใช้ Direct3D ล้มเหลวและใช้ DirectDraw แทน นั่นเป็นเพราะ API ยังคงเหมือนเดิม

หากคุณต้องการสร้างสไปรต์คุณไม่ต้องทำโดยตรง แต่ผ่านโรงงาน จากนั้นโรงงานจะเรียกใช้ฟังก์ชันที่ถูกต้องใน DLL และแปลงให้เป็นพาเรนต์

ดังนั้นนี่คือในRenderMethodAPI:

virtual Sprite* CreateSprite(const char* a_Name) = 0;

และนี่คือคำจำกัดความในRenderMethodDirectDraw:

Sprite* RenderMethodDirectDraw::CreateSprite(const char* a_Name)
{
    bool found = false;
    uint32 i;
    for (i = 0; i < m_SpriteDataFilled; i++)
    {
        if (!strcmp(m_SpriteData[i].name, a_Name))
        {
            found = true;
            break;
        }
    }

    if (!found) 
    {
        ERROR_EXPLAIN("Could not find sprite named '%s'", a_Name);
        return NULL; 
    }

    if (m_SpriteList[m_SpriteTotal]) { delete m_SpriteList[m_SpriteTotal]; }
    m_SpriteList[m_SpriteTotal] = new SpriteDirectDraw();

    ((SpriteDirectDraw*)m_SpriteList[m_SpriteTotal])->SetData(&m_SpriteData[i]);

    return (m_SpriteList[m_SpriteTotal++]);
}

ฉันหวังว่านี่จะสมเหตุสมผล :)

PS ฉันชอบที่จะใช้ STL สำหรับสิ่งนี้ แต่ไม่มีการสนับสนุนบน Android :(

โดยทั่วไป:

  • เก็บเรนเดอร์ทุกอันไว้ในบริบทของตัวเอง อาจเป็น DLL หรือไลบรารีแบบสแตติกหรือเป็นส่วนหัวก็ได้ ตราบใดที่คุณมี RenderMethodX, SpriteX และ StuffX คุณก็จะได้ทอง
  • ขโมยมากที่สุดเท่าที่จะทำได้จากแหล่งอสูร

แก้ไข: ใช่มันเหมาะสมที่จะมีอินเทอร์เฟซเสมือนเช่นนี้ หากความพยายามครั้งแรกของคุณล้มเหลวคุณสามารถลองวิธีการแสดงผลอื่นได้ วิธีนี้คุณสามารถเก็บวิธีการแสดงผลโค้ดของคุณทั้งหมดไม่เชื่อเรื่องพระเจ้า


1
มันสมเหตุสมผลหรือไม่ที่จะมีอินเทอร์เฟซเสมือนจริงหากคุณไม่เคยมีการใช้งานมากกว่าหนึ่งอย่างในเวลาเดียวกัน?
NocturnDragon

0

ฉันชอบที่จะใช้SDLสำหรับสิ่งนี้ มันมีตัวเรนเดอร์แบ็กเรนต์สำหรับ D3D, OpenGl, OpenGL ES และแบ็กเอนด์เฉพาะแพลตฟอร์มอื่น ๆ จำนวนหนึ่งและสามารถใช้ได้กับแพลตฟอร์มที่หลากหลายทุกประเภทและขณะนี้อยู่ระหว่างการพัฒนาที่ใช้งานอยู่

มันสรุปแนวคิดการแสดงภาพที่แตกต่างกันออกไปและสร้างวิดีโอ (รวมถึงการจัดการเสียงและอินพุตและสิ่งอื่น ๆ ) ที่มีอยู่ใน API ข้ามแพลตฟอร์มที่เรียบง่าย และได้รับการออกแบบโดย Sam Lantinga หนึ่งในนักพัฒนานำของ Blizzard โดยเฉพาะสำหรับการสร้างเกมพอร์ตและสร้างเกมข้ามแพลตฟอร์มได้ง่ายขึ้นดังนั้นคุณรู้ว่าคุณกำลังจัดการกับห้องสมุดคุณภาพสูง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.