Row
<style>#tz { margin: 30px 0; left: calc(50% - 81px); transform: translateX(-50%); width: clamp(600px, 90vw, 1400px); height: auto; aspect-ratio: 16/9; background: #eee url('https://638183.freep.cn/638183/t24/w4/row.webp') no-repeat center/cover; box-shadow: 2px 2px 8px #000; display: grid; place-items: center; z-index: 1; position: relative; }
#btnFs { bottom: 20px; color: #eee; text-align: center; }
#btnFs:hover { color: red; }
#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=1328534807" autoplay loop></audio>
<video id="vid" src="https://bpic.588ku.com/video_listen/588ku_video/22/11/05/08/05/29/video6365a8c98c8e9.mp4" autoplay loop muted></video>
<div id="player" title="播放/暂停"></div>
</div>
<script type="module">
import * as THREE from 'https://638183.freep.cn/638183/3dev/build/three.module.min.js';
import { FS } from 'https://638183.freep.cn/638183/web/ku/FS.js';
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(45, tz.offsetWidth/tz.offsetHeight, 0.1, 1000);
camera.position.set(0, 0, 120);
const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setSize(tz.offsetWidth, tz.offsetHeight);
const clock = new THREE.Clock();
tz.appendChild(renderer.domElement);
const boxGeometry = new THREE.BoxGeometry(30, 20, 5, 16, 8, 4);
const ballGeometry = new THREE.SphereGeometry(10, 32, 32);
const pointsMaterial = new THREE.PointsMaterial({ color: 0x00eeff, size: 1.2 });
const box = new THREE.Points(boxGeometry, pointsMaterial);
const ball = new THREE.Points(ballGeometry, pointsMaterial);
box.rotateX(Math.PI / 4);
box.position.set(-60, 20, 0);
box.add(ball);
scene.add(box);
const isMess = (event) => {
const raycaster = new THREE.Raycaster();
const pointer = new THREE.Vector2();
let intersects = [];
pointer.x = (event.offsetX / tz.offsetWidth) * 2 - 1;
pointer.y = -(event.offsetY / tz.offsetHeight) * 2 + 1;
raycaster.setFromCamera(pointer, camera);
intersects = raycaster.intersectObjects(, true);
return intersects.length > 0;
}
tz.onmousemove = (e) => {
isMess(e)
? (tz.style.cursor = 'pointer', tz.title = '播放/暂停 Alt+X')
: (tz.style.cursor = 'default', tz.title = '');
};
tz.onclick = (e) => {
if (isMess(e)) player.click();
};
const animate = () => {
requestAnimationFrame(animate);
const delta = clock.getDelta();
box.rotation.y -= delta;
renderer.render(scene, camera);
};
window.onresize = () => {
camera.aspect = tz.offsetWidth / tz.offsetHeight;
camera.updateProjectionMatrix();
renderer.setSize(tz.offsetWidth, tz.offsetHeight);
};
document.onvisibilitychange = () => {
if (aud.paused) return;
document.visibilityState === 'hidden' ? clock.stop() : clock.start();
};
aud.onplaying = aud.onpause = () => aud.paused ? clock.stop() : clock.start();
animate();
FS(tz, player);
</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: #eee url('https://638183.freep.cn/638183/t24/w4/row.webp') no-repeat center/cover; box-shadow: 2px 2px 8px #000; display: grid; place-items: center; z-index: 1; position: relative; }
#btnFs { bottom: 20px; color: #eee; text-align: center; }
#btnFs:hover { color: red; }
#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=1328534807" autoplay loop></audio>
<video id="vid" src="https://bpic.588ku.com/video_listen/588ku_video/22/11/05/08/05/29/video6365a8c98c8e9.mp4" autoplay loop muted></video>
<div id="player" title="播放/暂停"></div>
</div>
<script type="module">
import * as THREE from 'https://638183.freep.cn/638183/3dev/build/three.module.min.js';
import { FS } from 'https://638183.freep.cn/638183/web/ku/FS.js';
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(45, tz.offsetWidth/tz.offsetHeight, 0.1, 1000);
camera.position.set(0, 0, 120);
const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setSize(tz.offsetWidth, tz.offsetHeight);
const clock = new THREE.Clock();
tz.appendChild(renderer.domElement);
const boxGeometry = new THREE.BoxGeometry(30, 20, 5, 16, 8, 4);
const ballGeometry = new THREE.SphereGeometry(10, 32, 32);
const pointsMaterial = new THREE.PointsMaterial({ color: 0x00eeff, size: 1.2 });
const box = new THREE.Points(boxGeometry, pointsMaterial);
const ball = new THREE.Points(ballGeometry, pointsMaterial);
box.rotateX(Math.PI / 4);
box.position.set(-60, 20, 0);
box.add(ball);
scene.add(box);
const isMess = (event) => {
const raycaster = new THREE.Raycaster();
const pointer = new THREE.Vector2();
let intersects = [];
pointer.x = (event.offsetX / tz.offsetWidth) * 2 - 1;
pointer.y = -(event.offsetY / tz.offsetHeight) * 2 + 1;
raycaster.setFromCamera(pointer, camera);
intersects = raycaster.intersectObjects(, true);
return intersects.length > 0;
}
tz.onmousemove = (e) => {
isMess(e)
? (tz.style.cursor = 'pointer', tz.title = '播放/暂停 Alt+X')
: (tz.style.cursor = 'default', tz.title = '');
};
tz.onclick = (e) => {
if (isMess(e)) player.click();
};
const animate = () => {
requestAnimationFrame(animate);
const delta = clock.getDelta();
box.rotation.y -= delta;
renderer.render(scene, camera);
};
window.onresize = () => {
camera.aspect = tz.offsetWidth / tz.offsetHeight;
camera.updateProjectionMatrix();
renderer.setSize(tz.offsetWidth, tz.offsetHeight);
};
document.onvisibilitychange = () => {
if (aud.paused) return;
document.visibilityState === 'hidden' ? clock.stop() : clock.start();
};
aud.onplaying = aud.onpause = () => aud.paused ? clock.stop() : clock.start();
animate();
FS(tz, player);
</script>
本帖最后由 马黑黑 于 2025-6-10 20:30 编辑
本帖主要是尝试点材质 THREE.PointsMaterial
该材质可以用于任何几何体(Geometry),它只渲染几何体的顶点。几何体的顶点,以立方体 BoxGeometry 为例,默认时是八个,但我们已经知道,几何体的面是可以有分段数的,一般分为宽高深三个方向的分段数,这种情形下,分段数的设置会形成几何体的面上的顶点,分段数越多顶点越密集,下面这行代码:
const boxGeometry = new THREE.BoxGeometry(30, 20, 5, 16, 8, 4);
立方体几何体在xyz上的长度距离分别为 30、20、5 个距离单位,16、8、4 则分别是在xyz上的分段数,这样立方体上的顶点就不止8个了,每一个面上都有其它的顶点存在。
当使用点材质 THREE.PointsMaterial 与任意几何体,它们都是以“点”的方式渲染几何体的顶点,面上的不渲染。所以,要设计一下“点”的大小,缺省默认是 1 ,“点”缺省默认的颜色是白色 0xffffff。
注意观察相机的位置设置:
camera.position.set(0, 0, 120);
在 Z轴 上距离单位为 120,比较大,所以几何体的长宽深设为 30、20、5,点材质 THREE.PointsMaterial 的 size 属性设为 1.2;若相机的 Z轴 上的距离单位改变,这些数据也应跟着改变。
帖子中,球体也是用相同的点材质 THREE.PointsMaterial ,球体只有横纵两个分段数(球体只有一个面),设为 32、32。
这个帖子应该是讲pointsMaterial的吧,看到通过设置,能让它勾勒出绘制的球体和立方体{:4_187:} 这场景设置很奇妙,视频使用也很相配呢{:4_187:} 红影 发表于 2025-6-10 19:52
这个帖子应该是讲pointsMaterial的吧,看到通过设置,能让它勾勒出绘制的球体和立方体
这是要准备解释的材质。家里? 红影 发表于 2025-6-10 19:53
这场景设置很奇妙,视频使用也很相配呢
那里的视频应有尽有 pointsMaterial这个全是矩阵小点,球体和长方体全用了它做材质。。。
长方体设了几个点,就控制了大小和形状。。球体三个数据可以控制球体大小和点点排列疏密。。 球体和长方体结合在一起的几何体做小播,直接点击小播控制播放暂停,
第五行#player的左位负一千没啥用的吧。。
反正小播不管到哪都可以控制动态 背景暗黑,有点哥特风的美感,场景宏大。。
视频运动轨迹和小播完美衔接。。。。飞扬的粒子灵动好看。。
音乐节奏感强,好听 花飞飞 发表于 2025-6-10 20:15
pointsMaterial这个全是矩阵小点,球体和长方体全用了它做材质。。。
长方体设了几个点,就控制了大小和形 ...
具体看三楼,刚刚写好 花飞飞 发表于 2025-6-10 20:18
球体和长方体结合在一起的几何体做小播,直接点击小播控制播放暂停,
第五行#player的左位负一千没啥用的 ...
就是不让它出现,它的点击动作由ThreeJS绘制的图像接管 花飞飞 发表于 2025-6-10 20:21
背景暗黑,有点哥特风的美感,场景宏大。。
视频运动轨迹和小播完美衔接。。。。飞扬的粒子灵动好看。。
...
{:4_191:} 马黑黑 发表于 2025-6-10 19:09
本帖主要是尝试点材质 THREE.PointsMaterial
该材质可以用于任何几何体(Geometry),它只渲染几何体的 ...
没看到说明之前就是盲猜。。
原来点的大小是1.2,颜色也是自己根据贴子背景设定的。
几何体的长宽深和相机的位置有关联,数据设定还是很巧妙的,需要多试几次才能不变形 花飞飞 发表于 2025-6-10 20:50
没看到说明之前就是盲猜。。
原来点的大小是1.2,颜色也是自己根据贴子背景设定的。
对,距离没有单位,文档也没有特别详细的说明,很多需要尝试 有益探索,奇特效果,视听盛宴,经典分享{:4_191:} 这个漂亮,有空学习一下{:4_204:} 朵拉 发表于 2025-6-10 22:22
这个漂亮,有空学习一下
{:4_191:} 杨帆 发表于 2025-6-10 22:09
有益探索,奇特效果,视听盛宴,经典分享
{:4_191:} 地狱还是天堂,{:4_203:}