ソースを参照

Forgot to upload code... again.

Simon 4 年 前
コミット
b149e694e6

+ 21 - 21
LICENSE

@@ -1,21 +1,21 @@
-MIT License
-
-Copyright (c) 2020 simondevyoutube
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
+MIT License
+
+Copyright (c) 2020 simondevyoutube
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 9 - 0
base.css

@@ -0,0 +1,9 @@
+body {
+  width: 100%;
+  height: 100%;
+  position: absolute;
+  background: #000000;
+  margin: 0;
+  padding: 0;
+  overscroll-behavior: none;
+}

+ 12 - 0
index.html

@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>Three.JS Tutorial: Character Controller</title>
+  <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+  <link rel="stylesheet" type="text/css" href="base.css">
+</head>
+<body>
+  <script src="./main.js" type="module">
+  </script>
+</body>
+</html>

+ 625 - 0
main.js

@@ -0,0 +1,625 @@
+import * as THREE from 'https://cdn.jsdelivr.net/npm/[email protected]/build/three.module.js';
+
+import {FBXLoader} from 'https://cdn.jsdelivr.net/npm/[email protected]/examples/jsm/loaders/FBXLoader.js';
+import {GLTFLoader} from 'https://cdn.jsdelivr.net/npm/[email protected]/examples/jsm/loaders/GLTFLoader.js';
+import {OrbitControls} from 'https://cdn.jsdelivr.net/npm/[email protected]/examples/jsm/controls/OrbitControls.js';
+
+
+class BasicCharacterControllerProxy {
+  constructor(animations) {
+    this._animations = animations;
+  }
+
+  get animations() {
+    return this._animations;
+  }
+};
+
+
+class BasicCharacterController {
+  constructor(params) {
+    this._Init(params);
+  }
+
+  _Init(params) {
+    this._params = params;
+    this._decceleration = new THREE.Vector3(-0.0005, -0.0001, -5.0);
+    this._acceleration = new THREE.Vector3(1, 0.25, 50.0);
+    this._velocity = new THREE.Vector3(0, 0, 0);
+
+    this._animations = {};
+    this._input = new BasicCharacterControllerInput();
+    this._stateMachine = new CharacterFSM(
+        new BasicCharacterControllerProxy(this._animations));
+
+    this._LoadModels();
+  }
+
+  _LoadModels() {
+    const loader = new FBXLoader();
+    loader.setPath('./resources/zombie/');
+    loader.load('mremireh_o_desbiens.fbx', (fbx) => {
+      fbx.scale.setScalar(0.1);
+      fbx.traverse(c => {
+        c.castShadow = true;
+      });
+
+      this._target = fbx;
+      this._params.scene.add(this._target);
+
+      this._mixer = new THREE.AnimationMixer(this._target);
+
+      this._manager = new THREE.LoadingManager();
+      this._manager.onLoad = () => {
+        this._stateMachine.SetState('idle');
+      };
+
+      const _OnLoad = (animName, anim) => {
+        const clip = anim.animations[0];
+        const action = this._mixer.clipAction(clip);
+  
+        this._animations[animName] = {
+          clip: clip,
+          action: action,
+        };
+      };
+
+      const loader = new FBXLoader(this._manager);
+      loader.setPath('./resources/zombie/');
+      loader.load('walk.fbx', (a) => { _OnLoad('walk', a); });
+      loader.load('run.fbx', (a) => { _OnLoad('run', a); });
+      loader.load('idle.fbx', (a) => { _OnLoad('idle', a); });
+      loader.load('dance.fbx', (a) => { _OnLoad('dance', a); });
+    });
+  }
+
+  Update(timeInSeconds) {
+    if (!this._target) {
+      return;
+    }
+
+    this._stateMachine.Update(timeInSeconds, this._input);
+
+    const velocity = this._velocity;
+    const frameDecceleration = new THREE.Vector3(
+        velocity.x * this._decceleration.x,
+        velocity.y * this._decceleration.y,
+        velocity.z * this._decceleration.z
+    );
+    frameDecceleration.multiplyScalar(timeInSeconds);
+    frameDecceleration.z = Math.sign(frameDecceleration.z) * Math.min(
+        Math.abs(frameDecceleration.z), Math.abs(velocity.z));
+
+    velocity.add(frameDecceleration);
+
+    const controlObject = this._target;
+    const _Q = new THREE.Quaternion();
+    const _A = new THREE.Vector3();
+    const _R = controlObject.quaternion.clone();
+
+    const acc = this._acceleration.clone();
+    if (this._input._keys.shift) {
+      acc.multiplyScalar(2.0);
+    }
+
+    if (this._stateMachine._currentState.Name == 'dance') {
+      acc.multiplyScalar(0.0);
+    }
+
+    if (this._input._keys.forward) {
+      velocity.z += acc.z * timeInSeconds;
+    }
+    if (this._input._keys.backward) {
+      velocity.z -= acc.z * timeInSeconds;
+    }
+    if (this._input._keys.left) {
+      _A.set(0, 1, 0);
+      _Q.setFromAxisAngle(_A, 4.0 * Math.PI * timeInSeconds * this._acceleration.y);
+      _R.multiply(_Q);
+    }
+    if (this._input._keys.right) {
+      _A.set(0, 1, 0);
+      _Q.setFromAxisAngle(_A, 4.0 * -Math.PI * timeInSeconds * this._acceleration.y);
+      _R.multiply(_Q);
+    }
+
+    controlObject.quaternion.copy(_R);
+
+    const oldPosition = new THREE.Vector3();
+    oldPosition.copy(controlObject.position);
+
+    const forward = new THREE.Vector3(0, 0, 1);
+    forward.applyQuaternion(controlObject.quaternion);
+    forward.normalize();
+
+    const sideways = new THREE.Vector3(1, 0, 0);
+    sideways.applyQuaternion(controlObject.quaternion);
+    sideways.normalize();
+
+    sideways.multiplyScalar(velocity.x * timeInSeconds);
+    forward.multiplyScalar(velocity.z * timeInSeconds);
+
+    controlObject.position.add(forward);
+    controlObject.position.add(sideways);
+
+    oldPosition.copy(controlObject.position);
+
+    if (this._mixer) {
+      this._mixer.update(timeInSeconds);
+    }
+  }
+};
+
+class BasicCharacterControllerInput {
+  constructor() {
+    this._Init();    
+  }
+
+  _Init() {
+    this._keys = {
+      forward: false,
+      backward: false,
+      left: false,
+      right: false,
+      space: false,
+      shift: false,
+    };
+    document.addEventListener('keydown', (e) => this._onKeyDown(e), false);
+    document.addEventListener('keyup', (e) => this._onKeyUp(e), false);
+  }
+
+  _onKeyDown(event) {
+    switch (event.keyCode) {
+      case 87: // w
+        this._keys.forward = true;
+        break;
+      case 65: // a
+        this._keys.left = true;
+        break;
+      case 83: // s
+        this._keys.backward = true;
+        break;
+      case 68: // d
+        this._keys.right = true;
+        break;
+      case 32: // SPACE
+        this._keys.space = true;
+        break;
+      case 16: // SHIFT
+        this._keys.shift = true;
+        break;
+    }
+  }
+
+  _onKeyUp(event) {
+    switch(event.keyCode) {
+      case 87: // w
+        this._keys.forward = false;
+        break;
+      case 65: // a
+        this._keys.left = false;
+        break;
+      case 83: // s
+        this._keys.backward = false;
+        break;
+      case 68: // d
+        this._keys.right = false;
+        break;
+      case 32: // SPACE
+        this._keys.space = false;
+        break;
+      case 16: // SHIFT
+        this._keys.shift = false;
+        break;
+    }
+  }
+};
+
+
+class FiniteStateMachine {
+  constructor() {
+    this._states = {};
+    this._currentState = null;
+  }
+
+  _AddState(name, type) {
+    this._states[name] = type;
+  }
+
+  SetState(name) {
+    const prevState = this._currentState;
+    
+    if (prevState) {
+      if (prevState.Name == name) {
+        return;
+      }
+      prevState.Exit();
+    }
+
+    const state = new this._states[name](this);
+
+    this._currentState = state;
+    state.Enter(prevState);
+  }
+
+  Update(timeElapsed, input) {
+    if (this._currentState) {
+      this._currentState.Update(timeElapsed, input);
+    }
+  }
+};
+
+
+class CharacterFSM extends FiniteStateMachine {
+  constructor(proxy) {
+    super();
+    this._proxy = proxy;
+    this._Init();
+  }
+
+  _Init() {
+    this._AddState('idle', IdleState);
+    this._AddState('walk', WalkState);
+    this._AddState('run', RunState);
+    this._AddState('dance', DanceState);
+  }
+};
+
+
+class State {
+  constructor(parent) {
+    this._parent = parent;
+  }
+
+  Enter() {}
+  Exit() {}
+  Update() {}
+};
+
+
+class DanceState extends State {
+  constructor(parent) {
+    super(parent);
+
+    this._FinishedCallback = () => {
+      this._Finished();
+    }
+  }
+
+  get Name() {
+    return 'dance';
+  }
+
+  Enter(prevState) {
+    const curAction = this._parent._proxy._animations['dance'].action;
+    const mixer = curAction.getMixer();
+    mixer.addEventListener('finished', this._FinishedCallback);
+
+    if (prevState) {
+      const prevAction = this._parent._proxy._animations[prevState.Name].action;
+
+      curAction.reset();  
+      curAction.setLoop(THREE.LoopOnce, 1);
+      curAction.clampWhenFinished = true;
+      curAction.crossFadeFrom(prevAction, 0.2, true);
+      curAction.play();
+    } else {
+      curAction.play();
+    }
+  }
+
+  _Finished() {
+    this._Cleanup();
+    this._parent.SetState('idle');
+  }
+
+  _Cleanup() {
+    const action = this._parent._proxy._animations['dance'].action;
+    
+    action.getMixer().removeEventListener('finished', this._CleanupCallback);
+  }
+
+  Exit() {
+    this._Cleanup();
+  }
+
+  Update(_) {
+  }
+};
+
+
+class WalkState extends State {
+  constructor(parent) {
+    super(parent);
+  }
+
+  get Name() {
+    return 'walk';
+  }
+
+  Enter(prevState) {
+    const curAction = this._parent._proxy._animations['walk'].action;
+    if (prevState) {
+      const prevAction = this._parent._proxy._animations[prevState.Name].action;
+
+      curAction.enabled = true;
+
+      if (prevState.Name == 'run') {
+        const ratio = curAction.getClip().duration / prevAction.getClip().duration;
+        curAction.time = prevAction.time * ratio;
+      } else {
+        curAction.time = 0.0;
+        curAction.setEffectiveTimeScale(1.0);
+        curAction.setEffectiveWeight(1.0);
+      }
+
+      curAction.crossFadeFrom(prevAction, 0.5, true);
+      curAction.play();
+    } else {
+      curAction.play();
+    }
+  }
+
+  Exit() {
+  }
+
+  Update(timeElapsed, input) {
+    if (input._keys.forward || input._keys.backward) {
+      if (input._keys.shift) {
+        this._parent.SetState('run');
+      }
+      return;
+    }
+
+    this._parent.SetState('idle');
+  }
+};
+
+
+class RunState extends State {
+  constructor(parent) {
+    super(parent);
+  }
+
+  get Name() {
+    return 'run';
+  }
+
+  Enter(prevState) {
+    const curAction = this._parent._proxy._animations['run'].action;
+    if (prevState) {
+      const prevAction = this._parent._proxy._animations[prevState.Name].action;
+
+      curAction.enabled = true;
+
+      if (prevState.Name == 'walk') {
+        const ratio = curAction.getClip().duration / prevAction.getClip().duration;
+        curAction.time = prevAction.time * ratio;
+      } else {
+        curAction.time = 0.0;
+        curAction.setEffectiveTimeScale(1.0);
+        curAction.setEffectiveWeight(1.0);
+      }
+
+      curAction.crossFadeFrom(prevAction, 0.5, true);
+      curAction.play();
+    } else {
+      curAction.play();
+    }
+  }
+
+  Exit() {
+  }
+
+  Update(timeElapsed, input) {
+    if (input._keys.forward || input._keys.backward) {
+      if (!input._keys.shift) {
+        this._parent.SetState('walk');
+      }
+      return;
+    }
+
+    this._parent.SetState('idle');
+  }
+};
+
+
+class IdleState extends State {
+  constructor(parent) {
+    super(parent);
+  }
+
+  get Name() {
+    return 'idle';
+  }
+
+  Enter(prevState) {
+    const idleAction = this._parent._proxy._animations['idle'].action;
+    if (prevState) {
+      const prevAction = this._parent._proxy._animations[prevState.Name].action;
+      idleAction.time = 0.0;
+      idleAction.enabled = true;
+      idleAction.setEffectiveTimeScale(1.0);
+      idleAction.setEffectiveWeight(1.0);
+      idleAction.crossFadeFrom(prevAction, 0.5, true);
+      idleAction.play();
+    } else {
+      idleAction.play();
+    }
+  }
+
+  Exit() {
+  }
+
+  Update(_, input) {
+    if (input._keys.forward || input._keys.backward) {
+      this._parent.SetState('walk');
+    } else if (input._keys.space) {
+      this._parent.SetState('dance');
+    }
+  }
+};
+
+
+class CharacterControllerDemo {
+  constructor() {
+    this._Initialize();
+  }
+
+  _Initialize() {
+    this._threejs = new THREE.WebGLRenderer({
+      antialias: true,
+    });
+    this._threejs.outputEncoding = THREE.sRGBEncoding;
+    this._threejs.shadowMap.enabled = true;
+    this._threejs.shadowMap.type = THREE.PCFSoftShadowMap;
+    this._threejs.setPixelRatio(window.devicePixelRatio);
+    this._threejs.setSize(window.innerWidth, window.innerHeight);
+
+    document.body.appendChild(this._threejs.domElement);
+
+    window.addEventListener('resize', () => {
+      this._OnWindowResize();
+    }, false);
+
+    const fov = 60;
+    const aspect = 1920 / 1080;
+    const near = 1.0;
+    const far = 1000.0;
+    this._camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
+    this._camera.position.set(25, 10, 25);
+
+    this._scene = new THREE.Scene();
+
+    let light = new THREE.DirectionalLight(0xFFFFFF, 1.0);
+    light.position.set(-100, 100, 100);
+    light.target.position.set(0, 0, 0);
+    light.castShadow = true;
+    light.shadow.bias = -0.001;
+    light.shadow.mapSize.width = 4096;
+    light.shadow.mapSize.height = 4096;
+    light.shadow.camera.near = 0.1;
+    light.shadow.camera.far = 500.0;
+    light.shadow.camera.near = 0.5;
+    light.shadow.camera.far = 500.0;
+    light.shadow.camera.left = 50;
+    light.shadow.camera.right = -50;
+    light.shadow.camera.top = 50;
+    light.shadow.camera.bottom = -50;
+    this._scene.add(light);
+
+    light = new THREE.AmbientLight(0xFFFFFF, 0.25);
+    this._scene.add(light);
+
+    const controls = new OrbitControls(
+      this._camera, this._threejs.domElement);
+    controls.target.set(0, 10, 0);
+    controls.update();
+
+    const loader = new THREE.CubeTextureLoader();
+    const texture = loader.load([
+        './resources/posx.jpg',
+        './resources/negx.jpg',
+        './resources/posy.jpg',
+        './resources/negy.jpg',
+        './resources/posz.jpg',
+        './resources/negz.jpg',
+    ]);
+    texture.encoding = THREE.sRGBEncoding;
+    this._scene.background = texture;
+
+    const plane = new THREE.Mesh(
+        new THREE.PlaneGeometry(100, 100, 10, 10),
+        new THREE.MeshStandardMaterial({
+            color: 0x808080,
+          }));
+    plane.castShadow = false;
+    plane.receiveShadow = true;
+    plane.rotation.x = -Math.PI / 2;
+    this._scene.add(plane);
+
+    this._mixers = [];
+    this._previousRAF = null;
+
+    this._LoadAnimatedModel();
+    this._RAF();
+  }
+
+  _LoadAnimatedModel() {
+    const params = {
+      camera: this._camera,
+      scene: this._scene,
+    }
+    this._controls = new BasicCharacterController(params);
+  }
+
+  _LoadAnimatedModelAndPlay(path, modelFile, animFile, offset) {
+    const loader = new FBXLoader();
+    loader.setPath(path);
+    loader.load(modelFile, (fbx) => {
+      fbx.scale.setScalar(0.1);
+      fbx.traverse(c => {
+        c.castShadow = true;
+      });
+      fbx.position.copy(offset);
+
+      const anim = new FBXLoader();
+      anim.setPath(path);
+      anim.load(animFile, (anim) => {
+        const m = new THREE.AnimationMixer(fbx);
+        this._mixers.push(m);
+        const idle = m.clipAction(anim.animations[0]);
+        idle.play();
+      });
+      this._scene.add(fbx);
+    });
+  }
+
+  _LoadModel() {
+    const loader = new GLTFLoader();
+    loader.load('./resources/thing.glb', (gltf) => {
+      gltf.scene.traverse(c => {
+        c.castShadow = true;
+      });
+      this._scene.add(gltf.scene);
+    });
+  }
+
+  _OnWindowResize() {
+    this._camera.aspect = window.innerWidth / window.innerHeight;
+    this._camera.updateProjectionMatrix();
+    this._threejs.setSize(window.innerWidth, window.innerHeight);
+  }
+
+  _RAF() {
+    requestAnimationFrame((t) => {
+      if (this._previousRAF === null) {
+        this._previousRAF = t;
+      }
+
+      this._RAF();
+
+      this._threejs.render(this._scene, this._camera);
+      this._Step(t - this._previousRAF);
+      this._previousRAF = t;
+    });
+  }
+
+  _Step(timeElapsed) {
+    const timeElapsedS = timeElapsed * 0.001;
+    if (this._mixers) {
+      this._mixers.map(m => m.update(timeElapsedS));
+    }
+
+    if (this._controls) {
+      this._controls.Update(timeElapsedS);
+    }
+  }
+}
+
+
+let _APP = null;
+
+window.addEventListener('DOMContentLoaded', () => {
+  _APP = new CharacterControllerDemo();
+});

