Shaderey――非真实渲染



Shaderey――非真实渲染

本文版权归原作者所有仅供个人学习使用请勿转载勿用于任何商业用途
由于本人水平有限难免出错不清楚地方请大家以原著为准欢迎大家和我多多交流
作者:ArasPranckevicius
翻译:clayman
Blog:http://blog.csdn.net/soilwork
[email protected]

本文描述了以非真实渲染(none-photorealisticrendering)风格对户外场景进行着色技术在2003年秋天Beyond3D/ATIshadercompititon中Shaderey最先使用了这些技术来进行渲染在Shaderey户外场景中包含了地形树木房屋天空顶以及湖水如图所示:
.flickr.com/131/354342324_fabfd6abce.jpg?v=0\" border=\"0\" _disibledevent=>screen.width-333) {this.width=screen.width-333;this.title=\'open window\';}\" _disibledevent=>
确切这里使用NPR技术都是在图片空间(imagespace)进行操作它依赖于场景中两张重要图片:张包含了颜色信息张包含法线和深度信息处理过程分为两部分:
渲染:把场景渲染到颜色和法线/深度目标中
后期处理:在图片空间进行系列过滤操作获得最终非真实效果

后期处理包括:HSV空间下颜色扭曲屏幕空间中简单“阴影线(hatching)”渲染以及在法线/深度不连续处轮廓线绘制我们将在后面详细讨论这些过滤操作首先先来看看Shaderey场景渲染方式

场景渲染

场景中所有树木和房屋都经过了可视体裁剪(frustum-culled)地形是张512x512高度图但分为若干尺寸固定(32x32)小块(chunk)所有通过视见体裁剪地形小块都没有进行任何形式LOD整个场景使用了张1024x1024阴影帖图房屋和树木都将产生阴影并且投影到地面上场景中树木和木屋投射阴影而地形接收这些影子我们使用pick-nearest采样器对阴影贴图进行 4次有偏移采样然后再shader中对这些值进行均值采样以提高影子边界上质量阴影贴图并不需要覆盖整个地形大小在我们实现中它将随观察者位置移动以保证观察者前方总是有正确阴影

为了模拟湖面简单反射效果可以把摄像机反转到水面的下把场景渲染为张较小平面反射贴图我们把这张阴影贴图投影到水面上另外使用两张卷动EMBM风格凹凸贴图来模拟波纹为了减少几何数据渲染到反射贴图中地形将使用较低LOD层次对所有物体来说大气光照散射效果都是在顶点级别计算

除了把颜色渲染到后备缓冲的外还需要把场景中物体法线和深度渲染到张和屏幕大小相同A8R8B8G8纹理中世界坐标下法线信息保存在RGB通道中深度值导数保存在alpha通道中

下面是在vertexshader中使用HLSL正确计算法线和深度值倒数代码:


//outputnormalinRGB,sort-of-depthinA,p–final(clipspace)position,n—worldspacenormal

inlinefloat4gNormalZ(float4p,float3n)

{
float4o;
o.xyz=n*0.5+0.5;//o0….1range
o.w=100.0/(p.w+100);//kind-of-depth

}

如果支持DirectX9中MultipleRenderTarget(MRT)可以在渲染场景颜色同时渲染法线和深度如果不支持MRT则需要分两次渲染(译注:从demo来看使用MRT将会严重影响渲染质量应该是由于MRT不支持多重采样造成)当把地形渲染到法线/深度纹理中时需要使用<<Non-PhotorealisticRenderingwithPixelandVertexShader>>中所描述思路方法在pixelshader中对阴影贴图进行采样对阴影中像素来说需要对插值的后深度值取反(译注:在Non-Photo原文中是对法线值取反)这样做原因在后面描述后期处理部分会讲解

图片后期处理

目前已经把场景渲染为颜色和法线/深度图片了接下来就可以对这些图片进行系列处理了包括把颜色转到HSV颜色空间下进行风格化处理绘制边缘轮廓线实现阴影线

颜色失真

图片处理步是进行颜色失真获得风格化样式
1.降低采样率把图片缩为张521x512纹理
2.把颜色从RGB空间转换到HSV空间并且量化(quantize)颜色值颜色空间转换将通过对张体积材质查找来实现把原像素RGB值作为立方纹理坐标立方纹理中像素为HSV颜色空间这里我们将使用张32x32x32纹理并且不进行任何过滤所以颜色转换同时将会量化颜色值


