Windowsターミナルで無限のCTO

ちょっと前からWindowsターミナルの背景にHLSLでシェーダーを設定できるようになっている。

{
  "profiles": {
    "defaults": {
      "experimental.pixelShaderPath": "path\\to\\some.hlsl"
    }
  }
}

みんな大好きハンゼルマン先生がいくつか公開してるので取り合えず覗いてみるといいだろう。

GitHub - Hammster/windows-terminal-shaders: A small collection of terminal shaders

個人的にはdawnstarsneonroadあたりがいい感じ。 あるいはhueshiftCHANGE_RATEをお好みで増やしてゲーミングターミナルにしたりなど。

さて、やはり自分でも何か書いてみたくなるのがプログラマ人情というもの。

でもHLSLはさっぱりで先のコードを読み解くのは初見には流石にハードなのでもっとサンプル感のあるコードを見てなるほどを得る。

terminal/samples/PixelShaders at main · microsoft/terminal · GitHub

というわけで早速いっちょ書いてみたのがこちら。

Texture2D shaderTexture;
SamplerState samplerState;

cbuffer PixelShaderSettings {
  float  Time;
  float  Scale;
  float2 Resolution;
  float4 Background;
};

static float3 motemen[16] = {
  float3(0.47, 0.51, 0.55), float3(0.99, 1.00, 0.96), float3(0.08, 0.23, 0.54), float3(0.62, 0.65, 0.73),
  float3(0.51, 0.32, 0.15), float3(1.00, 0.88, 0.83), float3(1.00, 0.88, 0.83), float3(0.85, 0.18, 0.13),
  float3(0.64, 0.67, 0.76), float3(0.99, 0.77, 0.72), float3(1.00, 0.70, 0.64), float3(0.88, 0.42, 0.36),
  float3(0.68, 0.70, 0.72), float3(0.22, 0.24, 0.27), float3(0.33, 0.13, 0.05), float3(0.35, 0.35, 0.37)
};

float4 main(float4 pos : SV_POSITION, float2 tex : TEXCOORD) : SV_TARGET {
  float4 color = shaderTexture.Sample(samplerState, tex);
  float4 ocolor = shaderTexture.Sample(samplerState, tex + 2.0 * Scale * float2(-1.0, -1.0) / Resolution.y);

  float3 bg = motemen[int(tex.x * 4) + 4 * int(tex.y * 4)];
  return float4(lerp(lerp(bg, float(0.0), ocolor.w), color.xyz, color.w), 1.0);
}

これを適用するとこうなる。 偶然にもCTOのアイコンがシェーダー入門者にやさしかったので助かった。*1

とはいえこんなんじゃただ画像が貼ってあるのと変わらんので、シェーダーらしさをひとつまみ。

Texture2D shaderTexture;
SamplerState samplerState;

cbuffer PixelShaderSettings {
  float  Time;
  float  Scale;
  float2 Resolution;
  float4 Background;
};

static float3 motemen[16] = {
  float3(0.47, 0.51, 0.55), float3(0.99, 1.00, 0.96), float3(0.08, 0.23, 0.54), float3(0.62, 0.65, 0.73),
  float3(0.51, 0.32, 0.15), float3(1.00, 0.88, 0.83), float3(1.00, 0.88, 0.83), float3(0.85, 0.18, 0.13),
  float3(0.64, 0.67, 0.76), float3(0.99, 0.77, 0.72), float3(1.00, 0.70, 0.64), float3(0.88, 0.42, 0.36),
  float3(0.68, 0.70, 0.72), float3(0.22, 0.24, 0.27), float3(0.33, 0.13, 0.05), float3(0.35, 0.35, 0.37)
};

float4 main(float4 pos : SV_POSITION, float2 tex : TEXCOORD) : SV_TARGET {
  float4 color = shaderTexture.Sample(samplerState, tex);
  float4 ocolor = shaderTexture.Sample(samplerState, tex + 2.0 * Scale * float2(-1.0, -1.0) / Resolution.y);

  tex.xy += (Time % 10) / 10;
  if (tex.x > 1) {
    tex.x -= 1;
  }
  if (tex.y > 1) {
    tex.y -= 1;
  }

  float3 bg = motemen[int(tex.x * 4) + 4 * int(tex.y * 4)];
  return float4(lerp(lerp(bg, float(0.0), ocolor.w), color.xyz, color.w), 1.0);
}

これが∞motemenさんか…

youtu.be

ところで、いろいろなシェーダーを気分で切り替えたいので、いちいち設定ファイルを開いて書き換えるのは面倒である。 ということで、これをお手軽にできるPowerShellのモジュールをF#で作った話を次回する予定。

ちなみに常時オンだとやっぱアレなので次のようにしてショートカットキーで切り替えられるようにしている。

{
  "actions": [
    {
      "command": "toggleShaderEffects",
      "keys": "shift+f10"
    }
  ]
}