Source: lib/xutils/shaders/tile-thermal.glsl.js


import {glx} from './glx.glsl';

/**
 * It's supposed look like <a href='https://www.shadertoy.com/view/3ssGzn'>
 * Thermal Particles III @shadertoy</a>. And uv distortion can be done like
 * <a href='https://www.shadertoy.com/view/4sf3zS'>Texture twistery @shadertoy</a>,
 * with the help of color re-shaping:<pre>
     vec2 getDistortion(vec2 uv, float d, float t) {
      uv.x += cos(d) + t * 0.9;
      uv.y += sin(d + t * 0.75);
      return uv;
    }

    vec4 getDistortedTexture(sampler2D iChannel, vec2 uv) {
      vec4 rgb = texture(iChannel, uv);
      return rgb;
    }

    void mainImage( out vec4 fragColor, in vec2 fragCoord )
    {
      vec2 uv = fragCoord.xy / iResolution.xy;
      float t = iTime * 0.125;
      vec2 mid = vec2(0.5,0.5);

      vec2 focus = iMouse.xy / iResolution.xy;
      float d1 = distance(focus+sin(t * 0.125) * 0.5, uv);
      float d2 = distance(focus+cos(t), uv);

      vec4 rgb = (getDistortedTexture(iChannel0, getDistortion(uv, d1, t))
                  + getDistortedTexture(iChannel1, getDistortion(uv, -d2, t))) * 0.5;
      rgb.r /= d2;
      rgb.g += -0.5 + d1;
      rgb.b = -0.5 + (d1 + d2) / 2.0;
      // rgb.a = pow(rgb.a, 0.125);
      // rgb.g = pow(rgb.g, 0.5);
      rgb.r = pow(rgb.r, 1.5) * (sin(t * 10.) + 1.) * 0.125;
      rgb.b = pow(rgb.b, 1.5) * (sin((t + 5.2) * 10.) + 1.) * 0.125;
      fragColor = rgb;
    } </pre>
 * @param {object} vparas paras.vert_scale [optional] number scale of vertices
 * @return {object} {vertexShader, fragmentShader}
 * @member xglsl.tileOrbs
 * @function
 */
function tileOrbs(vparas) {
 var orbs = vparas.offsets.length || 1;
 var groups = vparas.geostyle.groups || 1;
 return {
  fragmentShader: `
    uniform float now;
    uniform float r[${orbs}];
    uniform vec4 orbColors[${orbs}];

    ${glx.u_whiteAlpha}
    uniform vec3 orbScale;
    uniform sampler2D u_tex;

    varying vec2 vUv;
    varying vec3 P;
    varying vec3 vscale;
    varying vec4 vcent[${orbs}];
    varying float vspeed;

    vec2 sdEllipsoid( vec3 eye, vec3 u, float r, vec3 centr, vec3 abc ) {
      // e = o - c, where o = eye, c = center
      vec3 e = eye - centr;
      e = e / abc;

      // delta = (u . e)^2 + r^2 - |e|^2
      u = normalize(u / abc);

      float delta = pow( dot( u, e ), 2. ) + pow( r, 2. ) - dot(e, e);
      if (delta < 0.) return vec2(delta);
      // d = - u.e +/- delta^0.5
      delta = pow( delta, 0.5 );
      return vec2( -dot( u, e ) + delta, -dot( u, e ) - delta );
    }

    vec4 mainImage( in vec2 fragCoord ) {
      vec4 fragColor = vec4(0.);
      vec3 e = cameraPosition;
      vec3 u = normalize( P - cameraPosition );

      // float speed = speedFrag[ int(tileIx) ];
      // float vspeed = .01;

      for (int i = 0; i < ${orbs}; i++) {
        vec3 ci = vcent[i].xyz;
        float ri = r[i];
        ri *= sin(now * vspeed * 0.6 + float(i) * 0.3) + 1.2;
        vec2 dists = sdEllipsoid( e, u, ri, ci, vscale );

        if (dists.x <= 0.00001) {
          ${vparas.orbDebug ? 'fragColor.g += 0.2;' : ''}
          continue;
        }

        vec3 p = e + dists.x * u;
        vec3 n = normalize(p - ci);
        float ratio = length(dists.x - dists.y) / (2. * ri);
        // working: fragColor += pow( clamp(ratio, 0.0, 1.), 8. * (sin(now * 0.001) + 1.75) ) * orbColors[i];
        // fragColor.r += pow( clamp(ratio, 0.0, 1.), 6. * (sin(now * speed + float(i) * 0.1      ) * 8. + 8.1) ) * orbColors[i].r;
        // fragColor.g += pow( clamp(ratio, 0.0, 1.), 8. * (sin(now * speed + float(i) * 0.1 + 0.01) * 9. + 9.6) ) * orbColors[i].g;
        // fragColor.b += pow( clamp(ratio, 0.0, 1.), 10. * (sin(now * speed + float(i) * 0.1 + 0.02) * 10. + 10.1) ) * orbColors[i].b;
        // fragColor.a += pow( clamp(ratio, 0.0, 1.), 11. * (sin(now * speed + float(i) * 0.1 + 0.03) * 10.5 + 10.6) ) * orbColors[i].a;

        fragColor += pow( clamp(ratio, 0.0, 1.), 8. + (abs(sin(now * vspeed + float(i) * 0.06)) * 4.) ) * orbColors[i];
        fragColor.a = 1.2 - ri;
      }
      fragColor = clamp(fragColor, 0., 1.);
      float txAlpha = clamp(whiteAlpha, 0., 1.);
      fragColor.a = 1. - txAlpha;

      vec4 texcolor = texture2D(u_tex, vUv);
      fragColor = mix(fragColor, texcolor, txAlpha);
      return fragColor;
    }

    void main() {
      gl_FragColor += mainImage(gl_FragCoord.xy);
    }`,

  vertexShader: `
    uniform float now;
    uniform float speedVert[${groups}];
    uniform float speedFrag[${groups}];
    // uniform float speed;
    uniform vec3 wpos;
    uniform vec3 offsets[${orbs}];
    uniform vec3 orbScale;

    attribute vec3 a_tan;
    attribute vec3 a_loc;

    varying vec2 vUv;
    varying vec3 P;
    varying vec3 vscale;
    varying vec4 vcent[${orbs}];
    varying float vspeed;

    void main() {
      vUv = uv;

      // gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
      vec4 worldPosition = modelMatrix * vec4(position, 1.0);

      P = worldPosition.xyz;
      vscale = orbScale;
      float speed = speedVert[ int(a_tan.y) ];
      vspeed = speedFrag[ int(a_tan.y) ];
      for (int i = 0; i < ${orbs}; i++) {
        vec3 offi = offsets[i] * 2. * sin(now * speed * 0.1 + float(i) * 0.3);
        vcent[i] = modelMatrix * vec4(a_loc + wpos + offi, 1.);
      }

      gl_Position = projectionMatrix * viewMatrix * worldPosition;
    } `
 }
}

