立方体旋转仅由鼠标移动或按键触发

问题描述 投票:0回答:1

编辑: 好吧,我忘记包含一些相关函数,使您很难识别错误。对此我很抱歉。 所以我再次更新了我的问题

我在应用程序中遇到了立方体旋转的特殊问题。立方体仅在我移动鼠标或按下按键时旋转,并且我希望能够连续旋转而不依赖于用户输入。

详情:

鼠标移动:当我移动鼠标时,立方体会正确旋转,但我需要它连续旋转,而不需要不断移动鼠标。 按键:按下一个键会立即旋转立方体。但是,我希望只要按住该键就可以继续旋转。 窗口关闭按钮:单击窗口的关闭按钮(X 按钮)不会按预期关闭应用程序窗口。 期望:

连续旋转立方体,无需不断移动鼠标或按键。 窗口关闭按钮的正确功能可关闭应用程序窗口。 当前实施:

立方体旋转在渲染函数中处理,由鼠标移动和按键触发。 应用程序循环(while 循环)使用 PeekMessage 和 GetMessage 函数处理输入事件。

主要.cpp

#include "WindowManager.h"
#include "EngineGraphics.h"

ID3D11Device* gp_Device;
ID3D11DeviceContext* gp_DeviceContext;

IDXGIDevice* gp_DXGI_Device;
IDXGIAdapter* gp_DXGI_Adapter;
IDXGIFactory* gp_DXGI_Factory;
IDXGISwapChain* gp_DXGI_SwapChain;

ID3D11VertexShader* gp_VS;
ID3D11PixelShader* gp_PS;
ID3D11InputLayout* gp_InputLayout;
ID3D11Buffer* gp_VBuffer;
ID3D11Buffer* gp_IBuffer;
ID3D11RasterizerState* gp_rs;

ID3D11RenderTargetView* gp_BackBuffer;

float input;

Vertex Cube[] = {
    { XMFLOAT3(-0.5f, -0.5f, -0.5f), XMFLOAT4(1.0f, 0.0f, 0.0f, 1.0f) },
    { XMFLOAT3(-0.5f, 0.5f, -0.5f), XMFLOAT4(1.0f, 0.0f, 1.0f, 1.0f) },
    { XMFLOAT3(0.5f, 0.5f, -0.5f), XMFLOAT4(0.0f, 0.0f, 0.0f, 1.0f) },
    { XMFLOAT3(0.5f, -0.5f, -0.5f), XMFLOAT4(1.0f, 1.0f, 0.0f, 1.0f) },
    // Back face
    { XMFLOAT3(-0.5f, -0.5f, 0.5f), XMFLOAT4(1.0f, 0.0f, 1.0f, 1.0f) },
    { XMFLOAT3(0.5f, -0.5f, 0.5f), XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f) },
    { XMFLOAT3(0.5f, 0.5f, 0.5f), XMFLOAT4(0.0f, 1.0f, 0.0f, 1.0f) },
    { XMFLOAT3(-0.5f, 0.5f, 0.5f), XMFLOAT4(0.0f, 1.0f, 1.0f, 1.0f) }
};
WORD CubeIndices[] = {
    // Front face
    0, 1, 2,
    0, 2, 3,
    // Back face
    4, 5, 6,
    4, 6, 7,
    // Left face
    4, 7, 1,
    4, 1, 0,
    // Right face
    3, 2, 6,
    3, 6, 5,
    // Top face
    1, 7, 6,
    1, 6, 2,
    // Bottom face
    4, 0, 3,
    4, 3, 5
};

void InitD3D(HWND& hWnd, RECT& wr);
void InitPipeline();
void InitGraphics();
void Render();
void CleanD3D();

using namespace ExtroEngine;

