ヒキダスブログ

テック系や最近見たもの感じたことを書いて残す引き出しスペースです

GLSLシェーダスクール2017を通して気づいたこと

f:id:pujoru35:20180223210019p:plain

はじめに

昨年の話になるのですが、フロントエンドの表現スキルをあげたいと思い、GLSLシェーダースクール2017に参加いたしました。
前回のブログで使っている技術である、シェーダの基礎を勉強するというもので、時系列としては逆になってしまいかつ期間も空いてしまいましたが、ここでの内容をかいつまみつつ自身の振り返りを整理しようと思いました。

GLSLシェーダスクール2017の内容

GLSLシェーダスクールのページにも記載されていたりしますが内容を整理すると、

  • WebGL開発支援サイト wgld.org, WebGL総本山の管理者doxasさんが主催の勉強会

  • 2017では10月下旬から隔週で計5回実施(5回目は年末年始を挟んで1月下旬に実施)

  • シェーダの基本文法からシェーダでできる表現の解説(なので、JSに関する解説はシェーダへの受け渡しをメインに1割くらい?)

  • doxasさん作のエディタ、webgl_editronを使って解説

  • 講義前半はdoxasさんが行い、後半の1時間を外部講師によるプラスワン講義の構成

  • 5回目では、受講生がシェーダを使って作品を作り、その発表会(WebGLに限らず、シェーダが使える環境ならOFでもTouch DesignerでもUnityでも可)

というものでした。

doxasさんは以前からWebGLやシェーダを研究し、WebGL総本山では国内海外のシェーダを使った事例の解説もされているパイオニア的存在です。

今回のゲストは、WebGLフレームワークGrimoire.jsの開発者で「独立行政法人情報処理推進機構の 2016 年度 未踏プロジェクト」にも採択された石井 翔さん、シェーダによる祭典Tokyo Demo Festのオーガナイザーを務めている佐々木 正樹さん、はてな所属のフロントエンドエンジニアでAtomのパッケージVEDAの開発をしたりVJもされている天城 孝義さんの4名でした。

実のところ、前回のシェーダスクールにも参加させていただいたのですが、理論がわかったつもりになっており、手を動かしてシェーダを操るレベルに至らなかったのです。受講生が作品を提出し発表会をするというのが今回初の試みでもあり、もう一度シェーダに理解と実践両面から関わりたいという思いと発表というアウトプット機会を作れると感じ再度参加することにいたしました。

以下、前半講義を中心に要所をかいつまんで残してみました。

第1回 GLSL とはなにかを知ろう

初回は、まずシェーダやWebGLの概論から、描画されるまでの処理フローをメインに学びました。シェーダは「GPUを利用し高速なグラフィック描画を行う技術・概念の総称」であり、シェーダを扱うには、DirectXOpenGLといったGPUを利用できるAPIが必要になります。
WebGLOpenGL ES 2.0を踏襲しており、OpenGL系でブラウザから制御できるようにしたものです。
処理フローも、シェーダのソースコードコンパイルし、それをGPUにアクセスできるプログラムオブジェクトとリンクづけることで動かすことができます。
かなり端折ってしまいましたが、詳細は WebGL開発支援サイト wgld.orgに詳しく解説されているのでそれを参考にすると良いと思います。
なので、この回はこうした用語や概念の説明と仕組みのお話、実サンプルでは板ポリを作って色をつけたり、マウスに応じて変形するものを扱いました。プラスワンではdoxasさんが担当し、光のオーブを表現したり、ラインを描く際の実装を解説頂きました。

第2回 頂点シェーダの基本と使い方を知ろう

第2回では、WebGLで扱える2種類のシェーダの一つ、「頂点シェーダ」にフォーカスした講義でした。頂点といっても、3次元空間上の点をディスプレイのような2次元で描画することから「座標変換」を行う必要があり、その処理の過程で行列を用います。そうしてディスプレイに投影した頂点を三角関数を使って動かしたり、画像(テクスチャ)を読み込み頂点や頂点で構成した板ポリに貼り付けるところをやりました。

第2回プラスワン講義では、前述の石井 翔さんが担当されました。GPUと行列をテーマに話され、GPUSIMD命令が使えかつCPUに比べコア数が多いことからグラフィック処理に使える点、行列は演算処理を便利にしたものに過ぎない点とあまり意識出来てなかった点を掘り下げた話題で興味深かったです。

第3回 フラグメントシェーダを使いこなそう

