Начнём с объяснения, что же такое четырёхмерное пространство.


Это — одномерное пространство, то есть просто ось OX. Любая точка на ней характеризуется одной координатой.


Теперь проведём ось OY перпендикулярно оси OX. Вот и получилось двумерное пространство, то есть плоскость XOY. Любая точка на ней характеризуется двумя координатами — абсциссой и ординатой.


Проведём ось OZ перпендикулярно осям OX и OY. Получится трёхмерное пространство, в котором у любой точки есть абсцисса, ордината и аппликата.


Логично, что четвёртая ось, OQ, должна быть перпендикулярной осям OX, OY и OZ одновременно. Но мы не можем точно построить такую ось, и потому остаётся только попытаться представить её себе. У каждой точки в четырёхмерном пространстве есть четыре координаты: x, y, z и q.

Теперь посмотрим, как появился четырёхмерный куб.


На картинке изображена фигура одномерного пространства — линия.


Если сделать параллельный перенос этой линии вдоль оси OY, а потом соединить соответствующие концы двух получившихся линий, получится квадрат.


Аналогично, если сделать параллельный перенос квадрата вдоль оси OZ и соединить соответствующие вершины, то получится куб.


А если сделать параллельный перенос куба вдоль оси OQ и соединить вершины двух этих кубов, то мы получим четырёхмерный куб. Кстати, он называется тессеракт.

Чтобы нарисовать куб на плоскости, нужно его спроецировать. Наглядно это выглядит так:

Представим, что в воздухе над поверхностью висит каркасная модель куба, то есть как бы «сделанная из проволоки», а над ней — лампочка. Если включить лампочку, обвести карандашом тень от куба, а потом выключить лампочку, то на поверхности будет изображена проекция куба.

Перейдём к немного более сложному. Ещё раз посмотрите на рисунок с лампочкой: как видите, все лучи сошлись в одной точке. Она называется точкой схода и используется для построения перспективной проекции( а бывает и параллельная, когда все лучи параллельны друг другу. Результат — не создаётся ощущения объёма, но она легче, и при том если точка схода достаточно сильно удалена от проецируемо��о объекта, то разница между этими двумя проекциями мало заметна). Чтобы спроецировать данную точку на данную плоскость, используя точку схода, нужно провести прямую через точку схода и данную точку, а потом найти точку пересечения получившейся прямой и плоскости. А для того, чтобы спроецировать более сложную фигуру, скажем, куб, нужно спроецировать каждую его вершину, а потом соответствующие точки соединить. Следует заметить, что алгоритм проекции пространства на подпространство можно обобщить для случая 4D->3D, а не только 3D->2D.

Как я уже говорил, мы не можем себе точно представить, как выглядит ось OQ, равно как и тессеракт. Зато мы можем получить ограниченное представление о нём, если мы спроецируем его на объём, а потом нарисуем это на экране компьютера!

Теперь поговорим о проекции тессеракта.


Слева находится проекция куба на плоскость, а справа — тессеракта на объём. Они довольно схожи: проекция куба выглядит как два квадрата, маленький и большой, один внутри другого, и у которых соответствующие вершины соединены линиями. А проекция тессеракта выглядит как два куба, маленький и большой, один внутри другого, и у которых соответствующие вершины соединены. Но мы все видели куб, и можем с уверенностью сказать, что и маленький квадрат, и большой, и четыре трапеции сверху, снизу, справа и слева от маленького квадрата, на самом деле являются квадратами, при чём равными. И у тессеракта тоже самое. И большой куб, и маленький куб, и шесть усечённых пирамид по бокам от маленького куба — это всё кубы, при чём равные.

Моя программа умеет не только рисовать проекцию тессеракта на объём, а ещё и вращать его. Рассмотрим, как делается это.

Для начала я вам расскажу, что такое вращение параллельно плоскости.

Представьте себе, что куб вращается вокруг оси OZ. Тогда каждая из его вершин описывает окружность вокруг оси OZ.

А окружность — фигура плоская. И плоскости каждой из этих окружностей параллельны между собой, и в данном случае параллельны плоскости XOY. То есть мы можем говорить не только о вращении вокруг оси OZ, а ещё и о вращении параллельно плоскости XOY.Как видим, у точек, которые вращаются параллельно оси XOY меняются только абсцисса и ордината, аппликата же остаётся неизменной И, вообще-то, мы можем говорить о вращении вокруг прямой только тогда, когда имеем дело с трёхмерным пространством. В двумерном всё вращается вокруг точки, в четырёхмерном — вокруг плоскости, в пятимерном пространстве мы говорим о вращении вокруг объёма. И если вращение вокруг точки мы можем себе представить, то вращение вокруг плоскости и объёма — что-то немыслимое. А если будем говорить о вращении параллельно плоскости, то тогда в любом n-мерном пространстве точка может вращаться параллельно плоскости.

Многие из вас, вероятно, слышали о матрице поворота. Умножив точку на неё, получим точку, повёрнутую параллельно плоскости на угол фи. Для двумерного пространства она выглядит так:

Как умножать: икс точки, повёрнутой на угол фи = косинус угла фи*икс первоначальной точки минус синус угла фи*игрек первоначальной точки;
игрек точки, повёрнутой на угол фи=синус угла фи*икс первоначальной точки плюс косинус угла фи*игрек первоначальной точки.
Xa`=cosф*Xa — sinф*Ya
Ya`=sinф*Xa + cosф*Ya
, где Xa и Ya — абсцисса и ордината точки, которую нужно повернуть, Xa` и Ya` — абсцисса и ордината уже повёрнутой точки

