DirectX9 SDK Samples(20) HDRDemo Sample(1)

HDR,这里有一篇写得不错的:http://www.zwqxin.com/archives/shaderglsl/review-high-dynamic-range.html

原理可以参考上面的博文~那就进入代码。

首先我们看看Luminance部分,也就是计算平均亮度的部分。

LPDIRECT3DPIXELSHADER9 g_pLumDispPS = NULL;             // PShader used to display the debug panel

LPDIRECT3DPIXELSHADER9 g_pLum1PS = NULL;             // PShader that does a 2x2 downsample and convert to greyscale
LPD3DXCONSTANTTABLE g_pLum1PSConsts = NULL;             // Interface to set the sampling points for the above PS

LPDIRECT3DPIXELSHADER9 g_pLum3x3DSPS = NULL;             // The PS that does each 3x3 downsample operation
LPD3DXCONSTANTTABLE g_pLum3x3DSPSConsts = NULL;             // Interface for the above PS

static const DWORD g_dwLumTextures = 6;                // How many luminance textures we're creating
// Be careful when changing this value, higher than 6 might
// require you to implement code that creates an additional
// depth-stencil buffer due to the luminance textures dimensions
// being greater than that of the default depth-stencil buffer.
LPDIRECT3DTEXTURE9 g_pTexLuminance[ g_dwLumTextures ];         // An array of the downsampled luminance textures
D3DFORMAT g_fmtHDR = D3DFMT_UNKNOWN;   // Should be either G32R32F or G16R16F depending on the hardware
上面的是用到的比较重要的变量。

下面将逐个对函数代码进行阅读。

//--------------------------------------------------------------------------------------
//  CreateResources( )
//
//      DESC:
//          This function creates the necessary texture chain for downsampling the
//          initial HDR texture to a 1x1 luminance texture.
函数描述。

    //[ 2 ] CREATE HDR RENDER TARGETS
    //-------------------------------
    int iTextureSize = 1;
    for( int i = 0; i < Luminance::g_dwLumTextures; i++ )
    {

        // Create this element in the array
        V( pDevice->CreateTexture( iTextureSize, iTextureSize, 1,
                                   D3DUSAGE_RENDERTARGET, Luminance::g_fmtHDR,
                                   D3DPOOL_DEFAULT, &Luminance::g_pTexLuminance[i], NULL ) );
        // Increment for the next texture
        iTextureSize *= 3;

    }
创建计算平均亮度所需要的纹理。

    V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"Shader Code\\Luminance.psh" ) );
    V( D3DXCompileShaderFromFile(str, NULL, NULL, "LuminanceDisplay", "ps_2_0", 0, &pCode, NULL, NULL ) );
编译亮度展示着色器。
    V( pDevice->CreatePixelShader( reinterpret_cast< DWORD* >( pCode->GetBufferPointer() ),
                                   &Luminance::g_pLumDispPS ) );
。。。。。接下来照葫芦画瓢,创建两个减取样着色器,一个用作转换为灰阶,一个计算平均值来进行减采样。这个函数就完成任务了。


下一个函数~

//--------------------------------------------------------------------------------------
//  MeasureLuminance( )
//
//      DESC:
//          This is the core function for this particular part of the application, it's
//          job is to take the previously rendered (in the 'HDRScene' namespace) HDR
//          image and compute the overall luminance for the scene. This is done by
//          repeatedly downsampling the image until it is only 1x1 in size. Doing it
//          this way (pixel shaders and render targets) keeps as much of the work on
//          the GPU as possible, consequently avoiding any resource transfers, locking
//          and modification.
    HDRScene::GetOutputTexture( &pSourceTex );
    pDestTex = Luminance::g_pTexLuminance[ Luminance::g_dwLumTextures - 1 ];

    pDevice->SetRenderTarget( 0, pDestSurf );
    pDevice->SetTexture( 0, pSourceTex );

    pDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );
    pDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );
首先得到整个场景作为源纹理,并得到最后一个亮度纹理作为输出。

    //[ 2 ] RENDER AND DOWNSAMPLE THE HDR TEXTURE
    //      TO THE LUMINANCE MAP.
    //-------------------------------------------
    // Set which shader we're going to use. g_pLum1PS corresponds
    // to the 'GreyScaleDownSample' entry point in 'Luminance.psh'.
    pDevice->SetPixelShader( Luminance::g_pLum1PS );

    // We need to compute the sampling offsets used for this pass.
    // A 2x2 sampling pattern is used, so we need to generate 4 offsets.
    D3DXVECTOR4 offsets[4];

    // Find the dimensions for the source data
    D3DSURFACE_DESC srcDesc;
    pSourceTex->GetLevelDesc( 0, &srcDesc );

    // Because the source and destination are NOT the same sizes, we
    // need to provide offsets to correctly map between them.
    float sU = ( 1.0f / static_cast< float >( srcDesc.Width ) );
    float sV = ( 1.0f / static_cast< float >( srcDesc.Height ) );

    // The last two components (z,w) are unused. This makes for simpler code, but if
    // constant-storage is limited then it is possible to pack 4 offsets into 2 float4's
    offsets[0] = D3DXVECTOR4( -0.5f * sU, 0.5f * sV, 0.0f, 0.0f );
