[go: up one dir, main page]

この記事は ゲスト投稿者 Active Theory による Android Developers Blog の記事 "Extending Web Technology with Android | Android Developers Blog" を元に翻訳・加筆したものです。詳しくは元記事をご覧ください。

Paper Planes は、「画面から画面に紙飛行機を飛ばすことができたら」というシンプルなアイデアから生まれました。

その中心にあるのは、お互いを瞬時に接続するウェブの力を借りて世界中の人々をつなぐという考え方です。画面上でできることは、特に JavaScript や WebGL といった最新のウェブ技術が登場したことによって広がりつつあります。

Paper Planes は、もともと Google I/O 2016 の基調講演の 30 分前に、参加者と外部からの視聴者をつないで実施されたものです。2016 年の世界平和の日の一般リリースに向けて、Google Play でも公開されている Android Experiment を作成し、既存のウェブ テクノロジーを Android Nougat ネイティブの機能で拡張しました。それによって、たとえば、世界のどこかで飛行機がキャッチされた場合に通知されるようになっています。

はじめに

ユーザーは自分の紙飛行機を作って、スタンプを追加します。スタンプには、自分の所在地があらかじめ設定されています。紙飛行機を飛ばすジェスチャーを行うと、飛行機は仮想世界に向かって飛び立ちます。PC からウェブサイトを開いたユーザーは、紙飛行機が画面上を飛び回っている様子を見ることができます。



その後、ユーザーは紙飛行機が世界のどこでキャッチされたかを確認することができます。紙飛行機のスタンプはパスポートのように読むことができ、3D で表示された地球に飛行経路や飛行距離が表示されます。

自分の飛行機を作れるだけでなく、ユーザーはスマートフォンを使って網で飛んできた飛行機をキャッチするジェスチャーをすることができます。ピンチ操作して飛行機を開くと、その飛行機がどこから飛んできたかがわかります。そして、自分のスタンプを追加してもう一度飛ばすことができます。

WebView

Paper Planes は、Google I/O の舞台上に設置された 50 インチ スクリーンから、最新のウェブ テクノロジーを使った PC やモバイル端末まで、さまざまな端末で動作するように開発されています。

WebGL

定型化されたローポリゴンの地球の表現から大量の紙飛行機まで、さまざまな 3D 要素のレンダリングに WebGL が使用されており、この体験をすばらしいものにしています。地球を照らす部分や、ユーザーがピンチ操作して飛行機を開いたり閉じたりする変形アニメーション部分は、カスタムの GLSL シェーダーを記述しています。




WebSocket

ユーザーが飛行機を「飛ばす」と、WebSocket 経由でメッセージがバックエンド サーバーに送信され、すべてのデスクトップ パソコンにリレーされて飛行機が飛び立つ様子が表示されます。



WebWorker

大量の飛行機の計算シミュレーションには、それぞれの飛行機の位置を計算し、その情報をメインスレッドに戻す WebWorker を使ってマルチスレッドで計算しています。メインスレッドでは、WebGL を使ってレンダリングを行います。



プラットフォームによらないエクスペリエンスを提供するために、ウェブをネイティブ Android コードで拡張しています。Android と密接に統合されている Chromium を活用することで、既存のウェブ コードを使ってアプリの表示レイヤーを作ることができました。同時に、豊富な通知機能やバックグラウンド サービスなど、OS との密接な統合による機能も追加できました。

WebView と Java コードの連携について詳しく知りたい方は、チュートリアルとしてこちらの GitHub レポジトリをご覧ください。

通知

Android アプリへのプッシュ通知の送信には、Firebase Cloud Messaging(FCM)を使用しています。誰かが飛行機をキャッチして飛ばしなおすと、いくつの都市を経たか、何マイル飛んだかといった情報が飛行機を作ったユーザーの端末に FCM 経由で通知されます。通知の送信の際には、端末に頻繁に通知がいかないような制御を行っています。

バックグラウンド サービス

