Может кто-нибудь объяснить математику, как работает этот скрипт, вращающий куб? - PullRequest
3 голосов
/ 09 сентября 2009

Если вы перейдете по следующей ссылке, вы увидите действительно классное моделирование Javascript для куба, который вращается в зависимости от положения мыши.

Моделирование: здесь.

alt text

Если вы просмотрите исходный сценарий вращения куба, вы увидите:

<script type="text/javascript">

/* I wrote this script in a few minutes just for fun. It's not made to win any
   competition. */

var dimension = 1, a = 0, b = 0, i = 27;
while (i--) document.write('<b id="l' + i + '">+</b>');

function f()
{
 i = 0;
 for (x = -dimension; x <= dimension; x += dimension)
  for (y = -dimension; y <= dimension; y += dimension)
   for (z = -dimension; z <= dimension; z += dimension)
   {
    u = x;
    v = y;
    w = z;
    u2 = u * Math.cos(a) - v * Math.sin(a);
    v2 = u * Math.sin(a) + v * Math.cos(a);
    w2 = w;
    u = u2; v = v2; w = w2;
    u2 = u;
    v2 = v * Math.cos(b) - w * Math.sin(b);
    w2 = v * Math.sin(b) + w * Math.cos(b);
    u = u2; v = v2; w = w2;
    var c = Math.round((w + 2) * 70);
    if (c < 0) c = 0;
    if (c > 255) c = 255;
    s = document.getElementById('l' + i).style;
    s.left = 300 + u * (w + 2) * 50;
    s.top  = 300 + v * (w + 2) * 50;
    s.color = 'rgb(' + c + ', ' + c + ', 0)';
    s.fontSize = (w + 2) * 16 + 'px';
    /* The Digg users missed depth sort, so here it is. */
    s.zIndex = Math.round((w + 2) * 10);
    i++;
   }
}

/* Using a timer instead of the onmousemove handler wastes CPU time but makes
   the animation much smoother. */
setInterval('f()', 17);

</script>

Я просмотрел его несколько раз и до сих пор не понимаю, как рассчитываются точки для куба. Это использует "Euler Rotations"? Одна из моих больших проблем - использование однобуквенных имен переменных, которые для меня ничего не значат.

Может ли кто-нибудь с необходимыми знаниями по математике объяснить, как математика работает за вращением куба в этой симуляции? Я хотел бы делать подобные вещи, но когда дело доходит до подсчета позиций, я немного растерялся.

Ответы [ 2 ]

7 голосов
/ 09 сентября 2009
  1. он пишет 27 (3x3x3) + (в узел жирный html)
  2. он итерирует по осям x, y и z от -1-> 0-> 1 (таким образом, достигая всех 27 (3x3x3) точек этого куба)
  3. так для каждого пункта он будет делать:
  4. вращение вокруг оси z с помощью (простого 2d-вращения)
  5. вращение вокруг оси x на b (снова простое 2d-вращение)
  6. сжатие значения c (которое является просто масштабированной z-координатой) в [0..255] (используя это как цвет [глубина-метка]
  7. Получите html-узлы и разместите их вокруг (300/300) с простым перспективным подходом
  8. настройка цвета и размера в соответствии с глубиной

Важная вещь, которую вы забыли упомянуть, это то, что глобальные a и b установлены в теге body:

<body onmousemove="a = event.clientX / 99; b = event.clientY / 99;"

список переменных:

  • я просто счетчик (без функции)
  • a - угол вокруг оси z
  • b - угол вокруг оси x
  • с интенсивностью цвета
  • x, y, z - координата в промежутке между [-1, -1, -1] - [1,1,1]
  • u, v, w - повернутые точки вокруг оси z
  • u2, v2, w2 - повернутые точки вокруг оси x
  • s - это htmlnode

Он использовал такой же подход, как и углы Эйлера, но он использует только две оси, поэтому нет никаких ограничений на использование углов Эйлера.

Для получения дополнительной информации о вращениях в трех измерениях смотрите википедию:

http://en.wikipedia.org/wiki/Rotation_matrix#Dimension_three

Также обратите внимание, что его проекции не являются реальными 3d: он не делит по z-координате проецирование в 2d-пространство. Таким образом, глубина «искажена» (сложно объяснить, но если вы соедините кресты, они не будут формировать куб, а будут искаженным кубом). В реальной 2-мерной проекции прямые линии снова образуют прямые. alt text

для правильной проекции на перспективу загляните в эту статью (не путайтесь с матричными вещами. Только диаграмма и простая теорема о перехвате - все, что вам нужно):

http://en.wikipedia.org/wiki/Perspective_projection#Perspective_projection

x' = x * (eye_dist / eye_dist + z)
y' = y * (eye_dist / eye_dist + z)

для такого простого подхода все в порядке, однако серьезные 3d будут работать с однородными координатами.

2 голосов
/ 09 сентября 2009

Идея состоит в том, чтобы использовать стандартную матрицу вращения. В 2D это:

--     --   --             -- --     --
| x_new |   | cos(a) -sin(a) | | x_old |
|       | = |               | |       |
| y_new |   | sin(a)  cos(a) | | y_old |
---    --   --             -- --     --

Где a - угол, на который вы вращаетесь.

Идея состоит в том, что вы переводите каждую точку в новую точку, используя это преобразование. Чтобы получить более полное представление об этом, рассмотрим единичный круг (который я не знаю, как рисовать с помощью ASCII-рисунка), и спросите себя, как вы можете переместить точку (0,1) в (sqrt(2)/2,sqrt(2)/2) (поворот на 45 градусов) ).

x_new = x_old * cos(45) - y_old * sin(45) = 1 * sqrt(2)/2 - 0 * sqrt(2)/2 = sqrt(2)/2
y_new = x_old * sin(45) + y_old * cos(45) = 1 * sqrt(2)/2 + 0 * sqrt(2)/2 = sqrt(2)/2

Теперь переведите это на (1,0), еще один поворот на 45 градусов:

x_new = x_old * cos(45) - y_old * sin(45) = sqrt(2)/2 * sqrt(2)/2 - sqrt(2)/2 * sqrt(2)/2 = 0
y_new = x_old * sin(45) + y_old * cos(45) = sqrt(2)/2 * sqrt(2)/2 + sqrt(2)/2 * sqrt(2)/2 = 1

Распространение этого на 3D довольно просто, все, что вам нужно сделать, - это использовать другое умножение для вращения вдоль плоскости XZ.

...