Duo OGRE 3DおよびSDL

最近、OGREエンジンに関連する記事が含まれます。 簡単なプログラムの作成に関する投稿があるので、延期せずにこの記事を書くことにしました。 少し前 、SDLライブラリの表面的な概要を少し書いたことがありますが、ここでは続きとして、このライブラリの具体的な使用例、つまりエンジンで動作させる方法を説明します。



イントロ



まず、質問に答えます-なぜですか? OGRE自体は、ほとんどの一般的なプラットフォームで動作し、視覚化、およびユーザー入力の処理のためのウィンドウを作成できます。これは、オフィスでの多くのレッスンです。 エンジンサイトでは、OISライブラリの使用を推奨しています。 これは確かにそうであり、以前はLinuxで記述しなければならなくなるまで、このライブラリとともにエンジンを使用していました。 その後、不快な瞬間が生じました。 OGREウィンドウは、私が理解していなかった理由により、ドラッグアンドドロップへの応答を拒否することが多く、しばしば画像がちらつきました(CompizまたはEmeraldとの競合の疑いがありました)。 OISを使用した入力は適切な速度を誇ることができず、マウスを数秒間使用した後、プログラムはできるだけ早く閉じたいと考えていました。 次に、OISの代替としてSDLを試すことにしました。 ライブラリは、割り当てられた責任に非常にうまく対処しました。ウィンドウを作成し、入力を処理しながら、適切な速度を示しました。



プログラムの枠組み



そのため、 OGRE SDKSDL SDKが必要です。 それらをインストールするプロセスについては説明しません。これはシステムによって異なるため、このトピックに関する多くの簡単なレッスンがあります。 すぐにポイントを取得しましょう。 最初のタスクは、SDLがウィンドウの作成と入力の処理に関与するプログラムコードを記述することです。OGREは、外部のウィンドウにのみレンダリングします。 少なくともWindowsとLinux間でコードを移植できるようにします。



SDLを初期化し、それを使用してウィンドウを作成することから始めましょう。

