【问题标题】:How to implement a ShaderToy shader in three.js?如何在three.js中实现ShaderToy着色器?
【发布时间】:2014-09-09 07:07:08
【问题描述】:

寻找有关如何在threejs 中重新创建ShaderToy 参数iGlobalTime、iChannel 等的信息。我知道 iGlobalTime 是自着色器启动以来经过的时间,我认为 iChannel 的东西是用于将 rgb 从纹理中提取出来,但希望能提供有关如何设置这些的信息。

edit: 已经浏览了三个.js 示例附带的所有着色器,并认为答案都在某个地方 - 只需要找到与 e.g. 等价的东西iChannel1 = 纹理输入等。

【问题讨论】:

    标签: three.js


    【解决方案1】:

    我不确定你是否已经回答了你的问题,但其他人可能知道 shadertoys 到 THREEJS 的集成步骤。

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

    第 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 片段着色器。 缺少代码的第一件事是制服和变量声明。将它们添加到片段着色器文件的顶部(只需复制并粘贴以下内容):

    uniform float iGlobalTime;
    uniform sampler2D iChannel0;
    uniform sampler2D iChannel1;
    
    varying vec2 vUv;
    

    请注意,仅声明了用于该示例的 shadertoys 变量,以及之前在我们的顶点着色器中声明的可变 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() 将模拟 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);
    

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

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

    就是这样,您现在可以使用此设置运行大多数着色玩具...

    【讨论】:

    • 感谢您的回答。但这是从哪里来的? vec2 p = -1.0 + 2.0 *vUv;
    • 它允许您将 UV 坐标转换为 XY 绝对坐标。这就是使它起作用的技巧/黑客......
    • 好消息!得到了你描述的工作示例。看着shadertoy.com/view/XsBXWt#,我被困在通道0 输入上,这是一个音频文件。我是否必须为此设置 HTML5 网络音频 api 内容?
    • "对于作为音频文件的 channel0 输入",是的,您必须集成网络音频 API 或使用现有的库,如 dancer.js (jsantell.github.io/dancer.js)。警告:dancer.js 是一个复杂的音频库,如果滥用会占用大量资源......
    • k 谢谢-从文件中播放音频...假设可以在这里继续...。我正在使用您的上述内容-“vec2 p = -1.0 + 2.0 *vUv;” ...这个着色器想要 iResolution.x,我可以传入它,但假设我可以从不同的 vec2 vUv 计算 iR.x 和 y?
    【解决方案2】:

    2022 年编辑: 下面描述的 Shaderfrog 版本不再积极开发。使用的编译器存在错误,使其无法正确解析所有着色器以进行导入,并且它不支持 Shadertoy 的许多功能,例如多个图像缓冲区。如果你想follow along,我正在开发一个新工具,否则你可以尝试以下方法,但它可能大部分时间都不起作用。

    原答案如下:

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

    您可能需要在导入后稍微调整参数,但我希望随着时间的推移会有所改善。例如,ShaderFrog 尚不支持音频和视频输入,但您可以使用图像来预览它们。

    概念证明:

    ShaderToyhttps://www.shadertoy.com/view/MslGWN

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

    全面披露:我是我上周推出的这个工具的作者。我认为这是一个有用的功能。

    【讨论】:

    • 我试过了,它总是返回错误并且着色器不会编译。我正在尝试导入此着色器:shadertoy.com/view/4sSGDc
    • 仍有一些语法边缘情况会导致导入器崩溃。我会将这个添加到错误列表中。
    • 我正在尝试导入 - shadertoy.com/view/XsBSzh#,它没有导入(尝试使用 URL 和源代码)
    • 我得到一个 json 作为 three.js 导出,对吗?我找不到在 three.js 中将 json 作为着色器导入的方法,我错过了什么吗?非常感谢
    • @Eskel 你必须使用 shader-frog 运行时库并遵循使用步骤github.com/DelvarWorld/ShaderFrog-Runtime
    【解决方案3】:

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

    基本上,您将 Shadertoy(iGlobalTime 等,请参阅此列表:https://www.shadertoy.com/howto)中缺少的统一变量插入片段着色器中,将 mainImage(out vec4 z, in vec2 w) 重命名为 main(),然后在源代码中更改 z到“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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-12-18
      • 2017-02-04
      • 2020-11-12
      • 2014-10-23
      • 1970-01-01
      • 2019-05-14
      • 2020-08-28
      • 2014-03-24
      相关资源
      最近更新 更多