嘘視野角シェーダーのメモ

嘘視野角シェーダーを他シェーダーに組み込むのはそこまで難しくはないのですが、エフェクトによって記述の仕方に微差があるのでその辺は臨機応変に対応できないとやっぱり難しいのかも。

 

まずコントローラー定義。

これはScale.fxのコントローラー用の計算が主です。

モデルにボーンを埋め込めるようにしてるので長くなってる。

 

//嘘視野角用のコントローラー定義

float3 OriginCtr : CONTROLOBJECT < string name = "ScaleControl.pmx"; string item = "スケール原点"; >;
float3 ScaleXYZCtr : CONTROLOBJECT < string name = "ScaleControl.pmx"; string item = "スケール変更"; >;
float ExpansionCtr : CONTROLOBJECT < string name = "ScaleControl.pmx"; string item = "拡大"; >;
float ReductionCtr : CONTROLOBJECT < string name = "ScaleControl.pmx"; string item = "縮小"; >;
float LperthM1Ctr  : CONTROLOBJECT < string name = "ScaleControl.pmx"; string item = "視野角大"; >;
float LperthM2Ctr  : CONTROLOBJECT < string name = "ScaleControl.pmx"; string item = "視野角小"; >;
float3 LperthBCtr : CONTROLOBJECT < string name = "ScaleControl.pmx"; string item = "嘘視野角"; >;

float3 OriginModel : CONTROLOBJECT < string name = "(self)"; string item = "スケール原点"; >;
float3 ScaleXYZModel : CONTROLOBJECT < string name = "(self)"; string item = "スケール変更"; >;
float ExpansionModel : CONTROLOBJECT < string name = "(self)"; string item = "拡大"; >;
float ReductionModel : CONTROLOBJECT < string name = "(self)"; string item = "縮小"; >;
float LperthM1Model  : CONTROLOBJECT < string name = "(self)"; string item = "視野角大"; >;
float LperthM2Model  : CONTROLOBJECT < string name = "(self)"; string item = "視野角小"; >;
float3 LperthBModel : CONTROLOBJECT < string name = "(self)"; string item = "嘘視野角"; >;

static float3 Origin = OriginCtr + OriginModel;
static float3 ScaleXYZ = ScaleXYZCtr + ScaleXYZModel;
static float Expansion = ExpansionCtr + ExpansionModel;
static float Reduction = ReductionCtr + ReductionModel;
static float LperthM1  = LperthM1Ctr + LperthM1Model;
static float LperthM2  = LperthM2Ctr + LperthM2Model;
static float3 LperthB  = LperthBCtr + LperthBModel;

static float Lperth = (LperthM2 * 40 + LperthB.x) - LperthM1 *10;


static float3 Scale = float3( clamp( pow(10.0f, 0.1f*ScaleXYZ.x), 0.01f, 100.0f ),
                              clamp( pow(10.0f, 0.1f*ScaleXYZ.y), 0.01f, 100.0f ),
                              clamp( pow(10.0f, -0.1f*ScaleXYZ.z), 0.01f, 100.0f ) );

 

次に座標変換行列の計算

既存のシェーダーの座標変換のパラメーターと重複しないようにする必要があります。

嘘視野角計算には視野角の計算にPROJECTIONの取得が必須。(シェーダーによってはないので追加する)

変更した視野角はWorldViewProjMatrixとLightWorldViewProjMatrixに割り込ませます。なので既存のシェーダーのWorldViewProjMatrixとLightWorldViewProjMatrixの取得はオフにしておく必要があります。

 

// 座標変換行列

float4x4 proj      : PROJECTION;

float4x4 wvpm      : WORLDVIEWPROJECTION;
float4x4 LWVPM : WORLDVIEWPROJECTION < string Object = "Light"; >;

 

float3 LightDirection : DIRECTION < string Object = "Light"; >;
float3   CameraPosition    : POSITION  < string Object = "Camera"; >;

static float perthx = clamp(proj._22+Lperth, 0.04, 114.5)/proj._22;


static float ScaleAll = 1/perthx * (1+Expansion) * (1.0f - 0.9f*Reduction);


static float4x4 ViewProjMatrix = {wvpm._11*perthx, wvpm._12*perthx, wvpm._13, wvpm._14,
                                    wvpm._21*perthx, wvpm._22*perthx ,wvpm._23, wvpm._24,
                                    wvpm._31*perthx, wvpm._32*perthx, wvpm._33, wvpm._34,
                                    wvpm._41, wvpm._42, wvpm._43, wvpm._44};


static float4x4 LightWorldViewProjMatrix = {LWVPM._11*perthx, LWVPM._12*perthx, LWVPM._13, LWVPM._14,
                                         LWVPM._21*perthx, LWVPM._22*perthx ,LWVPM._23, LWVPM._24,
                                         LWVPM._31*perthx, LWVPM._32*perthx, LWVPM._33, LWVPM._34,
                                         LWVPM._41, LWVPM._42, LWVPM._43, LWVPM._44};

 

Scale.fxの頂点変形の計算式部分。

置く場所は頂点シェーダーの直前あたりがいいようです。一応理屈としては座標変換計算の後に置けばいいはずですが。

 

// 座標変換関数
float4 TransPos(float4 Pos : POSITION) : POSITION
{
   Pos.x -= Origin.x;
   Pos.y -= Origin.y;
   Pos.z -= Origin.z;

   Pos.x *= ScaleAll * Scale.x;
   Pos.y *= ScaleAll * Scale.y;
   Pos.z *= ScaleAll * Scale.z;

   Pos.x += Origin.x;
   Pos.y += Origin.y;
   Pos.z += Origin.z;

   return Pos;

}

 

最後に頂点シェーダー内のScale.fxによる変形部分。// カメラ視点のワールドビュー射影変換の直前におくのが基本です。注意する必要があるのは頂点シェーダー側に「float4 Pos : POSITION」のような頂点の取得がない場合は追加してやる必要があります。あとシェーダーによってはPosが小文字でposだったりするので、その場合はどちらかに合わせて修正します。

 

    // スケール座標変換
    Pos = TransPos(Pos);
 

ちなみに頂点シェーダーは3つ~4つくらいある場合が大半なので(地面影用、エッジ用、セルフ影作成用、セルフ影OFF描画用、セルフ影あり描画用)、その場合は全部に追加を行います。