#include <Ogre.h> #include <SDL.h> #ifdef _WINDOWS #include <SDL_syswm.h> #endif ... // SDL SDL_Init(SDL_INIT_VIDEO); // SDL_putenv(( char *) "SDL_VIDEO_CENTERED=true" ); // 800x600@16 OpenGL SDL_SetVideoMode(800, 600, 16, SDL_OPENGL); // SDL_WM_SetCaption( "Demo window" , NULL); * This source code was highlighted with Source Code Highlighter .



  1. #include <Ogre.h> #include <SDL.h> #ifdef _WINDOWS #include <SDL_syswm.h> #endif ... // SDL SDL_Init(SDL_INIT_VIDEO); // SDL_putenv(( char *) "SDL_VIDEO_CENTERED=true" ); // 800x600@16 OpenGL SDL_SetVideoMode(800, 600, 16, SDL_OPENGL); // SDL_WM_SetCaption( "Demo window" , NULL); * This source code was highlighted with Source Code Highlighter .



  2. #include <Ogre.h> #include <SDL.h> #ifdef _WINDOWS #include <SDL_syswm.h> #endif ... // SDL SDL_Init(SDL_INIT_VIDEO); // SDL_putenv(( char *) "SDL_VIDEO_CENTERED=true" ); // 800x600@16 OpenGL SDL_SetVideoMode(800, 600, 16, SDL_OPENGL); // SDL_WM_SetCaption( "Demo window" , NULL); * This source code was highlighted with Source Code Highlighter .



  3. #include <Ogre.h> #include <SDL.h> #ifdef _WINDOWS #include <SDL_syswm.h> #endif ... // SDL SDL_Init(SDL_INIT_VIDEO); // SDL_putenv(( char *) "SDL_VIDEO_CENTERED=true" ); // 800x600@16 OpenGL SDL_SetVideoMode(800, 600, 16, SDL_OPENGL); // SDL_WM_SetCaption( "Demo window" , NULL); * This source code was highlighted with Source Code Highlighter .



  4. #include <Ogre.h> #include <SDL.h> #ifdef _WINDOWS #include <SDL_syswm.h> #endif ... // SDL SDL_Init(SDL_INIT_VIDEO); // SDL_putenv(( char *) "SDL_VIDEO_CENTERED=true" ); // 800x600@16 OpenGL SDL_SetVideoMode(800, 600, 16, SDL_OPENGL); // SDL_WM_SetCaption( "Demo window" , NULL); * This source code was highlighted with Source Code Highlighter .



  5. #include <Ogre.h> #include <SDL.h> #ifdef _WINDOWS #include <SDL_syswm.h> #endif ... // SDL SDL_Init(SDL_INIT_VIDEO); // SDL_putenv(( char *) "SDL_VIDEO_CENTERED=true" ); // 800x600@16 OpenGL SDL_SetVideoMode(800, 600, 16, SDL_OPENGL); // SDL_WM_SetCaption( "Demo window" , NULL); * This source code was highlighted with Source Code Highlighter .



  6. #include <Ogre.h> #include <SDL.h> #ifdef _WINDOWS #include <SDL_syswm.h> #endif ... // SDL SDL_Init(SDL_INIT_VIDEO); // SDL_putenv(( char *) "SDL_VIDEO_CENTERED=true" ); // 800x600@16 OpenGL SDL_SetVideoMode(800, 600, 16, SDL_OPENGL); // SDL_WM_SetCaption( "Demo window" , NULL); * This source code was highlighted with Source Code Highlighter .



  7. #include <Ogre.h> #include <SDL.h> #ifdef _WINDOWS #include <SDL_syswm.h> #endif ... // SDL SDL_Init(SDL_INIT_VIDEO); // SDL_putenv(( char *) "SDL_VIDEO_CENTERED=true" ); // 800x600@16 OpenGL SDL_SetVideoMode(800, 600, 16, SDL_OPENGL); // SDL_WM_SetCaption( "Demo window" , NULL); * This source code was highlighted with Source Code Highlighter .



  8. #include <Ogre.h> #include <SDL.h> #ifdef _WINDOWS #include <SDL_syswm.h> #endif ... // SDL SDL_Init(SDL_INIT_VIDEO); // SDL_putenv(( char *) "SDL_VIDEO_CENTERED=true" ); // 800x600@16 OpenGL SDL_SetVideoMode(800, 600, 16, SDL_OPENGL); // SDL_WM_SetCaption( "Demo window" , NULL); * This source code was highlighted with Source Code Highlighter .



  9. #include <Ogre.h> #include <SDL.h> #ifdef _WINDOWS #include <SDL_syswm.h> #endif ... // SDL SDL_Init(SDL_INIT_VIDEO); // SDL_putenv(( char *) "SDL_VIDEO_CENTERED=true" ); // 800x600@16 OpenGL SDL_SetVideoMode(800, 600, 16, SDL_OPENGL); // SDL_WM_SetCaption( "Demo window" , NULL); * This source code was highlighted with Source Code Highlighter .



  10. #include <Ogre.h> #include <SDL.h> #ifdef _WINDOWS #include <SDL_syswm.h> #endif ... // SDL SDL_Init(SDL_INIT_VIDEO); // SDL_putenv(( char *) "SDL_VIDEO_CENTERED=true" ); // 800x600@16 OpenGL SDL_SetVideoMode(800, 600, 16, SDL_OPENGL); // SDL_WM_SetCaption( "Demo window" , NULL); * This source code was highlighted with Source Code Highlighter .



  11. #include <Ogre.h> #include <SDL.h> #ifdef _WINDOWS #include <SDL_syswm.h> #endif ... // SDL SDL_Init(SDL_INIT_VIDEO); // SDL_putenv(( char *) "SDL_VIDEO_CENTERED=true" ); // 800x600@16 OpenGL SDL_SetVideoMode(800, 600, 16, SDL_OPENGL); // SDL_WM_SetCaption( "Demo window" , NULL); * This source code was highlighted with Source Code Highlighter .



  12. #include <Ogre.h> #include <SDL.h> #ifdef _WINDOWS #include <SDL_syswm.h> #endif ... // SDL SDL_Init(SDL_INIT_VIDEO); // SDL_putenv(( char *) "SDL_VIDEO_CENTERED=true" ); // 800x600@16 OpenGL SDL_SetVideoMode(800, 600, 16, SDL_OPENGL); // SDL_WM_SetCaption( "Demo window" , NULL); * This source code was highlighted with Source Code Highlighter .



  13. #include <Ogre.h> #include <SDL.h> #ifdef _WINDOWS #include <SDL_syswm.h> #endif ... // SDL SDL_Init(SDL_INIT_VIDEO); // SDL_putenv(( char *) "SDL_VIDEO_CENTERED=true" ); // 800x600@16 OpenGL SDL_SetVideoMode(800, 600, 16, SDL_OPENGL); // SDL_WM_SetCaption( "Demo window" , NULL); * This source code was highlighted with Source Code Highlighter .



  14. #include <Ogre.h> #include <SDL.h> #ifdef _WINDOWS #include <SDL_syswm.h> #endif ... // SDL SDL_Init(SDL_INIT_VIDEO); // SDL_putenv(( char *) "SDL_VIDEO_CENTERED=true" ); // 800x600@16 OpenGL SDL_SetVideoMode(800, 600, 16, SDL_OPENGL); // SDL_WM_SetCaption( "Demo window" , NULL); * This source code was highlighted with Source Code Highlighter .



