ウチツクシ

やったゲームのこと(大体STG)とか作ったゲームのこと

Effector TV

ワンライナー255byteのシェーダプログラムでグラフィックを楽しむツールです。
作ったコードをアップロードして共有することもできます(最新30まで)。

f:id:K-s:20141102083953j:plain:w240

HSPプログラムコンテスト2014 HSPTV部門に応募しました。
http://dev.onionsoft.net/seed/info.ax?id=918

ソースコードは以下より。
https://github.com/skymonsters-Ks/Effector-TV

動作環境

HSPTVブラウザが動作するWindows + OpenGL2.0以上対応環境。
制作・動作テスト環境は Windows7 64bit / GeForce GTX 650 Ti です。

操作方法

Enter      : プログラム実行
Ctrl+Enter : コードアップロード
Ctrl+O     : コード読込
Ctrl+S     : コード保存
F9         : スクリーンショット保存(カレントフォルダにshot.bmp)
Ctrl+F9    : スクリーンショット保存(ファイル名指定)

動画も参照してください。コーディングの説明・例も少しあります。

文の終わりには ";"(セミコロン)を使います。(末尾の ; は省略できます)
HSPの ":"(コロン)と似ていますが if文 などで少し異なるので注意してください。

if(P.x>-0.5&&P.x<0.5&&P.y>-0.5&&P.y<0.5){C.g=1.0;}else{C.b=1.0;}

この場合、閉じ括弧 "}" の直前のセミコロンは必要です。

データ型

HSPの整数型・実数型・文字列型のようなものです。
変数を宣言したり型変換するときに指定します。
( )内は当ソフトで使用できる略記です。

void (V)   : 値を返さない関数で使用
bool (B)   : 条件型(true|false)
int (I)    : 整数型
float (F)  : 実数型(浮動少数点数)
bvec2 (B2) : 2要素を持つ条件型(ベクトル)
bvec3 (B3) : 3要素...
bvec4 (B4) : 4要素...
ivec2 (I2) : 2要素を持つ整数型(ベクトル)
ivec3 (I3) : 3要素...
ivec4 (I4) : 4要素...
vec2 (V2)  : 2要素を持つ実数型(ベクトル)
vec3 (V3)  : 3要素...
vec4 (V4)  : 4要素...
mat2 (M2)  : 2×2要素を持つ実数型行列
mat3 (M3)  : 3×3要素...
mat4 (M4)  : 4×4要素...

暗黙の型変換は基本的に行われません。

I i=5;F a=i+1.0;     // 警告かエラー
I i=5;F a=F(i)+1.0;  // OK

変数

当ソフトであらかじめ用意されている変数。

C  : フラグメントの色RGB(vec3)(0.0~1.0で指定)
P  : フラグメントの座標XY(vec2)(xは-1.0~1.0、yは-0.75~0.75で上が正)
M  : マウスの座標XY(vec2)(同上)
T  : 実行後の経過時間(float)

S  : vec2(640.,480.)
SS : vec2(1.,-1.)
VM : マウス座標(vec2)(xは0.~640.、yは0.~480.で下が正)

C は (0.0, 0.0, 0.0)、その他は上記の値が初期値で入っています。
C 以外は参照のみに使用してください。

また変数はユーザーが自由に定義して使用できます。
定義の際に初期値を指定する必要があります。

変数の型 変数名=初期値

変数名はアンダースコアを含む半角英数字(頭が数字は除外)で他の名前と重複しないものを指定できます。
HSPと異なり大文字と小文字は区別されます。
ただし当ソフトでは大文字 "R" は for文 に展開されるため使用できません(繰り返しの項参照)

リテラル

実数値については
小数点以下が 0 の場合や、小数点以上が 0 の場合は省略できます。(小数点は必要、両方は不可)

1.0 → 1.
0.1 → .1
0.0 → 0. または .0

整数値は主に配列の要素指定に用います。
整数と実数では結果が異なったりコンパイルエラーになるので注意してください。

定数

PI : 3.14159265359

演算子

HSPで使用するものと(優先順位も)ほぼ同様です。
( )がある式ではそのなかの演算が優先されます。

