У меня есть рендеринг с использованием directx и openGL и 3d-сцены. Окно просмотра и окно имеют одинаковые размеры.Реализация Ray Picking
Как реализовать сбор данных координат мыши x и y независимо от платформы?
У меня есть рендеринг с использованием directx и openGL и 3d-сцены. Окно просмотра и окно имеют одинаковые размеры.Реализация Ray Picking
Как реализовать сбор данных координат мыши x и y независимо от платформы?
Если вы можете, сделайте выбор на процессоре, вычислив луч от глаза с помощью указателя мыши и пересечь его с вашими моделями.
Если это не вариант, я бы пошел с некоторым видом рендеринга ID. Назначьте каждый объект, который хотите выбрать уникальный цвет, визуализируйте объекты с этими цветами и, наконец, зачитайте цвет из фреймбуфера под указателем мыши.
EDIT: Если вопрос заключается в том, чтобы построить луч от координаты мыши вам необходимо следующее: проекционную матрицу P и камеры преобразования C. Если координаты указателя мыши (х, у) и размера окна просмотра является (ширина, высота) одно положения в усеченном пространстве вдоль луча:
mouse_clip = [
float(x) * 2/float(width) - 1,
1 - float(y) * 2/float(height),
0,
1]
(Обратите внимание, что I перебросил оси у, так как часто в начале координат мыши в верхнем левом углу)
следующая также верно:
mouse_clip = P * C * mouse_worldspace
Что дает:
mouse_worldspace = inverse(C) * inverse(P) * mouse_clip
Теперь у нас есть:
p = C.position(); //origin of camera in worldspace
n = normalize(mouse_worldspace - p); //unit vector from p through mouse pos in worldspace
Ну, довольно просто, теория за это всегда один и тот же
1) Unproject два раза ваших 2D координат на 3D-пространство. (каждый API имеет свою функцию, но вы можете реализовать свои собственные, если хотите). Один в Min Z, один в Max Z.
2) С помощью этих двух значений вычислить вектор, который идет от Min Z и точки к Max Z.
3) с вектором и точкой вычислить луч, который идет от Min Z до MaxZ
4) Теперь у вас есть луч, при этом вы можете сделать луч-треугольник/луч-плоскости/луча то пересечение и получить результат ...
у меня есть немного DirectX, но я уверен, что он похож на OpenGL. Вы хотите получить вызов gluUnproject.
Если у вас есть действительный буфер Z вы можете запросить содержимое буфера Z в положении мыши с:
// 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);
, если вы не хотите использовать Glu вы также можете реализовать gluUnProject вы могли также реализовать его самостоятельно, это функциональность относительно проста и описана в opengl.org
спасибо, хотя мне нужен API-метод агностики. –
@ Как я уже сказал, если вы не хотите использовать функцию glu, вы можете просто реализовать ее функциональность самостоятельно, все, что вам нужно, это получить представление модели и проекцию матрицы для каждого и получить положение окна z для каждого. – wich
, который потребует от меня выяснить тот же xyz, я мог бы затем опубликовать этот xyz и отметить это как ответ вместо этого, вы видите мои рассуждения? Кто-то еще разместил математику в любом случае –
Вот смотровое усеченный:
Прежде всего, необходимо определить, где на nearplane мышь нажмите произошло:
unview = (P * M).inverse() = M.inverse() * P.inverse()
, где M
- это матрица ModelView, а P
- матрица проекции.Затем определите, где находится камера в мировом пространстве, и нарисуйте луч, начинающийся с камеры, и проходящий через точку, найденную на ближайшей плоскости.
Камера находится в M.inverse().col(4)
, то есть в последнем столбце обратной матрицы ModelView.
Final псевдокод:
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
Что это за матрица modelView? Это комбинация матрицы modelToWorld модели, которую мы пытаемся ударить, и viewCatrix камеры? – Jubei
Прошло некоторое время с тех пор, как я написал это, но я думаю, что это матрица, которая преобразует мировые координаты в координаты камеры. Если в вашем вершинном шейдере есть строка, например 'gl_Position = projection * modelView * vertexPos;', это бит в середине, где матрица 'projection' - это перевод с камеры на координаты просмотра. HTH: / – nornagon
Хорошо, эта тема старая, но это было лучшее, что я нашел на эту тему, и это помогло мне немного, поэтому я выложу здесь для тех, кто следуют ;-)
Это способ, которым я получил его на работу без вычисления обратной матрицы проекции:
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;
}
Это предполагает перспективную проекцию, но вопрос никогда не возникает для го ортографический, в первую очередь.
У меня такая же ситуация с обычным выбором луча, но что-то не так. Я выполнил операцию unproject надлежащим образом, но он просто не работает. Думаю, я ошибся, но не могу понять, где. Мое умножение matix, обратное и векторное умножение matix все видели, чтобы работать нормально, я их протестировал. В моем коде я реагирую на WM_LBUTTONDOWN. Поэтому lParam возвращает [Y] [X] координаты как 2 слова в dword. Я извлекаю их, а затем конвертирую в нормализованное пространство, я проверил эту часть, также отлично работает. Когда я нажимаю левый нижний угол - я получаю близкие значения -1 -1 и хорошие значения для всех трех других углов. Затем я использую массив linepoins.vtx для отладки, и это даже не близко к реальности.
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;
Я знаю это! вопрос в том, как !!!! –
@Tom Это не совсем ясно из вопроса. В любом случае, я отредактировал свой ответ, надеюсь, что это поможет. –
Стоит отметить, что если вы используете DirectX-подобные матрицы, то порядок умножения меняется на противоположный. – Goz