#include <Ogre.h> #include <SDL.h> #ifdef _WINDOWS #include <SDL_syswm.h> #endif ... // SDL SDL_Init(SDL_INIT_VIDEO); // SDL_putenv(( char *) "SDL_VIDEO_CENTERED=true" ); // 800x600@16 OpenGL SDL_SetVideoMode(800, 600, 16, SDL_OPENGL); // SDL_WM_SetCaption( "Demo window" , NULL); * This source code was highlighted with Source Code Highlighter .





次に、OGREを構成し、ビジュアライザーをインストールする必要があります。 プログラムのこの部分をどのようにコーディングするかは、すべての人にとって純粋に個人的な好みです。 ここでは、最も必要なプラグインのみを手動でダウンロードし、必要なパラメーターを設定する権利を確保しました。 主なことは、OGREを使用してウィンドウを作成しないことです。





  1. //ルートオブジェクトを作成してOGREの初期化を開始します
  2. Ogre :: Root * root = new Ogre :: Root();
  3. //現在のフォルダー(または別の場所)からOpenGLビジュアライザープラグインをダウンロードします
  4. #ifdef _WINDOWS
  5. root-> loadPlugin( "./RenderSystem_GL.dll" );
  6. #else
  7. root-> loadPlugin( "./RenderSystem_GL.so" );
  8. #endif
  9. //ビジュアライザー自体を作成します
  10. Ogre :: RenderSystem * rs = root-> getRenderSystemByName( "OpenGL Rendering Subsystem" );
  11. // ...最新のものにする
  12. root-> setRenderSystem(rs);
  13. // ...そしてビデオモードを設定します
  14. rs-> setConfigOption( "Full Screen""no" );
  15. rs-> setConfigOption( "ビデオモード""800 x 600 16ビットカラー" );
  16. // OGREを初期化しますが、ウィンドウを自動的に作成しません
  17. root->初期化( false );
*このソースコードは、 ソースコードハイライターで強調表示されました。


最も興味深いのは、OpenGLコンテキストがすでに受信されていることをOGREに伝えることであり、それにレンダリングする必要があります。





  1. // OGREウィンドウを作成するためのパラメーターを設定します。
  2. //実際、ウィンドウは作成されません。 OGREにどこに伝えるのか
  3. //レンダリングします
  4. Ogre :: NameValuePairList params ;
  5. #ifdef _WINDOWS
  6. SDL_SysWMinfo情報;
  7. SDL_VERSION(&info.version);
  8. SDL_GetWMInfo(&info);
  9. params [ "externalWindowHandle" ] = Ogre :: StringConverter :: toString(reinterpret_cast <size_t>(info.window));
  10. params [ "externalGLContent" ] = Ogre :: StringConverter :: toString(reinterpret_cast <size_t>(info.hglrc));
  11. params [ "externalGLControl" ] = Ogre :: String"True" );
  12. #else
  13. // Linuxでは少し簡単に
  14. params [ "currentGLContext" ] = Ogre :: String"True" );
  15. #endif
  16. //選択したオプションで「仮想」ウィンドウを作成します
  17. Ogre :: RenderWindow * wnd = root-> createRenderWindow( "メインウィンドウ" 、800、600、 false 、& params );
  18. wnd-> setVisible( true );
