5.再使用一张立方纹理把颜色转换回HSV空间。
第2~5步的pixel shader代码如下,需要pixel shader 2.0的支持。
struct PS_INPUT {
float2 uv[2] : TEXCOORD0; //base uv,displace uv };
float4 psMain( PS_INTPUT i) : COLOR {
//sample rgb,convert into hsv
half base = tex2D( smpBase, i.uv[0] ).rgb;
base = tex3D( smpRGB2HSV, base ).rgb;
//get 2 displaced sample locations
half2 bleedB = tex2D ( smpBleedB, i.uv[1] ).rg * 2 -1;
half2 bleedC = tex2D ( smpBleedC, i.uv[1] ).rg * 2 -1;
float2 uvB = i.uv[0] + bleedB * (8.0/512);
float2 uvC = i.uv[0] + bleedC * (-7.0/512);
//sample base at displaced locations ,convert to hsv
half3 baseB = tex2D( smpBase,uvB).rgb;
baseB = tex3D( smpRGB2HSV,baseB);
half3 baseC = tex2D( smpBase, uvC).rgb;
baseC = tex3D( smpRGB2HSV,baseC);
half3 bleed = baseB * 0.5 + baseC * 0.5;
//final color is base if differences in hsv values are smller than tresholds
//else average of displace values
half3 diff = abs(base - baseC) - half( 1/8.0,1/3.0,1/3.0)
half3 final = all( diff < float3 ( 0,0,0) ? base : bleed;
//leave original hue channel
final.r = base.r;
//convert back to rgb
return tex3D ( smpHSV2RGB),final); }
边缘检测和轮廓线
为了获得NPR风格的样式,必须在图片上渲染出深色的轮廓线和阴影线,表现出场景的着色效果。在Shaderey中,我们将同时绘制边缘轮廓线和阴影线。这里需要使用之前计算的法线/深度图来计算边缘,用光线和法线的点积来计算那些区域需要绘制阴影线。阴影线是一张简单的纹理。在这一步处理中,边缘和轮廓线都是白色。最终合成时,进行反色处理,轮廓线变为纯黑色,轮廓线颜色根据场景的着色进行衰减。
以下是绘制轮廓线和阴影线的pixel shader代码:
half4 psMain ( float2 uv[3]:TEXCOORD): COLOR {
//sample center and 2 neightbours
half4 cbase = tex2D( smpBase, i.uv[0]);
half4 cb1 = tex2D(smpBase, i.uv[1]);
half4 cb3 = tex2D(smpBase, i.uv[2]);
//normal into -1..1 range
half3 nbase = cbase.xyz * 2 -1;
half3 nb1 = cb1.xyz * 2 - 1;
half3 nb3 = cb3.xyz * 2 - 1;
//edges from normals
half2 ndiff;
ndiff.x = dot( nbase,nb1);
ndiff.y = dot( nbase,nb3);
ndiff -= 0.6;
ndiff = ndiff > half2(0,0) ? half2(0,0):half2(1,1);
half ndiff1 = ndiff.x + ndiff.y;
//edges from z
float2 zdiff;
zdiff.x = cbase.a - cd1.a;
zdiff.y = cbase.a - cb3.a;
adiff = abs(zdiff) - 0.02;
zdiff = zdiff > half2(0,0) ? half2(1,1) : half2(0,0);
//sampler hatch
half4 chatch = tex2D( smpHatch, i.uv[0]);
//dot normal with light
half dotNL = dot( nbase, vLightDir);
//hatch blend factor
half factor = saturate( (1.0 - 0.9 - dotNL) * 2);
chatch *= factor;
return chatch + ndiff1 + dot(zdiff,half2(1,1)); } |