55.htm 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  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/b5.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>5.5. Освещение по Фонгу
  54. <!-- Article -->
  55. <p>Здесь принято делать, как минимум, такие предположения:
  56. <ul>
  57. <li>Ks = 0 (то есть грань не отражает свет, а только рассеивает)
  58. </ul>
  59. <p>Да-да, здесь нет никакой ошибки. Практически все обычно используемые (в demo
  60. по меньшей мере) методы т.н. "освещения по Фонгу" НЕ учитывают отраженной
  61. компоненты освещенности.
  62. <p>Здесь будет рассказано о самом, наверное, популярном методе освещения по
  63. Фонгу, который сводит освещение к текстурированию по определенной текстуре.
  64. <p>Этот метод базируется на таких добавочных предположениях:
  65. <ul>
  66. <li>L - константа (как бы точечный источник, удаленный бесконечно далеко)
  67. <li>длина единичной нормали к объекту при интерполяции между вершинами
  68. грани НЕ меняется
  69. </ul>
  70. <p>То есть, утверждается, что если в вершинах нормаль к объекту имеет длину 1,
  71. то при интерполяции этой нормали между вершинами по какой-то грани мы будем
  72. получать в каждой точке нормаль той же самой длины 1. На самом деле это вовсе
  73. даже не так, но для несильно разнящихся углов наклона нормалей приблизительно
  74. верно.
  75. <p>Так как Ks = 0, а длина N по предположению равна 1 на всей грани, имеем:
  76. <p class=expression>intensity = ambient + amp * (N * L).<br>
  77. <p>Рассмотрим упрощенный случай, когда вектор L = (0,0,1). Общий случай можно
  78. без особых вычислительных затрат привести к этому упрощенному, как - будет
  79. рассказано чуть позже. Так вот, в этом случае
  80. <p class=expression>intensity = ambient + amp * (N.x * L.x + N.y * L.y + N.z * L.z) =<br>
  81. = ambient + amp * (N.x * 0 + N.y * 0 + N.z * 1) =<br>
  82. = ambient + amp * N.z =<br>
  83. = ambient + amp * sqrt(1 - (N.x * N.x + N.y * N.y)).<br>
  84. <p>То есть интенсивность выражается через N.x, N.y, а эти величины меняются
  85. линейно. N.x и N.y у нас - числа с плавающей запятой от -1 до 1 (т.к. длина
  86. вектора равна 1), интерполировать их - занятие медленное, да корень считать
  87. раз в пиксел тоже не хочется. Поэтому вместо интерполяции N.x и N.y обычно
  88. интерполируют, например, 128*(N.x+1) и 128*(N.y+1), причем уже в целых
  89. числах. Тогда все возможные значения таким образом отмасштабировнных N.x,
  90. N.y - это 0, 1, ..., 255. Поэтому можно заранее посчитать табличку значений
  91. intensity для каждой пары отмасштабировнных N.x, N.y.
  92. <p>То есть, мы линейно интерполируем 128*(N.x+1) и 128*(N.y+1) (эти значения
  93. меняются тоже линейно, раз N.x, N.y меняются линейно) и по ним по таблице
  94. определяем интенсивность. Это и есть текстурирование, только в качестве
  95. текстуры используется таблица освещенности размером 256x256 (или любым
  96. другим), а в качестве координат текстуры u, v для каждой вершины берутся
  97. отмасшатбированные координаты нормали в этой вершине.
  98. <p>Таблица, согласно всего вышеупомянутого, считается так:
  99. <pre class=source>
  100. // ...
  101. for (i = 0; i < 256; i++) {
  102. for (j = 0; j < 256; j++) {
  103. r =
  104. pow((i - 128) / 256.0, 2) + // это N.x*N.x
  105. pow((j - 128) / 256.0, 2); // это N.y*N.y
  106. // длина N меньше 1, поэтому r > 1 быть не может
  107. if (r > 1) r = 1;
  108. phongTable[i][j] = amp * sqrt(1 - r);
  109. }
  110. }
  111. // ...
  112. </pre>
  113. <p>Правда, обычно используют другую - нелинейную - таблицу, видимо, хоть для
  114. какой-то компенсации всяких ошибок линеаризации... Результаты выглядят
  115. действительно получше. Считается она так:
  116. <pre class=source>
  117. // ...
  118. for (i = 0; i < 256; i++)
  119. for (j = 0; j < 256; j++)
  120. phongTable[i][j] =
  121. amp * pow(sin(i * PI / 256) * sin(j * PI / 256), 4);
  122. // ...
  123. </pre>
  124. <p>Для полного комплекта осталось только привести кусочек кода по вычислению
  125. координат в этой таблице:
  126. <pre class=source>
  127. // ...
  128. len = N.x * N.x + N.y * N.y + N.z * N.z;
  129. N.x /= len; // на случай, если длина N не равна 1
  130. N.y /= len;
  131. N.z /= len;
  132. u = (1 + N.x) * 128; // собственно расчет координат
  133. v = (1 + N.y) * 128;
  134. // ...
  135. </pre>
  136. <p>Теперь вернемся к вопросу о том, как привести случай с произвольным вектором
  137. освещения к только что рассмотренному, где L = (0,0,1). Здесь все вроде бы
  138. просто. Просто применим к нормалям в вершинах любой поворот, совмещающий наш
  139. произвольный вектор света с вектором (0,0,1). Скалярное произведение при этом
  140. не изменяется, поэтому так делать можно. Ну, а после этого поворота уже имеем
  141. только что расписанный упрощенный случай.
  142. <p>Этот поворот нормалей в каждой вершине не требует практически никаких затрат
  143. по следующей причине. Поворот сам по себе, конечно, достаточно медленная
  144. процедура и процессорное время отъедает. Но при движении и вращении камеры
  145. и объекта мы все равно должны будем соответственно поворачивать нормали. Так
  146. вот, эти два поворота можно совместить в один. Если использовать матрицы,
  147. все это делается совсем просто - достаточно перемножить (в нужном порядке!)
  148. матрицу собственного поворота объекта, матрицу перехода от произвольной
  149. камеры к нашей "стандартной" камере и матрицу перехода от произвольного
  150. вектора света к "стандартному" вектору света (0,0,1). Т.е. добавится расчет
  151. этой матрицы перехода и одно матричное умножение на объект, а это уже мелочь.
  152. </div>
  153. </td></table>
  154. <!-- Bottom Navigation -->
  155. <img src="../img/b.gif" width=500 height=1 alt=""><br><img src="../img/t.gif" width=500 height=2 alt=""><br>
  156. <table width=500 cellpadding=0 cellspacing=0 border=0>
  157. <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>
  158. <td><p class=pagetitle><img src="../img/t.gif" width=265 height=1 alt=""><br>demo.design<br>3D programming FAQ</td>
  159. <td align=center><p class=navy><a href="54.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>
  160. <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>
  161. <td align=center><p class=navy><a href="56.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>
  162. </table>
  163. <img src="../img/t.gif" width=500 height=4 alt=""><br>
  164. <img src="../img/b.gif" width=500 height=1 alt=""><br>
  165. <img src="../img/t.gif" width=500 height=1 alt=""><br>
  166. <img src="../img/b.gif" width=500 height=1 alt=""><br>
  167. </center></body>
  168. </html>