만화적 표현은 크게 2가지 특징이 있다. 첫째로 외곽선 표현하는 것이고, 둘째로는 명암처리를 칼같이(?) 표현해 주는 것이다.
뭐 당연한 이야기니 자세한건 스킵. (사실 본인도 그외의 것은 잘 모르겠음)
일단은 외곽선을 생성해봅시다.
명암처리는 사실 너무 단순하다. 어차피 밝기가 0~1 사이 값으로 올테니 중간 중간에 양자화(Quantization) 해버리면 그만!
//**************************************************************//
// Effect File exported by RenderMonkey 1.6
//
// - Although many improvements were made to RenderMonkey FX
// file export, there are still situations that may cause
// compilation problems once the file is exported, such as
// occasional naming conflicts for methods, since FX format
// does not support any notions of name spaces. You need to
// try to create workspaces in such a way as to minimize
// potential naming conflicts on export.
//
// - Note that to minimize resulting name collisions in the FX
// file, RenderMonkey will mangle names for passes, shaders
// and function names as necessary to reduce name conflicts.
//**************************************************************//
//--------------------------------------------------------------//
// Cartoon Drawing
//--------------------------------------------------------------//
//--------------------------------------------------------------//
// Pass 0 : Normal
//--------------------------------------------------------------//
string Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_0_:_Normal_Model : ModelData = ".\\Model\\ElephantBody\\ElephantBody.3ds";
texture RTDepth_Tex : RenderColorTarget
<
float2 ViewportRatio={1.0,1.0};
string Format="D3DFMT_A8R8G8B8";
float ClearDepth=1.000000;
int ClearColor=-16777216;
>;
float4x4 view_proj_matrix : ViewProjection;
struct VS_INPUT
{
float4 Pos : POSITION;
float3 Normal : NORMAL;
float2 TexCoord : TEXCOORD0;
};
struct VS_OUTPUT
{
float4 Pos : POSITION;
float4 Color : COLOR0;
};
VS_OUTPUT Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_0_:_Normal_Vertex_Shader_vs_main( VS_INPUT In )
{
VS_OUTPUT Out;
Out.Pos = mul( In.Pos, view_proj_matrix );
Out.Color = float4(In.Normal, 1.0f);//Out.Pos.z/Out.Pos.w;
return Out;
}
float4 Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_0_:_Normal_Pixel_Shader_ps_main(float4 Color : COLOR0) : COLOR0
{
return Color ;
}
//--------------------------------------------------------------//
// Pass 0 : Depth
//--------------------------------------------------------------//
string Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_0_:_Depth_Model : ModelData = ".\\Model\\ElephantBody\\ElephantBody.3ds";
texture Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_0_:_Depth_RTDepth : RenderColorTarget
<
float2 ViewportRatio={1.0,1.0};
string Format="D3DFMT_A8R8G8B8";
float ClearDepth=1.000000;
int ClearColor=-16777216;
>;
float4x4 Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_0_:_Depth_Vertex_Shader_view_proj_matrix : ViewProjection;
struct Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_0_:_Depth_Vertex_Shader_VS_INPUT
{
float4 Pos : POSITION;
float3 Normal : NORMAL;
float2 TexCoord : TEXCOORD0;
};
struct Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_0_:_Depth_Vertex_Shader_VS_OUTPUT
{
float4 Pos : POSITION;
float4 Color : COLOR0;
};
Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_0_:_Depth_Vertex_Shader_VS_OUTPUT Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_0_:_Depth_Vertex_Shader_vs_main( Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_0_:_Depth_Vertex_Shader_VS_INPUT In )
{
Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_0_:_Depth_Vertex_Shader_VS_OUTPUT Out;
Out.Pos = mul( In.Pos, Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_0_:_Depth_Vertex_Shader_view_proj_matrix );
Out.Color = Out.Pos.z/Out.Pos.w;
return Out;
}
float4 Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_0_:_Depth_Pixel_Shader_ps_main(float4 Color : COLOR0) : COLOR0
{
return Color;
}
//--------------------------------------------------------------//
// Pass 1 : Edge
//--------------------------------------------------------------//
string Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_1_:_Edge_ScreenAlignedQuad : ModelData = ".\\Model\\Etc\\ScreenAlignedQuad.3ds";
texture RTEdge_Tex : RenderColorTarget
<
float2 ViewportRatio={1.0,1.0};
string Format="D3DFMT_A8R8G8B8";
float ClearDepth=1.000000;
int ClearColor=-16777216;
>;
float4x4 Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_1_:_Edge_Vertex_Shader_view_proj_matrix;
struct Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_1_:_Edge_Vertex_Shader_VS_INPUT
{
float4 Pos : POSITION;
float3 Normal : NORMAL;
float2 TexCoord : TEXCOORD0;
};
struct Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_1_:_Edge_Vertex_Shader_VS_OUTPUT
{
float4 Pos : POSITION;
float2 TexCoord : TEXCOORD0;
};
Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_1_:_Edge_Vertex_Shader_VS_OUTPUT Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_1_:_Edge_Vertex_Shader_vs_main( Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_1_:_Edge_Vertex_Shader_VS_INPUT In )
{
Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_1_:_Edge_Vertex_Shader_VS_OUTPUT Out;
In.Pos.xy = sign(In.Pos.xy);
Out.Pos = float4(In.Pos.xy, 0.0, 1.0);
// Image-space
Out.TexCoord.x = 0.5 * (1 + In.Pos.x);
Out.TexCoord.y = 0.5 * (1 - In.Pos.y);
return Out;
}
sampler2D mapDepth = sampler_state
{
Texture = (RTDepth_Tex);
ADDRESSU = CLAMP;
ADDRESSV = CLAMP;
};
float mask[9] =
{ -1, -1, -1,
-1, 8, -1,
-1, -1, -1 }; // Laplacian Filter
float coord[3] = { -1, 0, +1 };
float divider = 1;
float fViewportWidth : ViewportWidth;
float fViewportHeight : ViewportHeight;
float4 Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_1_:_Edge_Pixel_Shader_ps_main( float2 Tex : TEXCOORD0 ) : COLOR
{
float4 Color = 0;
float4 Ret;
for( int i = 0 ; i < 9 ; i++ )
Color += mask[i] * ( tex2D( mapDepth, Tex + float2( coord[i%3]/(fViewportWidth), coord[i/3]/(fViewportHeight) ) ) );
float gray = 1 - (Color.r * 0.3 + Color.g * 0.59 + Color.b * 0.11);
Ret = float4( gray, gray, gray, 1 ) / divider;
return smoothstep(0.8, 1, Ret);
}
//--------------------------------------------------------------//
// Pass 2 : Blurred Edge
//--------------------------------------------------------------//
string Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_2_:_Blurred_Edge_ScreenAlignedQuad : ModelData = ".\\Model\\Etc\\ScreenAlignedQuad.3ds";
texture RTBlurredEdge_Tex : RenderColorTarget
<
float2 ViewportRatio={1.0,1.0};
string Format="D3DFMT_A8R8G8B8";
float ClearDepth=1.000000;
int ClearColor=-16777216;
>;
float4x4 Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_2_:_Blurred_Edge_Vertex_Shader_view_proj_matrix;
struct Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_2_:_Blurred_Edge_Vertex_Shader_VS_INPUT
{
float4 Pos : POSITION;
float2 TexCoord : TEXCOORD0;
};
struct Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_2_:_Blurred_Edge_Vertex_Shader_VS_OUTPUT
{
float4 Pos : POSITION;
float2 TexCoord : TEXCOORD0;
};
Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_2_:_Blurred_Edge_Vertex_Shader_VS_OUTPUT Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_2_:_Blurred_Edge_Vertex_Shader_vs_main( Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_2_:_Blurred_Edge_Vertex_Shader_VS_INPUT In )
{
Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_2_:_Blurred_Edge_Vertex_Shader_VS_OUTPUT Out;
In.Pos.xy = sign(In.Pos.xy);
Out.Pos = float4(In.Pos.xy, 0.0, 1.0);
// Image-space
Out.TexCoord.x = 0.5 * (1 + In.Pos.x);
Out.TexCoord.y = 0.5 * (1 - In.Pos.y);
return Out;
}
sampler2D mapEdge = sampler_state
{
Texture = (RTEdge_Tex);
ADDRESSU = CLAMP;
ADDRESSV = CLAMP;
MAGFILTER = ANISOTROPIC;
MINFILTER = ANISOTROPIC;
MIPFILTER = ANISOTROPIC;
};
float Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_2_:_Blurred_Edge_Pixel_Shader_fViewportWidth : ViewportWidth;
float Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_2_:_Blurred_Edge_Pixel_Shader_fViewportHeight : ViewportHeight;
float Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_2_:_Blurred_Edge_Pixel_Shader_mask[9] =
{ 1, 1, 1,
1, 1, 1,
1, 1, 1 }; // LPH
float Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_2_:_Blurred_Edge_Pixel_Shader_coord[3] = { -1, 0, +1 };
float Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_2_:_Blurred_Edge_Pixel_Shader_divider = 9;
float4 Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_2_:_Blurred_Edge_Pixel_Shader_ps_main( float2 TexCoord : TEXCOORD0 ) : COLOR
{
float4 Color = 0;
float4 Ret;
for( int i = 0 ; i < 9 ; i++ )
{
float2 tex = TexCoord + float2( Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_2_:_Blurred_Edge_Pixel_Shader_coord[i%3]/Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_2_:_Blurred_Edge_Pixel_Shader_fViewportWidth, Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_2_:_Blurred_Edge_Pixel_Shader_coord[i/3]/Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_2_:_Blurred_Edge_Pixel_Shader_fViewportHeight ) ;
tex = saturate(tex);
Color += Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_2_:_Blurred_Edge_Pixel_Shader_mask[i] * ( tex2D( mapEdge, tex ) );
}
Color = Color / Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_2_:_Blurred_Edge_Pixel_Shader_divider;
return Color;
}
//--------------------------------------------------------------//
// Pass 3 : Interior
//--------------------------------------------------------------//
string Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_3_:_Interior_Model : ModelData = ".\\Model\\ElephantBody\\ElephantBody.3ds";
texture RTInterior_Tex : RenderColorTarget
<
float2 ViewportRatio={1.0,1.0};
string Format="D3DFMT_A8R8G8B8";
float ClearDepth=1.000000;
int ClearColor=-1;
>;
float4x4 Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_3_:_Interior_Vertex_Shader_view_proj_matrix : ViewProjection;
float4x4 view_matrix : View;
struct Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_3_:_Interior_Vertex_Shader_VS_INPUT
{
float4 Pos : POSITION;
float3 Normal : NORMAL;
float2 TexCoord : TEXCOORD0;
};
struct Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_3_:_Interior_Vertex_Shader_VS_OUTPUT
{
float4 Pos : POSITION;
float3 Normal : TEXCOORD0;
float2 TexCoord : TEXCOORD1;
};
Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_3_:_Interior_Vertex_Shader_VS_OUTPUT Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_3_:_Interior_Vertex_Shader_vs_main( Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_3_:_Interior_Vertex_Shader_VS_INPUT In )
{
Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_3_:_Interior_Vertex_Shader_VS_OUTPUT Out;
Out.Pos = mul( In.Pos, Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_3_:_Interior_Vertex_Shader_view_proj_matrix );
float3 Normal = mul( In.Normal, view_matrix );
Out.Normal = normalize(Normal);
Out.TexCoord = In.TexCoord;
return Out;
}
sampler2D mapModel;
texture texShade_Tex
<
string ResourceName = ".\\Texture\\Cartoon Drawing\\shade.jpg";
>;
sampler2D mapShade = sampler_state
{
Texture = (texShade_Tex);
};
float4 vColor
<
string UIName = "vColor";
string UIWidget = "Color";
bool UIVisible = true;
> = float4( 0.65, 0.65, 0.65, 1.00 );
float3 lightPos
<
string UIName = "lightPos";
string UIWidget = "Numeric";
bool UIVisible = false;
float UIMin = -1.00;
float UIMax = 1.00;
> = float3( 0.52, 0.77, -0.37 );
float4 Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_3_:_Interior_Pixel_Shader_ps_main( float3 Normal : TEXCOORD0,
float4 TexCoord : TEXCOORD1 ) : COLOR0
{
float3 EyeDir = normalize(lightPos);
float3 Diffuse = saturate(dot(Normal, EyeDir));
float4 Color = tex2D( mapShade, float2( Diffuse.x, 0.0f ));
//return vColor * float4(Diffuse, 1.0f);
return vColor * (Color+0.4);//tex2D( mapModel, TexCoord);
}
//--------------------------------------------------------------//
// Pass 4 : Mix Above Results
//--------------------------------------------------------------//
string Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_4_:_Mix_Above_Results_ScreenAlignedQuad : ModelData = ".\\Model\\Etc\\ScreenAlignedQuad.3ds";
float4x4 Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_4_:_Mix_Above_Results_Vertex_Shader_view_proj_matrix;
struct Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_4_:_Mix_Above_Results_Vertex_Shader_VS_INPUT
{
float4 Pos : POSITION;
float3 Normal : NORMAL;
float2 TexCoord : TEXCOORD0;
};
struct Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_4_:_Mix_Above_Results_Vertex_Shader_VS_OUTPUT
{
float4 Pos : POSITION;
float2 TexCoord : TEXCOORD0;
};
Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_4_:_Mix_Above_Results_Vertex_Shader_VS_OUTPUT Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_4_:_Mix_Above_Results_Vertex_Shader_vs_main( Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_4_:_Mix_Above_Results_Vertex_Shader_VS_INPUT In )
{
Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_4_:_Mix_Above_Results_Vertex_Shader_VS_OUTPUT Out;
In.Pos.xy = sign(In.Pos.xy);
Out.Pos = float4(In.Pos.xy, 0.0, 1.0);
// Image-space
Out.TexCoord.x = 0.5 * (1 + In.Pos.x);
Out.TexCoord.y = 0.5 * (1 - In.Pos.y);
return Out;
}
sampler2D mapInterior = sampler_state
{
Texture = (RTInterior_Tex);
ADDRESSU = CLAMP;
ADDRESSV = CLAMP;
};
sampler2D mapBlurredEdge = sampler_state
{
Texture = (RTEdge_Tex);
ADDRESSU = CLAMP;
ADDRESSV = CLAMP;
};
float4 Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_4_:_Mix_Above_Results_Pixel_Shader_ps_main(float2 TexCoord : TEXCOORD0) : COLOR0
{
float4 Color1 = saturate(tex2D( mapInterior, TexCoord));
float4 Color2 = saturate(tex2D( mapBlurredEdge, TexCoord + float2(0, 0.001)));
//Color2 = saturate(tex2D( mapEdge, TexCoord ));
//return Color1;
return Color1 * Color2;
}
//--------------------------------------------------------------//
// Technique Section for HL Project.Non Photorealistic Rendering.Cartoon Drawing
//--------------------------------------------------------------//
technique Cartoon_Drawing
{
pass Pass_0_:_Normal
<
string Script = "RenderColorTarget0 = RTDepth_Tex;"
"ClearColor = (0, 0, 0, 255);"
"ClearDepth = 1.000000;";
>
{
CULLMODE = CCW;
VertexShader = compile vs_2_0 Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_0_:_Normal_Vertex_Shader_vs_main();
PixelShader = compile ps_2_0 Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_0_:_Normal_Pixel_Shader_ps_main();
}
pass Pass_0_:_Depth
<
string Script = "RenderColorTarget0 = Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_0_:_Depth_RTDepth;"
"ClearColor = (0, 0, 0, 255);"
"ClearDepth = 1.000000;";
>
{
CULLMODE = CCW;
VertexShader = compile vs_2_0 Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_0_:_Depth_Vertex_Shader_vs_main();
PixelShader = compile ps_2_0 Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_0_:_Depth_Pixel_Shader_ps_main();
}
pass Pass_1_:_Edge
<
string Script = "RenderColorTarget0 = RTEdge_Tex;"
"ClearColor = (0, 0, 0, 255);"
"ClearDepth = 1.000000;";
>
{
CULLMODE = CW;
VertexShader = compile vs_2_0 Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_1_:_Edge_Vertex_Shader_vs_main();
PixelShader = compile ps_2_0 Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_1_:_Edge_Pixel_Shader_ps_main();
}
pass Pass_2_:_Blurred_Edge
<
string Script = "RenderColorTarget0 = RTBlurredEdge_Tex;"
"ClearColor = (0, 0, 0, 255);"
"ClearDepth = 1.000000;";
>
{
CULLMODE = NONE;
VertexShader = compile vs_1_1 Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_2_:_Blurred_Edge_Vertex_Shader_vs_main();
PixelShader = compile ps_2_0 Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_2_:_Blurred_Edge_Pixel_Shader_ps_main();
}
pass Pass_3_:_Interior
<
string Script = "RenderColorTarget0 = RTInterior_Tex;"
"ClearColor = (255, 255, 255, 255);"
"ClearDepth = 1.000000;";
>
{
CULLMODE = CCW;
VertexShader = compile vs_2_0 Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_3_:_Interior_Vertex_Shader_vs_main();
PixelShader = compile ps_2_0 Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_3_:_Interior_Pixel_Shader_ps_main();
}
pass Pass_4_:_Mix_Above_Results
{
CULLMODE = CW;
VertexShader = compile vs_2_0 Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_4_:_Mix_Above_Results_Vertex_Shader_vs_main();
PixelShader = compile ps_2_0 Non_Photorealistic_Rendering_Cartoon_Drawing_Pass_4_:_Mix_Above_Results_Pixel_Shader_ps_main();
}
}