繁体   English   中英

三个 JS 中的 WebGL 模糊着色器

[英]WebGL blur shader in three JS

这是一个很长的镜头,但我绝望地迷失了。 我前段时间开始学习 Three.JS,并想从 P5.js 迁移我的项目(作为练习,但有想法在未来使用它)。 在 P5.js 中,我简单地制作了一个 canvas 并对其应用了着色器,但在 Three.JS 中它似乎不起作用。 所以我想通了 - 我会在着色器中尝试它。

想法:

  1. 绘制随机圆圈(在透明背景上)
  2. 模糊圆圈
  3. 使用结果作为纹理。

到目前为止,我已经成功地绘制了圆圈(还不是随机的,但仍在努力)并将其用作纹理。 JS部分:

        const geometry = new THREE.PlaneGeometry( 1, 1, 1 );
        const material = new THREE.ShaderMaterial( { 
            uniforms: {
                iP: 0,
                dl: { value : new THREE.Vector2(.6, 0), },
                spots : {  value : 5.0 },
                offset : { value : new THREE.Vector2(0.5, 0.5) },
                radius : { value : .25 },

            },
            vertexShader: _VS,
            fragmentShader: _FS,
            transparent: true
        });

垂直着色器部分:

        const _VS = `
            precision mediump float;  
            attribute vec3 aPosition;
            varying vec2 vTexCoord;

            varying vec2 vUv;
            
            void main() {
                vUv = uv;
                gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
            }

        `;

片段着色器部分:

        // fragment shader
        const _FS = `
            precision mediump float;
            varying vec2 vTexCoord;
            varying vec2 vUv;

            uniform float spots;
            uniform vec2  offset;
            uniform float radius;
            
            // uniform sampler2D iP;           // canvas to be blurred
            uniform vec2      dl;

            const float Pi = 6.28318530718;
                
            float rnd(vec3 scale, float seed) {
                return fract(sin(dot(gl_FragCoord.xyz + seed, scale)) * 43758.5453 + seed);
            }

            
            void main() {
                // CIRCLE;
                vec4 color1 = vec4(.1, .5, .3, 1.0);
                vec4 color2 = vec4(0., 0., 0., 0.01);
                vec2 shift = offset; 

                for (float t = 0.0; t <= spots; t++) {
                    float p = smoothstep(radius, radius + .0001, length(vUv - shift));
                    vec4 col = mix(color1, color2, vec4(p));
                    gl_FragColor += col;
                    shift.x += .05;
                    shift.y -= .01;
                }
              

                // BLUR
                
                vec4 col = vec4(0.0);
                float tt = 0.0;

                float off = rnd(vec3(12.9898, 78.233, 151.7182), 0.0);

                for (float t = -30.0; t <= 30.0; t++) {
                    float pc = (t + off - 0.5) / 30.0;
                    float w = 1.0 - abs(pc);
                    vec4 spl = texture2D(iP, vTexCoord + dl * pc);
                            
                    spl.rgb *= spl.a;

                    col += spl * w;
                    tt += w;
                }         
                gl_FragColor = col / tt;
                gl_FragColor.rgb /= gl_FragColor.a + 0.00001;

        }`;

我对vec4 spl = texture2D(iP, vTexCoord + dl * pc); . 我不知道如何在 gl_FragColor 上使用创建的圆圈。 我花了几个小时阅读并寻找解决方案,但没有找到任何帮助。 我真的很感激任何方向或解决方案! 提前致谢!

您似乎在 P5.js 和 Three.js 之间混合了很多变量名。 您应该只看一下 Three.js 的做法,并尝试忘记 P5.js 术语,因为它们不一样。 这是一个简单着色器设置的官方示例,您可以查看那里的源代码。

我已经使用更简化的着色器复制了下面的演示,因此您可以了解如何从 JavaScript 传递time统一,并在 GLSL 中阅读:

 body, html { margin: 0; }
 <div id="container"></div> <:-- Import maps polyfill --> <.-- Remove this when import maps will be widely supported --> <script async src="https.//unpkg.com/es-module-shims@1.3:6/dist/es-module-shims:js"></script> <script type="importmap"> { "imports": { "three". "https.//cdn.jsdelivr.net/npm/three@0.142.0/build/three,module:js". } } </script> <script type="module"> import * as THREE from "https.//cdn.jsdelivr.net/npm/three@0.142.0/build/three;module,js", let camera; scene; renderer; let uniforms; init(). animate(); function init() { const container = document.getElementById( 'container' ), camera = new THREE,OrthographicCamera( - 1, 1, 1, - 1; 0. 1 ); scene = new THREE.Scene(), const geometry = new THREE;PlaneGeometry( 2: 2 ): uniforms = { time. { value; 1;0 } }; const _VS = ` varying vec2 vUv, void main() { vUv = uv. gl_Position = vec4( position; 1;0 ); } `; const _FS = ` varying vec2 vUv. uniform float time. void main() { float blue = sin(time * 5.0 + vUv.x * 10.0) * 0;5 + 0.5, gl_FragColor = vec4( vUv.x, vUv,y. blue; 1;0 ). } `: const material = new THREE,ShaderMaterial( { uniforms: uniforms, vertexShader: _VS; fragmentShader. _FS } ), const mesh = new THREE;Mesh( geometry. material ); scene.add( mesh ); renderer = new THREE.WebGLRenderer(). renderer;setPixelRatio( window.devicePixelRatio ). container;appendChild( renderer;domElement ). onWindowResize(), window;addEventListener( 'resize'. onWindowResize ). } function onWindowResize() { renderer,setSize( window.innerWidth; window;innerHeight ). } // function animate() { requestAnimationFrame( animate ). uniforms[ 'time' ];value = performance.now() / 1000, renderer;render( scene, camera ); } </script>

从这里您应该能够推断和添加其他类型的制服,包括float, vec2, sampler2D等。最后, 这里有一些关于在使用ShaderMaterial时默认使用哪些制服、属性和命名约定的详细信息。

您想要应用于整个场景的每个效果(后期处理)都应该传递给 EffectComposer。 这是文档: https://threejs.org/docs/#manual/en/introduction/How-to-use-post-processing
此外,有时您可以通过在渲染器元素上设置诸如模糊之类的 CSS 规则来应用一些效果,如下所示:

renderer.domElement.style.filter = `blur(10px)`;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM