興味のあるポイントの上に感嘆符を付ける3Dゲームを作成しています。
2D画面のどこにマーカーを配置するかを見つけるために、マーカーを配置する3Dポイントを手動で投影しています。
次のようになります。
よさそうだ。マーカーが画面の外側にある場合は、座標をクリップして画面に合わせます。次のようになります。
これまでのところ、アイデアはかなりうまくいっています。ただし、対象のポイントがカメラの背後にある場合、結果のX、Y座標が反転し(正/負など)、次のように画面の反対側の隅にマーカーが表示されます。
(投影されてからクランプされた点がマーカーの先端です。マーカーの回転を気にしないでください)
錐台の後ろの座標がXとYで反転しているので、それは理にかなっています。したがって、私がしていることは、カメラの後ろにある座標を反転することです。しかし、座標を反転する必要があるときの正確な条件はまだわかりません。
これは現在、私の投影コードは次のようになっています(C#でSharpDXを使用)。
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座標が負の場合に座標を反転させることです。ほとんどの場合は機能しますが、機能しない特定のカメラ位置がまだいくつかあります。特にこの点は、1つの座標が機能し、他の座標が機能しないことを示しています(正しい位置は右下でなければなりません)。
私は次の場合に反転を試みました:
Z
否定的です(これが私にとって最も意味のあることです)W
は負です(負のW値の意味がわかりません)- どちらか
Z
またはW
負である(現在はほとんどの時間を働いているもの) Z
とW
は別の記号です、別名:(Z / W < 0
私には理にかなっています。ただし機能しません)
しかし、私のすべての点が正しく投影される一貫した方法をまだ見つけていません。
何か案は?