马黑黑 发表于 2025-6-30 18:11

元素能量之英雄主题

<style>
        #papa { margin: 30px 0; left: calc(50% - 81px); transform: translateX(-50%);width: clamp(600px, 90vw, 1400px); height: auto; aspect-ratio: 16/9; background: #000; box-shadow: 2px 2px 8px #000; display: grid; place-items: center; z-index: 1; position: relative; }
        #btnFs { bottom: 30px; color: cyan; border-color: cyan !important; }
        #player { position: absolute; width: 16vw; height: 16vw; border-radius: 50%; transform: translate(10px, -20px); cursor: pointer; z-index: 91; }
        #vid {position: absolute; width: 100%; height: 100%; object-fit: cover; mask: radial-gradient(transparent 20%, red); -webkit-mask: radial-gradient(transparent 20%, red); opacity: .6; pointer-events: none; z-index: 90; }
</style>

<div id="papa">
        <audio id="aud" src="https://music.163.com/song/media/outer/url?id=1984625" autoplay loop></audio>
        <video id="vid" src="https://bpic.588ku.com/video_listen/588ku_video/25/04/08/17/14/59/video67f4e91361a39.mp4" autoplay loop muted></video>
        <div id="player" title="播放/暂停"></div>
</div>

<script type="module">
        import { THREE, scene, camera, renderer, clock, basic3 } from 'https://638183.freep.cn/638183/3dev/3/3basic.js?v=1.0';
        import TWEEN from 'https://638183.freep.cn/638183/3dev/examples/jsm/libs/tween.module.js';
        import { FS } from 'https://638183.freep.cn/638183/web/ku/FS.js';
        basic3(papa, aud.paused);

        const map = new THREE.TextureLoader().load('https://638183.freep.cn/638183/t24/w4/lzlx.webp');
        map.colorSpace = THREE.SRGBColorSpace;
        const planeGeometry = new THREE.PlaneGeometry(8, 4.5);
        const planeMaterial = new THREE.MeshBasicMaterial({ map: map });
        const plane = new THREE.Mesh(planeGeometry, planeMaterial);

        const geometry1 = new THREE.TorusGeometry(0.4, 0.2, 40, 40); // 几何体1
        geometry1.translate(-3, 0, 0); // 位置调整
        const geometry2 = new THREE.TorusGeometry(0.4, 0.2, 40, 40); // 几何体2(仅取其点数据)
        geometry2.translate(3, 0, 0); // 位置调整
        const pointsMaterial = new THREE.PointsMaterial({
                size: 0.05, // 尺寸
                color: 'cyan', // 颜色
                transparent: true, // 开启透明度
                opacity: 0.3 // 透明设置
        });
        const points = new THREE.Points(geometry1, pointsMaterial); // 用几何体1构图
        scene.add(plane, points);

        const startPositions = geometry1.attributes.position; // tween动画起始位置数组
        const endPositions = geometry2.attributes.position; // tween动画终点位置数组
        const total = startPositions.count; // 点云的点数量
        // tween动画设计 : 点位置交换规则 →
        for(let i = 0; i < startPositions.count; i++) {
                if (i % 10 === 0) continue; // 跳过被10整除的点
                const tween = new TWEEN.Tween(startPositions.array)
                .to({
                        : endPositions.array[(total - i - 1) * 3],
                        : endPositions.array[(total - i - 1) * 3 + 1],
                        : endPositions.array[(total - i - 1) * 3 + 2]
                }, 5000 * Math.random() + 5000)
                .delay(2000)
                .easing(TWEEN.Easing.Exponential.Out)
                .onUpdate(() => startPositions.needsUpdate = true)
                .repeat(Infinity)
                .repeatDelay(1500)
                .yoyo(3000)
                .start();
        }

        const animate = () => {
                TWEEN.update();
                const delta = clock.getDelta();
                plane.rotation.z += delta / 5;
                renderer.render(scene, camera);
                requestAnimationFrame(animate);
        };

        const tweens = TWEEN.getAll();

        aud.onplaying = aud.onpause = () => {
                tweens.forEach(tween => aud.paused ? tween.pause() : tween.resume());
                aud.paused ? clock.stop() : clock.start();
        };

        animate();
        FS(papa, player);
</script>

马黑黑 发表于 2025-6-30 18:12

帖子代码

