SSブログ

Androidアプリ開発 OpenGL queueEventを使う [Android OpenGL]

本日は、久しぶりにOpenGLネタである。といっても純粋にOpenGLのネタかというとそうでもなく、どちらかというとAndroidの方かな。

OpenGLで何か表示しようと思ったら、GLSurfaceViewを使う必要がある。GLSurfaceViewも、SurfaceViewもどちらも描画専用のスレッドを持っている。onDrawFrameはこの専用のスレッドで実行されている。
SurfaceViewでない単なるビューは。描画用のスレッドがない。アクティビティと同じUIスレッドで描画が行われる。マルチスレッドで動くことになると、スレッド間でのデータ通信が必要になってくる。

描画用のデータと、アクティビティで使うデータがきっちり分かれていれば、スレッド間でデータのやりとりを行う必要はない。しかし、同じアプリの中で動いているスレッドなので、普通に考えれば何かしらのデータ通信が必要。

データ通信といっても、単にメソッドを呼び出すだけの場合が多い。publicフィールドにして直接フィールドにアクセスしてしまう、という手もあるが「カプセル化」といった面からみてもこれは避けた方が無難。

アクティビティの方で、メニューのイベントやら、タップイベントやらをコールバックで処理していたとする。それを受けて「これは再描画が必要だな」っていうことで、viewのinvalidateを呼び出してはいけない。viewがSurfaceViewじゃなければ問題はない。viewがSurfaceViewだとinvalidateを呼び出した瞬間に例外となる。

じゃあ、どうすればよいかというと、postInvalidate()を呼び出せばOKみたい。しかし、GLSurfaceViewだと描画し続ける、っていうのが普通だと思う(「無効になって必要な時だけ」という描画方法にもできるみたいではあるが)。invalidate()はあまり行われない。

最初にやってエラーをくらうのは、メインスレッドの方で、OpenGLのちょっとした有効、無効を切り替えようと思った時。OpenGLのAPIを呼び出す場合、AndroidのOpenGL ESだとGL10のインスタンスが必要だが、これは適当にフィールドで覚えておいて、glRememberField.glEnable(GL10.GL_LIGHT)とかやってみたりすると、以下のようなエラーになってしまう。

E/libEGL(21579): call to OpenGL ES API with no current context (logged once per thread)


よくありがちなのは(AREarthroidでもそうだが)、テクスチャ画像の読み込みは、メインのUIスレッドで行って、onDrawFrameはなるべく止めずに、っていう感じでスレッドの役割分担をしたとき。
onCreateSurfaceでテクスチャを読み込んでいる分には、OpenGLのスレッドでやっているので問題はない。読み込みをメインスレッドでやって、ビットマップをロードするために、texImage2Dを呼び出すとこのエラーが発生する。

参考記事
Androidアプリ開発 OpenGL テクスチャマッピング


では、どうすればよいかというと、queueEventを使う。

queueEventはGLSurfaceViewのメソッドで、OpenGLのスレッドに実行を依頼するもの。使い方が少々まどろっこしい。
どうするかというと、queueEventの引数に、Runnableインターフェースを実装したオブジェクトのインスタンスを作って渡してやる。クラスを作ってもよいが、名前なしでインスタンスを生成してしまうことが多い。
Runnableインターフェースには、メソッドvoid run()が必要なので、このメソッドを作ってやり、メソッド内でスレッドで実行させたいコードを書く。
以下、が実際の例。

	@Override
	public void onLongPress(MotionEvent arg0) {
		queueEvent(new Runnable(){
			public void run(){
				glRememberField.glEnable(GL10.GL_LIGHT);
			}
		});
	}


SampleGLSurfaceViewのonLongPressで使ってみた。glRememberFieldは、onDrawFrameで引数のglをそのまま代入。
どこかのstaticフィールドにありそうではあるが、見つからなかったので。onDrawFrameで引数のglを代入して記憶している。使い方は間違っているかも知れない。ちょっと自信がない。

ライティングする、しないのスイッチだけなら、フィールド変数を作成して、onDrawFrameでそのフィールド変数を見て処理をわけた方が普通の作り方だと思う。

時間がかかりそうな処理を別スレッドでやらせて、処理が終わった時点で、OpenGL側にそれを伝えるわけだが。そのスレッド上でそのまま、OpenGLのAPI呼び出しをすると、call to OpenGL ES API with no current contextのエラーが発生する。なので、queueEventを使ってGLThreadで処理を行うようにすればOK。

もうひとつ。

onDrawFrameで複数のモデルを描画しているとする。ここにもうひとつ追加したいとする。リストになっているので、newしてaddすればOKなのだが、これをメインスレッドで行うと、リストが競合して、エラーになってしまう(場合がある)。
スレッドの処理タイミングによっては、競合が発生しないので、何事もなかったかのように動作する。マルチコアのCPUを持つ端末でやると発生しやすかったりする。

onDrawFrameでリストを参照して描画処理を行っている最中に、別のスレッドでリストへの追加が起きるとエラーになる。そこで、リストへの追加処理をqueueEventを使ってやるようにする。そうすれば、GLThreadで、リストへの追加が行われるので、うまくいくようになる。

AREarthroid




サイト内を検索

タグ:OpenGL Android
nice!(0) 

nice! 0



Copyright Atsushi Asai Google+朝井淳
[改訂第4版]SQLポケットリファレンス

[改訂第4版]SQLポケットリファレンス

  • 作者: 朝井 淳
  • 出版社/メーカー: 技術評論社
  • 発売日: 2017/02/18
  • メディア: 単行本(ソフトカバー)

イラストで理解 SQL はじめて入門

イラストで理解 SQL はじめて入門

  • 作者: 朝井 淳
  • 出版社/メーカー: 技術評論社
  • 発売日: 2019/05/16
  • メディア: 単行本(ソフトカバー)

[データベースの気持ちがわかる]SQLはじめの一歩 (WEB+DB PRESS plus)

[データベースの気持ちがわかる]SQLはじめの一歩 (WEB+DB PRESS plus)

  • 作者: 朝井 淳
  • 出版社/メーカー: 技術評論社
  • 発売日: 2015/03/03
  • メディア: 単行本(ソフトカバー)

Access クエリ 徹底活用ガイド ~仕事の現場で即使える

Access クエリ 徹底活用ガイド ~仕事の現場で即使える

  • 作者: 朝井 淳
  • 出版社/メーカー: 技術評論社
  • 発売日: 2018/05/25
  • メディア: 大型本

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。