Сказ о том, как я арктангенсы мучал
Попользовавшись своим маршировщиком лучей в деле, я пришёл к неутешительным выводам. В определённых сценариях, критически важных, компилятор генерирует просто тонну инструкций. И это всего то для четырёх фигур! Так шо принялся я сокращать и обобщать.
Эти фигуры и ещё бесконечное множество многоугольников можно построить всего через 3 функции:
- Формула для произвольного двумерного многоугольника, которую любезно сделали Иньиго Куилез и Александр Алексеев aka TDM. Особая прелесть в том, что за пределами фигуры изолинии плавные. Это позволяет её изящно скруглять операцией, внезапно, скругления.
- Функция для выдавливания. Тут ничего особенного не скажешь, просто вытягивает по третьей оси двумерную фигуру. Всё на том же пятиугольнике это отчётливо видно.
- Функция для... раскручивания? Её результат видно на четырёх фигурах справа. Конус - это треугольник, раскрученный вокруг своей оси. Тор - круг, раскрученный по определённому радиусу. Сфера - круг, раскрученный вокруг оси. Цилиндр тоже можно сделать через прямоугольник вокруг оси. Его вообще как угодно можно сделать, я по приколу выбрал выдавливание.
От себя ввёл понятие эксцентриситета для неравномерного масштабирования. Настолько не коряво, насколько мог. Потому что неравномерное масштабирование приводит к искажению нашего евклидового пространства для трассировщика, а это ухудшает его работу. С такими вещами нужно аккуратнее. Но на практике эллипсоиды и прочие вытянутые по одной оси фигуры нужны, деваться некуда.
И всё бы хорошо, но покоя не давала мне одна вещь: ёбаная тригонометрия
Любая обратная тригонометрия - вещь противная. В первую очередь потому, что аппаратной реализации для неё нет. И ваш арктангенс развёрнется в словах ассемблера на целую портянку. Вдвойне обидно, что atan2 или арктангенс с двумя переменными или atan y/x - вещь очень ходовая и избавиться от неё в коде бывает практически невозможно.
Но разве невозможное повод не ебаться? Конечно же, не повод! Итак, приступим.
Первая моя мысль была, что atan2 можно посчитать только в начале. А потом, зная направление движения и длину пути, прибавлять заранее вычисленное приращение. Конечно же, это не так работает для нелинейных функций, коей atan2, конечно же, является. Она ещё и кусочная, но это уже не так страшно:
Я же надеялся, что ошибка не будет слишком сильно накапливаться, если я постараюсь этого не допускать. Конечно же, она страшно накапливалась и где-то примерно половина изображения превращалась в неведомую кашу. Но половина была почти идеально точной, стоит сказать.
Тогда я пошёл с другого угла (ха, угол, арктангенс, поняли, да ну ведь поняли же...). Этот угол a нам нужен для определения синуса и косинуса. А как вы точно знаете, синус и косинус выражаются в векторной арифметике. Тут нам надо обратить внимание, что вообще такое есть арктангенс с двумя аргументами:
atan2 - угол между положительной полуосью x и лучём проведенным из начала координат в заданную точку.
Зная, что косинус зашифрован в скалярном произведении векторов, можно взять это произведение для точки p и положительной полуоси х(1, 0). p, само собой, нормализовать. Синус зашифрован в векторном произведении. И слегка изъебнувшись с тем, что векторное произведение трёхмерное, можно получить и его.
Но здесь можно пойти и дальше. Так как х(1, 0) фактически указывает на нулевой угол, а если говорить корректно, на полуось, нам ВООБЩЕ не надо выполнять с этим вектором никакие операции. Достаточно нормализовать вектор p и в его координатах уже будут зашифрованы косинус и синус. Это, к слову, можно заметить, если взять, например, скалярное произведение вручную. Так как одна ось нулевая, то результат будет равняться p.x*1+p.y*0 = p.x.
И всё это прекрасно работало бы, если бы у нас была формула atan2(p.y, p.x). Но внимательный читатель мог обратить внимание, что встречает нас уот такая вот хуйня:
То бишь, полученный в atan2 угол мы ещё много раз преобразуем. Это нужно для того, чтобы получить сектора граней многоугольника. Переменная sa как раз шифрует величину сектора 2π/N. Без подобных выкрутасов вместо произвольного многоугольника у нас будет обычный круг.
"И чем же всё кончилось!?" - спросит пытливый зритель. А нихуя это ничем не кончилось. Чтобы преобразовать сам угол, нам надо достать его из синуса/косинуса, то есть взять арксинус/арккосинус. Снова обратная тригонометрия, только с другой стороны, приплыли.
В общем, это заметка о пути, который сам оказался кругом. Было весело озадачиться, потраченного времени не жаль, такая вот разминка для ума на один вечер.