在 Direct3D 11 中,如何更新附加到精灵的顶点缓冲区或常量缓冲区以使其在屏幕上平滑移动?

How do you update the vertex buffer or constant buffer attached to a sprite to move it smoothly across the screen in Direct3D 11?

我已将纹理附加到一组存储在动态顶点缓冲区中的 4 个索引顶点。我还在顶点着色器的常量缓冲区中添加了一个转换矩阵。但是,当我尝试更新常量缓冲区以更改平移矩阵以便我可以移动精灵时,精灵移动不流畅。它会随机停止一小段时间,然后再次移动一小段距离。

下面是渲染函数、主循环和正在使用的着色器:

    void Sprite::Render(ID3D11DeviceContext* devcon, float dt) {
    // 2D rendering on backbuffer here
    UINT stride = sizeof(VERTEX);
    UINT offset = 0;

    spr_const_data.translateMatrix.r[3].m128_f32[0] += 60.0f*dt;

    devcon->IASetInputLayout(m_data_layout);
    devcon->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

    devcon->VSSetShader(m_spr_vert_shader, 0, 0);
    devcon->PSSetShader(m_spr_pixel_shader, 0, 0);

    devcon->VSSetConstantBuffers(0, 1, &m_spr_const_buffer);
    devcon->PSSetSamplers(0, 1, &m_tex_sampler_state);
    devcon->PSSetShaderResources(0, 1, &m_shader_resource_view);

    // select vertex and index buffers
    devcon->IASetIndexBuffer(m_sprite_index_buffer, DXGI_FORMAT_R32_UINT, offset);
    devcon->IASetVertexBuffers(0, 1, &m_sprite_vertex_buffer, &stride, &offset);

    D3D11_MAPPED_SUBRESOURCE ms;
    ZeroMemory(&ms, sizeof(D3D11_MAPPED_SUBRESOURCE));
    devcon->Map(m_spr_const_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &ms);
    memcpy(ms.pData, &spr_const_data, sizeof(spr_const_data));
    devcon->Unmap(m_spr_const_buffer, 0);

    // select which primitive type to use
    // draw vertex buffer to backbuffer
    devcon->DrawIndexed(6, 0, 0);
}

void RenderFrame(float dt) {
        float background_color[] = { 1.0f, 1.0f, 1.0f, 1.0f };

        // clear backbuffer
        devcon->ClearRenderTargetView(backbuffer, background_color);

        knight->Render(devcon, dt);

        // switch back and front buffer
        swapchain->Present(0, 0);
    }

void MainLoop() {
        MSG msg;
        auto tp1 = std::chrono::system_clock::now();
        auto tp2 = std::chrono::system_clock::now();
        while (GetMessage(&msg, nullptr, 0, 0) > 0) {
            tp2 = std::chrono::system_clock::now();
            std::chrono::duration<float> dt = tp2 - tp1;
            tp1 = tp2;
            TranslateMessage(&msg);
            DispatchMessage(&msg);

            RenderFrame(dt.count());
        }
    }
cbuffer CONST_BUFFER_DATA : register(b0)
{
    matrix orthoMatrix;
    matrix translateMatrix;
};

struct VOut {
    float4 position : SV_POSITION;
    float2 tex : TEXCOORD0;
};

VOut VShader(float4 position : POSITION, float2 tex : TEXCOORD0) {
    VOut output;

    position = mul(translateMatrix, position);
    output.position = mul(orthoMatrix, position);
    output.tex = tex;

    return output;
}
Texture2D square_tex;
SamplerState tex_sampler;

float4 PShader(float4 position : SV_POSITION, float2 tex : TEXCOORD0) : SV_TARGET
{
    float4 tex_col = square_tex.Sample(tex_sampler, tex);
    return tex_col;
}

我还包括了交换链和后备缓冲区的初始化,以防出现错误。

DXGI_SWAP_CHAIN_DESC scd; // hold swap chain information
        ZeroMemory(&scd, sizeof(DXGI_SWAP_CHAIN_DESC));

        // fill swap chian 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 (draw into back buffer)
        scd.OutputWindow = hWnd; // window to be used
        scd.SampleDesc.Count = 1; // how many multisamples
        scd.Windowed = true; // windowed/full screen

        // create device, device context and swap chain using scd
        D3D11CreateDeviceAndSwapChain(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, D3D11_CREATE_DEVICE_DEBUG, nullptr, NULL, D3D11_SDK_VERSION, &scd, &swapchain, &dev, nullptr, &devcon);

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

        // use back buffer address to create render target
        dev->CreateRenderTargetView(pBackBuffer, nullptr, &backbuffer);
        pBackBuffer->Release();

        // set the render target as the backbuffer
        devcon->OMSetRenderTargets(1, &backbuffer, nullptr);

        // Set the viewport
        D3D11_VIEWPORT viewport;
        ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT));

        viewport.TopLeftX = 0;
        viewport.TopLeftY = 0;
        viewport.Width = WINDOW_WIDTH;
        viewport.Height = WINDOW_HEIGHT;

        devcon->RSSetViewports(1, &viewport); // activates viewport

我也曾尝试通过 D3D11_MAPPED_SUBRESOURCE 对象的 pData 成员获取指向顶点数据的指针,然后将其转换为 VERTEX* 来操作数据,但问题仍然存在。我想知道如何在 window.

中平滑地移动精灵

我通过编写一个固定的 FPS 游戏循环并将先前状态和当前状态之间的插值提供给渲染函数来解决这个问题。我还以错误的方式更新了常量缓冲区。