Как обновить буфер вершин или постоянный буфер, прикрепленный к спрайту, для плавного перемещения по экрану в Direct3D 11? - PullRequest
0 голосов
/ 30 марта 2020

Я прикрепил текстуру к набору из 4 проиндексированных вершин, которые хранятся в динамическом буфере вершин c. Я также добавил матрицу перевода в постоянный буфер вершинного шейдера. Однако, когда я пытаюсь обновить постоянный буфер, чтобы изменить матрицу перевода, чтобы я мог переместить спрайт, спрайт не перемещается плавно. Он останавливается случайным образом на короткое время, прежде чем снова перемещаться на небольшое расстояние.

Ниже приведены функции рендеринга, основные l oop и используемые шейдеры:

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

Я также включил инициализацию swapchain и backbuffer на случай, если из-за этого произошла ошибка.

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

Я также попытался получить указатель на данные вершин через член pData объект D3D11_MAPPED_SUBRESOURCE и затем преобразует его в VERTEX* для манипулирования данными, но проблема остается. Я хотел бы знать, как плавно перемещать спрайт по окну.

1 Ответ

0 голосов
/ 24 апреля 2020

Я решил эту проблему, написав фиксированную игру FPS l oop и передав интерполированные значения между предыдущим и текущим состояниями функции рендеринга. Я также некорректно обновлял константный буфер.

...