Решение для постобработки на трех js с прозрачностью

Я обнаружил это решение для создания эффектов постобработки с помощью 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

    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>


person Michaël    schedule 18.06.2019    source источник
comment
Да. gl_FragColor = vec4(color, 1.0); имеет очень заметное альфа-значение 1.0. Вам придется изменить это значение, если вы хотите прозрачности.   -  person Marquizzo    schedule 18.06.2019
comment
Спасибо за ответ, да, я это заметил. Я только что отредактировал свой вопрос: я пытаюсь поиграть с атрибутом gl_FragColor.a моего фрагментного шейдера.   -  person Michaël    schedule 18.06.2019
comment
@MichaëlGarciaДо сих пор не ясно, правильно ли вы меняете gl_FragColor.a, судя по опубликованному вами коду. Можете ли вы опубликовать живой пример, который может воспроизвести это поведение?   -  person ScieCode    schedule 19.06.2019
comment
Я только что обновил свой вопрос и добавил фрагмент с таким поведением.   -  person Michaël    schedule 19.06.2019
comment
возможно, это поможет вам: stackoverflow.com/questions/55393149/   -  person Alex Khoroshylov    schedule 19.06.2019


Ответы (1)


В альфа-канале 0 означает полностью прозрачный, а 1 — полностью непрозрачный.

Единственное, что вам нужно в этом случае, это передать gl_FragColor результат из вашего образца текстуры. Вам даже не нужно беспокоиться о его ценности.

gl_FragColor = texture2D(uScene, uv);

JSFiddle

person ScieCode    schedule 19.06.2019
comment
Это имеет смысл, большое спасибо, теперь это работает. Я заметил одну последнюю проблему: теперь у меня есть небольшая рамка вокруг моей сетки. Я обновил свой вопрос скриншотом. - person Michaël; 19.06.2019
comment
Воздержитесь от редактирования вашего вопроса слишком много. В нынешнем виде текущая проблема, похоже, не связана со старой. Отметьте этот ответ как правильный, если он решает вашу первоначальную проблему, и рассмотрите возможность создания нового вопроса для текущей проблемы. - person ScieCode; 19.06.2019