Реализация поворота в 2D текстуре по центру - PullRequest
0 голосов
/ 24 мая 2018

Я все еще изучаю Directx 11.

Я следую учебному пособию по Rastertek Directx 11, мне удалось отобразить 2D-текстуру на экране, вот ссылка на руководство: http://www.rastertek.com/dx11tut11.html

Мне интересно, как я мог вращать эту текстуру в центре ее оси.Я не знаю с чего начать.Я попытался использовать матрицу вращения z, чтобы заставить его вращаться, но он не вращается вокруг своего центра, он вращается вокруг где-то еще.

Я предполагаю, что мы должны добавить вращение в GraphicsClass :: Render

bool GraphicsClass::Render(float rotation)
{
    D3DXMATRIX worldMatrix, viewMatrix, projectionMatrix, orthoMatrix;
    bool result;


    // Clear the buffers to begin the scene.
    m_D3D->BeginScene(0.0f, 0.0f, 0.0f, 1.0f);

    // Generate the view matrix based on the camera's position.
    m_Camera->Render();

    // Get the world, view, projection, and ortho matrices from the camera and d3d objects.
    m_Camera->GetViewMatrix(viewMatrix);
    m_D3D->GetWorldMatrix(worldMatrix);
    m_D3D->GetProjectionMatrix(projectionMatrix);
    m_D3D->GetOrthoMatrix(orthoMatrix);

    // Turn off the Z buffer to begin all 2D rendering.
    m_D3D->TurnZBufferOff();

    // Put the bitmap vertex and index buffers on the graphics pipeline to prepare them for drawing.
    result = m_Bitmap->Render(m_D3D->GetDeviceContext(), 100, 100);
    if(!result)
    {
        return false;
    }

    // Render the bitmap with the texture shader.
    result = m_TextureShader->Render(m_D3D->GetDeviceContext(), m_Bitmap->GetIndexCount(), worldMatrix, viewMatrix, orthoMatrix, m_Bitmap->GetTexture());
    if(!result)
    {
        return false;
    }

    // Turn the Z buffer back on now that all 2D rendering has completed.
    m_D3D->TurnZBufferOn();

    // Present the rendered scene to the screen.
    m_D3D->EndScene();

    return true;
}

bool BitmapClass::Render(ID3D11DeviceContext* deviceContext, int positionX, int positionY)
{
    bool result;


    // Re-build the dynamic vertex buffer for rendering to possibly a different location on the screen.
    result = UpdateBuffers(deviceContext, positionX, positionY);
    if(!result)
    {
        return false;
    }

    // Put the vertex and index buffers on the graphics pipeline to prepare them for drawing.
    RenderBuffers(deviceContext);

    return true;
}


