У меня есть сфера в Godot, к которой я применяю fragment shader.
Сейчас я смотрю, есть ли пересечение с прямой из камеры со сферой или нет, в зависимости от этого я раскрашиваю сферу.
Идея реализации состоит в том, чтобы задать точку (камеру) и её направление как параметрическую прямую вида:
x = t * ray_direction.x + ray_origin.x
y = t * ray_direction.y + ray_origin.y
z = t * ray_direction.z + ray_origin.z
После чего подставить это в уравнение сферы и решить относительно t:
t^2 * (ray_direction.x ^ 2 + ray_direction.y ^ 2 + ray_direction.z ^ 2) + 2 * t * (ray_direction.x * ray_origin.x + ray_direction.y * ray_origin.y + ray_direction.z * ray_origin.z) + (ray_origin.x ^ 2 + ray_origin.y ^ 2 + ray_origin.z ^ 2) - r^2 = 0
Вот итоговый код шейдера:
shader_type spatial;
render_mode world_vertex_coords, unshaded;
uniform vec3 sphere_center = vec3(0.0);
uniform float sphere_radius = 1.0;
struct Segment {
bool was_init;
vec3 start_point;
vec3 end_point;
};
Segment get_intersection(vec3 ray_origin, vec3 ray_direction) {
Segment result;
result.was_init = false;
float b = 2.0 * dot(ray_origin, ray_direction);
float c = dot(ray_origin, ray_origin) - pow(sphere_radius, 2.0);
float discrim = pow(b, 2.0) - 4.0 * c;
if (discrim >= 0.0) {
float t_0 = (-b - sqrt(discrim)) / 2.0;
float t_1 = (-b + sqrt(discrim)) / 2.0;
// Retrun to global coords
result.start_point = ray_direction * t_0 + ray_origin + sphere_center;
result.end_point = ray_direction * t_1 + ray_origin + sphere_center;
result.was_init = true;
}
return result;
}
void fragment() {
vec3 ray_origin = CAMERA_POSITION_WORLD;
vec3 ray_direction = normalize(VERTEX - ray_origin);
Segment data = get_intersection(
ray_origin - sphere_center,
ray_direction
);
if (!data.was_init) {
ALBEDO = vec3(0.0, 0.0, 1.0);
} else {
ALBEDO = vec3(1.0, 0.0, 0.0);
}
ALPHA = 1.0;
}
Однако я получаю неверный результат:
Ещё я заметил, что по какой-то причине, результат меняется от различного положения камеры и дистанции до сферы. Чего, по логике моей программы, происходить не должно.
задан 29 окт. 2025 в 18:48
Evil Giraffe
1101 золотой знак1 серебряный знак10 бронзовых знаков
-
¿А какой результат ожидается? ¿Вся красная или вся белая сфера или что-то еще?user7860670– user78606702025年10月29日 18:53:57 +00:00Commented 29 окт. 2025 в 18:53
-
@user7860670 Я хотел протестировать код и красить вершины сферы в красный, если луч, выпущенный из камеры в сторону этой вершины пересекает сферу. Как вы понимаете, в данном примере вся сфера должна стать красной, но в результате происходит что-то непредвиденное.Evil Giraffe– Evil Giraffe2025年10月29日 18:57:07 +00:00Commented 29 окт. 2025 в 18:57
-
Вам нужно проверить факт попадания прямой в сферу или найти точку пересечения?MBo– MBo2025年10月29日 19:13:34 +00:00Commented 29 окт. 2025 в 19:13
-
@MBo В будущем мне потребуются точки пересечения (я уже нахожу их), но сейчас я проверяю факт попадания прямой в сферу и уже не справляюсь.Evil Giraffe– Evil Giraffe2025年10月29日 19:17:04 +00:00Commented 29 окт. 2025 в 19:17
-
Вот как можно попроще проверить: ru.stackoverflow.com/a/921657/291659 ( Dot(pr, pr) сравнивать с квадратом радиуса сферы)MBo– MBo2025年10月29日 19:19:49 +00:00Commented 29 окт. 2025 в 19:19
Знаете кого-то, кто может ответить? Поделитесь ссылкой на этот вопрос по почте, через Твиттер или Facebook.
Начните задавать вопросы и получать на них ответы
Найдите ответ на свой вопрос, задав его.
Задать вопросdefault