読者です 読者をやめる 読者になる 読者になる

hayateasdf's blog

Unity,C#, javascript,C++,python,batなど

DirectX9 レンダリングターゲット

レンダリングターゲット思った以上にめんどくさいよぉぉぉぉ

とりあえずのクラス化行っきまぁぁっぁぁっぁす。

#define SAFE_RELEASE(a) { if(a) { (a)->Release(); (a)=NULL; } }

// レンダリングターゲット用
class RenderTarget{
private:
	LPDIRECT3DTEXTURE9 texture_;
	LPDIRECT3DSURFACE9 surface_;
	LPDIRECT3DSURFACE9 depth_;
	D3DVIEWPORT9	  viewport_;
	DWORD width_;
	DWORD height_;
public:
	RenderTarget() : texture_(NULL), surface_(NULL), depth_(NULL), width_(0), height_(0){}
	~RenderTarget(){ 
		SAFE_RELEASE(surface_);
		SAFE_RELEASE(depth_);
		SAFE_RELEASE(texture_);
	}
	bool CreateRenderTarget(LPDIRECT3DDEVICE9 device, DWORD width, DWORD height){
		width_ = width;
		height_ = height;
		if(!CreateTexture_(device)) return false;
		if(!CreateDepth_(device)) return false;
		if(!CreateSurface_(device) return false;
		CreateViewport_();
		
		return true;
	}
	void SetRenderTarget(LPDIRECT3DDEVICE9 device){
		device->SetRenderTarget(0, surface_);
		device->SetDepthStencilSurface(depth_);
		device->SetViewport(&viewport_);
	}
	LPDIRECT3DTEXTURE9 GetTexture(){ return texture_; }
private:
	bool CreateTexture_(LPDIRECT3DDEVICE9 device){
		if(FAILED(device->CreateTexture(width_, height_, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &texture_, NULL))){
			return false;
		}		
		return true;
	}
	bool CreateDepth_(LPDIRECT3DDEVICE9 device){
		if(FAILED(device->CreateDepthStencilSurface(width_, height_, D3DFMT_D16, D3DMULTISAMPLE_NONE, 0, TRUE, &depth_, NULL))){
			return false;
		}
		return true;
	}
	bool CreateSurface_(LPDIRECT3DDEVICE9 device){
		if(FAILED(texture_->GetSufaceLevel(0, &surface_))){
			return false;
		}
		return true;
	}
	void CreateViewport_(){
		viewport_.X = 0;
		viewport_.Y = 0;
		viewport_.Width = width_;
		viewport_.Height = height_;
		viewport_.MinZ = 0.0f;
		viewport_.MaxZ = 1.0f;		
	}
	
};
// バックバッファ保存用
class BackBuffer{
private:
	D3DVIEWPORT9 viewport_;
	LPDIRECTSURFACE9 surface_;
	LPDIRECTSURFACE9 depth_;
public:
	explicit BackBuffer(LPDIRECT3DDEVICE9 device){
		device->GetViewport(&viewport_);
		device->GetRenderTarget(0, &surface_);
		device->GetDepthStencilSurface(&depth_);
	}
	~BackBuffer(){
		SAFE_RELEASE(surface_);
		SAFE_RELEASE(depth_);		
	}
	void SetRenderTarget(LPDIRECT3DDEVICE9 device){
		device->SetRenderTarget(0, surface_);
		device->SetDepthStencilSurface(depth_);
		device->SetViewport(&viewport_);
	}
};

void Draw(LPDIRECT3DDEVICE9 device, LPDIRECT3DTEXTURE9 texture, int dx, int dy, int dw, int dh){
	// ---------------------------------------------------------------------------------------
	// バックバッファのデータをレンダリングターゲットを保存しないと、描画できなくなるので保存。
	// ---------------------------------------------------------------------------------------
	BackBuffer back(device);
	
	// ---------------------------------------------------------------------------------------
	// あらかじめ作成したレンダリングターゲットに切り替える
	// ---------------------------------------------------------------------------------------	
	RenderTarget render;
	render.CreateRenderTarget(device, dw, dh);
	render.SetRenderTarget(device);
	device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0, 1.0f, 0);
	
