File size: 3,850 Bytes
ee5ec19
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
<!DOCTYPE html><html><head><meta charset="utf-8"><title>anim test</title>
<style>html,body{margin:0;height:100%;background:#202028;overflow:hidden}
#hud{position:fixed;top:0;left:0;color:#0f0;font:12px monospace;z-index:9;padding:6px;background:#000a;white-space:pre}</style>
<script type="importmap">{"imports":{
"three":"https://unpkg.com/three@0.160.0/build/three.module.js",
"three/addons/":"https://unpkg.com/three@0.160.0/examples/jsm/",
"fflate":"https://unpkg.com/fflate@0.8.2/esm/browser.js"
}}</script></head>
<body><div id="hud">loading…</div>
<script type="module">
import * as THREE from 'three';
import {FBXLoader} from 'three/addons/loaders/FBXLoader.js';
const hud=document.getElementById('hud');const L=(m)=>hud.textContent=m;
const renderer=new THREE.WebGLRenderer({antialias:true});
renderer.setPixelRatio(Math.min(devicePixelRatio,1.5));renderer.setSize(innerWidth,innerHeight);
renderer.shadowMap.enabled=true;document.body.appendChild(renderer.domElement);
const scene=new THREE.Scene();scene.background=new THREE.Color(0x202028);
scene.add(new THREE.HemisphereLight(0xffffff,0x445,1.2));
const dl=new THREE.DirectionalLight(0xffffff,2.2);dl.position.set(3,8,6);dl.castShadow=true;scene.add(dl);
const ground=new THREE.Mesh(new THREE.PlaneGeometry(40,40),new THREE.MeshStandardMaterial({color:0x33343e}));
ground.rotation.x=-Math.PI/2;ground.receiveShadow=true;scene.add(ground);
const cam=new THREE.PerspectiveCamera(45,innerWidth/innerHeight,0.05,100);
cam.position.set(0,1.1,3.6);cam.lookAt(0,1.0,0);
scene.overrideMaterial=new THREE.MeshStandardMaterial({color:0xbfc4cc,roughness:.7});
const fbx=new FBXLoader();
const load=p=>new Promise((res,rej)=>fbx.load(p,res,undefined,rej));

const WHICH=location.hash==='#boss'?'boss':'player';
const BASE=WHICH==='boss'?'assets/chars/malenia.fbx':'assets/chars/player.fbx';
const NAMES=WHICH==='boss'
  ?['idle','walk','run','attack1','attack2','kick','block','powerup','hit','death']
  :['idle','walk','walkback','run','attack1','attack2','combo','kick','block','hit','roll'];

let mixer,clips={},cur,action;
window.__clip=(n)=>{if(!clips[n])return 'no '+n;const na=mixer.clipAction(clips[n]);
  if(action&&action!==na){action.fadeOut(0.2);}na.reset().fadeIn(0.2).play();action=na;cur=n;return {n,dur:+clips[n].duration.toFixed(2)};};
window.__list=()=>Object.keys(clips).map(n=>({n,dur:+clips[n].duration.toFixed(2)}));

(async()=>{
  L('loading base '+WHICH+'…');
  const base=await load(BASE);
  const box=new THREE.Box3().setFromObject(base);const s=new THREE.Vector3();box.getSize(s);
  const sc=1.8/s.y;base.scale.setScalar(sc);base.position.y=-box.min.y*sc;
  base.traverse(o=>{if(o.isMesh){o.castShadow=true;o.frustumCulled=false;}});
  scene.add(base);
  mixer=new THREE.AnimationMixer(base);
  const boneNames=new Set();base.traverse(o=>{if(o.isBone)boneNames.add(o.name);});
  for(const n of NAMES){
    try{const a=await load('assets/anim/'+WHICH+'/'+n+'.fbx');
      if(a.animations&&a.animations[0]){clips[n]=a.animations[0];clips[n].name=n;}
      else L('no clip in '+n);
    }catch(e){console.warn(n,e);}
  }
  // report track/bone match on first clip
  const first=clips[NAMES[0]];
  let matched=0,total=0;
  if(first){for(const tr of first.tracks){total++;const bn=tr.name.split('.')[0];if(boneNames.has(bn))matched++;}}
  L(`base bones=${boneNames.size}  clips=${Object.keys(clips).length}  tracksMatched=${matched}/${total}\n__clip(n) __list()`);
  window.__loaded={bones:boneNames.size,clips:Object.keys(clips),matched,total};
  if(clips.idle)window.__clip('idle');
  let last=performance.now();
  (function loop(now){requestAnimationFrame(loop);const dt=Math.min((now-last)/1000,0.05);last=now;
    if(mixer)mixer.update(dt);renderer.render(scene,cam);})(performance.now());
})().catch(e=>L('ERR '+e.message+'\n'+(e.stack||'')));
</script></body></html>