马黑黑 发表于 2025-7-1 20:21

History Repeating

<style>
    #papa { margin: 30px 0; left: calc(50% - 81px); transform: translateX(-50%);width: clamp(600px, 90vw, 1400px); height: auto; aspect-ratio: 16/9; background: snow url('https://638183.freep.cn/638183/t24/w4/galaxy.webp') no-repeat center/cover; 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: 10vw; height: 10vw; border-radius: 50%; filter: drop-shadow(0 0 80px #000) opacity(0.5); cursor: pointer; z-index: 2; animation: rot 8s linear infinite var(--state); }
    #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; }
    @keyframes rot { to { transform: rotate(360deg); } }
</style>

<div id="papa">
    <audio id="aud" src="https://music.163.com/song/media/outer/url?id=1971315292" autoplay loop></audio>
    <video id="vid" src="https://bpic.588ku.com/video_listen/588ku_video/25/03/24/13/59/29/video67e0f4c17e4d2.mp4" autoplay loop muted></video>
    <img id="player" src="https://638183.freep.cn/638183/small/2025/b3.webp" title="播放/暂停" alt="" />
</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 texture = new THREE.TextureLoader().load(`data:image/svg+xml;charset=utf-8, <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 32 32"><circle cx="16" cy="16" r="14" fill="white"/></svg>`);
    texture.colorSpace = THREE.SRGBColorSpace;
    texture.center.set(0.5,0.5);

    const geometry1 = new THREE.SphereGeometry(0.5, 32, 32); // 几何体1
    geometry1.translate(-1.5, -1, 0);
    geometry1.rotateX(Math.PI / 6);
    const geometry2 = new THREE.SphereGeometry(0.5, 32, 32); // 几何体2
    geometry2.translate(1.5, 1, 1);
    geometry2.rotateX(-Math.PI / 6);
    const startPositions = geometry1.attributes.position;
    const endPositions = geometry2.attributes.position;
    const pointsGeometry = new THREE.BufferGeometry();
    pointsGeometry.setAttribute('position', startPositions);
    const pointsMaterial = new THREE.PointsMaterial({ map: texture, size: 0.1, transparent: true });
    const points = new THREE.Points(pointsGeometry, pointsMaterial);
    scene.add(points);

    const total = startPositions.count;
    for(let i = 0; i < total; i++) {
      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();
      points.rotation.z += delta / 5;
      points.rotation.y += 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-7-1 20:21

帖子代码

<style>
    #papa { margin: 30px 0; left: calc(50% - 81px); transform: translateX(-50%);width: clamp(600px, 90vw, 1400px); height: auto; aspect-ratio: 16/9; background: snow url('https://638183.freep.cn/638183/t24/w4/galaxy.webp') no-repeat center/cover; 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: 10vw; height: 10vw; border-radius: 50%; filter: drop-shadow(0 0 80px #000) opacity(0.5); cursor: pointer; z-index: 2; animation: rot 8s linear infinite var(--state); }
    #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; }
    @keyframes rot { to { transform: rotate(360deg); } }
</style>

<div id="papa">
    <audio id="aud" src="https://music.163.com/song/media/outer/url?id=1971315292" autoplay loop></audio>
    <video id="vid" src="https://bpic.588ku.com/video_listen/588ku_video/25/03/24/13/59/29/video67e0f4c17e4d2.mp4" autoplay loop muted></video>
    <img id="player" src="https://638183.freep.cn/638183/small/2025/b3.webp" title="播放/暂停" alt="" />
</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 texture = new THREE.TextureLoader().load(`data:image/svg+xml;charset=utf-8, <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 32 32"><circle cx="16" cy="16" r="14" fill="white"/></svg>`);
    texture.colorSpace = THREE.SRGBColorSpace;
    texture.center.set(0.5,0.5);

    const geometry1 = new THREE.SphereGeometry(0.5, 32, 32); // 几何体1
    geometry1.translate(-1.5, -1, 0);
    geometry1.rotateX(Math.PI / 6);
    const geometry2 = new THREE.SphereGeometry(0.5, 32, 32); // 几何体2
    geometry2.translate(1.5, 1, 1);
    geometry2.rotateX(-Math.PI / 6);
    const startPositions = geometry1.attributes.position;
    const endPositions = geometry2.attributes.position;
    const pointsGeometry = new THREE.BufferGeometry();
    pointsGeometry.setAttribute('position', startPositions);
    const pointsMaterial = new THREE.PointsMaterial({ map: texture, size: 0.1, transparent: true });
    const points = new THREE.Points(pointsGeometry, pointsMaterial);
    scene.add(points);

    const total = startPositions.count;
    for(let i = 0; i < total; i++) {
      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();
      points.rotation.z += delta / 5;
      points.rotation.y += 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-7-1 20:21

本帖最后由 马黑黑 于 2025-7-1 20:35 编辑

历史是今天对昨天的重复,但不是简单的重复。

帖子也差不多:总有一点点变革。

本帖:

一、使用了SVG做粒子的纹理贴图。很简单,在SVG里画一个圆,然后将SVG弄成 base64 编码数据的图片,然后加载为纹理;

二、为了能让几何体加载纹理摆脱矩形模样,得创建一个缓冲几何体 Buffergeometry,并将从ThreeJS内置几何体之一获得的顶点数据赋予它,酱紫点云材质就具备了纹理的圆形形状;

三、缓冲几何体+点云材质构建的图像在 z、y 轴上的旋转,点云的点做tween运动,运动形式华丽丽;

四、播放器回归HTML元素,它设置一定的透明度,酱紫,点云粒子好像穿过它而在两地间交换。

泡沫 发表于 2025-7-1 20:27

占一楼等个说明先{:4_173:}

泡沫 发表于 2025-7-1 20:29

昨天的圆环能量输送的基础上加了个整体旋转运动{:4_199:}
叠加运动越来越熟练了。。

泡沫 发表于 2025-7-1 20:35

球体粒子似乎比昨天的更密集一些。
粒子形状由方形变成了圆形。。。更漂亮了。。。
这次没有跳过哪些粒子点,全部进行交流。。{:4_173:}

马黑黑 发表于 2025-7-1 20:37

泡沫 发表于 2025-7-1 20:35
球体粒子似乎比昨天的更密集一些。
粒子形状由方形变成了圆形。。。更漂亮了。。。
这次没有跳过哪些粒子 ...

粒子数量取决于分段数:分段数越多顶点数就越多。不同的几何体分段数设置不一样,昨天的帖子是圆环几何体,今天的是圆球几何体。

马黑黑 发表于 2025-7-1 20:37

泡沫 发表于 2025-7-1 20:29
昨天的圆环能量输送的基础上加了个整体旋转运动
叠加运动越来越熟练了。。

这个本来不复杂

泡沫 发表于 2025-7-1 20:40

马黑黑 发表于 2025-7-1 20:21
历史是今天对昨天的重复,但不是简单的重复。

帖子也差不多:总有一点点变革。


原来由矩形变圆形还有这么多步骤和思路才能完成。。
赞。。
刚看到http://www.w3.org/2000/svg,点又点不开,是不是你说的SVG弄成 base64 编码数据的图片{:4_173:}

泡沫 发表于 2025-7-1 20:43

马黑黑 发表于 2025-7-1 20:37
粒子数量取决于分段数:分段数越多顶点数就越多。不同的几何体分段数设置不一样,昨天的帖子是圆环几何体 ...

这个分段数记得学过,半个月没看又陌生了,看来还要回去啃教程去。。。{:4_173:}
密集或者也因为是粒子的点设的比较大一点

泡沫 发表于 2025-7-1 20:44

马黑黑 发表于 2025-7-1 20:37
这个本来不复杂

你这么一天天更新迭代,一{:4_173:}步步加上去,按顺序看就容易看出区别

泡沫 发表于 2025-7-1 20:46

小播透明还有穿越内部空间的效果。。。这个构思也是金点子。{:4_199:}

马黑黑 发表于 2025-7-1 20:46

泡沫 发表于 2025-7-1 20:46
小播透明还有穿越内部空间的效果。。。这个构思也是金点子。

小播一定透明度设置过去常用呀

马黑黑 发表于 2025-7-1 20:47

泡沫 发表于 2025-7-1 20:44
你这么一天天更新迭代,一步步加上去,按顺序看就容易看出区别

{:4_190:}

马黑黑 发表于 2025-7-1 20:48

泡沫 发表于 2025-7-1 20:43
这个分段数记得学过,半个月没看又陌生了,看来还要回去啃教程去。。。
密集或者也因为是粒子 ...

也可以想一想几何体的尺寸:尺寸小了,点的密集度就显得强烈

红影 发表于 2025-7-1 20:49

两个球之间做着粒子交换,同时做着空间的旋转。运动中套着运动,这个太漂亮了。{:4_199:}

马黑黑 发表于 2025-7-1 20:49

泡沫 发表于 2025-7-1 20:40
原来由矩形变圆形还有这么多步骤和思路才能完成。。
赞。。
刚看到http://www.w3.org/2000/svg,点又点 ...

SVG的语法规范里头,需要有那个地址,那个地址是凭证。打开打不开没关系,有了就合法,就能存为图片。base64编码图片没有实体图片,它就是图片。

马黑黑 发表于 2025-7-1 20:51

红影 发表于 2025-7-1 20:49
两个球之间做着粒子交换,同时做着空间的旋转。运动中套着运动,这个太漂亮了。

谢漂

红影 发表于 2025-7-1 20:52

粒子的颗粒感更强了,立体感也更强了呢。{:4_187:}
播放器回归HTML元素,但好像不是在粒子交换的当中?有点偏,可能视觉误差?

泡沫 发表于 2025-7-1 20:58

马黑黑 发表于 2025-7-1 20:46
小播一定透明度设置过去常用呀

以前没有粒子空间穿梭效果呀。。
以前透明度是为了跟背景融合,现在是透明度的另一种用法。
页: [1] 2 3 4 5 6
查看完整版本: History Repeating