//省略其他offset设置
    // Set the offsets to the constant table
    Luminance::g_pLum1PSConsts->SetVectorArray( pDevice, "tcLumOffsets", offsets, 4 );

    // With everything configured we can now render the first, initial, pass
    // to the luminance textures.
    RenderToTexture( pDevice );
这一个过程每计算一次平均亮度只需要进行一次,因为转换为灰阶只需要进行一次。下面先看看RenderToTexture再回来继续下面的亮度计算。

//--------------------------------------------------------------------------------------
//  RenderToTexture( )
//
//      DESC:
//          A simple utility function that draws, as a TL Quad, one texture to another
//          such that a pixel shader (configured before this function is called) can
//          operate on the texture. Used by MeasureLuminance() to perform the
//          downsampling and filtering.
    // To correctly map from texels->pixels we offset the coordinates
    // by -0.5f:
    float fWidth = static_cast< float >( desc.Width ) - 0.5f;
    float fHeight = static_cast< float >( desc.Height ) - 0.5f;

    // Now we can actually assemble the screen-space geometry
    Luminance::TLVertex v[4];

    v[0].p = D3DXVECTOR4( -0.5f, -0.5f, 0.0f, 1.0f );
    v[0].t = D3DXVECTOR2( 0.0f, 0.0f );

    v[1].p = D3DXVECTOR4( fWidth, -0.5f, 0.0f, 1.0f );
    v[1].t = D3DXVECTOR2( 1.0f, 0.0f );

    v[2].p = D3DXVECTOR4( -0.5f, fHeight, 0.0f, 1.0f );
    v[2].t = D3DXVECTOR2( 0.0f, 1.0f );

    v[3].p = D3DXVECTOR4( fWidth, fHeight, 0.0f, 1.0f );
    v[3].t = D3DXVECTOR2( 1.0f, 1.0f );

    // Configure the device and render..
    pDev->SetVertexShader( NULL );
    pDev->SetFVF( Luminance::FVF_TLVERTEX );
    pDev->DrawPrimitiveUP( D3DPT_TRIANGLESTRIP, 2, v, sizeof( Luminance::TLVertex ) );
渲染代码挺简单,注意texel和pixel之间的坐标转换就好了。下面回到MeasureLuminance。
    //[ 3 ] SCALE EACH RENDER TARGET DOWN
    //      The results ("dest") of each pass feeds into the next ("src")
    //-------------------------------------------------------------------
    for( int i = ( Luminance::g_dwLumTextures - 1 ); i > 0; i-- )
    {

        // Configure the render targets for this iteration
        pSourceTex = Luminance::g_pTexLuminance[ i ];
        pDestTex = Luminance::g_pTexLuminance[ i - 1 ];
        if( FAILED( pDestTex->GetSurfaceLevel( 0, &pDestSurf ) ) )
        {
//省略
        }

        pDevice->SetRenderTarget( 0, pDestSurf );
        pDevice->SetTexture( 0, pSourceTex );
//省略
        // Because each of these textures is a factor of 3
        // different in dimension, we use a 3x3 set of sampling
        // points to downscale.
        D3DSURFACE_DESC srcTexDesc;
        pSourceTex->GetLevelDesc( 0, &srcTexDesc );

        // Create the 3x3 grid of offsets
        D3DXVECTOR4 DSoffsets[9];
        int idx = 0;
        for( int x = -1; x < 2; x++ )
        {
            for( int y = -1; y < 2; y++ )
            {
                DSoffsets[idx++] = D3DXVECTOR4(
                    static_cast< float >( x ) / static_cast< float >( srcTexDesc.Width ),
                    static_cast< float >( y ) / static_cast< float >( srcTexDesc.Height ),
                    0.0f,   //unused
                    0.0f    //unused
                    );
            }
        }
        // Set them to the current pixel shader
        pDevice->SetPixelShader( Luminance::g_pLum3x3DSPS );
        Luminance::g_pLum3x3DSPSConsts->SetVectorArray( pDevice, "tcDSOffsets", DSoffsets, 9 );

        // Render the display to this texture
        RenderToTexture( pDevice );
//省略
    }
接下来是DisplayLuminance函数

//--------------------------------------------------------------------------------------
//  DisplayLuminance( )
//
//      DESC:
//          This function is for presentation purposes only - and isn't a *required*
//          part of the HDR rendering pipeline. It draws the 6 stages of the luminance
//          calculation to the appropriate part of the screen.
所以我就不说了。。。Next

//--------------------------------------------------------------------------------------
//  GetLuminanceTexture( )
//
//      DESC:
//          The final 1x1 luminance texture created by the MeasureLuminance() function
//          is required as an input into the final image composition. Because of this
//          it is necessary for other parts of the application to have access to this
//          particular texture.
这个函数是输出最后的1X1结果

HRESULT GetLuminanceTexture( IDirect3DTexture9** pTex )
{

    // [ 0 ] ERASE ANY DATA IN THE INPUT
    //----------------------------------
    SAFE_RELEASE( *pTex );

    // [ 1 ] COPY THE PRIVATE REFERENCE
    //---------------------------------
    *pTex = Luminance::g_pTexLuminance[ 0 ];

    // [ 2 ] INCREMENT THE REFERENCE COUNT..
    //--------------------------------------
    ( *pTex )->AddRef();

    return S_OK;

}

这样我们就完成了HDR三部分的其中之一(Tone Mapping,另外还有Bloom和最终的合成)。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值