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



我试图在列表项目上集成WebGL动画:鼠标悬停时给视频留出位置的图片。

过渡与http://taotajima.jp/相同,我的灵感来自https://github.com/watab0shi/taotajimajp-transition

的碎片和顶点为此,我使用Angular和CurtainsJS与GSAP。

我的问题是第一个纹理隐藏了动画末尾的视频(更多细节在这篇文章的末尾)

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

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

CodeSandbox链接:https://codesandbox.io/s/divine-leftpad-wdf41?file=/src/app/app.component.ts

有人能解释一下我做错了什么吗?

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

  • 你正在使用你的uProgress统一的分数值,但是当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. );
}

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

希望能满足你的需要,

最新更新