【立体視】むっちむちなアリスで裏表ラバーズ【たこ入り】
MikuMikuEffect 使用による立体視のテストです。
Furia さんの『立体視せっと』
を改造して、視差をコントロールするタイプのものにしてみました。
基本的には、MikuMikuDance が標準で持つ NVIDIA 3D Vision/Discover のもの
と同様の方式*1で、画面上で注目すべき部分を(左右に分けた)画面上で同じ位置に来るように出来ます。
その注目ポイント(収束点)が、MMD 標準のものは(MMD 上だと赤丸で示される)「カメラ位置」に固定されているのに対して、こちらのものは『立体視せっと』で読み込む 3DViewBufferRender_交差法.x
*2 を利用して Z軸(奥行方向)の距離を取得しています。*3
なので、カメラ位置以外の場所に収束点を置くことが可能になっています。*4
使い方
2. 3DViewModelRender_LeftEye.fx
を以下の内容に書き換える
//////////////////////////////////////////////////////////////////////////////////////////////// // // full.fx ver1.2+ // 作成: 舞力介入P // Modified: Furia // エッジカラー対応 // 異方向性フィルタ使用テクスチャ追加 // Modified: kadotanimitsuru // //////////////////////////////////////////////////////////////////////////////////////////////// //左右カメラの視点位置からみた補正角度 マイナスで平行/交差法入れ替わる #define SlideValue 0.5f // 3DViewModelRender_LeftEye.fx はこちら //#define SlideValue -0.5f // 3DViewModelRender_RightEye.fx はこちら //視点位置の距離に対する補正値 #define Zdiff -1.0f // 顔の前面あたりに来るように、頭の中心からの距離を入れる // パラメータ宣言 // オブジェクト座標 float4 ControlObject : CONTROLOBJECT < string name = "3DViewBufferRender_交差法.x"; >; float4 ControlObjectSize : CONTROLOBJECT < string name = "3DViewBufferRender_交差法.x"; string item = "Si"; >; // 座法変換行列 float4x4 WorldViewProjMatrix : WORLDVIEWPROJECTION; float4x4 WorldMatrix : WORLD; float4x4 ViewMatrix : VIEW; float4x4 WorldViewMatrix : WORLDVIEW; float4x4 ProjMatrix : PROJECTION; float4x4 LightWorldViewProjMatrix : WORLDVIEWPROJECTION < string Object = "Light"; >; float3 LightDirection : DIRECTION < string Object = "Light"; >; float3 CameraPosition : POSITION < string Object = "Camera"; >; // マテリアル色 float4 MaterialDiffuse : DIFFUSE < string Object = "Geometry"; >; float3 MaterialAmbient : AMBIENT < string Object = "Geometry"; >; float3 MaterialEmmisive : EMISSIVE < string Object = "Geometry"; >; float3 MaterialSpecular : SPECULAR < string Object = "Geometry"; >; float SpecularPower : SPECULARPOWER < string Object = "Geometry"; >; float3 MaterialToon : TOONCOLOR; // ライト色 float3 LightDiffuse : DIFFUSE < string Object = "Light"; >; float3 LightAmbient : AMBIENT < string Object = "Light"; >; float3 LightSpecular : SPECULAR < string Object = "Light"; >; static float4 DiffuseColor = MaterialDiffuse * float4(LightDiffuse, 1.0f); static float3 AmbientColor = saturate(MaterialAmbient * LightAmbient + MaterialEmmisive); static float3 SpecularColor = MaterialSpecular * LightSpecular; //輪郭色 float4 EdgeColor : EDGECOLOR; bool parthf; // パースペクティブフラグ bool transp; // 半透明フラグ bool spadd; // スフィアマップ加算合成フラグ #define SKII1 1500 #define SKII2 8000 #define Toon 3 // オブジェクトのテクスチャ texture ObjectTexture: MATERIALTEXTURE; sampler ObjTexSampler = sampler_state { texture = <ObjectTexture>; MINFILTER = ANISOTROPIC; MAGFILTER = ANISOTROPIC; MIPFILTER = LINEAR; AddressU = WRAP; AddressV = WRAP; MAXANISOTROPY = 16; }; // スフィアマップのテクスチャ texture ObjectSphereMap: MATERIALSPHEREMAP; sampler ObjSphareSampler = sampler_state { texture = <ObjectSphereMap>; MINFILTER = LINEAR; MAGFILTER = LINEAR; }; // MMD本来のsamplerを上書きしないための記述です。削除不可。 sampler MMDSamp0 : register(s0); sampler MMDSamp1 : register(s1); sampler MMDSamp2 : register(s2); //////////////////////////////////////////////////////////////////////////////////////////////// // 作業用 float4 PosMove(float4 Pos, float slideX) : POSITION { slideX *= ControlObjectSize / 10; float d = mul(ControlObject, ViewMatrix).z + Zdiff; float r = radians(slideX); Pos = mul(Pos, WorldViewMatrix); Pos.z -= d; float x = Pos.x; Pos.x = Pos.x * cos(r) + Pos.z * sin(r); Pos.z = Pos.z * cos(r) - x * sin(r); Pos.z += d; return Pos; } // 輪郭描画 // 頂点シェーダ float4 ColorRender_VS(float4 Pos : POSITION, uniform float slideX) : POSITION { // カメラ視点のワールドビュー射影変換 Pos = PosMove(Pos, slideX); return mul( Pos, ProjMatrix); // mul( Pos, WorldViewProjMatrix ); } // ピクセルシェーダ float4 ColorRender_PS() : COLOR { // 黒で塗りつぶし return EdgeColor;//float4(0,0,0,1); } // 輪郭描画用テクニック technique EdgeTec < string MMDPass = "edge"; > { pass DrawEdge { AlphaBlendEnable = FALSE; AlphaTestEnable = FALSE; MultiSampleAntialias = TRUE; VertexShader = compile vs_2_0 ColorRender_VS(SlideValue); PixelShader = compile ps_2_0 ColorRender_PS(); } } /////////////////////////////////////////////////////////////////////////////////////////////// // 影(非セルフシャドウ)描画 // 頂点シェーダ float4 Shadow_VS(float4 Pos : POSITION, uniform float slideX) : POSITION { // カメラ視点のワールドビュー射影変換 Pos = PosMove(Pos, slideX); return mul( Pos, ProjMatrix); // mul( Pos, WorldViewProjMatrix ); } // ピクセルシェーダ float4 Shadow_PS() : COLOR { // アンビエント色で塗りつぶし return float4(AmbientColor.rgb, 0.65f); } // 影描画用テクニック technique ShadowTec < string MMDPass = "shadow"; > { pass DrawShadow { VertexShader = compile vs_2_0 Shadow_VS(SlideValue); PixelShader = compile ps_2_0 Shadow_PS(); } } /////////////////////////////////////////////////////////////////////////////////////////////// // オブジェクト描画(セルフシャドウOFF) struct VS_OUTPUT { float4 Pos : POSITION; // 射影変換座標 float2 Tex : TEXCOORD1; // テクスチャ float3 Normal : TEXCOORD2; // 法線 float3 Eye : TEXCOORD3; // カメラとの相対位置 float2 SpTex : TEXCOORD4; // スフィアマップテクスチャ座標 float4 Color : COLOR0; // ディフューズ色 }; // 頂点シェーダ VS_OUTPUT Basic_VS(float4 Pos : POSITION, float3 Normal : NORMAL, float2 Tex : TEXCOORD0, uniform bool useTexture, uniform bool useSphereMap, uniform bool useToon, uniform float slideX) { VS_OUTPUT Out = (VS_OUTPUT)0; // カメラとの相対位置 Out.Eye = CameraPosition - mul( Pos, WorldMatrix ); // カメラ視点のワールドビュー射影変換 Pos = PosMove(Pos, slideX); Out.Pos = mul( Pos, ProjMatrix); // mul( Pos, WorldViewProjMatrix ); // 頂点法線 Out.Normal = normalize( mul( Normal, (float3x3)WorldMatrix ) ); // ディフューズ色+アンビエント色 計算 Out.Color.rgb = AmbientColor; if ( !useToon ) { Out.Color.rgb += max(0,dot( Out.Normal, -LightDirection )) * DiffuseColor.rgb; } Out.Color.a = DiffuseColor.a; Out.Color = saturate( Out.Color ); // テクスチャ座標 Out.Tex = Tex; if ( useSphereMap ) { // スフィアマップテクスチャ座標 float2 NormalWV = mul( Out.Normal, (float3x3)ViewMatrix ); Out.SpTex.x = NormalWV.x * 0.5f + 0.5f; Out.SpTex.y = NormalWV.y * -0.5f + 0.5f; } return Out; } // ピクセルシェーダ float4 Basic_PS(VS_OUTPUT IN, uniform bool useTexture, uniform bool useSphereMap, uniform bool useToon , uniform sampler DiffuseSamp ) : COLOR0 { // ディフューズ色+アンビエント色 計算 IN.Color.rgb = AmbientColor; if ( !useToon ) { IN.Color.rgb += max(0,dot( IN.Normal, -LightDirection )) * DiffuseColor.rgb; } IN.Color.a = DiffuseColor.a; IN.Color = saturate( IN.Color ); // スペキュラ色計算 float3 HalfVector = normalize( normalize(IN.Eye) + -LightDirection ); float3 Specular = pow( max(0,dot( HalfVector, normalize(IN.Normal) )), SpecularPower ) * SpecularColor; float4 Color = IN.Color; if ( useTexture ) { // テクスチャ適用 Color *= tex2D( DiffuseSamp, IN.Tex ); } if ( useSphereMap ) { // スフィアマップ適用 if(spadd) Color += tex2D(ObjSphareSampler,IN.SpTex); else Color *= tex2D(ObjSphareSampler,IN.SpTex); } if ( useToon ) { // トゥーン適用 float LightNormal = dot( IN.Normal, -LightDirection ); Color.rgb *= lerp(MaterialToon, float3(1,1,1), saturate(LightNormal * 16 + 0.5)); } // スペキュラ適用 Color.rgb += Specular; return Color; } //----------------------------------------------------------------------------------------------------- // 標準エミュレート // オブジェクト描画用テクニック(アクセサリ用) // 不要なものは削除可 technique MainTec0 < string MMDPass = "object"; bool UseTexture = false; bool UseSphereMap = false; bool UseToon = false; > { pass DrawObject { MultiSampleAntialias = TRUE; VertexShader = compile vs_2_0 Basic_VS(false, false, false,SlideValue); PixelShader = compile ps_2_0 Basic_PS(false, false, false, ObjTexSampler); } } technique MainTec1 < string MMDPass = "object"; bool UseTexture = true; bool UseSphereMap = false; bool UseToon = false; > { pass DrawObject { MultiSampleAntialias = TRUE; VertexShader = compile vs_2_0 Basic_VS(true, false, false,SlideValue); PixelShader = compile ps_2_0 Basic_PS(true, false, false, ObjTexSampler); } } technique MainTec2 < string MMDPass = "object"; bool UseTexture = false; bool UseSphereMap = true; bool UseToon = false; > { pass DrawObject { MultiSampleAntialias = TRUE; VertexShader = compile vs_2_0 Basic_VS(false, true, false,SlideValue); PixelShader = compile ps_2_0 Basic_PS(false, true, false, ObjTexSampler); } } technique MainTec3 < string MMDPass = "object"; bool UseTexture = true; bool UseSphereMap = true; bool UseToon = false; > { pass DrawObject { MultiSampleAntialias = TRUE; VertexShader = compile vs_2_0 Basic_VS(true, true, false,SlideValue); PixelShader = compile ps_2_0 Basic_PS(true, true, false, ObjTexSampler); } } // オブジェクト描画用テクニック(PMDモデル用) technique MainTec4 < string MMDPass = "object"; bool UseTexture = false; bool UseSphereMap = false; bool UseToon = true; > { pass DrawObject { MultiSampleAntialias = TRUE; VertexShader = compile vs_2_0 Basic_VS(false, false, true,SlideValue); PixelShader = compile ps_2_0 Basic_PS(false, false, true, ObjTexSampler); } } technique MainTec5 < string MMDPass = "object"; bool UseTexture = true; bool UseSphereMap = false; bool UseToon = true; > { pass DrawObject { MultiSampleAntialias = TRUE; VertexShader = compile vs_2_0 Basic_VS(true, false, true,SlideValue); PixelShader = compile ps_2_0 Basic_PS(true, false, true, ObjTexSampler); } } technique MainTec6 < string MMDPass = "object"; bool UseTexture = false; bool UseSphereMap = true; bool UseToon = true; > { pass DrawObject { MultiSampleAntialias = TRUE; VertexShader = compile vs_2_0 Basic_VS(false, true, true,SlideValue); PixelShader = compile ps_2_0 Basic_PS(false, true, true, ObjTexSampler); } } technique MainTec7 < string MMDPass = "object"; bool UseTexture = true; bool UseSphereMap = true; bool UseToon = true; > { pass DrawObject { MultiSampleAntialias = TRUE; VertexShader = compile vs_2_0 Basic_VS(true, true, true,SlideValue); PixelShader = compile ps_2_0 Basic_PS(true, true, true, ObjTexSampler); } } /////////////////////////////////////////////////////////////////////////////////////////////// // セルフシャドウ用Z値プロット struct VS_ZValuePlot_OUTPUT { float4 Pos : POSITION; // 射影変換座標 float4 ShadowMapTex : TEXCOORD0; // Zバッファテクスチャ }; // 頂点シェーダ VS_ZValuePlot_OUTPUT ZValuePlot_VS( float4 Pos : POSITION ) { VS_ZValuePlot_OUTPUT Out = (VS_ZValuePlot_OUTPUT)0; // ライトの目線によるワールドビュー射影変換をする Out.Pos = mul( Pos, LightWorldViewProjMatrix ); // テクスチャ座標を頂点に合わせる Out.ShadowMapTex = Out.Pos; return Out; } // ピクセルシェーダ float4 ZValuePlot_PS( float4 ShadowMapTex : TEXCOORD0 ) : COLOR { // R色成分にZ値を記録する return float4(ShadowMapTex.z/ShadowMapTex.w,0,0,1); } // Z値プロット用テクニック technique ZplotTec < string MMDPass = "zplot"; > { pass ZValuePlot { AlphaBlendEnable = FALSE; VertexShader = compile vs_2_0 ZValuePlot_VS(); PixelShader = compile ps_2_0 ZValuePlot_PS(); } } /////////////////////////////////////////////////////////////////////////////////////////////// // オブジェクト描画(セルフシャドウON) // シャドウバッファのサンプラ。"register(s0)"なのはMMDがs0を使っているから sampler DefSampler : register(s0); struct BufferShadow_OUTPUT { float4 Pos : POSITION; // 射影変換座標 float4 ZCalcTex : TEXCOORD0; // Z値 float2 Tex : TEXCOORD1; // テクスチャ float3 Normal : TEXCOORD2; // 法線 float3 Eye : TEXCOORD3; // カメラとの相対位置 float2 SpTex : TEXCOORD4; // スフィアマップテクスチャ座標 float4 Color : COLOR0; // ディフューズ色 }; // 頂点シェーダ BufferShadow_OUTPUT BufferShadow_VS(float4 Pos : POSITION, float4 Normal : NORMAL, float2 Tex : TEXCOORD0, uniform bool useTexture, uniform bool useSphereMap, uniform bool useToon, uniform float slideX) { BufferShadow_OUTPUT Out = (BufferShadow_OUTPUT)0; float4 Pos0 = Pos; // カメラとの相対位置 Out.Eye = CameraPosition - mul( Pos, WorldMatrix ); // カメラ視点のワールドビュー射影変換 Pos = PosMove(Pos, slideX); Out.Pos = mul( Pos, ProjMatrix); // mul( Pos, WorldViewProjMatrix ); // 頂点法線 Out.Normal = normalize( mul( Normal, (float3x3)WorldMatrix ) ); // ライト視点によるワールドビュー射影変換 Out.ZCalcTex = mul( Pos0, LightWorldViewProjMatrix ); // ディフューズ色+アンビエント色 計算 Out.Color.rgb = AmbientColor; if ( !useToon ) { Out.Color.rgb += max(0,dot( Out.Normal, -LightDirection )) * DiffuseColor.rgb; } Out.Color.a = DiffuseColor.a; Out.Color = saturate( Out.Color ); // テクスチャ座標 Out.Tex = Tex; if ( useSphereMap ) { // スフィアマップテクスチャ座標 float2 NormalWV = mul( Out.Normal, (float3x3)ViewMatrix ); Out.SpTex.x = NormalWV.x * 0.5f + 0.5f; Out.SpTex.y = NormalWV.y * -0.5f + 0.5f; } return Out; } // ピクセルシェーダ float4 BufferShadow_PS(BufferShadow_OUTPUT IN, uniform bool useTexture, uniform bool useSphereMap, uniform bool useToon , uniform sampler DiffuseSamp ) : COLOR { // ディフューズ色+アンビエント色 計算 IN.Color.rgb = AmbientColor; if ( !useToon ) { IN.Color.rgb += max(0,dot( IN.Normal, -LightDirection )) * DiffuseColor.rgb; } IN.Color.a = DiffuseColor.a; IN.Color = saturate( IN.Color ); // スペキュラ色計算 float3 HalfVector = normalize( normalize(IN.Eye) + -LightDirection ); float3 Specular = pow( max(0,dot( HalfVector, normalize(IN.Normal) )), SpecularPower ) * SpecularColor; float4 Color = IN.Color; float4 ShadowColor = float4(AmbientColor, Color.a); // 影の色 if ( useTexture ) { // テクスチャ適用 float4 TexColor = tex2D( DiffuseSamp, IN.Tex ); Color *= TexColor; ShadowColor *= TexColor; } if ( useSphereMap ) { // スフィアマップ適用 float4 TexColor = tex2D(ObjSphareSampler,IN.SpTex); if(spadd) { Color += TexColor; ShadowColor += TexColor; } else { Color *= TexColor; ShadowColor *= TexColor; } } // スペキュラ適用 Color.rgb += Specular; // テクスチャ座標に変換 IN.ZCalcTex /= IN.ZCalcTex.w; float2 TransTexCoord; TransTexCoord.x = (1.0f + IN.ZCalcTex.x)*0.5f; TransTexCoord.y = (1.0f - IN.ZCalcTex.y)*0.5f; if( any( saturate(TransTexCoord) != TransTexCoord ) ) { // シャドウバッファ外 return Color; } else { float comp; if(parthf) { // セルフシャドウ mode2 comp=1-saturate(max(IN.ZCalcTex.z-tex2D(DefSampler,TransTexCoord).r , 0.0f)*SKII2*TransTexCoord.y-0.3f); } else { // セルフシャドウ mode1 comp=1-saturate(max(IN.ZCalcTex.z-tex2D(DefSampler,TransTexCoord).r , 0.0f)*SKII1-0.3f); } if ( useToon ) { // トゥーン適用 comp = min(saturate(dot(IN.Normal,-LightDirection)*Toon),comp); ShadowColor.rgb *= MaterialToon; } float4 ans = lerp(ShadowColor, Color, comp); if( transp ) ans.a = 0.5f; return ans; } } //----------------------------------------------------------------------------------------------------- // 標準エミュレート // オブジェクト描画用テクニック(アクセサリ用) technique MainTecBS0 < string MMDPass = "object_ss"; bool UseTexture = false; bool UseSphereMap = false; bool UseToon = false; > { pass DrawObject { MultiSampleAntialias = TRUE; VertexShader = compile vs_2_0 BufferShadow_VS(false, false, false,SlideValue); PixelShader = compile ps_2_0 BufferShadow_PS(false, false, false, ObjTexSampler); } } technique MainTecBS1 < string MMDPass = "object_ss"; bool UseTexture = true; bool UseSphereMap = false; bool UseToon = false; > { pass DrawObject { MultiSampleAntialias = TRUE; VertexShader = compile vs_2_0 BufferShadow_VS(true, false, false,SlideValue); PixelShader = compile ps_2_0 BufferShadow_PS(true, false, false, ObjTexSampler); } } technique MainTecBS2 < string MMDPass = "object_ss"; bool UseTexture = false; bool UseSphereMap = true; bool UseToon = false; > { pass DrawObject { MultiSampleAntialias = TRUE; VertexShader = compile vs_2_0 BufferShadow_VS(false, true, false,SlideValue); PixelShader = compile ps_2_0 BufferShadow_PS(false, true, false, ObjTexSampler); } } technique MainTecBS3 < string MMDPass = "object_ss"; bool UseTexture = true; bool UseSphereMap = true; bool UseToon = false; > { pass DrawObject { MultiSampleAntialias = TRUE; VertexShader = compile vs_2_0 BufferShadow_VS(true, true, false,SlideValue); PixelShader = compile ps_2_0 BufferShadow_PS(true, true, false, ObjTexSampler); } } // オブジェクト描画用テクニック(PMDモデル用) technique MainTecBS4 < string MMDPass = "object_ss"; bool UseTexture = false; bool UseSphereMap = false; bool UseToon = true; > { pass DrawObject { MultiSampleAntialias = TRUE; VertexShader = compile vs_2_0 BufferShadow_VS(false, false, true,SlideValue); PixelShader = compile ps_2_0 BufferShadow_PS(false, false, true, ObjTexSampler); } } technique MainTecBS5 < string MMDPass = "object_ss"; bool UseTexture = true; bool UseSphereMap = false; bool UseToon = true; > { pass DrawObject { MultiSampleAntialias = TRUE; VertexShader = compile vs_2_0 BufferShadow_VS(true, false, true,SlideValue); PixelShader = compile ps_2_0 BufferShadow_PS(true, false, true, ObjTexSampler); } } technique MainTecBS6 < string MMDPass = "object_ss"; bool UseTexture = false; bool UseSphereMap = true; bool UseToon = true; > { pass DrawObject { MultiSampleAntialias = TRUE; VertexShader = compile vs_2_0 BufferShadow_VS(false, true, true,SlideValue); PixelShader = compile ps_2_0 BufferShadow_PS(false, true, true, ObjTexSampler); } } technique MainTecBS7 < string MMDPass = "object_ss"; bool UseTexture = true; bool UseSphereMap = true; bool UseToon = true; > { pass DrawObject { MultiSampleAntialias = TRUE; VertexShader = compile vs_2_0 BufferShadow_VS(true, true, true,SlideValue); PixelShader = compile ps_2_0 BufferShadow_PS(true, true, true, ObjTexSampler); } } ///////////////////////////////////////////////////////////////////////////////////////////////
3. 3DViewModelRender_RightEye.fx
も同様に書き換える
ただし、
//左右カメラの視点位置からみた補正角度 マイナスで平行/交差法入れ替わる #define SlideValue 0.5f // 3DViewModelRender_LeftEye.fx はこちら //#define SlideValue -0.5f // 3DViewModelRender_RightEye.fx はこちら
の部分は
//左右カメラの視点位置からみた補正角度 マイナスで平行/交差法入れ替わる //#define SlideValue 0.5f // 3DViewModelRender_LeftEye.fx はこちら #define SlideValue -0.5f // 3DViewModelRender_RightEye.fx はこちら
としてください。
4. 3DViewBufferRender_交差法.x
を読み込んで、目標とするモデルの『頭』に関連付けする
その座標(から Zdiff だけ動かした Z 位置)が収束点の奥行方向の距離になります。(場合によってはダミーボーンを読み込んでそれに関連付けして手動で動かした方が扱いやすいかもしれません)
以上で立体視できているはず。
ちなみに Si
の値を変えると視差をコントロールできます。(標準では 1度)
視野角の変化に応じてコントロールする必要があるでしょう。
MMD 上で立体視するには 3DViewBufferRender_交差法.x
を使うのが妥当*5ですが、3DViewBufferRender_インタレースLR.x
等インタレース系のものに替えれば収束点の位置、および収束点以外の位置でのズレの量を確認しやすいです。
注意:
3DViewBufferRender_インタレースLR.xに替える場合はfloat4 ControlObject : CONTROLOBJECT < string name = "3DViewBufferRender_交差法.x"; >; float4 ControlObjectSize : CONTROLOBJECT < string name = "3DViewBufferRender_交差法.x"; string item = "Si"; >;の部分も合わせて書き換える必要があります。
利用条件について
上記 .fx は元にした Furia さんのものと同様の条件で利用してください。つまり
◆利用規約
使用に際して、参考元ソース作成者および、私が責任を負わない
かつ、自己責任のもと使用する場合において上記以外の制限を追加することはありません。
ということになります。