3.使用2D偏移纹理对同纹理中当前像素两个偏移位置进行采样用来访问偏移纹理纹理坐标由控制它们将和观察者位置有关(观察点yaw值将在水平方向影响偏移pitch值在垂直方向影响)这些额外采样颜色也必须转换到HSV空间
4.替换图片中颜色目前我们有2个额外偏移采样首先我们检察两个偏移值的间差分差值如果小于某个限制就什么也不做如果它们的间差别足够大则输出S和V通道均值保留中心原像素H值这个思路方法能高效在颜色区域边缘替换原像素饱和度
5.再使用张立方纹理把颜色转换回HSV空间
第2~5步pixelshader代码如下需要pixelshader2.0支持

structPS_INPUT
{
float2uv[2]:TEXCOORD0;//baseuv,displaceuv
};



float4psMain(PS_INTPUTi):COLOR
{

//samplergb,convertohsv
halfbase=tex2D(smpBase,i.uv[0]).rgb;
base=tex3D(smpRGB2HSV,base).rgb;

//get2displacedsamplelocations
half2bleedB=tex2D(smpBleedB,i.uv[1]).rg*2-1;
half2bleedC=tex2D(smpBleedC,i.uv[1]).rg*2-1;
float2uvB=i.uv[0]+bleedB*(8.0/512);
float2uvC=i.uv[0]+bleedC*(-7.0/512);

//samplebaseatdisplacedlocations,converttohsv
half3baseB=tex2D(smpBase,uvB).rgb;
baseB=tex3D(smpRGB2HSV,baseB);
half3baseC=tex2D(smpBase,uvC).rgb;
baseC=tex3D(smpRGB2HSV,baseC);
half3bleed=baseB*0.5+baseC*0.5;

//finalcolorisbasedferencesinhsvvaluesaresmllerthantresholds
//averageofdisplacevalues
half3df=abs(base-baseC)-half(1/8.0,1/3.0,1/3.0)
half3final=all(df<float3(0,0,0)?base:bleed;

//leaveoriginalhuechannel
final.r=base.r;
//convertbacktorgb
tex3D(smpHSV2RGB),final);

}

边缘检测和轮廓线
为了获得NPR风格样式必须在图片上渲染出深色轮廓线和阴影线表现出场景着色效果在Shaderey中我们将同时绘制边缘轮廓线和阴影线这里需要使用的前计算法线/深度图来计算边缘用光线和法线点积来计算那些区域需要绘制阴影线阴影线是张简单纹理在这步处理中边缘和轮廓线都是白色最终合成时进行反色处理轮廓线变为纯黑色轮廓线颜色根据场景着色进行衰减
以下是绘制轮廓线和阴影线pixelshader代码:

half4psMain(float2uv[3]:TEXCOORD):COLOR
{
//samplecenterand2neightbours
half4cbase=tex2D(smpBase,i.uv[0]);
half4cb1=tex2D(smpBase,i.uv[1]);
half4cb3=tex2D(smpBase,i.uv[2]);

//normalo-1..1range
half3nbase=cbase.xyz*2-1;
half3nb1=cb1.xyz*2-1;


half3nb3=cb3.xyz*2-1;

//edgesfromnormals
half2ndf;
ndf.x=dot(nbase,nb1);
ndf.y=dot(nbase,nb3);
ndf-=0.6;
ndf=ndf>half2(0,0)?half2(0,0):half2(1,1);
halfndf1=ndf.x+ndf.y;

//edgesfromz
float2zdf;
zdf.x=cbase.a-cd1.a;
zdf.y=cbase.a-cb3.a;
adf=abs(zdf)-0.02;
zdf=zdf>half2(0,0)?half2(1,1):half2(0,0);

//samplerhatch
half4chatch=tex2D(smpHatch,i.uv[0]);
//dotnormalwithlight
halfdotNL=dot(nbase,vLightDir);
//hatchblendfactor
halffactor=saturate((1.0-0.9-dotNL)*2);
chatch*=factor;
chatch+ndf1+dot(zdf,half2(1,1));
}

最终合成
在处理完了两张图片的后把失真的后颜色和反转的后边缘/轮廓线进行调制合成出最终图像

点击这里下载完成和代码
.flickr.com/63/354342325_bd69628c3d.jpg?v=0\" border=\"0\" _disibledevent=>screen.width-333) {this.width=screen.width-333;this.title=\'open window\';}\" _disibledevent=>
.flickr.com/126/354342326_063a0fa88e.jpg?v=0\" border=\"0\" _disibledevent=>screen.width-333) {this.width=screen.width-333;this.title=\'open window\';}\" _disibledevent=>

Tags: 

延伸阅读

最新评论

发表评论