Tôi đang làm một trò chơi 3D trong đó tôi đặt dấu chấm than trên các điểm ưa thích.
Để tìm ra vị trí trong màn hình 2D, tôi nên đặt điểm đánh dấu ở đâu, tôi đang chiếu thủ công điểm 3D nơi điểm đánh dấu phải ở.
Nó trông như thế này:
Trông khá tốt. Khi điểm đánh dấu nằm ngoài màn hình, tôi chỉ cần cắt các tọa độ để chúng khớp với màn hình. Nó trông như thế này:
Cho đến nay ý tưởng đang diễn ra khá tốt. Tuy nhiên, khi các điểm ưa thích nằm phía sau camera, các tọa độ X, Y kết quả sẽ bị đảo ngược (như dương / âm) và tôi nhận được điểm đánh dấu xuất hiện ở góc đối diện của màn hình, như sau:
(Điểm được kẹp-sau đó được kẹp là điểm đánh dấu. Đừng bận tâm đến việc xoay điểm đánh dấu)
Điều này có ý nghĩa, vì tọa độ đằng sau sự thất vọng được đảo ngược trong X và Y. Vì vậy, những gì tôi đang làm là đảo ngược tọa độ khi chúng ở phía sau camera. Tuy nhiên, tôi vẫn không biết chính xác điều kiện khi đảo tọa độ là gì.
Đây hiện là mã trình chiếu của tôi trông như thế nào (trong C # với 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);
}
Như bạn có thể thấy, ý tưởng hiện tại của tôi là đảo ngược tọa độ khi tọa độ Z hoặc W âm. Nó hoạt động - hầu hết thời gian, nhưng vẫn có một số vị trí máy ảnh rất cụ thể mà nó không hoạt động. Cụ thể, điểm này cho thấy một tọa độ hoạt động và một tọa độ khác thì không (vị trí chính xác phải ở dưới cùng bên phải):
Tôi đã thử đảo ngược khi:
Z
là tiêu cực (đây là điều có ý nghĩa nhất đối với tôi)W
là âm (tôi không hiểu ý nghĩa của giá trị W âm)- Hoặc là
Z
hoặcW
là tiêu cực (những gì hiện đang làm việc hầu hết thời gian) Z
vàW
có dấu hiệu khác nhau, aka:Z / W < 0
(có ý nghĩa với tôi. Mặc dù vậy không hoạt động)
Nhưng vẫn chưa tìm thấy một cách nhất quán mà tất cả các điểm của tôi được chiếu chính xác.
Có ý kiến gì không?