2010-01-19 25 views
30

Tôi có trình kết xuất đồ họa bằng directx và openGL và cảnh 3d. Khung nhìn và cửa sổ có cùng kích thước.Thực hiện Chọn Ray

Làm cách nào để triển khai chọn các tọa độ chuột cho x và y theo cách độc lập trên nền tảng?

Trả lời

27

Nếu bạn có thể, hãy chọn trên CPU bằng cách tính một tia từ mắt qua con trỏ chuột và cắt nó với các kiểu máy của bạn.

Nếu đây không phải là tùy chọn, tôi sẽ thực hiện với một số loại hiển thị ID. Chỉ định từng đối tượng bạn muốn chọn một màu duy nhất, hiển thị các đối tượng bằng các màu này và cuối cùng đọc ra màu từ bộ đệm khung bên dưới con trỏ chuột.

EDIT: Nếu câu hỏi là làm thế nào để xây dựng các tia từ tọa độ chuột bạn cần như sau: một ma trận chiếu P và camera chuyển C. Nếu tọa độ của con trỏ chuột là (x, y) và kích thước của khung nhìn là (chiều rộng, chiều cao) một vị trí trong không gian kẹp dọc theo ray là:

mouse_clip = [ 
    float(x) * 2/float(width) - 1, 
    1 - float(y) * 2/float(height), 
    0, 
    1] 

(Chú ý rằng tôi lật trục y kể từ thường nguồn gốc của các tọa độ chuột là ở góc trên bên trái)

sau đây cũng là đúng:

mouse_clip = P * C * mouse_worldspace 

Mà cho:

mouse_worldspace = inverse(C) * inverse(P) * mouse_clip 

Bây giờ chúng ta có:

p = C.position(); //origin of camera in worldspace 
n = normalize(mouse_worldspace - p); //unit vector from p through mouse pos in worldspace 
+0

Tôi biết điều đó! câu hỏi là thế nào !!!! –

+3

@Tom Đó không phải là hoàn toàn rõ ràng từ câu hỏi. Dù sao, tôi đã chỉnh sửa câu trả lời của tôi, hy vọng đó là một số trợ giúp. –

+0

Cần lưu ý rằng nếu bạn sử dụng ma trận DirectX giống nhau thì thứ tự nhân được đảo ngược. – Goz

1

Vâng, khá đơn giản, lý thuyết đằng sau này luôn luôn là như nhau

1) Unproject hai lần phối hợp 2D của bạn vào không gian 3D. (mỗi API có chức năng riêng của nó, nhưng bạn có thể thực hiện chức năng của riêng mình nếu bạn muốn). Một lúc Min Z, một ở Max Z.

2) Với hai giá trị tính toán vector mà đi từ Min Z và trỏ đến Max Z.

3) Với các vector và một điểm tính toán ray mà đi từ Min Z để MaxZ

4) Bây giờ bạn có một tia, với điều này bạn có thể làm một tia-tam giác/ray-plane/ray-một cái gì đó ngã và nhận được kết quả của bạn ...

1

tôi có chút Trải nghiệm DirectX, nhưng tôi chắc rằng nó tương tự như OpenGL. Những gì bạn muốn là cuộc gọi gluUnproject.

Giả sử bạn có một bộ đệm Z có giá trị bạn có thể truy vấn các nội dung của bộ đệm Z ở một vị trí chuột với:

// obtain the viewport, modelview matrix and projection matrix 
// you may keep the viewport and projection matrices throughout the program if you don't change them 
GLint viewport[4]; 
GLdouble modelview[16]; 
GLdouble projection[16]; 
glGetIntegerv(GL_VIEWPORT, viewport); 
glGetDoublev(GL_MODELVIEW_MATRIX, modelview); 
glGetDoublev(GL_PROJECTION_MATRIX, projection); 

// obtain the Z position (not world coordinates but in range 0 - 1) 
GLfloat z_cursor; 
glReadPixels(x_cursor, y_cursor, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &z_cursor); 

// obtain the world coordinates 
GLdouble x, y, z; 
gluUnProject(x_cursor, y_cursor, z_cursor, modelview, projection, viewport, &x, &y, &z); 

nếu bạn không muốn sử dụng Glu bạn cũng có thể thực hiện các gluUnProject bạn có thể cũng thực hiện nó cho mình, đó là chức năng là tương đối đơn giản và được mô tả tại opengl.org

+0

cảm ơn, mặc dù Id cần một phương pháp thuyết bất khả tri API là có thể –

+0

@Tom như tôi đã nói, nếu bạn không muốn sử dụng hàm glu, bạn chỉ có thể thực hiện chức năng của nó, tất cả những gì bạn cần là lấy mô hình và chiếu ma trận cho mỗi và có được vị trí cửa sổ z cho mỗi. – wich

+0

sẽ yêu cầu tôi tìm ra cùng xyz, sau đó tôi có thể đăng xyz đó và đánh dấu đó là câu trả lời thay vì câu trả lời này, bạn thấy lý do của tôi không? Ai đó đã đăng toán anyways –

20

đây là hình cụt xem:

viewing frustum

.210

Trước tiên, bạn cần phải xác định nơi trên nearplane nhấp chuột đã xảy ra:

  1. rescale tọa độ cửa sổ (0..640,0..480) để [-1,1], với (-1 , -1) ở góc dưới bên trái và (1,1) ở trên cùng bên phải.
  2. 'hoàn tác' phép chiếu bằng cách nhân các toạ độ được chia tỷ lệ với những gì tôi gọi là ma trận 'chưa xem': unview = (P * M).inverse() = M.inverse() * P.inverse(), trong đó M là ma trận ModelView và P là ma trận chiếu.

