先頭にコピペするだけ!Shadertoy → GLSL Sandbox / NEORT の移植用ヘッダーコードの紹介

ShadertoyのコードをGLSL Sandboxに一発で移植するコードを思いつきました。

以下のコードをShadertoyのコードの先頭にコピペするだけで、元のコードには一切手を加えずにGLSL Sandbox用のコードに変換できます。

// BEGIN: shadertoy porting template
// https://gam0022.net/blog/2019/03/04/porting-from-shadertoy-to-glslsandbox/
precision highp float;

uniform vec2 resolution;
uniform float time;
uniform vec2 mouse;

#define iResolution resolution
#define iTime time
#define iMouse mouse

void mainImage(out vec4 fragColor, in vec2 fragCoord);

void main(void) {
    vec4 col;
    mainImage(col, gl_FragCoord.xy);
    gl_FragColor = col;
}
// END: shadertoy porting template

Shadertoyのマルチパスやテクスチャ機能をつかったShaderの移植はできませんが、普通の1パスのShaderなら移植できると思います。

ぜひ使ってみてください!

Shadertoy → NEORT の移植事例

最近、NEORTという国内産Shadertoyのようなサイトが登場しました。

NEORTはGLSL Sandbox互換があるので、ご紹介した方法で一発でShadertoyから移植できました。

解説

なぜこれでうまく移植できるのか、簡単に解説します。

uniform名の違いの吸収

まず以下のコードでShadertoyとGLSL Sandboxのuniform名の違いの吸収しています。

単純に #define のプリプロセッサで置換しているだけなので、特に不思議なことは無いと思います。

uniform vec2 resolution;
uniform float time;
uniform vec2 mouse;

#define iResolution resolution
#define iTime time
#define iMouse mouse

エントリーポイント名の違いの吸収

Shadertoyのエントリポイントは mainImage で、GLSL Sandboxは main です。

が、よく考えてみると、ShadertoyもWebGLで実装されているからにはGLSLのルールに従って main が定義されているはずです。

Shadertoyのソースコードを眺めてみると、mainImage を呼び出す main 関数をヘッダーとして挿入する実装になっています。

void main(void) {
    vec4 col;
    mainImage(col, gl_FragCoord.xy);
    gl_FragColor = col;
}

この「mainImage を呼び出す main を定義する」というアイデアはkanetaさんのこの作品からヒントをもらいました!

次はコンパイルエラーを避けるための前方宣言です。

void mainImage(out vec4 fragColor, in vec2 fragCoord);

GLSLではC言語と同様に、別の関数から呼び出される前に関数を定義するか、前方宣言する必要があります。

comments powered by Disqus

gam0022.net

Qiita