none
DirectXフルスクリーン時のTextBox表示方法をご教示下さい。 RRS feed

  • 質問

  • 現在 VisualC# + Direct3D を用いてゲームソフトを作成しており
    タイトルのような問題が発生し、困っております。

    開発ツールはVisualStudio2005 AcademicEdition です。

    具体的には、Direct3Dのテクスチャを描画したフォーム上にテキストボックスを表示し
    入力したテキストにより、描画画像を変更するといった処理です。

    ウィンドウモードでは問題なく動作するのですが
    フルスクリーンの対応を入れた途端、テキストボックスが表示されなくなってしまいました。

    【モード変更処理参考サイト … おのでら様 ソーサリーフォース】
    http://sorceryforce.com/manageddirectx/direct3d_fullscreen.html

    しかし、下記理由のためテキストボックスが存在していることは確実です。
    ・マウスカーソルを重ねると、矢印から「I」の形に変更される
    ・テキスト入力内容は見えませんが、エンターキーにて入力完了すると描画画像が変更される

    また、フルスクリーン状態から、ウィンドウモードに変更するとテキストボックスも見えるようになります。


    以上です。原因どころか、特定手段さえ見えなくなってしまっているため
    ご教示頂ければと思い投稿させて頂きました。

    ご協力お願い致します。

    • 編集済み tetsuwo 2012年4月18日 11:03
    2012年4月18日 8:41

