shadertoy.html 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  1. <!DOCTYPE html>
  2. <html lang="zh">
  3. <head>
  4. <meta charset="utf-8">
  5. <title>Three.js and Shadertoy</title>
  6. <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
  7. <meta name="twitter:card" content="summary_large_image">
  8. <meta name="twitter:site" content="@threejs">
  9. <meta name="twitter:title" content="Three.js – and Shadertoy">
  10. <meta property="og:image" content="https://threejs.org/files/share.png">
  11. <link rel="shortcut icon" href="../../files/favicon_white.ico" media="(prefers-color-scheme: dark)">
  12. <link rel="shortcut icon" href="../../files/favicon.ico" media="(prefers-color-scheme: light)">
  13. <link rel="stylesheet" href="../resources/lesson.css">
  14. <link rel="stylesheet" href="../resources/lang.css">
  15. <script type="importmap">
  16. {
  17. "imports": {
  18. "three": "../../build/three.module.js"
  19. }
  20. }
  21. </script>
  22. <link rel="stylesheet" href="/manual/zh/lang.css">
  23. </head>
  24. <body>
  25. <div class="container">
  26. <div class="lesson-title">
  27. <h1>Three.js 与 Shadertoy</h1>
  28. </div>
  29. <div class="lesson">
  30. <div class="lesson-main">
  31. <p><a href="https://shadertoy.com">Shadertoy</a> 是一个有着众多惊艳的shader实践的著名网站。 经常有人问如何在 Three.js 里面使用那些shader。</p>
  32. <p>重要的是要知道,被称作Shader<strong>TOY</strong> 事出有因。 通常与其把 ShaderToy 里的shader当做最佳实践,不如称它们是有趣的挑战,比如:<a
  33. href="https://dwitter.net">dwitter</a> (代码少于140 个字符) 或<a href="https://js13kgames.com">js13kGames</a>
  34. (用不多于13k代码制作游戏)。</p>
  35. <p>使用Shadertoy 的难题是, <em>给特定位置的像素着色写函数从而绘制有趣的图像</em>。这是一种有趣的挑战,很多的结果非常惊艳。但请注意,这并非最佳实践。</p>
  36. <p>点击 <a href="https://www.shadertoy.com/view/XtsSWs">这个惊艳的shader绘制了整个城市</a></p>
  37. <div class="threejs_center"><img src="../resources/images/shadertoy-skyline.png"></div>
  38. <p>在我的GPU 上全屏运行,它的运行速度为每秒大约5帧。与<a
  39. href="https://store.steampowered.com/app/255710/Cities_Skylines/">《城市:天际线》</a>这样的游戏形成鲜明对比。</p>
  40. <div class="threejs_center"><img src="../resources/images/cities-skylines.jpg" style="width: 600px;"></div>
  41. <p>这个游戏在同一台机器上每秒运行 30-60 帧,因为它使用更多 传统技术,建筑物由三角形绘制而成,并带有纹理,等等...</p>
  42. <p>言归正传,让我们回到如何在three.js使用 Shadertoy的shader 。</p>
  43. <p>当你在 <a href="https://www.shadertoy.com/new">shadertoy.com</a>上点击“新建”,这是个初始的shader,至少 2019 年 1 月是这样的。</p>
  44. <pre class="prettyprint showlinemods notranslate lang-glsl" translate="no">// By iq: https://www.shadertoy.com/user/iq
  45. // license: Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
  46. void mainImage( out vec4 fragColor, in vec2 fragCoord )
  47. {
  48. // Normalized pixel coordinates (from 0 to 1)
  49. vec2 uv = fragCoord/iResolution.xy;
  50. // Time varying pixel color
  51. vec3 col = 0.5 + 0.5*cos(iTime+uv.xyx+vec3(0,2,4));
  52. // Output to screen
  53. fragColor = vec4(col,1.0);
  54. }
  55. </pre>
  56. <p>关于shader你首要知道的重点是,他们是用一种叫做GLSL (Graphics Library Shading Language)的语言写成的,这是一种专为3D 数学设计的强类型语言。在上面我们看到<code
  57. class="notranslate" translate="no">vec4</code>, <code class="notranslate" translate="no">vec2</code>,<code
  58. class="notranslate" translate="no">vec3</code> 这三种特定类型。 一个 <code class="notranslate"
  59. translate="no">vec2</code> 有2个value, 一个 <code class="notranslate" translate="no">vec3</code>
  60. 有3个value,一个<code class="notranslate" translate="no">vec4</code> 有4个 values。他们的使用方法非常灵活。最常见的一种是通过 <code
  61. class="notranslate" translate="no">x</code>, <code class="notranslate" translate="no">y</code>, <code
  62. class="notranslate" translate="no">z</code>, 以及<code class="notranslate" translate="no">w</code> 表示向里。</p>
  63. <pre class="prettyprint showlinemods notranslate lang-glsl" translate="no">vec4 v1 = vec4(1.0, 2.0, 3.0, 4.0);
  64. float v2 = v1.x + v1.y; // adds 1.0 + 2.0
  65. </pre>
  66. <p>与JavaScript不同,GLSL更像是C / C++,其中变量必须定义类型,所以不能写成这样<code class="notranslate" translate="no">var v = 1.2;</code>
  67. 而是通过 <code class="notranslate" translate="no">float v = 1.2;</code> 将 <code class="notranslate"
  68. translate="no">v</code> 声明为浮点数。 </p>
  69. <p>详解 GLSL超出本文范畴。 概览GLSL可以点击<a
  70. href="https://webglfundamentals.org/webgl/lessons/webgl-shaders-and-glsl.html">本文</a>
  71. ,进阶可以查看 <a href="https://thebookofshaders.com/">本系列</a>。</p>
  72. <p>注意,在2019 年 1 月,
  73. <a href="https://shadertoy.com">shadertoy.com</a> 仅关注 <em>fragment
  74. shaders</em>. Fragment shader的职责在于,给定一个像素的位置,输出该像素颜色。
  75. </p>
  76. <p>上面的代码我们看到 shader 有一个<code class="notranslate" translate="no">out</code> 修饰的叫<code class="notranslate"
  77. translate="no">fragColor</code>的参数。<code class="notranslate" translate="no">out</code> 代表 <code
  78. class="notranslate" translate="no">output</code>。这个参数向函数传递参数。我们需要将其设置为某种颜色。</p>
  79. <p>它也有一个 叫 <code class="notranslate" translate="no">fragCoord</code>的<code class="notranslate"
  80. translate="no">in</code> (代表 input)参数。 这代表了将要绘制的像素坐标。基于坐标我们可以生成特定颜色。 如果canvas有 400x300 像素,那么函数将会被调用 400x300
  81. 次或者说是 120,000 次。 每次 <code class="notranslate" translate="no">fragCoord</code> 都是一个不同的像素坐标。</p>
  82. <p>还有 2 个正在使用但未在代码中定义的变量, 一是
  83. <code class="notranslate" translate="no">iResolution</code>。 该参数设置 canvas分辨率 。若该参数设置为
  84. 400x300 则 <code class="notranslate" translate="no">iResolution</code> 是 400,300 。随着像素值
  85. 在400,300变化 <code class="notranslate" translate="no">uv</code> 将在texture的纵横两个方向从 0.0 to 1.0 变化。 使用
  86. <em>规范化</em> 值能简化工作,而且 shadertoy上大部分的
  87. shaders也以类似方式开始。
  88. </p>
  89. <p>shader中另一个未定义的参数是 <code class="notranslate" translate="no">iTime</code>。 该参数代表页面加载后的秒数。</p>
  90. <p>上面这俩全局变量在shader术语中被称为 <em>uniform</em> 变量。 之所以被称为 <em>uniform</em>
  91. 在于这些变量在shader的一次调用中保持uniform(统一),直到下一次shader调用。需要注意的是,这些参数都是在shadertoy定义的特定变量, 而非GLSL<em>官方</em>
  92. 变量。这俩变量是发明shadertoy的人定义的。</p>
  93. <p>这篇 <a href="https://www.shadertoy.com/howto">Shadertoy 文档</a>中有更多定义。 现在让我们一起来写点代码来操作上面俩shader参数。</p>
  94. <p>首先我们定义一个填充canvas的plane。
  95. 参考这篇<a href="backgrounds.html">关于背景的文章</a>。
  96. 我们以这篇文章开始,不过要先删掉cube。代码很简单,如下:</p>
  97. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">function main() {
  98. const canvas = document.querySelector('#c');
  99. const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
  100. renderer.autoClearColor = false;
  101. const camera = new THREE.OrthographicCamera(
  102. -1, // left
  103. 1, // right
  104. 1, // top
  105. -1, // bottom
  106. -1, // near,
  107. 1, // far
  108. );
  109. const scene = new THREE.Scene();
  110. const plane = new THREE.PlaneGeometry(2, 2);
  111. const material = new THREE.MeshBasicMaterial({
  112. color: 'red',
  113. });
  114. scene.add(new THREE.Mesh(plane, material));
  115. function resizeRendererToDisplaySize(renderer) {
  116. const canvas = renderer.domElement;
  117. const width = canvas.clientWidth;
  118. const height = canvas.clientHeight;
  119. const needResize = canvas.width !== width || canvas.height !== height;
  120. if (needResize) {
  121. renderer.setSize(width, height, false);
  122. }
  123. return needResize;
  124. }
  125. function render() {
  126. resizeRendererToDisplaySize(renderer);
  127. renderer.render(scene, camera);
  128. requestAnimationFrame(render);
  129. }
  130. requestAnimationFrame(render);
  131. }
  132. main();
  133. </pre>
  134. <p>正如<a href="backgrounds.html">关于背景的文章</a>所解释,这些参数将定义
  135. <a href="/docs/#api/en/cameras/OrthographicCamera"><code class="notranslate"
  136. translate="no">OrthographicCamera</code></a> 以及一个大小是2个单位且被canvas填充的plane。
  137. 当前我们得到一个红色的canvas,因为我们使用的是红色
  138. <a href="/docs/#api/en/materials/MeshBasicMaterial"><code class="notranslate"
  139. translate="no">MeshBasicMaterial</code></a>材质。
  140. </p>
  141. <p></p>
  142. <div translate="no" class="threejs_example_container notranslate">
  143. <div><iframe class="threejs_example notranslate" translate="no" style=" "
  144. src="/manual/examples/resources/editor.html?url=/manual/examples/shadertoy-prep.html"></iframe></div>
  145. <a class="threejs_center" href="/manual/examples/shadertoy-prep.html" target="_blank">点击此处在新标签页中打开</a>
  146. </div>
  147. <p></p>
  148. <p>现在我们添加shadertoy shader。 </p>
  149. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">const fragmentShader = `
  150. #include &lt;common&gt;
  151. uniform vec3 iResolution;
  152. uniform float iTime;
  153. // By iq: https://www.shadertoy.com/user/iq
  154. // license: Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
  155. void mainImage( out vec4 fragColor, in vec2 fragCoord )
  156. {
  157. // Normalized pixel coordinates (from 0 to 1)
  158. vec2 uv = fragCoord/iResolution.xy;
  159. // Time varying pixel color
  160. vec3 col = 0.5 + 0.5*cos(iTime+uv.xyx+vec3(0,2,4));
  161. // Output to screen
  162. fragColor = vec4(col,1.0);
  163. }
  164. void main() {
  165. mainImage(gl_FragColor, gl_FragCoord.xy);
  166. }
  167. `;
  168. </pre>
  169. <p>上面我们定义了刚刚提到的2个uniform变量,接下来我们关注从shadertoy里的shader GLSL代码。我们调用
  170. <code class="notranslate" translate="no">mainImage</code> ,同时传递
  171. <code class="notranslate" translate="no">gl_FragColor</code> 和 <code class="notranslate"
  172. translate="no">gl_FragCoord.xy</code>。 <code class="notranslate" translate="no">gl_FragColor</code>
  173. 是一个WebGL官方
  174. 全局变量,代表当前像素的颜色。<code class="notranslate" translate="no">gl_FragCoord</code> 是另一个WebGL官方
  175. 全局变量,代表当前着色像素的坐标。
  176. </p>
  177. <p>然后设置three.js uniforms,以便控制shader参数。 </p>
  178. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">const uniforms = {
  179. iTime: { value: 0 },
  180. iResolution: { value: new THREE.Vector3() },
  181. };
  182. </pre>
  183. <p>在THREE.js的每个uniform都有 <code class="notranslate" translate="no">value</code> 参数。该参数必须与shader中的uniform类型匹配。</p>
  184. <p>然后我们把fragmentshader和uniforms都传递给
  185. <a href="/docs/#api/en/materials/ShaderMaterial"><code class="notranslate"
  186. translate="no">ShaderMaterial</code></a>。
  187. </p>
  188. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">-const material = new THREE.MeshBasicMaterial({
  189. - color: 'red',
  190. -});
  191. +const material = new THREE.ShaderMaterial({
  192. + fragmentShader,
  193. + uniforms,
  194. +});
  195. </pre>
  196. <p>在渲染前,需要先设置uniforms的值。
  197. </p>
  198. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">-function render() {
  199. +function render(time) {
  200. + time *= 0.001; // convert to seconds
  201. resizeRendererToDisplaySize(renderer);
  202. + const canvas = renderer.domElement;
  203. + uniforms.iResolution.value.set(canvas.width, canvas.height, 1);
  204. + uniforms.iTime.value = time;
  205. renderer.render(scene, camera);
  206. requestAnimationFrame(render);
  207. }
  208. </pre>
  209. <blockquote>
  210. <p>注意:
  211. 不清楚为何<code class="notranslate" translate="no">iResolution</code>是个<code class="notranslate"
  212. translate="no">vec3</code>,而且
  213. <a href="https://www.shadertoy.com/howto">shadertoy.com</a>上的文档也没有说明第三个参数是啥,在上面没有用到第三个参数所以暂时设置为1。¯\_(ツ)_/¯
  214. </p>
  215. </blockquote>
  216. <p></p>
  217. <div translate="no" class="threejs_example_container notranslate">
  218. <div><iframe class="threejs_example notranslate" translate="no" style=" "
  219. src="/manual/examples/resources/editor.html?url=/manual/examples/shadertoy-basic.html"></iframe></div>
  220. <a class="threejs_center" href="/manual/examples/shadertoy-basic.html" target="_blank">点击此处在新标签页中打开</a>
  221. </div>
  222. <p></p>
  223. <p>上面定义的新shader效果与我们在 <a href="https://www.shadertoy.com/new">Shadertoy</a>上看到的匹配,
  224. 至少 2019 年 1 月是这样的 😉。这个shader做了些啥? </p>
  225. <ul>
  226. <li><code class="notranslate" translate="no">uv</code> 从0变到1。</li>
  227. <li><code class="notranslate" translate="no">cos(uv.xyx)</code>得到3个cos值,以<code class="notranslate"
  228. translate="no">vec3</code>形式输出,一个是<code class="notranslate" translate="no">uv.x</code>的cos值, 一个是<code
  229. class="notranslate" translate="no">uv.y</code>的cos值,最后是<code class="notranslate"
  230. translate="no">uv.x</code>的cos值。</li>
  231. <li>参数中加上时间 <code class="notranslate" translate="no">cos(iTime+uv.xyx)</code>形成动画。</li>
  232. <li>另外<code class="notranslate" translate="no">vec3(0,2,4)</code>参数与<code class="notranslate"
  233. translate="no">cos(iTime+uv.xyx+vec3(0,2,4))</code> 求和使cos波偏移。</li>
  234. <li><code class="notranslate" translate="no">cos</code> 输出值范围从-1到1,所以经过<code class="notranslate"
  235. translate="no">0.5 * 0.5 + cos(...)</code>从-1 &lt;-&gt; 1 变为 0.0 &lt;-&gt; 1.0</li>
  236. <li>计算结果作为RGB颜色赋予当前像素。</li>
  237. </ul>
  238. <p>为了更容易看出cos波形我们稍微调整一下代码。当前<code class="notranslate" translate="no">uv</code>
  239. 仅能从0到1,因cos波形在2π处重复,我们通过将uv乘上40,实现cos波形从0到40的变化,这将会使cos波形重复大约6.3次。</p>
  240. <pre class="prettyprint showlinemods notranslate lang-glsl" translate="no">-vec3 col = 0.5 + 0.5*cos(iTime+uv.xyx+vec3(0,2,4));
  241. +vec3 col = 0.5 + 0.5*cos(iTime+uv.xyx*40.0+vec3(0,2,4));
  242. </pre>
  243. <p>如下我数了下大约是重复了6.3次,通过 <code class="notranslate"
  244. translate="no">+vec3(0,2,4)</code>偏移了4因此我们能看到红蓝相间,否则我们将看到红蓝颜色混合为紫色。</p>
  245. <p></p>
  246. <div translate="no" class="threejs_example_container notranslate">
  247. <div><iframe class="threejs_example notranslate" translate="no" style=" "
  248. src="/manual/examples/resources/editor.html?url=/manual/examples/shadertoy-basic-x40.html"></iframe></div>
  249. <a class="threejs_center" href="/manual/examples/shadertoy-basic-x40.html" target="_blank">点击此处在新标签页中打开</a>
  250. </div>
  251. <p></p>
  252. <p>了解到输入如此简单,当看到如
  253. <a href="https://www.shadertoy.com/view/MdXGW2">a city canal</a>,
  254. <a href="https://www.shadertoy.com/view/4ttSWf">a forest</a>,
  255. <a href="https://www.shadertoy.com/view/ld3Gz2">a snail</a>,
  256. <a href="https://www.shadertoy.com/view/4tBXR1">a
  257. mushroom</a>这些结果,让人更觉得充满挑战。幸运的是这也清晰的说明为何相对于传统的三角形构成的场景,这通常这不是正确的方式。因为每个像素颜色都需要经过许多数学计算,通常会导致运行缓慢。
  258. </p>
  259. <p>有些shadertoy的shaders使用纹理贴图作为输入,比如<a href="https://www.shadertoy.com/view/MsXSzM">这个</a>。</p>
  260. <pre class="prettyprint showlinemods notranslate lang-glsl" translate="no">// By Daedelus: https://www.shadertoy.com/user/Daedelus
  261. // license: Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
  262. #define TIMESCALE 0.25
  263. #define TILES 8
  264. #define COLOR 0.7, 1.6, 2.8
  265. void mainImage( out vec4 fragColor, in vec2 fragCoord )
  266. {
  267. vec2 uv = fragCoord.xy / iResolution.xy;
  268. uv.x *= iResolution.x / iResolution.y;
  269. vec4 noise = texture2D(iChannel0, floor(uv * float(TILES)) / float(TILES));
  270. float p = 1.0 - mod(noise.r + noise.g + noise.b + iTime * float(TIMESCALE), 1.0);
  271. p = min(max(p * 3.0 - 1.8, 0.1), 2.0);
  272. vec2 r = mod(uv * float(TILES), 1.0);
  273. r = vec2(pow(r.x - 0.5, 2.0), pow(r.y - 0.5, 2.0));
  274. p *= 1.0 - pow(min(1.0, 12.0 * dot(r, r)), 2.0);
  275. fragColor = vec4(COLOR, 1.0) * p;
  276. }
  277. </pre>
  278. <p>给shader传递纹理与<a href="textures.html">给常规材质传递纹理</a>一样,只不过需要通过uniforms来设置纹理。</p>
  279. <p>首先需要给shader添加一个纹理的uniform。在GLSL中对应为
  280. <code class="notranslate" translate="no">sampler2D</code> 。
  281. </p>
  282. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">const fragmentShader = `
  283. #include &lt;common&gt;
  284. uniform vec3 iResolution;
  285. uniform float iTime;
  286. +uniform sampler2D iChannel0;
  287. ...
  288. </pre>
  289. <p>然后我们可以像<a href="textures.html">这里</a>一样载入纹理,并且设置uniform的值。</p>
  290. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">+const loader = new THREE.TextureLoader();
  291. +const texture = loader.load('resources/images/bayer.png');
  292. +texture.minFilter = THREE.NearestFilter;
  293. +texture.magFilter = THREE.NearestFilter;
  294. +texture.wrapS = THREE.RepeatWrapping;
  295. +texture.wrapT = THREE.RepeatWrapping;
  296. const uniforms = {
  297. iTime: { value: 0 },
  298. iResolution: { value: new THREE.Vector3() },
  299. + iChannel0: { value: texture },
  300. };
  301. </pre>
  302. <p></p>
  303. <div translate="no" class="threejs_example_container notranslate">
  304. <div><iframe class="threejs_example notranslate" translate="no" style=" "
  305. src="/manual/examples/resources/editor.html?url=/manual/examples/shadertoy-bleepy-blocks.html"></iframe>
  306. </div>
  307. <a class="threejs_center" href="/manual/examples/shadertoy-bleepy-blocks.html"
  308. target="_blank">点击此处在新标签页中打开</a>
  309. </div>
  310. <p></p>
  311. <p>到目前为止,我们一直用<a href="https://shadertoy.com">Shadertoy.com</a>上的方式使用 Shadertoy
  312. shaders,即在canvas上绘制shader。但我们无需受限于此。请留意,通常人们在Shadertoy上写的函数仅输入一个<code class="notranslate"
  313. translate="no">fragCoord</code> 和一个<code class="notranslate" translate="no">iResolution</code>参数。<code
  314. class="notranslate" translate="no">fragCoord</code> 不一定来自像素坐标,像纹理坐标也可以,然后就可以像常规的纹理一样使用。通常把这种通过函数生成纹理的技术叫做<a
  315. href="https://www.google.com/search?q=procedural+texture"><em>procedural texture</em></a>。</p>
  316. <p>让我们改一改上面的shader,最简单的莫过于使用three.js提供的纹理坐标,乘上<code class="notranslate"
  317. translate="no">iResolution</code>再传到<code class="notranslate" translate="no">fragCoords</code>。</p>
  318. <p>我们需要加一个<em>varying</em>变量。varing变量通过对顶点进行插值(也叫varied)实现从vertex shader传值到fragment shader。在fragment
  319. shader中使用之前需要先声明该变量。这个变量名中的 <code class="notranslate" translate="no">uv</code>代表纹理坐标,前面的<code
  320. class="notranslate" translate="no">v</code>代表<em>varying</em>。</p>
  321. <pre class="prettyprint showlinemods notranslate lang-glsl" translate="no">...
  322. +varying vec2 vUv;
  323. void main() {
  324. - mainImage(gl_FragColor, gl_FragCoord.xy);
  325. + mainImage(gl_FragColor, vUv * iResolution.xy);
  326. }
  327. </pre>
  328. <p>然后我们需要实现vertex shader,下面是最简化的three.js的vertex shader。three.js中定义了<code class="notranslate"
  329. translate="no">uv</code>,<code class="notranslate" translate="no">projectionMatrix</code>,<code
  330. class="notranslate" translate="no">modelViewMatrix</code>,和 <code class="notranslate"
  331. translate="no">position</code>这几个参数,且可以传值给shader。</p>
  332. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">const vertexShader = `
  333. varying vec2 vUv;
  334. void main() {
  335. vUv = uv;
  336. gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
  337. }
  338. `;
  339. </pre>
  340. <p>把vertexshader传给<a href="/docs/#api/en/materials/ShaderMaterial"><code class="notranslate"
  341. translate="no">ShaderMaterial</code></a>。</p>
  342. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">const material = new THREE.ShaderMaterial({
  343. vertexShader,
  344. fragmentShader,
  345. uniforms,
  346. });
  347. </pre>
  348. <p>因为<code class="notranslate" translate="no">iResolution</code>保持不变,因此可以在初始化时设定它的值。</p>
  349. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">const uniforms = {
  350. iTime: { value: 0 },
  351. - iResolution: { value: new THREE.Vector3() },
  352. + iResolution: { value: new THREE.Vector3(1, 1, 1) },
  353. iChannel0: { value: texture },
  354. };
  355. </pre>
  356. <p>在渲染时无需设置它的值。</p>
  357. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">-const canvas = renderer.domElement;
  358. -uniforms.iResolution.value.set(canvas.width, canvas.height, 1);
  359. uniforms.iTime.value = time;
  360. </pre>
  361. <p>另外我从<a href="responsive.html">关于响应能力的文章</a>复制了一段3个旋转cube代码。效果如下:</p>
  362. <p></p>
  363. <div translate="no" class="threejs_example_container notranslate">
  364. <div><iframe class="threejs_example notranslate" translate="no" style=" "
  365. src="/manual/examples/resources/editor.html?url=/manual/examples/shadertoy-as-texture.html"></iframe>
  366. </div>
  367. <a class="threejs_center" href="/manual/examples/shadertoy-as-texture.html" target="_blank">点击此处在新标签页中打开</a>
  368. </div>
  369. <p></p>
  370. <p>希望这篇文字能说清在three.js使用shadertoy shader的入门方法。再次重申,大部分的shadertoy
  371. shaders与其说是性能方面的最佳实践,不如称它们是有趣的挑战(通过函数实现所有绘制)。尽管如此,他们还是有着令人印象深刻的惊艳和美,了解shader工作原理可以学到很多东西。</p>
  372. </div>
  373. </div>
  374. </div>
  375. <script src="../resources/prettify.js"></script>
  376. <script src="../resources/lesson.js"></script>
  377. </body>
  378. </html>