LRESULT CALLBACK WinProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    HWND hWnd;

    UINT style = CS_HREDRAW | CS_VREDRAW;
    WindowManager::InitWindowExW(style, WinProc, 0, 0, hInstance, L"Scene", NULL, IDC_ARROW, NULL, NULL, CreateSolidBrush(RGB(0, 0, 0)));

    hWnd = CreateWindowExW(NULL, L"Scene", L"Scene", WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, 600, 600,
        NULL, NULL, hInstance, NULL);
    ShowWindow(hWnd, nCmdShow);

    RECT wr = { 0, 0, SCENE_WIDTH, SCENE_HEIGHT };
    AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE);

    InitD3D(hWnd, wr);

    MSG msg = { 0 };
    while (TRUE)
    {
        if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
            if (msg.message == WM_QUIT)
                break;
        }
        Render();
    }
    CleanD3D();
    return 0;
}
void InitD3D(HWND& hWnd, RECT& wr)
{
    HRESULT hr = 0;
    GetClientRect(hWnd, &wr);
    D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_10_1 };
    D3D_DRIVER_TYPE DriveType[] = { D3D_DRIVER_TYPE_HARDWARE, D3D_DRIVER_TYPE_WARP, D3D_DRIVER_TYPE_REFERENCE };

    DXGI_SWAP_CHAIN_DESC swpDesc;
    ZeroMemory(&swpDesc, sizeof(DXGI_SWAP_CHAIN_DESC));
    swpDesc.BufferCount = 1;
    swpDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    swpDesc.BufferDesc.Width = SCENE_WIDTH_MAX_HD;
    swpDesc.BufferDesc.Height = SCENE_HEIGHT_MAX_HD;
    swpDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    swpDesc.OutputWindow = hWnd;
    swpDesc.SampleDesc.Count = 1;
    swpDesc.SampleDesc.Quality = 0;
    swpDesc.Windowed = TRUE;

    for (auto DriveSelect : DriveType)
    {
        hr = D3D11CreateDeviceAndSwapChain(NULL, DriveSelect, NULL, NULL, NULL, NULL,
            D3D11_SDK_VERSION, &swpDesc, &gp_DXGI_SwapChain, &gp_Device, featureLevels, &gp_DeviceContext);
        if (SUCCEEDED(hr))
        {
            break;
        }
    }
    if (FAILED(hr)) {
        MessageBox(NULL, L"Error Create Device And Swap Chain", L"Error", MB_OK);
        CleanD3D();
        return;
    }

    ID3D11Texture2D* pBackBuffer;
    gp_DXGI_SwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);

    gp_Device->CreateRenderTargetView(pBackBuffer, NULL, &gp_BackBuffer);
    pBackBuffer->Release();

    gp_DeviceContext->OMSetRenderTargets(1, &gp_BackBuffer, NULL);

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

    viewport.TopLeftX = 0;
    viewport.TopLeftY = 0;
    viewport.Width = SCENE_WIDTH_MAX_HD;
    viewport.Height = SCENE_HEIGHT_MAX_HD;

    gp_DeviceContext->RSSetViewports(1, &viewport);

    InitPipeline();
    InitGraphics();
}
// -------------  KHỞI TẠO BỘ BIÊN DỊCH ĐỒ HOẠ
void InitPipeline()
{
    HRESULT hr;

    ID3DBlob* VS, * PS;
    hr = D3DCompileFromFile(L"ColorVPS.hlsl", NULL, D3D_COMPILE_STANDARD_FILE_INCLUDE,
        "VShader", "vs_5_0", 0, 0, &VS, NULL);
    if (FAILED(hr)) {
        MessageBox(NULL, L"Compile From File {ColorVPS.hlsl} Error With {VShader}",
            L"Error", MB_OK);
        CleanD3D();
        return;
    }

    hr = D3DCompileFromFile(L"ColorVPS.hlsl", NULL, D3D_COMPILE_STANDARD_FILE_INCLUDE,
        "PShader", "ps_5_0", 0, 0, &PS, NULL);
    if (FAILED(hr)) {
        MessageBox(NULL, L"Compile From File {ColorVPS.hlsl} Error With {PShader}",
            L"Error", MB_OK);
        CleanD3D();
        return;
    }

    hr = gp_Device->CreateVertexShader(VS->GetBufferPointer(), VS->GetBufferSize(), NULL, &gp_VS);
    if (FAILED(hr)) {
        MessageBox(NULL, L"Create Vertex Shader Error With {VS}",
            L"Error", MB_OK);
        CleanD3D();
        return;
    }

    hr = gp_Device->CreatePixelShader(PS->GetBufferPointer(), PS->GetBufferSize(), NULL, &gp_PS);
    if (FAILED(hr)) {
        MessageBox(NULL, L"Create Pixel Shader Error With {PS}",
            L"Error", MB_OK);
        CleanD3D();
        return;
    }

    gp_DeviceContext->VSSetShader(gp_VS, NULL, 0);
    gp_DeviceContext->PSSetShader(gp_PS, NULL, 0);

    D3D11_INPUT_ELEMENT_DESC InputShader[] =
    {
        {"POSITION",0,DXGI_FORMAT_R32G32B32_FLOAT,0,0,D3D11_INPUT_PER_VERTEX_DATA,0},
        {"COLOR",0,DXGI_FORMAT_R32G32B32_FLOAT,0,12,D3D11_INPUT_PER_VERTEX_DATA,0}
    };
    gp_Device->CreateInputLayout(InputShader, 2, VS->GetBufferPointer(), VS->GetBufferSize(), &gp_InputLayout);
    gp_DeviceContext->IASetInputLayout(gp_InputLayout);
}