第3回は「フラグメントシェーダ」をテーマにした内容でした。特に、頂点・フラグメントで描画した結果を一時的に保持しそのテクスチャをもとにフラグメントシェーダで加工する「ポストプロセス(ポストエフェクト)」の話題が主でした。ちょっとイメージつきにくいかもですが、インスラグラムにあるようなフィルタ機能のようなものと考えれば良いかと。
ポストプロセスの概要から、具体的にどういう表現ができるのか、乱数を使ったノイズ処理やナイトスコープ(緑色の色調でTVのような走査線が走るエフェクト)、モザイクを題材に実装の解説をいただきました。

プラスワン講義は佐々木 正樹さんが担当で、この回のテーマであるフラグメントシェーダに絡めて、組み込み関数を理解しリファレンスをよく読んでおくこと、絵が出なかったり他者からのシェーダソースを使ったがうまく表示されない時のトラブル対処法、エフェクトを組み合わせる時の考え方だったりと、JSと違ってデバッグがしづらいシェーダで陥りがちなポイントや、一歩進めた表現のアプローチとこと細かく解説がなされていて勉強になりました。

第4回 ハイレベルなシェーダテクニック

この回では全体的に特殊で高度な内容でした。まず、「擬似ディスプレースメント」について。3DCGではテクスチャに応じて頂点の座標を動かし凸凹の質感を作る「ディスプレースメントマッピング」と言うものがありますが、doxasさんが呼んでいる擬似ディスプレースメントは、頂点座標を動かさずテクスチャの色味を係数として捉えテクスチャ座標をずらすことで立体的に見える手法を解説しました。次に、パノラマ画像を極座標変換させてTHETAのような全天球画像にしてみたり、GPUをグラフィック用途だけでなく汎用的な演算にも活用し座標移動をGPUで行わせる「GPGPU」の概念や仕組みの解説もありました。正直GPGPUは今も自分にとって扱える代物ではないですが、いつか挑戦したい領域でもありどうやって実現しているのか中身のロジックを理解することができただけでも貴重な経験でした。それから、レイ(光線)を飛ばして閾値に入るものを塗りつぶす処理のレイトレーシングの解説もあったりと、シェーダ表現でも一歩踏み込んだ説明が聞けました。

最後のプラスワン講義は、天城 孝義さん。天城さんはwgld.orgからシェーダについて覚え、シェーダを使ってライブコーディングVJをしたいということで前述のパッケージまで作ったお人です。講義ではVEDAのインストールから操作方法をレクチャーいただきました。かなり機能が盛り込まれていて、標準でそのままVJに持っていけそうな感じでしたし、こちらもゆくゆく触って覚えていこうと思います。

第5回 作品発表

最終回は、事前にdoxasさんに作った作品をファイル添付あるいはURLで送付し、それをdoxasさんのマシンで投影し各人発表してもらう形式でした。
最初はフラグメントシェーダのみで作ったものをdoxasさんに提出しましたが、改めて本スクールを通してチャレンジしてみたかったことに挑戦することにしました。

以下、提出した作品になります。

https://qeita.github.io/motion/js/001/

やってみたかったのは、頂点シェーダで3Dの物体のあるべき形状を歪ませたりできないかというものでした。生のWebGLだとオブジェクトを作るのに多数のポリゴン作って組み合わせたりと骨が折れるため、Three.jsを使うことにしました。

THREE.FontLoaderで日本語・英語の2種フォントを読み込み、メッシュを作っています(初期表示は日本語)。左右矢印キーあるいはメッシュ自体をクリックすると、文字が切り替わって行き、上下矢印キーで日英フォントを切り替えることができます。

文字のメッシュを歪ませている処理は、以下頂点シェーダのところで行っています。
元の位置であるposition.x, position.y, position.zを基準に、乱数(rand(xxx))と原点からの距離(len(xxx))と時間を三角関数でラップしたものとuniform変数sizeを掛け合わせたものを加算しています。
x, y, z軸にそれぞれ同じ値を加算すると、x/y/z軸方向に単純な平行移動になってしまうため、各頂点の座標に応じて加算する度合いを変える必要がありました。

ちなみに、uniform変数sizeは、文字が切り替わるタイミングでJS側でランダムに可変値をセットし、それに応じて変わったタイミングで頂点をグニャグニャ動かす度合いも変化させています。

uniform float time;
uniform float size;
varying float vTime;

float rand(vec2 co){
  return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
}

float len(vec2 posiiton){
  float len = length(position);
  return 200.0/len;
}

void main(){

  vTime = time;

  gl_Position = projectionMatrix * modelViewMatrix * vec4(
    position.x + rand(vec2(sin(time)) * position.xy) * len(position.xy) * cos(time) * size,
    position.y + rand(vec2(cos(time))) * len(position.xy) * sin(time) * size,
    position.z + 0.1 * len(position.xy) ,
    1.0
  );
}

