3D Game Demo Multiusers web 3D system
Created on 29/08/2016 20:28 Last post 3 years
0
411
Views
1
Users

• I have created this post on stackoverflow.com last summer and wanted to share the info with everyone. This tutorial explains the steps to integrate most shadertoys with multivers3D or any THREE.js apps. The tutorial is a little lengthy, but it should be very easy for any intermediate 3D Javascript programmer to follow. Plus, just think about the infinit texture possibilities once you've gone through the tutorial.

Original posting:

"I am not sure if you have answered your question, but it might be good for others to know the integration steps for shadertoys to THREEJS."

First, you need to know that shadertoys is a fragment shader. That being said, you have to set a "general purpose" vertex shader that should work with all shadertoys (fragment shaders).

Step 1: Create a "general purpose" vertex shader
``varying vec2 vUv;void main() {    vUv = uv;    vec4 mvPosition = modelViewMatrix * vec4(position, 1.0 );    gl_Position = projectionMatrix * mvPosition;}``
This vertex shader is very basic. Notice that we defined a varying variable vUv to tell the fragment shader where is the texture mapping. This is important because, we are not going to use the screen resolution (iResolution) for our base rendering. We will use the texture coordinates instead. We have done that in order to integrate multiple shadertoys on different objects in the same THREEJS scene.

Step 2: pick the shadertoys that we wanna and create the fragment shader (I have chosen a simple toy that performs well: Simple tunnel 2D by niklashuss https://www.shadertoy.com/view/4sXSzs)

Here is the given code for this toy:
``void main(void) {    vec2 p = gl_FragCoord.xy / iResolution.xy;    vec2 q = p - vec2(0.5, 0.5);    q.x += sin(iGlobalTime* 0.6) * 0.2;    q.y += cos(iGlobalTime* 0.4) * 0.3;    float len = length(q);    float a = atan(q.y, q.x) + iGlobalTime * 0.3;    float b = atan(q.y, q.x) + iGlobalTime * 0.3;    float r1 = 0.3 / len + iGlobalTime * 0.5;    float r2 = 0.2 / len + iGlobalTime * 0.5;    float m = (1.0 + sin(iGlobalTime * 0.5)) / 2.0;    vec4 tex1 = texture2D(iChannel0, vec2(a + 0.1 / len, r1 ));    vec4 tex2 = texture2D(iChannel1, vec2(b + 0.1 / len, r2 ));    vec3 col = vec3(mix(tex1, tex2, m)); gl_FragColor = vec4(col * len * 1.5, 1.0);}``

Step 3: customize the shadertoy raw code to have a complete GLSL fragment shader.

The first thing missing out the code are the uniforms and varyings declaration. Add them at the top of your fragment shader file (just copy and paste the following):
``uniform float iGlobalTime;uniform sampler2D iChannel0;uniform sampler2D iChannel1;varying vec2 vUv;``
Note, only the shadertoys variables used for that sample are declared, plus the varying vUv previously declared in our vertex shader.

The last thing we have to twick is the proper UV mapping, now that we have decided to not use the screen resolution. To do so, just replace the line that uses the IResolution uniforms i.e.:
``vec2 p = gl_FragCoord.xy / iResolution.xy;``
with:
``vec2 p = -1.0 + 2.0 *vUv;``
``var tuniform = {    iGlobalTime: { type: 'f', value: 0.1 },    iChannel0: { type: 't', value: THREE.ImageUtils.loadTexture( 'textures/tex07.jpg') },    iChannel1: { type: 't', value: THREE.ImageUtils.loadTexture( 'textures/infi.jpg' ) },};``
``tuniform.iChannel0.value.wrapS = tuniform.iChannel0.value.wrapT = THREE.RepeatWrapping;tuniform.iChannel1.value.wrapS = tuniform.iChannel1.value.wrapT = THREE.RepeatWrapping;``
``var mat = new THREE.ShaderMaterial( {                         uniforms: tuniform,                     vertexShader: vshader,                     fragmentShader: fshader,                     side:THREE.DoubleSide                     } );var tobject = new THREE.Mesh( new THREE.PlaneGeometry(700, 394,1,1), mat);``
``delta=clock.getDelta();tuniform.iGlobalTime.value += delta``