三亩地·寻
本帖最后由 马黑黑 于 2025-6-24 08:10 编辑 <br /><br /><style>#tz { margin: 30px 0; left: calc(50% - 81px); transform: translateX(-50%);width: clamp(600px, 90vw, 1400px); height: auto; aspect-ratio: 16/9; background: url('https://638183.freep.cn/638183/t24/w4/xy.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: #eee; }
#player { position: absolute; left: -1000px; }
#vid {position: absolute; width: 100%; height: 100%; object-fit: cover; mask: radial-gradient(transparent 20%, red); -webkit-mask: radial-gradient(transparent 20%, red); pointer-events: none; }
</style>
<div id="tz">
<audio id="aud" src="https://music.163.com/song/media/outer/url?id=31445474" autoplay loop></audio>
<video id="vid" src="https://bpic.588ku.com/video_listen/588ku_video/22/11/05/18/16/40/video63663808aba6e.mp4" autoplay loop muted></video>
<div id="player"></div>
</div>
<script type="module">
import { THREE, scene, camera, renderer, clock, basic3, click3 } from 'https://638183.freep.cn/638183/3dev/3/3basic.js';
import { FS } from 'https://638183.freep.cn/638183/web/ku/FS.js';
FS(tz, player);
basic3(tz);
const group = new THREE.Group(), sGroup = new THREE.Group;
const tt = 40, poses = [ , [-2, 0, 0], , , ];
// 圆环
for (let i = 0; i < tt; i ++) {
const ellipse = drawEllipse(1.2, 0.8);
ellipse.rotateY(THREE.MathUtils.degToRad(360 / tt * i));
group.add(ellipse);
}
// 球
poses.forEach( (pos, key) => {
const texture = new THREE.TextureLoader().load('https://638183.freep.cn/638183/small/texture/wdrop.jpg');
texture.colorSpace = THREE.SRGBColorSpace;
const mesh = new THREE.Mesh(
new THREE.SphereGeometry(0.25),
new THREE.MeshBasicMaterial({ map: texture })
);
mesh.position.set(pos, pos, pos);
if (key === 0) mesh.scale.set(2, 2, 2);
sGroup.add(mesh);
});
sGroup.rotateX(-0.15);
group.add(sGroup);
scene.add(group);
animate();
aud.onplaying = aud.onpause = () => aud.paused ? clock.stop() : clock.start();
tz.onclick = (e) => { if (click3(group, e)) player.click() };
tz.onmousemove = (e) => {
tz.title = click3(group, e) ? '播放/暂停' : '';
tz.style.cursor = click3(group, e) ? 'pointer' : 'default';
}
// 绘制圆环函数
function drawEllipse(r1, r2) {
const curve = new THREE.EllipseCurve(0, 0, r1, r2, 0, 2 * Math.PI, false, 0);
const arc = new THREE.Line(
new THREE.BufferGeometry().setFromPoints( curve.getPoints(50) ),
new THREE.LineDashedMaterial( { color: 0xffffff * Math.random(), dashSize: 0.02, gapSize: 0.02 } )
);
arc.computeLineDistances(); // 显示虚线必须计算线距
return arc;
}
function animate() {
requestAnimationFrame(animate);
const delta = clock.getDelta();
group.rotation.y += delta / 5;
sGroup.children.forEach(child => child.rotation.y += delta);
renderer.render(scene, camera);
}
</script> 帖子代码
<style>
#tz { margin: 30px 0; left: calc(50% - 81px); transform: translateX(-50%);width: clamp(600px, 90vw, 1400px); height: auto; aspect-ratio: 16/9; background: url('https://638183.freep.cn/638183/t24/w4/xy.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: #eee; }
#player { position: absolute; left: -1000px; }
#vid {position: absolute; width: 100%; height: 100%; object-fit: cover; mask: radial-gradient(transparent 20%, red); -webkit-mask: radial-gradient(transparent 20%, red); pointer-events: none; }
</style>
<div id="tz">
<audio id="aud" src="https://music.163.com/song/media/outer/url?id=31445474" autoplay loop></audio>
<video id="vid" src="https://bpic.588ku.com/video_listen/588ku_video/22/11/05/18/16/40/video63663808aba6e.mp4" autoplay loop muted></video>
<div id="player"></div>
</div>
<script type="module">
import { THREE, scene, camera, renderer, clock, basic3, click3 } from 'https://638183.freep.cn/638183/3dev/3/3basic.js';
import { FS } from 'https://638183.freep.cn/638183/web/ku/FS.js';
FS(tz, player);
basic3(tz);
const group = new THREE.Group(), sGroup = new THREE.Group;
const tt = 40, poses = [ , [-2, 0, 0], , , ];
// 圆环
for (let i = 0; i < tt; i ++) {
const ellipse = drawEllipse(1.2, 0.8);
ellipse.rotateY(THREE.MathUtils.degToRad(360 / tt * i));
group.add(ellipse);
}
// 球
poses.forEach( (pos, key) => {
const texture = new THREE.TextureLoader().load('https://638183.freep.cn/638183/small/texture/wdrop.jpg');
texture.colorSpace = THREE.SRGBColorSpace;
const mesh = new THREE.Mesh(
new THREE.SphereGeometry(0.25),
new THREE.MeshBasicMaterial({ map: texture })
);
mesh.position.set(pos, pos, pos);
if (key === 0) mesh.scale.set(2, 2, 2);
sGroup.add(mesh);
});
sGroup.rotateX(-0.15);
group.add(sGroup);
scene.add(group);
animate();
aud.onplaying = aud.onpause = () => aud.paused ? clock.stop() : clock.start();
tz.onclick = (e) => { if (click3(group, e)) player.click() };
tz.onmousemove = (e) => {
tz.title = click3(group, e) ? '播放/暂停' : '';
tz.style.cursor = click3(group, e) ? 'pointer' : 'default';
}
// 绘制圆环函数
function drawEllipse(r1, r2) {
const curve = new THREE.EllipseCurve(0, 0, r1, r2, 0, 2 * Math.PI, false, 0);
const arc = new THREE.Line(
new THREE.BufferGeometry().setFromPoints( curve.getPoints(50) ),
new THREE.LineDashedMaterial( { color: 0xffffff * Math.random(), dashSize: 0.02, gapSize: 0.02 } )
);
arc.computeLineDistances(); // 显示虚线必须计算线距
return arc;
}
function animate() {
requestAnimationFrame(animate);
const delta = clock.getDelta();
group.rotation.y += delta / 5;
sGroup.children.forEach(child => child.rotation.y += delta);
renderer.render(scene, camera);
}
</script>
本帖最后由 马黑黑 于 2025-6-24 08:30 编辑
ThreeJS部分解释:
虚线圆环共 40 个,通过旋转组成球体。圆环使用 ElliesCurve 即椭圆曲线构建,参数1、2为椭圆圆心XY坐标,参数3为 rx 半径、参数4为 ry 半径,参数6值为 2 * Math.PI 时将是封闭的椭圆,而当 rx=ry,所创建的将是正圆(本帖画的是椭圆)。材质使用 LineDashMaterial 虚线材质,设置好虚线尺寸、虚线间距,最后还要计算线距。为方便复用,绘制圆环工作放在函数 drawEllipse(r1,r2),所需参数对应椭圆的 rx、ry,代码在 57~66 行,具体绘制和构图代码在 22~28 行。
圆环放入 group 组。
圆球5个,放入 sGroup 组。圆球绘制前事先设计一个3d位置数组,再根据数组绘制数组长度个圆球并按数组元素的数据各归其位,第一个圆球放大两倍。
sGroup 组存入 group 组,这样,71 行的动画指令对 sGroup 圆球组同样产生作用,因为它们是父子关系,group 为父,sGroup 为子,子对象随父对象运动——这和 HTML 关键帧动画理念是延承的。 前面的没记住,又要回去看看那个线性的椭圆和做法和球体的做法了{:4_173:} 这个还挺复杂,40条圆环的绘制在动画设置时还要重新考虑。 制作很漂亮,这样的背景加独特的视频,营造了很迷幻的效果。
那个球体上的贴纸有变形呢,变形却恰恰带来了奇妙的效果{:4_199:} 欣赏老师的精彩制作。祝夏安! 马黑黑 发表于 2025-6-24 08:28
ThreeJS部分解释:
虚线圆环共 40 个,通过旋转组成球体。圆环使用 ElliesCurve 即椭圆曲线构建,参数1 ...
原来圆环是父,圆球是子{:4_173:} 高科技,精彩{:4_178:} 感谢老师经典讲授,谢谢老师精彩示范,为马老师点赞{:4_191:} 杨帆 发表于 2025-6-24 11:46
感谢老师经典讲授,谢谢老师精彩示范,为马老师点赞
{:4_191:} 朵拉 发表于 2025-6-24 10:02
高科技,精彩
{:4_190:} 红影 发表于 2025-6-24 08:46
原来圆环是父,圆球是子
ThreeJS网格(Mess)对象可以包含 梦江南 发表于 2025-6-24 08:39
欣赏老师的精彩制作。祝夏安!
{:4_190:} 红影 发表于 2025-6-24 08:38
制作很漂亮,这样的背景加独特的视频,营造了很迷幻的效果。
那个球体上的贴纸有变形呢,变形却恰恰带来了 ...
矩形上的平面图像,除非专门为圆球设计,否则贴上去后都会变形 红影 发表于 2025-6-24 08:36
这个还挺复杂,40条圆环的绘制在动画设置时还要重新考虑。
动画设置不考虑什么,动画是针对 group 组不针对圆环个体 红影 发表于 2025-6-24 08:34
前面的没记住,又要回去看看那个线性的椭圆和做法和球体的做法了
记不住查查资料,这是常规做法 马黑黑 发表于 2025-6-24 12:13
ThreeJS网格(Mess)对象可以包含
嗯嗯,把它们全包含进去了。 马黑黑 发表于 2025-6-24 12:14
矩形上的平面图像,除非专门为圆球设计,否则贴上去后都会变形
是的,除非那张地球图,是专门为球体设计的。
这里这个变形挺好的,很奇妙呢{:4_173:} 马黑黑 发表于 2025-6-24 12:15
动画设置不考虑什么,动画是针对 group 组不针对圆环个体
嗯嗯,前面看的时候还没看到讲解资料,是自己在盲猜中{:4_173:}