CurtainsJS GSAP WebGL 列表项鼠标悬停问题

CurtainsJS GSAP WebGL list items mouseover issue

我正在尝试在列表项上集成 WebGL 动画: 在鼠标悬停时让位给视频的图像。

过渡与http://taotajima.jp/ and I'm inspired of the frag and vertex from https://github.com/watab0shi/taotajimajp-transition

相同

为此,我使用 Angular 和 CurtainsJS 以及 GSAP。

我的问题是第一个纹理隐藏了动画结束时的视频(更多细节在这个post结尾)

我在我的组件 (home.page.ts) 之后创建了一个 TS class:

export class WebglHover {
  webGLCurtain: any;
  canvas: any;
  planeElement: any;
  mouse: any;
  params: any;
  plane: any;

  constructor(set) {
    this.canvas = set.canvas;
    this.webGLCurtain = new Curtains({
      container: this.canvas,
      watchScroll: false,
      pixelRatio: Math.min(1.5, window.devicePixelRatio),
    });
    this.planeElement = set.planeElement;
    this.mouse = {
      x: 0,
      y: 0,
    };
    this.params = {
      vertexShader: document.getElementById("plane-vs").textContent,
      fragmentShader: document.getElementById("plane-fs").textContent,
      widthSegments: 40,
      heightSegments: 40, // 40*40*6 = 9600 vertices
      uniforms: {
        time: {
          name: "uTime",
          type: "1f",
          value: 0,
        },
        mousepos: {
          name: "uMouse",
          type: "2f",
          value: [0, 0],
        },
        resolution: {
          name: "uReso",
          type: "2f",
          value: [innerWidth, innerHeight],
        },
        progress: {
          name: "uProgress",
          type: "1f",
          value: 0,
        },
        acceleration: {
          name: "uAccel",
          value: [0.5, 2.0],
          type: "2f"
        }
      },
    };
    this.initPlane();
  }

  initPlane() {
    this.plane = new Plane(this.webGLCurtain, this.planeElement, this.params);

    this.plane.setScale(1, 1);

    if (this.plane) {
      this.plane.onReady(() => {
        this.update();
        this.initEvent();
      });
    }
  }

  update() {
    this.plane.onRender(() => {
      this.plane.uniforms.time.value += 0.01;

      this.plane.uniforms.resolution.value = [innerWidth, innerHeight];
    });
  }

  resize() {
      // this.plane.resize();
      // this.plane.updatePosition();

      // this.plane.resetPlane(this);
      // this.plane.setPerspective(50, 0.1, 150)
  }

  initEvent() {

    this.planeElement.addEventListener("mouseenter", () => {
      TweenLite.to(this.plane.uniforms.progress, 0.8, {
        value: 1,
      });
    });

    this.planeElement.addEventListener("mouseout", () => {
      TweenLite.to(this.plane.uniforms.progress, 0.8, {
        value: 0,
      });
    });

    document.body.addEventListener("resize", () => {
      this.resize();
    });
  }

我在 WebGlHover (home.page.ts) 之前在我的组件中使用它:

  ngAfterViewInit(): void {
    window.onload = () => {
      setTimeout(() => {
        document.querySelectorAll(".list_items").forEach((slide) => {
          const canvas = slide.querySelector(".canvas");
          const planeElement = slide.querySelector(".plane");
          new WebglHover({
            canvas: canvas,
            planeElement: planeElement,
          });
        });
      });
    };
  }

模板(home.page.html)

  <main class="list_items">
    <section class="item">
      <div class="canvas"></div>
      <div class="plane">
        <img
          data-sampler="texture0"
          id="texture0"
          src="/assets/img/the-9d-project.jpg"
          crossorigin="anonymous"
        />
        <video
          id="video texture1"
          data-sampler="texture1"
          loop
          autoplay
          muted
          [controls]="false"
          preload="auto"
          data-setup='{ "controls": false, "autoplay": true, "preload": "auto", "loop":true }'
        >
          <source
            src="/assets/Main Sequence-1.webm"
            type="video/webm"
          />
        </video>
      </div>
      <div class="slide__content">
        <p>Lorem ipsum dolor sit.</p>
      </div>
    </section>
  </main>

顶点和着色器 (index.html)

<!-- vertex shader -->
 <script id="plane-vs" type="x-shader/x-vertex">
  precision mediump float;

  // those are the mandatory attributes that the lib sets
  attribute vec3 aVertexPosition;
  attribute vec2 aTextureCoord;

  // those are mandatory uniforms that the lib sets and that contain our model view and projection matrix
  uniform mat4 uMVMatrix;
  uniform mat4 uPMatrix;

  uniform mat4 texture0Matrix;
  uniform mat4 texture1Matrix;
  uniform mat4 mapMatrix;
  uniform float uFixAspect;

  // if you want to pass your vertex and texture coords to the fragment shader
  varying vec3 vVertexPosition;
  varying vec2 vTextureCoord0;
  varying vec2 vTextureCoord1;
  varying vec2 vTextureCoordMap;

  void main() {
    vec3 vertexPosition = aVertexPosition;

    gl_Position = uPMatrix * uMVMatrix * vec4(vertexPosition, 1.0);

    // set the varyings
    vTextureCoord0 = (texture0Matrix * vec4(aTextureCoord, 0., 1.)).xy;
    vTextureCoord1 = (texture1Matrix * vec4(aTextureCoord, 0., 1.)).xy;
    vVertexPosition = vertexPosition;
  }
</script>
<script id="plane-fs" type="x-shader/x-fragment">
  precision mediump float;

