Решение для постпроцессинга Three JS с прозрачностью - PullRequest
0 голосов
/ 18 июня 2019

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

1 Ответ

0 голосов
/ 19 июня 2019

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

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

gl_FragColor = texture2D(uScene, uv);

JSFiddle

...