开发者

How do i: convert surface to a texture or create a texture with certain multisampling parameters or render a surface with an alpha layer

I am creating two render targets, both must share the back buffer's depth buffer, so it is important that I set them to have the same multi sampling parameters, however pDevice->CreateTexture(..) does not give any param开发者_StackOverflow社区eters for setting the multi sampling types. So I created two render target surfaces using pDevice->CreateRenderTarget(...) giving the same values as the depth buffer, now the depth buffer works in conjunction with my render targets, however I am unable to render them over the screen properly because alpha blending does not work with ->StretchRect (or so I have been told, and it did not work when I tried).

So the title of this question is basically my questions, how do i: - convert a surface to a texture or - create a texture with certain multisampling parameters or - render a surface properly with an alpha layer


The documentation for StretchRect specifically explains how to do this:

Using StretchRect to downsample a Multisample Rendertarget

You can use StretchRect to copy from one rendertarget to another. If the source rendertarget is multisampled, this results in downsampling the source rendertarget. For instance you could:

  • Create a multisampled rendertarget.
  • Create a second rendertarget of the same size, that is not multisampled.
  • Copy (using StretchRect the multisample rendertarget to the second rendertarget.

Note that use of the extra surface involved in using StretchRect to downsample a Multisample Rendertarget will result in a performance hit.


So new response to an old question, but I came across this and thought I'd supply an answer in case someone else comes across it while running into this problem. Here is the solution with a stripped down version of my wrappers and functions for it.

I have a game in which the renderer has several layers, one of which is a geometry layer. When rendering, it iterates over all layers, calling their Draw functions. Each layer has its own instance of my RenderTarget wrapper. When the layer Draws, it "activates" its render target, clears the buffer to alpha, draws the scene, then "deactivates" its render target. After all layers have drawn to their render targets, all of those render targets are then combined onto the backbuffer to produce the final image.

GeometryLayer::Draw
* Activates the render target used by this layer
* Sets needed render states
* Clears the buffer
* Draws geometry
* Deactivates the render target used by this layer

void GeometryLayer::Draw( const math::mat4& viewProjection )
{
    m_pRenderTarget->Activate();

    pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE,TRUE);
    pDevice->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_SRCALPHA);
    pDevice->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA);

    pDevice->Clear(0,0,D3DCLEAR_TARGET,m_clearColor,1.0,0);
    pDevice->BeginScene();
    pDevice->Clear(0,0,D3DCLEAR_ZBUFFER,0,1.0,0);

    for(auto it = m->visibleGeometry.begin(); it != m->visibleGeometry.end(); ++it)
        it->second->Draw(viewProjection);

    pDevice->EndScene();

    m_pRenderTarget->Deactivate();
}

My RenderTarget wrapper contains an IDirect3DTexture9* (m_pTexture) which is used with D3DXCreateTexture to generate the texture to be drawn to. It also contains an IDirect3DSurface9* (m_pSurface) which is given by the texture. It also contains another IDirect3DSurface9* (m_pMSAASurface).

In the initialization of my RenderTarget, there is an option to enable multisampling. If this option is turned off, the m_pMSAASurface is initialized to nullptr. If this option is turned on, the m_pMSAASurface is created for you using the IDirect3DDevice9::CreateRenderTarget function, specifying my current multisampling settings as the 4th and 5th arguments.

RenderTarget::Init
* Creates a texture
* Gets a surface off the texture (adds to surface's ref count)
* If MSAA, creates msaa-enabled surface

void    RenderTarget::Init(const int width,const int height,const bool enableMSAA)
{
    m_bEnableMSAA = enableMSAA;
    D3DXCreateTexture(pDevice,
        width,
        height,
        1,
        D3DUSAGE_RENDERTARGET,
        D3DFMT_A8R8G8B8,
        D3DPOOL_DEFAULT,
        &m_pTexture;
    );
    m_pTexture->GetSurfaceLevel(0,&m_pSurface);

    if(enableMSAA)
    {
        Renderer::GetInstance()->GetDevice()->CreateRenderTarget(
            width,
            height,
            D3DFMT_A8R8G8B8,
            d3dpp.MultiSampleType,
            d3dpp.MultiSampleQuality,
            false,
            &m_pMSAAsurface,
            NULL
        );
    }
}

If this MSAA setting is off, RenderTarget::Activate sets m_pSurface as the render target. If this MSAA setting is on, RenderTarget::Activate sets m_pMSAASurface as the render target and enables the multisampling render state.

RenderTarget::Activate
* Stores the current render target (adds to that surface's ref count)
* If not MSAA, sets surface as the new render target
* If MSAA, sets msaa surface as the new render target, enables msaa render state

void    RenderTarget::Activate()
{
    pDevice->GetRenderTarget(0,&m_pOldSurface);

    if(!m_bEnableMSAA)
    {
        pDevice->SetRenderTarget(0,m_pSurface);
    }
    else
    {
        pDevice->SetRenderTarget(0,m_pMSAAsurface);
        pDevice->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS,true);
    }
}

If this MSAA setting is off, RenderTarget::Deactivate simply restores the original render target. If this MSAA setting is on, RenderTarget::Deactivate restores the original render target too, but also copies m_pMSAASurface onto m_pSurface.

RenderTarget::Deactivate
* If MSAA, disables MSAA render state
* Restores the previous render target
* Drops ref counts on the previous render target

void    RenderTarget::Deactivate()
{
    if(m_bEnableMSAA)
    {
        pDevice->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS,false);
        pDevice->StretchRect(m_pMSAAsurface,NULL,m_pSurface,NULL,D3DTEXF_NONE);
    }
    pDevice->SetRenderTarget(0,m_pOldSurface);

    m_pOldSurface->Release();
    m->pOldSurface = nullptr;
}

When the Renderer later asks the geometry layer for its RenderTarget texture in order to combine it with the other layers, that texture has the image copied from m_pMSAASurface on it. Assuming you're using a format that facilitates an alpha channel, this texture can be be blended with others, as I'm doing with the render targets of several layers.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