DirectX9 SDK Samples(20) HDRDemo Sample(3)

来源:互联网 发布:人人会计软件 编辑:程序博客网 时间:2024/06/05 23:02

HDR需要对源场景进行处理,因此在渲染初始源场景的时候,也要创建一个纹理,并且将场景渲染到这个纹理上,然后进行HDR处理。这个例子中,上述工作由HDRScene完成。关于渲染到纹理,这篇博文讲得很清楚:http://www.cnblogs.com/graphics/archive/2011/04/23/2024294.html

那么到此为止,我们明白了如何进行计算平均亮度,如何进行Bloom,如何渲染场景到纹理上。那么接下来我们就应该将这些东西组合起来,完成HDR的渲染。

让我们直接进入RenderScene函数:

    if( SUCCEEDED( pd3dDevice->BeginScene() ) )    {        // RENDER THE COMPLETE SCENE        //--------------------------        // The first part of each frame is to actually render the "core"        // resources - those that would be required for an HDR-based pipeline.        // HDRScene creates an unprocessed, raw, image to work with.        HDRScene::RenderScene( pd3dDevice );        // Luminance attempts to calculate what sort of tone/mapping should        // be done as part of the post-processing step.        Luminance::MeasureLuminance( pd3dDevice );        // The post-processing adds the blur to the bright (over-exposed) areas        // of the image.        PostProcess::PerformPostProcessing( pd3dDevice );
上面三个简单的句子就是前面讲过的渲染场景到纹理、计算平均亮度和Bloom。

            LPDIRECT3DSURFACE9 pFinalSurf = NULL;            g_pFinalTexture->GetSurfaceLevel( 0, &pFinalSurf );            pd3dDevice->SetRenderTarget( 0, pFinalSurf );            LPDIRECT3DTEXTURE9 pHDRTex = NULL;            HDRScene::GetOutputTexture( &pHDRTex );            LPDIRECT3DTEXTURE9 pLumTex = NULL;            Luminance::GetLuminanceTexture( &pLumTex );            LPDIRECT3DTEXTURE9 pBloomTex = NULL;            PostProcess::GetTexture( &pBloomTex );            pd3dDevice->SetTexture( 0, pHDRTex );            pd3dDevice->SetTexture( 1, pLumTex );            pd3dDevice->SetTexture( 2, pBloomTex );            pd3dDevice->SetPixelShader( g_pFinalPassPS );            D3DSURFACE_DESC d;            pBloomTex->GetLevelDesc( 0, &d );            g_pFinalPassPSConsts->SetFloat( pd3dDevice, "g_rcp_bloom_tex_w", 1.0f / static_cast< float >( d.Width ) );            g_pFinalPassPSConsts->SetFloat( pd3dDevice, "g_rcp_bloom_tex_h", 1.0f / static_cast< float >( d.Height ) );            g_pFinalPassPSConsts->SetFloat( pd3dDevice, "fExposure", g_fExposure );            g_pFinalPassPSConsts->SetFloat( pd3dDevice, "fGaussianScalar", PostProcess::GetGaussianMultiplier() );            DrawHDRTextureToScreen();//省略            pd3dDevice->SetRenderTarget( 0, pLDRSurface );
然后就是调用最后一个着色器完成合并工作。注意最后一句,将渲染目标还原为原来的LDR平面,其实也没用到。

前面没有看过FX文件,因为其实都比较简单。下面就看一下最后的这个PS完成了什么。

float4 main( in float2 t : TEXCOORD0 ) : COLOR0{    // Read the HDR value that was computed as part of the original scene        float4 c = tex2D( original_scene, t );        // Read the luminance value, target the centre of the texture which will map to the only pixel in it!        float4 l = tex2D( luminance, float2( 0.5f, 0.5f ) ); //也就是亮度平均值            // Compute the blur value using a bilinear filter        float xWeight = frac( t.x / g_rcp_bloom_tex_w ) - 0.5;        float xDir = xWeight;        xWeight = abs( xWeight );        xDir /= xWeight;        xDir *= g_rcp_bloom_tex_w;        float yWeight = frac( t.y / g_rcp_bloom_tex_h ) - 0.5;        float yDir = yWeight;        yWeight = abs( yWeight );        yDir /= yWeight;        yDir *= g_rcp_bloom_tex_h;    // sample the blur texture for the 4 relevant pixels, weighted accordingly        float4 b = ((1.0f - xWeight) * (1.0f - yWeight))    * tex2D( bloom, t );                b +=       (xWeight * (1.0f - yWeight))             * tex2D( bloom, t + float2( xDir, 0.0f ) );        b +=       (yWeight * (1.0f - xWeight))             * tex2D( bloom, t + float2( 0.0f, yDir ) );        b +=       (xWeight * yWeight)                      * tex2D( bloom, t + float2( xDir, yDir ) );                // Compute the actual colour:        float4 final = c + 0.25f * b;                // Reinhard's tone mapping equation (See Eqn#3 from     // "Photographic Tone Reproduction for Digital Images" for more details) is:    //    //      (      (   Lp    ))    // Lp * (1.0f +(---------))    //      (      ((Lm * Lm)))    // -------------------------    //         1.0f + Lp    //    // Lp is the luminance at the given point, this is computed using Eqn#2 from the above paper:    //    //        exposure    //   Lp = -------- * HDRPixelIntensity    //          l.r    //    // The exposure ("key" in the above paper) can be used to adjust the overall "balance" of     // the image. "l.r" is the average luminance across the scene, computed via the luminance    // downsampling process. 'HDRPixelIntensity' is the measured brightness of the current pixel    // being processed.            float Lp = (fExposure / l.r) * max( final.r, max( final.g, final.b ) );        // A slight difference is that we have a bloom component in the final image - this is *added* to the     // final result, therefore potentially increasing the maximum luminance across the whole image.     // For a bright area of the display, this factor should be the integral of the bloom distribution     // multipled by the maximum value. The integral of the gaussian distribution between [-1,+1] should     // be AT MOST 1.0; but the sample code adds a scalar to the front of this, making it a good enough    // approximation to the *real* integral.            float LmSqr = (l.g + fGaussianScalar * l.g) * (l.g + fGaussianScalar * l.g);        // Compute Eqn#3:        float toneScalar = ( Lp * ( 1.0f + ( Lp / ( LmSqr ) ) ) ) / ( 1.0f + Lp );        // Tonemap the final outputted pixel:        c = final * toneScalar;        // Return the fully composed colour        c.a = 1.0f;        return c;}
着色器完成了从纹理取值,并且根据公式计算像素颜色的工作。
DrawHDRTextureToScreen()完成的工作跟以前的同类函数类似,就是将纹理渲染到屏幕上。

到此为止,HDR渲染就差不多了。