// -------------- KHỞI TẠO ĐỒ HOẠ 
void InitGraphics() {
    HRESULT hr;

    // Tạo và gán giá trị cho Vertex Buffer (gp_VBuffer)
    D3D11_BUFFER_DESC bd;
    ZeroMemory(&bd, sizeof(bd));
    bd.Usage = D3D11_USAGE_DYNAMIC;
    bd.ByteWidth = sizeof(Vertex) * ARRAYSIZE(Cube);
    bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
    bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;

    D3D11_SUBRESOURCE_DATA InitData;
    ZeroMemory(&InitData, sizeof(InitData));
    InitData.pSysMem = Cube;

    hr = gp_Device->CreateBuffer(&bd, &InitData, &gp_VBuffer);
    if (!SUCCEEDED(hr)) {
        MessageBox(NULL, L"Create Vertex Buffer Error",
            L"Error", MB_OK);
        CleanD3D();
        return;
    }

    // Tạo và gán giá trị cho Index Buffer (gp_IBuffer)
    D3D11_BUFFER_DESC ib = {};
    ib.Usage = D3D11_USAGE_IMMUTABLE;
    ib.ByteWidth = sizeof(WORD) * ARRAYSIZE(CubeIndices);
    ib.BindFlags = D3D11_BIND_INDEX_BUFFER;

    D3D11_SUBRESOURCE_DATA initData = {};
    initData.pSysMem = CubeIndices;

    hr = gp_Device->CreateBuffer(&ib, &initData, &gp_IBuffer);
    if (FAILED(hr)) {
        MessageBox(NULL, L"Create Index Buffer Error",
            L"Error", MB_OK);
        CleanD3D();
        return;
    }

    // Tạo và thiết lập Rasterizer State (gp_rs)
    D3D11_RASTERIZER_DESC rasterizerDesc = {};
    rasterizerDesc.FillMode = D3D11_FILL_SOLID;
    rasterizerDesc.CullMode = D3D11_CULL_BACK; // or whatever cull mode you need

    hr = gp_Device->CreateRasterizerState(&rasterizerDesc, &gp_rs);
    if (FAILED(hr)) {
        MessageBox(NULL, L"Create Rasterizer State Error",
            L"Error", MB_OK);
        CleanD3D();
        return;
    }
}

