WebGLによる2Dグラフ描画【その1】
グラフ描画アプリ作成の第一歩としてグラフ描画部分について学びます。
2Dのグラフ描画なのにWebGLを使います。WebGLと言えば3Dの高速・美麗な描画ですが、2Dでもその高速な描画は活きてきます。ちなみに、WebGLでつくられた3Dがどんなものかということが分かる例は以下の記事を覗いてみるといいかもしれません。
【記事1】
liginc.co.jp
先ずはWebGLとな何かについては以下の記事を見ていくと分かると思います。
【記事2】
webglfundamentals.org
【記事3】
wgld.org
ただし、これを読んだからといって直ぐにグラフアプリが作れるかと言われれば私には無理です。
と言うことで、実例と基礎を行ったりきたりして動くものを自分で作れるようになるために以下記事を参考としました。
【記事4】
qiita.com
【記事5】
wordpress.notargs.com
【記事6】
www.youtube.com
【記事7】
github.com
【記事8】
qiita.com
【記事9】
qiita.com
【記事10】
medium.com
このあたりを見比べて作ったのが以下のコードです。
フォルダ内は以下3つのファイルだけでとりあえず動きます。
【ソースコード1:index.html】
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>WebGL</title> <meta name="Description" content="" /> <meta name="Keywords" content="" /> <link rel="stylesheet" type="text/css" media="screen,print" href="style.css" /> <script id="vs" type="x-shader/x-vertex"> attribute vec3 position; void main() { gl_Position = vec4(position, 1.0); gl_PointSize = 5.0; } </script> <script id="fs" type="x-shader/x-fragment"> precision mediump float; void main() { gl_FragColor = vec4(0.0, 1.0, 1.0, 1.0); } </script> <script type="text/javascript" src="index.js"></script> </head> <body> <canvas id="sin"></canvas> </body> </html>
【ソースコード2:index.js】
var c, gl; function initWebGL() { c = document.getElementById("sin"); c.width = 200; c.height = 200; gl = c.getContext('webgl') || c.getContext('experimental-webgl'); } function initShaders() { var p = gl.createProgram(); var v = document.getElementById("vs").textContent; var f = document.getElementById("fs").textContent; var vs = gl.createShader(gl.VERTEX_SHADER); var fs = gl.createShader(gl.FRAGMENT_SHADER); gl.shaderSource(vs, v); gl.shaderSource(fs, f); gl.compileShader(vs); gl.compileShader(fs); gl.attachShader(p, vs); gl.attachShader(p, fs); gl.linkProgram(p); gl.useProgram(p); gl.bindAttribLocation(p, 0, "position"); gl.enableVertexAttribArray(0); } function draw(t) { gl.clearColor(0.0, 0.0, 0.0, 1.0); gl.clear(gl.COLOR_BUFFER_BIT); var data = []; var MAX = 20; // データ列の生成 for ( var i = 0; i <= MAX; i++ ) { var x = 0.9 * (2 * i / MAX - 1.0); var y = 0.9 * (Math.sin(2 * Math.PI * i / MAX + t * Math.PI)); data = data.concat([x, y, 0.0]); } // 空バッファオブジェクト生成 gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer()); // シェーダー側の変数をjs側で受け取る gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0); // 描画 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(data), gl.STATIC_DRAW); gl.drawArrays(gl.LINE_STRIP, 0, data.length / 3); gl.drawArrays(gl.POINTS, 0, data.length / 3); // 更新 gl.flush(); } // 時間を計測開始 var startTime = Date.now(); onload = function(){ initWebGL(); initShaders(); setInterval(function(){ // 経過時間を取得 var totalTime = (Date.now() - startTime) / 10000.0; draw(totalTime); }, 10); }
* { margin: 0; padding: 0; border: 0; overflow: hidden; } body { background: #fff; font: 30px sans-serif; }
index.htmlを起動するとこんな感じになります。
【画像1】
うねうね動きます。上記ファイルではhtml中でscriptとして頂点シェーダとフラグメントシェーダのソース定義しています。html中にあまりごちゃごちゃ書きたくないので、javascripファイルのほうに詰め込もうと【記事10】にあるいかの記述をそのまま使えば良いかなと試してみたのですが、うまく動きませんでした。
【ソースコード4: 記事10の参考】
var fSource = [ “precision mediump float;”, “void main(void) {“, “gl_FragColor = vec4(“+ rgba.join(“,”) +”);”, “}” ].join(“\n”)
ちなみにこんな感じで書いてみました。
【ソースコード5: vs】
var vs = [ "attribute vec3 position;", "void main(void) {", "gl_Position = vec4(position, 1.0);", "}" ].join("\n");
【ソースコード6: fs】
var fs = [ "precision mediump float;", "void main(void) {", " gl_FragColor = vec4(0.0, 1.0, 1.0, 1.0);", "}" ].join("\n");
これをもともとのjsファイル中のvの代わりにおいてhtmlファイル中の該当箇所を削除してみると上手くいきません。彷徨っていると良い記事を見つけました。
【記事11】
qiita.com
Jadeとか良く分からないのでパス。
【記事12】
WebGL シェーダをどこに置くか? - code snippets
色々とみて、最終的にこんな感じになりました。ちなみにhtmlとjs中でエレメントのidをsinからcanvasに変更しました。
【ソースコード7】
var c, gl; function initWebGL() { c = document.getElementById("canvas"); c.width = 200; c.height = 200; gl = c.getContext('webgl') || c.getContext('experimental-webgl'); } function initShaders() { // programオブジェクトを作成 var p = gl.createProgram(); // シェーダーを作成 var vs = gl.createShader(gl.VERTEX_SHADER); var fs = gl.createShader(gl.FRAGMENT_SHADER); // シェーダーのソースコードを定義 var vSource = 'attribute vec3 position;' + 'void main(void) {' + 'gl_Position = vec4(position, 1.0);' + 'gl_PointSize = 5.0;' + '}'; var fSource = 'precision mediump float;'+ 'void main(void) {' + 'gl_FragColor = vec4(0.0, 1.0, 1.0, 1.0);' + '}'; // シェーダーにソースコードをセット gl.shaderSource(vs, vSource); gl.shaderSource(fs, fSource); // コンパイル gl.compileShader(vs); gl.compileShader(fs); // programオブジェクトのシェーダーを設定 gl.attachShader(p, vs); gl.attachShader(p, fs); // programのリンク gl.linkProgram(p); // programの割り当て gl.useProgram(p); gl.bindAttribLocation(p, 0, "position"); gl.enableVertexAttribArray(0); } function draw_line(t) { gl.clearColor(0.0, 0.0, 0.0, 1.0); gl.clear(gl.COLOR_BUFFER_BIT); var data = []; var MAX = 20; // データ列の生成 for ( var i = 0; i <= MAX; i++ ) { var x = 0.9 * (2 * i / MAX - 1.0); var y = 0.9 * (Math.sin(2 * Math.PI * i / MAX + t * Math.PI)); data = data.concat([x, y, 0.0]); } // 空バッファオブジェクト生成 gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer()); // シェーダー側の変数をjs側で受け取る gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0); // データ列描画 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(data), gl.STATIC_DRAW); gl.drawArrays(gl.LINE_STRIP, 0, data.length / 3); gl.drawArrays(gl.POINTS, 0, data.length / 3); // 更新 gl.flush(); } // 時間を計測開始 var startTime = Date.now(); onload = function(){ initWebGL(); initShaders(); setInterval(function(){ // 経過時間を取得 var totalTime = (Date.now() - startTime) / 10000.0; draw_line(totalTime); }, 10); }
これでとりあえず動くようになりました。
ここから目盛を追記しようと思ったのですが、基礎知識が足りないので複数のモデルを描画する方法がよくわかっていません。
次回は二つのモデルを描画する方法について簡単なものを作ってみたいと思います。
ロボット
ずっと気になっているBoston dynamicsのロボ達。特にAtlasの進化が素晴らしいです。
と思ったらオレゴン大学でもなかなか面白そうなロボを開発していました。またラボが素晴らしいですね。全部ラボで出来そうなのがいい。
日本はロボ開発としてどの程度の開発レベルなのかあまり調べもせずに批判したくはありませんが、こういうロボの話がいろいろと出てくると良いなぁ…。
結局、精密かつ安全な歩行というよりは転ぶの前提な歩行アルゴリズムのほうが自然な歩行を可能とする訳ですね。
あくまでも歩くことを完全にするのではなく、進むことの安定性をどうやって二足というツールで実現するかということですね。本質を見直すと案外いまやっていることって着想ズレてない?ということはよく見かけますね(笑)自分のプロジェクトでも気をつけねばなりません。
ラボの様子を見てふと思い出したのは下記記事
上記に関連して話は多少ズレますが、パナソニックが面白いアクチュエータを開発していました。
いままでケーブル関係は間接ロボのボトルネックでしたが、こういったものがあると枷がなくなりいろいろと自由度が高くなります。どの程度の実用性があるのか気になるところですが29日から展示会やっているのか…行きたい…けれど新商品の開発を急いでやらなければならないので難しいかな。
以上、気になるテクノロジの最近でした。
wk1747の成績
いつも季節の変わり目で去年はどんな服で乗り切っていたのか不思議になります。
もう少し長く着られる服を選ばなければ…。
ということで、遅れ馳せながらwk47の成績は以下の通りです。
ブログ
時々アクセス数が急激に伸びる日があるのですが何なのでしょうか(笑)いずれにせよ見てくださる人が増えるのは良いことです。
しかし、最近あまり記事を更新できていません。色々とネタはたまっているのですがまとめる時間が…そもそも本ブログは自分の備忘録用の意味合いが強いので、まとめなくて困るのは自分!早速しばらく前にやっていたことを再開するとどうやってたんだっけとなることがしばしばあります。
そうならないためにしっかりと記事にしていきたいと思います。
投資
株
ペッパーFSが膠着状態です。力の源HDに資金を移そうとした2日間20%前後の伸び…出遅れました。優位性が下がってしまいましたが、新宿一蘭の外国人による込み具合は凄まじく、とんこつラーメンは日本食として人気があります。
ペパーFSは今週膠着から変化が生じる可能性があるので少し様子を見てキャッシュ比率の引き上げを慎重に判断したいと思います。
暗号通貨
もはや完全に放置状態なのですが、ついにビットコインが100万円突破しましたね。ビットフライヤーに残っている雀の涙ほどのビットコイン資産で美味しいご飯が食べられるくらいになっていて驚きました(笑)
株のほうがモチベーションと投資活動としてのモチベーションが高いので、暗号通貨は技術動向がどうなるかといった興味のみに留め、特にはアクションをおこしません。
SIGMA 135mm F1.8 DG HSM
ようやく追加レンズ第一号を購入しました。そのレンズとはタイトルのこちら。
artレンズの評判が良いみたいで予てより気になっていたものです。
ヨドバシの店頭で85mmと135mmでとても悩んだのですが、今まで使っていたSP 24-70mm F/2.8 Di VC USD (Model A007)の焦点域と近いため作風を変えるという意味では135mmにチャレンジしてみることにしました。もちろんズームレンズと単焦点レンズ比べるのはナンセンスですが、細かい差よりも大きな差を気にするレベルなのでよいかと。
試しに家の近くを散歩したときの景色を撮ってみました。
開放で撮ろうと思ったのですが、被写体の奥行き方向に物が無くて遠近感が不自然になるのでf5.6で撮りました。また、あと30分くらい早ければ夕日が綺麗に差していたのですが、一歩遅く暗い感じになってしまいました(笑)
こちらも同じくf5.6。最近ボケさせれば正義というわけではないなというのを実感しています。
自分でカメラを本格的に始める前から不自然なボケをもつ写真は好きではなかったので、自分の作品でも自然でありながら被写体に印象の重点がある写真を目指して行きたいと思います。ライティングに関しても雰囲気を出すにしても違和感は出さないようにしたいところです。
デメリットを挙げておくなら、この焦点距離は屋内で使うにはハンドリングが難しいかもしれません。なぜなら人の全身を入れるために被写体との距離を相当とらなければならないためです。
いろいろと工夫していきたいと思います。
次は広角域の単焦点かな。
wk1746の成績
朝夕寒くなりましたが、まだまだ晴れた日の日中は暑いですね。晴れた日は爽やかで良いのですが、日差しが眩しいです。眩しいのが苦手なのでよくサングラスをかけていますが、最近はキャップも買ってみました。帽子が自分としては似合わないなと思いつつも、被ると似合うじゃんと言われるのでおかしくはないのでしょうから今後は被ってみたいと思います。
と言うことで今週の結果は以下の通りです。
ブログ
最近記事の更新数が減ってしまっています。本業の方が忙しく、なかなかほかの事をやっている時間を確保するのが難しくなった結果です。
自分のためにも色々な知識はまとめて記事としておきたいので、そのうちぽこぽこ理系記事を書きます。
また、近々ポートレート撮影をさせて頂けることとなったのでそれ自体を掲載するかは別として写真周辺の記事も書きたいところです。
あと、アクセス解析の画像を見ると100以上のアクセスとなる日が突然あるのですが、これって何かシステムの障害なのでは!?と思うような挙動なのです。一日のうちで時間帯がバラけていればまだ分かるのですが、時間もある1時間内で70アクセスとかきているので違和感しかありません。
そこまでアクセス数は気にしていないのですが、何が起きているのかは気になります(笑)
投資
ペッパーは停滞、他二つは落ちてしまいました。そろそろペッパーは半分くらい利確して多銘柄に切り替えたいところです。
候補は以下の通り。
力の源HD
日本セラミック
ローツェ
あとはもう一度四季報を見直してみて面白そうなのがあればピックアップして経営・財務・ときめきを確認しておきたいと思います。