D3D9 Render to Transparent Texture

Viewed 1080

I am attempting to do a Render to Texture such that the surface rendered to is transparent.

This is so I can later use that texture to overlay a 2D scene with 3D objects (obviously, if not transparent, can't see what's underneath).

The following works properly for Render to Texture, however, the image saved is fully opaque (I assume this to be that RenderTargets don't support Transparency) and since it's saved fully opaque, I have to imagine that's how it would appear on geometry rendered at a later time.

HRESULT Camera::RenderToTexture(Node* pScene)
{
    Wnd* pDisplay = pScene->GetDisplay();

    if (!pDisplay->m_pDevice)
        return E__NODEVICE;

    IDirect3DDevice9* pDevice = pDisplay->m_pDevice;

    HRESULT hr = S_OK;

    // original
    IDirect3DSurface9* renderTarget = NULL;
    IDirect3DSurface9* depthTarget = NULL;

    // new
    IDirect3DSurface9* renderTarget_ = NULL;
    IDirect3DSurface9* depthTarget_ = NULL;

    // render target
    hr = pDevice->GetRenderTarget(0, &renderTarget);    // currently set render target for restoration
    if (D3D_OK == hr)
    {
        D3DSURFACE_DESC desc; renderTarget->GetDesc(&desc);

        // m_fCamWidth = 1080; m_fCamHeight = 1920;
        hr = pDevice->CreateRenderTarget((UINT)m_fCamWidth, (UINT)m_fCamHeight, desc.Format,
                                         desc.MultiSampleType, desc.MultiSampleQuality,
                                         false, &renderTarget_, NULL);
        THROW_IF_FAILED(hr);
    }

    // matching depth target
    hr = pDevice->GetDepthStencilSurface(&depthTarget); // currently set depth target for restoration
    if (D3D_OK == hr)
    {
        D3DSURFACE_DESC desc; depthTarget->GetDesc(&desc);

        // m_fCamWidth = 1080; m_fCamHeight = 1920;
        hr = pDevice->CreateDepthStencilSurface((UINT)m_fCamWidth, (UINT)m_fCamHeight, desc.Format,
                                                desc.MultiSampleType, desc.MultiSampleQuality,
                                                false, &depthTarget_, NULL);
        THROW_IF_FAILED(hr);
    }

    if (renderTarget_) pDevice->SetRenderTarget(0, renderTarget_);
    if (depthTarget_) pDevice->SetDepthStencilSurface(depthTarget_);

    // hierarchy flattening
    THROW_IF_FAILED(pScene->UpdateTransform());
    THROW_IF_FAILED(pDevice->SetTransform(D3DTS_PROJECTION, &m_matProjection));
    THROW_IF_FAILED(pDevice->SetTransform(D3DTS_VIEW, &m_matView));

    THROW_IF_FAILED(pDevice->BeginScene());
    THROW_IF_FAILED(pDevice->Clear(NULL, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL, D3DCOLOR_ARGB(0, 128, 128, 128), 1.0f, 0));

    // hierarchy rendering
    pScene->Render();

    pDevice->SetRenderTarget(0, renderTarget);
    pDevice->SetDepthStencilSurface(depthTarget);

    LPDIRECT3DTEXTURE9 textureMap; CreateTexture(textureMap, pDisplay);
    LPDIRECT3DSURFACE9 l_Surface; textureMap->GetSurfaceLevel(0, &l_Surface);
    pDevice->StretchRect(renderTarget_, NULL, l_Surface, NULL, D3DTEXF_NONE);

    D3DXSaveTextureToFile("D:\\output.png", D3DXIMAGE_FILEFORMAT::D3DXIFF_PNG, textureMap, NULL);

    SAFE_RELEASE(renderTarget_);
    SAFE_RELEASE(depthTarget_);

    SAFE_RELEASE(renderTarget);
    SAFE_RELEASE(depthTarget);

    THROW_IF_FAILED(pDevice->EndScene());

    return hr;
}

CreateTexture function:

HRESULT Camera::CreateTexture(LPDIRECT3DTEXTURE9& _pTextureMap, Wnd* _pDisplay)
{
    IDirect3DDevice9* pDevice = _pDisplay->m_pDevice;

    HRESULT hr = S_OK;

    //m_fCamWidth = 1080; m_fCamHeight = 1920;
    hr = D3DXCreateTexture(pDevice,
                           (UINT)m_fCamWidth, (UINT)m_fCamHeight,
                           D3DX_DEFAULT,
                           D3DUSAGE_RENDERTARGET,
                           D3DFMT_A8R8G8B8,
                           D3DPOOL_DEFAULT,
                           &_pTextureMap);
    //Note: If you want the alpha channel then use D3DFMT_A8R8G8B8 format.

    return hr;
}

Current Render States:

D3DRS_AMBIENT, RGB(255, 255, 255)
0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2
0, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_PASSTHRU
1, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2
1, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_PASSTHRU

Unfortunately, I have to do this without the assist of shaders.

While technically I could save the image every frame and load it with a color key, this isn't a grand solution to me.

Current Output (from source code) Current Output

Corrected Output (edited via Paint.net) Corrected Output

edit: Added the following, to no avail:

pDevice->SetRenderState(D3DRENDERSTATETYPE::D3DRS_ALPHABLENDENABLE, TRUE);

pDevice->SetRenderState(D3DRENDERSTATETYPE::D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
pDevice->SetRenderState(D3DRENDERSTATETYPE::D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);

I've verified the Formats of my RenderTarget & Texture; both are D3DFMT_A8R8G8B8

edit 2:

Realizing I had a couple redundancies, I reduced some of what I was doing to make it a little less complex. However, I seem to be unable to clear my RenderTarget to transparent.

HRESULT Camera::RenderToTexture(Node* pScene)
{
    Wnd* pDisplay = pScene->GetDisplay();

    if (!pDisplay->m_pDevice)
        return E__NODEVICE;

    IDirect3DDevice9* pDevice = pDisplay->m_pDevice;

    HRESULT hr = S_OK;

    // original
    IDirect3DSurface9* renderTarget = NULL;
    IDirect3DSurface9* depthTarget = NULL;

    // new
    LPDIRECT3DTEXTURE9 textureMap = NULL;
    IDirect3DSurface9* depthTarget_ = NULL;

    // render target
    hr = pDevice->GetRenderTarget(0, &renderTarget);    // currently set render target for restoration
    if (D3D_OK == hr)
    {
        CreateTexture(textureMap, pDisplay);
        LPDIRECT3DSURFACE9 l_Surface; textureMap->GetSurfaceLevel(0, &l_Surface);

        THROW_IF_FAILED(hr);
        pDevice->SetRenderTarget(0, l_Surface);
    }

    // matching depth target
    hr = pDevice->GetDepthStencilSurface(&depthTarget); // currently set depth target for restoration
    if (D3D_OK == hr)
    {
        D3DSURFACE_DESC desc; depthTarget->GetDesc(&desc);

        hr = pDevice->CreateDepthStencilSurface((UINT)m_fCamWidth, (UINT)m_fCamHeight, desc.Format,
                                                desc.MultiSampleType, desc.MultiSampleQuality,
                                                false, &depthTarget_, NULL);
        THROW_IF_FAILED(hr);
        pDevice->SetDepthStencilSurface(depthTarget_);
    }

    THROW_IF_FAILED(pScene->UpdateTransform());
    THROW_IF_FAILED(pDevice->SetTransform(D3DTS_PROJECTION, &m_matProjection));
    THROW_IF_FAILED(pDevice->SetTransform(D3DTS_VIEW, &m_matView));

    THROW_IF_FAILED(pDevice->BeginScene());
    THROW_IF_FAILED(pDevice->Clear(NULL, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL, D3DCOLOR_RGBA(128, 12, 1, 0), 1.0f, 0));

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

    pScene->Render();

    pDevice->SetRenderTarget(0, renderTarget);
    pDevice->SetDepthStencilSurface(depthTarget);

    D3DXSaveTextureToFile("D:\\output.png", D3DXIMAGE_FILEFORMAT::D3DXIFF_PNG, textureMap, NULL);

    SAFE_RELEASE(depthTarget_);

    SAFE_RELEASE(renderTarget);
    SAFE_RELEASE(depthTarget);

    THROW_IF_FAILED(pDevice->EndScene());

    return hr;
}
0 Answers
Related