Вот подход, который я успешно использовал для огромного количества объектов. (Специально для атомных моделей с шариковой ручкой; см. Мою страницу пользователя в Википедии для уравнений, которые я использовал для них.)
Сначала преобразуйте объекты в систему координат, где глаз находится в начале координат, и проецируемая плоскость параллельна плоскости xy с центром на положительной оси z. Это значительно упрощает необходимые уравнения, как вы можете видеть на приведенной выше странице.
Например, если у вас есть единичный луч n (т. Е. n · n = 1) и сфера радиуса r с центром в c , луч пересекает сферу тогда и только тогда, когда h ≥ 0,
ч = ( n · c ) 2 + r 2 - ( c · c )
и если да, то на расстоянии d ,
d = n · c ± sqrt ( h )
Если вы разработаете необходимый код и используете разумные временные переменные, вы увидите, что вы можете отклонять непересекающиеся сферы, используя восемь умножений и шесть сложений или вычитаний, и что это легко векторизуется по объектам с использованием встроенных функций SSE2 / AVX. (#include <x86intrin.h>
). (То есть не пытайтесь использовать векторный регистр XMM / YMM для n или c , и вместо этого используйте каждый компонент регистра для другого объекта, вычисляя ч для 2/4/8 объектов одновременно.)
Для каждого луча сортируйте / выбирайте объекты для тестирования в соответствии с их известной минимальной координатой z (скажем, c z - r для сфер). Таким образом, когда вы найдете пересечение на расстоянии d , вы можете игнорировать все объекты с минимальной координатой z, превышающей d , потому что точка пересечения обязательно будет дальше, за уже известное пересечение.
Аналогично, вы должны игнорировать все пересечения, где расстояние меньше, чем расстояние до плоскости проекции (а это z d / n z , если плоскость имеет значение z = z d и нужно вычислять только один раз на луч), потому что эти пересечения находятся между глазом и плоскостью проекции. (Технически, тогда вы «врезались» во что-то, если думать о плоскости проекции как о камере.)