DirectX9 SDK Samples(26) PixelMotionBlur Sample
動(dòng)態(tài)模糊,一看到這個(gè)詞我就想到了極品飛車和MineCraft的光影MOD。DX11貌似可以很好地支持動(dòng)態(tài)模糊,但這個(gè)例子是基于DX9的,那DX9是怎么實(shí)現(xiàn)MotionBlur的呢?
SDK文檔里面提到,實(shí)現(xiàn)動(dòng)態(tài)模糊的其中一種方法是將場(chǎng)景用不同的Alpha通道渲染多遍。這個(gè)例子用的是另外一個(gè)方法,模仿現(xiàn)實(shí)中動(dòng)態(tài)模糊出現(xiàn)的條件,記錄像素的速度來(lái)實(shí)現(xiàn)動(dòng)態(tài)模糊。
既然是Post-Process,那么多個(gè)RenderTarget一般都是需要的。RenderTarget需要三個(gè)紋理,一個(gè)用來(lái)渲染原來(lái)的場(chǎng)景,另外兩個(gè)是浮點(diǎn)紋理,提供給PS來(lái)渲染每個(gè)像素的速度,其中一個(gè)記錄上一幀的速度,另外一個(gè)記錄當(dāng)前幀的速度。也需要一個(gè)QUAD用來(lái)顯示最后的紋理。
在Render函數(shù)主要完成了兩件事:1.渲染場(chǎng)景和記錄當(dāng)前幀每個(gè)像素的速度,假如設(shè)備不支持同時(shí)渲染多個(gè)RenderTarget,那么就需要在兩個(gè)Pass內(nèi)完成上述渲染;2.完成Post-Process,對(duì)一個(gè)全屏的矩形(就是上面提到的QUAD)每個(gè)像素執(zhí)行MB的PS。
那么該怎么計(jì)算速度呢?可以確定的是,這個(gè)計(jì)算必須在VS上進(jìn)行。那么是不是保存所有點(diǎn)的上一次的坐標(biāo)呢?明顯不用,只需要保存上一次的WVP矩陣就可以了。
// Transform from object space to homogeneous projection spacevPosProjSpaceCurrent = mul(vPos, mWorldViewProjection);vPosProjSpaceLast = mul(vPos, mWorldViewProjectionLast);// Output the vetrex position in projection spaceOutput.Position = vPosProjSpaceCurrent;// Convert to non-homogeneous points [-1,1] by dividing by w vPosProjSpaceCurrent /= vPosProjSpaceCurrent.w;vPosProjSpaceLast /= vPosProjSpaceLast.w;// Vertex's velocity (in non-homogeneous projection space) is the position this frame minus // its position last frame. This information is stored in a texture coord. The pixel shader // will read the texture coordinate with a sampler and use it to output each pixel's velocity.float2 velocity = vPosProjSpaceCurrent - vPosProjSpaceLast; // The velocity is now between (-2,2) so divide by 2 to get it to (-1,1)velocity /= 2.0f; // Store the velocity in a texture coordOutput.VelocityUV = velocity; 這一段HLSL代碼正是完成了計(jì)算速度的工作。注意,在計(jì)算速度前需要先除以w值,具體我也不清楚為什么。 PS_OUTPUT WorldPixelShader( VS_OUTPUT In ) { PS_OUTPUT Output;Output.RGBColor = tex2D(MeshTextureSampler, In.TextureUV) * In.Diffuse;Output.PixelVelocity = float4(In.VelocityUV,1.0f,1.0f);// Using MRT, output 2 values in the pixel shader. return Output; }PS不需要做什么,基本上輸出值就好了。接下來(lái)就是怎么樣利用記錄好的值來(lái)進(jìn)行MotionBlur了。
float curVelocitySqMag = curFramePixelVelocity.r * curFramePixelVelocity.r +curFramePixelVelocity.g * curFramePixelVelocity.g;float lastVelocitySqMag = lastFramePixelVelocity.r * lastFramePixelVelocity.r +lastFramePixelVelocity.g * lastFramePixelVelocity.g;if( lastVelocitySqMag > curVelocitySqMag ){pixelVelocity.x = lastFramePixelVelocity.r * PixelBlurConst; pixelVelocity.y = -lastFramePixelVelocity.g * PixelBlurConst;}else{pixelVelocity.x = curFramePixelVelocity.r * PixelBlurConst; pixelVelocity.y = -curFramePixelVelocity.g * PixelBlurConst; }// For each sample, sum up each sample's color in "Blurred" and then divide// to average the color after all the samples are added.float3 Blurred = 0; for(float i = 0; i < NumberOfPostProcessSamples; i++){ // Sample texture in a new spot based on pixelVelocity vector // and average it with the other samples float2 lookup = pixelVelocity * i / NumberOfPostProcessSamples + OriginalUV;// Lookup the color at this new spotfloat4 Current = tex2D(RenderTargetSampler, lookup);// Add it with the other samplesBlurred += Current.rgb;}// Return the average color of all the samplesreturn float4(Blurred / NumberOfPostProcessSamples, 1.0f); 以上就是MB的HLSL代碼,簡(jiǎn)單來(lái)說(shuō)就是首先確定使用哪一個(gè)速度值,然后就是根據(jù)速度方向來(lái)進(jìn)行采樣,這樣就產(chǎn)生了模糊效果。使用這樣的方法來(lái)模擬動(dòng)態(tài)模糊有兩個(gè)缺點(diǎn),一個(gè)是在邊緣會(huì)出現(xiàn)漏洞,第二個(gè)是當(dāng)物體移動(dòng)過(guò)快時(shí)模糊效果不對(duì),后一個(gè)可以通過(guò)提高幀數(shù)解決。前一個(gè)如果對(duì)每一個(gè)像素周圍的像素也進(jìn)行采用的話,估計(jì)改善情況。
總結(jié)
以上是生活随笔為你收集整理的DirectX9 SDK Samples(26) PixelMotionBlur Sample的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: git pull远程master_git
- 下一篇: 等了好久终于到今天--姐拿到驾照了(考试