回答

  • tetsuwo さんこんにちは、おのでらです。

    具体的には、Direct3Dのテクスチャを描画したフォーム上にテキストボックスを表示し
    入力したテキストにより、描画画像を変更するといった処理です。

    ウィンドウモードでは問題なく動作するのですが
    フルスクリーンの対応を入れた途端、テキストボックスが表示されなくなってしまいました。

     これはフルスクリーンモード時による描画はウインドウモード時の描画とは異なるためです。

     コードを見ていないのでおそらくの話なのですが、ウインドウモード時はウインドウに対して Direct3D の描画結果を表示させ、そのウインドウの上にテキストボックスのコントロールを載せているのでテキストボックスが常に見えている状態になります。

     しかし、フルスクリーンモードは Direct3D の描画結果が最前面に表示されるイメージであるため、ウインドウとは別のハンドルと持つテキストボックスなどのコントロールを表示させることができません。テキストボックスをアクティブにした時など完全に見えないというわけではありませんが、表示がちらついたり正しい描画にならないことがあるので、どちらにせよフルスクリーンモードを使う場合、Windows のコントロールと併用するのはおすすめしません。(たぶんテキストボックスが見えるのは本来アクティブであるはずのウインドウ以外のコントロールがマウスクリックによってアクティブになっているせいかもしれません)

    ほかのゲームを見ても Windows の標準のテキストボックスを使ってフルスクリーンで起動させているゲームは見たことないかと思います。

     一般的にフルスクリーンモード時にテキストを入力させる場合は独自のテキストボックスを作成させて描画、入力させます。C++言語なのですがリンク先の「CustomUI サンプル」のようなイメージです。リンク先の説明にもあるように

    すべての DXUT コントロールは、Windows コントロールと同じように動作します。これらは、まったくゼロの状態から実装されており、HWND または Windows コントロールは使用していません。また、これらは Direct3D でレンダリングされています。そのため、ウィンドウ表示モードおよび全画面表示のどちらでも Direct3D アプリケーションを使用できます。

    と書かれており、コントロールに対してウインドウハンドルを使用せずにすべて Direct3D で描画します。Managed DirectX(かな?) を使った場合のサンプルも探せばあるかもしれませんが、ない場合は自分で実装する必要があります。または、ほかで提供されているDirectX 系ライブラリなどにあるかもしれません。(Managed DirectX はほとんどないかな…)

     Windows Phone SDK で提供されている XNA+Silverlight を使うとものすごく簡単に実装できるんですけどね…。


    おのでら (http://sorceryforce.com/)

    • 回答の候補に設定 山本春海 2012年4月27日 8:37
    • 回答としてマーク 山本春海 2012年5月1日 7:52
    2012年4月19日 3:58
  • ─<D3D device を用いた描画>───────────────────────

    ① device.Clear() にて、セカンダリバッファを単色塗りつぶし
    ② device.BeginScene() 以降にセカンダリバッファに順次描画
    ③ device.EndScene() にて、セカンダリバッファへの描画完了(確定)
    ④ device.Present() にて、セカンダリバッファの描画内容をFormに上書コピー
    ───────────────────────────────────────────

    その為、フルスクリーン時にセカンダリバッファを表示しているということであれば
    ④が不要になってしまうので間違いでしょうか…?
    また、セカンダリバッファを表示せず、Present()を実施した上で
    Fromをスクリーン最前面に表示すればTextBoxが見えるのでは?と思います。

     ウィンドウモードとフルスクリーンモードの描画の仕組みは DirectX 9 ではそれぞれ異なります。しかし、それを device.Present メソッドが共通的に呼び出せるように吸収しているだけにすぎません。ですのでフルスクリーンモードでも device.Present は必要です。

     ウィンドウモードとフルスクリーンモードの違いはここで簡単にかけるようなものでもありませんし、DirectX のバージョンや OS のバージョンによって異なるので割愛します。(というか私も正確には書けません orz)。あんまりいいのはなかったですが、関係のある記事を少し探してみたので参照してください。(Web だとあんまり見つからないですね…)

     ウインドウモードの場合はウィンドウに Directt3D の描画結果を表示させ、それをディスプレイに表示させています。フルスクリーンモードの場合はウインドウを経由せずに直接ディスプレイに映像を映しています。ですのでフルスクリーンモード時では通常はウィンドウに配置したコントロールは見えません。フルスクリーンモードでも Direct3D と GDI の描画を共有できる仕組みはあった気がしますが、実際に試したことがあるわけではありませんので、気になるようであれば探してみるといいと思います。(メッセージボックスあたりはあった気がする)

     ただ、私の個人的な考えではウインドウモードだけに限定するなら Windows のコントロールを使うのはぎりぎりありかなとは思いますが、フルスクリーンモードを使い場合はやはり Direct3D を使ったコントロールの描画を使ったほうがいいかなと思います。

     一応別解としては Direct3D のフルスクリーンモードを使うのではなく、Form をディスプレイいっぱいに拡大(タイトルバー消去、タスクバー非表示など)、最前面に設置し、そこにウィンドウモードで描画すればコントロールの配置は可能だと思います。ユーザーのディスプレイのサイズをどうするかという問題などいろいろあるかと思いますが…。


    おのでら (http://sorceryforce.com/)


    2012年4月19日 10:47
  • すでにおのでらさんが的確な回答を返していらっしゃるので、私などが出る幕はありませんが、WPFアプリケーションのフルスクリーンモードを使う手もあるかと。

    おのでらさんが公開されている、下記の「WPF + WindowsFormsIntegration + XNA」のサンプルのWindow1に、下記のようなKeyDownイベントハンドラーを実装すると、フルスクリーンモードに切り替わります。

    http://sorceryforce.com/xna/tips_xnaonwpf.html

    		bool f_isFullScreen = false;
    
    		private void Window_KeyDown(object sender, KeyEventArgs e)
    		{
    			if (e.Key == Key.F11)
    			{
    				if (!f_isFullScreen)
    				{
    					this.WindowStyle = WindowStyle.None;
    					this.WindowState = WindowState.Maximized;
    					this.Topmost = true;
    				}
    				else
    				{
    					this.WindowStyle = WindowStyle.SingleBorderWindow;
    					this.WindowState = WindowState.Normal;
    
    				}
    				f_isFullScreen = !f_isFullScreen;
    			}
    		}
    

    ただ、このWPFフルスクリーン、別にビデオメモリを占有しているわけではない(単に枠なしウィンドウを最大化しているにすぎず、Direct3Dフルスクリーンではない)ので、おのでらさんが示された別解と同じです。Direct3Dのフルスクリーンモードはビデオメモリを占有できるため、パフォーマンスの点からは良いのですが、デバッグが結構大変ですね。市販のゲームは移植性を高めるためにも、コントロールにはWindows GDIなどは使わず、Direct3DやOpenGLを使って自前で描画しているものがほとんどだと思います。XNAを使って、WindowsとXbox 360とでマルチ展開を考える場合も、結局ゲーム内で使うテキストボックスなどは自前で作成して、Win32/WPFコントロールの使用はWindows上でのデバッグ専用と割り切ったほうがよいかと。

    • 回答としてマーク 山本春海 2012年5月1日 7:52
    2012年4月19日 16:27
  • ■Wモード/FSモードの違い
    ご紹介頂いたサイトをチラっと見てみたのですが、辞書が辞書を呼び理解がおいつきません(^^;)
    今の仕事が終わりましたら、じっくり読んでみようと思います…。
    (XNAへ移行する事を踏まえた上ででも、知識として必要でしょうか?)

     普通にゲームを作る上ではそんなに深く知る必要はないと思いますが、なぜフルスクリーンで Windows コントロールを使うべきではないかという理由がどうしても知りたいのであれば知識としては覚える必要はあると思います。(書籍の方がいい情報載っているかもしれません)

    ■WindowsコントロールのTextBoxについて
    Formをディスプレイ一杯に広げる手段として、Windowモードのまま解像度をFormと同サイズ(1280x720)に変更してしまえばいいのでは?
    と思いましたが、配慮点が多いのか少ないのか判断するのにも時間がかかる為、中止しました。

    一応、Direct3DとGDIの共有についても少し調べてみようと思います。

     直接解像度を変更するのは嫌がる人がいるので注意は必要ですね。


    おのでら (http://sorceryforce.com/)

    • 回答としてマーク 山本春海 2012年5月1日 7:52
    2012年4月21日 4:49

すべての返信

  • tetsuwo さんこんにちは、おのでらです。

    具体的には、Direct3Dのテクスチャを描画したフォーム上にテキストボックスを表示し
    入力したテキストにより、描画画像を変更するといった処理です。

    ウィンドウモードでは問題なく動作するのですが
    フルスクリーンの対応を入れた途端、テキストボックスが表示されなくなってしまいました。

     これはフルスクリーンモード時による描画はウインドウモード時の描画とは異なるためです。

     コードを見ていないのでおそらくの話なのですが、ウインドウモード時はウインドウに対して Direct3D の描画結果を表示させ、そのウインドウの上にテキストボックスのコントロールを載せているのでテキストボックスが常に見えている状態になります。

     しかし、フルスクリーンモードは Direct3D の描画結果が最前面に表示されるイメージであるため、ウインドウとは別のハンドルと持つテキストボックスなどのコントロールを表示させることができません。テキストボックスをアクティブにした時など完全に見えないというわけではありませんが、表示がちらついたり正しい描画にならないことがあるので、どちらにせよフルスクリーンモードを使う場合、Windows のコントロールと併用するのはおすすめしません。(たぶんテキストボックスが見えるのは本来アクティブであるはずのウインドウ以外のコントロールがマウスクリックによってアクティブになっているせいかもしれません)

    ほかのゲームを見ても Windows の標準のテキストボックスを使ってフルスクリーンで起動させているゲームは見たことないかと思います。

     一般的にフルスクリーンモード時にテキストを入力させる場合は独自のテキストボックスを作成させて描画、入力させます。C++言語なのですがリンク先の「CustomUI サンプル」のようなイメージです。リンク先の説明にもあるように

    すべての DXUT コントロールは、Windows コントロールと同じように動作します。これらは、まったくゼロの状態から実装されており、HWND または Windows コントロールは使用していません。また、これらは Direct3D でレンダリングされています。そのため、ウィンドウ表示モードおよび全画面表示のどちらでも Direct3D アプリケーションを使用できます。

    と書かれており、コントロールに対してウインドウハンドルを使用せずにすべて Direct3D で描画します。Managed DirectX(かな?) を使った場合のサンプルも探せばあるかもしれませんが、ない場合は自分で実装する必要があります。または、ほかで提供されているDirectX 系ライブラリなどにあるかもしれません。(Managed DirectX はほとんどないかな…)

     Windows Phone SDK で提供されている XNA+Silverlight を使うとものすごく簡単に実装できるんですけどね…。


    おのでら (http://sorceryforce.com/)

    • 回答の候補に設定 山本春海 2012年4月27日 8:37
    • 回答としてマーク 山本春海 2012年5月1日 7:52
    2012年4月19日 3:58
  • おのでらさん、こんにちは。tetsuwoです。
    ご回答ありがとうございます。

    とりあえずは「CustomUI」をC#上で実装しているサンプルを探してみます。
    次回作はDirectXではなく、XNAを用いて作成していくつもりです…(将来性的を考慮して)。

    1点、質問があります。
    フルスクリーン時の描画方法についてですが、セカンダリバッファの描画内容を直接ディスプレイに表示しているということでしょうか?

    私は、描画処理ロジックを下記のようにイメージしております。

    ─<D3D device を用いた描画>───────────────────────

    ① device.Clear() にて、セカンダリバッファを単色塗りつぶし
    ② device.BeginScene() 以降にセカンダリバッファに順次描画
    ③ device.EndScene() にて、セカンダリバッファへの描画完了(確定)
    ④ device.Present() にて、セカンダリバッファの描画内容をFormに上書コピー
    ───────────────────────────────────────────

    その為、フルスクリーン時にセカンダリバッファを表示しているということであれば
    ④が不要になってしまうので間違いでしょうか…?
    また、セカンダリバッファを表示せず、Present()を実施した上で
    Fromをスクリーン最前面に表示すればTextBoxが見えるのでは?と思います。

    上記認識の間違いや、技術的に不可能な点などございましたら
    ご教示頂ければと思います。

    • 編集済み tetsuwo 2012年4月19日 5:18
    2012年4月19日 5:15
  • ─<D3D device を用いた描画>───────────────────────

    ① device.Clear() にて、セカンダリバッファを単色塗りつぶし
    ② device.BeginScene() 以降にセカンダリバッファに順次描画
    ③ device.EndScene() にて、セカンダリバッファへの描画完了(確定)
    ④ device.Present() にて、セカンダリバッファの描画内容をFormに上書コピー
    ───────────────────────────────────────────

    その為、フルスクリーン時にセカンダリバッファを表示しているということであれば
    ④が不要になってしまうので間違いでしょうか…?
    また、セカンダリバッファを表示せず、Present()を実施した上で
    Fromをスクリーン最前面に表示すればTextBoxが見えるのでは?と思います。

     ウィンドウモードとフルスクリーンモードの描画の仕組みは DirectX 9 ではそれぞれ異なります。しかし、それを device.Present メソッドが共通的に呼び出せるように吸収しているだけにすぎません。ですのでフルスクリーンモードでも device.Present は必要です。

     ウィンドウモードとフルスクリーンモードの違いはここで簡単にかけるようなものでもありませんし、DirectX のバージョンや OS のバージョンによって異なるので割愛します。(というか私も正確には書けません orz)。あんまりいいのはなかったですが、関係のある記事を少し探してみたので参照してください。(Web だとあんまり見つからないですね…)

     ウインドウモードの場合はウィンドウに Directt3D の描画結果を表示させ、それをディスプレイに表示させています。フルスクリーンモードの場合はウインドウを経由せずに直接ディスプレイに映像を映しています。ですのでフルスクリーンモード時では通常はウィンドウに配置したコントロールは見えません。フルスクリーンモードでも Direct3D と GDI の描画を共有できる仕組みはあった気がしますが、実際に試したことがあるわけではありませんので、気になるようであれば探してみるといいと思います。(メッセージボックスあたりはあった気がする)

     ただ、私の個人的な考えではウインドウモードだけに限定するなら Windows のコントロールを使うのはぎりぎりありかなとは思いますが、フルスクリーンモードを使い場合はやはり Direct3D を使ったコントロールの描画を使ったほうがいいかなと思います。

     一応別解としては Direct3D のフルスクリーンモードを使うのではなく、Form をディスプレイいっぱいに拡大(タイトルバー消去、タスクバー非表示など)、最前面に設置し、そこにウィンドウモードで描画すればコントロールの配置は可能だと思います。ユーザーのディスプレイのサイズをどうするかという問題などいろいろあるかと思いますが…。


    おのでら (http://sorceryforce.com/)


    2012年4月19日 10:47
  • すでにおのでらさんが的確な回答を返していらっしゃるので、私などが出る幕はありませんが、WPFアプリケーションのフルスクリーンモードを使う手もあるかと。

    おのでらさんが公開されている、下記の「WPF + WindowsFormsIntegration + XNA」のサンプルのWindow1に、下記のようなKeyDownイベントハンドラーを実装すると、フルスクリーンモードに切り替わります。

    http://sorceryforce.com/xna/tips_xnaonwpf.html

    		bool f_isFullScreen = false;
    
    		private void Window_KeyDown(object sender, KeyEventArgs e)
    		{
    			if (e.Key == Key.F11)
    			{
    				if (!f_isFullScreen)
    				{
    					this.WindowStyle = WindowStyle.None;
    					this.WindowState = WindowState.Maximized;
    					this.Topmost = true;
    				}
    				else
    				{
    					this.WindowStyle = WindowStyle.SingleBorderWindow;
    					this.WindowState = WindowState.Normal;
    
    				}
    				f_isFullScreen = !f_isFullScreen;
    			}
    		}
    

    ただ、このWPFフルスクリーン、別にビデオメモリを占有しているわけではない(単に枠なしウィンドウを最大化しているにすぎず、Direct3Dフルスクリーンではない)ので、おのでらさんが示された別解と同じです。Direct3Dのフルスクリーンモードはビデオメモリを占有できるため、パフォーマンスの点からは良いのですが、デバッグが結構大変ですね。市販のゲームは移植性を高めるためにも、コントロールにはWindows GDIなどは使わず、Direct3DやOpenGLを使って自前で描画しているものがほとんどだと思います。XNAを使って、WindowsとXbox 360とでマルチ展開を考える場合も、結局ゲーム内で使うテキストボックスなどは自前で作成して、Win32/WPFコントロールの使用はWindows上でのデバッグ専用と割り切ったほうがよいかと。

    • 回答としてマーク 山本春海 2012年5月1日 7:52
    2012年4月19日 16:27
  • おのでらさん、syghさん
    ご回答・ご助言ありがとうございます。

    ■Wモード/FSモードの違い
    ご紹介頂いたサイトをチラっと見てみたのですが、辞書が辞書を呼び理解がおいつきません(^^;)
    今の仕事が終わりましたら、じっくり読んでみようと思います…。
    (XNAへ移行する事を踏まえた上ででも、知識として必要でしょうか?)


    ■WindowsコントロールのTextBoxについて
    Formをディスプレイ一杯に広げる手段として、Windowモードのまま解像度をFormと同サイズ(1280x720)に変更してしまえばいいのでは?
    と思いましたが、配慮点が多いのか少ないのか判断するのにも時間がかかる為、中止しました。

    一応、Direct3DとGDIの共有についても少し調べてみようと思います。


    ■C#でのCustomUIサンプル
    下記サイトの解説が非常に丁寧なのかな?と思いましたが、肝心のソースがありませんでしたorz
    コメントを残している方もいるので、本当にないのだと思います…。
    C#でのCustomUIサンプル


    上記以外はコレといったサイトを見つけられなかったので
    テキスト入力の実装中止が濃厚な気がします。
    (手探りで作成していくのは時間が掛かり過ぎると判断しました)



    ■WPFアプリケーションのFSモード
    現在作成中のソフトはXNAを採用していないので、次作にて試してみようと思います!
    ただ、環境が VisualStudio2005 なので、このままでは.netframework2.0のためWPFを試せないようです…。
    何よりも VisualStudio の新調が優先ですね。


    2012年4月20日 6:56
  • ■Wモード/FSモードの違い
    ご紹介頂いたサイトをチラっと見てみたのですが、辞書が辞書を呼び理解がおいつきません(^^;)
    今の仕事が終わりましたら、じっくり読んでみようと思います…。
    (XNAへ移行する事を踏まえた上ででも、知識として必要でしょうか?)

     普通にゲームを作る上ではそんなに深く知る必要はないと思いますが、なぜフルスクリーンで Windows コントロールを使うべきではないかという理由がどうしても知りたいのであれば知識としては覚える必要はあると思います。(書籍の方がいい情報載っているかもしれません)

    ■WindowsコントロールのTextBoxについて
    Formをディスプレイ一杯に広げる手段として、Windowモードのまま解像度をFormと同サイズ(1280x720)に変更してしまえばいいのでは?
    と思いましたが、配慮点が多いのか少ないのか判断するのにも時間がかかる為、中止しました。

    一応、Direct3DとGDIの共有についても少し調べてみようと思います。

     直接解像度を変更するのは嫌がる人がいるので注意は必要ですね。


    おのでら (http://sorceryforce.com/)

    • 回答としてマーク 山本春海 2012年5月1日 7:52
    2012年4月21日 4:49
  • こんにちは、tetsuwo さん。

    MSDN フォーラムのご利用ありがとうございます。オペレーターの山本です。
    みなさんから有効な情報をいただいているようでしたので、勝手ながら私のほうで回答としてマークさせていただきました。
    回答くださったみなさん、アドバイスありがとうございます。

    いただいた情報の中で、解決に役立った投稿や、参考になる情報など有効な情報には回答としてマークすることをお願いしています。
    今後、同じ問題でこのスレッドを参照される方にも、有効な情報を活用いただけるかと思いますので、ご協力よろしくお願いいたします。
    _____________________
    日本マイクロソフト株式会社 フォーラム オペレーター 山本 春海

    2012年5月1日 7:52