D3D11:如何绘制简单的像素对齐线?

发布于 2024-11-04 23:16:53 字数 1188 浏览 5 评论 0原文

我尝试用 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 } ;

  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 中这并没有那么困难。

请询问您是否需要更多信息。

谢谢,Stefan

编辑:找到 d3d10 的光栅化规则(应该与 d3d11 相同): http://msdn.microsoft.com /en-us/library/cc627092%28v=vs.85%29.aspx#Line_1

我希望这能帮助我理解......

I tried to draw a line between two vertices with D3D11. I have some experiences in D3D9 and D3D11, but it seems to be a problem in D3D11 to draw a line, which starts in one given pixel and ends in an other.

What I did:

  1. I added 0.5f to the pixel coordinates of each vertex to fit the texel-/pixel coordinate system (I read the Microsoft pages to the differeces between D3D9 and D3D11 coordinate systems):

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

  2. Generated a ortho projection matrix to fit the render target:

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

  3. Set RasterizerState, BlendState, Viewport, ...

  4. Draw Vertices as D3D11_PRIMITIVE_TOPOLOGY_LINELIST

Problem:
The Line seems to be one pixel to short. It starts in the given pixel coordinate an fits it perfect. The direction of the line looks correct, but the pixel where I want the line to end is still not colored. It looks like the line is just one pixel to short...

Is the any tutorial explaining this problem or does anybody have the same problem? As I remember it wasn't as difficult in D3D9.

Please ask if you need further information.

Thanks, Stefan

EDIT: found the rasterization rules for d3d10 (should be the same for d3d11):
http://msdn.microsoft.com/en-us/library/cc627092%28v=vs.85%29.aspx#Line_1

I hope this will help me understanding...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

疏忽 2024-11-11 23:16:53

根据光栅化规则(上面问题中的链接),我可能找到了一个可行的解决方案:

  1. 对顶点 StartX < 进行排序。 EndX 和 StartY < EndY
  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 }
};

如果您知道更好的解决方案,请告诉我。

According to the rasterisation rules (link in the question above) I might have found a solution that should work:

  1. sort the vertices StartX < EndX and StartY < EndY
  2. add (0.5/0.5) to the start vertex (as i did before) to move the vertex to the center of the pixel
  3. add (1.0/1.0) to the end vertex to move the vertex to the lower right corner

This is needed to tell the rasterizer that the last pixel of the line should be drawn.

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

If you know a better solution, please let me know.

梓梦 2024-11-11 23:16:53

我不知道 D3D11,但你的问题听起来很像 D3D9 中的 D3DRS_LASTPIXEL 渲染状态 - 也许你需要研究一下 D3D11 的同等情况。

I don't know D3D11, but your problem sounds a lot like the D3DRS_LASTPIXEL render state from D3D9 - maybe there's an equal for D3D11 you need to look into.

小猫一只 2024-11-11 23:16:53

我遇到了完全相同的问题,感谢这次讨论,我解决了。

我的顶点存储在 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 调用,它似乎工作得很好。

I encountered the exact same issue, and i fixed thank to this discussion.

My vertices are stored into a D3D11_PRIMITIVE_TOPOLOGY_LINELIST vertex buffer.

Thank for this usefull post, you made me fix this bug today.
It was REALLY trickier than i thought at start.

Here a few line of my code.

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

I tested Several DrawLine2D calls, and it seems to work well.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文