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> 帖子代码
<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:35 编辑
历史是今天对昨天的重复,但不是简单的重复。
帖子也差不多:总有一点点变革。
本帖:
一、使用了SVG做粒子的纹理贴图。很简单,在SVG里画一个圆,然后将SVG弄成 base64 编码数据的图片,然后加载为纹理;
二、为了能让几何体加载纹理摆脱矩形模样,得创建一个缓冲几何体 Buffergeometry,并将从ThreeJS内置几何体之一获得的顶点数据赋予它,酱紫点云材质就具备了纹理的圆形形状;
三、缓冲几何体+点云材质构建的图像在 z、y 轴上的旋转,点云的点做tween运动,运动形式华丽丽;
四、播放器回归HTML元素,它设置一定的透明度,酱紫,点云粒子好像穿过它而在两地间交换。
占一楼等个说明先{:4_173:} 昨天的圆环能量输送的基础上加了个整体旋转运动{:4_199:}
叠加运动越来越熟练了。。 球体粒子似乎比昨天的更密集一些。
粒子形状由方形变成了圆形。。。更漂亮了。。。
这次没有跳过哪些粒子点,全部进行交流。。{:4_173:} 泡沫 发表于 2025-7-1 20:35
球体粒子似乎比昨天的更密集一些。
粒子形状由方形变成了圆形。。。更漂亮了。。。
这次没有跳过哪些粒子 ...
粒子数量取决于分段数:分段数越多顶点数就越多。不同的几何体分段数设置不一样,昨天的帖子是圆环几何体,今天的是圆球几何体。 泡沫 发表于 2025-7-1 20:29
昨天的圆环能量输送的基础上加了个整体旋转运动
叠加运动越来越熟练了。。
这个本来不复杂 马黑黑 发表于 2025-7-1 20:21
历史是今天对昨天的重复,但不是简单的重复。
帖子也差不多:总有一点点变革。
原来由矩形变圆形还有这么多步骤和思路才能完成。。
赞。。
刚看到http://www.w3.org/2000/svg,点又点不开,是不是你说的SVG弄成 base64 编码数据的图片{:4_173:} 马黑黑 发表于 2025-7-1 20:37
粒子数量取决于分段数:分段数越多顶点数就越多。不同的几何体分段数设置不一样,昨天的帖子是圆环几何体 ...
这个分段数记得学过,半个月没看又陌生了,看来还要回去啃教程去。。。{:4_173:}
密集或者也因为是粒子的点设的比较大一点 马黑黑 发表于 2025-7-1 20:37
这个本来不复杂
你这么一天天更新迭代,一{:4_173:}步步加上去,按顺序看就容易看出区别 小播透明还有穿越内部空间的效果。。。这个构思也是金点子。{:4_199:} 泡沫 发表于 2025-7-1 20:46
小播透明还有穿越内部空间的效果。。。这个构思也是金点子。
小播一定透明度设置过去常用呀 泡沫 发表于 2025-7-1 20:44
你这么一天天更新迭代,一步步加上去,按顺序看就容易看出区别
{:4_190:} 泡沫 发表于 2025-7-1 20:43
这个分段数记得学过,半个月没看又陌生了,看来还要回去啃教程去。。。
密集或者也因为是粒子 ...
也可以想一想几何体的尺寸:尺寸小了,点的密集度就显得强烈 两个球之间做着粒子交换,同时做着空间的旋转。运动中套着运动,这个太漂亮了。{:4_199:} 泡沫 发表于 2025-7-1 20:40
原来由矩形变圆形还有这么多步骤和思路才能完成。。
赞。。
刚看到http://www.w3.org/2000/svg,点又点 ...
SVG的语法规范里头,需要有那个地址,那个地址是凭证。打开打不开没关系,有了就合法,就能存为图片。base64编码图片没有实体图片,它就是图片。 红影 发表于 2025-7-1 20:49
两个球之间做着粒子交换,同时做着空间的旋转。运动中套着运动,这个太漂亮了。
谢漂 粒子的颗粒感更强了,立体感也更强了呢。{:4_187:}
播放器回归HTML元素,但好像不是在粒子交换的当中?有点偏,可能视觉误差? 马黑黑 发表于 2025-7-1 20:46
小播一定透明度设置过去常用呀
以前没有粒子空间穿梭效果呀。。
以前透明度是为了跟背景融合,现在是透明度的另一种用法。