1 日に 1 回実行され、ローカルのストレージを確認してユーザーが最後にアプリを開いた時間を判断するバックグラウンド サービスが実装されています。ユーザーが 2 週間以上アプリを開いていない場合、アプリを開いて新しい飛行機を作ることをうながす通知を送信します。

通信ネットワーク

このアプリは、Google Cloud Platform 上のサーバー ネットワークで実行されています。スタンプ用に大まかな地理的位置を取得するために、ビルトインのジオコーディング ヘッダーを利用し、WebSocket 経由ですべての端末と接続するために Socket.IO を利用しています。

ユーザーは最寄りのサーバーに接続します。サーバーはメッセージを単一のメインサーバーにリレーするとともに、その地域でアプリを参照しているすべてのデスクトップ パソコンにもリレーします。

さらなる進化

このアプローチは大成功で、プラットフォームやフォーム ファクタによらないスムーズで魅力的な体験を提供し、世界中の人々をつなぐことができています。ウェブをネイティブ機能で拡張することは、高品質な体験を進化させる貴重な手法であることがわかりました。Android Experiments ウェブサイトの詳細もご覧ください。



Posted by Yuichi Araki - Developer Relations Team

[この記事は Shanee Nishry による Android Developers Blog の記事 "Game Performance: Vertex Array Objects" を元に翻訳・加筆したものです。詳しくは元記事をご覧ください。]

以前、頂点レイアウト修飾子を使用して、OpenGL アプリケーションのパフォーマンスと決定性を向上させる方法をご案内しました。この投稿では、オブジェクト描画に際し、パフォーマンスを向上し、よりクリーンなコードを生成できる便利なテクニックをもう 1 つご紹介します。

頂点バッファのバインド

画面上に描画する前に、該当する頂点シェーダー属性に頂点データ(例、ポジション、法線、テクスチャ座標)をバインドする必要があります。それには、頂点バッファをバインドし、全体の頂点属性を有効にして、glVertexAttribPointer でバッファのレイアウトを記述します。

描画処理は以下のようになります。
const GLuint ATTRIBUTE_LOCATION_POSITIONS   = 0;
const GLuint ATTRIBUTE_LOCATION_TEXTUREUV = 1;
const GLuint ATTRIBUTE_LOCATION_NORMALS     = 2;
// Bind shader program, uniforms and textures
// ...
// Bind the vertex buffer
glBindBuffer( GL_ARRAY_BUFFER, vertex_buffer_object );
// Set the vertex attributes
glEnableVertexAttribArray( ATTRIBUTE_LOCATION_POSITIONS );
glVertexAttribPointer( ATTRIBUTE_LOCATION_POSITIONS, 3, GL_FLOAT, GL_FALSE, 32, 0 );

glEnableVertexAttribArray( ATTRIBUTE_LOCATION_TEXTUREUV );
glVertexAttribPointer( ATTRIBUTE_LOCATION_TEXTUREUV, 2, GL_FLOAT, GL_FALSE, 32, 12 );

glEnableVertexAttribArray( ATTRIBUTE_LOCATION_NORMALS );
glVertexAttribPointer( ATTRIBUTE_LOCATION_NORMALS, 3, GL_FLOAT, GL_FALSE, 32, 20 );
// Draw elements
glDrawElements( GL_TRIANGLES, count, GL_UNSIGNED_SHORT, 0 );
このコードは、あまり好ましいものではありません。それにはいくつかの理由があります。1 つめの理由は、描画の前に正しい属性を有効または無効にして、頂点バッファのレイアウトをキャッシュに格納する必要があることです。つまり、ほとんど意味のないタスクのために、ハードコーディングかデータ保管のいずれかを実行しなければなりません。

2 つめの理由はパフォーマンスです。有効化する属性を個別にドライバーに伝えなければならず、これは最適とはいえません。この情報をプリコンパイルしておいて、一括して引き渡すのが最善策です。

最後に、これは純粋に見た目の問題ですが、長いボイラプレートコードによって描画処理が雑然としてしまうということが挙げられます。これは、できるならば避けたいところです。

