D3D11: Как нарисовать простую линию, выровненную по пикселям? - PullRequest
6 голосов
/ 05 мая 2011

Я попытался нарисовать линию между двумя вершинами с помощью D3D11. У меня есть некоторый опыт работы с D3D9 и D3D11, но в D3D11, похоже, проблема нарисовать линию, которая начинается в одном данном пикселе и заканчивается в другом.

Что я сделал:

  1. Я добавил 0,5f к пиксельным координатам каждой вершины, чтобы соответствовать системе координат текселей / пикселей (я читаю страницы Microsoft по различиям между системами координат D3D9 и D3D11):

    f32 fOff = 0,5f; ColoredVertex newVertices [2] = { {D3DXVECTOR3 (fStartX + fOff, fStartY + fOff, 0), vecColorRGB}, {D3DXVECTOR3 (fEndX + fOff, fEndY + fOff, 0), vecColorRGB} };

    * +1010 *
  2. Создана матрица ортопроекции для соответствия цели рендеринга:

    D3DXMatrixOrthoOffCenterLH (& MatrixOrthoProj, 0.0f, (F32) uRTWidth, 0.0f, (F32) uRTHeight, 0.0f, 1.0f); D3DXMatrixTranspose (& cbConstant.m_matOrthoProjection, & MatrixOrthoProj);

  3. Установить RasterizerState, BlendState, Viewport, ...

  4. Рисовать вершины как D3D11_PRIMITIVE_TOPOLOGY_LINELIST

Проблема: Линия кажется одним пикселем, чтобы сократить. Он начинается с заданной координаты пикселя и подходит ему идеально. Направление линии выглядит правильным, но пиксель, в котором я хочу, чтобы линия заканчивалась, все еще не окрашен. Похоже, что длина строки составляет всего один пиксель ...

В каком-нибудь руководстве объясняется эта проблема, или у кого-то есть такая же проблема? Насколько я помню, в D3D9 это было не так сложно.

Пожалуйста, спросите, нужна ли вам дополнительная информация.

Спасибо, Стефан

РЕДАКТИРОВАТЬ: найдены правила растеризации для d3d10 (должны быть такими же для d3d11): http://msdn.microsoft.com/en-us/library/cc627092%28v=vs.85%29.aspx#Line_1

Надеюсь, это поможет мне понять ...

Ответы [ 3 ]

4 голосов
/ 06 мая 2011

В соответствии с правилами растеризации (ссылка в вопросе выше) я мог бы найти решение, которое должно работать:

  1. сортировка вершин StartX
  2. добавить (0,5 / 0,5) к начальной вершине (как я делал раньше), чтобы переместить вершину в центр пикселя
  3. добавить (1.0 / 1.0) к конечной вершине, чтобы переместить вершину в правый нижний угол

Это необходимо, чтобы сообщить растеризатору, что должен быть нарисован последний пиксель линии.

f32 fXStartOff = 0.5f;
f32 fYStartOff = 0.5f;
f32 fXEndOff = 1.0f;
f32 fYEndOff = 1.0f;

ColoredVertex newVertices[2] = 
{
    { D3DXVECTOR3((f32)fStartX + fXStartOff, (f32)fStartY + fYStartOff,0), vecColorRGB },
    { D3DXVECTOR3((f32)fEndX + fXEndOff , (f32)fEndY + fYEndOff,0), vecColorRGB }
};

Если вы знаете лучшее решение, пожалуйста, дайте мне знать.

1 голос
/ 06 мая 2011

Я не знаю D3D11, но ваша проблема звучит очень похоже на состояние рендеринга D3DRS_LASTPIXEL из D3D9 - возможно, есть D3D11, который вам нужно изучить.

0 голосов
/ 26 сентября 2015

Я столкнулся с точно такой же проблемой, и я исправил это обсуждение.

Мои вершины хранятся в буфере вершин D3D11_PRIMITIVE_TOPOLOGY_LINELIST.

Спасибо за этот полезный пост, вы меня исправилиэтот баг сегодня.Это было ДЕЙСТВИТЕЛЬНО хитрее, чем я думал в начале.

Вот несколько строк моего кода.

// projection matrix code
float width = 1024.0f;
float height = 768.0f;
DirectX::XMMATRIX offsetedProj = DirectX::XMMatrixOrthographicRH(width, height, 0.0f, 10.0f);
DirectX::XMMATRIX proj = DirectX::XMMatrixMultiply(DirectX::XMMatrixTranslation(- width / 2, height / 2, 0), offsetedProj);

// view matrix code
// screen top left pixel is 0,0 and bottom right is 1023,767
DirectX::XMMATRIX viewMirrored = DirectX::XMMatrixLookAtRH(eye, at, up);
DirectX::XMMATRIX mirrorYZ = DirectX::XMMatrixScaling(1.0f, -1.0f, -1.0f);
DirectX::XMMATRIX view = DirectX::XMMatrixMultiply(mirrorYZ, viewMirrored);

// draw line code in my visual debug tool.
void TVisualDebug::DrawLine2D(int2 const& parStart,
                              int2 const& parEnd,
                              TColor parColorStart,
                              TColor parColorEnd,
                              float parDepth)

{
    FLine2DsDirty = true;

    // D3D11_PRIMITIVE_TOPOLOGY_LINELIST
    float2 const startFloat(parStart.x() + 0.5f, parStart.y() + 0.5f);
    float2 const endFloat(parEnd.x() + 0.5f, parEnd.y() + 0.5f);
    float2 const diff = endFloat - startFloat;
    // return normalized difference or float2(1.0f, 1.0f) if distance between the points is null. Then multiplies the result by something a little bigger than 0.5f, 0.5f is not enough.
    float2 const diffNormalized =  diff.normalized_replace_if_null(float2(1.0f, 1.0f)) * 0.501f;

    size_t const currentIndex = FLine2Ds.size();
    FLine2Ds.resize(currentIndex + 2);
    render::vertex::TVertexColor* baseAddress = FLine2Ds.data() + currentIndex;
    render::vertex::TVertexColor& v0 = baseAddress[0];
    render::vertex::TVertexColor& v1 = baseAddress[1];
    v0.FPosition = float3(startFloat.x(), startFloat.y(), parDepth);
    v0.FColor = parColorStart;
    v1.FPosition = float3(endFloat.x() + diffNormalized.x(), endFloat.y() + diffNormalized.y(), parDepth);
    v1.FColor = parColorEnd;
}

Я протестировал несколько вызовов DrawLine2D, и, похоже, он работает хорошо.

...