Godot Fragment Shader Intersection

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


Ответы (0 шт):