//-------------------VẼ CỬA SỔ-------------------//
void Render()
{
    float clearColor[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
    gp_DeviceContext->ClearRenderTargetView(gp_BackBuffer, clearColor);

    gp_DeviceContext->VSSetShader(gp_VS, NULL, 0);
    gp_DeviceContext->PSSetShader(gp_PS, NULL, 0);
    gp_DeviceContext->IASetInputLayout(gp_InputLayout);
    gp_DeviceContext->OMSetRenderTargets(1, &gp_BackBuffer, NULL);

///////////////////// THIS ///////////////////////////////
    input = Input::GetKeyRaw(K);

    for (int i = 0; i < ARRAYSIZE(Cube); i++)
    {
        Rotation(0.05f, input, 0.05f, Cube[i].ScreenCoordinates);
    }
////////////////////////////////////////////////////////////

    D3D11_MAPPED_SUBRESOURCE map;
    gp_DeviceContext->Map(gp_VBuffer, NULL, D3D11_MAP_WRITE_DISCARD, NULL, &map);
    memcpy(map.pData, Cube, sizeof(Cube));
    gp_DeviceContext->Unmap(gp_VBuffer, NULL);

    UINT stride = sizeof(Vertex);
    UINT offset = 0;
    gp_DeviceContext->IASetIndexBuffer(gp_IBuffer, DXGI_FORMAT_R16_UINT, 0);
    gp_DeviceContext->RSSetState(gp_rs);
    gp_DeviceContext->IASetVertexBuffers(0, 1, &gp_VBuffer, &stride, &offset);
    gp_DeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

    gp_DeviceContext->DrawIndexed(ARRAYSIZE(CubeIndices), 0, 0);
    gp_DXGI_SwapChain->Present(0, 0);
}
//-------------------DỌN DẸP CỬA SỔ -------------//
void CleanD3D()
{
    SafeRelease(gp_Device);
    SafeRelease(gp_DeviceContext);

    SafeRelease(gp_DXGI_Device);
    SafeRelease(gp_DXGI_Adapter);
    SafeRelease(gp_DXGI_Factory);
    SafeRelease(gp_DXGI_SwapChain);

    SafeRelease(gp_VS);
    SafeRelease(gp_PS);
    SafeRelease(gp_InputLayout);
    SafeRelease(gp_IBuffer);
    SafeRelease(gp_rs);

    SafeRelease(gp_BackBuffer);
}

LRESULT CALLBACK WinProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_PAINT:
        Render();
        ValidateRect(hWnd, NULL);
        break;

    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
        break;
    }
    return DefWindowProc(hWnd, message, wParam, lParam);
}

WindowManager.h

#pragma once
#include <Windows.h>

struct WindowManager
{
    static void InitWindowExW(UINT style, WNDPROC lpfnWndProc, int cbClsExtra, int cbWndExtra, HINSTANCE hInstance, LPCWSTR lpszClassName, LPCWSTR lpszMenuName, LPCWSTR hCursor, LPCWSTR hIcon, LPCWSTR hIconSm, HBRUSH hbrBackground) {
        WNDCLASSEXW wndClass = {};
        wndClass.cbSize = sizeof(WNDCLASSEXW);
        wndClass.style = style;
        wndClass.lpfnWndProc = lpfnWndProc;
        wndClass.cbClsExtra = cbClsExtra;
        wndClass.hInstance = hInstance;
        wndClass.lpszClassName = lpszClassName;
        wndClass.lpszMenuName = lpszMenuName;
        wndClass.hCursor = LoadCursorW(hInstance, hCursor);
        wndClass.hIcon = LoadIconW(hInstance, hIcon);
        wndClass.hIconSm = LoadIconW(hInstance, hIconSm);
        wndClass.hbrBackground = hbrBackground;

        if (!RegisterClassExW(&wndClass)) {
            
        }
    }
};

EngineGraphics.h

#pragma once
#include <d3d11.h>
#include <dxgi1_2.h>
#include <d3dcompiler.h>
#include "ExtroEngine.h"
#include "EngineUtility.h"

#define SCENE_HEIGHT 600
#define SCENE_HEIGHT_MAX_HD 3300
#define SCENE_WIDTH_MAX_HD 2240
#define SCENE_WIDTH 600

using namespace DirectX;

struct Vertex
{
    XMFLOAT3 ScreenCoordinates;
    XMFLOAT4 Color;
};

template<typename T>
inline void SafeRelease(T& ptr)
{
    if (ptr != NULL)
    {
        ptr->Release();
        ptr = NULL;
    }
}

ExtroEngine.cpp

#include "ExtroEngine.h"

namespace ExtroEngine
{
    float Input::GetKeyRaw(Key key)
    {
        MSG msg = { 0 };
        if (GetMessage(&msg, NULL, 0, 0))
        {
            TranslateMessage(&msg);
            switch (msg.message)
            {
            case WM_KEYDOWN:
                if (msg.wParam == key)
                {
                    return 1.0f;
                }
                break;
            }
        }
        return 0.0f;
    }

