lucille 開発日記やspinで紹介されていた、バンプマップの親戚(?)であるパララクスマッピングを実装してみました。
で、いつものようにプログラムです。
ソースには、いつものように適当にファイルが入っています。
大事なファイルは次のものです。
main.h | アプリケーションのヘッダ |
main.cpp | アプリケーションのソース |
hlsl.fx | シェーダプログラム |
素材としては、DirectX 9 シェーダプログラミングブックで使ったデカールや法線マップにその基となった高さマップを使っています。
カーソルキーで、カメラが回って、zやxでズームが変えられます。 また、スペースキーで「パララクス マッピング」と「バンプ マッピング」の切り替えができます。
パララクスマッピングとは、テクスチャ座標を、高さに比例させて視線方向にずらして他のテクスチャをサンプリングする方法です。
バンプマップよりも強くでこぼこ間が出ます。
負荷もバンプマッピングとそれほど変わらないようです。
今回の方法は、Terry Welsh氏による実装を追っただけですが、パララクスマッピングは次のように日本人が発展させてきたもののようです。
spin からの引用
解説資料には次のものがあります。東京大学(当時)の金子智道氏らの研究がベースとなっており、 Welsh氏は、近似による方法の簡略化(視線ベクトルのz成分による除算を省略)と、 OpenGLの頂点プログラム(ARB)とフラグメントプログラム(ARB)での処理の記述などを行っています。 (1) 「Detailed Shape Representation with Parallax Mapping(パララクスマッピングによる3次元形状表現)」 (著者: 金子智道氏, 高幣俊之氏, 稲見昌彦氏, 川上直樹氏, 柳田康幸氏, 前田太郎氏 舘暲氏 / ICAT 2001 / 英文PDF) (2) 「Parallax Mapping with Offset Limiting: A PerPixel Approximation of Uneven Surfaces」 (著者: Terry Welsh氏 / 2004年1月 / PDF) 最初の論文は、2000年9月に、日本バーチャルリアリティ学会第5回大会にて、 東京大学(当時)の、高幣俊之氏、稲見昌彦氏、柳田康幸氏、前田太郎氏、舘暲氏が発表した論文 「両眼立体視のためのリアルタイム・テクスチャマッピング手法」になるようです。
パララクスマッピングのプログラムは、ピクセルシェーダの最初に高さマップを読み込みます。そしたら、それ以外のテクスチャをサンプリングするテクスチャ座標を、その高さで重みをつけて頂点座標系での視線ベクトル(の接線方向と従法線方向)でずらします。
あとは、バンプマップと同じようにします。ここで、ピクセルシェーダに入力された E と L は、頂点座標系での視線ベクトルとライトベクトルです。
hlsl.fx 0110: float4 PS( VS_OUTPUT In) : COLOR 0111: { 0112: float3 L = normalize(In.L); // ライトベクトル 0113: float3 E = normalize(In.E); // 視線ベクトル 0114: 0115: float h = tex2D( HeightSamp, In.Tex );// 高さマップのサンプリング 0116: 0117: float2 Tex = In.Tex + 0.03 * h * E.xy; 0118: 0119: float3 N = 2.0f*tex2D( NormalSamp, Tex ).xyz-1.0;// 法線マップからの法線 0120: float3 R = reflect(-E, N); // 反射ベクトル 0121: float amb = -vLightDir.w; // 環境光の強さ 0122: 0123: return In.Color * tex2D( DecaleSamp, Tex ) // 拡散光と環境光には、 0124: * (max(0, dot(N, L))+amb) // 頂点色とテクスチャの色を合成する 0125: + 0.3f * pow(max(0,dot(R, L)), 8); // Phong 鏡面反射光 0126: }
ちなみに、バンプマッピングのプログラムは、次のようになります。
hlsl.fx 0129: float4 PS_BUMP( VS_OUTPUT In) : COLOR 0130: { 0131: float3 L = normalize(In.L); // ライトベクトル 0132: float3 E = normalize(In.E); // 視線ベクトル 0133: 0134: float h = tex2D( HeightSamp, In.Tex );// 高さマップのサンプリング 0135: 0136: float2 Tex = In.Tex; 0137: 0138: float3 N = 2.0f*tex2D( NormalSamp, Tex ).xyz-1.0;// 法線マップからの法線 0139: float3 R = reflect(-E, N); // 反射ベクトル 0140: float amb = -vLightDir.w; // 環境光の強さ 0141: 0142: return In.Color * tex2D( DecaleSamp, Tex ) // 拡散光と環境光には、 0143: * (max(0, dot(N, L))+amb) // 頂点色とテクスチャの色を合成する 0144: + 0.3f * pow(max(0,dot(R, L)), 8); // Phong 鏡面反射光 0145: }
まぁ、10分ぐらいでできたのですが、どうでしょうねぇ?
バンプよりは強くかかりますが、少し違和感を感じます。