【问题标题】:DirectX11 ClearRenderTargetViewback with transparent buffer?DirectX11 ClearRenderTargetViewback 与透明缓冲区?
【发布时间】:2014-05-04 05:24:15
【问题描述】:

我正在尝试创建一个窗口,该窗口使用 directx 在 透明 视图(即桌面显示)之上绘制 不透明 内容。使用 DirectX11,我正在尝试执行以下操作,但它不会使背景透明。事实上,我输入的任何不透明度值都会给我完全相同的结果。

我在做什么:

float color[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
deviceContext->ClearRenderTargetView(backBuffer, color);

工作重现代码(main.cpp):

#include <Windows.h>
#include <windowsx.h>
#pragma comment (lib, "Winmm.lib")

#include <d3d11.h>
#pragma comment (lib, "d3d11.lib")
#include <d3dcompiler.h>
#pragma comment(lib, "D3DCompiler.lib")

#include <dwmapi.h>
#pragma comment (lib, "Dwmapi.lib")


// Globals
IDXGISwapChain *swapChain;
ID3D11Device *device;
ID3D11DeviceContext *deviceContext;
ID3D11RenderTargetView *backBuffer;
ID3D11InputLayout *inputLayout;            // the pointer to the input layout
ID3D11VertexShader *vertexShader;               // the pointer to the vertex shader
ID3D11PixelShader *pixelShader;                // the pointer to the pixel shader
ID3D11Buffer *vertexBuffer;                // the pointer to the vertex buffer

void InitializeDirectX(HWND hWnd);
void LoadTriangle();

struct Vertex {
    float x, y, z;
    float color[4];
};

// this is the main message handler for the program
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_DESTROY:
    {
                       // close the application entirely
                       PostQuitMessage(0);
                       return 0;
    }
    }
    return DefWindowProc(hWnd, message, wParam, lParam);
}

// Globals
const LPCWSTR ClassName = L"className";


// the entry point for any Windows program
int WINAPI WinMain(HINSTANCE hInstance,
    HINSTANCE hPrevInstance,
    LPSTR lpCmdLine,
    int nCmdShow)
{
    // the handle for the window, filled by a function
    HWND hWnd;
    // this struct holds information for the window class
    WNDCLASSEX wc;

    // Pick out window size
    int windowHeight = 400;
    int windowWidth = 400;

    // clear out the window class for use
    ZeroMemory(&wc, sizeof(WNDCLASSEX));

    // fill in the struct with the needed information
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = WindowProc;
    wc.hInstance = hInstance;
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
    wc.lpszClassName = ClassName;

    // register the window class
    RegisterClassEx(&wc);

    // Window style
    DWORD exStyle = WS_EX_LAYERED | WS_EX_TOPMOST;
    DWORD style = WS_POPUP;

    // create the window and use the result as the handle
    hWnd = CreateWindowEx(
        exStyle,        // extended styles
        ClassName,    // name of the window class
        L"TestOverlay",   // title of the window
        style,    // window style
        0,    // x-position of the window
        0,    // y-position of the window
        400,    // width of the window
        400,    // height of the window
        NULL,    // we have no parent window, NULL
        NULL,    // we aren't using menus, NULL
        hInstance,    // application handle
        NULL);    // used with multiple windows, NULL

    // display the window on the screen
    ShowWindow(hWnd, nCmdShow);

    SetWindowPos(hWnd,
        HWND_TOPMOST,
        0, 0,
        windowWidth, windowHeight,
        SWP_SHOWWINDOW);

    // Show the window
    ShowWindow(hWnd, SW_SHOWDEFAULT);
    UpdateWindow(hWnd);

    // Make the window transparent
    SetWindowLong(hWnd, GWL_EXSTYLE, WS_EX_LAYERED);
    SetLayeredWindowAttributes(hWnd, RGB(0, 0, 0), 255, LWA_ALPHA | LWA_COLORKEY);

    // NOTE: If I uncomment DwmExtendFrameIntoClientArea then it becomes transparent, otherwise its a black screen
    MARGINS dwmMargin = { -1 };
    //DwmExtendFrameIntoClientArea(hWnd, &dwmMargin);

    // DirectX
    InitializeDirectX(hWnd);
    LoadTriangle();

    // enter the main loop:
    MSG msg;
    BOOL gotMessage;
    while (TRUE)
    {
        if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);

            if (msg.message == WM_QUIT)
                break;

            // DirectX stuff
            float color[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
            deviceContext->ClearRenderTargetView(backBuffer, color);

            // Draw triangle
            UINT stride = sizeof(Vertex);
            UINT offset = 0;
            deviceContext->IASetVertexBuffers(0, 1, &vertexBuffer, &stride, &offset);
            deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
            deviceContext->Draw(3, 0);

            swapChain->Present(0, 0);

        }
    }

    return msg.wParam;
}