BIN
resources/dancer/Silly Dancing.fbx


BIN
resources/dancer/dance.fbx


BIN
resources/dancer/dancer.fbx


BIN
resources/dancer/girl.fbx


BIN
resources/negx.jpg


BIN
resources/negy.jpg


BIN
resources/negz.jpg


BIN
resources/posx.jpg


BIN
resources/posy.jpg


BIN
resources/posz.jpg


+ 13 - 0
resources/readme.txt

@@ -0,0 +1,13 @@
+Author
+======
+
+This is the work of Emil Persson, aka Humus.
+http://www.humus.name
+
+
+
+License
+=======
+
+This work is licensed under a Creative Commons Attribution 3.0 Unported License.
+http://creativecommons.org/licenses/by/3.0/

BIN
resources/rocket/Rocket_Ship_01.bin


+ 390 - 0
resources/rocket/Rocket_Ship_01.gltf

@@ -0,0 +1,390 @@
+{
+   "accessors" : [
+      {
+         "bufferView" : 0,
+         "componentType" : 5123,
+         "count" : 624,
+         "max" : [ 623 ],
+         "min" : [ 0 ],
+         "name" : "buffer-0-accessor-indices-buffer-0-mesh-0",
+         "type" : "SCALAR"
+      },
+      {
+         "bufferView" : 2,
+         "componentType" : 5126,
+         "count" : 624,
+         "max" : [ 3.294547080993652, 9.564169883728027, 3.294547080993652 ],
+         "min" : [ -3.294547080993652, 0, -3.294547080993652 ],
+         "name" : "buffer-0-accessor-position-buffer-0-mesh-0",
+         "type" : "VEC3"
+      },
+      {
+         "bufferView" : 2,
+         "byteOffset" : 7488,
+         "componentType" : 5126,
+         "count" : 624,
+         "max" : [ 1, 0.7847999930381775, 1 ],
+         "min" : [ -1, -0.9914000034332275, -1 ],
+         "name" : "buffer-0-accessor-normal-buffer-0-mesh-0",
+         "type" : "VEC3"
+      },
+      {
+         "bufferView" : 1,
+         "componentType" : 5126,
+         "count" : 0,
+         "max" : [ 0, 0 ],
+         "min" : [ 0, 0 ],
+         "name" : "buffer-0-accessor-texcoord-buffer-0-mesh-0",
+         "type" : "VEC2"
+      },
+      {
+         "bufferView" : 3,
+         "componentType" : 5126,
+         "count" : 0,
+         "max" : [ 0, 0, 0, 0 ],
+         "min" : [ 0, 0, 0, 0 ],
+         "name" : "buffer-0-accessor-color-buffer-0-mesh-0",
+         "type" : "VEC4"
+      },
+      {
+         "bufferView" : 0,
+         "byteOffset" : 1248,
+         "componentType" : 5123,
+         "count" : 240,
+         "max" : [ 239 ],
+         "min" : [ 0 ],
+         "name" : "buffer-0-accessor-indices-buffer-0-mesh-0",
+         "type" : "SCALAR"
+      },
+      {
+         "bufferView" : 2,
+         "byteOffset" : 14976,
+         "componentType" : 5126,
+         "count" : 240,
+         "max" : [ 1.958153963088989, 6.53810977935791, 1.958153963088989 ],
+         "min" : [ -1.958153963088989, 0, -1.958153963088989 ],
+         "name" : "buffer-0-accessor-position-buffer-0-mesh-0",
+         "type" : "VEC3"
+      },
+      {
+         "bufferView" : 2,
+         "byteOffset" : 17856,
+         "componentType" : 5126,
+         "count" : 240,
+         "max" : [ 0.9232000112533569, 0.1186000034213066, 0.9232000112533569 ],
+         "min" : [ -0.9232000112533569, -1, -0.9232000112533569 ],
+         "name" : "buffer-0-accessor-normal-buffer-0-mesh-0",
+         "type" : "VEC3"
+      },
+      {
+         "bufferView" : 1,
+         "componentType" : 5126,
+         "count" : 0,
+         "max" : [ 0, 0 ],
+         "min" : [ 0, 0 ],
+         "name" : "buffer-0-accessor-texcoord-buffer-0-mesh-0",
+         "type" : "VEC2"
+      },
+      {
+         "bufferView" : 3,
+         "componentType" : 5126,
+         "count" : 0,
+         "max" : [ 0, 0, 0, 0 ],
+         "min" : [ 0, 0, 0, 0 ],
+         "name" : "buffer-0-accessor-color-buffer-0-mesh-0",
+         "type" : "VEC4"
+      },
+      {
+         "bufferView" : 0,
+         "byteOffset" : 1728,
+         "componentType" : 5123,
+         "count" : 1056,
+         "max" : [ 1055 ],
+         "min" : [ 0 ],
+         "name" : "buffer-0-accessor-indices-buffer-0-mesh-0",
+         "type" : "SCALAR"
+      },
+      {
+         "bufferView" : 2,
+         "byteOffset" : 20736,
+         "componentType" : 5126,
+         "count" : 1056,
+         "max" : [ 2.062674045562744, 6.647388935089111, 2.062674045562744 ],
+         "min" : [ -2.062674045562744, 0, -2.062674045562744 ],
+         "name" : "buffer-0-accessor-position-buffer-0-mesh-0",
+         "type" : "VEC3"
+      },
+      {
+         "bufferView" : 2,
+         "byteOffset" : 33408,
+         "componentType" : 5126,
+         "count" : 1056,
+         "max" : [ 1, 1, 1 ],
+         "min" : [ -1, -1, -1 ],
+         "name" : "buffer-0-accessor-normal-buffer-0-mesh-0",
+         "type" : "VEC3"
+      },
+      {
+         "bufferView" : 1,
+         "componentType" : 5126,
+         "count" : 0,
+         "max" : [ 0, 0 ],
+         "min" : [ 0, 0 ],
+         "name" : "buffer-0-accessor-texcoord-buffer-0-mesh-0",
+         "type" : "VEC2"
+      },
+      {
+         "bufferView" : 3,
+         "componentType" : 5126,
+         "count" : 0,
+         "max" : [ 0, 0, 0, 0 ],
+         "min" : [ 0, 0, 0, 0 ],
+         "name" : "buffer-0-accessor-color-buffer-0-mesh-0",
+         "type" : "VEC4"
+      },
+      {
+         "bufferView" : 0,
+         "byteOffset" : 3840,
+         "componentType" : 5123,
+         "count" : 480,
+         "max" : [ 479 ],
+         "min" : [ 0 ],
+         "name" : "buffer-0-accessor-indices-buffer-0-mesh-0",
+         "type" : "SCALAR"
+      },
+      {
+         "bufferView" : 2,
+         "byteOffset" : 46080,
+         "componentType" : 5126,
+         "count" : 480,
+         "max" : [ 0.8525949716567993, 9.915228843688965, 0.8525949716567993 ],
+         "min" : [ -0.8525949716567993, 0, -0.8525949716567993 ],
+         "name" : "buffer-0-accessor-position-buffer-0-mesh-0",
+         "type" : "VEC3"
+      },
+      {
+         "bufferView" : 2,
+         "byteOffset" : 51840,
+         "componentType" : 5126,
+         "count" : 480,
+         "max" : [ 0.9239000082015991, 0.9775999784469604, 0.9239000082015991 ],
+         "min" : [ -0.9239000082015991, -1, -0.9239000082015991 ],
+         "name" : "buffer-0-accessor-normal-buffer-0-mesh-0",
+         "type" : "VEC3"
+      },
+      {
+         "bufferView" : 1,
+         "componentType" : 5126,
+         "count" : 0,
+         "max" : [ 0, 0 ],
+         "min" : [ 0, 0 ],
+         "name" : "buffer-0-accessor-texcoord-buffer-0-mesh-0",
+         "type" : "VEC2"
+      },
+      {
+         "bufferView" : 3,
+         "componentType" : 5126,
+         "count" : 0,
+         "max" : [ 0, 0, 0, 0 ],
+         "min" : [ 0, 0, 0, 0 ],
+         "name" : "buffer-0-accessor-color-buffer-0-mesh-0",
+         "type" : "VEC4"
+      },
+      {
+         "bufferView" : 0,
+         "byteOffset" : 4800,
+         "componentType" : 5123,
+         "count" : 96,
+         "max" : [ 95 ],
+         "min" : [ 0 ],
+         "name" : "buffer-0-accessor-indices-buffer-0-mesh-0",
+         "type" : "SCALAR"
+      },
+      {
+         "bufferView" : 2,
+         "byteOffset" : 57600,
+         "componentType" : 5126,
+         "count" : 96,
+         "max" : [ 1.929389953613281, 5.365962982177734, 1.92612898349762 ],
+         "min" : [ -1.929389953613281, 0, -1.92612898349762 ],
+         "name" : "buffer-0-accessor-position-buffer-0-mesh-0",
+         "type" : "VEC3"
+      },
+      {
+         "bufferView" : 2,
+         "byteOffset" : 58752,
+         "componentType" : 5126,
+         "count" : 96,
+         "max" : [ 1, 0, 1 ],
+         "min" : [ -1, 0, -1 ],
+         "name" : "buffer-0-accessor-normal-buffer-0-mesh-0",
+         "type" : "VEC3"
+      },
+      {
+         "bufferView" : 1,
+         "componentType" : 5126,
+         "count" : 0,
+         "max" : [ 0, 0 ],
+         "min" : [ 0, 0 ],
+         "name" : "buffer-0-accessor-texcoord-buffer-0-mesh-0",
+         "type" : "VEC2"
+      },
+      {
+         "bufferView" : 3,
+         "componentType" : 5126,
+         "count" : 0,
+         "max" : [ 0, 0, 0, 0 ],
+         "min" : [ 0, 0, 0, 0 ],
+         "name" : "buffer-0-accessor-color-buffer-0-mesh-0",
+         "type" : "VEC4"
+      }
+   ],
+   "asset" : {
+      "generator" : "Obj2GltfConverter",
+      "version" : "2.0"
+   },
+   "bufferViews" : [
+      {
+         "buffer" : 0,
+         "byteLength" : 4992,
+         "byteStride" : 0,
+         "name" : "buffer-0-bufferview-ushort",
+         "target" : 34963
+      },
+      {
+         "buffer" : 0,
+         "byteLength" : 1,
+         "name" : "buffer-0-bufferview-vec2"
+      },
+      {
+         "buffer" : 0,
+         "byteLength" : 59904,
+         "byteOffset" : 4992,
+         "byteStride" : 12,
+         "name" : "buffer-0-bufferview-vec3",
+         "target" : 34962
+      },
+      {
+         "buffer" : 0,
+         "byteLength" : 1,
+         "name" : "buffer-0-bufferview-vec4"
+      }
+   ],
+   "buffers" : [
+      {
+         "byteLength" : 64896,
+         "name" : "buffer-0",
+         "uri" : "Rocket_Ship_01.bin"
+      }
+   ],
+   "materials" : [
+      {
+         "doubleSided" : true,
+         "name" : "F44336",
+         "pbrMetallicRoughness" : {
+            "baseColorFactor" : [ 0.956863, 0.262745, 0.211765, 1 ],
+            "metallicFactor" : 0,
+            "roughnessFactor" : 0.7448017359246658
+         }
+      },
+      {
+         "doubleSided" : true,
+         "name" : "FFFFFF",
+         "pbrMetallicRoughness" : {
+            "metallicFactor" : 0,
+            "roughnessFactor" : 0.7448017359246658
+         }
+      },
+      {
+         "doubleSided" : true,
+         "name" : "455A64",
+         "pbrMetallicRoughness" : {
+            "baseColorFactor" : [ 0.270588, 0.352941, 0.392157, 1 ],
+            "metallicFactor" : 0,
+            "roughnessFactor" : 0.7448017359246658
+         }
+      },
+      {
+         "doubleSided" : true,
+         "name" : "78909C",
+         "pbrMetallicRoughness" : {
+            "baseColorFactor" : [ 0.470588, 0.564706, 0.611765, 1 ],
+            "metallicFactor" : 0,
+            "roughnessFactor" : 0.7448017359246658
+         }
+      },
+      {
+         "doubleSided" : true,
+         "name" : "80DEEA",
+         "pbrMetallicRoughness" : {
+            "baseColorFactor" : [ 0.501961, 0.870588, 0.917647, 1 ],
+            "metallicFactor" : 0,
+            "roughnessFactor" : 0.7448017359246658
+         }
+      }
+   ],
+   "meshes" : [
+      {
+         "name" : "buffer-0-mesh-0",
+         "primitives" : [
+            {
+               "attributes" : {
+                  "NORMAL" : 2,
+                  "POSITION" : 1,
+                  "TEXCOORD_0" : 3
+               },
+               "indices" : 0,
+               "material" : 0
+            },
+            {
+               "attributes" : {
+                  "NORMAL" : 7,
+                  "POSITION" : 6,
+                  "TEXCOORD_0" : 8
+               },
+               "indices" : 5,
+               "material" : 1
+            },
+            {
+               "attributes" : {
+                  "NORMAL" : 12,
+                  "POSITION" : 11,
+                  "TEXCOORD_0" : 13
+               },
+               "indices" : 10,
+               "material" : 2
+            },
+            {
+               "attributes" : {
+                  "NORMAL" : 17,
+                  "POSITION" : 16,
+                  "TEXCOORD_0" : 18
+               },
+               "indices" : 15,
+               "material" : 3
+            },
+            {
+               "attributes" : {
+                  "NORMAL" : 22,
+                  "POSITION" : 21,
+                  "TEXCOORD_0" : 23
+               },
+               "indices" : 20,
+               "material" : 4
+            }
+         ]
+      }
+   ],
+   "nodes" : [
+      {
+         "mesh" : 0,
+         "name" : "node-0"
+      }
+   ],
+   "scenes" : [
+      {
+         "name" : "scene-0",
+         "nodes" : [ 0 ]
+      }
+   ]
+}

BIN
resources/thing.glb


BIN
resources/zombie/dance.fbx


BIN
resources/zombie/hiphop.fbx


BIN
resources/zombie/idle.fbx


BIN
resources/zombie/mremireh_o_desbiens.fbx


BIN
resources/zombie/run.fbx


BIN
resources/zombie/walk.fbx