마스크라는 기법으로 필터링을 해서 색이 급격하게 변하는 부분을 외곽선이라 판단하는 방법이다.
색이 급격하게 변하는 부분을 찾기 위해 첫 패스에선 법선을 컬러로 렌더타깃에 렌더링하고 두번째 패스에서 이 렌더타겟을 이미지로서 프로세싱한다.
의 형태이다. 이걸 입력픽셀 (주변 픽셀 포함 3x3 매트릭스)와 연산하여 엗지검출을 하게된다.
라플라스 필터에 대해서는 다음에 자세히 공부해봐야겠다..
아래는 HLSL 샘플코드.
//--------------------------------------------------------------//
// OutlineRendering
//--------------------------------------------------------------//
//--------------------------------------------------------------//
// NormalRender
//--------------------------------------------------------------//
texture rtOrigin_Tex : RenderColorTarget
<
float2 RenderTargetDimensions = {512,512};
string Format="D3DFMT_A8R8G8B8";
float ClearDepth=1.000000;
int ClearColor=-16777216;
>;
extern float4x4 matViewProjection : ViewProjection;
extern float4x4 matView : View;
struct NormalRender_VS_INPUT
{
float4 Position : POSITION0;
float3 Normal : NORMAL0;
};
struct NormalRender_VS_OUTPUT
{
float4 Position : POSITION0;
float4 NormalColor : COLOR0;
};
NormalRender_VS_OUTPUT NormalRender_vs_main( NormalRender_VS_INPUT In )
{
NormalRender_VS_OUTPUT Out;
Out.Position = mul( In.Position, matViewProjection );
float3 Norm = mul( In.Normal, matView);
Out.NormalColor = float4(Norm, 1.0f);
return Out ;
}
float4 Position_NormalRender_ps_main(float4 NormalColor : COLOR0) : COLOR0
{
return NormalColor;
}
//--------------------------------------------------------------//
// OutlineRender
//--------------------------------------------------------------//
struct OutlineRender_VS_INPUT
{
float4 Position : POSITION0;
float3 Normal : NORMAL0;
};
struct OutlineRender_VS_OUTPUT
{
float4 Position : POSITION0;
float2 TexCoord : TEXCOORD0;
};
OutlineRender_VS_OUTPUT OutlineRender_vs_main( OutlineRender_VS_INPUT In )
{
OutlineRender_Vertex_Shader_VS_OUTPUT Out;
In.Position.xy = sign(In.Position.xy);
Out.Position = float4(In.Position.xy, 0.0f, 1.0f );
//Image-space
//Out.TexCoord = ( float2(In.Position.x, -In.Position.y) + 1.0f) * 0.5f;
Out.TexCoord.x = 0.5f * (1.0f + In.Position.x);
Out.TexCoord.y = 0.5f * (1.0f - In.Position.y);
return( Out );
}
sampler RT = sampler_state
{
Texture = (rtOrigin_Tex);
};
float mask[9] =
{ -1, -1, -1,
-1, 8, -1,
-1, -1, -1 };
float coord[3] = {-1, 0, 1};
float divider = 1.0f;
float MAP_CX = 512.0f;
float MAP_CY = 512.0f;
float4 OutlineRender_ps_main(float2 Tex : TEXCOORD0) : COLOR0
{
float4 color = 0;
for( int i=0; i<9; i++)
color += mask[i] * ( tex2D(RT, Tex + float2(coord[i%3]/MAP_CX, coord[i/3]/MAP_CY)) );
float gray = 1 - (color.r * 0.3f + color.g * 0.59f + color.b*0.11f);
return float4(gray, gray, gray, 1) / divider;
//return tex2D(RT, Tex);
}
//--------------------------------------------------------------//
// Technique Section for OutlineRendering
//--------------------------------------------------------------//
technique OutlineRendering
{
pass NormalRender
<
string Script = "RenderColorTarget0 = rtOrigin_Tex;"
"ClearColor = (0, 0, 0, 255);"
"ClearDepth = 1.000000;";
>
{
VertexShader = compile vs_2_0 NormalRender_vs_main();
PixelShader = compile ps_2_0 NormalRender_ps_main();
}
pass OutlineRender
{
VertexShader = compile vs_2_0 OutlineRender_vs_main();
PixelShader = compile ps_2_0 OutlineRender_ps_main();
}
}