Direct2d 是否可以在 window 上按监视器大小绘制而不考虑 window 大小?

Direct2d Is that possible to draw on window by monitor size regardless of window size?

我有使用 Direct2D 呈现的 directx window。当 window 调整绘制的 2D 内容的大小时,我的问题是按 window 大小缩放,因为 renderTarget 已调整大小。我不想使用等于显示器大小的 CHILD WINDOW。我应该借鉴相同的 window。我发现 HwndRenderTarget 无论 window 大小如何变化,它都有助于渲染 2D。我不确定那是否用于此目的。

我的 2D 渲染目标:

    D2D1_FACTORY_OPTIONS options2d;
options2d.debugLevel = D2D1_DEBUG_LEVEL_NONE;
result = D2D1CreateFactory(D2D1_FACTORY_TYPE::D2D1_FACTORY_TYPE_MULTI_THREADED, options2d, &m_factory2d);

m_screenSize.x = screenWidth; m_screenSize.y = screenHeight;

if (FAILED(result))
{
    return false;
}

// set up the D2D render target using the back buffer

m_swapChain->GetBuffer(0, IID_PPV_ARGS(&m_dxgiBackbuffer));

D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT, D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED));

m_factory2d->CreateDxgiSurfaceRenderTarget(m_dxgiBackbuffer, props, &m_d2dRenderTarget);

HWND 渲染目标:

    RECT rc;
GetClientRect(hwnd, &rc);

D2D1_SIZE_U size = D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top);

D2D1_RENDER_TARGET_PROPERTIES RTprops = D2D1::RenderTargetProperties();
D2D1_HWND_RENDER_TARGET_PROPERTIES RT_hWndProps = D2D1::HwndRenderTargetProperties(hwnd, size,D2D1_PRESENT_OPTIONS::D2D1_PRESENT_OPTIONS_IMMEDIATELY);
result = m_factory2d->CreateHwndRenderTarget(RTprops, RT_hWndProps, &m_d2dHwndRenderTarget);

和:

void D2DClass::TryRenderHWNDText() {
        static const WCHAR sc_helloWorld[] = L"Hello, World!";

        // Retrieve the size of the render target.
        D2D1_SIZE_F renderTargetSize = m_d2dHwndRenderTarget->GetSize();

        m_d2dHwndRenderTarget->BeginDraw();
        m_d2dHwndRenderTarget->Clear(ColorF(ColorF::Red));

        m_d2dHwndRenderTarget->SetTransform(D2D1::Matrix3x2F::Identity());
        m_whiteBrush->SetColor(ColorF(ColorF::Orange));
        if(textFormat){
        m_d2dHwndRenderTarget->DrawTextW(
            sc_helloWorld,
            ARRAYSIZE(sc_helloWorld) - 1,
            textFormat,
            D2D1::RectF(0, 0, renderTargetSize.width, renderTargetSize.height),
            m_whiteBrush
        );
        }
        m_d2dHwndRenderTarget->EndDraw();
}

在渲染循环中:

bool GraphicsClass::Render()
{
    m_Direct3D->BeginScene(0.0f, 0.0f, 0.0f, 1.0f);
    /*RENDER 2D renderTarget NOT hwndTarget and 3D target*/
    m_Direct3D->EndScene();

    m_Direct2D->TryRenderHWNDText();

}

开始场景:

void D3DClass::BeginScene(float red, float green, float blue, float alpha)
{
    float color[4];


    // Setup the color to clear the buffer to.
    color[0] = red;
    color[1] = green;
    color[2] = blue;
    color[3] = alpha;

    // Clear the back buffer.

    m_deviceContext->ClearRenderTargetView(m_renderTargetView, color);

    // Clear the depth buffer.
    m_deviceContext->ClearDepthStencilView(m_depthStencilView, D3D11_CLEAR_DEPTH, 1.0f, 0);

    return;
}

场景结束:

void D3DClass::EndScene()
{
    // Present the back buffer to the screen since rendering is complete.
    if (m_vsync_enabled)
    {
        // Lock to screen refresh rate.
        m_swapChain->Present(1, 0);
    }
    else
    {
        // Present as fast as possible.
        m_swapChain->Present(0, 0);
    }

    return;
}

我看到 2D 和 3D 但没有 HWNDrenderTarget。我在这里错过了什么? 有没有适合我的解决方案?

感谢任何建议

解决方法如下:

注意: 此解决方案适用于无边框 child window 且具有显示器大小的情况。

您应该修改程序的视口大小和屏幕外观, 只需在某处定义 D3D11_VIEWPORT。然后设置 width(Parent window width),height(Parent window height),SCREEN_NEAR(0.1),SCREEN_DEPTH(1000) 和屏幕纵横比。

这是结果:

void SystemClass::UpdateFrame() {

    if (ApplicationHandle->m_Graphics) {

            GetClientRect(ApplicationHandle->m_hwndOWNER, &clientRect);
            int w = ApplicationHandle->ClientSize.x = RECTWIDTH(clientRect);
            int h = ApplicationHandle->ClientSize.y = RECTHEIGHT(clientRect);
    
            ApplicationHandle->m_Graphics->clientSize = { w, h };
    
    
            viewport.Width = RECTWIDTH(clientRect);
            viewport.Height = RECTHEIGHT(clientRect);
    
            ApplicationHandle->m_Graphics->m_Direct3D->GetDeviceContext()->RSSetViewports(1, &viewport);
    
            float fieldOfView = 3.141592654f / 4.0f;
            float screenAspect = (float)RECTWIDTH(clientRect) / (float)RECTHEIGHT(clientRect);
    
            ApplicationHandle->m_Graphics->m_Direct3D->m_projectionMatrix = XMMatrixPerspectiveFovLH(fieldOfView, screenAspect, SCREEN_NEAR, SCREEN_DEPTH);
    
            ApplicationHandle->m_Graphics->Frame();
            DXRGN = CreateRectRgn(0, 0, w, h);
            SetWindowRgn(ApplicationHandle->m_hwnd, DXRGN, 0);
        }
    }

只需调用上面的 void 即可使其在消息中起作用。防止消息WM_SIZINGWM_SIZEWM_MOVE[=38之间发生冲突=] 放一个 bool Is_WM_SIZING 并允许 UpdateFrame() 只有当 [=53 时这是假的=]WM_MOVE 消息生成。将 WM_EXITSIZEMOVE 消息中的此值设置为 false,并在调用 UpdateFrame() 后也将此值设置为 false。这将根据您的 present(...) 调用防止某种类型的渲染问题。

附加操作: https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowrgn

有时,如果您从左侧调整 window 的大小太快,top-left、bottom-left 和顶部会产生严重的伪像并溢出到右侧或底部。 Microsoft 文档说 SetWindowRgn 会阻止在其内容之外绘制,这让我的程序变得更好。

HRGN hrgn; //DEFINE SOMEWHERE OUTSIDE
/*----*/
hrgn = CreateRectRgn(0,0,windowWidth,windowHeight);
SetWindowRgn(ApplicationHandle->m_hwnd, hrgn,0); //last parameter should be 0