Search code examples
aframe

How can I fix a blank output in aframe when converting a plane to a sphere using a custom shader with glsl script in three.js?


I can't figure out why the aframe custom shader outputs a blank in this plane to sphere conversion in vertex shader. The glsl script outputs an sphere without any issue in three.js but it doesn't work in aframe. Appreciate any help.

https://jsfiddle.net/AshVRAR/gya5x83e/34/

  AFRAME.registerShader("customShader", {
    schema: {
      color: { type: "color", is: "uniform", default: "red" },
      opacity: { type: "number", is: "uniform", default: 1.0 },
    },

    vertexShader: `
    precision mediump float;

    void main() {
          float PI = 3.14159265359;

          // convert position.xy from [-1,1] to [0,1]
          vec2 uv = position.xy * 0.5 + 0.5;

          // convert uv to spherical coordinates
          float theta = 2.0 * PI * uv.x; // azimuthal angle, [0, 2PI]
          float phi = PI * uv.y; // polar angle, [0, PI]

          // convert spherical coordinates to cartesian coordinates
          vec3 newPosition = vec3(0.0);
          newPosition.x = sin(phi) * cos(theta);
          newPosition.y = cos(phi);
          newPosition.z = sin(phi) * sin(theta);

          gl_Position = projectionMatrix * modelViewMatrix * vec4(newPosition, 1.0 );
          /* gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0 ) */;
          
        }
    `,

Solution

  • Four vertices (base a-plane) are a bit too little for the algorithm in the vertex shader - hence it changes the position of four points.

    If you add up some more segments, its working as intended:

    <script src="https://aframe.io/releases/1.4.1/aframe.min.js"></script>
    <script>
      AFRAME.registerShader("customShader", {
        schema: {
          color: {type: "color", is: "uniform", default: "red"},
          opacity: {type: "number", is: "uniform", default: 1.0},
        },
        vertexShader: `
            void main() {
                  float PI = 3.14159265359;
                  // convert uv to spherical coordinates
                  float theta = 2.0 * PI * uv.x; // azimuthal angle, [0, 2PI]
                  float phi = PI * uv.y; // polar angle, [0, PI]
    
                  // convert spherical coordinates to cartesian coordinates
                  vec3 newPosition = position;
                  newPosition.x = sin(phi) * cos(theta);
                  newPosition.y = cos(phi);
                    newPosition.z = sin(phi) * sin(theta);
                  gl_Position = projectionMatrix * modelViewMatrix * vec4(newPosition, 1.0 );
                }
            `,
        fragmentShader: `
                  precision mediump float;
                  uniform vec3 color;
                  uniform float opacity;
    
                  void main() {
                    gl_FragColor = vec4(color, 1.0);
                  }
            `,
      });
    </script>
    
      <a-scene background="color: black">
        <a-camera position="0 0 3"></a-camera>
        <a-plane 
               segments-height="15" 
               segments-width="15" 
               position="0 0 -2" 
               material="shader: customShader; color: green" />
        <a-sky color="#ECECEC"></a-sky>
      </a-scene>