メッシュのフラグメントシェーダは、シンプルに時間に三角関数に入れ込んで動的に色が変わるように、背景の平面も乱数を使ってざらついた見栄えにしました。

感想・振り返り

今回参加したことで以下4つの気づきを得ることができました。
最後のは個人的見解が強いのですが、自身の振り返りということで乗せてみました。

  • シェーダはコードベースなので直感的でない

  • 意図した通りの動きになるものでもないのでトライ&エラーの繰り返し(偶然を楽しむ)

  • 生のWebGLを書く利点(処理フローの理解、ファイルサイズ、ライブラリの記述・バグ)

  • シェーダ単体だと「表現のクセ」が出るので、複合的な組み合わせで違う角度からの演出・表現を狙う

まず1点目はシェーダのソースを見たことや書いたことがある方ならいわずもがなかもしれません。JSと違って、三角関数やベクトル、組み込み変数を多用して作るものによって何をやっているのかわからなかったりします。 ただ、その複雑性と高度性が表現系エンジニアとしてのアドバンテージや領域になるのではないかと感じました(一方で、クリエイティブからのリクエストとシェーダの複雑性に苛まれる可能性もあります)。

2点目は、第3回プラスワン講義の佐々木さんが仰っていた点とも同じになるのですが、先の複雑性からちょっと数値が変わるだけで全く違う見た目になることもあります。それにより、完全に意図した通りの見た目・動きにならなかったりするので試行錯誤の連続になる感じです。一方で、パラメータによって変わる偶然性を楽しんだりしてモチベーションの維持やアレンジの創出につなげる必要があります。

3点目は、本スクールではThree.jsは一切扱わず、WebGLで一から書かれたサンプルをベースに進めました。抽象化され多機能なThree.jsに頼りがちなところですが、逆に生で書くことの利点もいくつかあります。
まずは、一から書くことでどういう仕組みでGPUにデータを渡しているのか理解につながりやすいかと思います。Three.jsはそこまで意識せずに作れるところがありますが、WebGLの根幹を把握しておくと今後のWebGL自体のバージョンアップでも応用が利きそうではあります。
次に、Three.jsは色々できる反面ファイルサイズが大きくなりがちなところが挙げられます。本体だけでなくモデルデータを読み込んだりポストプロセス用のファイルを読み込んだりするとチリも積もって数MBになることもあります。スクラッチWebGLを書くと、余計な処理を除くことで軽量化が望めると思われます。実際講義で使ったポストプロセスのサンプルも50KB足らずだったりしました。ただ大量のテクスチャや多様なオブジェクトを扱うとその限りではありませんが、板ポリで表現するようなものであればThree.jsを使わない方がパフォーマンス的にも優しいかと考えます。逆に、沢山の3Dオブジェクトや文字を扱ったりと言ったものだと、多機能なThree.jsがいいでしょうし、そこはスクラッチとThree.jsの両方をフレキシブルに扱えるようになると強いかなという印象です。
それから、Three.jsに限らず、ライブラリはバージョンアップに伴いこれまで使えたAPIが使えなくなったり、記述が変わったりします。また、特定のブラウザでのバグが出ることもあり、ライブラリに左右されない書き方をするなら生でWebGLを書くと良いように思われます。デメリットとしては、Three.jsで調べるよりもWebGLで調べる方が思った記事に行き着かないかもですので、佐々木さんの講義にもあったようにkhronosが公開している組み込み変数やリファレンスを見ておくのが良さそうです。

4点目は、GLSL Sandbox を見て思ったことですが、シェーダだけだとかつてBootstrapで作ったサイトのように「表現のクセ」が出やすいように見受けられました。勿論パーティクルをギュルギュル動かしたインパクトある表現もあるのですが、単一のGUIや表現に絡む技術だけ扱うと、多少なり「クセ」は出てしまうものかなと。。多分Three.js単体で使ってもプリミティブなオブジェクトがバラバラでてるだけでThree.jsのクセが出てしまいそうではあります。ある種既視感に似たものでしょうか。

なので、Three.jsなりフォントなり違う領域のものと組み合わせることで、演出や表現に変化をつけることでオリジナリティにもつながりそうではないでしょうか。そういう意味でも、第5回発表会で発表された寺田 佳央さんのサイトがそういうアレンジ性がすごかったなと感じました。
Three.jsベースですが、テクスチャを貼り付けたり、ポストプロセスで歪ませたりとアーティステックな表現が興味深かったです。

長々となってしまいましたが、以上シェーダスクールで行ってきたことの振り返りです。
これから毎日...は難しいでしょうが、シェーダをガシガシ書いていこうと思います。