Я пытаюсь выполнить наведение луча по щелчку мыши с возможной целью найти точку столкновения с плоскостью. Однако я не могу создать луч. Мир визуализируется с использованием усеченного конуса и другой матрицы, которую я использую в качестве камеры, в порядке усеченного конуса * camera * vertex_position. С верхним левым краем экрана 0,0 я могу получить X, Y клика в пикселях. Затем я использую приведенный ниже код для преобразования этого луча:
float x = (2.0f * x_screen_position) / width - 1.0f;
float y = 1.0f - (2.0f * y_screen_position) / height;
Vector4 screen_click = Vector4 (x, y, 1.0f, 1.0f);
Vector4 ray_origin_world = get_camera_matrix() * screen_click;
Vector4 tmp = (inverse(get_view_frustum()) * screen_click;
tmp = get_camera_matrix() * tmp;
Vector4 ray_direction = normalize(tmp);
матрица view_frustum:
Matrix4 view_frustum(float angle_of_view, float aspect_ratio, float z_near, float z_far) {
return Matrix4(
Vector4(1.0/tan(angle_of_view), 0.0, 0.0, 0.0),
Vector4(0.0, aspect_ratio/tan(angle_of_view), 0.0, 0.0),
Vector4(0.0, 0.0, (z_far+z_near)/(z_far-z_near), 1.0),
Vector4(0.0, 0.0, -2.0*z_far*z_near/(z_far-z_near), 0.0)
);
}
Когда матрица «камеры» имеет значение 0,0,0, это дает ожидаемые результаты, однако, как только я перехожу на фиксированное положение камеры в другом месте, возвращаемые результаты вообще не верны. Фиксированная «камера» матрицы:
Matrix4(
Vector4(1.0, 0.0, 0.0, 0.0),
Vector4(0.0, 0.70710678118, -0.70710678118, 0.000),
Vector4(0.0, 0.70710678118, 0.70710678118, 0.0),
Vector4(0.0, 8.0, 20.0, 1.000)
);
Поскольку многие примеры, которые я нашел в Интернете, не реализуют камеру таким образом, я не могу найти много информации, чтобы помочь в этом случае. Кто-нибудь может предложить какое-либо понимание этого или указать мне в лучшем направлении?
Vector4 tmp = (inverse(get_view_frustum() * get_camera_matrix()) * screen_click; //take the inverse of the camera matrix as well
tmp /= tmp.w; //homogeneous coordinate "normalize" (different to typical normalization), needed with perspective projection or non-linear depth
Vector3 ray_direction = normalize(Vector3(tmp.x, tmp.y, tmp.z)); //make sure to normalize just the direction without w
Более длинный и похожий пост здесь: https://stackoverflow.com/a/20143963/1888983
Если у вас есть только матрицы, следует использовать начальную точку и точку в направлении луча. Для этого обычно используют точки в ближней и дальней плоскостях (преимущество заключается в том, что вы хотите, чтобы луч пересекал только видимые объекты). То есть,
(х, у, -1, 1) в (х, у, 1, 1)
Эти точки находятся в нормированных координатах устройства (NDC, от -1 до 1 куба, который является вашим объемом просмотра). Все, что вам нужно сделать, это переместить обе точки в мировое пространство и нормализовать …
ndcPoint4 = /* from above */;
eyespacePoint4 = inverseProjectionMatrix * ndcPoint4;
worldSpacePoint4 = inverseCameraMatrix * eyespacePoint4;
worldSpacePoint3 = worldSpacePoint4.xyz / worldSpacePoint4.w;
//alternatively, with combined matrices
worldToClipMatrix = projectionMatrix * cameraMatrix; //called "clip" space before normalization
clipToWorldMatrix = inverse(worldToClipMatrix);
worldSpacePoint4 = clipToWorldMatrix * ndcPoint4;
worldSpacePoint3 = worldSpacePoint4.xyz / worldSpacePoint4.w;
//then for the ray, after transforming both start/end points
rayStart = worldPointOnNearPlane;
rayEnd = worldPointOnFarPlane;
rayDir = rayEnd - rayStart;
Если у вас есть положение камеры в мировом пространстве, вы можете опустить либо начальную, либо конечную точку, поскольку все лучи проходят через точку начала камеры.
Других решений пока нет …