javascriptglslshaderwebglregl

WebGL interpolate with a reference color inside a triangle


Using regl, I am trying to draw a triangle with WebGL where I can define a color at some reference point inside the triangle, and have the color of the other pixels be a function of their distance to this point.

So far, it only works when this reference point is one of the corner :

gradient from corner

This was done using the following Vert and Frag shaders :

  vert: `
  precision mediump float;
  uniform float scale;
  attribute vec2 position;
  attribute vec3 color;
  varying vec3 fcolor;
  void main () {
    fcolor = color;
    gl_Position = vec4(scale * position, 0, 1);
  }
  `,

  frag: `
  precision mediump float;
  varying vec3 fcolor;
  void main () {
    gl_FragColor = vec4(sqrt(fcolor), 1);
  }
  `,

  attributes: {
    position: [
      [1, 0],
      [0, 1],
      [-1, -1]
    ],

    color: [
      [1, 0, 0],
      [0, 1, 0],
      [0, 0, 1]
    ]
  },

  uniforms: {
    scale: regl.prop('scale')
  }

The reference points here are [1,0], [0,1] and [-1,-1]. With the same triangle, how do I put another reference point at [0,0] with color white for instance ? (that would give an "island" of white inside the triangle)


Solution

  • You have to define 2 uniform variables One for the coordinates of the reference point and one for the color of the reference point:

    uniforms: {
        scale: regl.prop('scale'),
        refPoint: [0, 0],
        refColor: [1, 1, 1]
    }
    

    Pass the vertex coordinate from the vertex shader to the fragment shader by a varying variable:

    precision mediump float;
    
    uniform float scale;
    
    attribute vec2 position;
    attribute vec3 color;
    
    varying vec2 fpos;
    varying vec3 fcolor;
    
    void main()
    {
        fpos        = position;
        fcolor      = color;
        gl_Position = vec4(scale * position, 0, 1);
    }
    

    Calculate the distance from the reference point to the interpolated position in the fragment shader, by distance:

    float dist = distance(refPoint, fpos);
    

    Interpolate the colors dependent on the distance, by mix:

    vec3 micColor = mix(refColor, fcolor, dist);
    

    Fragment shader:

    precision mediump float;
    
    uniform vec2 refPoint;
    uniform vec3 refColor;
    
    varying vec2 fpos;
    varying vec3 fcolor;
    
    void main()
    {
        float dist    = distance(refPoint, fpos);
        vec3 micColor = mix(refColor, fcolor, dist);
        gl_FragColor  = vec4(sqrt(micColor), 1);
    }