このコードが好ましくないと思われる理由は他にもありますレイアウト修飾子を活用している点は素晴らしいのですが、このコードではすでに OpenGL ES 3 以上を使用しているため、 ジオメトリのインスタンス化 も使用すればさらに良くなるでしょう。単一の描画処理に多くのインスタンスをメッシュのようにバッチさせることで、パフォーマンスを確実に強化できます。

では、上記のコードをどのように改善できるのでしょうか。

頂点配列オブジェクト(Vertex Array Objects: VAO)

OpenGL ES 3 またはそれ以上を使用している場合、頂点属性の状態を保管するために頂点配列オブジェクト(VAO)を使用します。

VAO を使用することにより、繰り返して使用される頂点の説明フォーマットがドライバーにコンパイルされます。加えて、glVertexAttribPointer で必要とされる頂点フォーマットのキャッシュ格納が不要となり、また、描画ごとのボイラプレートコードを減らすことができます。

頂点配列オブジェクトの作成

最初に VAO を作成する必要があります。頂点バッファ オブジェクトに沿ってメッシュごとに作成すると、以下のようになります。
const GLuint ATTRIBUTE_LOCATION_POSITIONS   = 0;
const GLuint ATTRIBUTE_LOCATION_TEXTUREUV = 1;
const GLuint ATTRIBUTE_LOCATION_NORMALS     = 2;
// Bind the vertex buffer object
glBindBuffer( GL_ARRAY_BUFFER, vertex_buffer_object );
// Create a VAO
GLuint vao;
glGenVertexArrays( 1, &vao );
glBindVertexArray( vao );
// Set the vertex attributes as usual
glEnableVertexAttribArray( ATTRIBUTE_LOCATION_POSITIONS );
glVertexAttribPointer( ATTRIBUTE_LOCATION_POSITIONS, 3, GL_FLOAT, GL_FALSE, 32, 0 );

glEnableVertexAttribArray( ATTRIBUTE_LOCATION_TEXTUREUV );
glVertexAttribPointer( ATTRIBUTE_LOCATION_TEXTUREUV, 2, GL_FLOAT, GL_FALSE, 32, 12 );

glEnableVertexAttribArray( ATTRIBUTE_LOCATION_NORMALS );
glVertexAttribPointer( ATTRIBUTE_LOCATION_NORMALS, 3, GL_FLOAT, GL_FALSE, 32, 20 );
// Unbind the VAO to avoid accidentally overwriting the state
// Skip this if you are confident your code will not do so
glBindVertexArray( 0 );
以下の追加部分を除いて、前のコード セクションに類似していることに気づかれるでしょう。
// Create a vertex array object
GLuint vao;
glGenVertexArrays( 1, &vao );
glBindVertexArray( vao );
これらの行で VAO を作成し、バインドしています。この後の glEnableVertexAttribArrayglVertexAttribPointer コールはすべて今バインドされている VAO に記録されます。手順としては新たに生成された VAO を使用すればいいだけなので、描画ごとの手続きは大いに簡素化されます。

頂点配列オブジェクトの使用

このメッシュを使用して次に描画をする際は、glBindVertexArray を使用して VAO をバインドするのみで、
// Bind shader program, uniforms and textures
// ...
// Bind Vertex Array Object
glBindVertexArray( vao );
// Draw elements
glDrawElements( GL_TRIANGLES, count, GL_UNSIGNED_SHORT, 0 );
頂点属性の経由は不要になります。これにより、コードはよりシンプルに、フレームごとのコールは短く、効果的になり、ドライバーによるバインドが最適化されることでパフォーマンスも向上します。

glBindBuffer は呼び出されていないことにお気づきでしょうか。これは、VAO により glBindBuffer コール自体が記録されることはないものの、VAO が記録されている間の glVertexAttribPointer の呼び出しが、現在バインドされているバッファを参照しているからです。

ゲーム パフォーマンスを改善する方法をさらにお知りになりたい場合は、ゲーム パフォーマンスに関する記事のシリーズをご覧ください。Android でビルドしている場合、Android のパフォーマンス パターンもご参考にしてください。


Posted by Ryuichi Hoshi - Developer Relations Team

