如何在three.j中实现ShaderToy着色器?

时间:2022-06-02 00:27:02

looking for info on how to recreate the ShaderToy parameters iGlobalTime, iChannel etc within threejs. I know that iGlobalTime is the time elapsed since the Shader started, and I think the iChannel stuff is for pulling rgb out of textures, but would appreciate info on how to set these.

寻找关于如何在threejs中创建ShaderToy参数iGlobalTime, iChannel等的信息。我知道,iGlobalTime是自Shader启动以来的时间,我认为iChannel的内容是将rgb从纹理中拉出来,但是会欣赏关于如何设置这些的信息。

edit: have been going through all the shaders that come with three.js examples and think that the answers are all in there somewhere - just have to find the equivalent to e.g. iChannel1 = a texture input etc.

编辑:已经通过了所有的阴影,有三个。js示例并认为答案都在某个地方——只需找到等效的iChannel1 =纹理输入等。

3 个解决方案

#1


28  

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.

我不确定你是否已经回答了你的问题,但是对于其他的人来说,了解shadertoys与THREEJS的集成步骤是有好处的。

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

首先,您需要知道shadertoys是一个片段着色器。也就是说,你必须设置一个“通用的”顶点着色器,它应该与所有的着色器(片段着色器)一起工作。

Step 1 Create a "general purpose" vertex shader

步骤1创建一个“通用”顶点着色器。

varying vec2 vUv; 
void main()
{
    vUv = uv;

    vec4 mvPosition = modelViewMatrix * vec4(position, 1.0 );
    gl_Position = projectionMatrix * mvPosition;
}

This vertex shader is pretty 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.

这个顶点着色器是很基本的。注意,我们定义了一个可变的vUv来告诉碎片着色器,纹理映射在哪里。这很重要,因为我们不打算使用屏幕分辨率(iResolution)来进行基础渲染。我们将使用纹理坐标代替。我们这样做是为了在相同的THREEJS场景中集成多个不同对象的shadertoys。

Step 2 Pick the shadertoys that we want and create the fragment shader. (I have chosen a simple toy that performs well: Simple tunnel 2D by niklashuss).

步骤2选择我们想要的阴影玩具,并创建片段着色器。(我选择了一个性能很好的简单玩具:niklashuss的简单隧道2D)。

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 frag shader file (just copy and paste the following):

步骤3自定义shadertoy原始代码,以拥有一个完整的GLSL片段着色器。第一个丢失代码的是制服和varyings声明。将它们添加到您的frag着色文件的顶部(仅复制并粘贴以下内容):

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.

注意,只声明用于该示例的shadertoys变量,加上之前在我们的顶点着色器中声明的不同vUv。

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

我们最后要做的是正确的UV贴图,现在我们已经决定不使用屏幕分辨率。要做到这一点,只需更换使用IResolution制服的线,即:

vec2 p = gl_FragCoord.xy / iResolution.xy;

with:

:

vec2 p = -1.0 + 2.0 *vUv;

That's it, your shaders are now ready for usage in your THREEJS scenes.

就是这样,你的着色器现在可以在你的THREEJS场景中使用了。

Step 4 Your THREEJS code:

步骤4你的THREEJS代码:

Set up uniform:

建立统一的:

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' ) },
    };

Make sure the textures are wrapping:

确保纹理是包装的:

tuniform.iChannel0.value.wrapS = tuniform.iChannel0.value.wrapT = THREE.RepeatWrapping;
tuniform.iChannel1.value.wrapS = tuniform.iChannel1.value.wrapT = THREE.RepeatWrapping;

Create the material with your shaders and add it to a planegeometry. The planegeometry() will simulate the shadertoys 700x394 screen resolution, in other words it will best transfer the work the artist intented to share.

用你的着色器创建材料,并将其添加到一个平面几何中。plane几何体()将模拟shadertoys 700x394的屏幕分辨率,换句话说,它将最好地转移艺术家想要分享的作品。

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

Finally, add the delta of the THREE.Clock() to iGlobalTime value and not the total time in your update function.

最后,将THREE.Clock()的delta添加到iGlobalTime值,而不是更新函数中的总时间。

tuniform.iGlobalTime.value += clock.getDelta();

That is it, you are now able to run most of the shadertoys with this setup...

就是这样,你现在可以用这个设置来运行大部分的shadertoys…

#2


9  

This is an old thread, but there's now an automated way to do this. Simply go to http://shaderfrog.com/app/editor/new and on the top right click "Import > ShaderToy" and paste in the URL. If it's not public you can paste in the raw source code. Then you can save the shader (requires sign up, no email confirm), and click "Export > Three.js".

这是一个旧的线程,但是现在有一个自动化的方法来完成这个任务。只需访问http://shaderfrog.com/app/editor/new并在右上角单击“Import > ShaderToy”并粘贴到URL中。如果不公开,您可以在原始源代码中粘贴。然后您可以保存着色器(需要注册,没有电子邮件确认),然后单击“Export > Three.js”。

