2

У меня есть сфера в 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;
}

Однако я получаю неверный результат:

Иллюстрация проблемы 1

Ещё я заметил, что по какой-то причине, результат меняется от различного положения камеры и дистанции до сферы. Чего, по логике моей программы, происходить не должно.

Иллюстрация проблемы 2

задан 29 окт. 2025 в 18:48
9
  • ¿А какой результат ожидается? ¿Вся красная или вся белая сфера или что-то еще? Commented 29 окт. 2025 в 18:53
  • @user7860670 Я хотел протестировать код и красить вершины сферы в красный, если луч, выпущенный из камеры в сторону этой вершины пересекает сферу. Как вы понимаете, в данном примере вся сфера должна стать красной, но в результате происходит что-то непредвиденное. Commented 29 окт. 2025 в 18:57
  • Вам нужно проверить факт попадания прямой в сферу или найти точку пересечения? Commented 29 окт. 2025 в 19:13
  • @MBo В будущем мне потребуются точки пересечения (я уже нахожу их), но сейчас я проверяю факт попадания прямой в сферу и уже не справляюсь. Commented 29 окт. 2025 в 19:17
  • Вот как можно попроще проверить: ru.stackoverflow.com/a/921657/291659 ( Dot(pr, pr) сравнивать с квадратом радиуса сферы) Commented 29 окт. 2025 в 19:19

0

Знаете кого-то, кто может ответить? Поделитесь ссылкой на этот вопрос по почте, через Твиттер или Facebook.

Ваш ответ

Черновик сохранён
Черновик удалён

Зарегистрируйтесь или войдите

Регистрация через Google
Регистрация через почту

Отправить без регистрации

Необходима, но никому не показывается

Отправить без регистрации

Необходима, но никому не показывается

Нажимая «Отправить ответ», вы соглашаетесь с условиями пользования и подтверждаете, что прочитали политику конфиденциальности.

Начните задавать вопросы и получать на них ответы

Найдите ответ на свой вопрос, задав его.

Задать вопрос

Изучите связанные вопросы

Посмотрите похожие вопросы с этими метками.