bool BitmapClass::UpdateBuffers(ID3D11DeviceContext* deviceContext, int positionX, int positionY)
{
    float left, right, top, bottom;
    VertexType* vertices;
    D3D11_MAPPED_SUBRESOURCE mappedResource;
    VertexType* verticesPtr;
    HRESULT result;


    // If the position we are rendering this bitmap to has not changed then don't update the vertex buffer since it
    // currently has the correct parameters.
    if((positionX == m_previousPosX) && (positionY == m_previousPosY))
    {
        return true;
    }

    // If it has changed then update the position it is being rendered to.
    m_previousPosX = positionX;
    m_previousPosY = positionY;

    // Calculate the screen coordinates of the left side of the bitmap.
    left = (float)((m_screenWidth / 2) * -1) + (float)positionX;

    // Calculate the screen coordinates of the right side of the bitmap.
    right = left + (float)m_bitmapWidth;

    // Calculate the screen coordinates of the top of the bitmap.
    top = (float)(m_screenHeight / 2) - (float)positionY;

    // Calculate the screen coordinates of the bottom of the bitmap.
    bottom = top - (float)m_bitmapHeight;

    // Create the vertex array.
    vertices = new VertexType[m_vertexCount];
    if(!vertices)
    {
        return false;
    }

    // Load the vertex array with data.
    // First triangle.
    vertices[0].position = D3DXVECTOR3(left, top, 0.0f);  // Top left.
    vertices[0].texture = D3DXVECTOR2(0.0f, 0.0f);

    vertices[1].position = D3DXVECTOR3(right, bottom, 0.0f);  // Bottom right.
    vertices[1].texture = D3DXVECTOR2(1.0f, 1.0f);

    vertices[2].position = D3DXVECTOR3(left, bottom, 0.0f);  // Bottom left.
    vertices[2].texture = D3DXVECTOR2(0.0f, 1.0f);

    // Second triangle.
    vertices[3].position = D3DXVECTOR3(left, top, 0.0f);  // Top left.
    vertices[3].texture = D3DXVECTOR2(0.0f, 0.0f);

    vertices[4].position = D3DXVECTOR3(right, top, 0.0f);  // Top right.
    vertices[4].texture = D3DXVECTOR2(1.0f, 0.0f);

    vertices[5].position = D3DXVECTOR3(right, bottom, 0.0f);  // Bottom right.
    vertices[5].texture = D3DXVECTOR2(1.0f, 1.0f);

    // Lock the vertex buffer so it can be written to.
    result = deviceContext->Map(m_vertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
    if(FAILED(result))
    {
        return false;
    }

    // Get a pointer to the data in the vertex buffer.
    verticesPtr = (VertexType*)mappedResource.pData;

    // Copy the data into the vertex buffer.
    memcpy(verticesPtr, (void*)vertices, (sizeof(VertexType) * m_vertexCount));

    // Unlock the vertex buffer.
    deviceContext->Unmap(m_vertexBuffer, 0);

    // Release the vertex array as it is no longer needed.
    delete [] vertices;
    vertices = 0;

    return true;
}

void BitmapClass::RenderBuffers(ID3D11DeviceContext* deviceContext)
{
    unsigned int stride;
    unsigned int offset;


    // Set vertex buffer stride and offset.
    stride = sizeof(VertexType); 
    offset = 0;

    // Set the vertex buffer to active in the input assembler so it can be rendered.
    deviceContext->IASetVertexBuffers(0, 1, &m_vertexBuffer, &stride, &offset);

    // Set the index buffer to active in the input assembler so it can be rendered.
    deviceContext->IASetIndexBuffer(m_indexBuffer, DXGI_FORMAT_R32_UINT, 0);

    // Set the type of primitive that should be rendered from this vertex buffer, in this case triangles.
    deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

    return;
}

Как я могу вращать текстуру вокруг центра текстуры?

1 Ответ

0 голосов
/ 25 мая 2018

Не совсем.Это немного тоньше, чем это.Позвольте мне сначала пройтись по основам преобразований.

В DirectX и трехмерной графике в целом преобразования обычно представлены аффинной матрицей преобразования 4x4, которая выполняет три последовательных геометрических преобразования: одно из локального пространства в мировое пространство (матрица мира), одна из мирового пространства в пространство, ориентированное на камеру (матрица вида), и одна из пространства, ориентированного на камеру, в "пространство однородного клипа" (матрица проекции).Как правило, вы услышите это как матрицу WVP ( W orld- V iew- P rojection).

Матрица одиночного преобразования создается путем умножения каждой из отдельных матриц преобразования, из которых она состоит.Этот процесс умножения не является коммутативным, то есть матрица AB не совпадает с матрицей BA.В контексте преобразований AB применяет преобразование A, а затем преобразование B, тогда как BA применяет преобразование B и затем преобразование A. Если A - это поворот на 45 градусов вокруг Z, а b - это перевод 3 единиц вдоль X, AB будет вращатьсяобъект на 45 градусов и разместите его на 3 единицы вправо, тогда как BA сместит объект на 3 единицы вправо и повернет его на 45 градусов, как если бы он был соединен с исходным положением с помощью стержня.На рисунке ниже это показано графически.

RxT vs. TxR

Теперь, когда мы рассмотрели основы, давайте перейдем к реальному коду.

Рассматривая это, я вижу, что ваше первоначальное предположение о проблеме было и правильным, и неправильным - вы выяснили, в чем проблема, но неправильно истолковали причину.

Первая серьезная проблема - ваша геометрия полностью указана в мировом пространстве.Это нормально, если геометрия никогда не будет двигаться, но суть этого вопроса в том, чтобы заставить указанную геометрию двигаться, поэтому ...

Чтобы исправить это, постройте свою форму самым простым способом:по центру вокруг начала координат со сторонами длины 1. Это меняет четыре угла на следующие, предполагая, что + X направо, + Y вверх и + Z вне (в экран): (-0.5, 0.5, 0), (0,5, 0,5, 0), (-0,5, -0,5, 0), (0,5, -0,5, 0).Они представляют верхний левый, верхний правый, нижний левый и нижний правый углы соответственно.

Это также позволяет вам создать буфер вершин один раз в конструкторе, и вам больше никогда не потребуется его обновлять, даже еслиразмер изображения изменяется во время выполнения.

Во-вторых, поскольку исходная спецификация геометрии уже была в мировом пространстве, нам не требовалась матрица реального мира.Теперь, когда наша геометрия представляет собой единичный квадрат вокруг локального происхождения, мы делаем это.Чтобы получить изображение того же размера, что и исходное растровое изображение, мы создаем масштабную матрицу, которая масштабируется на m_bitmapWidth по оси X и m_bitmapHeight по оси Y.Затем мы умножаем его на матрицу вращения вокруг оси Z, чтобы вращать его, и, наконец, умножаем его на матрицу перевода, чтобы переместить его в positionX и positionY.Мы можем переписать UpdateBuffers следующим образом:

bool BitmapClass::UpdateBuffers(int positionX, int positionY, float rotationAngle)
{
    D3DXMATRIX scaling, rotation, translation, worldMatrix;
    // If the position we are rendering this bitmap to has not changed,
    // don't update the world matrix since it currently has the correct 
    // parameters.
    if((positionX == m_previousPosX) && (positionY == m_previousPosY))
    {
        return true;
    }
    // If it has changed then update the position it is being rendered to.
    m_previousPosX = positionX;
    m_previousPosY = positionY;

    // scale, rotate, and translate our unit square
    D3DXMatrixScaling(&scaling, m_bitmapWidth, m_bitmapHeight, 1);
    D3DXMatrixRotationZ(&rotation, rotationAngle);
    D3DXMatrixTranslation(&translation, positionX, positionY, 0);

    //Now concatenate all the transformations together,
    D3DXMatrixMultiply(&worldMatrix, &scaling, &rotation);
    D3DXMatrixMultiply(&worldMatrix, &worldMatrix, &translation);

    // And tell D3D this is our new world matrix.
    m_D3D->SetWorldMatrix(worldMatrix);

    return true;
}

Окончательное редактирование - удалить вызов на UpdateBuffers в BitmapClass::Render и выполнить вызов до вызова GetWorldMatrix.Это гарантирует, что процесс рендеринга использует правильную матрицу преобразования.

...