API 불가지론 적 브리지 (예 : OpenGL / D3D / 무엇이든). 그것들을 어떻게 사용합니까? 찬반 양론 [폐쇄]


12

3D 엔진을 만들고 있습니다. 최고의 멀티 플랫폼 세계를 원합니다. 갑자기 Windows 시스템에서 Direct3D를 사용하고 OSX / Linux에서 OpenGL을 사용하려면 최소 공통 분모 모두에서 지원되는 기능을 희생해야합니다.

일부는 자체적으로 가장 일반적인 분모가 아닌 것처럼 3 개의 OS에서 OpenGL을 사용할 수 있습니다. 모두 좋은. 그런 다음 그래픽 API 백엔드를 Nintendo의 GX로 이식해야하며 PS3 및 Xbox360 경로도 만들어야합니다.

너 뭐하니? 최소 공통 분모 인 자체 API를 설계하고 각 플랫폼에 대해 백엔드 구현을 작성하거나 자체 플랫폼 인 각 플랫폼에 대해 작성합니까?

자신의 API를 디자인하기로 선택한 경우 브리지 패턴 또는 자신의 부두를 사용합니까? 모든 것을 깨닫는 곳에서 광기가 멈추는 곳과 부엌 싱크대 접근 방식이 멈추어야하며 기본적으로 각 플랫폼마다 별도의 엔진이 지점으로 있습니다. 또는 모든 플랫폼과 주방 싱크대를 고수하고 각 플랫폼에 대한 백엔드 모듈 전문화에서 플랫폼 별 정보를 유지하십시오.

답변:


9

나는 가장 일반적인 분모 접근법의 팬이 아닙니다. 그렇게하면 기능이 손상되고 성능이 저하 될 수 있습니다.

대신, 내가 과거에 한 일은 라이브러리에서 약간 더 높은 수준의 기능을 제공하는 것입니다. 이 라이브러리는 (대부분) API에 구애받지 않고 어디서나 사용할 수 있지만 라이브러리 구현은 플랫폼 / 그래픽 백엔드마다 완전히 다릅니다. 예를 들어, SetStateX () 함수 대신 RenderMesh () 또는 CreateRenderTarget ()과 같은 더 높은 함수가 있습니다.

새 플랫폼으로 옮길 때마다 실제로는 얇은 계층보다 더 많은 작업이 필요하지만 해당 플랫폼에 최적의 방식으로 구현할 수 있기 때문에 완전히 가치가 있습니다. 고유하고 고유 한 기능의 이점.

한 가지 더 : 캡슐화가 약간 깨지는 것을 두려워하지 마십시오. 특정 기능을 갖춘 플랫폼에 있고 해당 기능을 사용할 수 없다는 것을 알고 더 이상 실망하지 않습니다. 높은 수준의 코드가 플랫폼을 활용할 수 있도록 일종의 백도어를 남겨 두는 것은 매우 유용합니다 (예를 들어, D3D 장치 또는 OpenGL 컨텍스트를 검색 할 수 있음).


3
나는 당신이 내가 말하려는 것을 말한 것으로 생각합니다.
AShelly

6

내가 말할 수있는 것은 Ogre3D를 살펴 보는 입니다. C ++, 오픈 소스 (지금은 MIT 라이센스)로 작성되었으며 모든 주요 플랫폼에서 즉시 실행됩니다. 렌더링 API를 추상화하고 몇 가지 설정만으로 DirectX 사용에서 OpenGL로 전환 할 수 있습니다. 그러나 DirectX와 OpenGL의 기능 세트의 차이점이 특정 기능을 지원하거나 지원하지 않는다는 차이점을 충분히 알지 못합니다.

Runic Games의 Torchlight 는 Ogre를 사용하여 작성되었으며 Mac 및 PC에서 재생했으며 두 가지 모두에서 잘 작동합니다.


2
오우거 접근시 +1 나는 그것에 대해 알고 코드 일부를 읽었습니다. 나는 접근 방식에 대한 개인적인 이야기와 그와 같은 상황에서 다른 사람들이하는 일에 더 관심이있었습니다.
키 프레임

2
감사! 글쎄, 나는 대부분 오우거처럼 그것을 할 것입니다. 많은 크로스 플랫폼 개발에서 Interface / Factory 접근 방식을 사용했으며 실제로 어떻게 다른 방법을 사용할지 잘 모르겠습니다. 그래도 동시에 여러 플랫폼에서 작업해야한다고 말하고 싶습니다. Windows에서 모든 것을 시도하고 코딩하지 말고 예를 들어 Mac으로 포팅하려고 시도하십시오.
Casey