+  : 加算
-  : 減算
*  : 乗算
/  : 除算

=  : 代入(HSPと異なり比較演算としては使用できない)

+= : 加算代入
-= : 減算...
*= : 乗算...
/= : 除算...

++ : インクリメント(前置・後置で結果は異なる)
-- : デクリメント(...)

== : 比較演算(等しい)
!= : ...(等しくない)
>  : ...(より大きい)
>= : ...(以上)
<  : ...(より小さい)
<= : ...(以下)

?: : 条件演算(A?B:C のように用い、条件Aが真ならB、偽ならCの値になる)

&& : 論理積(HSPと異なり記号は2つ続ける)
|| ; 論理和(...)
^^ : 排他的論理和(...)

スウィズル演算

ベクトル型の変数の各要素ごとに演算します。
変数名の後に "."(ピリオド)を置き、続いて x,y,z,w や r,g,b,a(1~4要素目に対応)の文字で記述します。

vec3 a = vec3(0.1, 0.3, 0.5) のとき

float b = a.r;     // b = 0.1
vec2 c = a.yx;     // c = (0.3, 0.1)
vec3 d = a.zzx;    // d = (0.5, 0.5, 0.1)
d.rb = a.gb;       // d = (0.3, 0.5, 0.5)
c.xy = c.yx;       // c = (0.1, 0.3)
d = c.rrg + a.zxx; // d = (0.6, 0.2, 0.4)

各要素を表す文字 x,y,z,w, r,g,b,a は変数名と重複しても問題ありません。

vec2 x = vec2(1.2, 3.4); x.y = x.x;

条件

条件による場合分けができます。

if(条件)処理
if(条件){処理}
if(条件){処理A}else{処理B}
if(条件A){処理A}else if(条件B){処理B}else{処理C}

繰り返し

条件を満たしている間、処理を繰り返します。

while(条件){処理}
do{処理}while(条件)
for(カウンタ初期化;条件;カウンタ更新){処理}

forは主に任意回数処理を繰り返すときに用います。例えば10回繰り返す場合、

for(float i=0.0;i<10.0;i++){処理}

のようになります。
また上記の例の場合、当ソフトでは以下の略記が用意されています。

Ri10{処理}

R + カウンタ変数(一文字まで) + 繰り返し回数(整数リテラルのみ)

この展開のため、変数名や関数名に "R" は使用できません。

組み込み関数

GLSLにあらかじめ用意されている、ユーザーが定義することなく使用できる関数です。
同じ関数名でも引数の数やデータ型が異なるものがあります。

RET FUNC( PRM, ... ) : RET は戻り値の型、 FUNC は関数名、PRM は引数の型。

型の gType は float, vec2, vec3, vec4 のいずれかを表し、引数と戻り値の型は同じになります。

gType sin( gType ) : 正弦(引数の単位はラジアン)
gType cos( gType ) : 余弦
gType tan( gType ) : 正接

gType asin( gType ) : 逆正弦(返値の単位はラジアン)
gType acos( gType ) : 逆余弦
gType atan( gType ) : 逆正接
gType atan( gType y, gType x ) : ...

gType radians( gType ) : 度数をラジアンに変換
gType degrees( gType ) : ラジアンを度数に変換

gType pow( gType x, gType y ) : x の y乗
gType exp( gType x ) : ネイピア数 e の x乗 
gType log( gType x ) : e を底とする x の対数
gType exp2( gType x ) : 2 の x乗
gType log2( gType x ) : 2 を底とする x の対数
gType sqrt( gType x ) : x の平方根
gType inversesqrt( gType x ) : 1/sqrt(x)

