このページでは、JavaScriptの基本的な説明と、Canvas APIを使用したアニメーションの作成方法について説明します。
また、3Dモデルの花を作成する方法についても触れます。
JavaScriptとは、Webブラウザ上で動作するスクリプト言語の一つで、動的なWebページを作成するために使用されるプログラミング言語のことです。
Webブラウザの機能を制御し、動的な操作やアニメーション、ユーザーとのインタラクション、データの検証や処理などを実現できます。
JavaScriptは、HTMLやCSSと組み合わせて使用されることが多く、Webページに高度な対話性や視覚効果を追加することができます。
Three.jsは、WebGLを使用して3Dグラフィックスを描画するためのJavaScriptライブラリです。
これにより、ブラウザ上でリアルタイムの3Dアニメーションやインタラクティブなコンテンツを作成することができます。
<script type="importmap">
{
"imports": {
"three": "https://cdn.jsdelivr.net/npm/three@0.167.0/build/three.module.js",
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.167.0/examples/jsm/"
}
}
</script>
<script type="module">
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
</script>
Canvas APIは、HTML5で導入された2Dグラフィックスを描画するためのAPIです。JavaScriptを使用して、
動的なグラフィックスやアニメーションを作成することができます。
<canvas> id="petalCanvas" width="600" height="480"></canvas>
JavaScriptを使用したアニメーションの作成方法について学びます。Three.jsでは`requestAnimationFrame()`を使用して、
スムーズな回転や移動アニメーションを実現することができます。
// アニメーションループ
function animate() {
requestAnimationFrame(animate); // 次のフレームを要求
// オブジェクトを回転
petal.rotation.z += 0.01; // Z軸回転
// カメラコントロールを更新
controls.update();
// シーンを描画
renderer.render(scene, camera);
}
// アニメーション開始
animate();
Three.jsでは、カメラと光源の設定が重要です。カメラはシーンをどのように見るかを決定し、光源はオブジェクトの見え方に影響を与えます。
ここでは、基本的なカメラと光源の設定方法について説明します。
// カメラの設定
const camera = new THREE.PerspectiveCamera(
60, // fov: 視野角(度)
canvas.width / canvas.height, // aspect: アスペクト比
0.1, // near: 近クリップ面
1000 // far: 遠クリップ面
);
camera.position.set(0, 0.5, 1.5);
// 光源の設定
const sunLight = new THREE.DirectionalLight(0xffffff, 0.8);
sunLight.position.set(3, 5, 2);
sunLight.castShadow = true;
scene.add(sunLight);
3Dの花を作成するために、Three.jsを使用して立体的な花のモデルを作成します。花びらや茎、葉っぱを個別に作成し、
組み合わせて1つの花を形成します。
このセクションでは、桜の花びらを描画するためのJavaScriptコードを示します。
花びらはCanvas APIを使用して描画され、マウスでドラッグして回転させることができます。
「quadraticCurveTo()」を使って桜の花びら特有の曲線を描画しました。
// 花びら生成関数
function createSakuraPetal(size, color, position) {
const shape = new THREE.Shape();
// 桜の花びらの形状を描画
shape.moveTo(0, 0); // 開始点
shape.quadraticCurveTo(size * 0.5, size * 0.2, size, size * 0.6); // 右の曲線
shape.quadraticCurveTo(size * 0.9, size * 1.0, size * 0.5, size * 1.2); // 先端の右側
shape.quadraticCurveTo(size * 0.2, size * 1.3, 0, size * 1.0); // 先端のくぼみ
shape.quadraticCurveTo(-size * 0.2, size * 0.7, -size * 0.1, size * 0.3); // 左の曲線
shape.quadraticCurveTo(-size * 0.05, size * 0.1, 0, 0); // 元の位置に戻る
}
// 2D形状を3Dに変換
const extrudeSettings = {
depth: 0.01, // 厚み
bevelEnabled: true, // 面取りを有効
bevelThickness: 0.005, // 面取りの厚み
bevelSize: 0.005, // 面取りのサイズ
bevelSegments: 2 // 面取りの分割数
};
const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
// 花びらに自然な湾曲を追加
const positionAttribute = geometry.attributes.position;
const vertex = new THREE.Vector3();
for (let i = 0; i < positionAttribute.count; i++) {
vertex.fromBufferAttribute(positionAttribute, i);
// 中心からの距離に応じて湾曲(Z方向に曲げる)
const dist = Math.sqrt(vertex.x ** 2 + vertex.y ** 2);
const curveStrength = 0.1; // 湾曲の強さ
vertex.z = Math.sin(dist * Math.PI) * curveStrength;
positionAttribute.setXYZ(i, vertex.x, vertex.y, vertex.z);
}
// 花びらの材質設定
const material = new THREE.MeshStandardMaterial({
color: color, // 色
transparent: true, // 透明度を有効
opacity: 0.9 // 透明度(90%不透明)
});
const petal = new THREE.Mesh(geometry, material);
このセクションでは、先ほどの桜の花びらを組み合わせて、一輪の桜の花を作成します。
上記の花びらを放射状に配置し、雄蕊と雌蕊を追加して、よりリアルな桜の花を表現します。
花びらの色や形状を調整することで、より自然な見た目を実現しています。
// 桜の花全体を作成
const sakuraFlower = new THREE.Group();
// 5枚の花びらを放射状に配置
for (let i = 0; i < 5; i++) {
const angle = (i / 5) * Math.PI * 2; // 72度ずつ配置
const petal = createRealisticSakuraPetal(0.2, 0xff69b4, angle, i);
sakuraFlower.add(petal);
}
// 雄蕊と雌蕊を追加
const stamens = createStamen(15);
const pistil = createPistil();
sakuraFlower.add(stamens);
sakuraFlower.add(pistil);
// 雄蕊を作成する関数
function createStamen(count = 15, sizeScale = 2.0) {
// 15本の雄蕊を円形に配置
for (let i = 0; i < count; i++) {
// 軸(stalk): 細い円柱
const stalkGeometry = new THREE.CylinderGeometry(
0.002 * sizeScale, // 上端半径
0.003 * sizeScale, // 下端半径
0.08 * sizeScale // 高さ
);
// 葯(anther): 花粉を含む球体
const antherGeometry = new THREE.SphereGeometry(
0.008 * sizeScale, 8, 8
);
// 円形配置の計算
const angle = (i / count) * Math.PI * 2;
const radius = (0.03 + Math.random() * 0.02) * sizeScale;
}
}
// 雌蕊を作成する関数
function createPistil(sizeScale = 2.0) {
// 雌蕊の軸: 円柱
const pistilGeometry = new THREE.CylinderGeometry(
0.004 * sizeScale, // 均一な太さ
0.004 * sizeScale,
0.06 * sizeScale // 高さ
);
// 柱頭(受粉部分): 白い球体
const stigmaGeometry = new THREE.SphereGeometry(
0.006 * sizeScale, 8, 8
);
}
// がくを1つ追加
const calyxGeometry = new THREE.ConeGeometry(
0.08 * calyxScale, // ★がくの底面半径
0.03 * calyxScale, // ★がくの高さ
5
);
const calyxMaterial = new THREE.MeshStandardMaterial({
color: 0x228b22
});
const calyx = new THREE.Mesh(calyxGeometry, calyxMaterial);
calyx.position.set(0, -0.02 * calyxScale, 0); // ★位置もスケールに合わせる
calyx.rotation.x = Math.PI;
completeFlower.add(calyx);
このセクションでは、桜の枝を作成します。
枝の形状や配置を工夫することで、より自然な桜の木を表現します。
// ★節の情報を定義
const nodes = [
{ position: new THREE.Vector3(0, 0, 0), direction: new THREE.Vector3(1, 0, 0) },
{ position: new THREE.Vector3(0.4, 0.1, 0.05), direction: new THREE.Vector3(0.8, 0.6, -0.1) },
{ position: new THREE.Vector3(0.7, 0.35, 0), direction: new THREE.Vector3(0.6, 0.8, 0.2) },
{ position: new THREE.Vector3(0.9, 0.7, 0.15), direction: new THREE.Vector3(0.3, 0.9, -0.1) },
{ position: new THREE.Vector3(1.0, 1.1, 0.1), direction: new THREE.Vector3(0.2, 1.0, 0.1) }
];
// ★節間のセグメントを作成
for (let i = 0; i < nodes.length - 1; i++) {
const startNode = nodes[i];
const endNode = nodes[i + 1];
// セグメントの長さ
const segmentLength = startNode.position.distanceTo(endNode.position);
// ★適度に真っ直ぐなセグメント作成
const segmentGeometry = new THREE.CylinderGeometry(
0.02 * (1 - i * 0.15), // 先端に向かって細くなる
0.025 * (1 - i * 0.1),
segmentLength,
12
);
// ★節(ふし)を作成
for (let i = 1; i < nodes.length - 1; i++) {
const node = nodes[i];
// 節の膨らみ
const nodeGeometry = new THREE.SphereGeometry(0.018, 12, 12);
const nodeSwelling = new THREE.Mesh(nodeGeometry, barkMaterial);
nodeSwelling.position.copy(node.position);
// ★節から小枝を追加(1-2本)
const subBranchCount = Math.random() > 0.5 ? 1 : 2;
for (let j = 0; j < subBranchCount; j++) {
createSubBranch(node.position, branchGroup, barkMaterial, i);
}
}
// ★小枝のセグメント数(2-4個に増加)
const segments = 2 + Math.floor(Math.random() * 3);
// ★小枝の節の位置を定義
const subNodes = [];
for (let i = 0; i <= segments; i++) {
const t = i / segments;
const position = new THREE.Vector3()
.copy(nodePosition)
.add(branchDirection.clone().multiplyScalar(branchLength * t));
// 小さなランダムな変化を追加
position.add(new THREE.Vector3(
(Math.random() - 0.5) * 0.02,
(Math.random() - 0.5) * 0.02,
(Math.random() - 0.5) * 0.02
));
subNodes.push(position);
}
// ★新しい関数:三次分岐(小枝から更に分岐)
function createTertiaryBranch(nodePosition, parentGroup, material, generation) {
// より細い枝の方向
const branchDirection = new THREE.Vector3(
(Math.random() - 0.5) * 2,
Math.random() * 0.6 + 0.1, // 上向き傾向を弱める
(Math.random() - 0.5) * 2
).normalize();
// より短い枝
const branchLength = 0.08 + Math.random() * 0.15;
const segments = 1 + Math.floor(Math.random() * 2); // 1-2セグメント
このセクションでは、今まで作成した桜の花、枝を使い、1本の枝付き桜を作成しました。
javascriptのexportを使用して、各コンポーネントをモジュール化し、再利用可能な形に整えます。
export function createSakuraFlower(scale = 1) {
// 花びらを1つだけ作成
const petal = createSakuraPetal(0.5, 0xff69b4, new THREE.Vector3(0, 0, 0));
petal.rotation.x = Math.PI / 2;
return petal;
}
import { createRealisticPlumBranch, createSubBranch, getBranchNodes,
createTertiaryBranch, createTinyTwig } from './cherry-parts/brunch_export.js';
import {createSakuraFlower} from './cherry-parts/petals_export.js';
import {OrbitControls} from 'three/addons/controls/OrbitControls.js';
約18時間
Canvas API の公式ドキュメント
https://developer.mozilla.org/ja/docs/Web/API/Canvas_API/TutorialThree.js の実装に関する技術記事
https://qiita.com/watabo_shi/items/bf9bcd4569b6d480c608JavaScript Three.js の技術解説
https://logmi.jp/main/technology/330425