tips.html 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. <!DOCTYPE html><html lang="ru"><head>
  2. <meta charset="utf-8">
  3. <title>Советы</title>
  4. <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
  5. <meta name="twitter:card" content="summary_large_image">
  6. <meta name="twitter:site" content="@threejs">
  7. <meta name="twitter:title" content="Three.js – Советы">
  8. <meta property="og:image" content="https://threejs.org/files/share.png">
  9. <link rel="shortcut icon" href="/files/favicon_white.ico" media="(prefers-color-scheme: dark)">
  10. <link rel="shortcut icon" href="/files/favicon.ico" media="(prefers-color-scheme: light)">
  11. <link rel="stylesheet" href="/manual/resources/lesson.css">
  12. <link rel="stylesheet" href="/manual/resources/lang.css">
  13. </head>
  14. <body>
  15. <div class="container">
  16. <div class="lesson-title">
  17. <h1>Советы</h1>
  18. </div>
  19. <div class="lesson">
  20. <div class="lesson-main">
  21. <p>Эта статья представляет собой набор небольших проблем, с которыми вы можете столкнуться при использовании three.js, которые кажутся слишком маленькими, чтобы иметь собственную статью. </p>
  22. <hr>
  23. <p><a id="screenshot" data-toc="Делаем скриншот холста"></a></p>
  24. <h1 id="-">Делаем скриншот холста</h1>
  25. <p>В браузере фактически есть 2 функции, которые сделают скриншот.
  26. Старая
  27. <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toDataURL"><code class="notranslate" translate="no">canvas.toDataURL</code></a>
  28. и новая улучшенная
  29. <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toBlob"><code class="notranslate" translate="no">canvas.toBlob</code></a></p>
  30. <p>Таким образом, вы думаете, что было бы легко сделать снимок экрана, просто добавив такой код, как </p>
  31. <pre class="prettyprint showlinemods notranslate lang-html" translate="no">&lt;canvas id="c"&gt;&lt;/canvas&gt;
  32. +&lt;button id="screenshot" type="button"&gt;Save...&lt;/button&gt;
  33. </pre>
  34. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">const elem = document.querySelector('#screenshot');
  35. elem.addEventListener('click', () =&gt; {
  36. canvas.toBlob((blob) =&gt; {
  37. saveBlob(blob, `screencapture-${canvas.width}x${canvas.height}.png`);
  38. });
  39. });
  40. const saveBlob = (function() {
  41. const a = document.createElement('a');
  42. document.body.appendChild(a);
  43. a.style.display = 'none';
  44. return function saveData(blob, fileName) {
  45. const url = window.URL.createObjectURL(blob);
  46. a.href = url;
  47. a.download = fileName;
  48. a.click();
  49. };
  50. }());
  51. </pre>
  52. <p>Вот пример из <a href="responsive.html">статьи об отзывчивости</a>
  53. с добавленным выше кодом и некоторым CSS для размещения кнопки </p>
  54. <p></p><div translate="no" class="threejs_example_container notranslate">
  55. <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/tips-screenshot-bad.html"></iframe></div>
  56. <a class="threejs_center" href="/manual/examples/tips-screenshot-bad.html" target="_blank">нажмите здесь, чтобы открыть в отдельном окне</a>
  57. </div>
  58. <p></p>
  59. <p>Когда я попробовал это, я получил этот скриншот </p>
  60. <div class="threejs_center"><img src="../resources/images/screencapture-413x313.png"></div>
  61. <p>Да, это просто черное изображение. </p>
  62. <p>Возможно, это сработало для вас в зависимости от вашего браузера / ОС, но в целом это вряд ли сработает. </p>
  63. <p>Проблема заключается в том, что по соображениям производительности и совместимости
  64. браузер по умолчанию очищает буфер рисования WebGL-холста после его отрисовки. </p>
  65. <p>Решение состоит в том, чтобы вызвать ваш код рендеринга непосредственно перед захватом. </p>
  66. <p>В нашем коде нам нужно настроить несколько вещей. Сначала давайте выделим код рендеринга. </p>
  67. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">+const state = {
  68. + time: 0,
  69. +};
  70. -function render(time) {
  71. - time *= 0.001;
  72. +function render() {
  73. if (resizeRendererToDisplaySize(renderer)) {
  74. const canvas = renderer.domElement;
  75. camera.aspect = canvas.clientWidth / canvas.clientHeight;
  76. camera.updateProjectionMatrix();
  77. }
  78. cubes.forEach((cube, ndx) =&gt; {
  79. const speed = 1 + ndx * .1;
  80. - const rot = time * speed;
  81. + const rot = state.time * speed;
  82. cube.rotation.x = rot;
  83. cube.rotation.y = rot;
  84. });
  85. renderer.render(scene, camera);
  86. - requestAnimationFrame(render);
  87. }
  88. +function animate(time) {
  89. + state.time = time * 0.001;
  90. +
  91. + render();
  92. +
  93. + requestAnimationFrame(animate);
  94. +}
  95. +requestAnimationFrame(animate);
  96. </pre>
  97. <p>Теперь этот <code class="notranslate" translate="no">render</code> касается только фактического рендеринга, мы можем вызвать его непосредственно перед захватом холста. </p>
  98. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">const elem = document.querySelector('#screenshot');
  99. elem.addEventListener('click', () =&gt; {
  100. + render();
  101. canvas.toBlob((blob) =&gt; {
  102. saveBlob(blob, `screencapture-${canvas.width}x${canvas.height}.png`);
  103. });
  104. });
  105. </pre>
  106. <p>И теперь это должно работать. </p>
  107. <p></p><div translate="no" class="threejs_example_container notranslate">
  108. <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/tips-screenshot-good.html"></iframe></div>
  109. <a class="threejs_center" href="/manual/examples/tips-screenshot-good.html" target="_blank">нажмите здесь, чтобы открыть в отдельном окне</a>
  110. </div>
  111. <p></p>
  112. <p>Для другого решения см. Следующий пункт. </p>
  113. <hr>
  114. <p><a id="preservedrawingbuffer" data-toc="Предотвращение очистки холста "></a></p>
  115. <h1 id="-">Предотвращение очистки холста</h1>
  116. <p>Допустим, вы хотели, чтобы пользователь рисовал анимированный объект.
  117. Вам нужно передать <code class="notranslate" translate="no">preserveDrawingBuffer: true</code> при создании <a href="/docs/#api/en/renderers/WebGLRenderer"><code class="notranslate" translate="no">WebGLRenderer</code></a>.
  118. Это мешает браузеру очистить холст. Вы также должны сказать three.js не очищать холст. </p>
  119. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">const canvas = document.querySelector('#c');
  120. -const renderer = new THREE.WebGLRenderer({canvas});
  121. +const renderer = new THREE.WebGLRenderer({
  122. + canvas,
  123. + preserveDrawingBuffer: true,
  124. + alpha: true,
  125. +});
  126. +renderer.autoClearColor = false;
  127. </pre>
  128. <p></p><div translate="no" class="threejs_example_container notranslate">
  129. <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/tips-preservedrawingbuffer.html"></iframe></div>
  130. <a class="threejs_center" href="/manual/examples/tips-preservedrawingbuffer.html" target="_blank">нажмите здесь, чтобы открыть в отдельном окне</a>
  131. </div>
  132. <p></p>
  133. <p>Обратите внимание, что если вы серьезно относитесь к созданию программы для рисования,
  134. это не будет решением, так как браузер будет очищать холст каждый раз, когда мы меняем его разрешение.
  135. Мы меняем разрешение в зависимости от размера дисплея. Размер дисплея изменяется при изменении размера окна.
  136. Это включает в себя, когда пользователь загружает файл, даже в другой вкладке, и браузер добавляет строку состояния.
  137. Это также включает в себя, когда пользователь поворачивает свой телефон и браузер переключается с портретного на альбомный. </p>
  138. <p>Если вы действительно хотите создать программу для рисования, вы должны .
  139. <a href="rendertargets.html">визуализировать текстуру, используя цель визуализации</a>.</p>
  140. <hr>
  141. <p><a id="tabindex" data-toc="Ввод с клавиатуры"></a></p>
  142. <h1 id="-">Ввод с клавиатуры</h1>
  143. <p>В этих уроках мы часто прикрепляли слушателей событий <code class="notranslate" translate="no">canvas</code>.
  144. Хотя многие события работают, по умолчанию не работают события клавиатуры. </p>
  145. <p>Чтобы получить события клавиатуры, установите для холста <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/tabIndex"><code class="notranslate" translate="no">tabindex</code></a>
  146. значение 0 или более. Например.</p>
  147. <pre class="prettyprint showlinemods notranslate lang-html" translate="no">&lt;canvas tabindex="0"&gt;&lt;/canvas&gt;
  148. </pre>
  149. <p>Это в конечном итоге вызывает новую проблему, хотя. Все, что имеет установленный <code class="notranslate" translate="no">tabindex</code> будет выделено, когда оно будет в фокусе.
  150. Чтобы исправить это, установите фокус CSS <code class="notranslate" translate="no">outline:none</code>. </p>
  151. <pre class="prettyprint showlinemods notranslate lang-css" translate="no">canvas:focus {
  152. outline:none;
  153. }
  154. </pre>
  155. <p>Для демонстрации здесь представлены 3 холста </p>
  156. <pre class="prettyprint showlinemods notranslate lang-html" translate="no">&lt;canvas id="c1"&gt;&lt;/canvas&gt;
  157. &lt;canvas id="c2" tabindex="0"&gt;&lt;/canvas&gt;
  158. &lt;canvas id="c3" tabindex="1"&gt;&lt;/canvas&gt;
  159. </pre>
  160. <p>и немного CSS только для последнего холста </p>
  161. <pre class="prettyprint showlinemods notranslate lang-css" translate="no">#c3:focus {
  162. outline: none;
  163. }
  164. </pre>
  165. <p>Давайте прикрепим к ним всех слушателей событий </p>
  166. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">document.querySelectorAll('canvas').forEach((canvas) =&gt; {
  167. const ctx = canvas.getContext('2d');
  168. function draw(str) {
  169. ctx.clearRect(0, 0, canvas.width, canvas.height);
  170. ctx.textAlign = 'center';
  171. ctx.textBaseline = 'middle';
  172. ctx.fillText(str, canvas.width / 2, canvas.height / 2);
  173. }
  174. draw(canvas.id);
  175. canvas.addEventListener('focus', () =&gt; {
  176. draw('has focus press a key');
  177. });
  178. canvas.addEventListener('blur', () =&gt; {
  179. draw('lost focus');
  180. });
  181. canvas.addEventListener('keydown', (e) =&gt; {
  182. draw(`keyCode: ${e.keyCode}`);
  183. });
  184. });
  185. </pre>
  186. <p>Обратите внимание, что вы не можете получить первый холст,
  187. чтобы принять ввод с клавиатуры. Второе полотно вы можете,
  188. но оно подсвечивается. На третьем холсте применяются оба решения. </p>
  189. <p></p><div translate="no" class="threejs_example_container notranslate">
  190. <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/tips-tabindex.html"></iframe></div>
  191. <a class="threejs_center" href="/manual/examples/tips-tabindex.html" target="_blank">нажмите здесь, чтобы открыть в отдельном окне</a>
  192. </div>
  193. <p></p>
  194. <hr>
  195. <p><a id="transparent-canvas" data-toc="Делаем холст прозрачным "></a></p>
  196. <h1 id="-">Делаем холст прозрачным</h1>
  197. <p>По умолчанию THREE.js делает холст непрозрачным. Если вы хотите, чтобы холст был прозрачным,
  198. передайте <a href="/docs/#api/en/renderers/WebGLRenderer#alpha"><code class="notranslate" translate="no">alpha:true</code></a> при создании <a href="/docs/#api/en/renderers/WebGLRenderer"><code class="notranslate" translate="no">WebGLRenderer</code></a></p>
  199. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">const canvas = document.querySelector('#c');
  200. -const renderer = new THREE.WebGLRenderer({canvas});
  201. +const renderer = new THREE.WebGLRenderer({
  202. + canvas,
  203. + alpha: true,
  204. +});
  205. </pre>
  206. <p>Вы, вероятно, также хотите сказать, что ваши результаты не используют предварительно умноженную альфа </p>
  207. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">const canvas = document.querySelector('#c');
  208. const renderer = new THREE.WebGLRenderer({
  209. canvas,
  210. alpha: true,
  211. + premultipliedAlpha: false,
  212. });
  213. </pre>
  214. <p>Three.js по умолчанию использует холст с использованием
  215. <a href="/docs/#api/en/renderers/WebGLRenderer#premultipliedAlpha"><code class="notranslate" translate="no">premultipliedAlpha: true</code></a> но по умолчанию используется для материалов, которые выводят
  216. <a href="/docs/#api/en/materials/Material#premultipliedAlpha"><code class="notranslate" translate="no">premultipliedAlpha: false</code></a>.</p>
  217. <p>Если вы хотите лучше понять, когда и когда не следует использовать предварительно умноженную альфу,
  218. <a href="https://developer.nvidia.com/content/alpha-blending-pre-or-not-pre"> вот хорошая статья об этом</a>.</p>
  219. <p>В любом случае давайте настроим простой пример с прозрачным холстом. </p>
  220. <p>Мы применили настройки выше к примеру из <a href="responsive.html">статьи об отзывчивости</a>.
  221. Давайте также сделаем материалы более прозрачными</p>
  222. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">function makeInstance(geometry, color, x) {
  223. - const material = new THREE.MeshPhongMaterial({color});
  224. + const material = new THREE.MeshPhongMaterial({
  225. + color,
  226. + opacity: 0.5,
  227. + });
  228. ...
  229. </pre>
  230. <p>И давайте добавим немного HTML-контента </p>
  231. <pre class="prettyprint showlinemods notranslate lang-html" translate="no">&lt;body&gt;
  232. &lt;canvas id="c"&gt;&lt;/canvas&gt;
  233. + &lt;div id="content"&gt;
  234. + &lt;div&gt;
  235. + &lt;h1&gt;Cubes-R-Us!&lt;/h1&gt;
  236. + &lt;p&gt;We make the best cubes!&lt;/p&gt;
  237. + &lt;/div&gt;
  238. + &lt;/div&gt;
  239. &lt;/body&gt;
  240. </pre>
  241. <p>а также немного CSS, чтобы поставить холст впереди </p>
  242. <pre class="prettyprint showlinemods notranslate lang-css" translate="no">body {
  243. margin: 0;
  244. }
  245. #c {
  246. width: 100%;
  247. height: 100%;
  248. display: block;
  249. + position: fixed;
  250. + left: 0;
  251. + top: 0;
  252. + z-index: 2;
  253. + pointer-events: none;
  254. }
  255. +#content {
  256. + font-size: 7vw;
  257. + font-family: sans-serif;
  258. + text-align: center;
  259. + width: 100%;
  260. + height: 100%;
  261. + display: flex;
  262. + justify-content: center;
  263. + align-items: center;
  264. +}
  265. </pre>
  266. <p>обратите внимание, что <code class="notranslate" translate="no">pointer-events: none</code> делает холст невидимым для мыши и сенсорных событий, поэтому вы можете выделить текст под ним.</p>
  267. <p></p><div translate="no" class="threejs_example_container notranslate">
  268. <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/tips-transparent-canvas.html"></iframe></div>
  269. <a class="threejs_center" href="/manual/examples/tips-transparent-canvas.html" target="_blank">нажмите здесь, чтобы открыть в отдельном окне</a>
  270. </div>
  271. <p></p>
  272. <hr>
  273. <p><a id="html-background" data-toc="Создание анимированного фона в three.js "></a></p>
  274. <h1 id="-three-js">Создание анимированного фона в three.js</h1>
  275. <p>Распространенный вопрос - как сделать анимацию three.js фоном веб-страницы. </p>
  276. <p>Есть 2 очевидных способа. </p>
  277. <ul>
  278. <li>Установите у холста CSS <code class="notranslate" translate="no">position</code> <code class="notranslate" translate="no">fixed</code> как в </li>
  279. </ul>
  280. <pre class="prettyprint showlinemods notranslate lang-css" translate="no">#c {
  281. position: fixed;
  282. left: 0;
  283. top: 0;
  284. ...
  285. }
  286. </pre>
  287. <p>Вы можете в основном увидеть это точное решение на предыдущем примере. Просто установите <code class="notranslate" translate="no">z-index</code> на -1, и кубы появятся за текстом. </p>
  288. <p>Небольшим недостатком этого решения является то, что ваш JavaScript должен интегрироваться со страницей,
  289. и если у вас сложная страница, вам нужно убедиться, что ни один из JavaScript в вашей визуализации
  290. three.js не конфликтует с JavaScript, выполняющим другие действия на странице. </p>
  291. <ul>
  292. <li>Используйте <code class="notranslate" translate="no">iframe</code></li>
  293. </ul>
  294. <p>Это решение используется на
  295. <a href="/">главной странице этого сайта </a>.</p>
  296. <p>На вашей веб-странице просто вставьте iframe, например </p>
  297. <pre class="prettyprint showlinemods notranslate lang-html" translate="no">&lt;iframe id="background" src="responsive.html"&gt;
  298. &lt;div&gt;
  299. Your content goes here.
  300. &lt;/div&gt;
  301. </pre>
  302. <p>Затем создайте стиль iframe, чтобы заполнить окно и оказаться в фоновом режиме,
  303. который в основном является тем же кодом, который мы использовали выше для холста,
  304. за исключением того, что нам также нужно установить значение none, поскольку
  305. у iframes по умолчанию есть граница. </p>
  306. <pre class="prettyprint showlinemods notranslate notranslate" translate="no">#background {
  307. position: fixed;
  308. width: 100%;
  309. height: 100%;
  310. left: 0;
  311. top: 0;
  312. z-index: -1;
  313. border: none;
  314. pointer-events: none;
  315. }
  316. </pre><p></p><div translate="no" class="threejs_example_container notranslate">
  317. <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/tips-html-background.html"></iframe></div>
  318. <a class="threejs_center" href="/manual/examples/tips-html-background.html" target="_blank">нажмите здесь, чтобы открыть в отдельном окне</a>
  319. </div>
  320. <p></p>
  321. </div>
  322. </div>
  323. </div>
  324. <script src="/manual/resources/prettify.js"></script>
  325. <script src="/manual/resources/lesson.js"></script>
  326. </body></html>