    void Rotation(float AngleX, float AngleY, float AngleZ, XMFLOAT3& point)
    {
        float rX = AngleX * (XM_PI / 180.0f);
        float rY = AngleY * (XM_PI / 180.0f);
        float rZ = AngleZ * (XM_PI / 180.0f);

        XMMATRIX rotationMatrixX = XMMatrixRotationX(rX);
        XMMATRIX rotationMatrixY = XMMatrixRotationY(rY);
        XMMATRIX rotationMatrixZ = XMMatrixRotationZ(rZ);

        XMMATRIX finalRotationMatrix = rotationMatrixX * rotationMatrixY * rotationMatrixZ;

        XMVECTOR pointVector = XMLoadFloat3(&point);
        pointVector = XMVector3TransformCoord(pointVector, finalRotationMatrix);
        XMStoreFloat3(&point, pointVector);
    }
    void Translation(float x, float y, float z, XMFLOAT3& point)
    {
        XMVECTOR pV = XMLoadFloat3(&point);
        XMMATRIX translationMatrix = XMMatrixTranslation(x, y, z);
        XMVECTOR transformedPoint = XMVector3TransformCoord(pV, translationMatrix);
        XMStoreFloat3(&point, transformedPoint);
    }

    float Time::DeltaTime = 0.0f;
}

ExtroEngine.h

#pragma once
#include "Key.h"
#include <DirectXMath.h>

using namespace DirectX;

namespace ExtroEngine
{
    class Transform
    {
    public:
        XMFLOAT3 Position;
        XMFLOAT3 Rotation;
        XMFLOAT3 Scale;
        Transform()
        {
            Position = { 0.0f,0.0f,0.0f };
            Rotation = { 0.0f,0.0f,0.0f };
            Scale = { 0.0f,0.0f,0.0f };
        }
    };
    struct Input
    {
        static float GetKeyRaw(Key key);
    };

    struct Time
    {
        static float DeltaTime;
    };

    void Rotation(float AngleX, float AngleY, float AngleZ, XMFLOAT3& point);
    void Translation(float x, float y, float z, XMFLOAT3& point);
}

和Key.h

#pragma once
#include <Windows.h>

typedef enum Key {
    A = 'A', B = 'B', C = 'C', D = 'D', E = 'E', F = 'F', G = 'G', H = 'H', I = 'I', J = 'J', K = 'K',
    L = 'L', M = 'M', N = 'N', O = 'O', P = 'P', Q = 'Q', R = 'R', S = 'S', T = 'T', U = 'U', V = 'V',
    W = 'W', X = 'X', Y = 'Y', Z = 'Z',
    NUM_0 = '0', NUM_1 = '1', NUM_2 = '2', NUM_3 = '3', NUM_4 = '4', NUM_5 = '5', NUM_6 = '6',
    NUM_7 = '7', NUM_8 = '8', NUM_9 = '9',
    ESC = VK_ESCAPE
} Key;

添加ColorVPS.hlsl

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

void main(in float4 position : POSITION, in float4 color : COLOR, out float4 oPosition : SV_POSITION, out float4 oColor : COLOR)
{
    VOut output = VShader(position, color);
    
    oPosition = output.position;
    oColor = output.color;
}

注意事项: 我使用 DirectX 11 来渲染和处理输入事件。

应用程序运行时没有任何错误或崩溃,但所描述的立方体旋转和窗口关闭按钮问题仍然存在。

我想知道我的代码错误在哪里

c++ windows directx-11
1个回答
0
投票

有多种方法可以解决此问题。

首先,您可以使用使用消息和消息队列中的官方消息循环,因此将您的

while(TRUE) ...
替换为:

BOOL bRet;
while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0)
{
    if (bRet == -1)
    {
        // handle the error and possibly exit
        break;
    }
    else
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
        // don't put Render() here
    }
}

然后在

WM_PAINT
中进行渲染循环。这就是您想要做的,但一个重要的细节如doc所说:

返回值 如果应用程序处理此消息,则返回零。

因此,将您的

WM_PAINT
处理替换为:

case WM_PAINT:
  Render();
  return 0; // we handle it

这对 Windows 来说实际上意味着您从未验证更新区域,因此 Windows 不断发送

WM_PAINT
消息。

另一个解决方案(更常见)是将

Render
保留在当前消息循环中,并处理
WM_PAINT
只是验证区域,如下所示,这样 Windows 就不会永远发送它:

case WM_PAINT:
{
  PAINTSTRUCT ps;
  HDC hdc = BeginPaint(hWnd, &ps);
  EndPaint(hWnd, &ps);
}
return 0;

并更改当前的

Input::GetKeyRaw(Key key)
实现,因为它运行另一个消息循环,这会导致奇怪的事情。将
WM_KEYDOWN
处理移到主循环中,并将键盘状态存储在某处,以便您可以在
Render()
中使用它。

© www.soinside.com 2019 - 2024. All rights reserved.