25.htm 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. <!--
  2. demo.design 3D programming FAQ
  3. Idea, texts, screenshots:
  4. Andrew A. Aksyonoff,
  5. shodan@chat.ru
  6. Web-design, illustrations:
  7. Andrey Samoilov,
  8. asy@sense.simbirsk.su
  9. -->
  10. <html>
  11. <head>
  12. <title>demo.design 3D programming FAQ. Основы 3D графики. Работа с произвольной камерой.</title>
  13. <link rel=stylesheet href="../style.css" type="text/css">
  14. </head>
  15. <script language="javascript">
  16. <!--//
  17. browser = navigator.appName;
  18. version = parseFloat(navigator.appVersion);
  19. if (browser == "Netscape" && version >= 3.0) { jsenabled = 1; } else
  20. if (browser == "Microsoft Internet Explorer" && version >= 3.0) { jsenabled = 1; } else { jsenabled = 0; }
  21. function swap(img,ref) { if (jsenabled) {document.images[img].src = ref;} }
  22. function loadtocache(img,ref) { cache[img] = new Image(); cache[img].src = ref; }
  23. if (jsenabled) {
  24. cache = new Array();
  25. loadtocache(0,"../img/xdl.gif");
  26. loadtocache(1,"../img/xfaq.gif");
  27. loadtocache(2,"../img/xlinks.gif");
  28. loadtocache(3,"../img/xauthor.gif");
  29. loadtocache(4,"../img/xe.gif");
  30. loadtocache(5,"../img/xprev.gif");
  31. loadtocache(6,"../img/xnext.gif");}
  32. //-->
  33. </script>
  34. <body bgcolor=white><center>
  35. <!-- Title -->
  36. <img src="../img/b.gif" width=500 height=1 alt=""><br>
  37. <img src="../img/t.gif" width=500 height=1 alt=""><br>
  38. <img src="../img/b.gif" width=500 height=1 alt=""><br>
  39. <img src="../img/t.gif" width=500 height=2 alt=""><br>
  40. <table width=500 cellpadding=0 cellspacing=0 border=0>
  41. <td><img src="../img/t.gif" width=5 height=1 alt=""><a href="../main.htm" onmouseover="swap('logo','../img/xe.gif');" onmouseout="swap('logo','../img/e.gif');"><img src="../img/e.gif" name=logo width=60 height=50 hspace=10 border=0 alt=" в самое начало "></a></td>
  42. <td><p class=pagetitle><img src="../img/t.gif" width=265 height=1 alt=""><br>demo.design<br>3D programming FAQ</td>
  43. <td align=center><p class=navy><a href="../download.htm" onmouseover="swap('dl','../img/xdl.gif');" onmouseout="swap('dl','../img/dl.gif');"><img src="../img/dl.gif" name=dl width=40 height=40 border=0 hspace=5 alt=" download "></a><br>download</td>
  44. <td align=center><p class=navy><a href="../links.htm" onmouseover="swap('links','../img/xlinks.gif');" onmouseout="swap('links','../img/links.gif');"><img src="../img/links.gif" name=links width=40 height=40 border=0 hspace=5 alt=" коллекция линков "></a><br>links</td>
  45. <td align=center><p class=navy><a href="../author.htm" onmouseover="swap('author','../img/xauthor.gif');" onmouseout="swap('author','../img/author.gif');"><img src="../img/author.gif" name=author width=40 height=40 border=0 hspace=5 alt=" автора! "></a><br>author</td>
  46. </table>
  47. <img src="../img/t.gif" width=500 height=4 alt=""><br><img src="../img/b.gif" width=500 height=1 alt=""><br>
  48. <!-- Head -->
  49. <table width=500 cellpadding=0 cellspacing=10 border=0><td><div align=justify>
  50. <p class=title>
  51. <img src="../img/b2.gif" width=70 height=70 align=left hspace=0 alt="">
  52. <img src="../img/t.gif" width=5 height=70 align=left hspace=0 alt="">
  53. ОСНОВЫ 3D ГРАФИКИ<br>2.5. Работа с произвольной камерой
  54. <!-- Article -->
  55. <p>Рассмотрим любую камеру как точку - центр проецирования и экран - плоский
  56. прямоугольник в 3D пространстве, на плоскость которого идет проецирование.
  57. Наша стандартная камера, например, задается точкой (0,0,-dist) и экраном с
  58. вершинами (-xSize/2,ySize/2), ..., (xSize/2,-ySize/2). Можно задать эту
  59. систему тремя векторами, задающими с точки зрения камеры направления вперед,
  60. вправо и вверх; вектор "вперед" соединяет центр проецирования и центр экрана,
  61. вектор "вправо" соединяет центр экрана и правую его границу, вектор "вверх",
  62. соответственно, центр экрана и верхнюю его границу. Обозначим эти вектора
  63. как p, q и r соответственно, а центр проецирования за s. Вот пример для
  64. стандартной камеры.
  65. <p><center><img src="illu/illu25a.gif" width=180 height=180 alt="рисунок (illu/illu25a.gif)"></center>
  66. <p>Здесь (для стандартной камеры; обозначим ее вектора как Sp, Sq, Sr, Ss)
  67. <p class=expression>Sp = p = (0,0,dist)<br>
  68. Sq = q = (xSize/2,0,0)<br>
  69. Sr = r = (0,ySize/2,0)<br>
  70. Ss = s = (0,0,-dist)<br>
  71. <p>Любые три взаимно перпендикулярных вектора и точка - центр координат задают в
  72. 3D пространстве систему координат. Так что объект мы можем рассматривать в
  73. системе обычных координат (x,y,z), в системе координат стандартной камеры
  74. (Sp,Sq,Sr) или в системе (p,q,r), соответствующей какой-то произвольной
  75. камере. В любом случае, если (a,b,c) - координаты точки в системе координат
  76. камеры (точнее, в системе координат с центром в точке s и базисом (p,q,r)),
  77. то координаты проекции точки на экране равны
  78. <p class=expression>screenX = xSize/2 + xSize/2 * a/c<br>
  79. screenY = ySize/2 - ySize/2 * b/c<br>
  80. <p>В случае стандартной камеры переход от обычной системы координат к системе
  81. координат камеры очевиден:
  82. <p class=expression>a = x / (xSize/2)<br>
  83. b = y / (ySize/2)<br>
  84. c = (z + dist) / dist<br>
  85. <p>Подставив это в формулы для screenX, screenY, получим как раз те самые формулы
  86. для проекции на стандартную камеру.
  87. <p>Поскольку со стандартной камерой нам достаточно удобно и понятно работать,
  88. для произвольной камеры мы должны сделаеть такое преобразование пространства,
  89. что как бы совместит произвольную камеру и стандартную камеру. То есть, такое
  90. преобразование, что вектора p, q, r перейдут в Sp, Sq, Sr, а точка s в точку
  91. Ss.
  92. <p>Посчитаем матрицу для *обратного* преобразования; оно должно переводить Sp,
  93. Sq, Sr, Ss в p, q, r, s. Преобразование, переводящее Ss в s (и наоборот) - это
  94. обычный паралелльный перенос; остается написать преобразование перевода Sp,
  95. Sq, Sr в p, q, r. Пусть у нас есть координаты p, q, r в системе координат
  96. (x,y,z):
  97. <p class=expression>p = (px,py,pz)<br>
  98. q = (qx,qy,qz)<br>
  99. r = (rx,ry,rz)<br>
  100. <p>Для Sp, Sq, Sr координаты (в этой же системе) известны и равны следующему:
  101. <p class=expression>Sp = (0,0,dist)<br>
  102. Sq = (xSize/2,0,0)<br>
  103. Sr = (0,ySize/2,0)<br>
  104. <p>Пусть T - искомая матрица перевода,
  105. <pre class=formula>
  106. [ a b c ]
  107. T = [ d e f ], a..i - какие-то неизвестные.
  108. [ g h i ]
  109. </pre>
  110. <p>Поскольку T переводит Sp, Sq, Sr в p, q, r; то есть
  111. <p class=expression>p = T*Sp<br>
  112. q = T*Sq<br>
  113. r = T*Sr<br>
  114. <p>то, подставляя, например, p и Sp, получаем:
  115. <pre class=formula>
  116. [ px ] [ a b c ] [ 0 ] [ c*dist ]
  117. [ py ] = [ d e f ] [ 0 ] = [ f*dist ], откуда
  118. [ pz ] [ g h i ] [ dist ] [ i*dist ]
  119. </pre>
  120. <p class=expression>c = px/dist,<br>
  121. f = py/dist,<br>
  122. i = pz/dist.<br>
  123. <p>Аналогично находим все остальные элементы матрицы T:
  124. <pre class=formula>
  125. [ qx*2/xSize rx*2/ySize px/dist ]
  126. T = [ qy*2/xSize ry*2/ySize py/dist ]
  127. [ qz*2/xSize rz*2/ySize pz/dist ]
  128. </pre>
  129. <p>Но нас интересует обратное к этому преобразование. Оно задается обратной
  130. матрицей к T, то есть такой матрицей T1, что
  131. <pre class=formla>
  132. [ 1 0 0 ]
  133. T * T1 = T1 * T = [ 0 1 0 ]
  134. [ 0 0 1 ]
  135. </pre>
  136. <p>Обратная матрица, вообще говоря, существует далеко не всегда, да и вычисление
  137. ее в общем случае - достаточно неприятная задача. Однако в данном случае из-за
  138. специального вида матрицы T (конкретнее, из-за того, что T - ортогональная
  139. матрица) она не только всегда существует, но и считается очень просто:
  140. <pre class=formula>
  141. [ qx*2/xSize rx*2/ySize px/dist ] [ qx1 rx1 px1 ]
  142. T = [ qy*2/xSize ry*2/ySize py/dist ] = [ qy1 ry1 py1 ]
  143. [ qz*2/xSize rz*2/ySize pz/dist ] [ qz1 rz1 pz1 ]
  144. [ qx1/lq qy1/lq qz1/lq ]
  145. T1 = [ rx1/lr ry1/lr rz1/lr ]
  146. [ px1/lp py1/lp pz1/lp ]
  147. </pre>
  148. <p>где
  149. <p class=expression>lp = px1*px1 + py1*py1 + pz1*pz1<br>
  150. lq = qx1*qx1 + qy1*qy1 + qz1*qz1<br>
  151. lr = rx1*rx1 + ry1*ry1 + rz1*rz1<br>
  152. <p>Сделав сначала параллельный перенос, совмещающий s и Ss, а потом полученное
  153. преобразование, как раз и получим преобразование, переводящее произвольную
  154. камеру в стандартную.
  155. <p>Теперь надо выяснить, как, собственно посчитать координаты p, q, r через
  156. имеющиеся у нас характеристики: положение, направление, угол зрения и угол
  157. поворота. 3D Studio (и мы вслед за ней) рассчитывает эти вектора по такому
  158. алгоритму:
  159. <p class=expression>1. Считаем p = target - location<br>
  160. 2. Если p.x == 0 и p.z == 0, то q = (0, 0, 1); иначе q = (p.z, 0, -p.x)<br>
  161. 3. Считаем r = crossProduct(p, q) - векторное произведение p на q<br>
  162. 4. Считаем lp = length(p) - длина p<br>
  163. 5. Приводим r и q к длине 2*lp*tan(FOV/2)<br>
  164. <p>Здесь мы не учитываем поворот камеры вокруг своей оси, его удобнее сделать
  165. после перехода к стандартной камере - в этом случае получаем обычный поворот
  166. относительно оси z на угол roll.
  167. <p>Таким образом, окончательная матрица перевода должна представлять собой
  168. произведение матрицы параллельного переноса, матрицы T1 и матрицы поворота
  169. вокруг оси z на угол roll:
  170. <p class=expression>FinalCameraMatrix = RollMatrix * T1 * MoveMatrix
  171. <p>Расчет матриц RollMatrix и MoveMatrix очевиден.
  172. </div>
  173. </td></table>
  174. <!-- Bottom Navigation -->
  175. <img src="../img/b.gif" width=500 height=1 alt=""><br><img src="../img/t.gif" width=500 height=2 alt=""><br>
  176. <table width=500 cellpadding=0 cellspacing=0 border=0>
  177. <td><img src="../img/t.gif" width=5 height=1 alt=""><a href="../main.htm" onmouseover="swap('logo2','../img/xe.gif');" onmouseout="swap('logo2','../img/e.gif');"><img src="../img/e.gif" name=logo2 width=60 height=50 hspace=10 border=0 alt=" в самое начало "></a></td>
  178. <td><p class=pagetitle><img src="../img/t.gif" width=265 height=1 alt=""><br>demo.design<br>3D programming FAQ</td>
  179. <td align=center><p class=navy><a href="24.htm" onmouseover="swap('prev','../img/xprev.gif');" onmouseout="swap('prev','../img/prev.gif');"><img src="../img/prev.gif" name=prev width=40 height=40 border=0 hspace=5 alt=" предыдущая статья "></a><br>previous</td>
  180. <td align=center><p class=navy><a href="../content.htm" onmouseover="swap('faq','../img/xfaq.gif');" onmouseout="swap('faq','../img/faq.gif');"><img src="../img/faq.gif" name=faq width=40 height=40 border=0 hspace=5 alt=" содержание "></a><br>content</td>
  181. <td align=center><p class=navy><a href="31.htm" onmouseover="swap('next','../img/xnext.gif');" onmouseout="swap('next','../img/next.gif');"><img src="../img/next.gif" name=next width=40 height=40 border=0 hspace=5 alt=" следующая статья "></a><br>next</td>
  182. </table>
  183. <img src="../img/t.gif" width=500 height=4 alt=""><br>
  184. <img src="../img/b.gif" width=500 height=1 alt=""><br>
  185. <img src="../img/t.gif" width=500 height=1 alt=""><br>
  186. <img src="../img/b.gif" width=500 height=1 alt=""><br>
  187. </center></body>
  188. </html>