如何在 DirectX12 和 C++ 中渲染到纹理?流程是什么?

问题描述

我一直在尝试弄清楚如何在 DX12 中将整个场景渲染为纹理。我知道如何在 OpenGL 中执行此操作,但在 DirectX12 中无法解决此问题。另外,网上关于它是如何完成的资源并不多。

(目前我们在场景中有一个应用了纹理的 3D 模型渲染)

有人能指点我一些资源,我可以使用这些资源在 DX12 中学习渲染目标和渲染到纹理吗?或者有什么好的网站?

非常感谢任何帮助。

亲切的问候, 查理

解决方法

OpenGL 更像 Direct3D 11,而 Direct3D 12 和 Vulkan 在设计/使用和有效使用它们所需的图形知识水平方面更相似。因此,您可能会发现在进入 Direct3D 12 渲染之前更容易从 Direct3D 11 开始。 11 和 12 之间的概念和 HLSL 编程都非常相似,因此可以从这里开始。

关于 DirectX 12 最重要的一点是它让应用程序(即程序员)负责 Direct3D 11 运行时处理的许多方面:CPU/GPU 同步、内存管理、资源调度等。 DirectX 12旨在为有经验的图形程序员提供更多控制权,从而能够在渲染复杂度相同的情况下实现更高级别的 CPU 端性能。然而,这种额外的控制和责任对于图形或 DirectX 的新手来说可能是压倒性的。在 DX12 中编写“在我的机器上运行”的东西要容易得多,但在其他人的机器上不会运行甚至崩溃。

综上所述,一些从 Direct3D 12 开始的好资源:

  • 这里有一个 DirectX 的新“登陆页面”,其中包含许多用于 DirectX 12 开发的有用链接和资源:https://devblogs.microsoft.com/directx/landing-page/

  • 由 DirectX 图形团队编写的官方 DirectX 12 示例位于 DirectX-Graphics-Samples

  • Xbox Advanced Technology Group 编写的公开示例位于 Xbox-ATG-Samples。特别是,请参阅 IntroGraphics 示例,其中提供了许多 DX11 和 DX12 形式的基本示例。

  • DirectX 工具包 是一个开源 C++ 库,为开始 Direct3D 开发提供帮助。有 DirectX 11DirectX 12 版本。如果您先学习 DX 11 版本,那么从那里迁移到 DX 12 非常简单,因为它会在您学习新 API 时为您处理许多“内务管理”任务。

至于 DirectX 12 中“渲染到纹理”的问题,有一些具体示例可以查看:

第二个使用这个辅助类 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 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,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(),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(),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);
}

你会像这样使用它:

// 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 */,nullptr);
m_commandList->ClearDepthStencilView(dsvDescriptor,D3D12_CLEAR_FLAG_DEPTH,1.0f,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,/* 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);

在这里,我们已经安排了渲染目标资源状态的转换,填充了所有的绘制调用,然后将屏障插入回像素着色器资源状态。此时,您可以使用渲染纹理 SRV 的描述符句柄进行渲染。与 DirectX 12 的所有内容一样,在您实际关闭命令列表并将其提交以供执行之前,什么都不会发生。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...