43.htm 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  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. Текстурирование. Перспективно-корректное.</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/b4.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. ТЕКСТУРИРОВАНИЕ<br>4.3. Перспективно-корректное
  54. <!-- Article -->
  55. <p>Этот метод основан на приближении u, v кусочно-линейными функциями. Кратко
  56. говоря, при рисовании каждая строка разбивается на куски (обычно несколько
  57. кусков длиной 8/16/32 пикселов и один оставшийся произвольной длины), в
  58. начале и конце каждого куска считаются точные значения u, v, а на куске
  59. они интерполируется линейно.
  60. <p>Точные значения u и v, в принципе, можно считать по формулам из 4.1, но
  61. обычно используют более простой путь. Он основан на том факте, что значени
  62. 1/Z, u/Z и v/Z зависят от sx, sy ЛИНЕЙНО. Доказательство этого факта пока
  63. опущено. Таким образом, достаточно для каждой вершины посчитать 1/Z, u/Z,
  64. v/Z и линейно их интерполировать - точно так же, как интерполируются u и v
  65. в 4.2. Причем, так как эти значения зависят от sx, sy строго линейно, то
  66. интерполяция дает не сильно приближенные результаты, а абсолютно точные!
  67. <p>Сами же точные значения u, v считаются как
  68. <p class=expression>u = (u/Z) / (1/Z),<br>
  69. v = (v/Z) / (1/Z).<br>
  70. <p>Дальше все становится совсем просто. При рисовании треугольника, на ребрах
  71. интерполируем не u и v, как в <a href="42.htm">4.2</a>, а 1/Z, u/Z, v/Z. Кроме того, заранее
  72. считаем d(u/Z)/dsx, d(v/Z)/dsx, d(1/Z)/dsx (то есть, изменений этих самых
  73. u/Z, v/Z, 1/Z соотвествующих шагу по dsx на 1) так, как считали du/dsx - это
  74. будет нужно для быстрого вычисления точных значений u, v. Каждую линию рисуем
  75. кусками по 8/16/32 пикселов (на самом деле, кусками любой длины; просто если
  76. длина - степень двойки, то при вычислении du/dx и dv/dx для текущего куска
  77. можно деление на длину куска заменить сдвигом вправо) и, если надо, рисуем
  78. оставшийся хвостик. Для расчета точных значений u, v в конце каждого куска
  79. пользуемся посчитанными (ага!) значениями d(u/Z)/dsx, d(v/Z)/dsx, d(1/Z)/dsx;
  80. раз значения u/Z, v/Z, 1/Z в начале куска известны, меняются они линейно и
  81. длина куска известна (либо 16 пикселов, либо длина остатка), то в конце
  82. куска они считаются все это до боли просто:
  83. <pre class=source>
  84. // расчет u/Z, v/Z, 1/Z в конце куска
  85. uZ_b = uZ_a + length * duZ_dsx;
  86. vZ_b = vZ_a + length * dvZ_dsx;
  87. Z1_b = Z1_a + length * dZ1_dsx;
  88. </pre>
  89. <p>Все вместе выглядеть это будет примерно так:
  90. <pre class=source>
  91. // ...
  92. current_sx = x_start;
  93. length = x_end - x_start;
  94. // расчет u/Z, v/Z, 1/Z, u, v в начале самого первого куска
  95. uZ_a = uZ_start;
  96. vZ_a = vZ_start;
  97. Z1_a = Z1_start; // это 1/Z
  98. u_a = uZ_a / Z1_a;
  99. v_a = vZ_a / Z1_a;
  100. // рисуем куски по 16 пикселов
  101. while (length >= 16) {
  102. // расчет u/Z, v/Z, 1/Z, u, v в конце куска
  103. uZ_b = uZ_a + 16 * duZ_dsx;
  104. vZ_b = vZ_a + 16 * dvZ_dsx;
  105. Z1_b = Z1_a + 16 * dZ1_dsx;
  106. u_b = uZ_b / Z1_b;
  107. v_b = vZ_b / Z1_b;
  108. u = u_a; // начинаем текстурирование с начала куска
  109. v = v_a;
  110. // можно сделать >> 4, используя fixedpoint
  111. du = (u_b - u_a) / 16;
  112. dv = (v_b - v_a) / 16;
  113. // рисуем 16 пикселов старым добрым "аффинным" методом
  114. len = 16;
  115. while (len--) {
  116. putpixel(current_sx, current_sy, texture[(int)v][(int)u]);
  117. u += du;
  118. v += dv;
  119. current_sx++;
  120. }
  121. length -= 16;
  122. // конец куска становится началом следующего куска
  123. uZ_a = uZ_b;
  124. vZ_a = vZ_b;
  125. Z1_a = Z1_b;
  126. u_a = u_b;
  127. v_a = v_b;
  128. }
  129. // дорисовываем "хвост" линии, если он непуст
  130. if (length != 0) {
  131. uZ_b = uZ_a + length * duZ_dsx;
  132. vZ_b = vZ_a + length * dvZ_dsx;
  133. Z1_b = Z1_a + length * dZ1_dsx;
  134. u_b = uZ_b / Z1_b;
  135. v_b = vZ_b / Z1_b;
  136. u = u_a; // начинаем текстурирование с начала куска
  137. v = v_a;
  138. du = (u_b - u_a) / length;
  139. dv = (v_b - v_a) / length;
  140. // рисуем остаток пикселов старым добрым "аффинным" методом
  141. while (length--) {
  142. putpixel(current_sx, current_sy, texture[v][u]);
  143. u += du;
  144. v += dv;
  145. current_sx++;
  146. }
  147. }
  148. // ...
  149. </pre>
  150. <p>Как и в <a href="42.htm">4.2</a>, пройдемся подобным куском кода по всем строкам грани, не забыв
  151. вместо "// ..." вставить интерполяцию всяких там [u/v/1]Z_start, содранную
  152. с интерполяции u_start.. и - о чудо, текстурированная с учетом перспективы
  153. грань!
  154. <p>Осталось сказать еще пару слов о кое-какой оптимизации.
  155. <p>Во-первых, два деления при расчете u и v в цикле прорисовки можно (и нужно)
  156. заменить на одно - посчитать tmp = 1/Z, дальше u = uZ * tmp, v = vZ * tmp.
  157. <p>Во-вторых, немного поменяв местами блоки расчета очередной пары точных
  158. значений u и v и прорисовки очередного куска линии, можно добиться того,
  159. что это самое одно деление, нужное для расчета u и v для *следующего* куска
  160. будет находиться сразу перед прорисовкой *текущего* куска. А в этом случае
  161. деление может исполняться в сопроцессоре одновременно с отрисовкой куска
  162. линии в процессоре. То есть единственная медленная операция будет считатьс
  163. на полную халяву! Получим перспективно-корректное текстурирование, которое
  164. (теоретически) будет работать ненамного медленнее аффинного.
  165. <p>В-третьих, деление на length при дорисовке хвостика длиной от 1 до 15
  166. пикселов можно заменить на умножение на 1/length, заранее посчитав табличку
  167. для значений 1/length.
  168. <p>И наконец, мелкие треугольники можно текстурировать аффинным методом, а
  169. большие - методом с коррекцией. Размер треугольника можно определять хот
  170. бы по длине самой длинной горизонтальной линии:
  171. <p class=expression>x_start = A.sx+(B.sy-A.sy)*(C.sx-A.sx)/(C.sy-A.sy),<br>
  172. x_end = B.sx,<br>
  173. longest_length = x_end - x_start,<br>
  174. <p>все равно мы ее считаем для расчета du_dsx или duZ_dsx и иже с ними.
  175. </div>
  176. </td></table>
  177. <!-- Bottom Navigation -->
  178. <img src="../img/b.gif" width=500 height=1 alt=""><br><img src="../img/t.gif" width=500 height=2 alt=""><br>
  179. <table width=500 cellpadding=0 cellspacing=0 border=0>
  180. <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>
  181. <td><p class=pagetitle><img src="../img/t.gif" width=265 height=1 alt=""><br>demo.design<br>3D programming FAQ</td>
  182. <td align=center><p class=navy><a href="42.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>
  183. <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>
  184. <td align=center><p class=navy><a href="44.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>
  185. </table>
  186. <img src="../img/t.gif" width=500 height=4 alt=""><br>
  187. <img src="../img/b.gif" width=500 height=1 alt=""><br>
  188. <img src="../img/t.gif" width=500 height=1 alt=""><br>
  189. <img src="../img/b.gif" width=500 height=1 alt=""><br>
  190. </center></body>
  191. </html>