  uniform float uTime;
  uniform float uProgress;
  uniform vec2 uReso;
  uniform vec2 uMouse;
  uniform vec2 uAccel;
  
  // get our varyings
  varying vec3 vVertexPosition;
  varying vec2 vTextureCoord0;
  varying vec2 vTextureCoord1;
  varying vec2 vTextureCoordMap;

  // the uniform we declared inside our javascript

  // our texture sampler (default name, to use a different name please refer to the documentation)
  uniform sampler2D texture0;
  uniform sampler2D texture1;
  uniform sampler2D map;

  vec2 translateDirection = vec2( -.5, 1. );

  vec2 mirrored( vec2 v ) {
    vec2 m = mod( v, 2. );
    return mix( m, 2. - m, step( 1., m ) );
  }
  
  float tri( float p ) {
    return mix( p, 1. - p, step( .5, p ) ) * 2.;
  }

  void main(){
    vec2 uv = vTextureCoord0; 

    float progress0 = uProgress;
    float progress1 = 1. - uProgress;

    float pct = fract( uProgress );

    float delayValue = ( ( pct * 7. ) - ( uv.y * 2. ) + uv.x ) - 2.;
    delayValue = clamp( delayValue, 0., 1. );
  
    vec2 translate = pct + delayValue * uAccel;
    vec2 translate0 = translateDirection * translate;
    vec2 translate1 = translateDirection * ( translate - 1. - uAccel );
  
    vec2 w = sin( sin( uTime ) * vec2( 0., 0.3 ) + uv.yx * vec2( 0., 4. ) ) * vec2( 0., .5 );
    vec2 xy = w * ( tri( pct ) * .5 + tri( delayValue ) * .5 );

    vec2 uv0 = vTextureCoord1 + translate0 + xy;
    vec2 uv1 = vTextureCoord1 + translate1 + xy;
  
    vec3 color0 = texture2D( texture0, mirrored( uv0 ) ).rgb;
    vec3 color1 = texture2D( texture1, mirrored( uv1 ) ).rgb;
  
    vec3 color = mix( color0, color1, delayValue );
  
    gl_FragColor = vec4( color, 1. );        
  }
</script>

所以,当我将鼠标悬停在一个项目上时,动画有效,但最后,视频 (texture1) 被第一张图片 (texture0) 取代,我不明白为什么。

结果: https://gyazo.com/115974a0920894ee113cb8a743587dea

代码沙盒link: https://codesandbox.io/s/divine-leftpad-wdf41?file=/src/app/app.component.ts

有人可以解释我做错了什么吗?

您的片段着色器中有几个错误。

  • 您正在使用 uProgress uniform 的分数值,但是当 uProgress 等于 1 时,它的分数值等于 0,然后您的混合操作再次回落到 color0。
  • 您的 translate1 值需要乘以 progress1,因此当 uProgress 等于 1 时,第二个纹理不再翻译。

这个片段着色器应该可以解决您的问题:

precision mediump float;

uniform float uTime;
uniform float uProgress;
uniform vec2 uReso;
uniform vec2 uMouse;
uniform vec2 uAccel;

// get our varyings
varying vec3 vVertexPosition;
varying vec2 vTextureCoord0;
varying vec2 vTextureCoord1;
varying vec2 vTextureCoordMap;

// the uniform we declared inside our javascript

// our texture sampler (default name, to use a different name please refer to the documentation)
uniform sampler2D texture0;
uniform sampler2D texture1;
uniform sampler2D map;

vec2 translateDirection = vec2( -.5, 1. );

vec2 mirrored( vec2 v ) {
    vec2 m = mod( v, 2. );
    return mix( m, 2. - m, step( 1., m ) );
}

float tri( float p ) {
    return mix( p, 1. - p, step( .5, p ) ) * 2.;
}

void main(){
    vec2 uv = vTextureCoord0;

    float progress0 = uProgress;
    float progress1 = 1. - uProgress;

    float pct = fract( uProgress );

    float delayValue = ( ( uProgress * 7. ) - ( uv.y * 2. ) + uv.x ) - 2.;
    delayValue = clamp( delayValue, 0., 1. );

    vec2 translate = pct + delayValue * uAccel;
    vec2 translate0 = translateDirection * translate;
    vec2 translate1 = translateDirection * ( translate - 1. - uAccel ) * progress1;

    vec2 w = sin( sin( uTime ) * vec2( 0., 0.3 ) + uv.yx * vec2( 0., 4. ) ) * vec2( 0., .5 );
    vec2 xy = w * ( tri( delayValue ) * .5 + tri( delayValue ) * .5 );

    vec2 uv0 = vTextureCoord1 + translate0 + xy;
    vec2 uv1 = vTextureCoord1 + translate1 + xy;

    vec3 color0 = texture2D( texture0, mirrored( uv0 ) ).rgb;
    vec3 color1 = texture2D( texture1,  uv1 ).rgb;

    vec3 color = mix( color0, color1, delayValue );

    gl_FragColor = vec4( color, 1. );
}

这是更新后的代码框:https://codesandbox.io/s/cranky-fog-sfd0n?file=/src/index.html

希望能满足您的需求,