メニュー

PlayCanvasにGLSL Sandboxのシェーダーアートを持ち込んでみた

2016年12月10日 - PlayCanvas, 作った
PlayCanvasにGLSL Sandboxのシェーダーアートを持ち込んでみた

この記事は WebGL Advent Calendar 2016 の12日目の記事です。

はじめに


先日GLSL WebGLの勉強会に参加させていただきまして、そこで初めてGLSLに触りました。
まだ慣れるには時間がかかりそうですが、ガッと表現力をあげれるシェーダーの力はぜひ身に着けたいところです。

そこで今回はGLSLの基本文法の復習がてら、GLSLのシェーダーアートをPlayCanvasに持ち込むまでを紹介したいと思います。

PlayCanvas


すべてWeb上で動作するWebGLのゲームエンジンです、ビジュアルエディタがあるので普段はグラフィックスやシェーダー等を意識することはあまりありません。

PlayCanvas

GLSLSandbox


いわずと知れたWebGLのシェーダアートが閲覧、投稿できるWebサイトです。
すべての作品のコードはすべて見ることができて、参考にできたり複製したりできるのが特徴的ですね。

GLSL Sandbox

 

下準備


PlayCanvasでプロジェクトを新規作成します。
余計のものを消して、カメラいっぱいに一枚の板ポリが写るように調整します

こんな感じ
実行すると板ポリが画面いっぱいにレンダリングされてると思います。

今回はこの板ポリにシェーダーを適用していきます。

スクリプトの用意


WebGLの開発は主に

で構成されており、それぞれにそれぞれの役割があります。
今回扱うシェーダアートではピクセルの色情報をつかさどるFragment Shaderがとても重要です。
まずそれらを制御するスクリプトをPlayCanvas上で作っていきます。

PlayCanvas上のシェーダではmouse, resolution, timeといったGLSLSandboxで標準的に入っているuniform変数が用意されていないので、PlayCanvasのAPI経由で値を取得してから、シェーダーにsetParameterメソッドで渡してあげる必要があります。
コード抜粋

//in initialize method
this.app.mouse.on(pc.EVENT_MOUSEMOVE,this._m,this); //マウスイベント時のコールバックメソッドを宣言
    if(this.app.touch){
        this.app.touch.on(pc.EVENT_TOUCHMOVE,this._m,this);//ついでにタッチイベントも
    }
    
    this.reso = new pc.Vec2(window.innerWidth,window.innerHeight);//resolution取得

また、GLSLとJavaScriptでは座標系が違うため、y座標の向きを変えてあげる必要があります。

Customshader.prototype._m = function(ev){//マウス及びタッチ時のコールバック
    if(this.app.touch){//タッチ座標を渡す
        this.material.setParameter('m_x',ev.changedTouches[0].x/this.reso.x);
        this.material.setParameter('m_y',(this.reso.y - ev.changedTouches[0].y)/this.reso.y);
    }
    else
    {//マウス座標を渡す
        this.material.setParameter('m_x',ev.x/this.reso.x);
        this.material.setParameter('m_y',(this.reso.y - ev.y)/this.reso.y);    
    }  
};

timeはupdate内で加算して渡します。
resolutionは実行中のcanvasサイズ変更に備えupdateメソッド内で毎フレーム渡します。

Customshader.prototype.update = function(dt) {
    this.time += dt;
    
    this.reso.set(window.innerWidth,window.innerHeight);
    
    this.material.setParameter('time',this.time);
    this.material.setParameter('reso_w',this.reso.x);
    this.material.setParameter('reso_h',this.reso.y);
};

 

シェーダーの用意


スクリプトが書き終わったらシェーダーを書き始めます。
PlayCanvas上でシェーダが作成できるので、Vertex Shader, Fragment Shader用それぞれ1つずつ作ります。

つくったらこの2つを先ほどのスクリプトにattribute経由で渡してあげます。

 

シェーダーの記述


今回はGLSLSandboxの移植なのでVertex Shaderはサンプルから特にいじる必要はありません。

FragmentShaderも基本的には同じですが、JavaScriptで渡したいくつかのuniform変数を受け取り、使える形にする必要があるため最初の部分だけ以下のように追記します。

varying vec2 vUv0;

uniform float reso_h;
uniform float reso_w;
uniform float m_x;
uniform float m_y;

vec2 mouse = vec2(m_x,m_y);
vec2 resolution = vec2(reso_w,reso_h);
uniform float time;

void main(){...}

 

移植

ここまでできたらGLSL SandboxからGLSLのコードをPlayCanvasのFragment Shaderにコピペして実行します。
このときmouse,resolution,timeは既に宣言してあるので消してしまって大丈夫です。
 

完成!


GLSL Sandboxのハローワールドをパブリッシュしてみました。

なかなかきれいに写りました、インタフェースもタッチが対応できるようになってるので手軽にシェーダアートをデモるにはちょうどいいのかも。

 

余談


PlayCanvasでのレンダリング結果をテクスチャとして受け取って、オフスクリーンレンダリング的なことをしてシェーダ適用したアウトプットを出力、みたいなこともできました

デフォルト

セピア

トゥーンシェーダーみたいな感じにしたかったけどできなかったやつ

シェーダーの知識や技術が今後必要そうになるので、これをきっかけに始めて行きたいと思います。

 

リンク(成果物)


GLSLSandbox to PlayCanvas
オフスクリーンレンダリング

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA