马黑黑 发表于 2025-5-17 09:44

闪耀的回声

<style>
    #tz { --state: running; margin: 30px 0; left: calc(50% - 81px); transform: translateX(-50%); width: clamp(600px, 90vw, 1400px); min-height: 80vh; aspect-ratio: 16/9; background: url('https://638183.freep.cn/638183/t24/webp3/e.webp') no-repeat center/cover; box-shadow: 2px 2px 8px #000; display: grid; place-items: center; pointer-events: none; z-index: 1; position: relative; }
    #tz::after { position: absolute; content: ''; width: 200px; height: 200px; cursor: pointer; pointer-events: auto; }
    #btnFs { bottom: 20px; color: #eee; text-align: center; pointer-events: auto; }
    #btnFs:hover { color: red; }
    #vid {position: absolute; width: 100%; height: 100%; object-fit: cover; mask: radial-gradient(transparent 20%, red); -webkit-mask: radial-gradient(transparent 20%, red); }
</style>

<div id="tz" title="播放/暂停">
    <!-- Shining Echoes -->
    <audio id="aud" src="https://music.163.com/song/media/outer/url?id=26196237" autoplay loop></audio>
    <video id="vid" src="https://bpic.588ku.com/video_listen/588ku_video/23/09/25/19/38/24/video6511713048374.mp4" autoplay loop muted></video>
</div>

<script type="module">
    import * as THREE from 'https://638183.freep.cn/638183/web/ku/three.module.min.js';
    import { FS } from 'https://638183.freep.cn/638183/web/ku/fscreen.js';

    const scene = new THREE.Scene;
    const camera = new THREE.PerspectiveCamera(45, tz.offsetWidth / tz.offsetHeight, 0.1, 1000);
    camera.position.set(0, 0, 8);
    const clock = new THREE.Clock();
    const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
    renderer.setSize(tz.offsetWidth, tz.offsetHeight);
    tz.appendChild(renderer.domElement);

    const geometry = new THREE.SphereGeometry();
    const texture = new THREE.TextureLoader().load('https://638183.freep.cn/638183/Pic/2022/jzlcover.jpg');
    const material = new THREE.MeshBasicMaterial({ color: 0x00ffff, map: texture, transparent: true, opacity: 0.7, side: THREE.DoubleSide });
    const ball = new THREE.Mesh(geometry, material);
    scene.add(ball);
    scene.add(ball);

    const animate = () => {
      requestAnimationFrame(animate);
      const delta = clock.getDelta();
      ball.rotation.x += delta / 5;
      ball.rotation.y += delta / 5;
      renderer.render(scene, camera);
    };

    tz.onclick = (e) => {
      if (e.target.id !== 'tz') return;
      aud.paused ? aud.play() : aud.pause();
      aud.paused ? (vid.pause(), clock.stop()) : (vid.play(), clock.start());
    }

    window.onresize = () => {
      camera.aspect = tz.offsetWidth / tz.offsetHeight;
      camera.updateProjectionMatrix();
      renderer.setSize(tz.offsetWidth, tz.offsetHeight);
    }

    animate();
    FS(tz);
</script>

马黑黑 发表于 2025-5-17 09:44

帖子代码

<style>
    #tz { --state: running; margin: 30px 0; left: calc(50% - 81px); transform: translateX(-50%); width: clamp(600px, 90vw, 1400px); min-height: 80vh; aspect-ratio: 16/9; background: url('https://638183.freep.cn/638183/t24/webp3/e.webp') no-repeat center/cover; box-shadow: 2px 2px 8px #000; display: grid; place-items: center; pointer-events: none; z-index: 1; position: relative; }
    #tz::after { position: absolute; content: ''; width: 200px; height: 200px; cursor: pointer; pointer-events: auto; }
    #btnFs { bottom: 20px; color: #eee; text-align: center; pointer-events: auto; }
    #btnFs:hover { color: red; }
    #vid {position: absolute; width: 100%; height: 100%; object-fit: cover; mask: radial-gradient(transparent 20%, red); -webkit-mask: radial-gradient(transparent 20%, red); }
</style>

<div id="tz" title="播放/暂停">
    <!-- Shining Echoes -->
    <audio id="aud" src="https://music.163.com/song/media/outer/url?id=26196237" autoplay loop></audio>
    <video id="vid" src="https://bpic.588ku.com/video_listen/588ku_video/23/09/25/19/38/24/video6511713048374.mp4" autoplay loop muted></video>
</div>

<script type="module">
    import * as THREE from 'https://638183.freep.cn/638183/web/ku/three.module.min.js';
    import { FS } from 'https://638183.freep.cn/638183/web/ku/fscreen.js';

    const scene = new THREE.Scene;
    const camera = new THREE.PerspectiveCamera(45, tz.offsetWidth / tz.offsetHeight, 0.1, 1000);
    camera.position.set(0, 0, 8);
    const clock = new THREE.Clock();
    const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
    renderer.setSize(tz.offsetWidth, tz.offsetHeight);
    tz.appendChild(renderer.domElement);

    const geometry = new THREE.SphereGeometry();
    const texture = new THREE.TextureLoader().load('https://638183.freep.cn/638183/Pic/2022/jzlcover.jpg');
    const material = new THREE.MeshBasicMaterial({ color: 0x00ffff, map: texture, transparent: true, opacity: 0.7, side: THREE.DoubleSide });
    const ball = new THREE.Mesh(geometry, material);
    scene.add(ball);
    scene.add(ball);

    const animate = () => {
      requestAnimationFrame(animate);
      const delta = clock.getDelta();
      ball.rotation.x += delta / 5;
      ball.rotation.y += delta / 5;
      renderer.render(scene, camera);
    };

    tz.onclick = (e) => {
      if (e.target.id !== 'tz') return;
      aud.paused ? aud.play() : aud.pause();
      aud.paused ? (vid.pause(), clock.stop()) : (vid.play(), clock.start());
    }

    window.onresize = () => {
      camera.aspect = tz.offsetWidth / tz.offsetHeight;
      camera.updateProjectionMatrix();
      renderer.setSize(tz.offsetWidth, tz.offsetHeight);
    }

    animate();
    FS(tz);
</script>

马黑黑 发表于 2025-5-17 10:01

帖子的音频控制并非通过 three.js 的图像对象的点击操作,而是帖子容器的伪元素:帖子容器定位所有包含其伪元素在内的子元素绝对居中,球体也刚好画在中央;帖子容器不可点击,伪元素、全屏按钮开放点击功能。

立体球体使用了纹理贴图,设置一定透明度。更多球体几何体的介绍请参阅 three.js几何体之球缓冲几何体 - 马黑黑教程专版 - 花潮论坛 - Powered by Discuz! 或网上更丰富、准确的相关资料,例如 three.js中文网。

音频联动控制方面,本帖采用及其简单的方式,帖子的点击操作,联合控制音频、视频、three.js 动画。球体动画通过 three.js 的 Clock 对象进行间接管理——当不需要计算 Clock 相关数据时,这个方法简单有效。Clock 对象还直接驱动动画的运行,其所提供的 getDelta() 方法能让动画的运行和 requestAnimationFrame 的频率更接近客户设备的分辨率,动画可能更为丝滑流畅。


three.js 适应窗口也较此前的作品做了一些改进,即对相机做相关设置,使其适应性更强,窗口的尺寸变化因此保持稳定的宽高比例。

小九 发表于 2025-5-17 11:08

这个画面很炫,等大家做出作品出来,效果应该会更炸裂。{:4_199:}

马黑黑 发表于 2025-5-17 11:10

小九 发表于 2025-5-17 11:08
这个画面很炫,等大家做出作品出来,效果应该会更炸裂。

{:4_191:}

红影 发表于 2025-5-17 11:14

这个球面贴纸有意思,把个球球弄得那么玄妙。{:4_199:}
好像用来贴球球的图图再宽点更好,感觉少了一条{:4_173:}

红影 发表于 2025-5-17 11:15

又是讲解后紧跟着的实例呢,黑黑太厉害了,这么快,构思也这么奇妙{:4_199:}

马黑黑 发表于 2025-5-17 11:24

红影 发表于 2025-5-17 11:14
这个球面贴纸有意思,把个球球弄得那么玄妙。
好像用来贴球球的图图再宽点更好,感觉少了一条{:4 ...
太对称了就像灯笼了

马黑黑 发表于 2025-5-17 11:24

红影 发表于 2025-5-17 11:15
又是讲解后紧跟着的实例呢,黑黑太厉害了,这么快,构思也这么奇妙

{:4_173:}

朵拉 发表于 2025-5-17 11:32

画面 音乐,震撼耶{:4_178:}

朵拉 发表于 2025-5-17 11:33

水印有些凸显,如何遮挡{:4_190:}

梦江南 发表于 2025-5-17 14:24

太震撼了!{:4_187:}

杨帆 发表于 2025-5-17 16:11

震撼的效果,细致的解读,到位的示范,为马老师点赞{:4_191:}

花飞飞 发表于 2025-5-17 18:04

进来被音乐和画面震撼到了 ,球体效果与刚看到的不同。。
不一样的纹理,有不同的效果
我刚跟了个海底的图,一会发出来{:4_173:}

花飞飞 发表于 2025-5-17 18:08

这个是点击球体可以停止,没有别的小播来控制。是设置了点击区域和球体重合实现的
跟木头点击停止的效果又不相同。
这是两种不同方法达到控动效果。。{:4_199:}

马黑黑 发表于 2025-5-17 18:27

花飞飞 发表于 2025-5-17 18:08
这个是点击球体可以停止,没有别的小播来控制。是设置了点击区域和球体重合实现的
跟木头点击停止的效果又 ...

站立的改了方式,更好

马黑黑 发表于 2025-5-17 18:28

花飞飞 发表于 2025-5-17 18:04
进来被音乐和画面震撼到了 ,球体效果与刚看到的不同。。
不一样的纹理,有不同的效果
我刚跟了个海底的 ...

{:4_191:}

花飞飞 发表于 2025-5-17 18:32

马黑黑 发表于 2025-5-17 18:27
站立的改了方式,更好

就是越来越先进。。越写越好

花飞飞 发表于 2025-5-17 18:36

马黑黑 发表于 2025-5-17 18:28

发出来了,我用的图看上去把球体变了个形状{:4_173:}

马黑黑 发表于 2025-5-17 18:42

花飞飞 发表于 2025-5-17 18:36
发出来了,我用的图看上去把球体变了个形状

这有可能
页: [1] 2 3
查看完整版本: 闪耀的回声