*このソースコードは、 ソースコードハイライターで強調表示されました。


初期化を終了して、作業部分に移動します。





  1. //ここで、処理のために次のイベントを追加します
  2. SDL_Event evt;
  3. //はい、ループを継続する必要があります
  4. bool running = true ;
  5. //メインレンダリングサイクル
  6. while (running)
  7. {
  8. //前のフレームの時間から受信したシステムイベントと入力イベントを読み取ります
  9. while (SDL_PollEvent(&evt))
  10. {
  11. //ユーザーがウィンドウを閉じた場合、ループを終了します
  12. if (evt.type == SDL_QUIT)
  13. running = false ;
  14. }
  15. //フレームを1つ描画します
  16. root-> renderOneFrame();
  17. //何らかの理由で、SDL_GL_SwapBuffers()を呼び出す必要があります; Windowsでのみ利用可能です。
  18. // Linuxでは、これがなくても正常に動作し、使用するとバグが発生します。
  19. #ifdef _WINDOWS
  20. SDL_GL_SwapBuffers();
  21. #endif
  22. }
*このソースコードは、 ソースコードハイライターで強調表示されました。


プログラムの最後で、削除することを忘れないでください:





  1. //メインOGREオブジェクトを削除して、エンジンで使用されているすべてのリソースを解放します
  2. ルートを削除します。
  3. // SDLを閉じます
  4. SDL_Quit();
*このソースコードは、 ソースコードハイライターで強調表示されました。


コードは非常に短いことが判明し、コメントはスペースの半分を占めています。 プログラムをコンパイルして開始すると、理解できない内容のウィンドウが表示されます。

画像

この段階では、OGREがレンダリングできるビューポートまたはカメラは1つも作成されていないため、これは期待される結果です。 したがって、ウィンドウに表示されるものはすべて、ビデオメモリ内の任意のデータです。



入力マネージャー



ここで、イベントをキャッチしてリスナーに送信するための小さな便利なシステムを作成するとよいでしょう。 最初に、リスナーインターフェイスについて説明します。





  1. // Input.h
  2. #include <list>
  3. #include <SDL.h>
  4. ///キーボードイベントリスナーインターフェース
  5. クラス KeyboardListener
  6. {
  7. 公開
  8. virtual〜KeyboardListener(){}
  9. 仮想 void onKeyboardEvent( const SDL_KeyboardEvent&evt)= 0;
  10. };
  11. ///マウスイベントリスナーインターフェース
  12. クラス MouseListener
  13. {
  14. 公開
  15. virtual〜MouseListener(){}
  16. 仮想 ボイド onMouseMotion( const SDL_MouseMotionEvent&evt)= 0;
  17. 仮想 void onMouseBtn( const SDL_MouseButtonEvent&evt)= 0;
  18. };
  19. ///他のすべてのタイプのイベントのリスナーのインターフェース
  20. クラス EventListener
  21. {
  22. 公開
  23. 仮想 〜EventListener(){}
  24. 仮想 void onEvent( const SDL_Event&evt)= 0;
  25. };
*このソースコードは、 ソースコードハイライターで強調表示されました。


リスナーインターフェイスを定義したら、入力マネージャークラス自体を記述できます。





  1. クラス InputManager
  2. {
  3. プライベート
  4. typedef std :: list <KeyboardListener *> KeyboardListenersList;
  5. typedef std :: list <MouseListener *> MouseListenersList;
  6. typedef std :: list <EventListener *> OtherEventsListenersList;
  7. プライベート
  8. KeyboardListenersList kb_listeners;
  9. MouseListenersList mouse_listeners;
  10. OtherEventsListenersList other_listeners;
  11. 公開
  12. InputManager(){}
  13. 〜InputManager(){}
  14. ///イベントをキャプチャして処理します
  15. ボイドキャプチャ();
  16. ///キーボードイベントリスナーを登録します
  17. void regKeyboardListener(KeyboardListener * l);
  18. ///キーボードイベントリスナーの登録を解除します
  19. void unregKeyboardListener(KeyboardListener * l);
  20. ///マウスイベントリスナーを登録します
  21. void regMouseListener(MouseListener * l);
  22. ///マウスイベントリスナーの登録を解除します
  23. void unregMouseListener(MouseListener * l);
  24. ///一般的なタイプのイベントのリスナーを登録します
  25. void regEventListener(EventListener * l);
  26. ///イベントタイプリスナーの登録を解除します
  27. void unregEventListener(EventListener * l);
  28. };