[この記事は Games Developer Advocate の Shanee Nishry による Android Developers Blog の記事 "Game Performance: Layout Qualifiers" を元に、萩倉が翻訳・加筆したものです。詳しくは元記事をご覧ください。]

今日は OpenGL Shading Language (GLSL)を利用してゲームのパフォーマンスを最適化し、ワークフローを簡素化するベスト プラク ティスについてお伝えします。Layout Qualifiers は特にコードの確定性を高め、作業者の負荷を減らしてパフォーマンスを高めます。

簡単な頂点シェーダーに変更を加えてみましょう。

位置座標とテクスチャ座標を取得し、頂点の位置を変換し、フラグメント シェーダーにデータを渡す、基本的な頂点シェーダーの例を次に示します。
attribute vec4 vertexPosition;
attribute vec2 vertexUV;

uniform mat4 matWorldViewProjection;

varying vec2 outTexCoord;
void main()
{
  outTexCoord = vertexUV;
  gl_Position = matWorldViewProjection * vertexPosition;
}

頂点属性インデックス

画面にメッシュを描画するには、頂点バッファを作成し、頂点データ(ここでは位置座標、テクスチャ座標など)を登録する必要があります。

サンプル シェーダーで頂点データを次のように記述します。
struct Vertex
{
  Vector4 Position;
  Vector2 TexCoords;
};
これに従い、頂点シェーダーの属性を次のように定義します。
attribute vec4 vertexPosition;
attribute vec2  vertexUV;
glGetAttribLocation へのコールによって指定された名前の属性の処理が行われ、頂点データがシェーダー属性と関連づけられます。すると属性フォーマットが glVertexAttribPointer へのコールとともに記述されます。
GLint handleVertexPos = glGetAttribLocation( myShaderProgram, "vertexPosition" );
glVertexAttribPointer( handleVertexPos, 4, GL_FLOAT, GL_FALSE, 0, 0 );
GLint handleVertexUV = glGetAttribLocation( myShaderProgram, "vertexUV" );
glVertexAttribPointer( handleVertexUV, 2, GL_FLOAT, GL_FALSE, 0, 0 );
しかし、vertexPosition 属性をもつ複数のシェーダーがある場合、各シェーダーの glGetAttribLocation を呼び出すのはパフォーマンスを無駄にし、ゲームの読み込み時間が長くなります。

Layout Qualifiers を利用すると、頂点シェーダー属性の宣言を次のように変更できます。
layout(location = 0) in vec4 vertexPosition;
layout(location = 1) in vec2 vertexUV;
またそのためには、使用するシェーダーが GL ES 3.1 に対応していることをシェーダー コンパイラーに伝える必要があります。

以下のバージョン宣言を追加します。
#version 300 es
例示のシェーダーがどのようになるかを見てみましょう。変更点を太字で示します。
#version 300 es

layout(location = 0) in vec4 vertexPosition;
layout(location = 1) in vec2 vertexUV;

uniform mat4 matWorldViewProjection;
out vec2 outTexCoord;
void main()
{
  outTexCoord = vertexUV;
  gl_Position = matWorldViewProjection * vertexPosition;
}
OutTexCoord が varying 変数から out 変数に変わっていることもご確認ください。Varying キーワードはバージョン 300 es から動作が保証されなくなったため、シェーダーを機能させるには変更が必要です。

頂点属性の修飾子と #version 300 es は OpenGL ES 3.0 以降でサポートされています。デスクトップ版は OpenGL 3.3 でサポートされ、#version 330 が使用されています。

ここで位置属性が常に 0 で、テクスチャ座標が 1 になるとわかったら、glGetAttribLocationを使わずに次のようにシェーダー
フォーマットをバインドできます。
const int ATTRIB_POS = 0;
const int ATTRIB_UV   = 1;

glVertexAttribPointer( ATTRIB_POS, 4, GL_FLOAT, GL_FALSE, 0, 0 );
glVertexAttribPointer( ATTRIB_UV, 2, GL_FLOAT, GL_FALSE, 0, 0 );
この簡単な変更でパイプラインを明確にし、コードをシンプルにして、起動の際の負荷を削減できます。

Android でのパフォーマンスの詳細については、Android Performance Patterns の動画シリーズをご覧ください。

Posted by Takeshi Hagikura - Developer Relations Team

[この記事は Software Engineer の Ankur Kotwal が Google Developers Blog に投稿した "Ho Ho Ho! Google's Santa Tracker is now open source" という記事を元に荒木が翻訳・加筆したものです]

季節はすっかり春ですね。クリスマスはずいぶん前のことのように感じられますが、お知らせがあります。Google サンタ トラッカーがオープンソースとして GitHub (google/santa-tracker-webgoogle/santa-tracker-androidに公開されました。Web と Android 両方のアプリが Google の開発者向けプロダクトを使ってどのように実現されているのかご覧いただけます。
サンタ トラッカーといっても、ただ単にクリスマス イブのサンタさんのプレゼント配達状況を追跡するだけではありません。クリスマス シーズンを通して、冬をテーマにした数々のゲームで遊んだり、北極にあるサンタ村でサンタさんか配達の準備をする様子を見ることができるんですよ。

オープンソースとしてリリースしたのは以下のようなものです。

Android アプリ

  • Android の サンタ トラッカー アプリはひとつの APK ファイルで Ice Cream Sandwich (4.0) 以降のすべての端末をサポートしています。アプリのソースコードはこちらでご覧いただけます。
  • サンタ村はビデオやゲームやトラッカー (地図) のランチャーになっています。横幅 1 万ピクセルにも及ぶサンタ村を実現するため、Android のリソース階層をちょっと変わったふうに利用しています。これによって画面解像度ごとに別々の画像を用意する必要をなくし、APK のサイズを削減しています。
  • サンタ トラッカーのゲームは様々な技術を組み合わせて作られています。GumballJBox2D、Memory Match は Android の View、Jetpack は OpenGL と特製のレンダリング エンジンを使っています。
  • ユーザー エンゲージメント向上のため、App Indexing API を使って Google 検索からサンタ トラッカーのゲームを開くことができるようにしています。Deep Linking を利用して実現されています。

Android Wear


Web 版


  • Web 版のサンタ トラッカーは Polymer を使って実装されています。Polymer は Chrome チームが Web Component に基づいて作り出した新しいライブラリです。サンタ トラッカーでの利用方法をご覧になれば、コードを再利用可能なコンポーネントとしてまとめるのも Polymer を使えば簡単だということがお分かりいただけるでしょう。サンタ村での各シーン (ゲーム、ビデオ、インタラクティブなページ) はすべてカスタム要素になっていて、必要なときだけ読み込むようにすることで起動のコストを最小化しています。
  • サンタ トラッカーのインタラクティブで楽しい体験は Web アニメーション API を使って作られています。JavaScript でコンテンツのアニメーションをを統一的に扱うための標準化された API です。CSS アニメーションから大きな進歩です。Web アニメーションはインタラクティブに記述することができ、ポリフィルを使えば全てのモダンなブラウザーをサポートすることができます。Polymer 自体もマテリアル デザインの効果を実現するために内部で Web アニメーションを利用しています。アニメーションの例は GitHub を検索すればたくさん見つかります。

  • サンタさんはモバイル ファーストを推進しています。今年はモバイル Web での最適化を主眼に据えて設計しました。完全なレスポンシブ デザイン、Polymer によるタッチ ジェスチャーのサポートなどです。また、theme-colorホーム画面に追加するための Web Application Manifest といった新機能もあります。
  • 徹底的なローカリゼーションのため、Web Component として新しく i18n-msg コンポーネントを開発しました。Chrome Extension の i18n の仕組みが元になっており、開発用にライブ更新も利用できますが、最適化用にビルド ステップも備えています。
サンタ トラッカーを支える技術がどのようなものか、ぜひソース コードをご覧になって確認して下さい。開発者の皆様のお役に立つことを願っております。

Posted by Yuichi Araki - Developer Relations Team