import * as THREE from './x.js'; import { OrbitControls } from './y.js'; const M = JSON.parse(document.getElementById('motion').textContent); const P = M.joints; // [T][22][3] const PARENTS = M.parents; const T = P.length, J = P[0].length; const scene = new THREE.Scene(); scene.background = new THREE.Color(0x101013); const cam = new THREE.PerspectiveCamera(45, innerWidth/innerHeight, 0.05, 100); const renderer = new THREE.WebGLRenderer({antialias:true}); renderer.setSize(innerWidth, innerHeight); document.body.appendChild(renderer.domElement); scene.add(new THREE.HemisphereLight(0xffffff, 0x334, 1.1)); const grid = new THREE.GridHelper(8, 16, 0x3a3a40, 0x26262c); scene.add(grid); // bounding box across ALL frames -> camera + center let mn=[1e9,1e9,1e9], mx=[-1e9,-1e9,-1e9]; for (const f of P) for (const p of f) for (let i=0;i<3;i++){ mn[i]=Math.min(mn[i],p[i]); mx[i]=Math.max(mx[i],p[i]); } const cx=(mn[0]+mx[0])/2, cy=(mn[1]+mx[1])/2, cz=(mn[2]+mx[2])/2; const R = Math.max(mx[0]-mn[0], mx[1]-mn[1], mx[2]-mn[2]); cam.position.set(cx+R*1.6, cy+R*0.8, cz+R*1.8); const controls = new OrbitControls(cam, renderer.domElement); controls.target.set(cx, cy, cz); const jmat = new THREE.MeshStandardMaterial({color:0xf3ead8}); const hmat = new THREE.MeshStandardMaterial({color:0xbba76f}); const spheres = []; for (let j=0;j=0) bonePairs.push([PARENTS[j], j]); const pos = new Float32Array(bonePairs.length*6); bonesGeo.setAttribute('position', new THREE.BufferAttribute(pos, 3)); scene.add(new THREE.LineSegments(bonesGeo, new THREE.LineBasicMaterial({color:0x9fc2ff}))); const scrub = document.getElementById('scrub'); const info = document.getElementById('info'); const playBtn = document.getElementById('play'); scrub.max = T-1; let frame = 0, playing = true, acc = 0, last = performance.now(); playBtn.onclick = () => { playing = !playing; playBtn.textContent = playing?'⏸':'▶'; }; scrub.oninput = () => { frame = +scrub.value; playing = false; playBtn.textContent='▶'; }; function setFrame(f){ const fr = P[f]; for (let j=0;j step){ acc -= step; frame = (frame+1) % T; } } last = now; setFrame(frame); controls.update(); renderer.render(scene, cam); } addEventListener('resize', () => { cam.aspect=innerWidth/innerHeight; cam.updateProjectionMatrix(); renderer.setSize(innerWidth, innerHeight); }); tick(performance.now());