Direct3D11 (C ++): Обновление координат текстуры в постоянном буфере? - PullRequest
4 голосов
/ 09 сентября 2011

Я пытаюсь сделать довольно простой 2D-движок с Direct3D.

Я сделал функцию LoadImage (), которая хранит все довольно статичное поведение изображения в объекте.(Шейдеры, вершинные буферы, сэмплеры и т. Д.)

Я планирую выполнить позиционирование вершин с матрицами в постоянных буферах.

Однако мне также хотелось бы иметь функцию DrawImage (), в которой был бы параметр, указывающий, какая часть текстуры должна быть нарисована (обрезана), поэтому мне придется обновить координаты текстуры.Поскольку вершинный буфер уже предопределен, я подумал, есть ли способ обновить координаты текстуры через константный буфер, который будет отправлен в вершинный шейдер?

Надеюсь, мой вопрос достаточно ясен, если у вас есть какие-либо сомненияпосмотрите на код ниже.

bool GameManager::GMLoadImage(Image* pImage, const char* pkcFilePath, ImageDesc* pImDesc)
{
    pImage = new Image();

    ID3D11ShaderResourceView* pColorMap = (pImage)->GetpColorMap();


/// CREATE SHADER RESOURCE VIEW (from file) ///
    HRESULT result = D3DX11CreateShaderResourceViewFromFileA(m_pDevice,
                                                             pkcFilePath,
                                                             0,
                                                             0,
                                                             &pColorMap,
                                                             0);
    if (FAILED(result)) {
        MessageBoxA(NULL,"Error loading ShaderResourceView from file","Error",MB_OK);
        return false;
    }


/// RECEIVE TEXTURE DESC ///
    ID3D11Resource* pColorTex;
    pColorMap->GetResource(&pColorTex);
    ((ID3D11Texture2D*)pColorTex)->GetDesc(&((pImage)->GetColorTexDesc()));
    pColorTex->Release();

/// CREATE VERTEX BUFFER ///
    D3D11_TEXTURE2D_DESC colorTexDesc = pImage->GetColorTexDesc();
    float halfWidth = static_cast<float>(colorTexDesc.Width)/2.0f;
    float halfHeight = static_cast<float>(colorTexDesc.Height)/2.0f;

    Vertex.PosTex vertices[]=
    {
        {XMFLOAT3( halfWidth, halfHeight, 1.0f ),   XMFLOAT2( 1.0f, 0.0f )},
        {XMFLOAT3( halfWidth, -halfHeight, 1.0f ),  XMFLOAT2( 1.0f, 1.0f )},
        {XMFLOAT3( -halfWidth, -halfHeight, 1.0f ), XMFLOAT2( 0.0f, 1.0f )},

        {XMFLOAT3( -halfWidth, -halfHeight, 1.0f ), XMFLOAT2( 0.0f, 1.0f )},
        {XMFLOAT3( -halfWidth, halfHeight, 1.0f ),  XMFLOAT2( 0.0f, 0.0f )},
        {XMFLOAT3( halfWidth, halfHeight, 1.0f ),   XMFLOAT2( 1.0f, 0.0f )}
    };

    D3D11_BUFFER_DESC vertexDesc;
    ZeroMemory(&vertexDesc,sizeof(vertexDesc));
    vertexDesc.Usage = D3D11_USAGE_DEFAULT;
    vertexDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
    vertexDesc.ByteWidth = sizeof(Vertex.PosTex)*6;

    D3D11_SUBRESOURCE_DATA resourceData;
    resourceData.pSysMem = vertices;

    ID3D11Buffer* pVBuffer = pImage->GetpVertexBuffer();
    result = m_pDevice->CreateBuffer(&vertexDesc,&resourceData,&pVBuffer);

    if (FAILED(result))
    {
        MessageBoxA(NULL,"Error Creating VBuffer","Error",MB_OK);
        return false;
    }



/// SET POINTER TO IMAGEDESC
    ImageDesc* pThisImDesc = pImage->GetpImageDesc();
    pThisImDesc = pImDesc;

    return true;
}

bool GameManager::GMDrawImage(Image* pImage, const CLIPRECT& rkClip)
{
    ImageDesc* thisImDesc = pImage->GetpImageDesc();

    if ( (thisImDesc != m_pImDesc) ) {
        m_pImDesc = thisImDesc;
        m_pContext->IASetInputLayout(m_pImDesc->pInputLayout);
        m_pContext->IASetPrimitiveTopology(m_pImDesc->Topology);

        m_pContext->VSSetShader(m_pImDesc->pSolidColorVS,0,0);
        m_pContext->PSSetShader(m_pImDesc->pSolidColorPS,0,0);
        m_pContext->PSSetSamplers(0,1,&m_pImDesc->pSampler);
        m_pContext->OMSetBlendState(m_pImDesc->pBlendState,NULL,0xFFFFFFFF);
    }

    UINT stride = m_pImDesc->VertexSize;
    UINT offset = 0;
    ID3D11Buffer* pVBuffer = pImage->GetpVertexBuffer();
    ID3D11ShaderResourceView* pColorMap = pImage->GetpColorMap();

    m_pContext->IASetVertexBuffers(0,1,&pVBuffer,&stride,&offset);
    m_pContext->PSSetShaderResources(0,1,&pColorMap);

    //set constant buffers?

    m_pContext->Draw(6,0);
}

1 Ответ

4 голосов
/ 09 сентября 2011

Да, если ваши координаты текстур жестко закодированы в диапазоне от 0,0 до 1,0 в буфере вершин, вы можете использовать матрицу преобразования текстур.Это матрица 3x3, которая преобразует ваши 2D-координаты текстуры.

Например, если вы хотите использовать нижний правый квадрант вашей текстуры (при условии, что верхний левый является источником), вы можете использовать следующую матрицу:

0.5 0.0 0.0
0.0 0.5 0.0
0.5 0.5 1.0

Затем в вершинном шейдере вы умножаете координаты текстуры на эту матрицу следующим образом:

float3 coord = float3(In.texCoord, 1.0);
coord *= textureTransform;
Out.texCoord = coord.xy / coord.z;

In.texCoord и Out.texCoord являются входными и выходными координатами текстуры float2соответственно.

Деление на Z необязательно, если вы выполняете только аффинные преобразования (переводы, масштабирование, вращения и перекосы), поэтому не стесняйтесь удалять его, если не нужно.

Для обобщения матрицы:

Sx  0.0 0.0
0.0 Sy  0.0
Tx  Ty  1.0

Где Txy - это положение области клипа, а Sxy - размер области клипа в координатах текстуры.

...