Sau đó xác định vị trí của máy ảnh trong không gian thế giới và vẽ một tia bắt đầu từ máy ảnh và đi qua điểm bạn tìm thấy trên máy bay gần.

Máy ảnh ở M.inverse().col(4), tức là cột cuối cùng của ma trận ModelView nghịch đảo.

giả cuối cùng:

normalised_x = 2 * mouse_x/win_width - 1 
normalised_y = 1 - 2 * mouse_y/win_height 
// note the y pos is inverted, so +y is at the top of the screen 

unviewMat = (projectionMat * modelViewMat).inverse() 

near_point = unviewMat * Vec(normalised_x, normalised_y, 0, 1) 
camera_pos = ray_origin = modelViewMat.inverse().col(4) 
ray_dir = near_point - camera_pos 
+0

ma trận "modelView" mà bạn tham chiếu là gì? Đó có phải là sự kết hợp của ma trận modelToWorld của mô hình mà chúng tôi đang cố gắng truy cập và chế độ xemMatrix của máy ảnh không? – Jubei

+1

Đã một thời gian kể từ khi tôi viết bài này, nhưng tôi nghĩ đó là ma trận biến đổi tọa độ thế giới thành các tọa độ camera. Nếu có một dòng trong bóng đổ đỉnh của bạn như 'gl_Position = projection * modelView * vertexPos;', đó là bit ở giữa, nơi ma trận 'chiếu' là bản dịch từ máy ảnh đến tọa độ khung nhìn. HTH: / – nornagon

0

Ok, chủ đề này là cũ nhưng nó là tốt nhất mà tôi tìm thấy về chủ đề này, và nó đã giúp tôi một chút, vì vậy tôi sẽ đăng ở đây cho những người đang đang theo dõi ;-)

Đây là cách tôi đã nhận nó để làm việc mà không cần phải tính toán nghịch đảo của ma trận chiếu:

void Application::leftButtonPress(u32 x, u32 y){ 
    GL::Viewport vp = GL::getViewport(); // just a call to glGet GL_VIEWPORT 
vec3f p = vec3f::from(      
     ((float)(vp.width - x)/(float)vp.width), 
     ((float)y/(float)vp.height), 
      1.); 
    // alternatively vec3f p = vec3f::from(      
    //  ((float)x/(float)vp.width), 
    //  ((float)(vp.height - y)/(float)vp.height), 
    //  1.); 

    p *= vec3f::from(APP_FRUSTUM_WIDTH, APP_FRUSTUM_HEIGHT, 1.); 
    p += vec3f::from(APP_FRUSTUM_LEFT, APP_FRUSTUM_BOTTOM, 0.); 

    // now p elements are in (-1, 1) 
    vec3f near = p * vec3f::from(APP_FRUSTUM_NEAR); 
    vec3f far = p * vec3f::from(APP_FRUSTUM_FAR); 

    // ray in world coordinates 
    Ray ray = { _camera->getPos(), -(_camera->getBasis() * (far - near).normalize()) }; 

    _ray->set(ray.origin, ray.dir, 10000.); // this is a debugging vertex array to see the Ray on screen 

    Node* node = _scene->collide(ray, Transform()); 
    cout << "node is : " << node << endl; 
} 

này giả định một chiếu phối cảnh, nhưng câu hỏi không bao giờ phát sinh cho th e chính tả một trong những nơi đầu tiên.

0

Tôi có tình huống tương tự với việc chọn tia thông thường, nhưng có điều gì đó sai. Tôi đã thực hiện các hoạt động unproject một cách thích hợp, nhưng nó chỉ không hoạt động. Tôi nghĩ, tôi đã phạm một số sai lầm, nhưng không thể tìm ra nơi. Phép nhân matix, nghịch đảo và vectơ của tôi bằng các phép nhân matix tất cả được xem là hoạt động tốt, tôi đã thử nghiệm chúng. Trong mã của tôi, tôi đang phản ứng trên WM_LBUTTONDOWN. Vì vậy, lParam trả về [Y] [X] tọa độ thành 2 từ trong một từ. Tôi trích xuất chúng, sau đó chuyển đổi sang không gian chuẩn hóa, tôi đã kiểm tra phần này cũng hoạt động tốt. Khi tôi nhấp vào góc dưới bên trái - Tôi nhận được các giá trị gần -1 -1 và các giá trị tốt cho cả 3 góc khác. Tôi sau đó sử dụng mảng linepoins.vtx để gỡ lỗi và nó thậm chí không gần với thực tế.

unsigned int x_coord=lParam&0x0000ffff; //X RAW COORD 
unsigned int y_coord=client_area.bottom-(lParam>>16); //Y RAW COORD 

double xn=((double)x_coord/client_area.right)*2-1; //X [-1 +1] 
double yn=1-((double)y_coord/client_area.bottom)*2;//Y [-1 +1] 

_declspec(align(16))gl_vec4 pt_eye(xn,yn,0.0,1.0); 
gl_mat4 view_matrix_inversed; 
gl_mat4 projection_matrix_inversed; 
cam.matrixProjection.inverse(&projection_matrix_inversed); 
cam.matrixView.inverse(&view_matrix_inversed); 

gl_mat4::vec4_multiply_by_matrix4(&pt_eye,&projection_matrix_inversed); 
gl_mat4::vec4_multiply_by_matrix4(&pt_eye,&view_matrix_inversed); 

line_points.vtx[line_points.count*4]=pt_eye.x-cam.pos.x; 
line_points.vtx[line_points.count*4+1]=pt_eye.y-cam.pos.y; 
line_points.vtx[line_points.count*4+2]=pt_eye.z-cam.pos.z; 
line_points.vtx[line_points.count*4+3]=1.0; 
Các vấn đề liên quan