Cầu nối bất khả tri API (ví dụ: OpenGL / D3D / Sao cũng được). Bạn có sử dụng chúng, làm thế nào bạn làm cho họ. Pro và Con [đóng]


12

Bạn đang làm một công cụ 3d. Bạn muốn tốt nhất của thế giới đa nền tảng. Đột nhiên bạn nhận ra rằng nếu bạn muốn sử dụng Direct3D trên các máy Windows và OpenGL trên OSX / Linux, bạn sẽ phải hy sinh các tính năng được hỗ trợ của cả hai mẫu số ít phổ biến nhất.

Một số có thể sử dụng OpenGL trên ba hệ điều hành ', vì nó dường như là mẫu số ít phổ biến nhất. Mọi thứ đều tốt. Sau đó, bạn phải chuyển phụ trợ API đồ họa của mình sang GX của Nintendo, bạn cũng phải tạo đường dẫn PS3 và Xbox360.

Bạn làm nghề gì? Bạn có thiết kế API của riêng mình, mẫu số ít phổ biến nhất trong chính nó và viết các triển khai phụ trợ cho nó cho từng nền tảng hay bạn viết cho mỗi nền tảng mà nó là chi nhánh riêng?

Nếu bạn chọn thiết kế API của riêng mình, bạn có sử dụng mô hình cầu nối hoặc voodoo của riêng bạn không? Sự điên rồ dừng lại ở đâu khi bạn nhận ra mọi thứ và cách tiếp cận bồn rửa nhà bếp phải dừng lại và về cơ bản bạn có động cơ riêng cho mỗi nền tảng như một nhánh. Hoặc bạn bám vào mọi thứ và bồn rửa nhà bếp và giữ các chi tiết cụ thể về nền tảng trong các chuyên ngành mô-đun phụ trợ cho từng nền tảng.

Câu trả lời:


9

Tôi không phải là người hâm mộ phương pháp mẫu số ít phổ biến nhất. Nếu bạn làm điều đó, bạn có thể kết thúc với các tính năng bị tê liệt và hiệu suất kém.

Thay vào đó, những gì tôi đã làm trong quá khứ, là cung cấp chức năng cấp cao hơn một chút trong thư viện. Thư viện đó (hầu hết) không biết API và có thể được sử dụng ở bất cứ đâu, nhưng việc triển khai thư viện hoàn toàn khác nhau đối với các nền tảng / phụ trợ đồ họa khác nhau. Vì vậy, ví dụ, thay vì có hàm SetStateX (), bạn có các hàm cao hơn như RenderMesh () hoặc CreateRenderTarget ().

Nó sẽ hoạt động nhiều hơn một lớp thực sự mỏng bất cứ khi nào bạn chuyển sang nền tảng mới, nhưng nó sẽ hoàn toàn xứng đáng vì bạn sẽ có thể triển khai mọi thứ theo cách tối ưu cho nền tảng đó và bạn sẽ có thể thực hiện lợi thế của bản địa, tính năng độc đáo.

Một điều nữa: Đừng sợ phá vỡ sự đóng gói. Không có gì bực bội hơn khi biết bạn đang ở trong một nền tảng với các khả năng nhất định và không thể sử dụng chúng. Để lại một cửa hậu của một số loại mã cấp cao hơn có thể tận dụng lợi thế của nền tảng là rất hữu ích (ví dụ: có thể truy xuất thiết bị D3D hoặc bối cảnh OpenGL).


3
Tôi nghĩ rằng bạn đã nói những gì tôi đã cố gắng để nói, chỉ tốt hơn.
AShelly

6

Tất cả những gì tôi có thể nói là hãy xem Ogre3D . Nó được viết bằng C ++, Nguồn mở (Giấy phép MIT ngay bây giờ) và chạy trên mọi nền tảng chính. Nó trừu tượng hóa api kết xuất và có thể chuyển từ sử dụng DirectX sang OpenGL chỉ với một vài cài đặt. Tuy nhiên, tôi không biết đủ về sự khác biệt giữa các bộ tính năng của DirectX và OpenGL để nói rằng nó có hoặc không hỗ trợ một tính năng cụ thể.

