daruma3940の日記

理解や文章に間違い等あればどんなことでもご指摘お願いします

「自分用」DXライブラリでHLSLシェーダー

新しい記事がQiitaに出ていて、そちらの方が洗練されているので以下記事を参考にした方がいい。
(IKUSAAAAAAAN!の作者さんによる記事だし)
qiita.com

ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
「DXライブラリでピクセルシェーダを使う その1-Quita」を参考にした。
情報がまとまってるページだけど死んでしまっているので「このページを参考にしました!」だけじゃなくてちゃんとどんなことをしたのか書いておこうと思う。






hoge.fx がHLSLシェーダーのソースコード
DXライブラリをダウンロードしたときについてくるShaderCompilier.exeを使ってコンパイルするとhoge.psoというのが作成される。

ShaderCompiler.exe /Tps_2_0 hoge.fx

ここで /Tps_2_0 はピクセルシェーダ2.0を使うということ。
これは32のテクスチャ命令と64の算術命令までしか実行できないので、/Tps_3_0にした方が良いのかもしれない。

DxLib_Init()を呼ぶ前に

SetUseDirect3DVersion(DX_DIRECT3D_9EX);

を呼ぶ必要がある。(これはピクセルシェーダーのバージョンによるかもしれない。)


以下はコードの必要そうな部分を抜き出してきたつぎはぎ(ちゃんと動かないかもしれない)
ーーCPPーーー

#include "DxLib.h"
typedef int ImageHandle;
typedef int ShaderHandle;

ShaderHandle  barreldistort;
ImageHandle imh;
const std::string BarrelDistortshaderpath = "./shader/ShaderCompiler/barreldistort.pso";

int ShaderScreen;
//頂点の設定
VERTEX2DSHADER vertex[4];

void initVertex() {
	for (int i = 0; i < 4; i++)
	{
		vertex[i].pos = VGet((i % 2) * 640.0f, (i / 2) * 640.0f, 0);
		vertex[i].rhw = 1.0f;
		vertex[i].dif = GetColorU8(255, 255, 255, 255);
		vertex[i].spc = GetColorU8(0, 0, 0, 0);
		vertex[i].u = vertex[i].su = (float)(i % 2);
		vertex[i].v = vertex[i].sv = (float)(i / 2);
	}
}


void TestBarrelShader() {
	float mousex = float(MyMouse::posx) / 640.0f;
	float mousey =float(MyMouse::posy) / 640.0f;
	

	SetDrawScreen(ShaderScreen);

	
	DrawModiGraph(0, 0, 640, 0, 640, 480, 0, 480, imh, TRUE);

	SetDrawScreen(DX_SCREEN_BACK); 
   //定数渡し
	SetUseTextureToShader(0, ShaderScreen);//0なのでs0
	SetPSConstSF(0, 1.30f);//0なのでc0
	SetPSConstSF(1, 2.0f);//0なのでc1

	SetPSConstSF(2, mousex);//0なのでc2
	SetPSConstSF(3, mousey);//0なのでc3

  //シェーダーを適用
	SetUsePixelShader(barreldistort);
	DrawPrimitive2DToShader(vertex, 4, DX_PRIMTYPE_TRIANGLESTRIP);


}

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
						 LPSTR lpCmdLine, int nCmdShow )
{
	SetUseDirect3DVersion(DX_DIRECT3D_9EX);//これを入れないとシェーダーが使えない

	ChangeWindowMode(TRUE);
	if( DxLib_Init() == -1 )	// DXライブラリ初期化処理
	{
		 return -1;				// エラーが起きたら直ちに終了
	}
       imh = (ImageHandle)LoadGraph("BG.png");
      const std::string BarrelDistortshaderpath = "./shader/barreldistort.pso";

      barreldistort = LoadPixelShader(BarrelDistortshaderpath.c_str());


       ShaderScreen = MakeScreen(640, 480);
	initVertex();
	while (!ProcessMessage() && !ClearDrawScreen() && !Key[KEY_INPUT_ESCAPE])
	{

		SetDrawScreen(DX_SCREEN_BACK);
		// 画面をクリア

		ClearDrawScreen();
		
		
		//画面の更新処理
		{
	
			TestBarrelShader();
		
		}
		MousePos();

	
		ScreenFlip();
	
	
		if (ProcessMessage() != 0) break;

	}

	
	DxLib_End() ;				// DXライブラリ使用の終了処理

	return 0 ;					// ソフトの終了
}

ーーHLSLーー
これBarrelDistortのプログラム。
t!=1.0にしたときの境界があんまりきれいにならないので上手い処理の方法があれば教えてください
PSいい感じになりました(注意)無理矢理画像の縦幅と横幅を640:640にしているので元のInput画像が縦に拡大されてしまっています)
https://www.geeks3d.com/20140213/glsl-shader-library-fish-eye-and-dome-and-barrel-distortion-post-processing-filters/2/

struct PS_INPUT
{
    float4 DiffuseColor       : COLOR0 ;
    float4 SpecularColor      : COLOR1 ;
    float2 TextureCoord0      : TEXCOORD0 ;
    float2 TextureCoord1      : TEXCOORD1 ;
} ;

// ピクセルシェーダーの出力
struct PS_OUTPUT
{
    float4 Output             : COLOR0 ;
} ;


sampler Texture : register( s0 ) ;

float BarrelPower : register( c0 );
float t : register( c1 );

float mousex : register( c2 );
float mousey : register( c3 );

PS_OUTPUT main( PS_INPUT PSInput )
{
    PS_OUTPUT PSOutput ;

    float2 xy=2.0*PSInput.TextureCoord0.xy-1.0;
    float2 mouse;
    mouse.x=mousex;
    mouse.y=mousey;
    mouse=2.0*mouse.xy-1.0;
    
    float2 xy2=t*(xy-mouse);
    float dist=length(xy2);
    float2 CalcPos;
    float4 TextureColor;

    if(dist>=1.0){
        CalcPos=PSInput.TextureCoord0.xy;
        TextureColor = tex2D( Texture , CalcPos );
    }
    else
    {
        float theta=atan2(xy2.y,xy2.x);
        float dist2=pow(dist,BarrelPower);
        //float dist2=dist*t;

        CalcPos.x=dist2*cos(theta);
        CalcPos.y=dist2*sin(theta);
        CalcPos*=1.0/t;
        CalcPos+=mouse;
        CalcPos=0.5*(CalcPos+1.0);
        TextureColor = tex2D( Texture , CalcPos );
        TextureColor.rgb  -= clamp(0.3*(1.0-dist),0.0,0.8);
    }
     
    PSOutput.Output = TextureColor;
    return PSOutput;
}

こんな感じになる

https://twitter.com/daruma3940/status/1199724459499802624?s=20