LightBloom

今回は、ライトブルームの記事を載せます。

基本的なものは、ブラーの処理を少し変更しただけなので
変更点のみ載せようと思います。

今回は、ブラーのときとは違いレンダーターゲットを二枚使用します。
設定の仕方はOpenGLでMultiRenderTargetを参照してください

その辺の変更点と、ブリンフォンシェーダーの変更点のみです。

ブラーの処理はまったく一緒なのでそのまま流用できます。

以下、変更点など。

ブリンフォンシェーダーの変更点は
ピクセルシェーダーのみです。
ブリンフォンシェーダー 変更点
//ライトカラー
float4 Ambient = float4( 1.0f, 1.0f, 1.0f, 1.0f );
float4 Diffuse = float4( 1.0f, 1.0f, 1.0f, 1.0f );
float4 Specular = float4( 1.0f, 1.0f, 1.0f, 1.0f );
//マテリアルカラー
float4 Ka = float4( 0.2f, 0.2f, 0.2f, 1.0f );
float4 Kd = float4( 0.6f, 0.6f, 0.6f, 1.0f );
float4 Ks = float4( 1.0f, 1.0f, 1.0f, 1.0f );
float power = 30.0f;

//追加点1
float bloomPower = 100.0f;

//入力ピクセル構造体
struct PS_INPUT
{
	float4 color	: COLOR0; //色
	float3 normal	: TEXCOORD1; //法線
	float3 light	: TEXCOORD0; //ライトベクトル
	float3 view		 : TEXCOORD2; //ビューベクトル
	float3 halfAngle : TEXCOORD3; //二等分ベクトル
};

//追加点2
//出力ピクセル構造体
struct PS_OUTPUT
{
	float4 color0 : COLOR0;
	float4 color1 : COLOR1;
};

//ピクセルシェーダー
PS_OUTPUT ps_main( 
	PS_INPUT input,
	uniform float4 Ambient,
	uniform float4 Diffuse,
	uniform float4 Specular,
	uniform float4 Ka,
	uniform float4 Kd,
	uniform float4 Ks,
	uniform float power,
	uniform float bloomPower
)
{
	PS_OUTPUT output;
	
	//ライトベクトルの正規化
	float3 L = normalize( input.light );
	//法線の正規化
	float3 N = normalize( input.normal );
	//ビューベクトルの正規化
	float3 V = normalize( input.view );
	//二等分べkとるの正規化
	float3 H = normalize( input.halfAngle );
	
	//ディフーズ
	float diffuse = max( dot( L, N ), 0 );
	//スペキュラ
	float specular = pow( max( dot( N, H ), 0 ), power );
	
	
	//環境光
	float4 totalAmbient = Ambient * Ka * input.color;
	//拡散反射光
	float4 totalDiffuse = Kd * Diffuse * diffuse * input.color;
	//鏡面反射光
	float4 totalSpecular = Ks * Specular * specular;
	
//追加点3
	float p = specular * bloomPower;
	
	//色情報を設定
	output.color0 = totalAmbient + totalDiffuse + totalSpecular;
	
//追加点4
	//光度情報設定
	output.color1 = float4( p, p, p, 1.0f );
	
	return output;
}

//テクニックの指定
technique blinnphong
{	
	//パスの指定
	pass Pass_0
	{
		CullFaceEnable = true;
		CullFace = Back;
		DepthTestEnable = true; //デプステストを有効
		VertexProgram = compile arbvp1 vs_main( world, view, projection, light );
		FragmentProgram = compile arbfp1 ps_main( Ambient, Diffuse, Specular, Ka, Kd, Ks, power, bloomPower );
	}
}

メインプログラム 変更点
namespace {
	//ブリンフォン
	Shader* blinn = NULL;
	//ブラー
	Shader* blur = NULL;

	//ワールド行列
	Matrix4 World;
	//透視変換行列
	Matrix4 Projection;
	//ビュー行列
	Matrix4 View;
	//回転角度
	float angle;
	//FBOID
	unsigned int fbo;
	//テクスチャID 変更点
	unsigned int texture[2];