gType abs( gType x ) : x の絶対値
gType sign( gType x ) : x が正の数なら 1.0、0.0 なら 0.0、負の数なら -1.0
gType ceil( gType x ) : x 以上の最小の整数
gType floor( gType x ) : x 以下の最大の整数
gType fract( gType x ) : x-floor(x)
gType mod( gType x, gType y ) : x-y*floor(x/y) (HSPの剰余算 \ と同じ)
gType mod( gType x, float y ) : ...
gType min( gType x, gType y ) : x と y の小さい方の値
gType min( gType x, float y ) : ...
gType max( gType x, gType y ) : x と y の大きい方の値
gType max( gType x, float y ) : ...
gType clamp( gType x, gType n, gType m ) : x<=n なら n、n<x<m なら x、m<=x なら m
gType clamp( gType x, float n, float m ) : ...
gType mix( gType x, gType y, gType a ) : x*(1-a)+y*a(線形補完)
gType mix( gType x, gType y, float a ) : ...
gType step( gType a, gType x ) : x<a なら 0.0、それ以外は 1.0
gType step( float a, gType x ) : ...
gType smoothstep( gType n, gType m, gType x ) : x<n なら 0.0、m<xなら 1.0、n<=x<=m なら 0.0~1.0間でエルミート補完
gType smoothstep( float n, float m, gType x ) : ...

float length( gType x ) : x の長さ
float distance( gType x, gType y ) : x と y の距離
float dot( gType x, gType y ) : x と y の内積
vec3 cross( vec3 x, vec3 y ) : x と y の外積
gType normalize( gType x ) : x を正規化した値
gType faceforward( gType N, gType I, gType R ) : dot(I,R)<0 なら N、それ以外は -N
gType reflect( gType I, gType N ) : N を法線としたときの I の反射方向
gType refract( gType I, gType N, float eta ) : N を法線、eta を屈折率としたときの I の屈折方向

mat matrixCompMult( mat, mat ) : 行列の要素ごとの乗算

bvec lessThan( vec x, vec y ) : 要素ごとの x<y
bvec lessThan( ivec x, ivec y ) : ...
bvec lessThanEqual( vec x, vec y ) : 要素ごとの x<=y
bvec lessThanEqual( ivec x, ivec y ) : ...
bvec greaterThan( vec x, vec y ) : 要素ごとの x>y
bvec greaterThan( ivec x, ivec y ) : ...
bvec greaterThanEqual( vec x, vec y ) : 要素ごとの x>=y
bvec greaterThanEqual( ivec x, ivec y ) : ...
bvec equal( vec x, vec y ) : 要素ごとの x==y
bvec equal( ivec x, ivec y ) : ...
bvec notEqual( vec x, vec y ) : 要素ごとの x!=y
bvec notEqual( ivec x, ivec y ) : ...
bool any( bvec ) : 全ての要素がfalseならfalseを、それ以外ならtrue
bool all( bvec ) : 全ての要素がtrueならtrueを、それ以外ならfalse
bvec not( bvec ) : 全ての要素の真偽値を反転

ユーザー定義関数

当ソフトは通常GLSLのmain関数内の記述を対象としているため、そのままでは関数は定義できません。
関数を定義する場合は、文頭に "!"(感嘆符)を置いてください。
このときmain関数も記述する必要がありますが、最後の閉じ括弧 "}" は書かないでください。

戻り値の型 関数名(引数){関数内容}

の形で関数を定義できます。戻り値や引数がない場合は void または V です。
戻り値は return の後ろに指定します。

!F c(F a,F b){return sin(length(P)+T*b)*a;}V main(V){C=V3(c(1.1,1.2),c(1.3,1.4),c(1.5,1.6));

参考URL

[連載]やってみれば超簡単! WebGL と GLSL で始める、はじめてのシェーダコーディング(1) - Qiita
http://qiita.com/doxas/items/b8221e92a2bfdc6fc211

wgld.org | GLSL |
http://wgld.org/d/glsl/

GLSLで簡単2Dエフェクト ≪ demoscene.jp
http://www.demoscene.jp/?p=1147

GLSL Sandbox Gallery
http://glslsandbox.com/

WebGL - GLSLについてのメモ - Qiita
http://qiita.com/edo_m18/items/71f6064f3355be7e4f45

Shaderific - GLSL
http://www.shaderific.com/glsl/

T.Teranishi:OpenGL:GLSL
http://www.asahi-net.or.jp/~YW3T-TRNS/opengl/glsl/


OpenGL Shading Language (GLSL) Quick Reference Guide
http://mew.cx/glsl_quickref.pdf

OpenGL ESシェーディング言語
http://ec.nikkeibp.co.jp/nsp/dl/08513/HTML5GAMES_AppC.pdf