运动模糊和景深其实是很早之前的光学拍摄器材的缺陷导致的现象,后面摄影技术发达之后这些反而作为局部后期处理的手段。时至今日,实时渲染也大行其道这种技术。
景深:是由于光学仪器受到焦距的影响,在一个特定的距离空间内的像会比较清晰,而这个区间外的物体会出现模糊。
实现思路:其本质就是对图像进行局部模糊,而模糊的规则就是把深度分成3个区域,前后是模糊的,中间是清晰的。
整个过程分三个Pass:
1.将场景渲染到一个RenderTarget,做为清晰版.
2.将上一步得到的RenderTarget进行模糊处理,得到BluredRT(模糊版).
3.合成.跟据距离来判断是否应该模糊,如果不在焦点范围内则绘制BluredRT,否则就绘制RenderTarget.
sampler RenderTarget;
sampler BluredRT;
//焦点范围
float fNearDis;
float fFarDis;
float4 ps_main( float2 TexCoord : TEXCOORD0 ) : COLOR0
{
float4 color = tex2D( RenderTarget, TexCoord );
if( color.a > fNearDis && color.a < fFarDis )
return color;
else
return tex2D( BluredRT, TexCoord );
}
这个做出效果并不难,难就难在如何在动态的环境中把景深用到最好。
运动模糊 :在拍摄快速运动的物体的时候,由于相机成像会有一小段时间的延时,导致这个区间内的像形成叠加效果。
实现原理:很多地方是用前后帧混合的方式实现运动模糊,我觉得那样子叠加少了效果不明显,多了性能不好,就采用了GPU3里面的那种方式。原理也很简单,以屏幕坐标和深度为参数,构建点的屏幕空间3D位置。然后一路逆转换,转换到世界空间,再用上一帧的转换矩阵,求出上一帧当前顶点的位置。最后,顶点屏幕空间的速度。然后进行插值采样,这种方式的好处是采样率比较高,缺点就是不能直接返回到模型空间,这样在世界空间中运动的物体就不会有运动模糊的效果。
[numthreads( 16, 16, 1 )]
void MotionBlur_CS( uint3 Gid : SV_GroupID, uint GI : SV_GroupIndex,uint3 DTid : SV_DispatchThreadID)
{
matrix inverViewProject = mbMatrix[0]; // view和project乘积的逆
matrix previousViewProject = mbMatrix[1]; // 前一帧的view*project矩阵
int2 iTexCoord = DTid.xy;
float currentDepth = mDepthTexture[iTexCoord].x; // 当前帧的深度
// 当前像素当前帧的view空间的位置
float2 fTexCoord = float2(iTexCoord.x/800,iTexCoord.y/600);
// 到透视空间
float4 currentPosPS = float4(fTexCoord.x*2.0f - 1.0f,(1.0f - fTexCoord.y)*2.0f - 1.0f,currentDepth,1.0f);
float4 currentPosWS = mul(currentPosPS,inverViewProject);
currentPosWS = currentPosWS/currentPosWS.w;
float4 previousPosPS = mul(currentPosWS,previousViewProject);
previousPosPS = previousPosPS/previousPosPS.w;
float2 velocity = abs((currentPosPS - previousPosPS)/2.0f); // 屏幕空间的速度 [0,1]
float4 sceneColor = mSceneTexture[iTexCoord];
float2 deltaVelocity = velocity/NUM_SAMPLES;
for (uint i = 0; i < NUM_SAMPLES-1; i++)
{
iTexCoord += uint2(deltaVelocity.x*800,deltaVelocity.y*600);
iTexCoord.x = clamp(iTexCoord.x,0,800-1);
iTexCoord.y = clamp(iTexCoord.y,0,600-1);
float4 sampleColor = mSceneTexture[iTexCoord];
sceneColor += sampleColor;
}
sceneColor = sceneColor/NUM_SAMPLES;
sceneColor.w = 1.0f;
Result[DTid.xy] = sceneColor;
}
总结:尽管效果做出来了,但是看的人晕。这两种效果本身是由拍摄过程中,器材呈现缺陷而导致的。最终,到这里却成了别人炒作的一个热点,效果本身没有错,就怕滥用,尤其是这种效果,应该建立在复杂的前提下,不经常出现才对。