void InitializeDirectX(HWND hWnd)
{
    // create a struct to hold information about the swap chain
    DXGI_SWAP_CHAIN_DESC scd;

    // clear out the struct for use
    ZeroMemory(&scd, sizeof(DXGI_SWAP_CHAIN_DESC));

    // fill the swap chain description struct
    scd.BufferCount = 1;                                    // one back buffer
    scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;     // use 32-bit color
    scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;      // how swap chain is to be used
    scd.OutputWindow = hWnd;                                // the window to be used
    scd.SampleDesc.Count = 4;                               // how many multisamples
    scd.Windowed = TRUE;                                    // windowed/full-screen mode

    // create a device, device context and swap chain using the information in the scd struct
    D3D11CreateDeviceAndSwapChain(NULL,
        D3D_DRIVER_TYPE_HARDWARE,
        NULL,
        NULL,
        NULL,
        NULL,
        D3D11_SDK_VERSION,
        &scd,
        &swapChain,
        &device,
        NULL,
        &deviceContext);


    // get the address of the back buffer
    ID3D11Texture2D *pBackBuffer;
    swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);

    // use the back buffer address to create the render target
    device->CreateRenderTargetView(pBackBuffer, NULL, &backBuffer);
    pBackBuffer->Release();

    // set the render target as the back buffer
    deviceContext->OMSetRenderTargets(1, &backBuffer, NULL);

    // Set the viewport size
    RECT cRect;
    GetClientRect(hWnd, &cRect);

    D3D11_VIEWPORT viewport;
    ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT));

    viewport.TopLeftX = 0;
    viewport.TopLeftY = 0;
    viewport.Width = cRect.right - cRect.left;
    viewport.Height = cRect.bottom - cRect.top;

    deviceContext->RSSetViewports(1, &viewport);


    // Initialize pipeline stuff
    ID3D10Blob *VS, *PS;

    // compile shader
    D3DCompileFromFile(L"shaders.shader", 0, 0, "VShader", "vs_4_0", 0, 0, &VS, 0);
    D3DCompileFromFile(L"shaders.shader", 0, 0, "PShader", "ps_4_0", 0, 0, &PS, 0);

    // encapsulate both shaders into shader objects
    device->CreateVertexShader(VS->GetBufferPointer(), VS->GetBufferSize(), NULL, &vertexShader);
    device->CreatePixelShader(PS->GetBufferPointer(), PS->GetBufferSize(), NULL, &pixelShader);

    deviceContext->VSSetShader(vertexShader, 0, 0);
    deviceContext->PSSetShader(pixelShader, 0, 0);

    // create input layout object
    D3D11_INPUT_ELEMENT_DESC ied[] =
    {
        { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
        { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
    };

    device->CreateInputLayout(ied, 2, VS->GetBufferPointer(), VS->GetBufferSize(), &inputLayout);
    deviceContext->IASetInputLayout(inputLayout);

}


void LoadTriangle()
{
    // create a triangle using the VERTEX struct
    Vertex OurVertices[] =
    {
    { 0.0f, 0.5f, 0.0f, { 1.0f, 0.0f, 0.0f, 1.0f } },
    { 0.45f, -0.5, 0.0f, { 0.0f, 1.0f, 0.0f, 1.0f } },
    { -0.45f, -0.5f, 0.0f, { 0.0f, 0.0f, 1.0f, 1.0f } }
    };


    // create the vertex buffer
    D3D11_BUFFER_DESC bd;
    ZeroMemory(&bd, sizeof(bd));

    bd.Usage = D3D11_USAGE_DYNAMIC;                // write access access by CPU and GPU
    bd.ByteWidth = sizeof(Vertex)* 3;             // size is the VERTEX struct * 3
    bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;       // use as a vertex buffer
    bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;    // allow CPU to write in buffer

    device->CreateBuffer(&bd, NULL, &vertexBuffer);       // create the buffer


    // copy the vertices into the buffer
    D3D11_MAPPED_SUBRESOURCE ms;
    deviceContext->Map(vertexBuffer, NULL, D3D11_MAP_WRITE_DISCARD, NULL, &ms);    // map the buffer
    memcpy(ms.pData, OurVertices, sizeof(OurVertices));                 // copy the data
    deviceContext->Unmap(vertexBuffer, NULL);                                      // unmap the buffer
}

着色器文件(shaders.shader):

struct VOut
{
    float4 position : SV_POSITION;
    float4 color : COLOR;
};

VOut VShader(float4 position : POSITION, float4 color : COLOR)
{
    VOut output;

    output.position = position;
    output.color = color;

    return output;
}

float4 PShader(float4 position : SV_POSITION, float4 color : COLOR) : SV_TARGET
{
    return color;
}

如果您取消注释第 119 行的 DwmExtendFrameIntoClientArea 调用,那么它会得到我正在寻找的效果。我想知道是否有一种方法可以在不使用 dwm 的情况下获得相同的效果(原因我不会深入探讨)。

有什么想法吗?

编辑:添加了工作示例的完整源代码。发现如果我调用 DwmExtendFrameIntoClientArea,就会得到我想要的效果。但我仍然想知道是否可以在不使用 dwm api 的情况下做到这一点。

【问题讨论】:

    标签: c++ windows directx directx-11


    【解决方案1】:

    您不能仅使用 DirectX 使窗口透明,以下代码仅将背景颜色清除为黑色。

    float color[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
    

    要实现你的窗口透明效果,你需要涉及一些win32的东西,SetLayeredWindowAttributes是你的选择。

    // Show the window
    ShowWindow( hWnd, SW_SHOWDEFAULT );
    UpdateWindow( hWnd );
    
    SetWindowLong(hWnd, GWL_EXSTYLE, WS_EX_LAYERED) ;
    SetLayeredWindowAttributes(hWnd, RGB(0, 0, 0), 100, LWA_ALPHA);
    

    更新:

    可行的代码只绘制绿色的透明窗口。

    #include <Windows.h>
    #include <windowsx.h>
    #pragma comment (lib, "Winmm.lib")
    
    #include <d3d11.h>
    #pragma comment (lib, "d3d11.lib")
    #include <d3dcompiler.h>
    #pragma comment(lib, "D3DCompiler.lib")
    
    #include <dwmapi.h>
    #pragma comment (lib, "Dwmapi.lib")
    
    
    // Globals
    IDXGISwapChain *swapChain;
    ID3D11Device *device;
    ID3D11DeviceContext *deviceContext;
    ID3D11RenderTargetView *backBuffer;
    
    void InitializeDirectX(HWND hWnd);
    
    // this is the main message handler for the program
    LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        switch (message)
        {
        case WM_DESTROY:
            {
                // close the application entirely
                PostQuitMessage(0);
                return 0;
            }
        }
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    
    // Globals
    const LPCWSTR ClassName = L"className";
    
    
    // the entry point for any Windows program
    int WINAPI WinMain(HINSTANCE hInstance,
                       HINSTANCE hPrevInstance,
                       LPSTR lpCmdLine,
                       int nCmdShow)
    {
        WNDCLASSEX wc;
        ZeroMemory(&wc, sizeof(WNDCLASSEX));
    
        // fill in the struct with the needed information
        wc.cbSize = sizeof(WNDCLASSEX);
        wc.style = CS_HREDRAW | CS_VREDRAW;
        wc.lpfnWndProc = WindowProc;
        wc.hInstance = hInstance;
        wc.hCursor = LoadCursor(NULL, IDC_ARROW);
        wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
        wc.lpszClassName = ClassName;
    
        // register the window class
        RegisterClassEx(&wc);
    
        // create the window and use the result as the handle
        HWND hWnd = CreateWindowEx(
            NULL,        // extended styles
            ClassName,    // name of the window class
            L"TestOverlay",   // title of the window
            WS_OVERLAPPEDWINDOW,    // window style
            0,    // x-position of the window
            0,    // y-position of the window
            400,    // width of the window
            400,    // height of the window
            NULL,    // we have no parent window, NULL
            NULL,    // we aren't using menus, NULL
            hInstance,    // application handle
            NULL);    // used with multiple windows, NULL
    
        // display the window on the screen
        ShowWindow(hWnd, nCmdShow);
        UpdateWindow(hWnd);
    
        // Make the window transparent
        SetWindowLong(hWnd, GWL_EXSTYLE, WS_EX_LAYERED) ;
        SetLayeredWindowAttributes(hWnd, RGB(0, 0, 0), 128, LWA_ALPHA);
    
        // DirectX
        InitializeDirectX(hWnd);
    
        // enter the main loop:
        MSG msg;
        BOOL gotMessage;
        while (TRUE)
        {
            if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
    
                if (msg.message == WM_QUIT)
                    break;
    
                // DirectX stuff
                float color[4] = { 0.0f, 1.0f, 0.0f, 0.0f };
                deviceContext->ClearRenderTargetView(backBuffer, color);
                swapChain->Present(0, 0);
            }
        }
    
        return msg.wParam;
    }
    
    
    void InitializeDirectX(HWND hWnd)
    {
        // create a struct to hold information about the swap chain
        DXGI_SWAP_CHAIN_DESC scd;
    
        // clear out the struct for use
        ZeroMemory(&scd, sizeof(DXGI_SWAP_CHAIN_DESC));
    
        // fill the swap chain description struct
        scd.BufferCount = 1;                                    // one back buffer
        scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;     // use 32-bit color
        scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;      // how swap chain is to be used
        scd.OutputWindow = hWnd;                                // the window to be used
        scd.SampleDesc.Count = 4;                               // how many multisamples
        scd.Windowed = TRUE;                                    // windowed/full-screen mode
    
        // create a device, device context and swap chain using the information in the scd struct
        D3D11CreateDeviceAndSwapChain(NULL,
            D3D_DRIVER_TYPE_HARDWARE,
            NULL,
            NULL,
            NULL,
            NULL,
            D3D11_SDK_VERSION,
            &scd,
            &swapChain,
            &device,
            NULL,
            &deviceContext);
    
    
        // get the address of the back buffer
        ID3D11Texture2D *pBackBuffer;
        swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);
    
        // use the back buffer address to create the render target
        device->CreateRenderTargetView(pBackBuffer, NULL, &backBuffer);
        pBackBuffer->Release();
    
        // set the render target as the back buffer
        deviceContext->OMSetRenderTargets(1, &backBuffer, NULL);
    
        // Set the viewport size
        RECT cRect;
        GetClientRect(hWnd, &cRect);
    
        D3D11_VIEWPORT viewport;
        ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT));
    
        viewport.TopLeftX = 0;
        viewport.TopLeftY = 0;
        viewport.Width = cRect.right - cRect.left;
        viewport.Height = cRect.bottom - cRect.top;
    
        deviceContext->RSSetViewports(1, &viewport);
    }
    

    【讨论】:

    • 是的,我已经这样做了。但是,由于某种原因,在 SetLayeredWindowAttributes 中指定的透明度颜色键不适用于我的 DirectX 清除颜色。
    • 这里对我有用,如果仍有问题,请粘贴完整代码。
    • 我设法通过添加对 DwmExtendFrameIntoClientArea 的调用使其工作。你也必须这样做吗?我不想在我正在做的事情上使用 Dwm,所以如果你的解决方案在没有那个调用的情况下工作,那么我会尝试将我的代码压缩成一个更小的 repro 并发布整个事情。
    • 不,我没有使用Dwm,我只是使用我上面发布的内容。
    • 我添加了工作复制的完整代码。感谢您迄今为止的帮助zdd
    猜你喜欢
    • 2015-03-26
    • 1970-01-01
    • 2021-11-27
    • 2014-01-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-21
    相关资源
    最近更新 更多