俺用の記事。
注意:みてもすごいわかりにくいよ!本当に知りたいときはコメントでも残してください。
後色々まちがってるよ!参考にしないほうがいいよ!
仕事場にソース持ち込めないからここに貼り付ける。
今は暇だからUniytのシェーダいじくりまわしている。
んでサーフェスシェーダ使わないで、頂点とフラグメントでライティングやらしている。
てかバンプ用意されてるからやる必要ないんだけどねw
でもシェーダの勉強だから頂点とフラグメントで計算する事にしている。
んでバンプマップでつまづいている。
シェーダソースは悪くないとおもう。
とか思ってたらCPU側でやる処理があったのね・・・。
学生の頃に普通にやってたから詰む意味がわからんとかおもってたらそうゆうことだった。
ソースはDirextXのHLSLです。
ソース張る。
D3DXMATRIX mtxRot; // 回転マトリクス
D3DXMATRIX mtxTlans; // 平行移動マトリクス
D3DXMatrixIdentity(&m_WorldMat); // ワールドマトリクスの初期化
D3DXMatrixScaling(&m_WorldMat,m_Scale.x, m_Scale.y, m_Scale.z); // 拡大、縮小
D3DXMatrixRotationYawPitchRoll(&mtxRot, m_Rot.y, m_Rot.x, m_Rot.z); // 回転処理
D3DXMatrixTranslation(&mtxTlans,m_Pos.x,m_Pos.y,m_Pos.z); // 平行移動
// マトリクスの計算
m_WorldMat = m_WorldMat * mtxRot * mtxTlans;
// モデルの逆用列用
D3DXMATRIX modelmatInv;
// モデルの逆行列を生成
D3DXMatrixInverse(&modelmatInv,NULL,&m_WorldMat);
// テクスチャのポインタ取得
CTexture *pTex = CManager::GetTexture();
CCamera *pCamera = CManager::GetCamera();
D3DXMATRIX mtxview = pCamera->GetMatView();
D3DXMATRIX mtxprj = pCamera->GetMatPrj();
// ビューとプロジェクションをかける
m_WorldMat = m_WorldMat * mtxview * mtxprj;
// 逆行列変換用ライトベクトル
D3DXVECTOR3 InvLightDirection;
// ライトベクトルを出す
// LightVec = LightVec - m_Pos;
// D3DXVec3Normalize(&LightVec, &LightVec);// ノーマライズ
// ライトベクトルとモデルの逆行列をかけたやつをつくる。
D3DXVec3TransformNormal(&InvLightDirection, &LightVec, &modelmatInv);
// カメラの座標を取得
D3DXVECTOR3 CP = CManager::GetCamera()->GetPos();
D3DXVECTOR4 InvCameraPos;
// カメラ座標と逆行列を掛け合わせたやーつを作る
D3DXVec3Transform(&InvCameraPos, &CP, &modelmatInv);
// 頂点シェーダーに送るライトベクトルを送る
m_pCT->SetFloatArray(pD3Ddev, "InvLightDirection", (float*)&InvLightDirection, 4);
// 頂点シェーダーに送るライトベクトルを送る
m_pCT->SetFloatArray(pD3Ddev, "InvCameraPos", (float*)&InvCameraPos, 4);
// WVPを送信
m_pCT->SetMatrix(pD3Ddev, "WorldViewProjection", &m_WorldMat);
CPU側でシェーダに送るデータで一番重要なのは、
ライトベクトルとカメラベクトルをモデルのワールドマトリクスの逆行列と計算する事
// モデルの逆行列を生成
D3DXMatrixInverse(&modelmatInv,NULL,&m_WorldMat);
// 逆行列変換用ライトベクトル
D3DXVECTOR3 InvLightDirection;
// ライトベクトルとモデルの逆行列をかけたやつをつくる。
D3DXVec3TransformNormal(&InvLightDirection, &LightVec, &modelmatInv);
// カメラの座標を取得
D3DXVECTOR3 CP = CManager::GetCamera()->GetPos();
D3DXVECTOR4 InvCameraPos;
// カメラ座標と逆行列を掛け合わせたやーつを作る
D3DXVec3Transform(&InvCameraPos, &CP, &modelmatInv);
あとは上記のやつを送るらしい。
俺はこれをすっかりわすれてたし、シェーダの記事みててもCPU側の事を一切きにしてなかった
次シェーダソース
頂点シェーダ
void VS(
in float4 inPosition : POSITION,
in float2 inTexcoord : TEXCOORD0,
in float3 inNormal : NORMAL0,
in float3 inTangent : TANGENT,
in float3 inBinormal : BINORMAL,
out float4 outPosition : POSITION,
out float2 outTexcoord : TEXCOORD0,
out float3 outLight : TEXCOORD1,
out float3 outEye : TEXCOORD2)
{
outPosition = mul( inPosition, WorldViewProjection );
outTexcoord = inTexcoord;
// こうやって計算すると行列変換ようのマトリクスを入れrう、
float4x4 mat = { float4( -inBinormal, 0.0f ),
float4( -inTangent, 0.0f ),
float4( inNormal, 0.0f ),
float4( 0.0f, 0.0f, 0.0f, 1.0f ) };
float4x4 invmat = transpose( mat );
// モデルの座標系とテクスチャの座標系を2回変換しないといけない
outLight = mul( InvLightDirection, invmat);
outLight = normalize(outLight);
// Eyeベクトルを出す
float4 eye = inPosition - InvCameraPos;
// ノーマライズ
eye = normalize(eye);
outEye = mul(eye, invmat);
}
ピクセルシェーダ
void PS2(in float2 inTexcoord : TEXCOORD0,in float3 inLight :TEXCOORD1,in float3 inEye:TEXCOORD2,
out float4 outDiffuse : COLOR )
{
// 高さ
//float height;// = (tex2D(TexHeight,inTexcoord).x - 0.0f) * 0.1f;
float depth = -inEye.z * 0.1f;
// アイベクトルやら高さやつかったテクスチャ座標を出す。
float2 TexCoord = inTexcoord.xy + inEye.xy * 0.1f;
//↓法線ベクトルを調整させるため
float3 N = tex2D( TexBump, TexCoord).xyz * 2.0f - 1.0f;
outDiffuse = -dot( N, inLight );
outDiffuse.a = 1.0f;
// 基本画像を合成
outDiffuse = outDiffuse * tex2D( TexSampler, TexCoord );
}
正直ピクセルシェーダはうごくかは謎。
どうやらこのシェーダは視差マッピングやったあとにバンプをやろうとして
視差マッピングのシェーダを改造させたものらしい。なんでやったかは忘れた。
あとはコレを仕事場でみてなんとかしな。
Unityで頂点とピクセルシェーダでこんな事している奴はたぶん少ない。
ゆえに記事がなくて困る。
そして記事よく記事に惑わされる。
特に一番困ったのが、ライトベクトルとカメラベクトルの取得方法。
Unityには定義済みのマクロが用意されている。
その中になんだったかわすれたけど、ライトベクトルを出すヘルパ関数と
カメラベクトルを出すヘルパ関数があるんだけど、そいつらは使わないほうがいいと思います。
もうシェーダのプロパティにスクリプト側からシェーダに座標関連を送ればいいと思う。
あとマルチレンダもまじで意味分からん。
Unityでマルチレンダに関する記事もかなり少ない。
英語ならなるかもしれないけど英語とか読む気にならないわ。
こうゆうところが日本人のプログラム技術が発展しにくい所だと思う。
あとマルチレンダ関連はUnityProじゃないとできない。
マーベリックプロジェクトっていうサイトでエッジフィルターのシェーダやってたら
Unityでマルチレンダってどうやるんだ?ってなったは。
まずメインとは別にカメラを作る。
そこにレンダテクスチャをあてる。
これで現在表示されている画面のテクスチャが生成できる。
そしてこのカメラはメインのカメラと座標が同じになるようにスクリプトでもくむ。
んでここからがやっかい。
フィルターだから2Dシェーダをつくらないといけないわけなんだけど・・・。
2Dにマテリアルどうやってあてるねんwww
そもそもマテリアルを入れる場所がない。
だからスプライトとかいうのにマテリアルがいれられるからそこにシェーダを適用した
マテリアルを無理やりつっこんだ。
このやり方が2Dシェーダを使うときにあっているかどうかはわからん。
でもできた。
んで深度テクスチャなんだけど、
シェーダー側に用意されてるっていうね・・・。
これもさっきつくったカメラにカメラモード=デプステクチャとかいうソースを書いて
んで2Dシェーダ側で
sampler2D DepthTexture;
とかいう変数宣言すると、普通にとってこれるっていう謎。
定義済みマクロらしい。(さっきヘルパ関数使わないって言った奴だれだ)
これで深度テクスチャはとれた。
んで2枚のテクスチャをあとは合成してエッジやらなんやら検出すればいけるっていう話。
まじでUnityでシェーダをばりばり書いている人いねぇかな・・・・。
記事すくなすぎて辛すぎ。
俺の記事参考にならないから見ないほうが良いよ。
UnityだからCg言語でやってるんだけど、ほぼシェーダの記述方式は変わらないから
そこは困ってない。ただ、CPU側でやる処理がDirectXとOpenGLと流れとか
全然把握できない。Unity謎多すぎ。