こんにちは
暑すぎてソブンガルデに招かれそうなくらいダラけているペチコです
意味のわからない事を言い出す時は、大抵何かに感化されている時なので気にしないでください
スカイリムたーのしい←やっぱりそれ
随分サボっているように見えますが、この間スカイリムで遊んだり、頂点テクスチャに失敗したり、エッジAAに失敗したり、スカイリムで遊んだりして忙しいのです
スカイリムが一歩リードですね
検索してたら、ライブラリ様の掲示板にてキューブマップ対応版を見つけました
http://hpcgi2.nifty.com/natupaji/bbs/patio.cgi?mode=view&no=3059素晴らしい事にサンプル付きなので、簡易版作って遊んでみました
キューブマップとは環境マップの一つで、6面(立方体)の部屋の中にオブジェクトを置いて、その反射をテクスチャとしてマッピングする感じです
うん、説明下手ですね
こんなカンジで周りの風景が鏡のように映り込みます

ペチコの稚拙なモデリング力だと伝わらないので指輪のメッシュをスカイリムからお借りしました
テスト版だとペチコの作ったDDSを読み込んでくれなかったので(最新版なら読み込めるのですが)先のサンプルのテクスチャをお借りしました

イメージとしては、こういう部屋の各面がオブジェクトに映り込むと考えていただければよいですね
キューブをスカイボックスとして、空にしたり山にしたりすると表現力がグッとアップするのです。多分
残念ながらわたしは
Paint.Netで作ったDDSを読み込めなかったので試す事ができません
DirectX SDKのDirectX Texture Toolならいいのかもですが、ペチコはSDK入れてないのです
通常は他にオブジェクトを置いて、それの反射もテクスチャにしてマッピングするのですが、そちらは既にサンプルにて実装されてますので、簡単なキューブのみのマップにしました
ペチコの頭も簡単なつくりなんです
CubeMap_Test.cpp#include "DxLib.h"
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { //ウインドウモード ChangeWindowMode( TRUE ) ; //アンチエイリアス SetFullSceneAntiAliasingMode( 4, 2 ) ; // DXライブラリの初期化 if( DxLib_Init() < 0 ) return -1;
// 画面モードの変更 SetGraphMode( 1024 , 768 , 32 ) ;
//カメラポジション VECTOR CameraPos ; // カメラの座標を初期化 CameraPos.x = 0.0f ; CameraPos.y = 0.0f ; CameraPos.z = -3.0f ; //モデル構造体 struct MODEL_Main { float x ; float y ; float z ; float RX; //Y軸回転 float RY; //Y軸回転 } ; MODEL_Main mdl ; // モデル情報の実体宣言 mdl.x = 0.0f ; mdl.y = 0.0f ; mdl.z = 0.0f ; mdl.RX = 0.0f ; mdl.RY = 0.0f ;
//マウス用 int MouseX , MouseY ; int MouseX_old , MouseY_old ;
// 頂点シェーダーを読み込む int Handle_1VS = LoadVertexShader( "CubeMapVS.vso" ) ; // ピクセルシェーダーを読み込む int Handle_1PS = LoadPixelShader( "CubeMapPS.pso" ) ;
//モデル読み込み int ModelHandle_1 = MV1LoadModel( "amulet.mv1" ) ;
//キューブマップ int CubeTex = LoadGraph( "TestCube.dds" ) ;
// ESCキーが押されるまでループ while( ProcessMessage() == 0 && CheckHitKey( KEY_INPUT_ESCAPE ) == 0 ) { // マウスの位置を取得 GetMousePoint( &MouseX , &MouseY ) ; //マウス if( ( GetMouseInput() & MOUSE_INPUT_LEFT ) != 0 ) { // 左 mdl.x -= (float)(MouseX_old - MouseX)*0.01f; mdl.y += (float)(MouseY_old - MouseY)*0.01f; }else if( ( GetMouseInput() & MOUSE_INPUT_RIGHT ) != 0 ) { // 右 mdl.RX += (float)(MouseY_old - MouseY)*0.5f; mdl.RY += (float)(MouseX_old - MouseX)*0.5f; } mdl.z -= GetMouseWheelRotVol() * 0.5f;
//マウス位置記憶 MouseX_old = MouseX; MouseY_old = MouseY;
// 描画先を裏画面にする SetDrawScreen( DX_SCREEN_BACK ) ;
// 画面を初期化 ClearDrawScreen() ;
//カメラ位置 SetCameraPositionAndTarget_UpVecY( CameraPos, VGet( 0.0f, 0.0f, 0.0f ) ) ; SetCameraNearFar( 0.1f, 1000.0f ) ; //モデル位置 MV1SetRotationXYZ( ModelHandle_1, VGet( mdl.RX * DX_PI_F / 180.0f, mdl.RY * DX_PI_F / 180.0f, 0.0f ) ) ; MV1SetPosition( ModelHandle_1, VGet( mdl.x, mdl.y, mdl.z ) ) ;
//シェーダ使用 MV1SetUseOrigShader( TRUE ) ;
// 使用するピクセルシェーダをセット SetUseVertexShader( Handle_1VS ) ; SetUsePixelShader( Handle_1PS ) ;
// カメラの位置を頂点シェーダの定数にセット SetVSConstF( 43, F4Get( CameraPos.x, CameraPos.y, CameraPos.z, 0.0f ) ) ;
//キューブ用テクスチャ SetUseTextureToShader( 2, CubeTex ) ;
// モデルを描画 MV1DrawModel( ModelHandle_1 ) ; // 設定した定数をリセット ResetVSConstF( 43, 1 ) ;
// 設定したテクスチャをリセット SetUseTextureToShader( 2, -1 ) ;
// 裏画面の内容を表画面に反映させる ScreenFlip() ; }
// 読み込んだモデルの削除 MV1DeleteModel( ModelHandle_1 ) ;
// 読み込んだピクセルシェーダーの削除 InitShader() ;
// DXライブラリの後始末 DxLib_End();
// ソフトの終了 return 0; } |
まだ先の掲示板にあるテスト版でしか動作しないので、自分用に全ソース。ファイル名とかは適宜読み替えてください
インデントずれが治る日はやって来ません
マウスでぐりぐりできるような処理を入れてので少し長くなってますが、実際に必要そうな所は
キューブマップはLoadGraphで読み込み
//キューブマップ int CubeTex = LoadGraph( "TestCube.dds" ) ;
|
キューブマップの作り方は、先の
ライブラリ様掲示板のリンク等をご参考ください
カメラの位置とキューブテクスチャを定数レジスタに入れる
// カメラの位置を頂点シェーダの定数にセット SetVSConstF( 43, F4Get( CameraPos.x, CameraPos.y, CameraPos.z, 0.0f ) ) ;
//キューブ用テクスチャ SetUseTextureToShader( 2, CubeTex ) ;
|
カメラの位置はVECTOR CameraPos;で予め宣言しときます
レジスタの43番を使っているのは、サンプル通りの9番を使ったらカメラのNearFarがおかしくなったから
なんでおかしくなるのかはわかりませんでした
キューブのテクスチャは0番ディフューズ、1番ノーマルマップという使い方を見据えて2番に入れてます
この辺を抑えておけば、サンプルのような他オブジェクトの映り込みにも対応できますね
シェーダ部分
頂点シェーダ
CubeMapVS.vso float3 viewVecW : TEXCOORD3 ; // ワールド } ;
// C++ 側で設定する定数の定義 float4x4 g_World : register( c94 ) ; // ローカル→ワールド float4x4 g_View : register( c6 ) ; // ワールド→ビュー float4x4 g_Proj : register( c2 ) ; // ビュー→射影 float3 cameraPosW : register( c43 ) ; //カメラ位置
// main関数 VS_OUTPUT main( VS_INPUT VSInput ) { VS_OUTPUT VSOutput;
//ローカル→ワールド→ビュー→射影変換 float4 worldPosition = mul(VSInput.Pos, g_World); float4 viewPosition = mul(worldPosition, g_View); VSOutput.Pos = mul(viewPosition, g_Proj);
//法線をビューへ float3 N = mul(VSInput.Normal,(float3x3)g_World); VSOutput.Norm = mul(N,(float3x3)g_View); //視線ベクトル VSOutput.viewVecW = worldPosition.xyz - cameraPosW ; VSOutput.normalW = N ; //テクスチャUV VSOutput.Tex = VSInput.Tex; return VSOutput; }
|
毎度ひねりのないランバートベースです
カメラの位置はfloat3型で受け取ってます
float3 cameraPosW : register( c43 ) ;
その値は
//視線ベクトル VSOutput.viewVecW = worldPosition.xyz - cameraPosW ; VSOutput.normalW = N ;
|
ワールド座標にある視線ベクトルとしてピクセルシェーダに渡します
Nは法線のワールド座標です
ピクセルシェーダ
CubeMapPS.pso// ピクセルシェーダーの入力 struct PS_INPUT { float2 Tex : TEXCOORD0 ; // テクスチャUV float3 Norm : TEXCOORD1 ; // 法線(ビュー) float3 normalW : TEXCOORD2 ; float3 viewVecW : TEXCOORD3 ; } ;
// ピクセルシェーダーの出力 struct PS_OUTPUT { float4 Color0 : COLOR0 ; } ;
// マテリアルパラメータ struct MATERIAL { float4 Diffuse ; // ディフューズカラー float4 Specular ; // スペキュラカラー float4 Power ; // スペキュラの強さ } ;
// ライトパラメータ struct LIGHT { float4 Position ; // 座標( ビュー空間 ) float3 Direction ; // 方向( ビュー空間 ) float4 Diffuse ; // ディフューズカラー float4 Specular ; // スペキュラカラー float4 Ambient ; // アンビエントカラーとマテリアルのアンビエントカラーを乗算したもの float4 Range_FallOff_AT0_AT1 ; // x:有効距離 y:スポットライト用FallOff z:距離による減衰処理用パラメータ0 w:距離による減衰処理用パラメータ1 float4 AT2_SpotP0_SpotP1 ; // x:距離による減衰処理用パラメータ2 y:スポットライト用パラメータ0( cos( Phi / 2.0f ) ) z:スポットライト用パラメータ1( 1.0f / ( cos( Theta / 2.0f ) - cos( Phi / 2.0f ) ) ) } ;
// C++ 側で設定するテクスチャや定数の定義 sampler DiffuseMapTexture : register( s0 ) ; // ディフューズマップテクスチャ samplerCUBE CubeMapTexture : register( s2 ) ; // キューブマップテクスチャ
float4 cfAmbient_Emissive : register( c1 ) ; // エミッシブカラー + マテリアルアンビエントカラー * グローバルアンビエントカラー MATERIAL cfMaterial : register( c2 ) ; // マテリアルパラメータ float4 cfFactorColor : register( c5 ) ; // 不透明度等 LIGHT cfLight : register( c32 ) ; // ライトパラメータ
// main関数 PS_OUTPUT main( PS_INPUT PSInput ) { PS_OUTPUT PSOutput; //法線とライト方向の正規化 float3 N = normalize( PSInput.Norm ); float3 L = normalize( cfLight.Direction ); //ライトの強さ float P = dot(N,-L); P = clamp( P,0,1 ); //色 float4 C = P * cfLight.Diffuse * cfMaterial.Diffuse + cfLight.Ambient + cfAmbient_Emissive; //テクスチャ float4 D = tex2D( DiffuseMapTexture, PSInput.Tex ); //反射 float3 vReflect = reflect( PSInput.viewVecW, PSInput.normalW ) ; float4 RefC = 0.55f * texCUBE( CubeMapTexture, vReflect ) + 0.75f ;
PSOutput.Color0.rgb = D * C.rgb * RefC; PSOutput.Color0.a = cfMaterial.Diffuse.a * D.a * cfFactorColor.a ; return PSOutput; }
|
ランバートに足したのはPS_INPUT部分とこの三行
//反射 float3 vReflect = reflect( PSInput.viewVecW, PSInput.normalW ) ; float4 RefC = 0.55f * texCUBE( CubeMapTexture, vReflect ) + 0.75f ; PSOutput.Color0.rgb = D * C.rgb * RefC;
|
hlslの関数refrectで反射ベクトルを得て、その座標にあるキューブマップを元のカラーに乗算してるだけです
現在の所は掲示板にあるテスト版でしか動作しませんが、本対応したらシェーダエフェクトの幅が広がりそうですね