Torchlight by Runic Games được viết bằng Ogre và tôi đã chơi nó trên Mac và PC và nó chạy rất tốt trên cả hai.


2
+1 cho cách tiếp cận của Ogre. Tôi biết về nó, đã đọc qua một số mã. Tôi đã thích thú hơn khi nghe những câu chuyện cá nhân về cách tiếp cận và những gì người khác làm trong tình huống như vậy.
Keyframe

2
Cảm ơn! Chà, tôi sẽ làm điều đó chủ yếu theo cách mà Ogre đã làm. Tôi đã sử dụng phương pháp Giao diện / Nhà máy trong rất nhiều phát triển đa nền tảng và tôi thực sự không chắc mình sẽ làm thế nào nếu không. Tôi sẽ nói rằng bạn hoàn toàn cần phải làm việc trên nhiều nền tảng cùng một lúc. Đừng thử và mã hóa mọi thứ trên Windows và hơn là cố gắng chuyển sang Mac chẳng hạn.
Casey

Đúng! Tôi đã trở nên thực sự mệt mỏi khi phải sử dụng trình bao bọc API chéo của riêng mình và sau đó tôi mới bắt đầu sử dụng Ogre. Không nhìn lại. :)
jacmoe

1

Tôi chưa làm điều này cho đồ họa, nhưng tôi đã tạo ra một bộ công cụ âm thanh đa nền tảng (PC / XBOX / PS2). Chúng tôi đã đi theo con đường tạo API của riêng mình với khả năng mẫu số ít phổ biến nhất cũng như các khả năng dành riêng cho nền tảng tùy chọn. Dưới đây là một số bài học kinh nghiệm:

Chìa khóa là xác định đường dẫn xử lý gói gọn các khả năng cốt lõi của từng nền tảng và cho phép tăng trưởng. Để thực hiện điều này, bạn cần thực sự hiểu API cấp thấp của mỗi nền tảng để bạn có thể xác định các tóm tắt đúng. Đảm bảo chuỗi hoạt động cho nền tảng có khả năng thấp nhất, đồng thời cung cấp quyền truy cập vào các tính năng nâng cao của patform có khả năng nhất. Làm công việc để có được điều này đúng và bạn sẽ tiết kiệm được rất nhiều nỗ lực sau này.

Đối với âm thanh, chuỗi là một cái gì đó như SoundSources -> [Decoders] -> Buffers -> [3D Positioner] ->[Effects] -> Players.

Đối với đồ họa, nó có thể Model -> Shapes -> Positioner -> Texturer -> [Lighting] -> [Particle Effects] -> Renderer. (Đây có lẽ là một bộ hoàn toàn sai, tôi không phải là một người đồ họa).

Viết API giao diện người dùng xử lý các đối tượng cốt lõi của bạn và mặt sau dành riêng cho nền tảng để ánh xạ API tới các khả năng cấp thấp. Cung cấp một nỗ lực tốt nhất cho mỗi khả năng. Chẳng hạn, trên PC và XBOX, việc định vị âm thanh 3D đã được thực hiện bằng cách sử dụng các khả năng HRTF của các chip âm thanh, trong khi đó, PS2 sử dụng một pan đơn giản và mờ dần. Một công cụ đồ họa có thể làm một cái gì đó tương tự với ánh sáng.

Triển khai càng nhiều giao diện càng tốt với mã trung tính nền tảng. Mã để kết hợp một đối tượng hồi âm với một đối tượng âm thanh hoặc một tài sản kết cấu cho một đối tượng hình dạng là hoàn toàn phổ biến, cũng như mã để lặp qua và xử lý các đối tượng hoạt động. Mặt khác, các đối tượng cấp thấp có thể hoàn toàn là nền tảng cụ thể ngoại trừ giao diện chung.

