Làm thế nào để tôi chiếu chính xác một điểm phía sau camera?


10

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:

Markers trông tuyệt vời

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:

Markers trông thậm chí còn tuyệt vời hơn

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 đánh dấu không quá tuyệt vời

(Đ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):

Markers một nửa tuyệt vờ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à Zhoặc Wlà tiêu cực (những gì hiện đang làm việc hầu hết thời gian)
  • ZWcó 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?

Câu trả lời:


2

Làm thế nào về việc làm nó một chút khác nhau?

Bắt đầu như bình thường và hiển thị tất cả các điểm đánh dấu trong chế độ xem. Nếu một điểm đánh dấu nằm ngoài khung nhìn - hãy tiến hành:

  1. Nhận vị trí của điểm đánh dấu A
  2. Nhận vị trí của máy ảnh B(có thể hơi ở phía trước của nó)
  3. Tính toán vectơ 3D ABgiữa hai
  4. Chuyển đổi và chuẩn hóa vectơ đó thành giới hạn màn hình 2D ( Asẽ ở giữa chế độ xem và Bsẽ chạm vào viền xem)

nhập mô tả hình ảnh ở đây

Đường màu là ABvectơ. Đường màu đen mỏng là chiều cao nhân vật. Bên phải là màn hình 2D

  1. Có thể thêm một quy tắc, rằng mọi thứ phía sau máy ảnh luôn đi về cạnh dưới
  2. Vẽ điểm đánh dấu trong không gian màn hình liên quan đến kích thước điểm đánh dấu và chồng chéo

Bạn có thể cần thử điều đó để xem liệu điểm đánh dấu tắt chế độ xem sẽ nhảy giữa các vị trí. Nếu điều đó xảy ra, bạn có thể thử nới lỏng vị trí khi điểm đánh dấu tiếp cận đường viền của khung nhìn.


Chính xác thì bước 4 đó hoạt động như thế nào?
Panda Pyjama

@PandaPajama: Tôi đã thêm một chút vào câu trả lời. Bây giờ thì rõ hơn chưa?
Kromster

Không hẳn vậy. Làm thế nào bạn "chuyển đổi và bình thường hóa" vector? Nếu đó là bằng cách áp dụng ma trận chiếu, thì bạn đang làm điều tương tự tôi đang làm
Panda Pajama

@PandaPajama: Theo như tôi hiểu thì bạn đang làm việc đó trong không gian máy ảnh (do đó là vấn đề ZW tiêu cực). Tôi đề nghị làm điều đó trong không gian thế giới và chỉ sau đó chuyển đổi sang không gian màn hình.
Kromster

Nhưng, bằng cách tính toán AB, tôi không chuyển đổi vị trí mục tiêu từ tọa độ thế giới sang tọa độ camera?
Panda Pyjama

1

Cho ba vectơ [camera position], [camera direction][object position]. Tính sản phẩm chấm của [camera direction][object position]-[camera position]. Nếu kết quả là âm tính, đối tượng ở phía sau camera.

Cho rằng tôi hiểu mã của bạn đúng, nó sẽ là:

if((PositionX - Camera.PositionX) * Camera.LookAtX
    + (PositionY - Camera.PositionY) * Camera.LookAtY
    + (PositionZ - Camera.PositionZ) * Camera.LookAtZ
    < 0)

YPositionY + (y * Scaling). Tôi sẽ thử nó tối nay
Panda Pajama

Với điều này, tôi thực sự có thể biết khi nào điểm nằm phía sau camera. Tuy nhiên, điều này không ngăn cản phép chiếu đạt điểm kỳ dị tại Z = 0.
Panda Pajama

@PandaPajama Đó có phải là một vấn đề thực tế? Xác suất Zchính xác 0là rất nhỏ, hầu hết người chơi sẽ không bao giờ trải nghiệm điều đó, và tác động chơi trò chơi trong một vài trường hợp dự kiến ​​là một trục trặc hình ảnh khung hình không đáng kể. Tôi muốn nói rằng thời gian của bạn tốt hơn dành ở nơi khác.
aaaaaaaaaaaa

0

Chỉ kiểm tra (dự kiến.W <0), không (Z <0 | | W <0).

Trong một số công thức không gian clip ( ho OpenGL ho ), phạm vi hiển thị bao gồm các giá trị Z dương và âm, trong khi W luôn dương trước camera và âm phía sau.


Tôi đã thử chỉ với W <0, nhưng vẫn có những nơi được chiếu không chính xác.
Panda Pyjama

0
float screenX = (((projectedVector.X / abs(projectedVector.W)) + 1.0f) / 2.0f) * viewportWidth;
float screenY = ((1.0f - (projectedVector.Y / abs(projectedVector.W))) / 2.0f) * viewportHeight;

Và loại bỏ phần này

// Invert X and Y when behind the camera
if (projectedVector.Z < 0 || projectedVector.W < 0)
{
    screenX = -screenX;
    screenY = -screenY;
}

-2

Hãy thử một bảng quảng cáo, nó sẽ tự động làm cho pic đối diện với máy ảnh và sẽ tự động vẽ pic lên màn hình ở vị trí thích hợp


3
Bạn đã đọc câu hỏi chưa?
Kromster

Xin lỗi, để tôi giải thích - Có thể lấy đầu ra của một bảng quảng cáo, loại bỏ tỷ lệ, (vì vậy nó là 2D nhưng tuân theo vị trí 3d), và sau đó giữ nó trong giới hạn của màn hình bằng cách sử dụng một số phép toán ma trận.
Michael Langford

Câu hỏi cụ thể là về "và sau đó giữ nó trong giới hạn của màn hình bằng một số phép toán ma trận "
Kromster
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.