WebGL シェーダをどこに置くか?

最終更新日30 May 2017 01:03

stringとして置く

Three.jsだとjavascriptの中にstringとしておいています

var VSHADER_SOURCE =
         " attribute vec3 a_Position;\n" +
            " void main(void) {\n" +
            " gl_Position = vec4(a_Position, 1.0);\n" +
            " }\n";

シェーダのコード1つ1つが短い場合はこれでもいいかもしれないけど、
この方式はあとで修正したりが面倒だし、正しくシンタックスハイライトしないので見づらいという欠点があります。

バックスラッシュを使って改行する

var VSHADER_SOURCE = "attribute vec3 a_Position;\
             void main(void) {\
             gl_Position = vec4(a_Position, 1.0);\
             }";

こういうやり方でも動いた。
]\n" +」の代わりに「\」です。
打ち込む文字が1行ごとに3文字減りますね!

もっと減らせる。。!テンプレート文字列を使う方法

シェーダコードをバックティック文字`で囲みます。

var v =`attribute vec3 a_Position;
  void main(void) {
  gl_Position = vec4(a_Position, 1.0);
  }`;

これはもう完璧heredocですね!
テンプレート文字列とは?

<script>タグ内に書く方法

<script id="shader-vs" type="x-shader/x-vertex">
attribute vec3 a_Position;
             void main(void) {
             gl_Position = vec4(a_Position, 1.0);
             }
</script>

そしてjavascript側で取り出すとき
 var vertsrc =  document.getElementById("shader-vs").innerHTML;

あるいは
 var vertsrc =  document.getElementById("shader-vs").textContent;

<script>タグ内でシェーダコードをかけば、ページにシェーダコードは表示されません。
もしページにシェーダコードを表示したかったら<pre>タグを使えばok.
改行した状態で表示されます。

シェーダコードを外部ファイルから読み込む

外部といっても同じドメインのファイルです。
もしシェーダコードが何千行と膨大になってしまった場合は、シェーダコードを別のファイルにしたい。
そんな時はHttpRequestです[3]]
下のコードではためしに頂点シェーダだけ外部テキストで読み込んでます。

function main() {
     canvas = document.getElementById("webgl");
    var gl = getWebGLContext(canvas);//cuon-utils.jsより
    var shaderurl ="http://miffysora.wdfiles.com/local--files/webgl-where-to-put-shader/simplestvs.glsl";
    var request = new XMLHttpRequest();
    request.open('GET', shaderurl , true);
    request.onreadystatechange = function () {
        if (request.readyState == 4 &&request.status == 200) {
               var v=request.responseText;
               var fragmentsrc =document.getElementById("shader-fs").textContent;
               initShaders(gl, v, fragmentsrc);
              var n =  initGeometry(gl);
              display(gl,n);
            } else {
                console.log("Failed");
            }
    };
    request.send(null);
}

頂点シェーダとフラグメントシェーダと2つ外部テキストとして読み込むには。。?未調査です。
が、StackOverfrow[3]に英語で詳しく書いてあります。

demo

<script src="https://rawgithub.com/mrdoob/three.js/master/build/three.js"></script>
<script src="https://code.jquery.com/jquery.min.js"></script>
<script type="x-shader/x-fragment" id="fshader">
uniform vec3      iResolution;           // viewport resolution (in pixels)
uniform float     iGlobalTime;           // shader playback time (in seconds)
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec2 uv = fragCoord.xy / iResolution.xy;
    fragColor = vec4(uv,0.5+0.5*sin(iGlobalTime),1.0);
}
void main(){
    mainImage(gl_FragColor,gl_FragCoord.xy);
}
</script>
<script>
downloadShader('http://miffysora.wdfiles.com/local--files/vertex-shader/uv-vertex-shader.glsl'); 
function downloadShader(url)
{
    $.get( url,init);
}
 
function init(vertshaderdata){
console.log(vertshaderdata);
    var width=500;
    var height=281;
    var scene = new THREE.Scene(); 
    var camera = new THREE.OrthographicCamera ( -1.0, 1.0,1.0, -1.0, 0.1, 2000 )
    camera.position.z = 5;
 
    var renderer = new THREE.WebGLRenderer({ alpha: true ,antialias:true});
    renderer.setClearColor( new THREE.Color(0x000000),0.0);//背景色
    renderer.setSize(width, height);
    document.body.appendChild(renderer.domElement); 
    var geometry =  new THREE.PlaneGeometry( 4, 4, 10, 10 );
var material = new THREE.ShaderMaterial({
        vertexShader: vertshaderdata,
        fragmentShader: document.getElementById('fshader').textContent,
        uniforms:{
          iResolution:{value: new THREE.Vector3(width,height,1.0) },
          iGlobalTime:{value:0.1}
        }
      });
    var cube = new THREE.Mesh(geometry, material);
     cube.needsUpdate =true;
    scene.add(cube);
 animate();
function animate() {
cube.material.uniforms.iGlobalTime.value += 1.0/60.0;
        requestAnimationFrame( animate );
renderer.render( scene, camera );
}
}
</script>
</body>

.glslで書いてnpmでビルドする

Threejsのような巨大なライブラリではこの方法をとっているようです。
npmはNode.jsをインストールすると使えるようになりました。
roll-upというやつも必要。

npm run build

というコマンドを実行すると、rollup.config.jsファイルに書いてある命令により、
.glslのファイルを一つの.jsファイルに文字列化して埋め込んでくれるという仕組みのようです。


threejs-shader


ファイル

サポートサイト Wikidot.com threejs-shader