Direct2d是否可以按监视器大小在窗口上绘制而不管窗口大小如何?

问题描述

我有用Direct2D渲染的DirectX窗口。由于rendertarget已调整大小,因此当窗口调整大小绘制的2D内容时,我的问题是按窗口大小进行缩放。我不想使用等于监视器大小的“儿童窗口”。我应该画在同一扇窗户上。我发现 Hwndrendertarget 不管窗口大小如何变化,都可以帮助渲染2D。我不确定这是否用于此。

我的2D渲染目标:

@H_502_7@    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渲染目标:

@H_502_7@    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);

和:

@H_502_7@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,rendertargetSize.width,rendertargetSize.height),m_whiteBrush
        );
        }
        m_d2dHwndrendertarget->EndDraw();
}

在渲染循环中:

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

    m_Direct2D->TryRenderHWNDText();

}

BeginScene:

@H_502_7@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;
}

结束场景:

@H_502_7@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。我在这里想念什么? 我有什么解决办法吗?

谢谢您的建议

解决方法

这是解决方案:

注意: 此解决方案适用于您具有无边界子窗口且其大小与监视器相同的情况。

您应该修改程序的视口大小和屏幕外观, 只需在D3D11_VIEWPORT处定义即可。然后设置宽度(父窗口宽度),高度(父窗口高度),SCREEN_NEAR(0.1),SCREEN_DEPTH(1000)和screenAspect。

这是结果:

<!-- Window.xaml -->
<StackPanel>
     <ContentControl IsTabStop="False" Content="{Binding UCtrl}"/>
</StackPanel>

<!-- UserControl.xaml -->
<UserControl.Resources>
    <Style x:Key="TabItemStyle" TargetType="{x:Type TreeViewItem}">
        <Setter Property="KeyboardNavigation.TabNavigation" Value="Cycle"/>
     </Style>
</UserControl.Resources>
<StackPanel>
    <TreeView IsTabStop="False" ItemContainerStyle="{StaticResource TabItemStyle}">
        <TreeViewItem IsExpanded="True" HorizontalContentAlignment="Stretch" >
            <TreeViewItem.Header>
                <TextBox TabIndex="1" Width="100"/>
            </TreeViewItem.Header>
        </TreeViewItem>
        <TreeViewItem IsExpanded="True" HorizontalContentAlignment="Stretch" >
            <TreeViewItem.Header>
                <TextBox TabIndex="2" Width="100"/>
            </TreeViewItem.Header>
        </TreeViewItem>
        <TreeViewItem IsExpanded="True" HorizontalContentAlignment="Stretch" >
            <TreeViewItem.Header>
                <TextBox TabIndex="3" Width="100"/>
            </TreeViewItem.Header>
        </TreeViewItem>
    </TreeView>
</StackPanel>

只需调用上面的void即可使其在消息中起作用。为防止消息 WM_SIZING WM_SIZE WM_MOVE 之间发生冲突,请在 Is_WM_SIZING 中添加一个bool并允许 UpdateFrame() 仅当生成 WM_SIZE WM_MOVE 消息时为假。在WM_EXITSIZEMOVE消息中将此值设置为false,并且在调用 UpdateFrame()之后也将其设置为false。这样可以防止某些类型的渲染问题,具体取决于您的present(...)调用。

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

有时,如果您从左,左上,左下和左上的窗口调整大小的速度过快,则会产生严重的伪影,并向右或向右溢出。 Microsoft文档说SetWindowRgn可以防止在其内容之外进行绘制,这使我的程序变得更好。

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,w,h);
            SetWindowRgn(ApplicationHandle->m_hwnd,DXRGN,0);
        }
    }