- 2007/06/14 17:30
- 未分類
ちょっと時間が空きましたがリフレクションシェーダ。
この間のテクスチャシェーダに追加で実装しました。
いろいろと苦労があって、なんとか完成。。
以下ソースコード↓
————————————————————
// un-tweakables //
float4x4 wvp : WorldViewProjection;
float4x4 world : World;
float4x4 worldIt : WorldInverseTranspose;
float4x4 view : View;
float4x4 viewIt : ViewInverseTranspose;
float4x4 viewI : ViewInverse;
// tweakables //
float4 colorGain : Diffuse
<
string UIName = "Color Gain";
string UIWidget = "Color";
> = { 1.0f, 1.0f, 1.0f, 1.0f };
float4 colorOffset : Diffuse
<
string UIName = "Color Offset";
string UIWidget = "Color";
> = { 0.0f, 0.0f, 0.0f, 1.0f };
float reflectivity
<
string UIWidget = "slider";
float UIMin = 0.0;
float UIMax = 1.0;
float UIStep = 0.01;
> = 0.5;
texture colorMap : Diffuse
<
string ResourceName = "nvidia1.dds";
string ResourceType = "2D";
>;
sampler2D colorMapSampler = sampler_state
{
Texture =
MinFilter = LinearMipMapLinear;
MagFilter = Linear;
};
texture envMap : Environment
<
string ResourceName = "Default_reflection.dds";
string ResourceType = "Cube";
>;
samplerCUBE envMapSampler = sampler_state
{
Texture =
MinFilter = LinearMipMapLinear;
MagFilter = Linear;
};
// struct //
struct appdata
{
float4 position : POSITION;
float2 coord : TEXCOORD0;
float3 normal : NORMAL;
};
struct vertexOutput
{
float4 position : POSITION;
float2 coord : TEXCOORD0;
float3 worldNormal : TEXCOORD1;
float3 worldView : TEXCOORD2;
};
// vertex shader //
vertexOutput vertex( appdata IN )
{
vertexOutput OUT;
OUT.position = mul( wvp, IN.position );
OUT.coord = IN.coord;
float3 N = ( float3x3(world), IN.normal ); // transform only rotation matrix
OUT.worldNormal = normalize( N );
float4 worldPos = mul( world, IN.position ); // to world
OUT.worldView = worldPos – viewIt[3];
return OUT;
}
// fragment shader //
float4 fragment( vertexOutput IN ) : COLOR
{
float4 color = tex2D( colorMapSampler, IN.coord );
float3 R = reflect( IN.worldView, IN.worldNormal );
float4 reflec = texCUBE( envMapSampler, R );
color = color * colorGain + colorOffset;
return lerp( color, reflec, reflectivity ); // linear interpolation
}
technique env
{
pass
{
VertexProgram = compile arbvp1 vertex();
FragmentProgram = compile arbfp1 fragment();
DepthTestEnable = true;
DepthMask = true;
DepthFunc = LEqual;
}
}
————————————————————
別の仕事やってたりとか、時間かかった理由はいろいろあるんですけど
とりあえず以下の箇所ですんげー引っかかってしまいました。
float3 N = ( float3x3(world), IN.normal );
ここではfloat4x4のworldを3×3にキャストしているのですが、
これはノーマルの変換に際して、回転行列のみを使用している、という意味になります。
ノーマルの変換の際には位置を考慮してはならず、
もし一緒に変換してしまうと、オブジェクトを動かした際に妙な動作をしてしまうことになります。
float4 N = ( world, IN.normal );としていた時は、
位置行列も変換の対象に含まれてしまい、動作が妙でした。
float4x4を3×3にキャストした場合、使用されるのは左上の3×3の領域です。
他は無視されます。
それともう一つ、以下の箇所に関して。
lerp( color, reflec, reflectivity );
これはcolorの値とreflecの値をreflectivityによって割合を調整するためのものみたいです。
本のサンプルで使ってたのでそのまま拝借。
実際の見え方はもうちょっと違うんだと思うけど、とりあえずはこんな感じで。
本に載っていたサンプルもまた例によって微妙に違っていたため、
球以外はまともにリフレクションが行われず、、
で、Mayaに付属のサンプルシェーダを参考にしていたのですが、
今度は行列の意味がわからず、、汗
結局プログラマさんに丁寧な解説をしていただいて、理解へといたりました。
ホントに感謝です。。
座標系の変換とかになってくるとどうしても行列って必要だもんね、、
完全にスルーしてました。勉強しときます。
もっと数学勉強して、オフラインレンダリング向けのカスタムシェーダも書きたいよ。
が、しかし、オフラインレンダリングでシェーダが必要になったことってほとんどない、、
HypershadeなりRenderTreeなりが優秀すぎるからなぁ。
僕にそこまでの実力がないってのも問題の一部だとは思うんですけど:P
もちろん、CgはCgでもっと書けるようになりたいです。
FX Composer2.0もそろそろリリースされるだろうし、mental millも使ってみたいし。
openGLとかでうにゃもにゃしたいし。
うふふふふ。
- Newer: [ tech ] vueでHDRI
- Older: 3Dのオーサリング
Comments:0
Trackbacks:0
- Trackback URL for this entry
- http://blog.taikomatsu.com/2007/06/14/cg-reflection/trackback/
- Listed below are links to weblogs that reference
- [ Cg ] reflection from memlog