	// ---------------------------------------------------------------------------------------
	// 座標変換
	// ---------------------------------------------------------------------------------------
	const float screen_width = static_cast<float>(SCREEN_WIDTH);
	const float screen_height = static_cast<float>(SCREEN_HEIGHT);
	D3DXMATRIX proj(
		2/screen_w, 0.0f, 0.0f, 0.0f,
		0.0f, -2/screen_h, 0.0f, 0.0f,
		0.0f, 0.0f, 1.0f, 0.0f,
		-1.0f, 1.0f, 0.0f, 1.0f);
	device->SetTransform(D3DTS_PROJECTION, &proj);
	// ---------------------------------------------------------------------------------------
	// 描画
	// ---------------------------------------------------------------------------------------	
	device->SetTexture(0, texture);
	const flost x = (float)dx;
	const float y = (float)dy;
	const float w = (float)dw;
	const float h = (float)dh;
	struct MyVertex{ 
		float x, y, z;
		DWORD color;
		float u, v; 
	} vtx[] = {
		x, y, 0.0f,	~0,	0.0f, 0.0f,
		x + w, y, 0.0f, ~0, 1.0f, 0.0f,
		x, y + h, 0.0f,	 ~0, 0.0f, 1.0f,
		x + w, y + h, 0.0f, ~0, 1.0f, 1.0f,
	};
	
	device->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, vtx, sizeof(MyVertex));
	
	// ---------------------------------------------------------------------------------------
	// バックバッファに切り替え 描画
	// ---------------------------------------------------------------------------------------	
	back.SetRenderTarget(device);
	device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0, 1.0f, 0);
	device->SetTexture(0, render.GetTexture());
	device->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, vtx, sizeof(MyVertx));
	
}

さらにシェーダ使ってみた版

// shader.fx
float4x4 mWVP;
texture Tex;
sampler Samp = sampler_state{
	Texture = <Tex>;
	AddressU = Border;
	AddressV = Border;
};
struct VS_OUTPUT{
	float4 Pos : POSITION;
	float2 Tex : TEXCOORD0;
};
//-----------------------------------------------------------------
// vertex_shader
//-----------------------------------------------------------------
VS_OUTPUT vs_main(float4 Pos : POSITION, float2 Tex : TEXCOORD){
	VS_OUTPUT Out = (VS_OUTPUT)0;
	Out.Pos = mul(Pos, mWVP);
	Out.Tex = Tex;
	return Out;
}
//-----------------------------------------------------------------
// pixel_shader 今回簡単なサンプルでグレースケールの適当版
//-----------------------------------------------------------------
float4 ps_gray(float2 Tex : TEXCOORD0) : COLOR0
{
	float4 color = tex2D(Samp, Tex);
	return (color.r + color.g + color.b) * 0.3333f;
}
//-----------------------------------------------------------------
// テクニック
//-----------------------------------------------------------------
technique TShader{
	pass p0{
		VertexShader = compile vs_3_0 vs_main();
		PixelShader = compile ps_3_0 ps_gray();
	}
}
// main.cpp
void Draw(LPDIRECT3DDEVICE9 device, LPDIRECT3DTEXTURE9 texture, int dx, int dy, int dw, int dh){
	BackBuffer back(device);
	TRenderTarget render;
	render.CreateRenderTarget(device, dw, dh);
	render.SetRenderTarget(device);
	shader_.Clear(device, ARGB(255, 0, 0, 0));

	const float screen_w = static_cast<float>(SCREEN_WIDTH);
	const float screen_h = static_cast<float>(SCREEN_HEIGHT);
	D3DXMATRIX proj( 
		2/screen_w, 0.0f, 0.0f, 0.0f,
		0.0f, -2/screen_h, 0.0f, 0.0f,
		0.0f, 0.0f, 1.0f, 0.0f,
		-1.0f, 1.0f, 0.0f, 1.0f); 
	device->SetTransform(D3DTS_PROJECTION, &proj);
	D3DXMATRIX& world = proj;
	effect_->SetMatrix("mWVP", &world);
	effect_->SetTexture("Tex", texture);
	const float x = (float)dx;
	const float y = (float)dy;
	const float w = (float)dw;
	const float h = (float)dh;
	struct MyVertex{ 
		float x, y, z; 
		DWORD color;
		float u, v;
	} vtx[] = { 
		x, y, 0.0f,	~0,	0.0f, 0.0f,
		x + w, y, 0.0f, ~0, 1.0f, 0.0f,
		x, y + h, 0.0f,	 ~0, 0.0f, 1.0f,
		x + w, y + h, 0.0f, ~0, 1.0f, 1.0f,
	};
	// シェーダ描画 レンダリングターゲット
	effect_->SetTechnique("TShader");
	effect_->Begin(NULL, 0);
	effect_->BeginPass(0);
	device->DrawPrimitiveUP( D3DPT_TRIANGLESTRIP, 2, vtx, sizeof(MyVertex) );
	effect_->EndPass();
	effect_->End();

	// バックバッファ
	back.SetRenderTarget(device);
	device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0, 1.0f, 0);
	device->SetTexture(0, render.GetTexture());
	device->DrawPrimitiveUP( D3DPT_TRIANGLESTRIP, 2, vtx, sizeof(MyVertex) );
}

感覚で書いてるから間違ってるかも。
質問受け付けてないです。がんばって解決してね!