今回は、バンプマッピングを載せます。
バンプマッピングは、凹凸の無い平面をライティングによって
凹凸があるかのように見せる技術です。
バンプマッピングを行うのに2種類のテクスチャが必要になります。
法線情報をテクスチャに書き込んだ法線マップとデカールテクスチャが必要になります。
デカールテクスチャ 例 法線テクスチャ 例

以下実装
バンプマッピング
//グローバル変数宣言
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