You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							416 lines
						
					
					
						
							23 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							416 lines
						
					
					
						
							23 KiB
						
					
					
				
								<!DOCTYPE html><html lang="en"><head>
							 | 
						|
								    <meta charset="utf-8">
							 | 
						|
								    <title>and Shadertoy</title>
							 | 
						|
								    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
							 | 
						|
								    <meta name="twitter:card" content="summary_large_image">
							 | 
						|
								    <meta name="twitter:site" content="@threejs">
							 | 
						|
								    <meta name="twitter:title" content="Three.js – and Shadertoy">
							 | 
						|
								    <meta property="og:image" content="https://threejs.org/files/share.png">
							 | 
						|
								    <link rel="shortcut icon" href="/files/favicon_white.ico" media="(prefers-color-scheme: dark)">
							 | 
						|
								    <link rel="shortcut icon" href="/files/favicon.ico" media="(prefers-color-scheme: light)">
							 | 
						|
								
							 | 
						|
								    <link rel="stylesheet" href="/manual/resources/lesson.css">
							 | 
						|
								    <link rel="stylesheet" href="/manual/resources/lang.css">
							 | 
						|
								<!-- Import maps polyfill -->
							 | 
						|
								<!-- Remove this when import maps will be widely supported -->
							 | 
						|
								<script async src="https://unpkg.com/es-module-shims@1.3.6/dist/es-module-shims.js"></script>
							 | 
						|
								
							 | 
						|
								<script type="importmap">
							 | 
						|
								{
							 | 
						|
								  "imports": {
							 | 
						|
								    "three": "../../build/three.module.js"
							 | 
						|
								  }
							 | 
						|
								}
							 | 
						|
								</script>
							 | 
						|
								  </head>
							 | 
						|
								  <body>
							 | 
						|
								    <div class="container">
							 | 
						|
								      <div class="lesson-title">
							 | 
						|
								        <h1>and Shadertoy</h1>
							 | 
						|
								      </div>
							 | 
						|
								      <div class="lesson">
							 | 
						|
								        <div class="lesson-main">
							 | 
						|
								          <p><a href="https://shadertoy.com">Shadertoy</a> is a famous website hosting amazing shader
							 | 
						|
								experiments. People often ask how they can use those shaders with Three.js.</p>
							 | 
						|
								<p>It's important to recognize it's called Shader<strong>TOY</strong> for a reason. In general
							 | 
						|
								shadertoy shaders are not about best practices. Rather they are a fun challenge
							 | 
						|
								similar to say <a href="https://dwitter.net">dwitter</a> (write code in 140 characters) or
							 | 
						|
								<a href="https://js13kgames.com">js13kGames</a> (make a game in 13k or less).</p>
							 | 
						|
								<p>In the case of Shadertoy the puzzle is, <em>write a function that for a given pixel
							 | 
						|
								location outputs a color that draws something interesting</em>. It's a fun challenge
							 | 
						|
								and many of the result are amazing. But, it is not best practice.</p>
							 | 
						|
								<p>Compare <a href="https://www.shadertoy.com/view/XtsSWs">this amazing shadertoy shader that draws an entire city</a></p>
							 | 
						|
								<div class="threejs_center"><img src="../resources/images/shadertoy-skyline.png"></div>
							 | 
						|
								
							 | 
						|
								<p>Fullscreen on my GPU it runs at about 5 frames a second. Contrast that to
							 | 
						|
								<a href="https://store.steampowered.com/app/255710/Cities_Skylines/">a game like Cities: Skylines</a></p>
							 | 
						|
								<div class="threejs_center"><img src="../resources/images/cities-skylines.jpg" style="width: 600px;"></div>
							 | 
						|
								
							 | 
						|
								<p>This game runs 30-60 frames a second on the same machine because it uses more
							 | 
						|
								traditional techniques, drawing buildings made from triangles with textures on
							 | 
						|
								them, etc...</p>
							 | 
						|
								<p>Still, let's go over using a Shadertoy shader with three.js.</p>
							 | 
						|
								<p>This is the default shadertoy shader if you <a href="https://www.shadertoy.com/new">pick "New" on shadertoy.com</a>, at least as of January 2019.</p>
							 | 
						|
								<pre class="prettyprint showlinemods notranslate lang-glsl" translate="no">// By iq: https://www.shadertoy.com/user/iq  
							 | 
						|
								// license: Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
							 | 
						|
								void mainImage( out vec4 fragColor, in vec2 fragCoord )
							 | 
						|
								{
							 | 
						|
								    // Normalized pixel coordinates (from 0 to 1)
							 | 
						|
								    vec2 uv = fragCoord/iResolution.xy;
							 | 
						|
								
							 | 
						|
								    // Time varying pixel color
							 | 
						|
								    vec3 col = 0.5 + 0.5*cos(iTime+uv.xyx+vec3(0,2,4));
							 | 
						|
								
							 | 
						|
								    // Output to screen
							 | 
						|
								    fragColor = vec4(col,1.0);
							 | 
						|
								}
							 | 
						|
								</pre>
							 | 
						|
								<p>One thing important to understand about shaders is they are written in a
							 | 
						|
								language called GLSL (Graphics Library Shading Language) designed for 3D math
							 | 
						|
								which includes special types. Above we see <code class="notranslate" translate="no">vec4</code>, <code class="notranslate" translate="no">vec2</code>, <code class="notranslate" translate="no">vec3</code> as 3 such
							 | 
						|
								special types. A <code class="notranslate" translate="no">vec2</code> has 2 values, a <code class="notranslate" translate="no">vec3</code> 3, a <code class="notranslate" translate="no">vec4</code> 4 values. They can be
							 | 
						|
								addressed in a bunch of ways. The most common ways are with <code class="notranslate" translate="no">x</code>, <code class="notranslate" translate="no">y</code>, <code class="notranslate" translate="no">z</code>, and
							 | 
						|
								<code class="notranslate" translate="no">w</code> as in</p>
							 | 
						|
								<pre class="prettyprint showlinemods notranslate lang-glsl" translate="no">vec4 v1 = vec4(1.0, 2.0, 3.0, 4.0);
							 | 
						|
								float v2 = v1.x + v1.y;  // adds 1.0 + 2.0
							 | 
						|
								</pre>
							 | 
						|
								<p>Unlike JavaScript, GLSL is more like C/C++ where variables have to have their
							 | 
						|
								type declared so instead of <code class="notranslate" translate="no">var v = 1.2;</code> it's <code class="notranslate" translate="no">float v = 1.2;</code> declaring <code class="notranslate" translate="no">v</code>
							 | 
						|
								to be a floating point number.</p>
							 | 
						|
								<p>Explaining GLSL in detail is more than we can do in this article. For a quick
							 | 
						|
								overview see <a href="https://webglfundamentals.org/webgl/lessons/webgl-shaders-and-glsl.html">this article</a>
							 | 
						|
								and maybe follow that up with <a href="https://thebookofshaders.com/">this series</a>.</p>
							 | 
						|
								<p>It should be noted that, at least as of January 2019,
							 | 
						|
								<a href="https://shadertoy.com">shadertoy.com</a> only concerns itself with <em>fragment
							 | 
						|
								shaders</em>. A fragment shader's responsibility is, given a pixel location output
							 | 
						|
								a color for that pixel.</p>
							 | 
						|
								<p>Looking at the function above we can see the shader has an <code class="notranslate" translate="no">out</code> parameter
							 | 
						|
								called <code class="notranslate" translate="no">fragColor</code>. <code class="notranslate" translate="no">out</code> stands for <code class="notranslate" translate="no">output</code>. It's a parameter the function is
							 | 
						|
								expected to provide a value for. We need to set this to some color.</p>
							 | 
						|
								<p>It also has an <code class="notranslate" translate="no">in</code> (for input) parameter called <code class="notranslate" translate="no">fragCoord</code>. This is the pixel
							 | 
						|
								coordinate that is about to be drawn. We can use that coordinate to decide on a
							 | 
						|
								color. If the canvas we're drawing to is 400x300 pixels then the function will
							 | 
						|
								be called 400x300 times or 120,000 times. Each time <code class="notranslate" translate="no">fragCoord</code> will be a
							 | 
						|
								different pixel coordinate.</p>
							 | 
						|
								<p>There are 2 more variables being used that are not defined in the code. One is
							 | 
						|
								<code class="notranslate" translate="no">iResolution</code>. This is set to the resolution of the canvas. If the canvas is
							 | 
						|
								400x300 then <code class="notranslate" translate="no">iResolution</code> would be 400,300 so as the pixel coordinates change
							 | 
						|
								that makes <code class="notranslate" translate="no">uv</code> go from 0.0 to 1.0 across and up the texture. Working with
							 | 
						|
								<em>normalized</em> values often makes things easier and so the majority of shadertoy
							 | 
						|
								shaders start with something like this.</p>
							 | 
						|
								<p>The other undefined variable in the shader is <code class="notranslate" translate="no">iTime</code>. This is the time since
							 | 
						|
								the page loaded in seconds.</p>
							 | 
						|
								<p>In shader jargon these global variables are called <em>uniform</em> variables. They are
							 | 
						|
								called <em>uniform</em> because they don't change, they stay uniform from one iteration
							 | 
						|
								of the shader to the next. It's important to note all of them are specific to
							 | 
						|
								shadertoy. They not <em>official</em> GLSL variables. They are variables the makers of
							 | 
						|
								shadertoy made up.</p>
							 | 
						|
								<p>The <a href="https://www.shadertoy.com/howto">Shadertoy docs define several more</a>. For
							 | 
						|
								now let's write something that handles the two being used in the shader above.</p>
							 | 
						|
								<p>The first thing to do is let's make a single plane that fills the canvas. If you
							 | 
						|
								haven't read it yet we did this in <a href="backgrounds.html">the article on backgrounds</a>
							 | 
						|
								so let's grab that example but remove the cubes. It's pretty short so here's the
							 | 
						|
								entire thing</p>
							 | 
						|
								<pre class="prettyprint showlinemods notranslate lang-js" translate="no">function main() {
							 | 
						|
								  const canvas = document.querySelector('#c');
							 | 
						|
								  const renderer = new THREE.WebGLRenderer({canvas});
							 | 
						|
								  renderer.autoClearColor = false;
							 | 
						|
								
							 | 
						|
								  const camera = new THREE.OrthographicCamera(
							 | 
						|
								    -1, // left
							 | 
						|
								     1, // right
							 | 
						|
								     1, // top
							 | 
						|
								    -1, // bottom
							 | 
						|
								    -1, // near,
							 | 
						|
								     1, // far
							 | 
						|
								  );
							 | 
						|
								  const scene = new THREE.Scene();
							 | 
						|
								  const plane = new THREE.PlaneGeometry(2, 2);
							 | 
						|
								  const material = new THREE.MeshBasicMaterial({
							 | 
						|
								      color: 'red',
							 | 
						|
								  });
							 | 
						|
								  scene.add(new THREE.Mesh(plane, material));
							 | 
						|
								
							 | 
						|
								  function resizeRendererToDisplaySize(renderer) {
							 | 
						|
								    const canvas = renderer.domElement;
							 | 
						|
								    const width = canvas.clientWidth;
							 | 
						|
								    const height = canvas.clientHeight;
							 | 
						|
								    const needResize = canvas.width !== width || canvas.height !== height;
							 | 
						|
								    if (needResize) {
							 | 
						|
								      renderer.setSize(width, height, false);
							 | 
						|
								    }
							 | 
						|
								    return needResize;
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  function render() {
							 | 
						|
								    resizeRendererToDisplaySize(renderer);
							 | 
						|
								
							 | 
						|
								    renderer.render(scene, camera);
							 | 
						|
								
							 | 
						|
								    requestAnimationFrame(render);
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  requestAnimationFrame(render);
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								main();
							 | 
						|
								</pre>
							 | 
						|
								<p>As <a href="backgrounds.html">explained in the backgrounds article</a> an
							 | 
						|
								<a href="/docs/#api/en/cameras/OrthographicCamera"><code class="notranslate" translate="no">OrthographicCamera</code></a> with these parameters and a 2 unit plane will fill the
							 | 
						|
								canvas. For now all we'll get is a red canvas as our plane is using a red
							 | 
						|
								<a href="/docs/#api/en/materials/MeshBasicMaterial"><code class="notranslate" translate="no">MeshBasicMaterial</code></a>.</p>
							 | 
						|
								<p></p><div translate="no" class="threejs_example_container notranslate">
							 | 
						|
								  <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/shadertoy-prep.html"></iframe></div>
							 | 
						|
								  <a class="threejs_center" href="/manual/examples/shadertoy-prep.html" target="_blank">click here to open in a separate window</a>
							 | 
						|
								</div>
							 | 
						|
								
							 | 
						|
								<p></p>
							 | 
						|
								<p>Now that we have something working let's add the shadertoy shader. </p>
							 | 
						|
								<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const fragmentShader = `
							 | 
						|
								#include <common>
							 | 
						|
								
							 | 
						|
								uniform vec3 iResolution;
							 | 
						|
								uniform float iTime;
							 | 
						|
								
							 | 
						|
								// By iq: https://www.shadertoy.com/user/iq  
							 | 
						|
								// license: Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
							 | 
						|
								void mainImage( out vec4 fragColor, in vec2 fragCoord )
							 | 
						|
								{
							 | 
						|
								    // Normalized pixel coordinates (from 0 to 1)
							 | 
						|
								    vec2 uv = fragCoord/iResolution.xy;
							 | 
						|
								
							 | 
						|
								    // Time varying pixel color
							 | 
						|
								    vec3 col = 0.5 + 0.5*cos(iTime+uv.xyx+vec3(0,2,4));
							 | 
						|
								
							 | 
						|
								    // Output to screen
							 | 
						|
								    fragColor = vec4(col,1.0);
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								void main() {
							 | 
						|
								  mainImage(gl_FragColor, gl_FragCoord.xy);
							 | 
						|
								}
							 | 
						|
								`;
							 | 
						|
								</pre>
							 | 
						|
								<p>Above we declared the 2 uniform variables we talked about. Then we inserted the
							 | 
						|
								shader GLSL code from shadertoy. Finally we called <code class="notranslate" translate="no">mainImage</code> passing it
							 | 
						|
								<code class="notranslate" translate="no">gl_FragColor</code> and <code class="notranslate" translate="no">gl_FragCoord.xy</code>.  <code class="notranslate" translate="no">gl_FragColor</code> is an official WebGL
							 | 
						|
								global variable the shader is responsible for setting to whatever color it wants
							 | 
						|
								the current pixel to be. <code class="notranslate" translate="no">gl_FragCoord</code> is another official WebGL global
							 | 
						|
								variable that tells us the coordinate of the pixel we're currently choosing a
							 | 
						|
								color for.</p>
							 | 
						|
								<p>We then need to setup three.js uniforms so we can supply values to the shader.</p>
							 | 
						|
								<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const uniforms = {
							 | 
						|
								  iTime: { value: 0 },
							 | 
						|
								  iResolution:  { value: new THREE.Vector3() },
							 | 
						|
								};
							 | 
						|
								</pre>
							 | 
						|
								<p>Each uniform in THREE.js has <code class="notranslate" translate="no">value</code> parameter. That value has to match the type
							 | 
						|
								of the uniform.</p>
							 | 
						|
								<p>Then we pass both the fragment shader and uniforms to a <a href="/docs/#api/en/materials/ShaderMaterial"><code class="notranslate" translate="no">ShaderMaterial</code></a>.</p>
							 | 
						|
								<pre class="prettyprint showlinemods notranslate lang-js" translate="no">-const material = new THREE.MeshBasicMaterial({
							 | 
						|
								-    color: 'red',
							 | 
						|
								-});
							 | 
						|
								+const material = new THREE.ShaderMaterial({
							 | 
						|
								+  fragmentShader,
							 | 
						|
								+  uniforms,
							 | 
						|
								+});
							 | 
						|
								</pre>
							 | 
						|
								<p>and before rendering we need to set the values of the uniforms</p>
							 | 
						|
								<pre class="prettyprint showlinemods notranslate lang-js" translate="no">-function render() {
							 | 
						|
								+function render(time) {
							 | 
						|
								+  time *= 0.001;  // convert to seconds
							 | 
						|
								
							 | 
						|
								  resizeRendererToDisplaySize(renderer);
							 | 
						|
								
							 | 
						|
								+  const canvas = renderer.domElement;
							 | 
						|
								+  uniforms.iResolution.value.set(canvas.width, canvas.height, 1);
							 | 
						|
								+  uniforms.iTime.value = time;
							 | 
						|
								
							 | 
						|
								  renderer.render(scene, camera);
							 | 
						|
								
							 | 
						|
								  requestAnimationFrame(render);
							 | 
						|
								}
							 | 
						|
								</pre>
							 | 
						|
								<blockquote>
							 | 
						|
								<p>Note: I have no idea why <code class="notranslate" translate="no">iResolution</code> is a <code class="notranslate" translate="no">vec3</code> and what's in the 3rd value
							 | 
						|
								<a href="https://www.shadertoy.com/howto">is not documented on shadertoy.com</a>. It's
							 | 
						|
								not used above so just setting it to 1 for now. ¯\_(ツ)_/¯</p>
							 | 
						|
								</blockquote>
							 | 
						|
								<p></p><div translate="no" class="threejs_example_container notranslate">
							 | 
						|
								  <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/shadertoy-basic.html"></iframe></div>
							 | 
						|
								  <a class="threejs_center" href="/manual/examples/shadertoy-basic.html" target="_blank">click here to open in a separate window</a>
							 | 
						|
								</div>
							 | 
						|
								
							 | 
						|
								<p></p>
							 | 
						|
								<p>This <a href="https://www.shadertoy.com/new">matches what we see on Shadertoy for a new shader</a>,
							 | 
						|
								at least as of January 2019 😉. What's the shader above doing? </p>
							 | 
						|
								<ul>
							 | 
						|
								<li><code class="notranslate" translate="no">uv</code> goes from 0 to 1. </li>
							 | 
						|
								<li><code class="notranslate" translate="no">cos(uv.xyx)</code> gives us 3 cosine values as a <code class="notranslate" translate="no">vec3</code>. One for <code class="notranslate" translate="no">uv.x</code>, another for <code class="notranslate" translate="no">uv.y</code> and another for <code class="notranslate" translate="no">uv.x</code> again.</li>
							 | 
						|
								<li>Adding in the time, <code class="notranslate" translate="no">cos(iTime+uv.xyx)</code> makes them animate.</li>
							 | 
						|
								<li>Adding in <code class="notranslate" translate="no">vec3(0,2,4)</code> as in <code class="notranslate" translate="no">cos(iTime+uv.xyx+vec3(0,2,4))</code> offsets the cosine waves</li>
							 | 
						|
								<li><code class="notranslate" translate="no">cos</code> goes from -1 to 1 so the <code class="notranslate" translate="no">0.5 * 0.5 + cos(...)</code> converts from -1 <-> 1 to 0.0 <-> 1.0</li>
							 | 
						|
								<li>the results are then used as the RGB color for the current pixel</li>
							 | 
						|
								</ul>
							 | 
						|
								<p>A minor change will make it easier to see the cosine waves. Right now <code class="notranslate" translate="no">uv</code> only
							 | 
						|
								goes from 0 to 1. A cosine repeats at 2π so let's make it go from 0 to 40 by
							 | 
						|
								multiplying by 40.0. That should make it repeat about 6.3 times.</p>
							 | 
						|
								<pre class="prettyprint showlinemods notranslate lang-glsl" translate="no">-vec3 col = 0.5 + 0.5*cos(iTime+uv.xyx+vec3(0,2,4));
							 | 
						|
								+vec3 col = 0.5 + 0.5*cos(iTime+uv.xyx*40.0+vec3(0,2,4));
							 | 
						|
								</pre>
							 | 
						|
								<p>Counting below I see about 6.3 repeats. We can see the blue between the red
							 | 
						|
								since it's offset by 4 via the <code class="notranslate" translate="no">+vec3(0,2,4)</code>. Without that the blue and red
							 | 
						|
								would overlap perfectly making purple.</p>
							 | 
						|
								<p></p><div translate="no" class="threejs_example_container notranslate">
							 | 
						|
								  <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/shadertoy-basic-x40.html"></iframe></div>
							 | 
						|
								  <a class="threejs_center" href="/manual/examples/shadertoy-basic-x40.html" target="_blank">click here to open in a separate window</a>
							 | 
						|
								</div>
							 | 
						|
								
							 | 
						|
								<p></p>
							 | 
						|
								<p>Knowing how simple the inputs are and then seeing results like
							 | 
						|
								<a href="https://www.shadertoy.com/view/MdXGW2">a city canal</a>,
							 | 
						|
								<a href="https://www.shadertoy.com/view/4ttSWf">a forest</a>,
							 | 
						|
								<a href="https://www.shadertoy.com/view/ld3Gz2">a snail</a>,
							 | 
						|
								<a href="https://www.shadertoy.com/view/4tBXR1">a mushroom</a>
							 | 
						|
								make the challenge all that much more impressive. Hopefully they also make it
							 | 
						|
								clear why it's not generally the right approach vs the more traditional ways of
							 | 
						|
								making scenes from triangles. The fact that so much math has to be put into
							 | 
						|
								computing the color of every pixel means those examples run very slow.</p>
							 | 
						|
								<p>Some shadertoy shaders take textures as inputs like
							 | 
						|
								<a href="https://www.shadertoy.com/view/MsXSzM">this one</a>. </p>
							 | 
						|
								<pre class="prettyprint showlinemods notranslate lang-glsl" translate="no">// By Daedelus: https://www.shadertoy.com/user/Daedelus
							 | 
						|
								// license: Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
							 | 
						|
								#define TIMESCALE 0.25 
							 | 
						|
								#define TILES 8
							 | 
						|
								#define COLOR 0.7, 1.6, 2.8
							 | 
						|
								
							 | 
						|
								void mainImage( out vec4 fragColor, in vec2 fragCoord )
							 | 
						|
								{
							 | 
						|
								    vec2 uv = fragCoord.xy / iResolution.xy;
							 | 
						|
								    uv.x *= iResolution.x / iResolution.y;
							 | 
						|
								
							 | 
						|
								    vec4 noise = texture2D(iChannel0, floor(uv * float(TILES)) / float(TILES));
							 | 
						|
								    float p = 1.0 - mod(noise.r + noise.g + noise.b + iTime * float(TIMESCALE), 1.0);
							 | 
						|
								    p = min(max(p * 3.0 - 1.8, 0.1), 2.0);
							 | 
						|
								
							 | 
						|
								    vec2 r = mod(uv * float(TILES), 1.0);
							 | 
						|
								    r = vec2(pow(r.x - 0.5, 2.0), pow(r.y - 0.5, 2.0));
							 | 
						|
								    p *= 1.0 - pow(min(1.0, 12.0 * dot(r, r)), 2.0);
							 | 
						|
								
							 | 
						|
								    fragColor = vec4(COLOR, 1.0) * p;
							 | 
						|
								}
							 | 
						|
								</pre>
							 | 
						|
								<p>Passing a texture into a shader is similar to 
							 | 
						|
								<a href="textures.html">passing one into a normal material</a> but we need to set
							 | 
						|
								up the texture on the uniforms.</p>
							 | 
						|
								<p>First we'll add the uniform for the texture to the shader. They're referred to
							 | 
						|
								as <code class="notranslate" translate="no">sampler2D</code> in GLSL.</p>
							 | 
						|
								<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const fragmentShader = `
							 | 
						|
								#include <common>
							 | 
						|
								
							 | 
						|
								uniform vec3 iResolution;
							 | 
						|
								uniform float iTime;
							 | 
						|
								+uniform sampler2D iChannel0;
							 | 
						|
								
							 | 
						|
								...
							 | 
						|
								</pre>
							 | 
						|
								<p>Then we can load a texture like we covered <a href="textures.html">here</a> and assign the uniform's value.</p>
							 | 
						|
								<pre class="prettyprint showlinemods notranslate lang-js" translate="no">+const loader = new THREE.TextureLoader();
							 | 
						|
								+const texture = loader.load('resources/images/bayer.png');
							 | 
						|
								+texture.minFilter = THREE.NearestFilter;
							 | 
						|
								+texture.magFilter = THREE.NearestFilter;
							 | 
						|
								+texture.wrapS = THREE.RepeatWrapping;
							 | 
						|
								+texture.wrapT = THREE.RepeatWrapping;
							 | 
						|
								const uniforms = {
							 | 
						|
								  iTime: { value: 0 },
							 | 
						|
								  iResolution:  { value: new THREE.Vector3() },
							 | 
						|
								+  iChannel0: { value: texture },
							 | 
						|
								};
							 | 
						|
								</pre>
							 | 
						|
								<p></p><div translate="no" class="threejs_example_container notranslate">
							 | 
						|
								  <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/shadertoy-bleepy-blocks.html"></iframe></div>
							 | 
						|
								  <a class="threejs_center" href="/manual/examples/shadertoy-bleepy-blocks.html" target="_blank">click here to open in a separate window</a>
							 | 
						|
								</div>
							 | 
						|
								
							 | 
						|
								<p></p>
							 | 
						|
								<p>So far we've been using Shadertoy shaders as they are used on
							 | 
						|
								<a href="https://shadertoy.com">Shadertoy.com</a>, namely drawing to cover the canvas.
							 | 
						|
								There's no reason we need to limit it to just that use case though. The
							 | 
						|
								important part to remember is the functions people write on shadertoy generally
							 | 
						|
								just take a <code class="notranslate" translate="no">fragCoord</code> input and a <code class="notranslate" translate="no">iResolution</code>. <code class="notranslate" translate="no">fragCoord</code> does not have to
							 | 
						|
								come from pixel coordinates, we could use something else like texture
							 | 
						|
								coordinates instead and could then use them kind of like other textures. This
							 | 
						|
								technique of using a function to generate textures is often called a
							 | 
						|
								<a href="https://www.google.com/search?q=procedural+texture"><em>procedural texture</em></a>.</p>
							 | 
						|
								<p>Let's change the shader above to do this. The simplest thing to do might be to
							 | 
						|
								take the texture coordinates that three.js normally supplies, multiply them by
							 | 
						|
								<code class="notranslate" translate="no">iResolution</code> and pass that in for <code class="notranslate" translate="no">fragCoords</code>. </p>
							 | 
						|
								<p>To do that we add in a <em>varying</em>. A varying is a value passed from the vertex
							 | 
						|
								shader to the fragment shader that gets interpolated (or varied) between
							 | 
						|
								vertices. To use it in our fragment shader we declare it. Three.js refers to its
							 | 
						|
								texture coordinates as <code class="notranslate" translate="no">uv</code> with the <code class="notranslate" translate="no">v</code> in front meaning <em>varying</em>.</p>
							 | 
						|
								<pre class="prettyprint showlinemods notranslate lang-glsl" translate="no">...
							 | 
						|
								
							 | 
						|
								+varying vec2 vUv;
							 | 
						|
								
							 | 
						|
								void main() {
							 | 
						|
								-  mainImage(gl_FragColor, gl_FragCoord.xy);
							 | 
						|
								+  mainImage(gl_FragColor, vUv * iResolution.xy);
							 | 
						|
								}
							 | 
						|
								</pre>
							 | 
						|
								<p>Then we need to also provide our own vertex shader. Here is a fairly common
							 | 
						|
								minimal three.js vertex shader. Three.js declares and will provide values for
							 | 
						|
								<code class="notranslate" translate="no">uv</code>, <code class="notranslate" translate="no">projectionMatrix</code>, <code class="notranslate" translate="no">modelViewMatrix</code>, and <code class="notranslate" translate="no">position</code>.</p>
							 | 
						|
								<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const vertexShader = `
							 | 
						|
								  varying vec2 vUv;
							 | 
						|
								  void main() {
							 | 
						|
								    vUv = uv;
							 | 
						|
								    gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
							 | 
						|
								  }
							 | 
						|
								`;
							 | 
						|
								</pre>
							 | 
						|
								<p>We need to pass the vertex shader to the <a href="/docs/#api/en/materials/ShaderMaterial"><code class="notranslate" translate="no">ShaderMaterial</code></a></p>
							 | 
						|
								<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const material = new THREE.ShaderMaterial({
							 | 
						|
								  vertexShader,
							 | 
						|
								  fragmentShader,
							 | 
						|
								  uniforms,
							 | 
						|
								});
							 | 
						|
								</pre>
							 | 
						|
								<p>We can set the <code class="notranslate" translate="no">iResolution</code> uniform value at init time since it will no longer change.</p>
							 | 
						|
								<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const uniforms = {
							 | 
						|
								  iTime: { value: 0 },
							 | 
						|
								-  iResolution:  { value: new THREE.Vector3() },
							 | 
						|
								+  iResolution:  { value: new THREE.Vector3(1, 1, 1) },
							 | 
						|
								  iChannel0: { value: texture },
							 | 
						|
								};
							 | 
						|
								</pre>
							 | 
						|
								<p>and we no longer need to set it at render time</p>
							 | 
						|
								<pre class="prettyprint showlinemods notranslate lang-js" translate="no">-const canvas = renderer.domElement;
							 | 
						|
								-uniforms.iResolution.value.set(canvas.width, canvas.height, 1);
							 | 
						|
								uniforms.iTime.value = time;
							 | 
						|
								</pre>
							 | 
						|
								<p>Otherwise I copied back in the original camera and code that sets up 3 rotating
							 | 
						|
								cubes from <a href="responsive.html">the article on responsiveness</a>. The result:</p>
							 | 
						|
								<p></p><div translate="no" class="threejs_example_container notranslate">
							 | 
						|
								  <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/shadertoy-as-texture.html"></iframe></div>
							 | 
						|
								  <a class="threejs_center" href="/manual/examples/shadertoy-as-texture.html" target="_blank">click here to open in a separate window</a>
							 | 
						|
								</div>
							 | 
						|
								
							 | 
						|
								<p></p>
							 | 
						|
								<p>I hope this at least gets you started on how to use a shadertoy shader with
							 | 
						|
								three.js. Again, it's important to remember that most shadertoy shaders are an
							 | 
						|
								interesting challenge (draw everything with a single function) rather than the
							 | 
						|
								recommended way to actually display things in a performant way. Still, they are
							 | 
						|
								amazing, impressive, beautiful, and you can learn a ton by seeing how they work.</p>
							 | 
						|
								
							 | 
						|
								        </div>
							 | 
						|
								      </div>
							 | 
						|
								    </div>
							 | 
						|
								  
							 | 
						|
								  <script src="/manual/resources/prettify.js"></script>
							 | 
						|
								  <script src="/manual/resources/lesson.js"></script>
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								</body></html>
							 |