はじめに
この記事はBabylon.js Advent Calendar 2024の12日目の記事です。
Babylon.jsを今知ったところですが、
とても便利そうなので、ChatGPT先生と一緒に試してみます。
Babylon.jsを知っているかChatGPT先生に聞いてみる。
早速プログラムを作ってもらう
index.html
<!DOCTYPE html>
<html>
<head>
<title>Flower Petal Dance</title>
<script src="https://cdn.babylonjs.com/babylon.js"></script>
</head>
<body>
<canvas id="renderCanvas" touch-action="none"></canvas>
<input type="file" id="fileInput" accept="audio/*" style="position: absolute; top: 10px; left: 10px; z-index: 1000;">
<script>
const canvas = document.getElementById("renderCanvas");
const engine = new BABYLON.Engine(canvas, true);
const scene = new BABYLON.Scene(engine);
const camera = new BABYLON.ArcRotateCamera("Camera", Math.PI / 2, Math.PI / 4, 20, BABYLON.Vector3.Zero(), scene);
camera.attachControl(canvas, true);
const light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(0, 1, 0), scene);
// 花びらの形状
const flowerPetal = BABYLON.MeshBuilder.CreateDisc("petal", { radius: 0.5, tessellation: 64 }, scene);
flowerPetal.rotation.x = Math.PI / 2;
// マテリアル
const petalMaterial = new BABYLON.StandardMaterial("petalMaterial", scene);
petalMaterial.diffuseColor = new BABYLON.Color3(1, 0.5, 0.5);
flowerPetal.material = petalMaterial;
// 花びらを大量に生成
const petals = [];
for (let i = 0; i < 100; i++) {
const petalInstance = flowerPetal.clone("petal" + i);
petalInstance.position = new BABYLON.Vector3(
Math.random() * 20 - 10,
Math.random() * 10,
Math.random() * 20 - 10
);
petals.push(petalInstance);
}
// 音楽の再生設定
const fileInput = document.getElementById("fileInput");
let audioContext = null;
let analyser = null;
let frequencyData = null;
fileInput.addEventListener("change", (event) => {
const file = event.target.files[0];
if (file) {
const audioElement = new Audio(URL.createObjectURL(file));
audioElement.crossOrigin = "anonymous"; // クロスオリジンの制限を回避
audioElement.play();
if (!audioContext) {
audioContext = new (window.AudioContext || window.webkitAudioContext)();
analyser = audioContext.createAnalyser();
analyser.fftSize = 256;
frequencyData = new Uint8Array(analyser.frequencyBinCount);
}
const source = audioContext.createMediaElementSource(audioElement);
source.connect(analyser);
analyser.connect(audioContext.destination);
}
});
// アニメーション
scene.registerBeforeRender(() => {
if (analyser && frequencyData) {
analyser.getByteFrequencyData(frequencyData);
const beatStrength = frequencyData[0] / 255; // 周波数データを正規化
petals.forEach(petal => {
petal.position.y += Math.sin(scene.getEngine().getDeltaTime() * 0.001 + Math.random()) * beatStrength;
petal.rotation.y += beatStrength * 0.1;
});
}
});
engine.runRenderLoop(() => {
scene.render();
});
window.addEventListener("resize", () => {
engine.resize();
});
</script>
</body>
</html>
index.html
<!DOCTYPE html>
<html>
<head>
<title>Flower Petal Dance</title>
<script src="https://cdn.babylonjs.com/babylon.js"></script>
</head>
<body>
<canvas id="renderCanvas" touch-action="none"></canvas>
<input type="file" id="fileInput" accept="audio/*" style="position: absolute; top: 10px; left: 10px; z-index: 1000;">
<script>
const canvas = document.getElementById("renderCanvas");
const engine = new BABYLON.Engine(canvas, true);
const scene = new BABYLON.Scene(engine);
const camera = new BABYLON.ArcRotateCamera("Camera", Math.PI / 2, Math.PI / 4, 20, BABYLON.Vector3.Zero(), scene);
camera.attachControl(canvas, true);
const light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(0, 1, 0), scene);
// 花びらの形状
const flowerPetal = BABYLON.MeshBuilder.CreateDisc("petal", { radius: 0.5, tessellation: 64 }, scene);
flowerPetal.rotation.x = Math.PI / 2;
// マテリアル
const petalMaterial = new BABYLON.StandardMaterial("petalMaterial", scene);
flowerPetal.material = petalMaterial;
// 花びらを大量に生成
const petals = [];
for (let i = 0; i < 100; i++) {
const petalInstance = flowerPetal.clone("petal" + i);
petalInstance.position = new BABYLON.Vector3(
Math.random() * 20 - 10,
Math.random() * 10,
Math.random() * 20 - 10
);
petals.push(petalInstance);
}
// 音楽の再生設定
const fileInput = document.getElementById("fileInput");
let audioContext = null;
let analyser = null;
let frequencyData = null;
let isPlaying = false;
fileInput.addEventListener("change", (event) => {
const file = event.target.files[0];
if (file) {
const audioElement = new Audio(URL.createObjectURL(file));
audioElement.crossOrigin = "anonymous"; // クロスオリジンの制限を回避
audioElement.play();
isPlaying = true;
if (!audioContext) {
audioContext = new (window.AudioContext || window.webkitAudioContext)();
analyser = audioContext.createAnalyser();
analyser.fftSize = 256;
frequencyData = new Uint8Array(analyser.frequencyBinCount);
}
const source = audioContext.createMediaElementSource(audioElement);
source.connect(analyser);
analyser.connect(audioContext.destination);
// 再生終了時にアニメーション停止
audioElement.addEventListener("ended", () => {
isPlaying = false;
});
}
});
// アニメーション
scene.registerBeforeRender(() => {
if (isPlaying && analyser && frequencyData) {
analyser.getByteFrequencyData(frequencyData);
const beatStrength = frequencyData[0] / 255; // 周波数データを正規化
petals.forEach(petal => {
// 花びらの動き
petal.position.y += Math.sin(scene.getEngine().getDeltaTime() * 0.001 + Math.random()) * beatStrength;
if (petal.position.y > 10) petal.position.y = -10; // Y座標が上限を超えたらリセット
petal.rotation.y += beatStrength * 0.1;
// 色の変化
const colorFactor = frequencyData[Math.floor(Math.random() * frequencyData.length)] / 255;
petal.material.diffuseColor = new BABYLON.Color3(colorFactor, 1 - colorFactor, Math.random());
});
}
});
engine.runRenderLoop(() => {
scene.render();
});
window.addEventListener("resize", () => {
engine.resize();
});
</script>
</body>
</html>
index.html
<!DOCTYPE html>
<html>
<head>
<title>Flower Petal Dance</title>
<script src="https://cdn.babylonjs.com/babylon.js"></script>
</head>
<body>
<canvas id="renderCanvas" touch-action="none"></canvas>
<input type="file" id="fileInput" accept="audio/*" style="position: absolute; top: 10px; left: 10px; z-index: 1000;">
<script>
const canvas = document.getElementById("renderCanvas");
const engine = new BABYLON.Engine(canvas, true);
const scene = new BABYLON.Scene(engine);
const camera = new BABYLON.ArcRotateCamera("Camera", Math.PI / 2, Math.PI / 4, 20, BABYLON.Vector3.Zero(), scene);
camera.attachControl(canvas, true);
const light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(0, 1, 0), scene);
// 花びらの形状
const flowerPetal = BABYLON.MeshBuilder.CreateDisc("petal", { radius: 0.5, tessellation: 64 }, scene);
flowerPetal.rotation.x = Math.PI / 2;
// マテリアル
const petalMaterial = new BABYLON.StandardMaterial("petalMaterial", scene);
flowerPetal.material = petalMaterial;
// 花びらを大量に生成
const petals = [];
for (let i = 0; i < 100; i++) {
const petalInstance = flowerPetal.clone("petal" + i);
petalInstance.position = new BABYLON.Vector3(
Math.random() * 20 - 10,
Math.random() * 10,
Math.random() * 20 - 10
);
petalInstance.rotation = new BABYLON.Vector3(
Math.random() * Math.PI,
Math.random() * Math.PI,
Math.random() * Math.PI
);
petalInstance.colorChangeFactor = Math.random(); // 色変化速度を個別に設定
petals.push(petalInstance);
}
// 音楽の再生設定
const fileInput = document.getElementById("fileInput");
let audioContext = null;
let analyser = null;
let frequencyData = null;
let isPlaying = false;
fileInput.addEventListener("change", (event) => {
const file = event.target.files[0];
if (file) {
const audioElement = new Audio(URL.createObjectURL(file));
audioElement.crossOrigin = "anonymous"; // クロスオリジンの制限を回避
audioElement.play();
isPlaying = true;
if (!audioContext) {
audioContext = new (window.AudioContext || window.webkitAudioContext)();
analyser = audioContext.createAnalyser();
analyser.fftSize = 256;
frequencyData = new Uint8Array(analyser.frequencyBinCount);
}
const source = audioContext.createMediaElementSource(audioElement);
source.connect(analyser);
analyser.connect(audioContext.destination);
// 再生終了時にアニメーション停止
audioElement.addEventListener("ended", () => {
isPlaying = false;
});
}
});
// アニメーション
let colorChangeSpeed = 0.01; // 色変化の速さを調整
scene.registerBeforeRender(() => {
if (isPlaying && analyser && frequencyData) {
analyser.getByteFrequencyData(frequencyData);
const beatStrength = frequencyData[0] / 255; // 周波数データを正規化
petals.forEach(petal => {
// 花びらのひらひら動き
petal.position.y += Math.sin(scene.getEngine().getDeltaTime() * 0.001 + petal.position.x) * 0.05;
petal.position.x += Math.cos(scene.getEngine().getDeltaTime() * 0.001 + petal.position.z) * 0.02;
// Y軸を超えたらリセット
if (petal.position.y > 10) petal.position.y = -10;
// ゆっくりとした回転
petal.rotation.x += 0.005;
petal.rotation.z += 0.003;
// 色の変化
petal.colorChangeFactor += colorChangeSpeed * Math.random(); // 個別の色変化速度
if (petal.colorChangeFactor > 1) petal.colorChangeFactor = 0;
const colorFactor = petal.colorChangeFactor;
petal.material.diffuseColor = new BABYLON.Color3(
Math.sin(colorFactor * Math.PI),
Math.sin((colorFactor + 0.33) * Math.PI),
Math.sin((colorFactor + 0.66) * Math.PI)
);
});
}
});
engine.runRenderLoop(() => {
scene.render();
});
window.addEventListener("resize", () => {
engine.resize();
});
</script>
</body>
</html>
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Flower Petal Dance</title>
<script src="https://cdn.babylonjs.com/babylon.js"></script>
<style>
body, html {
margin: 0;
padding: 0;
overflow: hidden;
width: 100%;
height: 100%;
}
#renderCanvas {
display: block;
width: 100%;
height: 100%;
}
#fileInput {
position: absolute;
top: 10px;
left: 10px;
z-index: 1000;
}
</style>
</head>
<body>
<canvas id="renderCanvas"></canvas>
<input type="file" id="fileInput" accept="audio/*">
<script>
const canvas = document.getElementById("renderCanvas");
const engine = new BABYLON.Engine(canvas, true);
const scene = new BABYLON.Scene(engine);
const camera = new BABYLON.ArcRotateCamera("Camera", Math.PI / 2, Math.PI / 4, 20, BABYLON.Vector3.Zero(), scene);
camera.attachControl(canvas, true);
const light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(0, 1, 0), scene);
// 花びらの形状
const flowerPetal = BABYLON.MeshBuilder.CreateDisc("petal", { radius: 0.5, tessellation: 64 }, scene);
flowerPetal.rotation.x = Math.PI / 2;
// マテリアル
const petalMaterial = new BABYLON.StandardMaterial("petalMaterial", scene);
flowerPetal.material = petalMaterial;
// 花びらを大量に生成
const petals = [];
for (let i = 0; i < 100; i++) {
const petalInstance = flowerPetal.clone("petal" + i);
petalInstance.position = new BABYLON.Vector3(
Math.random() * 20 - 10,
Math.random() * 10,
Math.random() * 20 - 10
);
petalInstance.rotation = new BABYLON.Vector3(
Math.random() * Math.PI,
Math.random() * Math.PI,
Math.random() * Math.PI
);
petalInstance.colorChangeFactor = Math.random();
petals.push(petalInstance);
}
// 音楽の再生設定
const fileInput = document.getElementById("fileInput");
let audioContext = null;
let analyser = null;
let frequencyData = null;
let isPlaying = false;
fileInput.addEventListener("change", (event) => {
const file = event.target.files[0];
if (file) {
const audioElement = new Audio(URL.createObjectURL(file));
audioElement.crossOrigin = "anonymous";
audioElement.play();
isPlaying = true;
if (!audioContext) {
audioContext = new (window.AudioContext || window.webkitAudioContext)();
analyser = audioContext.createAnalyser();
analyser.fftSize = 256;
frequencyData = new Uint8Array(analyser.frequencyBinCount);
}
const source = audioContext.createMediaElementSource(audioElement);
source.connect(analyser);
analyser.connect(audioContext.destination);
// 再生終了時にアニメーション停止
audioElement.addEventListener("ended", () => {
isPlaying = false;
});
}
});
// アニメーション
let colorChangeSpeed = 0.01;
scene.registerBeforeRender(() => {
if (isPlaying && analyser && frequencyData) {
analyser.getByteFrequencyData(frequencyData);
const beatStrength = frequencyData[0] / 255;
petals.forEach(petal => {
petal.position.y += Math.sin(scene.getEngine().getDeltaTime() * 0.001 + petal.position.x) * 0.05;
petal.position.x += Math.cos(scene.getEngine().getDeltaTime() * 0.001 + petal.position.z) * 0.02;
if (petal.position.y > 10) petal.position.y = -10;
petal.rotation.x += 0.005;
petal.rotation.z += 0.003;
petal.colorChangeFactor += colorChangeSpeed * Math.random();
if (petal.colorChangeFactor > 1) petal.colorChangeFactor = 0;
const colorFactor = petal.colorChangeFactor;
petal.material.diffuseColor = new BABYLON.Color3(
Math.sin(colorFactor * Math.PI),
Math.sin((colorFactor + 0.33) * Math.PI),
Math.sin((colorFactor + 0.66) * Math.PI)
);
});
}
});
engine.runRenderLoop(() => {
scene.render();
});
window.addEventListener("resize", () => {
engine.resize();
});
</script>
</body>
</html>
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Flower Petal Dance</title>
<script src="https://cdn.babylonjs.com/babylon.js"></script>
<style>
body, html {
margin: 0;
padding: 0;
overflow: hidden;
width: 100%;
height: 100%;
}
#renderCanvas {
display: block;
width: 100%;
height: 100%;
}
#fileInput {
position: absolute;
top: 10px;
left: 10px;
z-index: 1000;
}
</style>
</head>
<body>
<canvas id="renderCanvas"></canvas>
<input type="file" id="fileInput" accept="audio/*">
<script>
const canvas = document.getElementById("renderCanvas");
const engine = new BABYLON.Engine(canvas, true);
const scene = new BABYLON.Scene(engine);
// 背景を白に設定
scene.clearColor = new BABYLON.Color3(1, 1, 1);
const camera = new BABYLON.ArcRotateCamera("Camera", Math.PI / 2, Math.PI / 4, 20, BABYLON.Vector3.Zero(), scene);
camera.attachControl(canvas, true);
const light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(0, 1, 0), scene);
// 花びらの形状
const flowerPetal = BABYLON.MeshBuilder.CreateDisc("petal", { radius: 0.5, tessellation: 64 }, scene);
flowerPetal.rotation.x = Math.PI / 2;
// マテリアル
const petalMaterial = new BABYLON.StandardMaterial("petalMaterial", scene);
flowerPetal.material = petalMaterial;
// 花びらを大量に生成
const petals = [];
const totalPetals = 300; // 花びらの数を増加
for (let i = 0; i < totalPetals; i++) {
const petalInstance = flowerPetal.clone("petal" + i);
petalInstance.position = new BABYLON.Vector3(
Math.random() * 40 - 20,
Math.random() * 20,
Math.random() * 40 - 20
);
petalInstance.rotation = new BABYLON.Vector3(
Math.random() * Math.PI,
Math.random() * Math.PI,
Math.random() * Math.PI
);
petalInstance.colorChangeFactor = Math.random();
petals.push(petalInstance);
}
// 音楽の再生設定
const fileInput = document.getElementById("fileInput");
let audioContext = null;
let analyser = null;
let frequencyData = null;
let isPlaying = false;
fileInput.addEventListener("change", (event) => {
const file = event.target.files[0];
if (file) {
const audioElement = new Audio(URL.createObjectURL(file));
audioElement.crossOrigin = "anonymous";
audioElement.play();
isPlaying = true;
if (!audioContext) {
audioContext = new (window.AudioContext || window.webkitAudioContext)();
analyser = audioContext.createAnalyser();
analyser.fftSize = 256;
frequencyData = new Uint8Array(analyser.frequencyBinCount);
}
const source = audioContext.createMediaElementSource(audioElement);
source.connect(analyser);
analyser.connect(audioContext.destination);
// 再生終了時にアニメーション停止
audioElement.addEventListener("ended", () => {
isPlaying = false;
});
}
});
// アニメーション
let colorChangeSpeed = 0.005; // 色変化をゆっくり
scene.registerBeforeRender(() => {
if (isPlaying && analyser && frequencyData) {
analyser.getByteFrequencyData(frequencyData);
const beatStrength = frequencyData[0] / 255;
petals.forEach(petal => {
// 花びらのひらひら動き
petal.position.y += Math.sin(scene.getEngine().getDeltaTime() * 0.001 + petal.position.x) * 0.03;
petal.position.x += Math.cos(scene.getEngine().getDeltaTime() * 0.001 + petal.position.z) * 0.02;
if (petal.position.y > 20) petal.position.y = -5;
petal.rotation.x += 0.002;
petal.rotation.z += 0.001;
petal.colorChangeFactor += colorChangeSpeed * Math.random();
if (petal.colorChangeFactor > 1) petal.colorChangeFactor = 0;
const colorFactor = petal.colorChangeFactor;
petal.material.diffuseColor = new BABYLON.Color3(
Math.sin(colorFactor * Math.PI),
Math.sin((colorFactor + 0.33) * Math.PI),
Math.sin((colorFactor + 0.66) * Math.PI)
);
});
}
});
engine.runRenderLoop(() => {
scene.render();
});
window.addEventListener("resize", () => {
engine.resize();
});
</script>
</body>
</html>
実行結果
音楽に合わせて?オブジェクトが舞うようになった!
マウス操作で、3D空間を移動、拡大縮小ができる。
とても便利なライブラリ!
Babylon.jsの実験中 pic.twitter.com/yTVmCjPqdA
— MakerYuki (@maker_yuki) December 19, 2024