2010-09-12 10 views
5

Tôi đã đọc về cách tạo đồ họa "lớp trừu tượng" để làm cho nó thuận tiện để chuyển đổi giữa các nền tảng đồ họa. Thật không may, tôi đã không thể tìm thấy nhiều chi tiết về chủ đề này. Sự trừu tượng này có thể đạt được ở cấp chức năng với một cái gì đó như thế này không?Cách thiết kế OpenGL DirectX "Abstraction Layer"

void pushMatrix(){ 
    if (directx){ 
    // do directx function 

    }else if (opengl){ 
    // do opengl function 
    } 

} 

Đây có phải là cách hoạt động không? Có cách nào tốt hơn? Bất cứ ai có thể chỉ cho tôi một số ví dụ về những điều mà làm điều này hoặc mã ví dụ hơn?

+2

Có thể ví dụ tốt nhất về điều này là OGRE. Nó sử dụng các mô-đun để trừu tượng DirectX và OpenGL thành một dạng nội bộ thống nhất. Có rất nhiều mã, nhưng nó hoạt động khá tốt, vì vậy bạn có thể muốn kiểm tra nó. – ssube

+0

Tôi sẽ cảm ơn thông tin. –

Trả lời

7

gì thường được thực hiện là phải có một giao diện cho một "chung chung" renderer:

class RendererInterface{ 
    virtual DrawMesh() = 0; 
    virtual SwapBuffers() = 0; 
    /// etc 
} 

với một thực hiện cho mỗi lib:

class OpenGLRenderer : public RendererInterface{ 
    virtual DrawMesh(){... } 
    .... 
} 

Nhưng khái niệm này là giống như câu trả lời của Alexander .

3

Điều đó sẽ kết thúc lộn xộn và không hiệu quả. Tôi sẽ trừu tượng qua biểu đồ cảnh, tức là có một đại diện cấp cao tổng quát về "cảnh". Cảnh này sau đó sẽ được hiển thị bởi một thể hiện "renderer", có thể được thực hiện bằng cách sử dụng OpenGL hoặc Direct3D.

Tôi đề nghị bạn hãy xem một công cụ đồ họa đa nền tảng như Ogre3d.

+0

Hmm có vẻ khá kém hiệu quả khi thấy tôi sẽ phải viết lại hầu hết các lớp học của mình nhưng tôi hiểu ý bạn là gì khi có các lớp/lớp mức cao hơn. –

+1

Vấn đề với phương pháp của bạn là bạn sẽ thêm một tấn các nhánh không cần thiết và phân tán các cài đặt khác nhau trên toàn bộ mã của bạn. Nó trở nên tồi tệ hơn nếu bạn phải viết cho hơn 2 API - xem xét Direct3D 9, Direct3D 10/11, OpenGL 2.x, OpenGL 3/4, OpenGL ES 1, OpenGL ES 2, Playstation, Wii, vv. logic dựng hình thành các phần riêng biệt, nó trở nên dễ bảo trì hơn nhiều. –

+1

Bạn cũng có thể sử dụng thừa kế để chia sẻ logic giữa các trình kết xuất đồ họa tương tự, ví dụ: Trình kết xuất được phân lớp bởi Direct3DRenderer và OpenGLRenderer, OpenGLRenderer được phân lớp bởi OpenGLES2Renderer, v.v. –

4

Vâng, đó là cách hoạt động của nó. Bằng cách trừu tượng hóa API đồ họa bạn sử dụng, bạn sẽ loại bỏ nó khỏi những gì mà lập trình viên cần phải lo lắng. Điều này tương tự như cách GDI tóm tắt thiết bị được ghi vào, chẳng hạn như lập trình viên không cần lo lắng về nó.

Theo nghĩa này, thư viện chức năng của bạn tương tự như thư viện ở trên sẽ giống như HDC. Nó là giao diện của sự trừu tượng này.

