2010-01-19 36 views
16

Vì vậy, tôi đã một Plane 3D mô tả bởi 2 Vectors:Với một bề mặt bình thường, tìm luân chuyển cho 3D Plane

P: một điểm nằm trên Plane
N: bề mặt bình thường đối với các máy bay

Và tôi có một hình đa giác vuông, rất lớn, mà tôi muốn kết xuất để biểu diễn chiếc Máy bay này. Tôi có thể dễ dàng dịch đa giác đến điểm đã cho, nhưng sau đó tôi cần phải tìm xoay thích hợp để áp dụng để làm cho bề mặt bình thường thực sự là bề mặt bình thường.

Tôi đã thử một phương pháp nêu những nơi khác đó là:

1) Đi bất kỳ none vector song song (V) vào bình thường (N), và lấy sản phẩm chéo (W1)
2) Hãy sản phẩm chéo của (W1) và (N) bây giờ (W2) và đó là Vector (V ') nằm trên Plane

Sau đó tôi tạo ma trận xoay dựa trên (V') Máy bay, sao cho đa giác của tôi sẽ được căn chỉnh với (V '). đã làm việc, nhưng rõ ràng là phương pháp này không hoạt động chính xác như một tổng thể. Đa giác không vuông góc với bề mặt bình thường.

Bất kỳ ý tưởng nào về cách tạo vòng xoay phù hợp?

Trả lời

13

Một số điều hữu ích về phép quay:

  • Bất kỳ ba vectơ trực giao sắp xếp như hàng xác định một sự biến đổi thành một cơ sở mới (vòng xoay vào cơ sở đó).
  • Chuyển vị của bất kỳ phép quay nào là nghịch đảo của nó.
  • Vì vậy, bất kỳ ba vectơ trực giao nào được sắp xếp làm cột xác định một vòng quay từ cơ sở nào đó đến khung tham chiếu "thế giới" của bạn.

Vì vậy, vấn đề là tìm thấy bất kỳ bộ ba vectơ trực giao và sắp xếp chúng như

| x1 x2 x3 0 | 
| y1 y2 y3 0 | 
| z1 z2 z3 0 | 
| 0 0 0 1 | 

này là chính xác những gì phương pháp bạn mô tả cố gắng để làm, nếu nó không hoạt động sau đó là một vấn đề với việc triển khai của bạn. Chúng tôi rõ ràng có thể sử dụng bình thường của bạn như (x1, y1, z1), nhưng vấn đề là hệ thống có vô số giải pháp cho hai vectơ còn lại (mặc dù biết một trong số chúng cung cấp cho bạn cái kia, như sản phẩm chéo) . Các mã sau đây phải đưa ra một vector ổn định vuông góc với (x1, y1, z1):

float normal[3] = { ... }; 

int imin = 0; 
for(int i=0; i<3; ++i) 
    if(std::abs(normal[i]) < std::abs(normal[imin])) 
     imin = i; 

float v2[3] = {0,0,0}; 
float dt = normal[imin]; 

v2[imin] = 1; 
for(int i=0;i<3;i++) 
    v2[i] -= dt*normal[i]; 

này về cơ bản sử dụng Gram-Schmidt orthogonalisation với kích thước đó là đã trực giao nhất để vector bình thường.v3 có thể lấy được bằng cách lấy sản phẩm chéo của normalv2.

Bạn có thể cần phải cẩn thận thiết lập vòng xoay, đó là về nguồn gốc, do đó bạn cần áp dụng bản dịch sau khi xoay và nó dành cho vectơ cột thay vì vectơ hàng. Nếu bạn đang sử dụng đồng hồ OpenGL mà OpenGL lấy mảng theo thứ tự cột lớn (thay vì thứ tự lớn của hàng C), do đó bạn có thể cần phải chuyển vị trí.

Tôi sợ rằng tôi chưa thử nghiệm ở trên, tôi chỉ đơn thuần là nabbed nó từ một số mã tôi đã viết một lúc trước và thích nghi nó với vấn đề của bạn! Hy vọng rằng tôi đã không quên bất kỳ chi tiết nào.

Edit: tôi đã quên một cái gì đó :)

