Skip to content

シェーダを利用する

Akashic Engine v3 は、限定的にフラグメントシェーダをサポートしています。 シェーダを使うには、g.ShaderProgram を利用します。

凡例

javascript
var fragmentShader = scene.asset.getText["/text/shader.glsl"].data; // テキストアセットからフラグメントシェーダを取得
var shader = new g.ShaderProgram({
  fragmentShader: fragmentShader
});

var sprite = new g.Sprite({
  ..., // その他のプロパティ
  shaderProgram: shader // シェーダの指定
});
javascript
sprite.shaderProgram = shader; // 既存の sprite にシェーダを指定
sprite.modified(); // modified() で表示に反映

利用例

次のコンテンツは、画像をモノクロ化して表示します。

詳細

INFO

以下、 WebGL のシェーダについての知識が必要です。

Akashic Engine は現在、フラグメントシェーダを限定的に利用することができます。

TIP

バーテックスシェーダは非サポートで、attribute も固定です。uniform は利用できます。 したがって現状の用途は、画像に対する単純なフィルタなどに限られます。

シェーダを利用するには、まず game.jsonrendererswebgl を追加します。

json
"renderers": ["webgl"],

シェーダは g.ShaderProgram で表されます。g.ShaderProgramg.E やそれを継承したクラス (g.Sprite , g.Pane など) に適用できます。

シェーダプログラムは親エンティティの値を継承します。そのため、シェーダプログラムを適用したエンティティに複数の子エンティティに追加することで、複数のエンティティに同一のシェーダプログラムを適用することができます。

下記のコードでは、テキストアセット monochrome.glsl を読み込み Pane に指定しています。Pane の子エンティティである SpriteFilledRect にもシェーダが適応されます。

javascript
#version 100
precision mediump float;
varying vec2 vTexCoord;
uniform sampler2D uSampler;
uniform float uAlpha;

void main(void)
{
  // 対象ピクセルの色情報を取得
  vec4 color = texture2D(uSampler, vTexCoord);
  // 対象ピクセルのRGB値を加算
  float sum = dot(color.rgb, vec3(1.0));
  // モノクロ化
  vec3 outColor = vec3(sum / 3.0);
  // 最終出力色
  gl_FragColor = vec4(outColor, color.a * uAlpha);
}
javascript
function main() {
  var scene = new g.Scene({
    game: g.game,
    assetPaths: ["/image/player.png", "/text/monochrome.glsl"]
  });

  scene.onLoad.add(function () {
    var fragmentShader = scene.asset.getText("/text/monochrome.glsl").data;
    var shader = new g.ShaderProgram({
      fragmentShader: fragmentShader
    });
    var pane = new g.Pane({
      scene: scene,
      width: 300,
      height: 300,
      shaderProgram: shader
    });

    var sprite = new g.Sprite({
      scene: scene,
      src: scene.asset.getImage("/image/player.png"),
      x: 100,
      y: 100
    });
    var rect = new g.FilledRect({
      scene: scene,
      width: 100,
      height: 100,
      x: 50,
      cssColor: "red"
    });
    pane.append(sprite);
    pane.append(rect);
    scene.append(pane);
  });
  g.game.pushScene(scene);
}

module.exports = main;

.glsl 内で利用している uAlpha, uSampler, vTexCoord は固定で与えられます。 それぞれ opacity を反映した透明度、元の描画内容 (画像や FilledRect の単色) をテクスチャとして参照するサンプラー、そしてテクスチャ座標です。

設定したシェーダを戻したい場合、 undefined または null を指定します。 undefinednull は以下のように挙動が異なることにご留意ください。

  • undefined: 親エンティティのシェーダプログラムを利用する。(デフォルト)
  • null: 親エンティティのシェーダプログラムを利用せず、常に初期のシェーダプログラム( undefined )を利用する。
javascript
sprite.shaderProgram = null;
sprite.modified();

変数

akashic-engine@2.3.2 移行では、以下の変数がエンジン側から暗黙的に与えられます。

  • varying
    • vec2 vTexCoord
      • 対象の描画元のテクスチャ座標
      • 本値は 0 ~ 1.0 の範囲内で任意の矩形領域となり得ることに注意。
  • uniform
    • sampler2D uSampler
      • 対象の描画元のテクスチャ番号
    • float uAlpha
      • 透過度 (0 ~ 1.0 の範囲内)

ユーザ定義変数

ユーザが独自に定義した変数をフラグメントシェーダに与えることができます。

先程のサンプルにおいて、各色の重み付けをコンテンツから指定した例が以下になります。

glsl
#version 100
precision mediump float;

varying vec2 vTexCoord;
uniform sampler2D uSampler;
uniform float uAlpha;

uniform float redScale;
uniform float greenScale;
uniform float blueScale;

vec3 monoScale = vec3(redScale, greenScale, blueScale);
float monoScaleSum = dot(monoScale, vec3(1.0));

void main(void)
{
  // 対象ピクセルの色情報を取得
  vec4 color = texture2D(uSampler, vTexCoord);

  // 対象ピクセルのRGB値を加算
  float sum = dot(color.rgb, monoScale);

  // モノクロ化
  vec3 outColor = vec3(sum / monoScaleSum);

  // 最終出力色
  gl_FragColor = vec4(outColor, color.a * uAlpha);
}

redScale , greenScale , blueScale が uniform 値として渡されるようにフラグメントシェーダを修正しています。

g.ShaderProgram の生成時に利用する uniform を定義します。

javascript
const shader = new g.ShaderProgram({
  fragmentShader: fragmentShader,
  uniforms: {
    redScale: {
      type: "float",
      value: 0.299
    },
    greenScale: {
      type: "float",
      value: 0.587
    },
    blueScale: {
      type: "float",
      value: 0.114
    }
  }
});

uniform は、フラグメントシェーダで利用する際の変数名をキーとしたオブジェクトによって定義されます。各キーは g.ShaderUniform によって定義された形式で記述する必要があります。 type は対象の uniform の型、valueはその値を示します。

type には以下が指定できます。

  • float
  • int
  • vec2
  • vec3
  • vec4
  • ivec2
  • ivec3
  • ivec4
  • mat2
  • mat3
  • mat4

また、以下のように Array を利用することもできます。

フラグメントシェーダ

glsl
uniform param[3];

コンテンツ

javascript
const shader = new g.ShaderProgram({
  fragmentShader: fragmentShader,
  uniforms: {
    param: {
      type: "float",
      value: [0.0, 1.0, 0.4]
    }
  }
});

g.ShaderProgram#uniform#value の値はプログラムの実行中に任意に変更できます。

javascript
scene.update.add(() => {
  shader.uniforms.time.value = scene.game.age;
});

関連情報