今回は、放射ブラーを載せます。
このブラーは、放射状にブラーをかけるエフェクトです。
爆発エフェクトで使用したりなど、使い道は多いです。
今回のシェーダーはピクセルシェーダーのみを使います。
放射ブラー
//グローバル変数宣言
float center;
float texelSize;
float blurPower = 50.0f;
sampler2D target;
//入力ピクセル構造体
struct PS_INPUT
{
float2 texcoord : TEXCOORD0; //テクスチャ座標
};
//ピクセルシェーダー
float4 ps_main(
PS_INPUT input,
uniform float2 center,
uniform float blurPower,
uniform float texelSize,
uniform sampler2D target
) : COLOR0
{
float4 color[10];
//方向ベクトルの取得
float2 dir = center - input.texcoord;
//長さの取得
float len = length( dir );
//オフセットの取得
float offset = normalize( dir ) * texelSize;
offset *= ( blurPower * len );
color[0] = tex2D( target, input.texcoord ) * 0.19f;
color[1] = tex2D( target, input.texcoord + offset ) * 0.17f;
color[2] = tex2D( target, input.texcoord + offset * 2.0f ) * 0.15f;
color[3] = tex2D( target, input.texcoord + offset * 3.0f ) * 0.13f;
color[4] = tex2D( target, input.texcoord + offset * 4.0f ) * 0.11f;
color[5] = tex2D( target, input.texcoord + offset * 5.0f ) * 0.09f;
color[6] = tex2D( target, input.texcoord + offset * 6.0f ) * 0.07f;
color[7] = tex2D( target, input.texcoord + offset * 7.0f ) * 0.05f;
color[8] = tex2D( target, input.texcoord + offset * 8.0f ) * 0.03f;
color[9] = tex2D( target, input.texcoord + offset * 9.0f ) * 0.01f;
return color[0] + color[1] + color[2] + color[3] + color[4] + color[5] + color[6] + color[7] + color[8] + color[9];
}
//テクニックの指定
technique explosionblur
{
//パスの指定
pass Pass_0
{
FragmentProgram = compile arbfp1 ps_main( center, blurPower, texelSize, target );
}
}
メインプログラム
#include "Matrix4.h"
#include "Color4.h"
#include "Vector2.h"
#include "Vector3.h"
#include "MathUtility.h"
#include "TGATexture.h"
#include "Shader.h"
#include <GL/glew.h>
#include <GL/glut.h>
#include <iostream>
#include <string>
#pragma comment( lib, "cg.lib" )
#pragma comment( lib, "cgGL.lib" )
#pragma comment( lib, "glew32.lib" )
static void display();
static void idle();
static void key( unsigned char state, int x, int y );
static void initializeGL();
static void initializeCg();
static void drawRect( float x, float y, float w, float h );
namespace {
//ブリンフォンシェーダー
Shader* blinn = NULL;
//ブラーシェーダー
Shader* blur = NULL;
//ワールド行列
Matrix4 World;
//透視変換行列
Matrix4 Projection;
//ビュー行列
Matrix4 View;
//回転角度
float angle;
//FBOID
unsigned int fbo;
//テクスチャID
unsigned int texture;
//バッファのサイズ
static const float BUFFER_SIZE = 1024.0f;
//中心位置
Vector2 Center( 0.5f, 0.5f );
}
//メイン関数
void main( int argc, char* argv[] )
{
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH );
glutInitWindowPosition( 0, 0 );
glutInitWindowSize( 640, 480 );
glutCreateWindow( "Explosion [[Blur]] Shader Test" );
//glewの初期化
int err = glewInit();
if( err != GLEW_OK ){
std::cout << glewGetErrorString( err ) << std::endl;
exit(0);
}
//初期化
initializeGL();
initializeCg();
//関数の登録
glutDisplayFunc( display );
glutIdleFunc( idle );
glutKeyboardFunc( key );
glutMainLoop();
}
void initializeGL()
{
glClearColor( 0.0f, 0.0f, 1.0f, 1.0f );
glViewport( 0, 0, 640, 480 );
//OpenGLでは何もさせない
//透視変換行列の設定
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
Projection.setIdentity();
Projection.setPerspective( 45.0f, 640.0f/480.0f, 0.1f, 100.0f );
//ビュー行列の設定
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
View.setIdentity();
View.setLookAt(
Vector3( 0.0f, 0.0f, 5.0f ),
Vector3( 0.0f, 0.0f, 0.0f ),
Vector3( 0.0f, 1.0f, 0.0f )
);
//回転角度の初期化
angle = 0.0f;
//ワールド行列の設定
Matrix4 translate, scale, rotate;
translate.setIdentity();
translate.setTranslate( Vector3( 0.0f, 0.0f, 0.0f ) );
scale.setIdentity();
scale.setScale( Vector3( 1.0f, 1.0f, 1.0f ) );
rotate.setIdentity();
rotate.setRotateY( angle );
World = rotate * translate * scale;
glDisable( GL_DEPTH_TEST );
glDisable( GL_LIGHTING );
glDisable( GL_CULL_FACE );
//テクスチャのバインド
glGenTextures( 1, &texture );
glBindTexture( GL_TEXTURE_2D, texture );
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 );
glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 );
TGATexture::load( 0, "back.tga" );
}
void initializeCg()
{
//エフェクトの生成
blinn = new Shader( "BlinnPhong.cgfx" );
blur = new Shader( "ExplosionBlur.cgfx" );
//テクニックの取得
blinn->setTechnique( "blinnphong" );
blur->setTechnique( "explosionblur" );
//パラメータの設定
blinn->setParameter( "world", World );
blinn->setParameter( "view", View );
blinn->setParameter( "projection", Projection );
blur->setParameter( "center", Center );
blur->setParameter( "texelSize", (1.0f/BUFFER_SIZE+1.0f/BUFFER_SIZE)*0.5f );
blur->setTexture( "target", texture );
}
//描画
void display()
{
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, fbo );
glPushAttrib( GL_VIEWPORT_BIT );
glViewport( 0, 0, BUFFER_SIZE, BUFFER_SIZE );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glEnable( GL_TEXTURE_2D );
glBindTexture( GL_TEXTURE_2D, TGATexture::getID( 0 ) );
drawRect( 0, 0, 640, 480 );
glDisable( GL_TEXTURE_2D );
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 );
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 );
drawRect( 0, 0, 200, 200 );
glDisable( GL_TEXTURE_2D );
//バッファの切り替え
glutSwapBuffers();
}
//更新
void idle()
{
//回転角度の更新
angle += 1.0f;
//ワールド行列の更新
Matrix4 translate, scale, rotate;
translate.setTranslate( Vector3( 0.0f, 0.0f, 0.0f ) );
scale.setScale( Vector3( 1.0f, 1.0f, 1.0f ) );
rotate.setRotateY( angle );
World = rotate * scale * translate;
//パラメータの設定
blinn->setParameter( "world", World );
blinn->setParameter( "view", View );
blinn->setParameter( "projection", Projection );
//再描画
glutPostRedisplay();
}
//キー状態
void key( unsigned char state, int x, int y )
{
switch( state ){
//エスケープが押されたら終了
case '\033':
delete blinn;
delete blur;
exit( 0 );
break;
}
}
void drawRect( float x, float y, float w, float h )
{
//レンダリングモードの退避
glPushAttrib( GL_ENABLE_BIT | GL_CURRENT_BIT | GL_COLOR_BUFFER_BIT );
glDisable( GL_LIGHTING );
glDisable( GL_DEPTH_TEST );
glDisable( GL_CULL_FACE );
//透視変換行列の退避
glMatrixMode( GL_PROJECTION );
glPushMatrix();
//透視変換行列の設定
glLoadIdentity();
gluOrtho2D( 0, 640, 480, 0 );
//モデルビュー変換行列の退避
glMatrixMode( GL_MODELVIEW );
glPushMatrix();
//変換行列の初期化
glLoadIdentity();
//四角形の描画
glBegin( GL_QUADS );
glTexCoord2f( 0, 0 );
glVertex2f( x, y);
glTexCoord2f( 0, 1);
glVertex2f( x, y+h);
glTexCoord2f( 1, 1);
glVertex2f( x+w, y+h);
glTexCoord2f( 1, 0);
glVertex2f( x+w, y );
glEnd();
//モデルビュー変換行列の復帰
glPopMatrix();
//透視変換行列の復帰
glMatrixMode( GL_PROJECTION );
glPopMatrix();
//モデルビュー変換行列に設定
glMatrixMode( GL_MODELVIEW );
//レンダリングモードの復帰
glPopAttrib();
}
実行結果は以下のようになるはずです。
今回も背景を表示してあります。背景を表示しておかないと
ブラーのかかり具合が分かりにくいので表示を行っています。
設定するパラメータなどは違いますが、基本的なC++プログラムは
ブラーシェーダーと一緒なのでそちらを参考にしてください。
今回は、中心点は画面の真ん中に設定してあります。
最終更新:2009年04月23日 15:09