Ma trận trên giả bình thường của bạn để đa giác là dọc theo trục x, và tôi có một sự nghi ngờ tinh quái nó sẽ không thể được, tất cả các bạn cần làm là đặt vectơ "bình thường" vào cột chính xác của ma trận xoay và v2/v3 trong hai cột còn lại. Vì vậy, nếu bình thường đối với đa giác của bạn nằm dọc theo trục z, thì bình thường sẽ đi vào cột thứ 3 và v2/v3 sẽ nằm trong hai cột đầu tiên.

Xin lỗi nếu điều đó gây ra bất kỳ sự nhầm lẫn nào.

+2

Vì một lý do ngẫu nhiên tôi thấy mình xem lại câu trả lời này, khi tôi chọn kích thước trực giao nhất tôi nên đã sử dụng giá trị tuyệt đối của các thành phần vectơ bình thường - Tôi đã sửa lỗi này trong câu trả lời. –

+0

Điều gì xảy ra nếu bình thường không nằm dọc theo bất kỳ trục nào? Nếu, thay vào đó, nó giống như <1, 1, 1>? – Ren

+0

Thuật toán ánh xạ một tùy ý bình thường để nằm dọc theo một trong các trục (hoặc cách khác thông qua nghịch đảo), nếu bạn muốn xoay bình thường sang một giá trị bình thường khác, tôi sẽ tìm một vòng quay về sản phẩm chéo của hai chuẩn. –

2

Không chắc những gì phương pháp bạn đang sử dụng để render, nhưng vay từ OpenSceneGraph's matrix:

void Matrix_implementation::makeLookAt(const Vec3d& eye,const Vec3d& center,const Vec3d& up) 
{ 
    Vec3d f(center-eye); 
    f.normalize(); 
    Vec3d s(f^up); 
    s.normalize(); 
    Vec3d u(s^f); 
    u.normalize(); 

    set(
     s[0],  u[0],  -f[0],  0.0, 
     s[1],  u[1],  -f[1],  0.0, 
     s[2],  u[2],  -f[2],  0.0, 
     0.0,  0.0,  0.0,  1.0); 

    preMultTranslate(-eye); 
} 

inline void Matrixd::preMultTranslate(const Vec3d& v) 
{ 
    for (unsigned i = 0; i < 3; ++i) 
    { 
     double tmp = v[i]; 
     if (tmp == 0) 
      continue; 
     _mat[3][0] += tmp*_mat[i][0]; 
     _mat[3][1] += tmp*_mat[i][1]; 
     _mat[3][2] += tmp*_mat[i][2]; 
     _mat[3][3] += tmp*_mat[i][3]; 
    } 
} 

Hy vọng rằng điều này sẽ cung cấp cho bạn một ý tưởng để thực hiện của bạn. Tôi không giỏi với quaternions mà có thể có một giải pháp đơn giản hơn, nhưng phương pháp này hoạt động tốt cho tôi.

+0

Hhhmmm ... Vì vậy, điều này sẽ cung cấp ma trận xoay để trỏ máy ảnh tại một điểm cụ thể? Thích ứng với vấn đề của tôi, tôi sẽ cần một vector để xoay không? – Adam

+0

Điều này sẽ cung cấp cho một vòng quay cho máy ảnh, bạn cần vị trí mắt (vectơ cũng là vị trí trong OSG), vị trí trung tâm (P của bạn), và sau đó lên vector của bạn (N). Bạn nói rằng bạn cần phải làm cho bề mặt bình thường thực sự bề mặt bình thường và tôi không chắc chắn những gì bạn có nghĩa là do đó. Bạn có muốn nhìn thẳng vào tâm của mặt phẳng từ một điểm trên vectơ bình thường không? Nếu vậy, làm cho mắt của bạn vị trí một quy mô của bình thường hóa lên. P.S. bất cứ ai khác nghĩ rằng mọi người đều vui vẻ tên là Adam ở đây :) –

+0

Ya nó dường như là một tên phổ biến ở đây: P Xin lỗi nếu câu hỏi của tôi là khó hiểu, tôi không thực sự muốn làm bất cứ điều gì với máy ảnh của tôi. Tôi muốn xoay đa giác của mình sao cho Surface Normal của tôi, được tính ở một số nơi khác, giống như của Polygon (nếu tôi tính toán nó) – Adam

Các vấn đề liên quan