Làm cách nào tôi có thể quay camera về điểm mục tiêu?


18

Tôi đang vẽ một cảnh trong đó máy ảnh tự do di chuyển về vũ trụ. Lớp camera theo dõi điểm nhìn (hoặc nhìn vào ), vị trí của camera và vectơ lên. Các vectơ / điểm này sau đó được truyền vào gluLookAt.

Pan và zoom là gần như tầm thường để thực hiện. Tuy nhiên, tôi đang tìm kiếm xoay về nhìn vào điểm đến được nhiều hơn nữa của một vấn đề. Tôi muốn viết một chức năng Camera.rotate có 2 góc, một góc xoay lên / xuống và một góc xoay trái / phải dọc theo một quả cầu tưởng tượng tập trung vào điểm nhìn .

Có cách nào làm dễ hơn không?

Tôi (một thời gian ngắn) đã đọc về các quan điểm, nhưng tôi muốn xem liệu có một giải pháp dễ dàng hơn cho việc xây dựng cảnh tương đối đơn giản của tôi không.


Bạn có bất cứ thứ gì trong hộp công cụ của mình để xoay một điểm xung quanh gốc tọa độ, cho một trục và một góc không?
sam hocevar

Không có gì khác ngoài sự hiểu biết lỏng lẻo của tôi về Đệ tứ, không. Tôi càng nhìn vào điều này, tôi nghĩ rằng Đệ tứ có thể là câu trả lời. Tuy nhiên, tôi không chắc cách tính các giá trị trục x, y và z để sử dụng trong các công thức Đệ tứ.
Lu-ca

Tôi sẽ không nói với bạn rằng tứ phương không phải là con đường để đi. Họ là một giải pháp rất tốt cho vấn đề của bạn. Nhưng bạn sẽ cần một lớp bậc bốn và các cách để tương tác với GL và GLU, và tôi cảm thấy rằng trước tiên bạn nên thử làm quen với ma trận biến đổi. Những người khác có thể không đồng ý.
sam hocevar

xem xét thứ tự bạn thực hiện các phép quay. Áp dụng các phép quay để di chuyển vào không gian thế giới hoặc để di chuyển đến không gian máy ảnh khác nhau
Charlie

Câu trả lời:


25

Những gì bạn đang yêu cầu được gọi là xoay Arcball. Đệ tứ là giải pháp dễ dàng chỉ khi bạn hiểu cách chúng hoạt động. Bạn có thể đạt được điều tương tự mà không cần tứ phương.

Điều kiện tiên quyết

Bạn có biết làm thế nào để xoay đối tượng nói chung? Giả sử bạn có một đối tượng ở điểm gốc. Bạn có biết làm thế nào bạn xoay nó (gợi ý: nhân với một số ma trận xoay vòng)? Nếu có, thì tôi giả sử bạn biết điều gì sẽ xảy ra nếu bạn dịch đối tượng trước và sau đó xoay nó?

Bạn phải biết cách tính ma trận xoay từ trục góc (dễ như ăn bánh, nhìn vào vô số phương trình trực tuyến, rất nhiều trong số chúng cũng cung cấp cho bạn mã)

Dung dịch

  • Đưa máy ảnh lên và vectơ phải . Lưu ý rằng chúng nên được chuẩn hóa.
  • Lấy vector từ điểm lấy nét đến máy ảnh (camPocation - Lấy nét). Đây là vector mà bạn sẽ được quay. Hãy gọi đây là camF FocusVector .
  • Quyết định mức độ bạn muốn xoay trong ngáp / cao độ so với máy ảnh
  • Tạo hai ma trận quay. Ma trận xoay thứ 1 sẽ sử dụng góc lên của máy ảnh làm trục và góc ngáp mà bạn quyết định. Ma trận xoay 2 sẽ sử dụng đúng của máy ảnh như trục và sân góc mà bạn quyết định.
  • Bây giờ xoay camF FocusVector với ma trận xoay mới. Đây là vị trí mới của máy ảnh của bạn so với nguồn gốc. Tất nhiên, chúng tôi muốn nó liên quan đến điểm tập trung ...
  • Thêm vị trí điểm lấy nét vào camF FocusVector . Đây là vị trí mới của máy ảnh của bạn. Dịch máy ảnh của bạn cho phù hợp.
  • Cuối cùng, yêu cầu máy ảnh lấy nét vào điểm lấy nét bằng cách gọi hàm lookAt () của bạn

Hãy cẩn thận

Bạn sẽ phải tìm kiếm một số trường hợp hoặc điểm kỳ dị mà máy ảnh của bạn sẽ ngừng hoạt động. Nhìn thẳng xuống / lên chẳng hạn. Tôi sẽ cho bạn tìm ra cách đối phó với những điều đó.

EDIT1: Cách tính toán lại các vectơ trực giao của máy ảnh

Bạn đã biết hướng của máy ảnh ((cameraPos - FocusPoint) .n normalize ()). Bây giờ giả sử rằng máy ảnh của bạn lên là + Y (hoặc w / e trục hiện tại của thế giới của bạn là ... điều đó tùy thuộc vào bạn). Bây giờ chỉ cần vượt qua hướng với lên để có được quyền . Làm xong? Không! Vector lên của bạn không còn trực giao với hai cái kia. Để khắc phục điều đó, chéo đúng với hướng và bạn nhận mới của bạn lên .

Lưu ý rằng Gram-Schmidt thực sự là thứ nên được sử dụng để chỉnh hình vectơ.

Một lần nữa, hãy lưu ý các cảnh báo vì điều này sẽ không hoạt động trong một số trường hợp ( ví dụ như hướng song song với hướng lên ).


