【问题标题】:Three js postProcessing solution with transparency三个透明的js后处理方案
【发布时间】:2019-06-20 15:52:50
【问题描述】:

我发现了使用 three.js 创建后期处理效果的解决方案:
https://medium.com/@luruke/simple-postprocessing-in-three-js-91936ecadfb7 (由路易吉·德·罗萨制作)

这是一个很好的方法。不幸的是,我无法在最终渲染器中添加透明度。我应该在我的后处理片段着色器中添加一个透明度组件吗?

const fragmentShader = `precision highp float;
    uniform sampler2D uScene;
    uniform vec2 uResolution;
    uniform float uTime;

    void main() {
        vec2 uv = gl_FragCoord.xy / uResolution.xy;
        vec3 color = vec3(uv, 1.0);

        //simple distortion effect
        uv.y += sin(uv.x*30.0+uTime*10.0)/40.0;
        uv.x -= sin(uv.y*10.0-uTime)/40.0;

        color = texture2D(uScene, uv).rgb;

        gl_FragColor = vec4(color, 1.0);

    }
`;

谢谢

编辑 1:

我将属性transparent:true 添加到RawShaderMaterial

我将新THREE.WebGLRenderTarget 的格式更改为THREE.RGBAFormat 而不是THREE.RGBFormat

我还在片段着色器的末尾添加了这些行:

gl_FragColor = vec4(color, 1.0);
vec4 tex = texture2D( uScene, uv );
if(tex.a < 0.0) {
    gl_FragColor.a = 1.0;
}

但我还是看不透我的画布

编辑 2:

这是一个带有 postProcessing 类的 sn-p

    let renderer, camera, scene, W = window.innerWidth, H = window.innerHeight, geometry, material, mesh;

    initWebgl();
    function initWebgl(){

        renderer = new THREE.WebGLRenderer( { alpha: true, antialias: true } );
        renderer.setPixelRatio( window.devicePixelRatio );
        renderer.setSize( W, H );
        document.querySelector('.innerCanvas').appendChild( renderer.domElement );

        camera = new THREE.OrthographicCamera(-W/H/2, W/H/2, 1/2, -1/2, -0.1, 0.1);
        scene = new THREE.Scene();
       
        geometry = new THREE.PlaneBufferGeometry(0.5, 0.5);
        material = new THREE.MeshNormalMaterial();
        
        mesh = new THREE.Mesh( geometry , material );
        scene.add(mesh);

      
    } 

    function rafP(){
        requestAnimationFrame(rafP);

        // renderer.render(scene, camera);
        post.render(scene, camera);

    }
    
    
    const vertexShader = `precision highp float;
        attribute vec2 position;
        void main() {
          // Look ma! no projection matrix multiplication,
          // because we pass the values directly in clip space coordinates.
          gl_Position = vec4(position, 1.0, 1.0);
        }`;

    const fragmentShader = `precision highp float;
        uniform sampler2D uScene;
        uniform vec2 uResolution;
        uniform float uTime;

        void main() {
            vec2 uv = gl_FragCoord.xy / uResolution.xy;
            vec3 color = vec3(uv, 1.0);

            uv.y += sin(uv.x*20.0)/10.0;

            color = texture2D(uScene, uv).rgb;
            
            gl_FragColor = vec4(color, 1.0);

            vec4 tex = texture2D( uScene, uv );
            // if(tex.a - percent < 0.0) {
            if(tex.a < 0.0) {
                gl_FragColor.a = 1.0;
                //or without transparent = true use
                // discard; 
            }
        
        }`;

    //PostProcessing
    class PostFX {
        constructor(renderer) {
            this.renderer = renderer;
            this.scene = new THREE.Scene();
            // three.js for .render() wants a camera, even if we're not using it :(
            this.dummyCamera = new THREE.OrthographicCamera();
            this.geometry = new THREE.BufferGeometry();

            // Triangle expressed in clip space coordinates
            const vertices = new Float32Array([
              -1.0, -1.0,
              3.0, -1.0,
              -1.0, 3.0
            ]);

            this.geometry.addAttribute('position', new THREE.BufferAttribute(vertices, 2));

            this.resolution = new THREE.Vector2();
            this.renderer.getDrawingBufferSize(this.resolution);

            this.target = new THREE.WebGLRenderTarget(this.resolution.x, this.resolution.y, {
                format: THREE.RGBAFormat,  //THREE.RGBFormat
                stencilBuffer: false,
                depthBuffer: true
            });

            this.material = new THREE.RawShaderMaterial({
                fragmentShader,
                vertexShader,
                uniforms: {
                    uScene: { value: this.target.texture },
                    uResolution: { value: this.resolution }
                },
                transparent:true
            });

            // TODO: handle the resize -> update uResolution uniform and this.target.setSize()

            this.triangle = new THREE.Mesh(this.geometry, this.material);
            // Our triangle will be always on screen, so avoid frustum culling checking
            this.triangle.frustumCulled = false;
            this.scene.add(this.triangle);
        }

        render(scene, camera) {
            this.renderer.setRenderTarget(this.target);
            this.renderer.render(scene, camera);
            this.renderer.setRenderTarget(null);
            this.renderer.render(this.scene, this.dummyCamera);

            console.log(this.renderer);
        }
    }

    post = new PostFX(renderer); 
    rafP();
body{
  margin:0;
  padding:0;
  background:#00F;
 }
 .innerCanvas{
  position:fixed;
  top:0;
  left:0;
  width:100%;
  height:100%;
 }
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/105/three.js"></script>

<div class="innerCanvas"></div>

【问题讨论】:

  • 是的。 gl_FragColor = vec4(color, 1.0); 有一个非常明显的 alpha 值 1.0。如果您想要透明度,则必须修改该值。
  • 感谢您的回答,是的,我注意到了。我刚刚编辑了我的问题:我尝试使用片段着色器的gl_FragColor.a 属性。
  • @MichaëlGarcia 仍然不清楚您是否正确地更改了 gl_FragColor.a 通过您发布的代码查看。您能否发布一个可以重现此行为的实时示例?
  • 我刚刚更新了我的问题并添加了具有该行为的 sn-p。
  • 也许这会对你有所帮助:stackoverflow.com/questions/55393149/…

标签: three.js fragment-shader post-processing


【解决方案1】:

在 Alpha 通道上,0 表示完全透明,1 表示完全不透明。

在这种情况下,您唯一需要做的就是将纹理样本的结果传递给gl_FragColor。您甚至不必担心它的价值。

gl_FragColor = texture2D(uScene, uv);

JSFiddle

【讨论】:

  • 有道理,非常感谢,现在可以使用了。我注意到最后一个问题:我的网格周围现在有一个小边框。我用屏幕截图更新了我的问题。
  • 不要过多地编辑您的问题。就目前而言,当前的问题似乎与旧问题无关。如果此答案解决了您的原始问题,则将此答案标记为正确,并考虑为当前问题创建一个新问题。
猜你喜欢
  • 1970-01-01
  • 2016-06-08
  • 2021-02-20
  • 2015-01-18
  • 2015-03-16
  • 2017-10-26
  • 2015-07-14
  • 2015-02-14
  • 1970-01-01
相关资源
最近更新 更多