Для трёхмерного пространства это матрица обобщается следующим образом:

Вращение параллельно плоскости XOY. Как видим, координата Z не меняется, а меняются только X и Y
Xa`=cosф*Xa — sinф*Ya + Za*0
Ya`=sinф*Xa +cosф*Ya + Za*0
Za`=Xa*0 + Ya*0 + Za*1 (по сути, Za`=Za)


Вращение параллельно плоскости XOZ. Ничего нового,
Xa`=cosф*Xa + Ya*0 — sinф*Za
Ya`=Xa*0 + Ya*1 + Za*0 (по сути, Ya`=Ya)
Za`=sinф*Xa + Ya*0 + cosф*Za


И третья матрица.
Xa`=Xa*1 + Ya*0 + Za*0 (по сути, Xa`=Xa)
Ya`=Xa*0 + cosф*Ya — sinф*Za
Za`=Xa*0 + sinф*Ya + cosф*Za

А для четвёртого измерения они выглядят вот так:

Думаю, вы уже поняли, что на что множить, потому лишний раз расписывать не буду. Зато замечу, что она делает то же самое, что и матрица для поворота параллельно плоскости в трёхмерном пространстве! И та, и эта изменяют только ординату и аппликату, а остальные координаты не трогают, потому её можно использовать и в трёхмерном случае, просто не обращая внимания на четвёртую координату.

А вот с формулой проекции не всё так просто. Сколько я ни читал форумов, мне не подошёл ни один из способов проекции. Параллельная мне не подходила, так как проекция не будет выглядеть объёмной. В одних формулах проекции для нахождения точки нужно решить систему уравнений( а я не знаю, как научить компьютер их решать), другие я просто-напросто не понял… В общем, я решил придумать свой способ. Рассмотрим для этого проекцию 2D->1D.


pov значит «Point of view» (точка зрения), ptp значит «Point to project» (точка, которую нужно спроецировать), а ptp` — это искомая точка на оси OX.

Углы povptpB и ptpptp`A равны как соответствующие( пунктирная линия параллельна оси OX, прямая povptp — секущая).
Икс точки ptp` равен иксу точки ptp минус длина отрезка ptp`A. Этот отрезок можно найти из треугольника ptpptp`A: ptp`A = ptpA/тангенс угла ptpptp`A. Мы можем найти этот тангенс из треугольника povptpB: тангенс угла ptpptp`A = (Ypov-Yptp)(Xpov-Xptp).
Ответ: Xptp`=Xptp-Yptp/тангенс угла ptpptp`A.

Я не стал подробно расписывать этот алгоритм тут, так как там куча частных случаев, когда формула несколько меняется. Кому это интересно — посмотрите в исходниках программы, там всё расписано в комментариях.

Для того, чтобы спроецировать точку трёхмерного пространства на плоскость, просто рассмотрим две плоскости — XOZ и YOZ, и для каждой из них решим эту задачу. В случае четырёхмерного пространства нужно рассмотреть уже три плоскости: XOQ, YOQ и ZOQ.

И наконец, про программу. Она действует так: инициализировать шестнадцать вершин тессеракта -> в зависимости от введённых пользователем команд повернуть его -> спроецировать на объём -> в зависимости от введённых пользователем команд повернуть его проекцию -> спроецировать на плоскость -> нарисовать.

Проекции и повороты я написал сам. Они работают по формулам, которые я только что описал. Библиотека OpenGL рисует линии, а так же занимается смешиванием цветов. А координаты вершин тессеракта вычисляются таким образом:

Координаты вершин линии с центром в начале координат и длинной 2 — (1) и (-1);
— " — " — квадрата — " — " — и ребром длинной 2:
( 1; 1 ), ( -1; 1), (1; -1) и (-1; -1);
— " — " — куба — " — " -:
( 1; 1; 1 ), ( -1; 1; 1), (1; -1; 1), (-1; -1; 1), ( 1; 1; -1 ), ( -1; 1; -1), (1; -1; -1), (-1; -1; -1);
Как можно было заметить, квадрат — это одна линия над осью OY и одна линия под осью OY; куб — это один квадрат спереди от плоскости XOY, и один за ней; тессеракт — это один куб по ту сторону объёма XOYZ, и один — по эту. Но куда легче воспринять это чередование единиц и минус единиц, если их записать в столбик

1; 1; 1
-1; 1; 1
1; -1; 1
-1; -1; 1
1; 1; -1
-1; 1; -1
1; -1; -1
-1; -1; -1

В первом столбце один и минус один чередуются. Во втором столбце сначала идёт два плюса, потом два минуса. В третьем — четыре плюс единицы, а потом четыре минус единицы. Это были вершины куба. У тессеракта их в два раза больше, и потому нужно было написать цикл для их объявления, иначе очень легко запутаться.

Моя программа так же умеет рисовать анаглиф. Счастливые обладатели 3D-очков могут наблюдать стереоскопическую картинку. В рисовании картинки нет ничего хитрого, просто рисуется две проекции на плоскость, для правого и левого глаз. Зато программа становится намного более наглядной и интересной, а главное — даёт лучшее представление о четырёхмерном мире.

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

Архив с программой, исходником и инструкцией пользования: www.dropbox.com/s/xilxouqmgnsf6zs/%D0%A2%D0%B5%D1%81%D1%81%D0%B5%D1%80%D0%B0%D0%BA%D1%82.rar (нужно скачать и установить программу Dropbox: www.dropbox.com)

Исходник: docs.google.com/document/d/1sGjBTb-od84Qp_la0LS9tWFZL4aYk-1exUs0Za5_Uq0/edit