简体   繁体   中英

How to Render To Texture in DirectX12 & C++? What is the process?

I have been trying to figure out how to render the entire scene to a texture in DX12. I know how to do this in OpenGL, but I'm having trouble figuring it out in DirectX12. Plus, there isn't many resources online on how its done.

(Currently we have a 3D Model rendering in the scene with a texture applied)

Would anyone be able to point me towards some resources that I can use to learn Render Targets and Rendering to a Texture in DX12? or any good websites?

Any help is much appreciated.

Kind regards, Charlie

OpenGL is more like Direct3D 11, where Direct3D 12 and Vulkan are more alike in terms of design/usage and level of graphics knowledge needed to use them effectively. As such, you may find it easier to start with Direct3D 11 before jumping into Direct3D 12 rendering. The concepts and HLSL programming are all very similar between 11 & 12, so it can be a good place to start.

The biggest thing to know about DirectX 12 is that it makes the application (ie the programmer) responsible for many aspects that were handled by the Direct3D 11 Runtime: CPU/GPU synchronization, memory management, resource scheduling, etc. DirectX 12 is intended to give the experienced graphics programmer more control and therefore able to achieve higher-levels of CPU-side performance for the same complexity of rendering. This additional control and responsibility, however, can be overwhelming for someone new to graphics or DirectX. It's much easier in DX12 to write something that 'works on my machine', but won't run or even crashes on other people's machines.

With all that said , some good resources for starting with Direct3D 12:

  • There is a new 'landing page' for DirectX here with many useful links and resources for DirectX 12 development: https://devblogs.microsoft.com/directx/landing-page/

  • Official DirectX 12 samples written by the DirectX graphics team are at DirectX-Graphics-Samples .

  • Public samples written by the Xbox Advanced Technology Group are at Xbox-ATG-Samples . In particular, see the IntroGraphics samples which offer many basic samples in both DX11 & DX12 form.

  • The DirectX Tool Kit is an open-source C++ library that provides helpers for getting going with Direct3D development. There are both DirectX 11 and DirectX 12 versions. If you learn the DX 11 version first, it's pretty simple to move over to DX 12 from there as it handles a number of the 'house-keeping' tasks for you as you learn the new API.

As for the question of 'rendering-to-texture' in DirectX 12 , there are some specific samples to look at:

The second one uses this this helper class h / cpp .

    class RenderTexture
    {
    public:
        RenderTexture(DXGI_FORMAT format) noexcept;

        void SetDevice(_In_ ID3D12Device* device, D3D12_CPU_DESCRIPTOR_HANDLE srvDescriptor, D3D12_CPU_DESCRIPTOR_HANDLE rtvDescriptor);

        void SizeResources(size_t width, size_t height);

        void ReleaseDevice() noexcept;

        void TransitionTo(_In_ ID3D12GraphicsCommandList* commandList, D3D12_RESOURCE_STATES afterState);

        void BeginScene(_In_ ID3D12GraphicsCommandList* commandList)
        {
            TransitionTo(commandList, D3D12_RESOURCE_STATE_RENDER_TARGET);
        }

        void EndScene(_In_ ID3D12GraphicsCommandList* commandList)
        {
            TransitionTo(commandList, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
        }

        void SetClearColor(DirectX::FXMVECTOR color)
        {
            DirectX::XMStoreFloat4(reinterpret_cast<DirectX::XMFLOAT4*>(m_clearColor), color);
        }

        ID3D12Resource* GetResource() const noexcept { return m_resource.Get(); }
        D3D12_RESOURCE_STATES GetCurrentState() const noexcept { return m_state; }

        void SetWindow(const RECT& rect);

        DXGI_FORMAT GetFormat() const noexcept { return m_format; }

    private:
        Microsoft::WRL::ComPtr<ID3D12Device>                m_device;
        Microsoft::WRL::ComPtr<ID3D12Resource>              m_resource;
        D3D12_RESOURCE_STATES                               m_state;
        D3D12_CPU_DESCRIPTOR_HANDLE                         m_srvDescriptor;
        D3D12_CPU_DESCRIPTOR_HANDLE                         m_rtvDescriptor;
        float                                               m_clearColor[4];

        DXGI_FORMAT                                         m_format;

        size_t                                              m_width;
        size_t                                              m_height;
    };
RenderTexture::RenderTexture(DXGI_FORMAT format) noexcept :
    m_state(D3D12_RESOURCE_STATE_COMMON),
    m_srvDescriptor{},
    m_rtvDescriptor{},
    m_clearColor{},
    m_format(format),
    m_width(0),
    m_height(0)
{
}

void RenderTexture::SetDevice(_In_ ID3D12Device* device, D3D12_CPU_DESCRIPTOR_HANDLE srvDescriptor, D3D12_CPU_DESCRIPTOR_HANDLE rtvDescriptor)
{
    if (device == m_device.Get()
        && srvDescriptor.ptr == m_srvDescriptor.ptr
        && rtvDescriptor.ptr == m_rtvDescriptor.ptr)
        return;

    if (m_device)
    {
        ReleaseDevice();
    }

    {
        D3D12_FEATURE_DATA_FORMAT_SUPPORT formatSupport = { m_format, D3D12_FORMAT_SUPPORT1_NONE, D3D12_FORMAT_SUPPORT2_NONE };
        if (FAILED(device->CheckFeatureSupport(D3D12_FEATURE_FORMAT_SUPPORT, &formatSupport, sizeof(formatSupport))))
        {
            throw std::runtime_error("CheckFeatureSupport");
        }

        UINT required = D3D12_FORMAT_SUPPORT1_TEXTURE2D | D3D12_FORMAT_SUPPORT1_RENDER_TARGET;
        if ((formatSupport.Support1 & required) != required)
        {
#ifdef _DEBUG
            char buff[128] = {};
            sprintf_s(buff, "RenderTexture: Device does not support the requested format (%u)!\n", m_format);
            OutputDebugStringA(buff);
#endif
            throw std::runtime_error("RenderTexture");
        }
    }

    if (!srvDescriptor.ptr || !rtvDescriptor.ptr)
    {
        throw std::runtime_error("Invalid descriptors");
    }

    m_device = device;

    m_srvDescriptor = srvDescriptor;
    m_rtvDescriptor = rtvDescriptor;
}

void RenderTexture::SizeResources(size_t width, size_t height)
{
    if (width == m_width && height == m_height)
        return;

    if (m_width > UINT32_MAX || m_height > UINT32_MAX)
    {
        throw std::out_of_range("Invalid width/height");
    }

    if (!m_device)
        return;

    m_width = m_height = 0;

    auto heapProperties = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT);

    D3D12_RESOURCE_DESC desc = CD3DX12_RESOURCE_DESC::Tex2D(m_format,
        static_cast<UINT64>(width),
        static_cast<UINT>(height),
        1, 1, 1, 0, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET);

    D3D12_CLEAR_VALUE clearValue = { m_format, {} };
    memcpy(clearValue.Color, m_clearColor, sizeof(clearValue.Color));

    m_state = D3D12_RESOURCE_STATE_RENDER_TARGET;

    // Create a render target
    ThrowIfFailed(
        m_device->CreateCommittedResource(&heapProperties, D3D12_HEAP_FLAG_ALLOW_ALL_BUFFERS_AND_TEXTURES,
            &desc,
            m_state, &clearValue,
            IID_GRAPHICS_PPV_ARGS(m_resource.ReleaseAndGetAddressOf()))
    );

    SetDebugObjectName(m_resource.Get(), L"RenderTexture RT");

    // Create RTV.
    m_device->CreateRenderTargetView(m_resource.Get(), nullptr, m_rtvDescriptor);

    // Create SRV.
    m_device->CreateShaderResourceView(m_resource.Get(), nullptr, m_srvDescriptor);

    m_width = width;
    m_height = height;
}

