-
カテゴリー 技術 / デザイン / 制作
-
そうだ、アプリの研究しよう vol.2
最近、(元から?)体調の悪さがすぐ顔に出て困っている坂田です。
上司様に「3徹した顔」「フレッシュさがない」とdisられます。
2013年の抱負は「ボールドの宣伝のタマテツくらい爽やかになる」(分かる人には分かる)さて、いつものシリーズです!
前回は自分がなぜこのアプリを使っているのかということを書きました!
→vol1.じぶんインサイト。
今回は他の人がどんな点を好んでいるのかについてまとめてみます。============================
vol2 たにんインサイト
なぜTweetbotは人気があるのか。私のお気にいりポイントが他人と同じではないはず。
他の人が良いを思っているところはどこなのかを考察します。
============================
カテゴリー 技術 / デザイン / 制作 -
WebGL+HTML5で3DCGを勉強してみた! Part2
どうも。営業部の伊藤です。
前回のブログの続編です。
以下の見慣れないエレメントタイプはバーテックスシェーダ(頂点シェーダ)とフラグメントシェーダ(ピクセルシェーダ)という点まで書きました。
「x-shader/x-vertex」
「x-shader/x-fragment」シェーダはSTEP3のタイトル(シェーダを生成&コンパイル)にも記載しているようにプログラム内でコンパイルして利用するため、コンパイルするまでは単なる文字列しかありません。
そのため、今回はHTML内に記載しておりますが、JavaScript内部で文字列として宣言、管理する形でも問題ないです。
該当の属性はHTMLで定義された正式なエレメントではないため、一般的なブラウザでは理解されず無視されます。
注意しなければいけないのが、scriptタグの中身がJavaScriptと誤認されないようにしなければいけないという点です。
それを回避するため、type属性を使って各々のシェーダを宣言しています。次はシェーダ内の記述を見てみます。
言語はGLSL(OpenGL Shading Language)で実装しています。
GLSLは名前のとおりOpenGLと親和性がある、C言語ライクな言語となります。■バーテックスシェーダ(頂点シェーダ)
attribute vec3 vertexPosition;
attribute vec2 vertexTexture;
uniform mat4 vertexMatrix1;
uniform mat4 vertexMatrix2;
varying vec2 textureCoord;void main(void) {
gl_Position = vertexMatrix1 * vertexMatrix2 * vec4(vertexPosition, 1.0);
textureCoord = vertexTexture;
}■フラグメントシェーダ(ピクセルシェーダ)
precision mediump float;
uniform sampler2D fragmentTexture;
varying vec2 textureCoord;void main(void) {
gl_FragColor = texture2D(fragmentTexture, vec2(textureCoord));
}attribute、vec3、vec2、uniform、mat4、varyingなど様々な単語が出てきましたね。
まず、開発経験者の方であればある程度想像できると思いますが、先頭部分は修飾子(attribute、uniform、varying)、その次はデータ型(vec3、vec2、mat4)、最後は任意の変数名(vertexPositionなど)となります。
修飾子、データ型について纏めます。○attribute
バーテックスシェーダ(頂点シェーダ)専用の修飾子です。
attribute修飾子で宣言された変数はWebGLとシェーダ間で頂点情報を橋渡しする(シェーダ側が受け取る)ための変数となります。
WebGL側で同じ名前の変数に頂点情報を設定しておき、シェーダ側に情報を渡します。○uniform
バーテックスシェーダ(頂点シェーダ)、フラグメントシェーダ(ピクセルシェーダ)の両方で利用できる修飾子です。
attribute同様に、uniformで宣言された変数はWebGL側から情報を渡すための変数となります。
ではattributeと何が違うのか?
attribute修飾子は3Dオブジェクトの頂点に関する情報を受け渡すための専用修飾子です。
逆にuniform修飾子は「全頂点に対して一律に処理される情報」を受け渡すための修飾子となります。
要約すると、3Dを描画しているcanvas上全体に情報を受け渡す場合に利用します。
STEP6(座標変換行列を生成&通知)で詳しく説明します。○varying
バーテックスシェーダ(頂点シェーダ)、フラグメントシェーダ(ピクセルシェーダ)の両方で利用できる修飾子です。
前回のブログにも書きましたが、フラグメントシェーダ(ピクセルシェーダ)が着色内容を計算、決定するには頂点関連の情報が必要になります。
このバーテックスシェーダ(頂点シェーダ)とフラグメントシェーダ(ピクセルシェーダ)の橋渡しをするための変数をvaryingで定義します。○vec2、vec3、mat4
vec(数値)は浮動小数点のベクトル型です。
数値には1~4が設定でき、添字によりベクトル要素数が変わります。
vec2 => 2Dベクトル
vec3 => 3Dベクトル
vec4 => 4Dベクトルmat(数値)は浮動小数点の正方行列です。
数値には2~4を設定でき、添字により正方行列数が変わります。(matは恐らくマトリックスの意ですね)
mat2 => 2×2
mat3 => 3×3
mat4 => 4×4attributeで宣言したvertexPositionやvertexTexture、uniformで宣言したvertexMatrix1、vertexMatrix2はSTEP6(座標変換行列を生成&通知)で値の受け渡しを実施し、
varyingで宣言したtextureCoordは頂点関連情報を受取後、フラグメントシェーダ(ピクセルシェーダ)にデータを受け渡しています。シェーダの宣言部(WebGLとのデータ連携方法や受皿、シェーダ間の連携方法)は以上となり、次はシェーダの処理部です。
ご覧のとおり、バーテックスシェーダ(頂点シェーダ)、フラグメントシェーダ(ピクセルシェーダ)共にmainという関数が定義されています。C言語ライクですね。
必ずmainという関数を定義し、そのなかに処理内容を記述します。
そして、バーテックスシェーダ(頂点シェーダ)ではgl_Positionという組込み変数に頂点データを渡し、フラグメントシェーダ(ピクセルシェーダ)ではgl_FragColoという組み込み変数にデータを渡します。
※頂点データは必須となりますが、フラグメンテーションは必須ではないです。変数宣言(WebGLとの連係用受皿)、シェーダ間連携内容の実装、計算処理内容の実装などシェーダ自体の宣言が完了したため、次はWebGLで該当のシェーダをコンパイルします。
まず、getElementByIdでHTML内のバーテックスシェーダ(頂点シェーダ)、フラグメントシェーダ(ピクセルシェーダ)エレメントを取得します。var shader;
var shaderElement = document.getElementById(id);
if (!shaderElement) {
return null;
}その後、エレメントタイプをチェックし、タイプ毎に該当のシェーダ生成します。
ここで初めてシェーダを生成(createShader)しています。switch(shaderElement.type){
case “x-shader/x-vertex”:
shader = gl.createShader(gl.VERTEX_SHADER);
break;
case “x-shader/x-fragment”:
shader = gl.createShader(gl.FRAGMENT_SHADER);
break;
default:
return null;
}次に、HTML内で宣言した変数、連携内容、計算処理などの文字列(ソース)を上記シェーダに割り当て(shaderSource)るため、firstChildでエレメント内の文字列を取得します。
一通りの文字列取得が完了したら最後にコンパイル(compileShader)です。//子ノード取得
var source = “”;
var childNodes = shaderElement.firstChild;
while (childNodes) {
if (childNodes.nodeType == 3) {
source += childNodes.textContent;
}
childNodes = childNodes.nextSibling;
}
gl.shaderSource(shader, source); // ソース割り当て
gl.compileShader(shader); // コンパイルこれでSTEP3の「シェーダを生成&コンパイル」は終わりです。
&
今回のブログも終わりです!!細かなところは端折りながら書いているつもりですが…想定外に長文&長期化しております。。。
まだまだSTEP3ですが、STEP4以降も頑張って連載していきますので宜しくお願いします。ではでは。
カテゴリー 技術 / デザイン / 制作 -
そうだ、アプリの研究しよう vol.1
-
PhoneGapの検証【導入編】
-
WebGL+HTML5で3DCGを勉強してみた! Part1
どうも。営業部の伊藤です。
前回のブログで書いたように、今更感は否めないですが…最近WebGLの勉強をしています。
まだ超々初心者レベルまでしか勉強できていないですが、これはなかなか頭の体操になります。
今まであまり経験した事のない思考が必要という事もあり、抜け毛の本数が増えそうではありますが…初心者レベルになれるまでは頑張ろうと思います。という事で、復習も兼ねてWebGLを利用した3Dグラフィックの描画方法について書こうと思います。
※3DCG、WebGLに着目しているため、実装で利用するHTML、JavaScript、数学的知識の基礎については省かせていただきます。3DCGのサンプルは以下をご覧ください。
※ピカピカしているのは描画遅延ではないです。チカチカしたらすいません。。。【補足情報】
利用しているオープンソースは以下2種類となります。
○Google webgl-utils.js
setIntervalやsetTimeoutだと色々と問題が多い(複数オブジェクトの描画に向いていない、処理の効率化ができない(GPUに優しくない))ので、上記再帰処理はwebgl-utilsを利用しています。○glMatrix.js
3DCGを表現するために必要となる行列計算用ライブラリとして利用しています。
後述しますが、STEP6の座標変換行列を生成&通知のところで利用します。勉強に利用しているサイトは以下になります。
○wgld.org
初心者向けに基礎から細かくレクチャーしてくれており、非常に分かりやすいです。オススメ!!
それではサンプルをもとに実装内容を書いていきます。
3DCG描画までのSTEPは以下のようになります。STEP1 canvasエレメントを取得
STEP2 canvasからWebGLコンテキストを取得
STEP3 シェーダを生成&コンパイル
STEP4 モデルデータを用意
STEP5 モデルデータからVBO(VertexBufferObject)を生成&バインド
STEP6 座標変換行列を生成&通知
STEP7 描画命令
STEP8 STEP6~7の再帰処理(canvasをレンダリング)それでは早速STEP1から処理の内容から確認していきます。
■STEP1(canvasエレメントを取得)
WebGLを利用した3DレンダリングはHTML5で策定されたcanvasタグ上で動きますので、まずはHTML内のcanvasエレメントを取得します。
今回の場合、以下部分でエレメントを取得しています。var canvas = document.getElementById(“cube”);■STEP2(canvasからWebGLコンテキストを取得)
次に、描画処理用オブジェクトとして、STEP1で取得したcanvasエレメントからWebGLコンテキストを取得します。
このコンテキストで各種描画処理や属性の設定をするため、ここでコンテキストが取得できなれけばWebGLを利用できないブラウザという事になります。
今回の場合、以下部分でコンテキストを取得しています。gl = c.getContext(“webgl”) || c.getContext(“experimental-webgl”);
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.enable(gl.DEPTH_TEST);canvasに”webgl”という名前のコンテキストを要求しますが、仕様が策定中の時は失敗してしまうため”experimental-webgl”という名前のコンテキストも要求します。(失敗時用)
その後、コンテキスト内部を初期化(clearColor)し、黒色に塗りつぶしています。
3行目のenable(gl.DEPTH_TEST)はコンテキストに深度(DEPTH)を計算(TEST)しておけよ!という命令です。
近くにあるものが遠くにあるものを隠すためにも描画の前に深度を把握しておく必要があります。サクサク進みますね。
以外と簡単なのでは?と僕もここまでは今までの知識で問題なく吸収できたのですが、STEP3から急に難しくなり髪の毛が数本抜けたのを覚えています。。。■STEP3(シェーダを生成&コンパイル)
まず3D関係の知識が無い人はここで壁にぶるつかるでしょう。
「シェーダ」ってなに?
ウィキペディア先生には以下のように記載されています。主にライティング(光源計算)・シェーディング(陰影処理)とレンダリング(ピクセル化)を実行するためにグラフィックリソースに対して使用するソフトウェア命令の組み合わせである。
「shade」とは「次第に変化させる」「陰影・グラデーションを付ける」という意味で、「shader」は頂点色やピクセル色などを次々に変化させるもの(より具体的に、狭義の意味で言えば関数)を意味する。
※wikipedia内の文章を引用難しい………
超々初心者なりに要約します(間違えていたらすいません)。
ソース内のコメントにも記載しておりますが、シェーダには大きく以下2種類のシェーダ存在します。1. バーテックスシェーダ(頂点シェーダ)
2. フラグメントシェーダ(ピクセルシェーダ)【バーテックスシェーダ(頂点シェーダ)】
3次元描画はポリゴンで表示する事が多く、ポリゴンは一般的に三角形の面をつなげたものが使われます(四角形を利用する事もあります)。
三角形が利用されるポイントは、三角形は頂点の位置さえ決めれば面の位置やサイズが確定するという点です。
四角形、五角形、、、それ以上の多角形も頂点だけでは面の位置やサイズを決める事はできません。
この頂点の位置を計算するのがバーテックスシェーダ(頂点シェーダ)です。
※バーテックスシェーダは頂点の位置情報だけ管理する訳ではなく、頂点に関する”全ての情報(頂点の法線、テクスチャ座標、頂点色など)”を管理します。【フラグメントシェーダ(ピクセルシェーダ)】
バーテックスシェーダ(頂点シェーダ)で頂点の位置や形状を決め、その後ラスタライズ(着色前準備)まで終えると、次にオブジェクトへの「着色」が必要になります。
この着色内容を計算、決定する役割を担うのがフラグメントシェーダ(ピクセルシェーダー)です。
色の計算だけであれば簡単に思えますが、これがそうでもないんです。
3次元を表現するため、陰影、深度、光源、重複(オブジェクトやテクスチャの重なり)、乗算(透過時の後ろのテクスチャ色)などを考慮した着色計算が必要です。
よって、上記のような色を計算するため、バーテックスシェーダ(頂点シェーダ)の情報が不可欠になります。
このシェーダ連携についてはSTEP6で書かせていただきます。シェーダの生成&コンパイルは以下部分で実施しています。
var shader;
var shaderElement = document.getElementById(id);
if (!shaderElement) {
return null;
}switch(shaderElement.type){
case “x-shader/x-vertex”:
shader = gl.createShader(gl.VERTEX_SHADER);
break;
case “x-shader/x-fragment”:
shader = gl.createShader(gl.FRAGMENT_SHADER);
break;
default:
return null;
}//子ノード取得
var source = “”;
var childNodes = shaderElement.firstChild;
while (childNodes) {
if (childNodes.nodeType == 3) {
source += childNodes.textContent;
}
childNodes = childNodes.nextSibling;
}
gl.shaderSource(shader, source); // ソース割り当て
gl.compileShader(shader); // コンパイル見慣れないエレメントタイプがありますね。
「x-shader/x-vertex」
「x-shader/x-fragment」JavaScriptファイルではなく、HTMLファイルのheader部分も見てみてください。
この2つのキーワードが上記で説明したバーテックスシェーダ(頂点シェーダ)とフラグメントシェーダ(ピクセルシェーダ)です。<script id=”vertex” type=”x-shader/x-vertex”>
attribute vec3 vertexPosition;
attribute vec2 vertexTexture;
uniform mat4 vertexMatrix1;
uniform mat4 vertexMatrix2;
varying vec2 textureCoord;void main(void) {
gl_Position = vertexMatrix1 * vertexMatrix2 * vec4(vertexPosition, 1.0);
textureCoord = vertexTexture;
}
</script>
<script id=”fragment” type=”x-shader/x-fragment”>
precision mediump float;
uniform sampler2D fragmentTexture;
varying vec2 textureCoord;void main(void) {
gl_FragColor = texture2D(fragmentTexture, vec2(textureCoord));
}
</script>中途半端にはなりますが…
ここから説明が一気に難しくなる&細かくなり始めるので今回のブログはここまでにします。ではでは。
カテゴリー 技術 / デザイン / 制作