BumpMap

今回は、バンプマッピングを載せます。

バンプマッピングは、凹凸の無い平面をライティングによって
凹凸があるかのように見せる技術です。

バンプマッピングを行うのに2種類のテクスチャが必要になります。
法線情報をテクスチャに書き込んだ法線マップとデカールテクスチャが必要になります。

デカールテクスチャ 例 法線テクスチャ 例

法線テクスチャを自分で作るのは面倒なので
自分はGIMPというフリーソフトの法線マップを出力するツールを使っています。
http://nifelheim.dyndns.org/~cocidius/normalmap/

以下実装

バンプマッピング
//グローバル変数宣言
float4x4 world;      //ワールド行列
float4x4 view;       //ビュー行列
float4x4 projection; //プロジェクション行列 
float3 light = float3( 10.0f, 10.0f, 10.0f ); //ライトの位置
	
sampler2D base;      //テクスチャ
sampler2D normal;    //法線テクスチャ
	
//入力頂点構造体
struct VS_INPUT
{
	float4 position : POSITION;  //頂点座標
	float3 normal   : NORMAL;	 //法線ベクトル
	float2 texcoord : TEXCOORD0; //テクスチャ座標
	float4 color	: COLOR00;   //色
	float3 tangent  : TANGENT0;  //接ベクトル
	float3 binormal : BINORMAL0; //従法線ベクトル
};
	
//出力頂点構造体
struct VS_OUTPUT
{
	float4 position  : POSITION;  //頂点座標
	float3 normal	 : TEXCOORD1; //法線ベクトル
	float2 texcoord  : TEXCOORD0; //テクスチャ座標
	float4 color	 : COLOR0;    //色
	float3 light	 : TEXCOORD4; //ライトベクトル
	float3 view		 : TEXCOORD2; //ビューベクトル
	float3 halfAngle : TEXCOORD3; //二等分ベクトル
};

//頂点シェーダー
VS_OUTPUT vs_main(
	VS_INPUT input,
	uniform float4x4 world,
	uniform float4x4 view,
	uniform float4x4 projection,
	uniform float3 light
)
{
	VS_OUTPUT output;
	
	//ワールドビュー行列
	float4x4 WV = mul( world, view );
	
	//法線ベクトルの座標変換
	output.normal = mul(input.normal,(float3x3)WV);
	
	//ワールドビュープロジェクション行列
	float4x4 WVP = mul( WV, projection );
	
	//視点座標系の頂点を求める
	float3 PosEye = mul( input.position, WV );
	
	//視点座標系のライト位置を求める
	float3 LightPosEye = mul( light, (float3x3)view );
	
	//ライト方向のベクトルを求める
	float3 L = normalize( LightPosEye - PosEye );
	//視点方向のベクトルを求める
	float3 V = normalize( -PosEye );
	//二等分ベクトルを求める
	float3 H = normalize( L+V );
	
	//法線ベクトルの座標変換
	float3 N = mul( input.normal, (float3x3)WV );
	//接ベクトルの座標変換
	float3 T = mul( input.tangent, (float3x3)WV );
	//従法線ベクトルの座標変換
	float3 B = mul( input.binormal, (float3x3)WV );
	
	//テクスチャ座標系に変換する行列を作成する
	float3x3 TBN = float3x3( T, B, N );
	
	//L,V,Hベクトルをテクスチャ座標系に変換
	output.light = mul( TBN, L );
	output.view = mul( TBN, V );
	output.halfAngle = mul( TBN, H );
	
	//頂点座標の座標変換
	output.position = mul(input.position,WVP);
	
	//テクスチャ座標を設定
	output.texcoord = input.texcoord;
	
	//色を設定
	output.color = input.color;
		
	return output;
}
	
//ライトカラー
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 = 90.0f;
	
//入力ピクセル構造体
struct PS_INPUT
{
	float2 texcoord : TEXCOORD0; //テクスチャ座標
	float4 color	: COLOR0;    //色
	float3 normal	: TEXCOORD1; //法線
	float3 light	: TEXCOORD4; //ライトベクトル
	float3 view		 : TEXCOORD2; //ビューベクトル
	float3 halfAngle : TEXCOORD3; //二等分ベクトル
};
	
float4 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 sampler2D base,
	uniform sampler2D normal
) : COLOR0
{
	//各ベクトルを正規化
	float3 L = normalize( input.light );
	float3 V = normalize( input.view );
	float3 H = normalize( input.halfAngle );
		
	//法線マップから法線ベクトルを取得
	float3 N = normalize( tex2D( normal, input.texcoord ).xyz * 2.0f - 1.0f );
	
	//拡散反射光、鏡面反射光を計算する
	float diffuse = max(dot(N,L),0.0f);
	float specluar = pow(max(dot(N,H),0.0f),power);
	
	//ベーステクスチャのカラーを取得
	float4 baseColor = tex2D(base, input.texcoord );
	
	//環境光、拡散反射光、鏡面反射光を計算する
	float4 totalAmbient = Ambient * Ka * baseColor;
	float4 totalDiffuse = Diffuse * Kd * diffuse * baseColor;
	float4 totalSpecular = Specular * Ks * specluar;
	
	//最終的なカラーを計算する
	float4 color = totalAmbient + totalDiffuse + totalSpecular;
	
	return color;
}
	