Lưu ý rằng vectơ phải có thể thu được bằng cách sử dụng normalize(up ^ camFocusVector)(hoặc ngược lại nếu thuận tay trái).
sam hocevar

Nhìn tốt cho đến nay, hoạt động tốt cho xoay trái / phải (Tôi có vectơ lên ​​rất dễ dàng). '^' Có nghĩa là gì trong bình luận của bạn @SamHocevar? Đó có phải là sản phẩm chéo? Ngoài ra, làm cách nào tôi có thể tính toán lại vectơ lên ​​sau khi tôi thực hiện các bản dịch?
Lu-ca

@Luke: Kiểm tra EDIT1 của tôi
Samaursa

1
@Samaursa Cảm ơn bạn rất nhiều. Giải pháp của bạn hoạt động hoàn hảo, và tôi đã học được rất nhiều trong quá trình!
Lu-ca

2
đây là một câu trả lời TUYỆT VỜI, cảm ơn bạn rất nhiều vì lời giải thích của bạn. Trong trường hợp của tôi, tôi muốn máy ảnh chỉ xoay về điểm mục tiêu trong mặt phẳng XY và vì vậy sau khi thực hiện tất cả các phép tính, tôi luôn đặt cameraRight.z thành 0 và sau đó tính toán vectơ cameraUp. Điều này đã cho hiệu quả mong muốn. Chỉ cần nghĩ đến việc chia sẻ
codemonkey

1

Những gì bạn cần là một camera ArcBall điển hình, về cơ bản là một camera giữ vị trí mục tiêu và cho phép bạn di chuyển camera theo cách "hình cầu" xung quanh mục tiêu đó.

Đó là trong XNA nhưng IIRC tôi đã sử dụng triển khai này trước đây và nó hoạt động khá tốt:

http://roy-t.nl/index.php/2010/02/21/xna-simple-arcballcamera/


Việc triển khai đó dường như chỉ di chuyển trực tiếp dọc theo vectơ bên phải, điều này sẽ xấp xỉ một cung tròn cho các giá trị nhỏ của số lượng . Anh ấy cũng di chuyển điểm LookAt, như nơi tôi muốn di chuyển máy ảnh (gần, nhưng khác biệt tinh tế). Tôi tin rằng Samaursa đã cung cấp cách hoàn thành đơn giản nhất để đạt được điều này.
Lu-ca

Cảm ơn phản hôi của bạn. Tôi phải thừa nhận rằng tôi đã sử dụng triển khai này một chút dưới dạng "hộp đen" nhưng tôi không nhận thấy bất kỳ vấn đề nào. Để làm rõ có lẽ bạn đang nói về các phương thức MoveCameraRight / MoveCameraForward? Những phương pháp đó đã được thêm vào để xoay camera xung quanh, nhưng không phải là một phần của giao diện Arcball. Nếu bạn muốn xoay camera xung quanh mục tiêu, bạn chỉ cần thay đổi thuộc tính Yaw hoặc Pitch.
David Gouveia

Xin lỗi, bạn nói đúng, đó là những phương pháp panning. Tôi không nhận thấy cách anh ta đặt cờ bẩn cho ma trận khi ngáp và cao độ được thay đổi.
Lu-ca

0

Đây là mã của tôi để xoay quanh một điểm, thấy mình sử dụng lại nó rất nhiều.

float distance;      // Straight line distance between the camera and look at point

// Calculate the camera position using the distance and angles
float camX = distance * -sinf(camAngleX*(M_PI/180)) * cosf((camAngleY)*(M_PI/180));
float camY = distance * -sinf((camAngleY)*(M_PI/180));
float camZ = -distance * cosf((camAngleX)*(M_PI/180)) * cosf((camAngleY)*(M_PI/180));

// Set the camera position and lookat point
gluLookAt(camX,camY,camZ,   // Camera position
          0.0, 0.0, 0.0,    // Look at point
          0.0, 1.0, 0.0);   // Up vector

1
Về cơ bản, đó là cách tôi đã làm ban đầu. Có nhiều vấn đề với việc làm theo cách này (ít nhất là đối với tôi). Về cơ bản việc thực hiện này chỉ xoay khoảng 2 trục cố định. Hãy nói rằng bạn xoay lên gần đến cực bắc . Sau đó xoay phải . Bạn sẽ thấy mình quay tròn trong một vòng tròn nhỏ thay vì đi theo vectơ bên phải của máy ảnh trên toàn cầu .
Lu-ca

Bây giờ bạn đã đề cập đến điều đó, tôi đoán có hai cách khác nhau để xem xét vấn đề. Trong ứng dụng của mình, tôi đã sử dụng máy ảnh ArcBall để xoay quanh một hòn đảo mục tiêu trên biển và nếu tôi sử dụng 3 trục tự do thì nó sẽ trông có vẻ không ổn (chẳng hạn như nhìn thấy hòn đảo lộn ngược hoặc nằm nghiêng).
David Gouveia

Làm thế nào để tôi có được các góc máy ảnh ở đây?
rafvasq

0

Thuật toán rất đơn giản này để đạt được điều đó thật tuyệt vời:

Là P điểm trung tâm về bạn muốn xoay (điểm "nhìn" hoặc "mục tiêu"):

translate(-P)

rotate horizontal
rotate vertical

translate(P)

Tôi đã sử dụng nó và tốt đẹp của nó.

Nguồn được tìm thấy tại stackoverflow chị em: /programming/287655/opengl-rotating-a-camera-around-a-point

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.