Search code examples
javascriptaframe

aframe splitscreen to single screen effect


Hey there dearest reader,

is there a way to show the same picture/ video on two or even more flat objects (i.e. Triangle, rectangle, circle, ect.)? Sounds easy enough, but I mean with a splitscreen to single screen effect like this for example. The simplest way is probably splitting the content, aye? So maybe a javascript video editor? Found nothing really satisfying so far, but maybe I am just searching with an unclear imagination of what I want. Therefor any suggestions are welcome.

Thanks & Greetings Orys


Solution

  • Hey there dearest OP.

    If you can't fake it (having a big plane with the image + overlay a cross), then I'd try with using shaders.

    A custom shader which will use the "top" or "bottom" side of the image could look like this:

    <script src="https://aframe.io/releases/1.1.0/aframe.min.js"></script>
    <script>
      // register a custom component
      AFRAME.registerComponent("foo", {
        // we wanna pass a value "top" or "bottom"
        schema: {
          side: {
            value: "top"
          }
        },
        init: function() {
    
          // vertex shader. we only want it to pass the UV to the frag shader
          const vertexShader = `
            varying vec2 vUv;
            void main() {
                vUv = uv;
                gl_Position = projectionMatrix *
                              modelViewMatrix *
                              vec4(position,1.0);
              }
            `;
    
          const fragmentShader = `
                uniform bool top;
                uniform sampler2D map; 
                varying vec2 vUv;           
                    
                void main() {
                    // the top one is 1 - .5
                    // the bottom one .5 - 0
                    
                    vec2 coords = vUv.xy;
                    coords.y = coords.y / 2.0; // stretch half of it.
                    if (top) {
                        coords.y += 0.5; // if top - apply offset
                    }
                                    
                    vec4 mapTexel = texture2D( map, coords );
                    gl_FragColor = mapTexel;
                }
            `
          // wait until the entity is loaded
          this.el.addEventListener("loaded", e => {
            // grab the mesh
            const mesh = this.el.getObject3D("mesh")
            // load the texture
            const texture = new THREE.TextureLoader().load('https://i.imgur.com/wjobVTN.jpeg');
            // create a new shadermaterial with the defined shaders
            const newMaterial = new THREE.ShaderMaterial({
              uniforms: {
                top: {
                  type: "b",
                  value: this.data.side === "top" ? true : false
                },
                map: {
                  type: "t",
                  value: texture
                }
              },
              vertexShader: vertexShader,
              fragmentShader: fragmentShader,
              transparent: true
            });
    
            // apply the new material - get rid of the old one
            const oldMaterial = mesh.material;
            mesh.material = newMaterial
            mesh.material.needsUpdate = true;
    
            oldMaterial.dispose();
          })
        }
      })
    </script>
    <a-scene>
    
      <a-plane width="2" position="0 2.25 -3" foo="side: top"></a-plane>
      <a-plane width="2" position="0 1 -3" foo="side: bottom"></a-plane>
    
      <a-plane position="0 0 -4" rotation="-90 0 0" width="4" height="4" color="#7BC8A4"></a-plane>
    </a-scene>