technique bumpmapping
{	
	//パスの指定
	pass Pass_0
	{
		VertexProgram = compile arbvp1 vs_main( world,view, projection, light );
		FragmentProgram = compile arbfp1 ps_main( Ambient, Diffuse, Specular, Ka, Kd, Ks, power, base, normal );
	}
}

メインプログラム
#include "Matrix4.h"
#include "Color4.h"
#include "Vector2.h"
#include "Vector3.h"
#include "MathUtility.h"
#include "TGATexture.h"
#include "Shader.h"
#include <iostream>
#include <GL/glew.h>
#include <GL/glut.h>
 
#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();
 
namespace {
	//バンプマップシェーダー
	Shader* bump = NULL;
	//ワールド行列
	Matrix4 World;
	//透視変換行列
	Matrix4 Projection;
	//ビュー行列
	Matrix4 View;
	//回転角度
	float angle;
}
 
//メイン関数
void main( int argc, char* argv[] )
{
	glutInit( &argc, argv );
	glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH );
	glutInitWindowPosition( 0, 0 );
	glutInitWindowSize( 640, 480 );
 
	glutCreateWindow( "BumpMapping Shader Test" );
 
	//初期化
	initializeGL();
	initializeCg();
	//関数の登録
	glutDisplayFunc( display );
	glutIdleFunc( idle );
	glutKeyboardFunc( key );
 
	glutMainLoop();
}
 
void initializeGL()
{
 
	glewInit();
 
	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 = translate * scale * rotate;
 
	glDisable( GL_DEPTH_TEST );
	glDisable( GL_LIGHTING );
	glDisable( GL_CULL_FACE );
 
	TGATexture::load( 0, "rockwall.tga" );
	TGATexture::load( 1, "rockwall_normal.tga" );
}
 
void initializeCg()
{
	//シェーダーの生成
	bump = new Shader( "BumpMapping.cgfx" );
	//テクニックの取得
	bump->setTechnique( "bumpmapping" );
	//パラメータの設定
	bump->setParameter( "world", World );
	bump->setParameter( "view", View );
	bump->setParameter( "projection", Projection );
	bump->setTexture( "base", TGATexture::getID( 0 ) );
	bump->setTexture( "normal", TGATexture::getID( 1 ) );
}
 
//描画
void display()
{
	glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
 
	bump->begin();
	for( unsigned int pass = 0; pass < bump->getPassNum(); pass++ )
	{
		bump->setPass( pass );
 
		glBegin( GL_QUADS );
		glNormal3f( 0.0f, 0.0f, 1.0f );				//法線ベクトル
		glVertexAttrib3f( 14, 1.0f, 0.0f, 0.0f );	//接ベクトル
		glVertexAttrib3f( 15, 0.0f, -1.0f, 0.0f );	//従法線ベクトル
		glTexCoord2f( 0.0f, 0.0f );
		glVertex3f( -1.0f, 1.0f, 0.0f );
		glTexCoord2f( 0.0f, 1.0f );
		glVertex3f( -1.0f, -1.0f, 0.0f );
		glTexCoord2f( 1.0f, 1.0f );
		glVertex3f( 1.0f, -1.0f, 0.0f );
		glTexCoord2f( 1.0f, 0.0f );
		glVertex3f( 1.0f, 1.0f, 0.0f );
		glEnd();
	}
	bump->end();
	
	//バッファの切り替え
	glutSwapBuffers();
}
 
//更新
void idle()
{
	//回転角度の更新
	angle += 1.0f;
 
	//ワールド行列の更新
	Matrix4 translate, scale, rotate;
	translate.setTranslate( Vector3( 0.0f, 0.0f, 0.0f ) );
	scale.setScale( Vector3( 2.0f, 2.0f, 2.0f ) );
	rotate.setRotateY( angle );
	World = translate * scale * rotate;
 
	//パラメータの設定
	bump->setParameter( "world", World );
 
	//再描画
	glutPostRedisplay();
}
  
//キー状態
void key( unsigned char state, int x, int y )
{
	switch( state ){
		//エスケープが押されたら終了
		case '\033':
			delete bump;
			exit( 0 );
			break;
	}
}

実行結果は以下のようになると思います。
最終更新:2009年06月05日 16:23
ツールボックス

下から選んでください:

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