	//バッファのサイズ
	static const float BUFFER_SIZE = 1024.0f;
}

void initializeGL()
{
//テクスチャのバインドの部分が変更点 それ以外はそのままで大丈夫です
	//テクスチャのバインド
	glGenTextures( 2, texture );
	glBindTexture( GL_TEXTURE_2D, texture[0] );
	
	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
	
	glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, BUFFER_SIZE, BUFFER_SIZE, 0, GL_RGBA, GL_FLOAT, 0 );
	
	glBindTexture( GL_TEXTURE_2D, texture[1] );
	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
	
	glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, BUFFER_SIZE, BUFFER_SIZE, 0, GL_RGBA, GL_FLOAT, 0 );
	glBindTexture( GL_TEXTURE_2D, 0 );
	
	glGenFramebuffersEXT( 1, &fbo );
	glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, fbo );
	glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, texture[0], 0 );
	glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, texture[1], 0 );
	glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 );
}

void initializeCg()
{
	//シェーダーの生成
	blinn = new Shader( "BlinnPhong.cgfx" );
	blur = new Shader( "Blur.cgfx" );
  
	//テクニックの設定
	blinn->setTechnique( "blinnphong" );
	blur->setTechnique( "blur" );

	//パラメータの設定
	blinn->setParameter( "world", World );
	blinn->setParameter( "view", View );
	blinn->setParameter( "projection", Projection );

	blur->setParameter( "u", 1.0f/(BUFFER_SIZE/4.0f) );
	blur->setParameter( "v", 1.0f/(BUFFER_SIZE/4.0f) );
//変更点
	blur->setTexture( "target", texture[1] );
}

//描画
void display()
{
	glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

	glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, fbo );
	 
	//ここも重要 追加点
	unsigned int attachments[] = {GL_COLOR_ATTACHMENT0_EXT,GL_COLOR_ATTACHMENT1_EXT};
	glDrawBuffers( 2, attachments );

	glPushAttrib( GL_VIEWPORT_BIT  );
	glViewport( 0, 0, BUFFER_SIZE, BUFFER_SIZE );
	glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

	blinn->begin();
	for( unsigned int pass = 0; pass < blinn->getPassNum(); pass++ ){
		blinn->setPass( pass );
		//トーラスの描画
		//glutSolidSphere( 0.5f, 32, 32 );
		glutSolidTorus( 0.5f, 1.0f, 4, 4 );
		//glutSolidCube( 0.5f );
	}
	blinn->end();

	glPopAttrib();
	glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 );

	glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

	blur->setTexture( "target", texture[1] );

	glEnable( GL_TEXTURE_2D );
	glBindTexture( GL_TEXTURE_2D, texture[0] );
	drawRect( 0, 0, 640, 480 );
	glDisable( GL_TEXTURE_2D );

	blur->begin();

	for( unsigned int pass = 0; pass < blur->getPassNum(); pass++ ){
		blur->setPass( pass );
		
		drawRect( 0, 0, 640, 480 );

	}
	blur->end();

	//Framebufferの表示
	glEnable( GL_TEXTURE_2D );

	glBindTexture( GL_TEXTURE_2D, texture[0] );
	drawRect( 0, 0, 200, 200 );

	glBindTexture( GL_TEXTURE_2D, texture[1] );
	drawRect( 0, 200, 200, 200 );

	glDisable( GL_TEXTURE_2D );

	//バッファの切り替え
	glutSwapBuffers();
}

実行結果は以下のようになるはずです。

ブリンフォンで二枚目のレンダーターゲットに光度情報を書き込み
光度情報書き込んだレンダーターゲットをブラーシェーダーで
ぼかして一枚目のレンダーターゲットに加算ブレンドを行っています。

最近のゲームではよく使われる技術ですので使えたほうが良いと思います。
最終更新:2009年04月10日 16:04
ツールボックス

下から選んでください:

新しいページを作成する
ヘルプ / FAQ もご覧ください。