自動方向
自動方向の作り方
フラットな円が傾いたリングをめぐり、手前ではふくらんでゆっくり、奥では縮んで速く見える。遠近の倍率を位置と大きさの両方へ等しくかけると、緩急も奥行きもこの一つの投影から揃って出てくる。フラットな見た目のまま、幾何が揃えてくれる奥行きが欲しいときの作り方を、コードつきで追う。
- Published
- 2026年6月14日
- Topics
- Auto-orient · 3D · Perspective · SVG
傾いたリングと二軸の回転を組む
- 手で置くのは同じ大きさの円が 8 つ — 明るい色と暗い色をひとつおきに並べる
- 円は平らな円盤ではなく、画面から少し傾けた 3D のリングにのせる
- リングは画面の軸のまわりに回り、円はリング自身の向きのまわりにも回る — この二重の回転で動く
// フレーム番号をループの中の位置へ折り返す
const wrap = (frame, span) => ((frame % span) + span) % span;
// 最初に一度だけ: 傾けたリングの向きと、親まわり・子まわりの回る速さ
const n0 = tiltedUnit(axis, tiltDeg, tiltAzimuthDeg);
const parentPerFrame = 360 * parentTurns / periodFrames;
const spinPerFrame = 360 * spinTurns / periodFrames;tiltedUnit は、まっすぐな軸からリングの面を傾けて、その面に垂直な向き(法線)を返す。ringPoints3d は、その法線を中心にした円のまわりへ count 個の点を等間隔に置く。rotationAboutAxis と applyMat3 は、点を好きな軸のまわりに回す道具で、軸まわりの回転はロドリゲスの公式、サインとコサインだけで書ける。どれもベクトルの足し算とかけ算でできた小さな部品で、n0 を一度作ればあとは毎フレーム使い回す。
// フレーム番号 → 各円の画面での位置と大きさ
const dotsAt = (frame) => {
const t = wrap(frame, periodFrames);
// 子: 円がリングの向きのまわりをめぐる
const ring = ringPoints3d(n0, spinPhase0 + spinPerFrame * t, ringRadius, count);
// 親: リングごと画面の軸のまわりに回る
const rot = rotationAboutAxis(axis, parentPerFrame * t);
return ring.map((p, i) => {
const spun = applyMat3(rot, p);
const z = spun[2] / ringRadius;
const m = 1 + depthK * z; // ひとつの遠近の倍率を位置にも大きさにも同じだけ
const dark = i % 2 === 0;
return {
cx: center[0] + spun[0] * m,
cy: center[1] + spun[1] * m,
r: (dark ? darkRadius : lightRadius) * m,
z,
dark,
};
});
};ここが正体だ。手前と奥を分けているのは z、つまり点の奥行きで、それを depthK で倍率 m に変える。その同じ m を、中心からの位置にも円の大きさにもかける — だから手前の円は外へ大きく、奥の円は内へ小さく見える。見かけのゆっくり・速い、縦の弾み、手前と奥の入れ替わりは、どれもこの遠近(透視)からひとりでに生まれる。キーフレームのイージングはどこにも書いていない。
画面に出すときは、奥の円から先に描く — 手前の円があとから重なって、近いものが上に来る。あとは円をひとつずつ描くだけだ。色は決め打ちにせず、ページの地の色を受け取り、明るいほうの円だけ少し薄くして明暗を出す。動かすのは requestAnimationFrame で、経過した時間にコマ数をかけてフレーム番号にし、periodFrames で wrap して dotsAt にわたせば、このデモと同じループになる。
遊ぶなら傾きの tiltDeg とその向き tiltAzimuthDeg を変えてみる。リングの寝かせ方が変わって、手前と奥の差が強くも弱くもなる。spinTurns と parentTurns を入れ替えれば回る向きと速さが変わり、depthK を大きくすると遠近がきつくなって、手前の円がぐっと前に出る。円を四角に変えても、count 個を 3D に置いて回すこの仕組みはそのまま使える。