シェーダの最適化を楽しむ(2)
id:ABAさんのシェーダに続き、id:erakanさんのシェーダについて、使用スロット数上の最適化を行ってみました。
- http://d.hatena.ne.jp/erakan/20070612より
- ShaderOriginal→ShaderXELFMod
- こちらも同じ話題に基づくシェーダです。
- 提供されているzipのEdge.fxを置き換えることで動作します。
float4x4 g_mWorldViewProjection; // World * View * Projection matrix float g_fEdgeWidth; // Width of edge struct VS_INPUT { float4 Position : POSITION; float4 Diffuse : COLOR0; float2 Texcoord : TEXCOORD0; }; struct VS_OUTPUT { float4 Position : POSITION; float4 Diffuse : COLOR0; float2 Texcoord : TEXCOORD0; }; struct PS_OUTPUT { float4 Color : COLOR0; }; VS_OUTPUT VS(VS_INPUT Input) { VS_OUTPUT Output; Output.Position = mul(Input.Position, g_mWorldViewProjection); Output.Diffuse = float4(1.0f, 1.0f, 1.0f, 1.0f); Output.Texcoord = Input.Texcoord; return Output; } PS_OUTPUT PS(VS_OUTPUT Input) { PS_OUTPUT Output; // make 'screen to texcoord' matrix float a = ddx(Input.Texcoord.x); float b = ddx(Input.Texcoord.y); float c = ddy(Input.Texcoord.x); float d = ddy(Input.Texcoord.y); // make inverse('texcoord to screen') matrix float det = a*d - b*c; float idet = (det != 0.0f) ? 1.0f / det : 0.0f; float ia = d * idet; float ib = -b * idet; float ic = -c * idet; float id = a * idet; float2 screenXY; float screenLength; // convert uv(1,0) to screenXY screenXY = float2(ia, ib); screenLength = length(screenXY); // calculate U where screenLength = g_fEdgeWidth float edgeU = g_fEdgeWidth / screenLength; // convert uv(0,1) to screenXY screenXY = float2(ic, id); screenLength = length(screenXY); // calculate V where screen length = g_fEdgeWidth float edgeV = g_fEdgeWidth / screenLength; float edge = ( Input.Texcoord.x <= edgeU || Input.Texcoord.x >= 1.0f - edgeU || Input.Texcoord.y <= edgeV || Input.Texcoord.y >= 1.0f - edgeV) ? 0.0f : 1.0f; Output.Color = float4(edge, edge, edge, 1.0f); return Output; } PS_OUTPUT PSX(VS_OUTPUT Input) { PS_OUTPUT Output; // make 'screen to texcoord' matrix float4 m = float4(ddx(Input.Texcoord.xy), ddy(Input.Texcoord.xy)); // make inverse('texcoord to screen') matrix float det = dot(m.xy * float2(+1, -1), m.wz); // a*d - b*c; float idet = (det != 0.0f) ? 1.0f / det : 0.0f; float4 screen = m.wyzx * float4(+1, -1, -1, +1) * idet; float2 screenLength = float2(length(screen.xy), length(screen.zw)); // calculate U,V where screenLength = g_fEdgeWidth float2 edge = g_fEdgeWidth / screenLength; float2 bound = (Input.Texcoord.xy >= edge) * (Input.Texcoord.xy <= float2(1, 1) - edge); float mask = bound.x * bound.y; Output.Color = float4(mask, mask, mask, 1.0f); return Output; } technique ShaderXELFMod { pass P0 { VertexShader = compile vs_3_0 VS(); // XELF's mod / ps_3_0: 25-slots @ D3D10 Shader Compiler 9.19.949.0046 PixelShader = compile ps_3_0 PSX(); } } technique ShaderOriginal { pass P0 { VertexShader = compile vs_3_0 VS(); // original / ps_3_0: 36-slots @ D3D10 Shader Compiler 9.19.949.0046 PixelShader = compile ps_3_0 PS(); } }