void RenderTexture::ReleaseDevice() noexcept
{
    m_resource.Reset();
    m_device.Reset();

    m_state = D3D12_RESOURCE_STATE_COMMON;
    m_width = m_height = 0;

    m_srvDescriptor.ptr = m_rtvDescriptor.ptr = 0;
}

void RenderTexture::TransitionTo(_In_ ID3D12GraphicsCommandList* commandList, D3D12_RESOURCE_STATES afterState)
{
    TransitionResource(commandList, m_resource.Get(), m_state, afterState);
    m_state = afterState;
}

void RenderTexture::SetWindow(const RECT& output)
{
    // Determine the render target size in pixels.
    auto width = size_t(std::max<LONG>(output.right - output.left, 1));
    auto height = size_t(std::max<LONG>(output.bottom - output.top, 1));

    SizeResources(width, height);
}

You'd use it like this:

// Setup
m_scene = std::make_unique<DX::RenderTexture>( /* format that matches your resource and your Pipeline State Objects you will use to render */ );
m_scene->SetClearColor( /* color value you use to clear */ );

m_scene->SetDevice(m_device,
    /* CPU descriptor handle for your scene as a SRV texture */,
    /* CPU descriptor handle for your scene as a RTV texture */);

m_scene->SetWindow( /* provide viewport size for your render texture */ );
// Reset command list and allocator.

// Transition the backbuffer target into the correct state to allow for 

// Clear the render texture
CD3DX12_CPU_DESCRIPTOR_HANDLE rtvDescriptor(
        /* CPU descriptor handle for your scene as a RTV texture */
        static_cast<INT>(m_backBufferIndex), m_rtvDescriptorSize);

CD3DX12_CPU_DESCRIPTOR_HANDLE dsvDescriptor(m_dsvDescriptorHeap->GetCPUDescriptorHandleForHeapStart());

m_commandList->OMSetRenderTargets(1, &rtvDescriptor, FALSE, &dsvDescriptor);
m_commandList->ClearRenderTargetView(rtvDescriptor, /* clear color */, 0, nullptr);
m_commandList->ClearDepthStencilView(dsvDescriptor, D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, nullptr);

// Set the viewport and scissor rect.
D3D12_VIEWPORT viewport = { 0.0f, 0.0f, /* width/height of your render texture */, D3D12_MIN_DEPTH, D3D12_MAX_DEPTH };
D3D12_RECT scissorRect = { 0, 0, /* width/height of your render texture */ };
m_commandList->RSSetViewports(1, &viewport);
m_commandList->RSSetScissorRects(1, &scissorRect);

// Tell helper we are starting the render
m_scene->BeginScene(m_commandList);
    
/* Do rendering to m_commandList */

m_scene->EndScene(m_commandList);

Here we've scheduled the transition to render target resource state, populated all the draw calls, and then inserted a barrier back to the pixel shader resource state. At that point, you can use the descriptor handle to your render-texture's SRV to render. As with all things DirectX 12, nothing happens until you actually close the command-list and submit it for execution.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM