首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >Direct3D查找2D屏幕坐标有效,但在压力下会出现镜像毛刺

Direct3D查找2D屏幕坐标有效,但在压力下会出现镜像毛刺
EN

Stack Overflow用户
提问于 2018-12-17 01:13:48
回答 2查看 218关注 0票数 0

我有这个函数来从3D坐标位置获得2D像素位置。X、y、z是变换前坐标(1到-1)。这是一个模型视图架构,相机固定在-3.5,0,0处,看着0,0,0,同时对象/场景坐标通过水平xz旋转和垂直y旋转等进行变换,以生成最终帧。

此函数主要用于在3D场景的顶部覆盖2D文本。2D文本相对于3D基础场景的位置。

void My3D::Get2Dfrom3Dx(float x, float y, float z, float* psx, float* psy)  {

    XMVECTOR xmScreenCoord = XMLoadFloat3( (XMFLOAT3*) &screenCoord);
    XMMATRIX xmWorldViewProjection = XMLoadFloat4x4( (XMFLOAT4X4*) &m_WorldViewProjection);
    XMVECTOR result = XMVector3TransformCoord( xmScreenCoord, xmWorldViewProjection);
    XMStoreFloat3( (XMFLOAT3*) &screenCoord, result);

    screenCoord.x = ((screenCoord.x + 1.0f) / 2.0f) * m_nCurrWidth;
    screenCoord.y = ((-screenCoord.y + 1.0f) / 2.0f) * m_nCurrHeight;

*psx = screenCoord.x;
*psy = screenCoord.y; }

当场景完全/大部分可见时( -4和-1.5之间的视力),此函数可以完美地工作。

我有一个恼人的问题,文字显示镜像在3D位置,它不应该是。例如,当我从下面查看图像(在对象下方向上60+度)和缩放(将眼睛位置移动到更接近-.5,0,0的位置)时,就会发生这种情况。文本应该是不可见的,因为它应该在眼睛后面(请注意,eye不超过0,0,0,这会使图像变得混乱),但不知何故,上面的函数会导致计算出的屏幕x,y坐标显示在视口中,而不应该显示在视口中。

我似乎认为有一个简单的解决方案来解决这个副作用,但找不到。希望有人以前看过这个2d镜像问题/效果,并知道简单的调整。

我意识到我可以走一条更复杂的路径来确定视图矢量是否与目标点相反,并以这种方式进行过滤,但我似乎认为应该有一个更简单的解决方案。

再一次,相机永远在线上-3.5,0,0说的是-.5,0,0,因为周围的世界正在变化。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-12-17 01:47:43

问题出在投影的工作方式上。基本上,透视投影将x和y坐标除以z坐标。这就是你如何获得透视效果的,也就是说,较远的东西(较大的z坐标)在屏幕上看起来较小。这种透视划分的一个问题是(简化的),它不能正确地工作在相机后面的东西。相机后面的物体会有一个负的z坐标。当你将x和y除以一个负值时,你的点就会反映在原点周围。这就是你所看到的。因为相机后面的东西无论如何都是不可见的,所以解决这个问题的一种方法是在除以z之前简单地裁剪所有几何体,这样所有z值为负的东西都会被截断并移除。

我假设您代码中的除法是在XMVector3TransformCoord()内部进行的。正如您注意到的那样,文本在有问题的案例中无论如何都不应该可见。因此,我建议您只需检查文本是否在相机后面,如果是,就不要渲染它。要做到这一点,一种方法是简单地检查使用xmWorldViewProjection矩阵变换世界空间位置的结果,只有当它恰好在相机前面时才继续。xmScreenCoord保存点的同构剪贴空间坐标。如果xmScreenCoord的z坐标大于零,则该点将位于相机的前面。所以我猜你会想要这样做

if (XMVectorGetZ(xmScreenCoord) > 0)
{
    …
}

由于下面的评论中的讨论,边注:当一个人想要解决涉及屏幕上对象的投影的问题时,人们通常可以通过将问题转换为其对偶并直接在齐次坐标上的投影空间中工作来避免显式地计算投影。因为你的问题是在屏幕上放置2D文本,但是,我不认为这是一个选择。您可以将用于绘制文本的几何图形直接放置在剪裁空间中。您可以重新开始计算要附加2D文本的3D点的剪裁空间坐标(将它们与m_WorldViewProjection相乘,但不除以w)。然后,您可以为绘制文本的几何图形生成同构坐标,只需从该点偏移x和y坐标,即可获得四边形的角或需要构造的任何东西。如果您随后还通过点的w坐标缩放四边形的大小,您将在该位置获得一个四边形,该四边形在屏幕上始终投影到相同的大小(因为与w的预乘有效地抵消了投影)。然而,您所做的一切实际上就是将投影的应用程序留在GPU上。如果你想渲染大量的四边形,这可能是一个需要考虑的选项,因为它可以完全在GPU上完成,例如,使用几何体着色器。但是,如果您只有几个文本元素,则跳过摄像机后面的文本元素的绘制会简单得多,而且可能也更有效,如上所述…

票数 1
EN

Stack Overflow用户

发布于 2018-12-24 21:26:15

Michael的回答非常有帮助,让我继续走上了一条解决方案应该是简单比较的道路。在我的例子中,我必须重新计算屏幕坐标,只应用世界变换,而不是完整的WorldViewProjection。我称其为TargetTransformed。我的比较值是简单的眼睛/相机位置(这永远不会调整(除了缩放),因为世界是围绕眼睛变换的。)再次注意,我的相机在这个例子中是-3.5,0,0,看着0,0,0 (模型的中心,实际上是8,0,0,因此有一条穿过中心的线)。所以我必须比较x分量,而不是z分量。我添加了一些模糊的.1F,因为当目标明显在相机后面时,镜像伪影就会发生。在这种情况下,我返回在外层空间转换的最终screenCoord位置(-8000),以确保它们在视口中看不到。

if ((Eye.x + 0.1F) > TargetTransformed.x) 
{
    screenCoord.x += -8000;
    screenCoord.y += -8000;
    //TRACE("point is behind camera.\n");
    *psx = screenCoord.x;
    *psy = screenCoord.y;
}
else
{
    *psx = screenCoord.x;
    *psy = screenCoord.y;
}

为了完整,我的项目有两个视图模型: a)沿着模型中心的一条线看。它可以转换为从任何方向看,并通过屏幕x和y偏移。第一个视图模型可以很好地使用上面的代码。第二个视图模型b)将摄像机对准模型的焦点,然后允许围绕该随机点(而不是模型的中心)进行完全旋转,这需要计算一个棘手的附加平移矩阵和向量,我称之为TargetViewTranslation。对于这个额外的转换,该公式添加了额外转换的z分量。

if ((Eye.x + 0.1F - m_structTargetViewTranslation.Z) > TargetTransformed.x) 
{
    screenCoord.x += -8000;
    screenCoord.y += -8000;
    //TRACE("point is behind camera.\n");
    *psx = screenCoord.x;
    *psy = screenCoord.y;
}
else
{
    *psx = screenCoord.x;
    *psy = screenCoord.y;
}

如果成功,我的镜像文本问题就解决了。希望这能帮助其他人解决这个镜像文本问题。意识到可能只需要通过World变换来转换测试用例,这应该是一个简单的比较,相机的位置可能会影响使用哪个x或z分量。如果您正在以任何其他方式翻译世界,那么如果比较x或z,则此翻译也可能会产生影响。使用跟踪并查看x、y、z值有助于确定在特定情况下需要使用哪些组件。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53804602

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档