はじめに
HLSLは「High Level Shading Language」の頭文字となるが、マイクロソフトの説明サイトでは「上位レベルシェーダー言語」と訳されている。適当な漢字で表せば「高級着色像素言語」的な感じだ。
HLSLはシェーダー言語(=シェーディング言語=着色像素言語)に属し、他のシェーダー言語には、GLSLやCGが存在する。
このシェーダー言語を使えば光の反射、乱反射、空気感を含んだ「高級な画像(動画)」が作成できる。
画像の計算は、画面にあるドット(=画素。フルハイビジョンなら1920×1080画素)一つ一つ毎に計算をする為、大量の計算が必要なる。そのため、CPUではなく、GPUを使って画面全体の総ドットを並列計算で処理していく。
そして今回大切なことは、HLSLで作成した画像は、Windows Terminalの背景にできる!
本来であれば、HLSLはUnity(ゲームエンジン、ゲーム開発環境)と、C++言語やC#言語等プログラム言語と一緒にして活用する様だが、自分はUnityを一度も使ったことがないので、HLSLをVisual Studio Codeでポチポチ打ちながらWindows Terminal画面で画像が出たら一喜一憂した。
ちなみにBlender (3DCGアニメ作成の為の統合開発環境)は、HLSLではなくGLSLです。
パソコン環境
- Windows10
- Windows Terminal : 1.15.2712.0
- Visual Studio Code
【初期設定】Windows Terminalの設定
Windows Terminalの背景にHLSLで作成した画像を表示する為には、Windows Terminalの設定ファイル「settings.json」内の「Profiles」以下の「defaults」以下に「experimental.pixelShaderPath」とHLSLファイルのアドレスを示す行を追加する。
HLSLの拡張子は「.hlsl」となる。
"defaults":
{
"experimental.pixelShaderPath": "C:\\Users\\ユーザー名\\適当なファイルパス\\sample.hlsl"
},
HLSLと画像の事例
事例1:赤一色
float4 main(float4 pos : SV_POSITION, float2 tex : TEXCOORD) : SV_TARGET{
//SV_POSITION:均質空間内の頂点位置らしい。よくわからん
//TEXCOORD :テクスチャー座標らしい。よくわからん
//SV_Target レンダー ターゲットの配列らしい。全然わからん
return float4(1,0,0,1);//赤
//return float4(0,1,0,1);//緑
//return float4(0,0,1,1);//青
//return float4(1,0,0,1)+float4(0,1,0,1)+float4(0,0,1,1);//白
}
事例2:変数を使った緑一色
float4 main(float4 pos : SV_POSITION, float2 tex : TEXCOORD) : SV_TARGET{
float3 g = float3(0,1,0);
return float4(g,1.0);
}
事例3:背景色が赤
Texture2D shaderTexture;
SamplerState samplerState;
float4 main(float4 pos : SV_POSITION, float2 tex : TEXCOORD) : SV_TARGET{
float4 t = shaderTexture.Sample(samplerState, float2(1.0, 1.0));
float4 color = shaderTexture.Sample(samplerState, tex);
color.xyz += float3(1, 0.0, 0.0);
return color;
}
事例4:グラデーション
Texture2D shaderTexture;
SamplerState samplerState;
float4 main(float4 pos : SV_POSITION, float2 tex : TEXCOORD) : SV_TARGET{
float4 t = shaderTexture.Sample(samplerState, float2(1.0, 2.0));
float4 color = shaderTexture.Sample(samplerState, tex);
color.xyz += float3(t.x * 8 + (tex.x + tex.y) / 4, 0.0, 0.6);
return color;
}
事例5:背景色を縦に領域分け
Texture2D shaderTexture;
SamplerState samplerState;
float4 main(float4 pos : SV_POSITION, float2 tex : TEXCOORD) : SV_TARGET{
float4 t = shaderTexture.Sample(samplerState, float2(1.0, 1.0));
float4 color = shaderTexture.Sample(samplerState, tex);
if (tex.x > 0.1 ){
color.xyz += float3(1.0, 0.0, 0.5);
}
return color;
}
事例6:背景色を横に領域分け
Texture2D shaderTexture;
SamplerState samplerState;
float4 main(float4 pos : SV_POSITION, float2 tex : TEXCOORD) : SV_TARGET{
float4 t = shaderTexture.Sample(samplerState, float2(1.0, 1.0));
float4 color = shaderTexture.Sample(samplerState, tex);
if (tex.y > 0.1 ){
color.xyz += float3(1.0, 0.0, 0.5);
}
return color;
}
事例7:赤の縦線を引く
Texture2D shaderTexture;
SamplerState samplerState;
cbuffer PixelShaderSettings {
float Time;//1ベクトル=スカラー値
float Scale;//1ベクトル=スカラー値
float2 Resolution;//2✕1ベクトル
float4 Background;//4✕1ベクトル
};
float4 main(float4 pos : SV_POSITION, float2 tex : TEXCOORD) : SV_TARGET{
float4 t = shaderTexture.Sample(samplerState, float2(1.0, 1.0));
float4 color = shaderTexture.Sample(samplerState, tex);
if (tex.x * Resolution.x > 200 && tex.x * Resolution.x < 201 ){
color.xyz += float3(1.0, 0.0, 0.0);
}
return color;
}
事例8:赤の横線を引く
Texture2D shaderTexture;
SamplerState samplerState;
cbuffer PixelShaderSettings {
float Time;//1ベクトル=スカラー値
float Scale;//1ベクトル=スカラー値
float2 Resolution;//2✕1ベクトル
float4 Background;//4✕1ベクトル
};
float4 main(float4 pos : SV_POSITION, float2 tex : TEXCOORD) : SV_TARGET{
float4 t = shaderTexture.Sample(samplerState, float2(1.0, 1.0));
float4 color = shaderTexture.Sample(samplerState, tex);
if (tex.y * Resolution.y > 110 && tex.y * Resolution.y < 111 ){
color.xyz += float3(1.0, 0.0, 0.0);
}
return color;
}
事例9:赤の斜め線を引く
Texture2D shaderTexture;
SamplerState samplerState;
cbuffer PixelShaderSettings {
float Time;//1ベクトル=スカラー値
float Scale;//1ベクトル=スカラー値
float2 Resolution;//2✕1ベクトル
float4 Background;//4✕1ベクトル
};
float4 main(float4 pos : SV_POSITION, float2 tex : TEXCOORD) : SV_TARGET{
float4 t = shaderTexture.Sample(samplerState, float2(1.0, 1.0));
float4 color = shaderTexture.Sample(samplerState, tex);
if (tex.y * Resolution.y > tex.x * Resolution.x -0.5 && tex.y * Resolution.y < tex.x * Resolution.x+0.5 ){
color.xyz += float3(1.0, 0.0, 0.0);
}
return color;
}
事例10:放物線
Texture2D shaderTexture;
SamplerState samplerState;
cbuffer PixelShaderSettings {
float Time;//1ベクトル=スカラー値
float Scale;//1ベクトル=スカラー値
float2 Resolution;//2✕1ベクトル
float4 Background;//4✕1ベクトル
};
float4 main(float4 pos : SV_POSITION, float2 tex : TEXCOORD) : SV_TARGET{
float4 t = shaderTexture.Sample(samplerState, float2(1.0, 1.0));
float4 color = shaderTexture.Sample(samplerState, tex);
const float y_add = 800.0;
const float x_add = 30.0;
float yy = tex.y * Resolution.y - y_add ;
float xx = tex.x * Resolution.x/10 - x_add;
if (yy> - (xx)*(xx) - 1.0 && yy < -(xx )*(xx ) +1.0){
color.xyz += float3(1.0, 1.0, 1.0);
}
return color;
}
事例11:Sinカーブ(線が不連続になってしまった)
Texture2D shaderTexture;
SamplerState samplerState;
cbuffer PixelShaderSettings {
float Time;//1ベクトル=スカラー値
float Scale;//1ベクトル=スカラー値
float2 Resolution;//2✕1ベクトル
float4 Background;//4✕1ベクトル
};
float4 main(float4 pos : SV_POSITION, float2 tex : TEXCOORD) : SV_TARGET{
float4 t = shaderTexture.Sample(samplerState, float2(1.0, 1.0));
float4 color = shaderTexture.Sample(samplerState, tex);
const float y_add = 200.0;
const float x_add = 30.0;
float yy = tex.y * Resolution.y - y_add ;
float xx = tex.x * Resolution.x/10 - x_add;
//ここがサインカーブ
if (yy > - 100*sin(xx) - 1.0 && yy < -100*sin(xx ) +1.0){
color.xyz += float3(1.0, 1.0, 1.0);
}
return color;
}
事例11-2:Sinカーブ(不連続な線を、連続に修正)
Texture2D shaderTexture;
SamplerState samplerState;
cbuffer PixelShaderSettings {
float Time;//1ベクトル=スカラー値
float Scale;//1ベクトル=スカラー値
float2 Resolution;//2✕1ベクトル
float4 Background;//4✕1ベクトル
};
float4 main(float4 pos : SV_POSITION, float2 tex : TEXCOORD) : SV_TARGET{
float4 t = shaderTexture.Sample(samplerState, float2(1.0, 1.0));
float4 color = shaderTexture.Sample(samplerState, tex);
const float y_add = 200.0;
const float x_add = 150.0;
float yy = tex.y * Resolution.y - y_add ;
float xx = tex.x * Resolution.x - x_add;
for (float i=1;i<10;i++){
float xi = xx + i/10;
if (yy > - 100*sin(xi/31.4) - 1.0 && yy < -100*sin(xi/31.4) +1.0){
color.xyz += float3(1.0, 1.0, 1.0) ;
}
}
return color;
}
事例12:恒例のドット絵
Texture2D shaderTexture;
SamplerState samplerState;
cbuffer PixelShaderSettings {
float Time;//1ベクトル=スカラー値
float Scale;//1ベクトル=スカラー値
float2 Resolution;//2✕1ベクトル
float4 Background;//4✕1ベクトル
};
float4 main(float4 pos : SV_POSITION, float2 tex : TEXCOORD) : SV_TARGET{
float4 t = shaderTexture.Sample(samplerState, float2(1.0, 1.0));
float4 color = shaderTexture.Sample(samplerState, tex);
//アルファベットのAのドット絵情報
int dot_color[5][6] ={{1,0,0,0,1,1},{0,1,0,1,1,1},{1,0,0,0,1,1},{1,1,1,1,1,1},{1,1,1,1,1,1}};
for (float x_d=0.0;x_d<6.0;x_d++){
for (float y_d=0.0;y_d<6.0;y_d++){
if (tex.x > x_d/20 && tex.x < (x_d+1)/20){
if (tex.y > y_d/20 && tex.y < (y_d+1)/20){
color.xyz += float3(1.0, dot_color[x_d][y_d], 0.0) ;
}
}
}
}
return color;
}
事例13:ドット絵その2
Texture2D shaderTexture;
SamplerState samplerState;
float4 main(float4 pos : SV_POSITION, float2 tex : TEXCOORD) : SV_TARGET{
float4 t = shaderTexture.Sample(samplerState, float2(1.0, 1.0));
float4 color = shaderTexture.Sample(samplerState, tex);
//[横][縦][RGB]
float dot4_color[16][15][3] ={
{{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,1.0,0.0},{0.0,1.0,0.0},{0.0,1.0,0.0},{0.0,1.0,0.0},{0.0,1.0,0.0},{0.0,1.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.0}},
{{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,1.0,0.0},{0.0,1.0,0.0},{0.0,1.0,0.0},{0.0,1.0,0.0},{0.0,1.0,0.0},{0.0,1.0,0.0},{0.0,1.0,0.0},{0.0,1.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.0}},
{{0.0,0.0,0.0},{0.0,0.0,0.0},{1.0,0.6,0.0},{0.0,0.0,0.0},{0.0,1.0,0.0},{0.0,0.0,0.5},{0.0,0.0,0.5},{0.0,0.0,0.5},{0.0,0.0,0.5},{0.0,0.0,0.5},{0.0,0.0,0.5},{0.0,1.0,0.0},{0.0,0.0,0.0},{1.0,0.6,0.0},{0.0,0.0,0.0}},
{{0.0,0.0,0.0},{0.0,0.0,0.0},{1.0,0.6,0.0},{0.0,0.0,0.0},{0.0,0.0,0.5},{0.0,0.0,0.5},{0.0,0.0,0.5},{0.0,0.0,0.5},{0.0,0.0,0.5},{0.0,0.0,0.5},{0.0,0.0,0.5},{0.0,0.0,0.5},{0.0,0.0,0.0},{1.0,0.6,0.0},{0.0,0.0,0.0}},
{{0.0,0.0,0.0},{0.0,0.0,0.0},{1.0,0.6,0.0},{1.0,0.6,0.0},{0.0,0.0,0.5},{1.0,0.6,0.0},{0.0,1.0,0.0},{1.0,0.6,0.0},{1.0,0.6,0.0},{0.0,1.0,0.0},{1.0,0.6,0.0},{0.0,0.0,0.5},{1.0,0.6,0.0},{1.0,0.6,0.0},{0.0,0.0,0.0}},
{{0.0,0.0,0.0},{0.0,0.0,0.0},{1.0,0.6,0.0},{1.0,0.6,0.0},{0.0,0.0,0.5},{1.0,0.6,0.0},{0.0,0.0,0.5},{1.0,0.6,0.0},{1.0,0.6,0.0},{0.0,0.0,0.5},{1.0,0.6,0.0},{0.0,0.0,0.5},{1.0,0.6,0.0},{1.0,0.6,0.0},{0.0,0.0,0.0}},
{{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.0},{1.0,0.6,0.0},{1.0,0.6,0.0},{1.0,0.6,0.0},{1.0,0.6,0.0},{1.0,0.6,0.0},{1.0,0.6,0.0},{1.0,0.6,0.0},{1.0,0.6,0.0},{1.0,0.6,0.0},{1.0,0.6,0.0},{0.0,0.0,0.5},{0.0,0.0,0.0}},
{{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,1.0,0.0},{0.0,1.0,0.0},{1.0,0.6,0.0},{1.0,0.6,0.0},{0.0,0.0,0.5},{0.0,0.0,0.5},{1.0,0.6,0.0},{1.0,0.6,0.0},{0.0,1.0,0.0},{0.0,1.0,0.0},{0.0,0.0,0.5},{0.0,0.0,0.0}},
{{0.0,0.0,0.0},{0.0,0.0,0.5},{0.0,0.0,0.5},{0.0,0.0,0.5},{0.0,0.0,0.5},{0.0,0.0,0.5},{1.0,0.6,0.0},{1.0,0.6,0.0},{1.0,0.6,0.0},{1.0,0.6,0.0},{0.0,1.0,0.0},{0.0,1.0,0.0},{0.0,0.0,0.5},{0.0,0.0,0.5},{0.0,0.0,0.5}},
{{0.0,0.0,0.5},{0.0,0.0,0.5},{1.0,0.6,0.0},{0.0,0.0,0.5},{0.0,0.0,0.5},{0.0,0.0,0.5},{0.0,0.0,0.5},{0.0,1.0,0.0},{0.0,1.0,0.0},{0.0,1.0,0.0},{0.0,1.0,0.0},{0.0,1.0,0.0},{1.0,0.6,0.0},{0.0,0.0,0.5},{0.0,0.0,0.5}},
{{0.0,0.0,0.5},{1.0,0.6,0.0},{1.0,0.6,0.0},{1.0,0.6,0.0},{0.0,0.0,0.5},{0.0,0.0,0.5},{1.0,0.6,0.0},{0.0,0.0,0.5},{0.0,0.0,0.5},{0.0,1.0,0.0},{0.0,1.0,0.0},{1.0,0.6,0.0},{1.0,0.6,0.0},{1.0,0.6,0.0},{0.0,0.0,0.5}},
{{0.0,0.0,0.5},{0.0,0.0,0.5},{1.0,0.6,0.0},{0.0,0.0,0.5},{0.0,0.0,0.5},{0.0,0.0,0.5},{1.0,0.6,0.0},{0.0,1.0,0.0},{0.0,0.0,0.5},{0.0,0.0,0.5},{0.0,0.0,0.5},{0.0,0.0,0.5},{1.0,0.6,0.0},{1.0,0.6,0.0},{1.0,0.6,0.0}},
{{0.0,0.0,0.5},{0.0,0.0,0.5},{1.0,0.6,0.0},{0.0,0.0,0.5},{0.0,0.0,0.5},{0.0,0.0,0.5},{1.0,0.6,0.0},{0.0,0.0,0.5},{0.0,0.0,0.5},{0.0,1.0,0.0},{0.0,1.0,0.0},{0.0,1.0,0.0},{0.0,1.0,0.0},{1.0,0.6,0.0},{0.0,0.0,0.0}},
{{0.0,0.0,0.5},{0.0,0.0,0.5},{0.0,0.0,0.5},{0.0,0.0,0.5},{0.0,0.0,0.5},{0.0,0.0,0.5},{1.0,0.6,0.0},{0.0,1.0,0.0},{0.0,1.0,0.0},{0.0,1.0,0.0},{0.0,1.0,0.0},{0.0,1.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.0}},
{{0.0,0.0,0.0},{1.0,0.6,0.0},{1.0,0.6,0.0},{1.0,0.6,0.0},{1.0,0.6,0.0},{1.0,0.6,0.0},{0.0,0.0,0.5},{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.5},{0.0,0.0,0.5},{0.0,0.0,0.5},{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.0}},
{{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.5},{0.0,0.0,0.5},{0.0,0.0,0.5},{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.0}},
};
for (float y_d=0.0;y_d<16.0;y_d++){
for (float x_d=0.0;x_d<16.0;x_d++){
if (tex.x > x_d/100 && tex.x < (x_d+1)/100){
if (tex.y > y_d/100 && tex.y < (y_d+1)/100){
color.xyz += float3(dot4_color[y_d][x_d][0], dot4_color[y_d][x_d][1], dot4_color[y_d][x_d][2]) ;
}
}
}
}
return color;
}
実行したら、パソコンのファンがうなりをあげた
HLSLはif文(条件分岐)が鬼門
sample13.hlslを実行したら、パソコンのファンがうなりをあげ、操作もカクカクした。パソコンの負荷が高い様だ。
タスクマネージャーを見たらGPU負荷が100%あった。これは悲しい。
Webで調べたら、HLSLはif文(条件分岐)が遅くなる要因と書いてあった。
sample13.hlslの本文を見るとif文を256回(=16×16)使っているのがダメなようだ。
事例14:ドット絵その3(if文の低減版)
Texture2D shaderTexture;
SamplerState samplerState;
cbuffer PixelShaderSettings {
float Time;//1ベクトル=スカラー値
float Scale;//1ベクトル=スカラー値
float2 Resolution;//2✕1ベクトル
float4 Background;//4✕1ベクトル
};
const static float3 dot4_color[16][15] ={
{{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,1.0,0.0},{0.0,1.0,0.0},{0.0,1.0,0.0},{0.0,1.0,0.0},{0.0,1.0,0.0},{0.0,1.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.0}},
{{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,1.0,0.0},{0.0,1.0,0.0},{0.0,1.0,0.0},{0.0,1.0,0.0},{0.0,1.0,0.0},{0.0,1.0,0.0},{0.0,1.0,0.0},{0.0,1.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.0}},
{{0.0,0.0,0.0},{0.0,0.0,0.0},{1.0,0.6,0.0},{0.0,0.0,0.0},{0.0,1.0,0.0},{0.44,0.26,0.16},{0.44,0.26,0.16},{0.44,0.26,0.16},{0.44,0.26,0.16},{0.44,0.26,0.16},{0.44,0.26,0.16},{0.0,1.0,0.0},{0.0,0.0,0.0},{1.0,0.6,0.0},{0.0,0.0,0.0}},
{{0.0,0.0,0.0},{0.0,0.0,0.0},{1.0,0.6,0.0},{0.0,0.0,0.0},{0.44,0.26,0.16},{0.44,0.26,0.16},{0.44,0.26,0.16},{0.44,0.26,0.16},{0.44,0.26,0.16},{0.44,0.26,0.16},{0.44,0.26,0.16},{0.44,0.26,0.16},{0.0,0.0,0.0},{1.0,0.6,0.0},{0.0,0.0,0.0}},
{{0.0,0.0,0.0},{0.0,0.0,0.0},{1.0,0.6,0.0},{1.0,0.6,0.0},{0.44,0.26,0.16},{1.0,0.6,0.0},{0.0,1.0,0.0},{1.0,0.6,0.0},{1.0,0.6,0.0},{0.0,1.0,0.0},{1.0,0.6,0.0},{0.44,0.26,0.16},{1.0,0.6,0.0},{1.0,0.6,0.0},{0.0,0.0,0.0}},
{{0.0,0.0,0.0},{0.0,0.0,0.0},{1.0,0.6,0.0},{1.0,0.6,0.0},{0.44,0.26,0.16},{1.0,0.6,0.0},{0.44,0.26,0.16},{1.0,0.6,0.0},{1.0,0.6,0.0},{0.44,0.26,0.16},{1.0,0.6,0.0},{0.44,0.26,0.16},{1.0,0.6,0.0},{1.0,0.6,0.0},{0.0,0.0,0.0}},
{{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.0},{1.0,0.6,0.0},{1.0,0.6,0.0},{1.0,0.6,0.0},{1.0,0.6,0.0},{1.0,0.6,0.0},{1.0,0.6,0.0},{1.0,0.6,0.0},{1.0,0.6,0.0},{1.0,0.6,0.0},{1.0,0.6,0.0},{0.44,0.26,0.16},{0.0,0.0,0.0}},
{{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,1.0,0.0},{0.0,1.0,0.0},{1.0,0.6,0.0},{1.0,0.6,0.0},{0.44,0.26,0.16},{0.44,0.26,0.16},{1.0,0.6,0.0},{1.0,0.6,0.0},{0.0,1.0,0.0},{0.0,1.0,0.0},{0.44,0.26,0.16},{0.0,0.0,0.0}},
{{0.0,0.0,0.0},{0.44,0.26,0.16},{0.44,0.26,0.16},{0.44,0.26,0.16},{0.44,0.26,0.16},{0.44,0.26,0.16},{1.0,0.6,0.0},{1.0,0.6,0.0},{1.0,0.6,0.0},{1.0,0.6,0.0},{0.0,1.0,0.0},{0.0,1.0,0.0},{0.44,0.26,0.16},{0.44,0.26,0.16},{0.44,0.26,0.16}},
{{0.44,0.26,0.16},{0.44,0.26,0.16},{1.0,0.6,0.0},{0.44,0.26,0.16},{0.44,0.26,0.16},{0.44,0.26,0.16},{0.44,0.26,0.16},{0.0,1.0,0.0},{0.0,1.0,0.0},{0.0,1.0,0.0},{0.0,1.0,0.0},{0.0,1.0,0.0},{1.0,0.6,0.0},{0.44,0.26,0.16},{0.44,0.26,0.16}},
{{0.44,0.26,0.16},{1.0,0.6,0.0},{1.0,0.6,0.0},{1.0,0.6,0.0},{0.44,0.26,0.16},{0.44,0.26,0.16},{1.0,0.6,0.0},{0.44,0.26,0.16},{0.44,0.26,0.16},{0.0,1.0,0.0},{0.0,1.0,0.0},{1.0,0.6,0.0},{1.0,0.6,0.0},{1.0,0.6,0.0},{0.44,0.26,0.16}},
{{0.44,0.26,0.16},{0.44,0.26,0.16},{1.0,0.6,0.0},{0.44,0.26,0.16},{0.44,0.26,0.16},{0.44,0.26,0.16},{1.0,0.6,0.0},{0.0,1.0,0.0},{0.44,0.26,0.16},{0.44,0.26,0.16},{0.44,0.26,0.16},{0.44,0.26,0.16},{1.0,0.6,0.0},{1.0,0.6,0.0},{1.0,0.6,0.0}},
{{0.44,0.26,0.16},{0.44,0.26,0.16},{1.0,0.6,0.0},{0.44,0.26,0.16},{0.44,0.26,0.16},{0.44,0.26,0.16},{1.0,0.6,0.0},{0.44,0.26,0.16},{0.44,0.26,0.16},{0.0,1.0,0.0},{0.0,1.0,0.0},{0.0,1.0,0.0},{0.0,1.0,0.0},{1.0,0.6,0.0},{0.0,0.0,0.0}},
{{0.44,0.26,0.16},{0.44,0.26,0.16},{0.44,0.26,0.16},{0.44,0.26,0.16},{0.44,0.26,0.16},{0.44,0.26,0.16},{1.0,0.6,0.0},{0.0,1.0,0.0},{0.0,1.0,0.0},{0.0,1.0,0.0},{0.0,1.0,0.0},{0.0,1.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.0}},
{{0.0,0.0,0.0},{1.0,0.6,0.0},{1.0,0.6,0.0},{1.0,0.6,0.0},{1.0,0.6,0.0},{1.0,0.6,0.0},{0.44,0.26,0.16},{0.0,0.0,0.0},{0.0,0.0,0.0},{0.44,0.26,0.16},{0.44,0.26,0.16},{0.44,0.26,0.16},{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.0}},
{{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.0},{0.44,0.26,0.16},{0.44,0.26,0.16},{0.44,0.26,0.16},{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.0}},
};
float4 main(float4 pos : SV_POSITION, float2 tex : TEXCOORD) : SV_TARGET{
float4 t = shaderTexture.Sample(samplerState, float2(1.0, 1.0));
float4 color = shaderTexture.Sample(samplerState, tex);
int div_num = 8;
int left = 40;
int top = 4;
int x_int = trunc((tex.x * Resolution.x - div_num*left)/div_num);
int y_int = trunc((tex.y * Resolution.y - div_num*top)/div_num);
if (x_int > left - 16 &&x_int < left && y_int > top && y_int < top + 16){
color.xyz += float3(dot4_color[y_int-top][x_int-left][0], dot4_color[y_int-top][x_int-left][1], dot4_color[y_int-top][x_int-left][2]);
}
return color;
}
パソコンのファンは停止し、GPUの負荷率も20%代に減った。
負荷を減らした際のポイント
- 大小のif文(条件分岐)は、割り算の答えの整数部で判断した。
- 変数をconst(定数)にすると多少、負荷が減った。
- 変数をmain関数の外に出した場合、「static」が必要になる。
蛇足:ドット文字との比較
文字データは横の黒線が入るので、やはりHLSLが綺麗。
HLSLでつまづいたメモ
以下を読解してメモします。ちなみに私はマイクロソフトのページが分かりにくいです。
その1
float型を存在する一方、「float2」や「float3」が存在する。「float」はわかる。Go言語やC#を経験してたので、「float32」が32ビット、「float64」が64ビットを意味するのは理解できる。しかし「float2」ってなんだ!「float3」ってなんなんだ!
float2 fVector = { 0.2, 0.3};
その2【数字の後ろの「f」について】
よく、数字の後ろに「f」が付くサンプルのプログラムを見るが、float型を意味する様です。しかし「f」がなくてもプログラムが動く。不思議だ。魔物だ。
float3 fVector = { 0.2f, 0.3f, 0.4f };
その3【行列(マトリックス)の型は「float2x2」が存在する】
なんだそれは!
float2x2 fMatrix = { 0.0f, 0.1, // 1行目
2.1f, 2.2f // 2行目
};
その4【4行4列の行列の型】
float4x4 変数名 = float4( {0,0,0,0}, {1,1,1,1}, {2,2,2,2}, {3,3,3,3} );
その5【5行6列の行列の型】
int dot_color[5][6] ={{1,0,0,0,1,1},{0,1,0,1,1,1},{1,0,0,0,1,1},{1,1,1,1,1,1},{1,1,1,1,1,1}};
その6
マトリックスは、次の構文で宣言することもできる。しかし4行4列を超えるとエラーが出た。限界?
matrix <Type, Number> VariableName
//↓こんな感じ
matrix <float, 2, 2> fMatrix = { 0.0f, 0.1, // row 1
2.1f, 2.2f // row 2
};
その7 ベクトルの配列数の上限
配列数を増やして確かめた結果、要素が4つのfloat4等のベクトルの配列の上限は最大4096個までであった。
配列数が4096を超えると、HLSLのコンパイルが失敗する。
4096の配列数は合計が上限であり、例えば2048┼2048┼1はエラーとなる。
float4 aiueo_kakikukeko[64][64]//限界
ちなみに、4096を超える方法もあるようだが、よくわからない。(4096×16=65526)
そうなると、ドット絵は64×64が上限になってしまうが、一つのfloat4中に、情報を詰めればもう少しドット絵を増やせるだろう。
他のページからの参考
参考1:格子状の線を色のグラデーションを付けて引く
Texture2D shaderTexture;
SamplerState samplerState;
cbuffer PixelShaderSettings {
float Time;//1ベクトル=スカラー値
float Scale;//1ベクトル=スカラー値
float2 Resolution;//2✕1ベクトル
float4 Background;//4✕1ベクトル
};
float3 hsv2rgb(float3 hsv){
// ref. https://gist.github.com/iUltimateLP/5129149bf82757b31542
float4 K = float4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
//frac(x) x の小数部を返します。
//abs(x) 絶対値
float3 p = abs(frac(hsv.xxx + K.xyz) * 6.0 - K.www);
//lerp(x,y,a) xとyの間の線形補間。
//clamp( x, min, max ) xがmin以下ならmin, max以上ならmax
return hsv.z * lerp(K.xxx, clamp(p - K.xxx, 0.0, 1.0), hsv.y);
}
float4 main(float4 pos : SV_POSITION, float2 tex : TEXCOORD) : SV_TARGET
{
float4 t = shaderTexture.Sample(samplerState, float2(0.0, 0.0));
float4 color = shaderTexture.Sample(samplerState, tex);
if (tex.x * Resolution.x % 20 < 1.0 || tex.y * Resolution.y % 20 < 1.0)
{
color.xyz += hsv2rgb(float3(t.x * 8 + (tex.x + tex.y) / 4, 1.0, 0.6));
}
return color;
}
参考2:複数のグラデーション
Texture2D shaderTexture;
SamplerState samplerState;
cbuffer PixelShaderSettings {
float Time;
float Scale;
float2 Resolution;
float4 Background;
};
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);
const float thickness = 0.1;
float ny = floor(tex.y/thickness);
float my = tex.y%thickness;
const float pi = 3.141592654;
float cola = ny*2.0*pi;
float3 col = 0.75+0.25*float3(sin(cola*0.111), sin(cola*0.222), sin(cola*0.333));
float brightness = 1.0-smoothstep(0.0, thickness*0.5, abs(my - 0.5*thickness));
float3 rasterColor = col*brightness;
float3 final = rasterColor;
final = lerp(final, float(0.0), ocolor.w);
final = lerp(final, color.xyz, color.w);
return float4(final, 1.0);
}
感想
HLSLは線や曲線が書くのが苦手な気がする。
Link集
参考にしたYouTube
↓「Windowsターミナル用のカスタムピクセルシェーダーを作成する方法を探る。」内容は英語ですが、画面内のHLSLは参考になった。
参考リンク
HLSLリファレンスまとめ
GLSL/HLSL/Metal 命令対応表