У вас есть SDF и луч. Как найти, где луч упирается в поверхность? Самый очевидный ответ — идём вдоль луча маленькими шагами и проверяем, попали ли.
// плохо: фиксированный шаг
for (int i = 0; i < 1000; i++) {
if (sdf(p) < EPS) return p;
p += dir * 0.01;
}
И вот ловушка. Шаг маленький — тысячи итераций на пиксель, шейдер выдает 5 fps. Шаг большой — луч проскакивает сквозь тонкие объекты, артефакты по всей сцене. Компромисс «либо медленно, либо неточно». А хочется оба.
Собственно, в чём идея. SDF возвращает расстояние до ближайшей поверхности. Значит, можно шагнуть ровно на это расстояние — и гарантированно не пройти насквозь.
// хорошо: sphere tracing
for (int i = 0; i < 64; i++) {
float d = sdf(p);
if (d < EPS) return p;
p += dir * d; // ← шаг ровно SDF
}
Близко к поверхности шаги мелкие (поле говорит «осторожно, рядом»), в пустоте — большие («лети спокойно»). Обычно 30–60 итераций на всю сцену.
По сути, вся магия SDF держится именно на этой идее. Без sphere tracing формулы расстояний были бы просто красивой математикой без практического смысла.
#мат_геймдев #МатРазбор #шейдеры