*このソースコードは、 ソースコードハイライターで強調表示されました。


それでは、クラスの実装に移りましょう。 主な関心事はcapture()メソッドです:





  1. SDL_Event evt;
  2. while (SDL_PollEvent(&evt))
  3. {
  4. スイッチ (evt.type)
  5. {
  6. //キーボードイベント
  7. ケース SDL_KEYUP: ケース SDL_KEYDOWN:
  8. {
  9. KeyboardListenersList :: const_iterator kb_it = kb_listeners.begin()、kb_end = kb_listeners.end();
  10. for (; kb_it!= kb_end; ++ kb_it)
  11. (* kb_it)-> onKeyboardEvent(evt.key);
  12. 休憩 ;
  13. }
  14. //マウスイベント
  15. ケース SDL_MOUSEBUTTONDOWN: ケース SDL_MOUSEBUTTONUP: ケース SDL_MOUSEMOTION:
  16. {
  17. MouseListenersList :: const_iterator m_it = mouse_listeners.begin()、m_end = mouse_listeners.end();
  18. for (; m_it!= m_end; ++ m_it)
  19. {
  20. if (evt.type == SDL_MOUSEBUTTONDOWN || evt.type == SDL_MOUSEBUTTONUP)
  21. (* m_it)-> onMouseBtn(evt.button);
  22. if (evt.type == SDL_MOUSEMOTION)
  23. (* m_it)-> onMouseMotion(evt.motion);
  24. }
  25. 休憩 ;
  26. }
  27. //他のすべてのイベント
  28. デフォルト
  29. OtherEventsListenersList :: const_iterator other_it = other_listeners.begin()、other_end = other_listeners.end();
  30. for (; other_it!= other_end; ++ other_it)
  31. (* other_it)-> onEvent(evt);
  32. }
  33. }
*このソースコードは、 ソースコードハイライターで強調表示されました。


このメソッドは、キューからイベントを抽出し、適切なリスナーに送信します。 このコードは、さまざまな特定のタイプのイベントをリッスンするように簡単に調整できます。 実際、非常に多くの非常に特殊なリスナーを作成できます。この場合、マウスとキーボードのリスナーの例を示しました。

学生を登録する方法を実装するための残りはほとんどありません。 ここではすべてが単純なので、キーボードリスナーの登録メソッドにのみ実装コードを提供し、残りは類推によって実装されます。





  1. void InputManager :: regKeyboardListener(KeyboardListener * l)
  2. {
  3. if (l && std :: find(kb_listeners.begin()、kb_listeners.end()、l)== kb_listeners.end())
  4. kb_listeners.push_back(l);
  5. }
  6. void InputManager :: unregKeyboardListener(KeyboardListener * l)
  7. {
  8. if (l)
  9. kb_listeners.remove(l);
  10. }
*このソースコードは、 ソースコードハイライターで強調表示されました。


現在、完璧な入力マネージャーはありませんが、完璧ではありませんが、さらなる改善の点で想像力の余地があります。 入力マネージャーを使用して、メインプログラムループを書き換えることができます。





  1. InputManager * imgr = new InputManager();
  2. while (!stop)
  3. {
  4. imgr-> capture();
  5. root-> renderOneFrame();
  6. ...
  7. }
  8. imgrを削除します。
*このソースコードは、 ソースコードハイライターで強調表示されました。


イベントを処理するには、対応するインターフェースを実装するクラスを作成する必要があります。 少なくとも、プログラムを正しく終了するには、SDL_QUITイベントをキャッチする価値があります。



最後に



私は、SDLの使用を必要とは考えていませんが、それでも、ライブラリは非常に快適に使用できます。 APIは完全にCで記述されていますが、オブジェクト指向のOISインターフェースよりも使い勝手は劣っていません。 OGREにリンクしても、特に不便なことはありません。 OGREは、極端な条件下でのパフォーマンスを再び示しました。



All Articles