three+webgl+gsap模拟海底海水涟漪动画效果代码

代码语言:html

所属分类:动画

代码描述:three+webgl+gsap模拟海底海水涟漪动画效果代码

代码标签: three webgl gsap 模拟 海底 海水 涟漪 动画

下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开

<!DOCTYPE html>
<html lang="en" >

<head>

  <meta charset="UTF-8">
<link type="text/css" rel="stylesheet" href="//repo.bfw.wiki/bfwrepo/css/reset.min.css">

</head>

<body>
  <canvas id="webgl-canvas"></canvas>

<!-- vertexShader -->
<script id="js-vertex-shader" type="x-shader/x-vertex">
  varying vec2 vUv;

  void main() {
    vUv = uv;
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
  }
</script>

<!-- fragmentShader -->
<script id="js-fragment-shader" type="x-shader/x-fragment">
  precision mediump float;
  
  uniform float time;
  uniform float uCircleScale;
  uniform vec2 uViewport;
  uniform sampler2D uVideo;
  uniform sampler2D uImage;
  varying vec2 vUv;
  
  // 以下のサイトにあるavener.glslのノイズを使い、ノイズを生成する。
  // https://gist.github.com/akella/330b3caec2b68bb7f4534dae5918c0e9
  mat2 rot2d (in float angle) {
    return mat2(cos(angle), -sin(angle), sin(angle), cos(angle));
  }
  float r (in float a, in float b) { return fract(sin(dot(vec2(a,b),vec2(12.9898,78.233)))*43758.5453); }
  float h (in float a) { return fract(sin(dot(a,dot(12.9898,78.233)))*43758.5453); }

  float noise (in vec3 x) {
      vec3 p  = floor(x);
      vec3 f  = fract(x);
      f       = f*f*(3.0-2.0*f);
      float n = p.x + p.y*57.0 + 113.0*p.z;
      return mix(mix(mix( h(n+0.0), h(n+1.0),f.x),
                     mix( h(n+57.0), h(n+58.0),f.x),f.y),
                 mix(mix( h(n+113.0), h(n+114.0),f.x),
                     mix( h(n+170.0), h(n+171.0),f.x),f.y),f.z);
  }
  // http://www.iquilezles.org/www/articles/morenoise/morenoise.htm
  // http://www.pouet.net/topic.php?post=401468
  vec3 dnoise2f (in vec2 p) {
      float i = floor(p.x), j = floor(p.y);
      float u = p.x-i, v = p.y-j;
      float du = 30.*u*u*(u*(u-2.)+1.);
      float dv = 30.*v*v*(v*(v-2.)+1.);
      u=u*u*u*(u*(u*6.-15.)+10.);
      v=v*v*v*(v*(v*6.-15.)+10.);
      float a = r(i,     j    );
      float b = r(i+1.0, j    );
      float c = r(i,     j+1.0);
      float d = r(i+1.0, j+1.0);
      float k0 = a;
      float k1 = b-a;
      float k2 = c-a;
      float k3 = a-b-c+d;
      return vec3(k0 + k1*u + k2*v + k3*u*v,
                  du*(k1 + k3*v),
                  dv*(k2 + k3*u));
  }

  float fbm (in vec2 uv) {
      vec2 p = uv;
    float f, dx, dz, w = 0.5;
      f = dx = dz = 0.0;
      for(int i = 0; i < 3; ++i){        
          vec3 n = dnoise2f(uv);
          dx += n.y;
          dz += n.z;
          f += w * n.x / (1.0 + dx*dx + dz*dz);
          w *= 0.86;
          uv *= vec2(1.36);
          uv *= rot2d(1.25 * noise(vec3(p * 0.1, 0.12 * time)) +
                      0.75 * noise(vec3(p * 0.1, 0.20 * time)));
      }
      return f;
  }

  float fbmLow (in vec2 uv) {
      float f, dx, dz, w = 0.5;
      f = dx = dz = 0.0;
      for(int i = 0; i < 3; ++i){        
          vec3 n = dnoise2f(uv);
          dx += n.y;
          dz += n.z;
          f += w * n.x / (1.0 + dx*dx + dz*dz);
          w *= 0.95;
          uv *= vec2(3);
      }
      return f;
  }
  // ノイズここまで
  
  // circle関数
  // 円を作成する。
  float circle(vec2 uv, float radius, float sharp) {
    // 円の位置を中心にする。
    vec2 tempUV = uv - vec2(0.5);
    
    // sharp(輪郭)に半径を乗算したものを半径から減算したもの(x)と、
    // sharp(輪郭)に半径を乗算したものに半径を加算したもの(y)の値を、
    // dotに渡したtempUVの値で線形補間する。
    // 最終的に求められた値を1.0から引くことによって、円の内側に動画が表示されるようになる。(逆に1.0から引かないと、円の外側に動画が表示される)
    return 1.0 - smoothstep(
      radius - radius * sharp,
      radius + radius * sharp,
      dot(tempUV, tempUV) * 4.0
    );
  }

  void main()	{
    // 動画のアスペクト比(幅 / 高さ)
    float videoAspect = 1280.0 / 720.0;
    // 画面のアスペクト比(幅 / 高さ)
    float screenAspect = uViewport.x / uViewport.y;
    vec2 multiplier = vec2(1.0);
    // 動画の位置を中心にする。
    vec2 centerVector = vUv - vec2(0.5);
    
    // 動画のアスペクト比が画面のアスペクト比よりも大きかったら、
    // multiplierのxに"画面のアスペクト比 / 動画のアスペクト比"を渡す。
    if(videoAspect > screenAspect) {
      multiplier = vec2(screenAspect / videoAspect, 1.0);
    }

    // centerVectorにmultiplierを乗算し、それに0.5を加算したものをnewUVとする。
    vec2 newUV = centerVector * multiplier + vec2(0.5);
    
    // ripples(波紋)
    vec2 noiseUV = centerVector;
    // noiseUV(centerVector)にtimeの値を渡したrot2d関数を乗算していくことで、
    // noiseが繰り返される&回転による波紋が不規則に広がるようになる。
    noiseUV *= rot2d(time * 10.5);
    vec2 rv = noiseUV / (length(noiseUV * 20.0) * noiseUV * 20.0);
    float swirl = 10.0 * fbm(
      noiseUV * fbmLow(vec2(length(noiseUV) - time + 0.0 * rv))
    );
    // noiseUV(centerVector)に負のtimeの値を渡したrot2d関数を乗算していくことで、
    // noiseが繰り返される&回転による波紋が不規則に広がるようになる。
    noiseUV *= rot2d(-time * 4.5);
    // fbmLow関数にnoiseUVにswirlを乗算したものを渡し、さらにそれにcenterVectorを乗算することで、
    // swirlDistort(ノイズの強さ)を求める。
    vec2 swirlDistort = fbmLow(noiseUV * swirl) * centerVector * 15.0;
    
    // centerVectorに0.5を乗算したものにnewUVを加算することで内側(動画)の位置を中心にし、それにuCircleScaleを乗算したものをinsideUVに渡す。
    // この時、uCircleScaleの値を1.0から減算したものを乗算すると円の拡大に応じて動画も拡大するようになり、
    // uCircleScaleの値をそのまま乗算すると、円の拡大に応じて動画は小さくなり、かつ繰り返されるようになる。
    vec2 insideUV = newUV + 0.5 * centerVector * (1.0 - uCircleScale);
    // insideUVの値をfract関数に渡し、それを再度insideUVに渡す。
    insideUV = fract(insideUV);
    // end of ripples

    // centerVectorのx,yそれぞれに1.0を乗算したものに0.5を加算し、circleUVを求める。
    vec2 circleUV = centerVector * (1.0, 1.0) + vec2(0.5);
    // circle関数にcircleUV(uv)、uCircleScale(radius)、0.25 + 0.25 * uCircleScale(sharp)を渡し、それをcircleProgress(円の進捗状況)に渡す。
    // この時、sharpの値を変更すると、テクスチャと動画の線形補間の割合が変わる。(circle関数が内部でsmoothstep関数を使っているので)
    float circleProgress = circle(circleUV, uCircleScale, 0.25 + 0.25 * uCircleScale);
    // ここまで求めてきたnewUV(動画のuv)、swirlDistort(ノイズの強さ)、centerVector(中心ベクトル)、circleProgress(円の進捗状況)を使って、backgroundUV(uImageから取り出した値を渡すuv)を求める。
    vec2 backgroundUV = newUV + 0.1 * swirlDistort - centerVector * circleProgress - 0.5 * centerVector * uCircleScale;
    // texture2DにuVideoとinsideUVを渡し、uVideoから取り出した値をinsideUVに渡したものをvideoとする。
    vec4 video = texture2D(uVideo, insideUV);
    // texture2DにuImageとbackgroundUVを渡し、uImageから取り出した値をbackgroundUVに渡したものをimageとする。
    vec4 image = texture2D(uImage, backgroundUV);
    // mix関数を使い、image(テクスチャ)とvideo(動画)をcircleProgress(円の進捗状況)の値で線形補間する。
    vec4 final = mix(image, video, circleProgress);

    gl_FragColor = final;
  }
</s.........完整代码请登录后点击上方下载按钮下载查看

网友评论0