Direct2d Можно ли рисовать в окне по размеру монитора независимо от размера окна?

У меня есть окно DirectX, которое отображается с помощью Direct2D. Моя проблема, когда размер окна изменен, нарисованный 2D-контент масштабируется по размеру окна, поскольку размер renderTarget изменяется. Я не хочу использовать ДЕТСКОЕ ОКНО, которое равно размеру монитора. Я должен рисовать в том же окне. Я нашел HwndRenderTarget, многие из которых помогают рендерить 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. Что мне здесь не хватает? Есть ли решение для моей цели?

Спасибо за любой совет


person Gomi Odabaşıoğlu    schedule 11.09.2020    source источник
comment
Если у вас уже есть цепочка обмена и цель рендеринга dxgi, зачем вам цель рендеринга hwnd?   -  person Simon Mourier    schedule 11.09.2020
comment
@Simon Mourier Если я изменю размер своего окна, весь 2D-контент тоже будет масштабироваться, я хочу сохранить их масштаб на основе масштаба монитора. Я хочу отображать 2D-контент на основе размера монитора, а не клиентской области. Если это возможно сделать с целью рендеринга dxgi, я хочу знать.   -  person Gomi Odabaşıoğlu    schedule 11.09.2020
comment
Вам нужна только одна цель рендеринга. Просто нарисуйте свой m_d2dRenderTarget, который уже отображен в цепочке обмена.   -  person Simon Mourier    schedule 11.09.2020
comment
Могу ли я использовать m_swapChain-›ResizeBuffers(); - установить размер экрана при изменении размера окна, может быть ???   -  person Gomi Odabaşıoğlu    schedule 11.09.2020
comment
да, вы можете это сделать.   -  person Simon Mourier    schedule 12.09.2020
comment
@GomiOdabaşıoğlu Эта проблема решена?   -  person Rita Han    schedule 15.09.2020
comment
@Rita Han В моем случае это не поддерживает такое изменение размера. (Для DXGI Surface Render Target) Для этого мне нужно освободить D3Device, но это вызовет проблемы с производительностью. Чтобы предотвратить эту проблему, Microsoft docs рекомендует поддерживать 2D-ресурсы во время процесса повторного создания и повторно использовать их. Это решает загадку для меня. Тем не менее, у меня много дел, и это будет последнее, над чем я буду работать.   -  person Gomi Odabaşıoğlu    schedule 15.09.2020
comment
@Rita Han, я думаю, следует установить D3D11_VIEWPORT с помощью GetDeviceContext()->RSSetViewports(1, &viewport); затем установите усеченную камеру для 3D-рисования, поскольку 2D не требуется. Это не нужно будет выпускать.   -  person Gomi Odabaşıoğlu    schedule 15.09.2020


Ответы (1)


Вот решение:

ПРИМЕЧАНИЕ. это решение предназначено для случая, когда у вас есть дочернее окно без полей размером с монитор.

Вы должны изменить размер области просмотра и аспект экрана вашей программы. Просто определите где-нибудь D3D11_VIEWPORT. Затем установите ширину (ширину родительского окна), высоту (высоту родительского окна), SCREEN_NEAR (0,1), SCREEN_DEPTH (1000) и screenAspect.

Вот результат:

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);
        }
    }

Просто вызовите пустоту выше, чтобы заставить ее работать в сообщениях. Чтобы предотвратить конфликт между сообщениями WM_SIZING, WM_SIZE и WM_MOVE, установите логическое значение Is_WM_SIZING и разрешите UpdateFrame() только в том случае, если это значение ложно при создании сообщений WM_SIZE и WM_MOVE. Установите для этого значения в сообщении WM_EXITSIZEMOVE значение false, а также после вызова UpdateFrame(). Это предотвратит некоторые проблемы с рендерингом в зависимости от вашего текущего (...) вызова.

Дополнительная операция: https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowrgn

Иногда, если вы слишком быстро изменяете размер окна слева, сверху слева, снизу слева и сверху, это приводит к серьезным артефактам и перетеканию вправо или вниз. Документы Microsoft говорят, что SetWindowRgn предотвращает рисование за пределами своего содержимого, что сделало мою программу лучше.

HRGN hrgn; //DEFINE SOMEWHERE OUTSIDE
/*----*/
hrgn = CreateRectRgn(0,0,windowWidth,windowHeight);
SetWindowRgn(ApplicationHandle->m_hwnd, hrgn,0); //last parameter should be 0
person Gomi Odabaşıoğlu    schedule 18.09.2020