1

Apologies for the vague question but I wasn't sure how to phrase this. I'm trying to write some THREE.js/GLSL code that produces a circular gradient (for some SDF stuff). With the code below I would expect to see the gradient on the plane, but the plane remains white and nothing else renders on it. Can anyone tell me where I'm going wrong?

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>My first three.js app</title>
        <style>
            body { margin: 0; }
            canvas { width: 100%; height: 100% }
        </style>
    </head>
    <body>
        <script type="x-shader/x-vertex" id="sdfVS">
            varying vec2 vUv; // pass the uv coordinates of each pixel to the frag shader

            void main() {
              vUv = uv;
              gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
            }
        </script>
        <script type="x-shader/x-fragment" id="sdfFS">
            precision mediump float;
            uniform vec2 u_resolution;
            varying vec2 vUv;

            float circle(vec2 pos, float radius)
            {
                return distance(pos, vec2(radius));
            }

            void main()
            {
                vec2 pos = (gl_FragCoord.xy / vUv) * 2.0 - 1.0;
                float circle1 = circle(pos, 0.5);
                vec3 color = vec3(circle1);
                gl_FragColor = vec4(color, 1.0);
            }
        </script>
        <script src="../../js/three.min.js"></script>
        <script>
            var scene, camera, renderer, aspect, geometry, material, plane;
            var container;
            var frustumSize = 2;

            init();
            animate();

            function init() {
                container = document.createElement( 'div' );
                document.body.appendChild( container );

                scene = new THREE.Scene();
                scene.background = new THREE.Color(0x0000ff);

                aspect = window.innerWidth / window.innerHeight;
                camera = new THREE.OrthographicCamera( 0.5 * frustumSize * aspect / - 2, 0.5 * frustumSize * aspect / 2, frustumSize / 2, frustumSize / - 2, 0.1, 1 );
                cameraOrthoHelper = new THREE.CameraHelper( camera );
                scene.add( cameraOrthoHelper );

                var width = 1;
                var height = 1;
                geometry = new THREE.PlaneGeometry(width, height);

                material = new THREE.ShaderMaterial( {
                    vertexShader: document.getElementById('sdfVS').textContent,
                    fragmentShader: document.getElementById('sdfFS').textContent,
                    side: THREE.DoubleSide
                } );

                plane = new THREE.Mesh( geometry, material );
                plane.rotation.x = 0;
                plane.rotation.y = THREE.Math.degToRad( -90 );
                plane.rotation.z = 0;
                scene.add( plane )

                renderer = new THREE.WebGLRenderer();
                renderer.setPixelRatio( window.devicePixelRatio );
                renderer.setSize( window.innerWidth, window.innerHeight );
                container.appendChild( renderer.domElement );

                window.addEventListener( 'resize', onWindowResize, false );
            }

            function onWindowResize() {
                camera.aspect = window.innerWidth / window.innerHeight;
                camera.updateProjectionMatrix();
                renderer.setSize( window.innerWidth, window.innerHeight );
            }

            function animate() {
                requestAnimationFrame( animate );
                render();
            }

            function render() {
                camera.position.x = -1;
                camera.position.y = 0;
                camera.position.z = 0;
                camera.lookAt( scene.position );
                camera.updateMatrixWorld();
                renderer.render( scene, camera );
            }
        </script>
    </body>
</html>
1
  • If you change vec2 pos = (gl_FragCoord.xy / vUv) * 2.0 - 1.0; to vec2 pos = vUv;, is this the effect you expect? Commented Oct 26, 2019 at 18:00

1 Answer 1

1

Can't get this line:

vec2 pos = (gl_FragCoord.xy / vUv) * 2.0 - 1.0;

Seems like you want to calculate uv coordinates, but if so, then you already have uvs (passed in vUv).

You can do the thing this way, as an option:

var scene, camera, renderer, aspect, geometry, material, plane;
var container;
var clock = new THREE.Clock();
var frustumSize = 2;

init();
animate();

function init() {
  container = document.createElement('div');
  document.body.appendChild(container);

  scene = new THREE.Scene();
  scene.background = new THREE.Color(0x0000ff);

  aspect = window.innerWidth / window.innerHeight;
  camera = new THREE.OrthographicCamera(0.5 * frustumSize * aspect / -2, 0.5 * frustumSize * aspect / 2, frustumSize / 2, frustumSize / -2, 0.1, 1);
  cameraOrthoHelper = new THREE.CameraHelper(camera);
  scene.add(cameraOrthoHelper);

  var width = 1;
  var height = 1;
  geometry = new THREE.PlaneGeometry(width, height);

  material = new THREE.ShaderMaterial({
  	uniforms: {time: {value: 0}},
    vertexShader: document.getElementById('sdfVS').textContent,
    fragmentShader: document.getElementById('sdfFS').textContent,
    side: THREE.DoubleSide
  });

  plane = new THREE.Mesh(geometry, material);
  plane.rotation.x = 0;
  plane.rotation.y = THREE.Math.degToRad(-90);
  plane.rotation.z = 0;
  scene.add(plane)

  renderer = new THREE.WebGLRenderer();
  renderer.setPixelRatio(window.devicePixelRatio);
  renderer.setSize(window.innerWidth, window.innerHeight);
  container.appendChild(renderer.domElement);

  window.addEventListener('resize', onWindowResize, false);
}

function onWindowResize() {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight);
}

function animate() {
  requestAnimationFrame(animate);
  render();
}

function render() {
  camera.position.x = -1;
  camera.position.y = 0;
  camera.position.z = 0;
  camera.lookAt(scene.position);
  camera.updateMatrixWorld();
  var t = clock.getElapsedTime();
  material.uniforms.time.value = t;
  renderer.render(scene, camera);
}
body {
  overflow: hidden;
  margin: 0;
}
<script src="https://threejs.org/build/three.min.js"></script>
<script type="x-shader/x-vertex" id="sdfVS">
  varying vec2 vUv; // pass the uv coordinates of each pixel to the frag shader

  void main() {
    vUv = uv;
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
  }
</script>
<script type="x-shader/x-fragment" id="sdfFS">
  precision mediump float;

  uniform float time;
  uniform vec2 u_resolution;
  varying vec2 vUv;

  float circle(vec2 uv, vec2 pos, float radius) {
    return smoothstep(radius, 0., length(uv - pos));
  }

  void main()
  {
    vec2 uv = vUv * 2. - 1.;
    vec2 pos = vec2(cos(time), sin(time));
    float circle1 = circle(uv, pos, 1.0);
    vec3 color = vec3(circle1);
    gl_FragColor = vec4(color, 1.0);
  }
</script>

Sign up to request clarification or add additional context in comments.

1 Comment

Ah absolutely awesome, using your code I get the result I'd expected (with bonus movement), thanks!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.