예! 나는 자신의 크로스 API 래퍼를 굴리는 것에 정말로 지 쳤고, 방금 오우거를 사용하기 시작했습니다. 돌아 보지 않았습니다. :)
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를 저수준 기능에 매핑하는 플랫폼 별 백엔드를 작성하십시오. 각 기능마다 최선의 노력을 다하십시오. 예를 들어 PC와 XBOX에서 3D 오디오 포지셔닝은 사운드 칩의 HRTF 기능을 사용하여 수행되었으며 PS2는 간단한 팬과 페이드를 사용했습니다. 그래픽 엔진은 조명과 비슷한 작업을 수행 할 수 있습니다.

플랫폼 중립 코드를 사용하여 프런트 엔드를 최대한 구현하십시오. 리버브 객체를 사운드 객체로, 텍스처 자산을 모양 객체로 연결하는 코드는 활성 객체를 반복 처리하는 코드와 마찬가지로 완전히 공통적이어야합니다. 반면에 저수준 객체는 공통 인터페이스를 제외하고 플랫폼에 따라 완전히 다를 수 있습니다.

사용자가 API 또는 구성 파일을 사용하여 플랫폼 별 옵션을 지정할 수 있는지 확인하십시오. 우리는 구성 파일에 플랫폼 별 코드를 게임 레벨로 푸시하지 않기 위해 노력했습니다. 한 플랫폼의 구성 파일은 "effect : SuperDuperParticleGenerator"를 지정할 수 있지만 다른 플랫폼은 "effect : SoftGlow"라고 말합니다.

플랫폼을 동시에 개발하십시오. 플랫폼 별 인터페이스가 자체적으로 잘 정의되고 테스트 가능한지 확인하십시오. 이렇게하면 "플랫폼 수준입니까 아니면 API 수준입니까?" 디버깅시 문제.


0

모바일 플랫폼 (Windows Mobile, Android) 용 YoghurtGum이라는 오픈 소스 게임 엔진을 작성 중입니다. 이것은 내 큰 문제 중 하나였습니다. 먼저 다음과 같이 해결했습니다.

class RenderMethod
{

public:

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

  virtual void* GetSomeData(); 

}

당신은 발견 했습니까 void*? RenderMethodDirectDrawDirectDraw 표면을 RenderMethodDirect3D반환하고 정점 풀 을 반환 하기 때문 입니다. 다른 모든 것들도 분리되었습니다. 포인터 또는 포인터 가있는 Sprite클래스가 있습니다 . 그것은 빨려 들었다.SpriteDirectDrawSpriteDirect3D

그래서 최근에 많은 것을 다시 쓰고 있습니다. 내가 지금 가지고있는 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++]);
}

이것이 의미가 있기를 바랍니다. :)

추신 : 나는 이것을 위해 STL을 사용하고 싶었지만 Android에서는 지원하지 않습니다. :(

원래:

  • 모든 렌더링을 자체 컨텍스트로 유지하십시오. DLL 또는 정적 라이브러리 또는 여러 헤더입니다. RenderMethodX, SpriteX 및 StuffX가 있으면 황금색입니다.
  • 오우거 소스에서 최대한 많이 훔치십시오.

편집 : 예. 이와 같은 가상 인터페이스를 갖는 것이 합리적입니다. 첫 번째 시도가 실패하면 다른 렌더링 방법을 시도 할 수 있습니다. 이런 식으로 모든 코드 렌더 메소드를 무시할 수 있습니다.


1
동시에 둘 이상의 구현을 활성화하지 않을 경우 가상 인터페이스를 사용하는 것이 합리적입니까?
NocturnDragon

0

나는 이것을 위해 SDL 을 사용하고 싶다 . D3D, OpenGl, OpenGL ES 및 소수의 다른 플랫폼 별 백엔드에 대한 렌더러 백엔드를 보유하고 있으며 다양한 플랫폼에 사용할 수 있으며 현재 개발중인 많은 언어에 바인딩하여 현재 개발 중입니다.

다른 렌더러 개념을 추상화하고 간단한 크로스 플랫폼 API에서 비디오 제작 (사운드 및 입력 처리 및 기타 몇 가지 처리)을 사용할 수 있습니다. 블리자드의 수석 개발자 중 한 명인 Sam Lantinga가 특별히 포팅 게임을 만들고 플랫폼 간 게임을 더 쉽게 만들 수 있도록 설계되었으므로 고품질 라이브러리를 다루고 있다는 것을 알 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.