如何在three.js 中实现ShaderToy 着色器? [英] How to implement a ShaderToy shader in three.js?

查看:139
本文介绍了如何在three.js 中实现ShaderToy 着色器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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.

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

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.

推荐答案

我不确定您是否已经回答了您的问题,但是让其他人了解将 shadertoys 集成到 THREEJS 的步骤可能会有好处.

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是一个片段着色器.话虽如此,您必须设置一个通用"顶点着色器,它应该适用于所有着色器玩具(片段着色器).

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

步骤 1创建一个通用"顶点着色器

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

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

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.

第 2 步选择我们想要的着色器并创建片段着色器.(我选择了一个性能良好的简单玩具:niklashuss 的简单隧道 2D).

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

这是这个玩具的给定代码:

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

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

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

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

varying vec2 vUv;

请注意,仅声明了用于该示例的 shadertoys 变量,以及之前在我们的顶点着色器中声明的可变 vUv.

Note, only the shadertoys variables used for that sample are declared, plus the varying vUv previously declared in our vertex shader.

我们最后需要调整的是正确的 UV 映射,因为我们已经决定不使用屏幕分辨率.为此,只需替换使用 IResolution 统一的行,即:

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;

与:

vec2 p = -1.0 + 2.0 *vUv;

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

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

第 4 步您的 THREEJS 代码:

Step 4 Your THREEJS code:

设置制服:

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() 将模拟 700x394 屏幕分辨率的 shadertoy,换句话说,它将最好地传输艺术家打算分享的作品.

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.

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 值,而不是更新函数中的总时间.

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

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

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

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

这篇关于如何在three.js 中实现ShaderToy 着色器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