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>
|