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

时间:2014-07-18 08:00:35

标签: three.js

寻找有关如何在threejs内重新创建ShaderToy参数iGlobalTime,iChannel等的信息。我知道iGlobalTime是自着色器开始以来经过的时间,我认为iChannel的东西是用于从纹理中拉出rgb,但是会很感激如何设置它们。

编辑:已经浏览了所有带有three.js示例的着色器,并且认为答案都在某处 - 只需要找到等效的例子。 iChannel1 =纹理输入等。

3 个答案:

答案 0 :(得分:29)

我不确定你是否已经回答了你的问题,但是对于其他人来说,了解一下对于THREEJS的整合步骤可能会有好处。

首先,您需要知道shadecorys是片段着色器。话虽这么说,你必须设置一个“通用”顶点着色器,它应该适用于所有的shadeaeys(片段着色器)。

第1步 创建“通用”顶点着色器

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

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

这个顶点着色器非常基本。请注意,我们定义了一个变量变量vUv来告诉片段着色器纹理映射在哪里。这很重要,因为我们不会将屏幕分辨率(iResolution)用于基本渲染。我们将使用纹理坐标。我们已经这样做了,以便在同一个THREEJS场景中的不同对象上集成多个阴影。

第2步 选择我们想要的阴影并创建片段着色器。 (我选择了一个表现良好的简单玩具:Simple tunnel 2D by niklashuss)。

以下是此玩具的给定代码:

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

第3步 自定义shadertoy原始代码以获得完整的GLSL片段着色器。 错过代码的第一件事是制服和变化声明。将它们添加到frag shader文件的顶部(只需复制并粘贴以下内容):

uniform float iGlobalTime;
uniform sampler2D iChannel0;
uniform sampler2D iChannel1;

varying vec2 vUv;

注意,只声明用于该样本的shadeaeys变量,以及先前在我们的顶点着色器中声明的变化的vUv。

我们必须解决的最后一件事是正确的UV映射,现在我们决定不使用屏幕分辨率。为此,只需更换使用IResolution制服的线,即:

vec2 p = gl_FragCoord.xy / iResolution.xy;

使用:

vec2 p = -1.0 + 2.0 *vUv;

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

第4步 你的THREEJS代码:

设置制服:

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;

使用着色器创建材质并将其添加到planegeometry中。 planegeometry()将模拟阴影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);

最后,将THREE.Clock()的增量添加到iGlobalTime值,而不是更新功能中的总时间。

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

就是这样,你现在可以使用这个设置运行大部分阴影......

答案 1 :(得分:9)

这是一个旧线程,但现在有一种自动化的方法。只需转到http://shaderfrog.com/app/editor/new,然后点击右上角的“导入> ShaderToy”并粘贴到网址中。如果它不公开,您可以粘贴原始源代码。然后您可以保存着色器(需要注册,无需确认电子邮件),然后单击“导出> Three.js”。

您可能需要在导入后略微调整参数,但我希望随着时间的推移对其进行改进。例如,ShaderFrog尚不支持音频输入或视频输入,但您可以使用图像预览它们。

概念证明:

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

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

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

答案 2 :(得分:2)

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

基本上,您将Shadertoy中缺少的统一变量(iGlobalTime等,请参阅此列表:https://www.shadertoy.com/howto)插入片段着色器,将main()重命名为z,然后更改{源代码中的{1}}为“gl_FragColor”。在大多数Shadertoys'z'中都是'fragColor'。

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

工作的jsFiddle在这里:https://jsfiddle.net/dirkk0/zt9dhvqx/ 在第56行中将着色器从frag1更改为frag2以查看两个示例。

并且不要在jsFiddle中“整洁” - 它打破了着色器。

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