/**Get shader of thermal tiles.
 * @param {object} vparas
 * @return {object} {vertexShader, fragmentShader}
 * @member xglsl.thermalTile
 * @function
 */
export function thermalTile(vparas) {
 var orbs = vparas.offsets.length || 1;
 var groups = vparas.geostyle.groups || 1;
 return {
  fragmentShader: `
    uniform float now;
    uniform float r[${orbs}];
    uniform vec4 orbColors[${orbs}];
	uniform float maxHeight;

    ${glx.u_whiteAlpha}
    uniform vec3 orbScale;
	uniform vec3 thermalColors[3];
    uniform sampler2D u_tex;

    varying vec2 vUv;
    varying vec3 P;
    varying vec3 vscale;
    varying vec4 vcent[${orbs}];
    varying float vspeed;
	varying float pos_y;
    ${glx.thermalColor}
    ${glx.sdEllipsoid}

    vec4 mainImage( in vec2 fragCoord ) {
      vec4 fragColor = vec4(0.);
      vec3 e = cameraPosition;
      vec3 u = normalize( P - cameraPosition );

      for (int i = 0; i < ${orbs}; i++) {
        vec3 ci = vcent[i].xyz;
        float ri = r[i];
        ri *= sin(now * vspeed * 0.6 + float(i) * 0.3) + 1.2;
        vec2 dists = sdEllipsoid( e, u, ri, ci, vscale );

        if (dists.x <= 0.00001) {
          ${vparas.orbDebug ? 'fragColor.g += 0.2;' : ''}
          continue;
        }

        vec3 p = e + dists.x * u;
        vec3 n = normalize(p - ci);
        float ratio = length(dists.x - dists.y) / (2. * ri);
        // working: fragColor += pow( clamp(ratio, 0.0, 1.), 8. * (sin(now * 0.001) + 1.75) ) * orbColors[i];
        fragColor += pow( clamp(ratio, 0.0, 1.), 8. + (abs(sin(now * vspeed + float(i) * 0.06)) * 4.) ) * orbColors[i];
        fragColor.a = 1.2 - ri;
      }
      fragColor = clamp(fragColor, 0., 1.);
      float txAlpha = clamp(whiteAlpha, 0., 1.);
      fragColor.a = 1. - txAlpha;

	  vec4 thermal = thermalColor(thermalColors, vec2(0, maxHeight), pos_y);
      fragColor = mix(fragColor, thermal, txAlpha);
      return fragColor;
    }

    void main() {
      gl_FragColor += mainImage(gl_FragCoord.xy);
    }`,

  vertexShader: `
    uniform float now;
    uniform float speedVert[${groups}];
    uniform float speedFrag[${groups}];
    uniform vec3 wpos;
    uniform vec3 offsets[${orbs}];
    uniform vec3 orbScale;

    attribute vec3 a_tan;
    attribute vec3 a_loc; // prism center compare to model center, the geo origin.

    varying vec2 vUv;
    varying vec3 P;
    varying vec3 vscale;
    varying vec4 vcent[${orbs}];
    varying float vspeed;
	varying float pos_y;

    void main() {
      vUv = uv;
      pos_y = position.y;

      // gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
      vec4 worldPosition = modelMatrix * vec4(position, 1.0);

      P = worldPosition.xyz;
      vscale = orbScale;
      float speed = speedVert[ int(a_tan.y) ];
      vspeed = speedFrag[ int(a_tan.y) ];
      for (int i = 0; i < ${orbs}; i++) {
        vec3 offi = offsets[i] * 2. * sin(now * speed * 0.1 + float(i) * 0.3);
        vcent[i] = modelMatrix * vec4(a_loc + wpos + offi, 1.);
      }

      gl_Position = projectionMatrix * viewMatrix * worldPosition;
    } `
 }
}