<style>
    #papa { margin: 30px 0; left: calc(50% - 81px); transform: translateX(-50%);width: clamp(600px, 90vw, 1400px); height: auto; aspect-ratio: 16/9; background: #000; box-shadow: 2px 2px 8px #000; display: grid; place-items: center; z-index: 1; position: relative; }
    #btnFs { bottom: 30px; color: cyan; border-color: cyan !important; }
    #player { position: absolute; width: 16vw; height: 16vw; border-radius: 50%; transform: translate(10px, -20px); cursor: pointer; z-index: 91; }
    #vid {position: absolute; width: 100%; height: 100%; object-fit: cover; mask: radial-gradient(transparent 20%, red); -webkit-mask: radial-gradient(transparent 20%, red); opacity: .6; pointer-events: none; z-index: 90; }
</style>

<div id="papa">
    <audio id="aud" src="https://music.163.com/song/media/outer/url?id=1984625" autoplay loop></audio>
    <video id="vid" src="https://bpic.588ku.com/video_listen/588ku_video/25/04/08/17/14/59/video67f4e91361a39.mp4" autoplay loop muted></video>
    <div id="player" title="播放/暂停"></div>
</div>

<script type="module">
    import { THREE, scene, camera, renderer, clock, basic3 } from 'https://638183.freep.cn/638183/3dev/3/3basic.js?v=1.0';
    import TWEEN from 'https://638183.freep.cn/638183/3dev/examples/jsm/libs/tween.module.js';
    import { FS } from 'https://638183.freep.cn/638183/web/ku/FS.js';
    basic3(papa, aud.paused);

    const map = new THREE.TextureLoader().load('https://638183.freep.cn/638183/t24/w4/lzlx.webp');
    map.colorSpace = THREE.SRGBColorSpace;
    const planeGeometry = new THREE.PlaneGeometry(8, 4.5);
    const planeMaterial = new THREE.MeshBasicMaterial({ map: map });
    const plane = new THREE.Mesh(planeGeometry, planeMaterial);

    const geometry1 = new THREE.TorusGeometry(0.4, 0.2, 40, 40); // 几何体1
    geometry1.translate(-3, 0, 0); // 位置调整
    const geometry2 = new THREE.TorusGeometry(0.4, 0.2, 40, 40); // 几何体2(仅取其点数据)
    geometry2.translate(3, 0, 0); // 位置调整
    const pointsMaterial = new THREE.PointsMaterial({
      size: 0.05, // 尺寸
      color: 'cyan', // 颜色
      transparent: true, // 开启透明度
      opacity: 0.3 // 透明设置
    });
    const points = new THREE.Points(geometry1, pointsMaterial); // 用几何体1构图
    scene.add(plane, points);

    const startPositions = geometry1.attributes.position; // tween动画起始位置数组
    const endPositions = geometry2.attributes.position; // tween动画终点位置数组
    const total = startPositions.count; // 点云的点数量
    // tween动画设计 : 点位置交换规则 →
    for(let i = 0; i < startPositions.count; i++) {
      if (i % 10 === 0) continue; // 跳过被10整除的点
      const tween = new TWEEN.Tween(startPositions.array)
      .to({
            : endPositions.array[(total - i - 1) * 3],
            : endPositions.array[(total - i - 1) * 3 + 1],
            : endPositions.array[(total - i - 1) * 3 + 2]
      }, 5000 * Math.random() + 5000)
      .delay(2000)
      .easing(TWEEN.Easing.Exponential.Out)
      .onUpdate(() => startPositions.needsUpdate = true)
      .repeat(Infinity)
      .repeatDelay(1500)
      .yoyo(3000)
      .start();
    }

    const animate = () => {
      TWEEN.update();
      const delta = clock.getDelta();
      plane.rotation.z += delta / 5;
      renderer.render(scene, camera);
      requestAnimationFrame(animate);
    };

    const tweens = TWEEN.getAll();

    aud.onplaying = aud.onpause = () => {
      tweens.forEach(tween => aud.paused ? tween.pause() : tween.resume());
      aud.paused ? clock.stop() : clock.start();
    };

    animate();
    FS(papa, player);
</script>

马黑黑 发表于 2025-6-30 18:24

帖子使用两个圆环几何体(TorusGeometry),第一个跟点云材质(PointsMaterial)构图,第二个仅取其点云数据。两个圆环几何体做对称偏移,目的是拉开距离,为点云的动画布置路径长度。

tween动画是点对点的运动,点云中的点按 → 这样的次序交叉换位。

