three.js : 与音频联动的球体动画
本帖最后由 马黑黑 于 2025-5-10 19:25 编辑 <br /><br /><style>#btnPrev { box-shadow: 2px 2px 6px rgba(0,0,0,.5); }
#btnPrev:hover { box-shadow: 2px 2px 12px rgba(0,0,0,.5); font-weight: bold; }
</style>
<div id="hEdiv"><pre id="hEpre">
<audio id="aud" src="https://music.163.com/song/media/outer/url?id=1464843172" autoplay loop controls></audio>
<script type="module">
import * as THREE from 'https://esm.sh/three';
import { OrbitControls } from "https://esm.sh/three/examples/jsm/controls/OrbitControls";
let rotRaf, isPaused = true;
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 20;
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
const geometry = new THREE.SphereGeometry(2, 32, 32, 0, 2 * Math.PI, 0, 2 * Math.PI);
for (let i = 0; i <= 8; i++) {
const material = new THREE.MeshNormalMaterial({
transparent: true,
opacity: 0.6,
side: THREE.DoubleSide
});
const ball = new THREE.Mesh(geometry, material);
const radian = (360 / 8) * (Math.PI / 180);
if (i < 8) ball.position.set(8 * Math.sin(radian * i), 8 * Math.cos(radian * i), 0);
scene.add(ball);
}
const controls = new OrbitControls(camera, renderer.domElement);
controls.enablePan = true;
controls.maxPolarAngle = 1.5;
controls.minPolarAngle = 0.0;
controls.autoRotate = true;
controls.dampingFactor = 0.5;
isPaused = aud.paused;
const mState = () => {
isPaused = aud.paused;
aud.paused ? cancelAnimationFrame(rotRaf) : rotating();
};
const rotating = () => {
if (isPaused ) return;
controls.update();
renderer.render(scene, camera);
rotRaf = requestAnimationFrame(rotating);
};
aud.onplaying = aud.onpause = () => mState();
aud.onseeked = () => cancelAnimationFrame(rotRaf);
rotating();
</script>
<style>
body { margin: 0; }
audio { position: absolute; bottom: 20px; right: 20px; }
</style>
</pre></div>
<blockquote><button id="btnPrev">运行代码</button></button></blockquote>
<script type="module">
import hlight from 'https://638183.freep.cn/638183/web/helight/helight1.js';
hlight.hl(hEdiv, hEpre);
btnPrev.onclick = () => {
const value = hEpre.textContent;
const previewWindow = window.open('', 'preview1', 'width=1200,height=768,top=100,left=100');
previewWindow.document.open();
previewWindow.document.write(value);
setTimeout(function() { previewWindow.document.title = "预览" }, 100);
previewWindow.document.close();
};
</script> 本帖最后由 马黑黑 于 2025-5-10 17:50 编辑
本帖,在 three.js : 画球 - 马黑黑教程专版 - 花潮论坛 - Powered by Discuz! 第二个示例基础加入一些其它元素,比如音频、three.js 的 OrbitControls 对象(相机控件,用于控制相机)。
设置好相关 OrbitControls 控件参数,尤其是 autoRotate,就能启用相机绕场景旋转,但仅是启用,要真正实现旋转,还得在动画部分更新(update)。一楼代码中,我们将 OrbitControls 实例化 为 controls,所以,rotating 动画函数中使用 controls.update() 来真正启动相机的旋转。
注意,相机的旋转是绕场景 scene 进行的,观者看到的则是场景中 3d对象 的旋转。
音频联动方面,首先设置一个函数 mState,它根据 audio 音频控件的暂停与否来决定控制three动画开关 isPaused 的布尔值,并直接参与动画播放暂停的管控。其中的 rotRaf 变量用于管理 requestAnimationFrame(请求关键帧动画);其次,监听 audio 音频控件的 pause 和 playing 两个事件,用以联动管理动画。
请求关键帧动画必须做好管理,否则会出现一些意外,比如动画无法运行或运行的越来越快,变量 rotRaf 的赋值与注销因此至关重要。
9个球体自身没有任何动画,但给人的感觉是它们也在不停地旋转。原理:球体使用了双面渲染,side: THREE.DoubleSide,就会出现球面上的“斑块”,由于相对密集,相机在旋转的时候在这些斑块上掠过,造成球体旋转的错觉。
{:4_173:}
刚看到这神奇的效果,过来看看说明。。。
我的天,它本身没有转的么,从看到的第一眼就觉得它在自转 本帖最后由 花飞飞 于 2025-5-10 18:23 编辑
两边的 计算还是有所不同的,粒子数量都是8,这里显示的是9个。
整体合在一起旋转,还要透视各方面都对得上,3D效果功能强大
旋转之前立方体里出现过,最近这个THREE出现好多新的名词,虽然每次看都是满头黑线,看不懂
但效果足够炫酷。。
现在音乐也能够一起联动了,是不是不久就可以看到新效果的实例贴子了。{:4_173:} 花飞飞 发表于 2025-5-10 18:03
刚看到这神奇的效果,过来看看说明。。。
我的天,它本身没有转的么,从看到的第一眼就觉得它 ...
心甘情愿的错觉{:4_170:} 本帖最后由 马黑黑 于 2025-5-10 18:43 编辑
花飞飞 发表于 2025-5-10 18:21
两边的 计算还是有所不同的,粒子数量都是8,这里显示的是9个。
整体合在一起旋转,还要透视各方面都对得 ...
那个for语句你看看, 小于,小于等于 马黑黑 发表于 2025-5-10 18:37
心甘情愿的错觉
利用错觉可以出许多精美效果
没办法,你选用的材质太{:4_173:}亮眼,头一回见 花飞飞 发表于 2025-5-10 18:30
旋转之前立方体里出现过,最近这个THREE出现好多新的名词,虽然每次看都是满头黑线,看不懂
但效果足够炫 ...
这是两种不同形式的旋转:之前的是立方体绕自己的中心旋转,现在这个是相机绕场景旋转 花飞飞 发表于 2025-5-10 18:30
旋转之前立方体里出现过,最近这个THREE出现好多新的名词,虽然每次看都是满头黑线,看不懂
但效果足够炫 ...
现在你都可以做到帖子里面去了 花飞飞 发表于 2025-5-10 18:44
利用错觉可以出许多精美效果
没办法,你选用的材质太亮眼,头一回见
{:4_191:} 马黑黑 发表于 2025-5-10 18:39
那个for语句你看看, 小于,小于等于
{:4_170:}看了。。知道算的方法不同。。
最近这3D画儿跟星球一样不好懂 马黑黑 发表于 2025-5-10 18:44
这是两种不同形式的旋转:之前的是立方体绕自己的中心旋转,现在这个是相机绕场景旋转
{:4_173:}原来有这样的区别
这个可以理解,像是舞台上人在唱歌,摄像大哥拿着机器围着歌手绕转,出来的效果就特写中的特写 马黑黑 发表于 2025-5-10 18:44
现在你都可以做到帖子里面去了
加个背景就成了{:4_173:}但还是想看你做的效果 马黑黑 发表于 2025-5-10 18:45
喝得晕乎乎的一会 花飞飞 发表于 2025-5-10 18:52
喝得晕乎乎的一会
挺好挺好 花飞飞 发表于 2025-5-10 18:51
加个背景就成了但还是想看你做的效果
暂时不做 花飞飞 发表于 2025-5-10 18:50
原来有这样的区别
这个可以理解,像是舞台上人在唱歌,摄像大哥拿着机器围着歌手绕转,出来的 ...
对对对,就是这个意思 马黑黑 发表于 2025-5-10 19:26
挺好挺好
{:4_181:}来看看怎么个好法 马黑黑 发表于 2025-5-10 19:26
暂时不做
好在是暂时的{:4_170:}