You might need to tweak the parameters a little after import, but I hope to have this improved over time. For example, ShaderFrog doesn't support audio nor video inputs yet, but you can preview them with images instead.

您可能需要在导入后稍微调整参数,但是我希望随着时间的推移可以改进这些参数。例如,ShaderFrog不支持音频和视频输入,但是你可以用图片来预览。

Proof of concept:

的概念:

ShaderToy https://www.shadertoy.com/view/MslGWN

ShaderToy https://www.shadertoy.com/view/MslGWN

ShaderFrog http://shaderfrog.com/app/view/247

ShaderFrog http://shaderfrog.com/app/view/247

Full disclosure: I am the author of this tool which I launched last week. I think this is a useful feature.

完全披露:我是我上周发布的这个工具的作者。我认为这是一个有用的特性。

#3


2  

This is based on various sources , including the answer of @INF1.

这是基于各种来源,包括@INF1的答案。

Basically you insert missing uniform variables from Shadertoy (iGlobalTime etc, see this list: https://www.shadertoy.com/howto) into the fragment shader, the you rename mainImage(out vec4 z, in vec2 w) to main(), and then you change z in the source code to 'gl_FragColor'. In most Shadertoys 'z' is 'fragColor'.

基本上,您可以从Shadertoy (iGlobalTime等)中插入丢失的一致变量,查看这个列表:https://www.shadertoy.com/howto)到片段着色器中,您可以将mainImage(在vec2w中)重命名为mainImage(在vec2w中)到main(),然后将源代码中的z更改为“gl_FragColor”。在大多数的Shadertoys 'z'是'fragColor'。

I did this for two cool shaders from this guy (https://www.shadertoy.com/user/guil) but unfortunately I didn't get the marble example to work (https://www.shadertoy.com/view/MtX3Ws).

我从这个家伙(https://www.shadertoy.com/user/guil)做了两个很酷的着色,但不幸的是我没有得到这个大理石的例子(https://www.shadertoy.com/view/MtX3Ws)。

A working jsFiddle is here: https://jsfiddle.net/dirkk0/zt9dhvqx/ Change the shader from frag1 to frag2 in line 56 to see both examples.

一个工作的jsFiddle在这里:https://jsfiddle.net/dirkk0/zt9dhvqx/将来自frag1的shader改为第56行中的frag2,以查看两个示例。

And don't 'Tidy' in jsFiddle - it breaks the shaders.

不要在jsFiddle“整洁”——它会破坏着色器。

EDIT: https://medium.com/@dirkk/converting-shaders-from-shadertoy-to-threejs-fe17480ed5c6

编辑:https://medium.com/@dirkk / converting-shaders-from-shadertoy-to-threejs-fe17480ed5c6

#1


28  

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.

我不确定你是否已经回答了你的问题,但是对于其他的人来说,了解shadertoys与THREEJS的集成步骤是有好处的。

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

首先,您需要知道shadertoys是一个片段着色器。也就是说,你必须设置一个“通用的”顶点着色器,它应该与所有的着色器(片段着色器)一起工作。

Step 1 Create a "general purpose" vertex shader

步骤1创建一个“通用”顶点着色器。

varying vec2 vUv; 
void main()
{
    vUv = uv;

    vec4 mvPosition = modelViewMatrix * vec4(position, 1.0 );
    gl_Position = projectionMatrix * mvPosition;
}

This vertex shader is pretty 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.

这个顶点着色器是很基本的。注意,我们定义了一个可变的vUv来告诉碎片着色器,纹理映射在哪里。这很重要,因为我们不打算使用屏幕分辨率(iResolution)来进行基础渲染。我们将使用纹理坐标代替。我们这样做是为了在相同的THREEJS场景中集成多个不同对象的shadertoys。

Step 2 Pick the shadertoys that we want and create the fragment shader. (I have chosen a simple toy that performs well: Simple tunnel 2D by niklashuss).

步骤2选择我们想要的阴影玩具,并创建片段着色器。(我选择了一个性能很好的简单玩具:niklashuss的简单隧道2D)。

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 frag shader file (just copy and paste the following):

步骤3自定义shadertoy原始代码,以拥有一个完整的GLSL片段着色器。第一个丢失代码的是制服和varyings声明。将它们添加到您的frag着色文件的顶部(仅复制并粘贴以下内容):

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.

注意,只声明用于该示例的shadertoys变量,加上之前在我们的顶点着色器中声明的不同vUv。

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

我们最后要做的是正确的UV贴图,现在我们已经决定不使用屏幕分辨率。要做到这一点,只需更换使用IResolution制服的线,即:

vec2 p = gl_FragCoord.xy / iResolution.xy;

with:

:

vec2 p = -1.0 + 2.0 *vUv;

That's it, your shaders are now ready for usage in your THREEJS scenes.

就是这样,你的着色器现在可以在你的THREEJS场景中使用了。

Step 4 Your THREEJS code:

步骤4你的THREEJS代码:

Set up uniform:

建立统一的:

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' ) },
    };

Make sure the textures are wrapping:

确保纹理是包装的:

tuniform.iChannel0.value.wrapS = tuniform.iChannel0.value.wrapT = THREE.RepeatWrapping;
tuniform.iChannel1.value.wrapS = tuniform.iChannel1.value.wrapT = THREE.RepeatWrapping;

Create the material with your shaders and add it to a planegeometry. The planegeometry() will simulate the shadertoys 700x394 screen resolution, in other words it will best transfer the work the artist intented to share.

用你的着色器创建材料,并将其添加到一个平面几何中。plane几何体()将模拟shadertoys 700x394的屏幕分辨率,换句话说,它将最好地转移艺术家想要分享的作品。

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

Finally, add the delta of the THREE.Clock() to iGlobalTime value and not the total time in your update function.

最后,将THREE.Clock()的delta添加到iGlobalTime值,而不是更新函数中的总时间。

tuniform.iGlobalTime.value += clock.getDelta();

That is it, you are now able to run most of the shadertoys with this setup...

就是这样,你现在可以用这个设置来运行大部分的shadertoys…

#2


9  

This is an old thread, but there's now an automated way to do this. Simply go to http://shaderfrog.com/app/editor/new and on the top right click "Import > ShaderToy" and paste in the URL. If it's not public you can paste in the raw source code. Then you can save the shader (requires sign up, no email confirm), and click "Export > Three.js".

这是一个旧的线程,但是现在有一个自动化的方法来完成这个任务。只需访问http://shaderfrog.com/app/editor/new并在右上角单击“Import > ShaderToy”并粘贴到URL中。如果不公开,您可以在原始源代码中粘贴。然后您可以保存着色器(需要注册,没有电子邮件确认),然后单击“Export > Three.js”。

You might need to tweak the parameters a little after import, but I hope to have this improved over time. For example, ShaderFrog doesn't support audio nor video inputs yet, but you can preview them with images instead.

您可能需要在导入后稍微调整参数,但是我希望随着时间的推移可以改进这些参数。例如,ShaderFrog不支持音频和视频输入,但是你可以用图片来预览。

Proof of concept:

的概念:

ShaderToy https://www.shadertoy.com/view/MslGWN

ShaderToy https://www.shadertoy.com/view/MslGWN

ShaderFrog http://shaderfrog.com/app/view/247

ShaderFrog http://shaderfrog.com/app/view/247

Full disclosure: I am the author of this tool which I launched last week. I think this is a useful feature.

完全披露:我是我上周发布的这个工具的作者。我认为这是一个有用的特性。

#3


2  

This is based on various sources , including the answer of @INF1.

这是基于各种来源,包括@INF1的答案。

Basically you insert missing uniform variables from Shadertoy (iGlobalTime etc, see this list: https://www.shadertoy.com/howto) into the fragment shader, the you rename mainImage(out vec4 z, in vec2 w) to main(), and then you change z in the source code to 'gl_FragColor'. In most Shadertoys 'z' is 'fragColor'.

基本上,您可以从Shadertoy (iGlobalTime等)中插入丢失的一致变量,查看这个列表:https://www.shadertoy.com/howto)到片段着色器中,您可以将mainImage(在vec2w中)重命名为mainImage(在vec2w中)到main(),然后将源代码中的z更改为“gl_FragColor”。在大多数的Shadertoys 'z'是'fragColor'。

I did this for two cool shaders from this guy (https://www.shadertoy.com/user/guil) but unfortunately I didn't get the marble example to work (https://www.shadertoy.com/view/MtX3Ws).

我从这个家伙(https://www.shadertoy.com/user/guil)做了两个很酷的着色,但不幸的是我没有得到这个大理石的例子(https://www.shadertoy.com/view/MtX3Ws)。

A working jsFiddle is here: https://jsfiddle.net/dirkk0/zt9dhvqx/ Change the shader from frag1 to frag2 in line 56 to see both examples.

一个工作的jsFiddle在这里:https://jsfiddle.net/dirkk0/zt9dhvqx/将来自frag1的shader改为第56行中的frag2,以查看两个示例。

And don't 'Tidy' in jsFiddle - it breaks the shaders.

不要在jsFiddle“整洁”——它会破坏着色器。

EDIT: https://medium.com/@dirkk/converting-shaders-from-shadertoy-to-threejs-fe17480ed5c6

编辑:https://medium.com/@dirkk / converting-shaders-from-shadertoy-to-threejs-fe17480ed5c6