Sẽ khó khăn hơn khi kiểm tra API đơn giản, sau đó gọi (các) chức năng thích hợp. Hai API (DirectX và OpenGL) là rất khác nhau, và abstracting chúng cả hai thành một giao diện duy nhất sẽ không dễ dàng, đặc biệt là nếu bạn muốn bao gồm hầu hết các chức năng.

Bạn sẽ cần trừu tượng hơn sau đó chỉ cần thực hiện các chức năng phổ quát. Bạn sẽ cần phải tạo ra các cấu trúc phức tạp hơn. Giả sử giả thuyết rằng OpenGL yêu cầu bạn gọi hàm A, sau đó hàm B để thực hiện điều gì đó, nhưng DX yêu cầu bạn gọi func B, sau đó func A. Để chứa điều này, bạn sẽ cần phải làm một cái gì đó tương tự như sau:

void functionA(...) { 
    if (OpenGL) { 
    glFuncA(); 
    } else { 
    //store parameters 
    } 
} 

void functionB(...) { 
    if (OpenGL) { 
    glFuncB(); 
    } else { 
    dxFuncB(); 
    dxFuncA(saved params); 
    } 
} 

Nó không phải là một ví dụ rất tốt, nhưng nó thể hiện hiệu trưởng. Tạo một trừu tượng cho các API rất lớn và khác nhau sẽ đòi hỏi nhiều suy nghĩ, và nỗ lực nhiều hơn nữa sau đó gói mỗi chức năng.

+0

Còn những thứ như OpenGL cho OpenGL ES 2.0 thì sao? –

+0

@Justin: OpenGL cho OpenGL ES là một thay đổi nhỏ hơn nhiều. DirectX và OpenGL về cơ bản là khác nhau, OpenGL và OpenGL ES rất giống nhau (so sánh). Điều đó có thể xảy ra chỉ với các khối 'if else'. – ssube

+0

@peachykeen Ok cảm ơn bạn đó là những gì tôi đã lên kế hoạch để làm. –

1

Tôi đồng ý với mhutch 100%. Bằng cách tái cơ cấu trình kết xuất của bạn để tập trung vào những gì nó đang làm, thay vì trên CÁCH để làm điều đó, bạn sẽ làm cho một thiết kế sạch hơn nhiều.

Thiết kế xung quanh một API quá chặt chẽ, hoặc tệ hơn, xả rác mã của bạn với if (this_platform) { do_this(); } else { do_that(); } sẽ nhanh chóng tạo ra một mớ hỗn độn lớn của chương trình.

Lời khuyên của tôi là đi qua ứng dụng của bạn và tìm ra một danh sách những gì nó làm, cố gắng không chú ý nhiều đến CÁCH.Nó có thể là muộn trong dự án của bạn để làm điều này, tôi không biết kịch bản cụ thể của bạn, nhưng (IMHO) refactoring nó từ một cuộc gọi API gọi là cơn ác mộng rải rác đến một cái gì đó abstracts nó chỉ đủ sẽ cải thiện kết quả cuối cùng của bạn.

Mặc dù lúc đầu suy nghĩ, bạn có thể nghĩ rằng việc triển khai hệ thống đồ thị cảnh sẽ thêm một loạt chi phí. Trong thực tế, tôi đã tăng tốc với công cụ dựng hình bằng cách sử dụng biểu đồ cảnh để quản lý các thay đổi trạng thái - bằng cách tránh thay đổi trạng thái (thay đổi họa tiết, thay đổi bóng đổ, vv) và vẽ cảnh theo thứ tự tối ưu hơn nhiều. Những thứ như instancing được tích hợp một cách tao nhã vào một hệ thống đồ thị cảnh và có thể cung cấp cho bạn các tăng tốc lớn cũng như dọn dẹp tất cả các mớ hỗn độn của API ra khỏi mã của bạn và tách "những gì nó làm" từ "nó như thế nào" logic chương trình.