我正在制作3D游戏,在其中将感叹号放在关注点上方。
为了找出应该在2D屏幕中放置标记的位置,我手动将3D点投影到标记应放置的位置。
看起来像这样:
看起来还不错 当标记位于屏幕之外时,我只需剪切坐标即可使其适合屏幕。看起来像这样:
到目前为止,这个想法进展顺利。但是,当关注点在相机后面时,得到的X,Y坐标将反转(正/负),并且我将标记显示在屏幕的对角,如下所示:
(投影然后夹紧的点是标记的尖端。不要介意标记的旋转)
这是有道理的,因为平截头体后面的坐标在X和Y中是反转的。所以我要做的是在它们位于摄影机后面时反转它们的坐标。但是,我仍然不知道将坐标反转时的确切条件是什么。
当前,这是我的投影代码的样子(在带有SharpDX的C#中):
public override PointF ProjectPosition(float viewportWidth, float viewportHeight, float y)
{
var projectionMatrix = Matrix.PerspectiveFovRH(GetCalibratedFOV(Camera.FOV, viewportWidth, viewportHeight), viewportWidth / viewportHeight, Camera.Near, Camera.Far);
var viewMatrix = Matrix.LookAtRH(new Vector3(Camera.PositionX, Camera.PositionY, Camera.PositionZ), new Vector3(Camera.LookAtX, Camera.LookAtY, Camera.LookAtZ), Vector3.UnitY);
var worldMatrix = Matrix.RotationY(Rotation) * Matrix.Scaling(Scaling) * Matrix.Translation(PositionX, PositionY, PositionZ);
var worldViewProjectionMatrix = worldMatrix * viewMatrix * projectionMatrix;
Vector4 targetVector = new Vector4(0, y, 0, 1);
Vector4 projectedVector = Vector4.Transform(targetVector, worldViewProjectionMatrix);
float screenX = (((projectedVector.X / projectedVector.W) + 1.0f) / 2.0f) * viewportWidth;
float screenY = ((1.0f - (projectedVector.Y / projectedVector.W)) / 2.0f) * viewportHeight;
float screenZ = projectedVector.Z / projectedVector.W;
// Invert X and Y when behind the camera
if (projectedVector.Z < 0 ||
projectedVector.W < 0)
{
screenX = -screenX;
screenY = -screenY;
}
return new PointF(screenX, screenY);
}
如您所见,我当前的想法是在Z或W坐标为负时反转坐标。它在大多数情况下都可以使用,但是仍然有一些非常特定的相机位置无法使用。特别是这一点显示一个坐标有效,而另一坐标不工作(正确的位置应在右下角):
我尝试在以下情况下反转:
Z
是负面的(这对我来说最有意义)W
为负(我不了解负W值的含义)- 无论是
Z
或W
为负(什么是目前工作的大部分时间) Z
并且W
具有不同的符号,又名:(Z / W < 0
对我来说很有意义。虽然不起作用)
但仍未找到正确投影所有点的一致方法。
有任何想法吗?