旋转的背景也是 ThreeJS 动画,这是一个平面几何体 PlaneGeometry,在 Z 轴上旋转。

红影 发表于 2025-6-30 19:24

这个太奇妙了,刚开始还是圆环1的点朝圆环2跑,然后反过来跑,跑两次后达到均衡,就变成两边彼此跑了。这个看着太奇妙了{:4_199:}

红影 发表于 2025-6-30 19:31

圆环2被设置成了终点位置,交换点的方式还是 → 错位的,空间交错特别好看。
{:4_187:}

红影 发表于 2025-6-30 19:37

好像时间长点不去看它,再 看的时候又开始初始的点的分配了。

马黑黑 发表于 2025-6-30 19:42

红影 发表于 2025-6-30 19:31
圆环2被设置成了终点位置,交换点的方式还是 → 错位的,空间交错特别好看。

最初的设计是走弧线。点太多,感觉把控不完美,放弃,换用现在的交叉换位方式。

马黑黑 发表于 2025-6-30 19:44

红影 发表于 2025-6-30 19:37
好像时间长点不去看它,再 看的时候又开始初始的点的分配了。

这个有可能:tween有它的管理机制,3basic.js 模块考虑到关键帧动画的节流问题,但和tween的接洽没有实现机制,因为之前没有接触过tween

马黑黑 发表于 2025-6-30 19:47

红影 发表于 2025-6-30 19:24
这个太奇妙了,刚开始还是圆环1的点朝圆环2跑,然后反过来跑,跑两次后达到均衡,就变成两边彼此跑了。这个 ...

一切是随机tween动画的结果:tween动画使用 for 循环为每一个参与动画的粒子设计,每一个粒子运行的时间是 5000 * Math.random() + 5000,最少5秒一个运行周期,最长10秒(几乎没有),以这样的时间差计算,一般会走两个来回才会均衡。

杨帆 发表于 2025-6-30 19:57

独特的景观,奇妙的效果,谢谢马老师精彩分享{:4_176:}

红影 发表于 2025-6-30 21:12

马黑黑 发表于 2025-6-30 19:42
最初的设计是走弧线。点太多,感觉把控不完美,放弃,换用现在的交叉换位方式。

天啊,那些点还能走弧线呢,这也太神奇了。

红影 发表于 2025-6-30 21:13

马黑黑 发表于 2025-6-30 19:44
这个有可能:tween有它的管理机制,3basic.js 模块考虑到关键帧动画的节流问题,但和tween的接洽没有实现 ...

是的,就是黑黑说的节流问题吧,估计这个也有的。{:4_187:}

红影 发表于 2025-6-30 21:14

马黑黑 发表于 2025-6-30 19:47
一切是随机tween动画的结果:tween动画使用 for 循环为每一个参与动画的粒子设计,每一个粒子运行的时间 ...

嗯嗯,正像黑黑说的,走了两个来回后才均衡的呢{:4_187:}

马黑黑 发表于 2025-6-30 21:33

红影 发表于 2025-6-30 21:14
嗯嗯,正像黑黑说的,走了两个来回后才均衡的呢

也可以一开始就均衡的,一切看怎么设计

马黑黑 发表于 2025-6-30 21:33

红影 发表于 2025-6-30 21:13
是的,就是黑黑说的节流问题吧,估计这个也有的。

对,tween是讲究节流的

马黑黑 发表于 2025-6-30 21:34

红影 发表于 2025-6-30 21:12
天啊,那些点还能走弧线呢,这也太神奇了。

tween动画走弧线难度较大,因为它是线性的

马黑黑 发表于 2025-6-30 21:34

杨帆 发表于 2025-6-30 19:57
独特的景观,奇妙的效果,谢谢马老师精彩分享

{:4_190:}

红影 发表于 2025-6-30 21:41

马黑黑 发表于 2025-6-30 21:33
也可以一开始就均衡的,一切看怎么设计

还是现在这样样子好,很神奇的感觉。

马黑黑 发表于 2025-6-30 21:41

红影 发表于 2025-6-30 21:41
还是现在这样样子好,很神奇的感觉。

还好

红影 发表于 2025-6-30 21:42

马黑黑 发表于 2025-6-30 21:33
对,tween是讲究节流的

所以不去看的时候它就不演示了。
页: [1] 2 3 4 5
查看完整版本: 元素能量之英雄主题