Đảm bảo API hoặc tệp cấu hình cho phép người dùng chỉ định các tùy chọn dành riêng cho nền tảng. Chúng tôi đã cố gắng tránh đẩy mã dành riêng cho nền tảng lên cấp trò chơi bằng cách giữ mã đó trong các tệp cấu hình: Tệp cấu hình của một nền tảng có thể chỉ định "effect: SuperDuperParticleGenerator" trong khi một cái khác nói "effect: SoftGlow"

Chắc chắn phát triển các nền tảng song song. Đảm bảo rằng các giao diện cụ thể của nền tảng được xác định rõ và có thể tự kiểm tra. Điều này ngăn chặn rất nhiều "mức độ nền tảng hay cấp độ API?" vấn đề khi gỡ lỗi.


0

Tôi đang viết một công cụ trò chơi mã nguồn mở có tên YoghurtGum cho các nền tảng di động (Windows Mobile, Android). Đây là một trong những vấn đề lớn của tôi. Đầu tiên tôi giải nó như thế này:

class RenderMethod
{

public:

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

  virtual void* GetSomeData(); 

}

Bạn đã phát hiện ra void*? Đó là bởi vì RenderMethodDirectDrawtrả về một bề mặt DirectDraw trong khi RenderMethodDirect3Dtrả về một đỉnh đỉnh. Mọi thứ khác cũng được chia ra. Tôi có một Spritelớp có SpriteDirectDrawcon trỏ hoặc SpriteDirect3Dcon trỏ. Nó loại mút.

Gần đây, tôi đã viết lại nhiều thứ. Những gì tôi có bây giờ là một RenderMethodDirectDraw.dllvà a RenderMethodDirect3D.dll. Thực tế, bạn có thể thử sử dụng Direct3D, thất bại và sử dụng DirectDraw thay thế. Đó là bởi vì API vẫn giữ nguyên.

Nếu bạn muốn tạo một sprite, bạn không thực hiện trực tiếp mà thông qua một nhà máy. Sau đó, nhà máy gọi hàm chính xác trong DLL và chuyển đổi nó thành cha mẹ.

Vì vậy, đây là trong RenderMethodAPI:

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

Và đây là định nghĩa trong 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++]);
}

Tôi hy vọng điều này có ý nghĩa. :)

Tái bút: Tôi rất thích sử dụng STL cho việc này, nhưng không có hỗ trợ nào trên Android. :

Về cơ bản:

  • Giữ mỗi kết xuất trong bối cảnh riêng của nó. Hoặc là một DLL, hoặc một thư viện tĩnh hoặc chỉ là một loạt các tiêu đề. Miễn là bạn có vàng RenderMethodX, SpriteX và StuffX.
  • Ăn cắp càng nhiều càng tốt từ nguồn Ogre.

EDIT: Vâng, thật có ý nghĩa khi có các giao diện ảo như thế này. Nếu lần thử đầu tiên của bạn thất bại, bạn có thể thử một phương thức kết xuất khác. Bằng cách này, bạn có thể giữ tất cả mã của mình làm cho phương thức bất khả tri.


1
Có thực sự có ý nghĩa khi có một giao diện ảo nếu bạn sẽ không bao giờ có nhiều hơn một triển khai hoạt động cùng một lúc?
NocturnDragon

0

Tôi thích sử dụng SDL cho việc này. Nó có các phụ trợ kết xuất cho D3D, OpenGl, OpenGL ES và một số phụ trợ dành riêng cho nền tảng khác và nó có sẵn cho tất cả các loại nền tảng khác nhau và hiện đang được phát triển tích cực, có liên kết với nhiều ngôn ngữ khác nhau.

Nó trừu tượng hóa các khái niệm trình kết xuất khác nhau và giúp tạo video (cũng như xử lý âm thanh và đầu vào và một vài thứ khác) có sẵn trong API đa nền tảng đơn giản. Và nó được thiết kế bởi Sam Lantinga, một trong những nhà phát triển hàng đầu tại Blizzard, đặc biệt để làm cho các trò chơi porting và tạo các trò chơi đa nền tảng dễ dàng hơn, vì vậy bạn biết rằng bạn đang làm việc với một thư viện chất lượng cao.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.