├── LICENSE
├── base.css
├── index.html
├── main.js
└── resources
├── dancer
├── Silly Dancing.fbx
├── dance.fbx
├── dancer.fbx
└── girl.fbx
├── negx.jpg
├── negy.jpg
├── negz.jpg
├── posx.jpg
├── posy.jpg
├── posz.jpg
├── readme.txt
├── rocket
├── Rocket_Ship_01.bin
└── Rocket_Ship_01.gltf
├── thing.glb
└── zombie
├── dance.fbx
├── hiphop.fbx
├── idle.fbx
├── mremireh_o_desbiens.fbx
├── run.fbx
└── walk.fbx
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 simondevyoutube
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/base.css:
--------------------------------------------------------------------------------
1 | body {
2 | width: 100%;
3 | height: 100%;
4 | position: absolute;
5 | background: #000000;
6 | margin: 0;
7 | padding: 0;
8 | overscroll-behavior: none;
9 | }
10 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Three.JS Tutorial: Character Controller
5 |
6 |
7 |
8 |
9 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/main.js:
--------------------------------------------------------------------------------
1 | import * as THREE from 'https://cdn.jsdelivr.net/npm/three@0.118/build/three.module.js';
2 |
3 | import {FBXLoader} from 'https://cdn.jsdelivr.net/npm/three@0.118.1/examples/jsm/loaders/FBXLoader.js';
4 | import {GLTFLoader} from 'https://cdn.jsdelivr.net/npm/three@0.118.1/examples/jsm/loaders/GLTFLoader.js';
5 | import {OrbitControls} from 'https://cdn.jsdelivr.net/npm/three@0.118/examples/jsm/controls/OrbitControls.js';
6 |
7 |
8 | class BasicCharacterControllerProxy {
9 | constructor(animations) {
10 | this._animations = animations;
11 | }
12 |
13 | get animations() {
14 | return this._animations;
15 | }
16 | };
17 |
18 |
19 | class BasicCharacterController {
20 | constructor(params) {
21 | this._Init(params);
22 | }
23 |
24 | _Init(params) {
25 | this._params = params;
26 | this._decceleration = new THREE.Vector3(-0.0005, -0.0001, -5.0);
27 | this._acceleration = new THREE.Vector3(1, 0.25, 50.0);
28 | this._velocity = new THREE.Vector3(0, 0, 0);
29 |
30 | this._animations = {};
31 | this._input = new BasicCharacterControllerInput();
32 | this._stateMachine = new CharacterFSM(
33 | new BasicCharacterControllerProxy(this._animations));
34 |
35 | this._LoadModels();
36 | }
37 |
38 | _LoadModels() {
39 | const loader = new FBXLoader();
40 | loader.setPath('./resources/zombie/');
41 | loader.load('mremireh_o_desbiens.fbx', (fbx) => {
42 | fbx.scale.setScalar(0.1);
43 | fbx.traverse(c => {
44 | c.castShadow = true;
45 | });
46 |
47 | this._target = fbx;
48 | this._params.scene.add(this._target);
49 |
50 | this._mixer = new THREE.AnimationMixer(this._target);
51 |
52 | this._manager = new THREE.LoadingManager();
53 | this._manager.onLoad = () => {
54 | this._stateMachine.SetState('idle');
55 | };
56 |
57 | const _OnLoad = (animName, anim) => {
58 | const clip = anim.animations[0];
59 | const action = this._mixer.clipAction(clip);
60 |
61 | this._animations[animName] = {
62 | clip: clip,
63 | action: action,
64 | };
65 | };
66 |
67 | const loader = new FBXLoader(this._manager);
68 | loader.setPath('./resources/zombie/');
69 | loader.load('walk.fbx', (a) => { _OnLoad('walk', a); });
70 | loader.load('run.fbx', (a) => { _OnLoad('run', a); });
71 | loader.load('idle.fbx', (a) => { _OnLoad('idle', a); });
72 | loader.load('dance.fbx', (a) => { _OnLoad('dance', a); });
73 | });
74 | }
75 |
76 | Update(timeInSeconds) {
77 | if (!this._target) {
78 | return;
79 | }
80 |
81 | this._stateMachine.Update(timeInSeconds, this._input);
82 |
83 | const velocity = this._velocity;
84 | const frameDecceleration = new THREE.Vector3(
85 | velocity.x * this._decceleration.x,
86 | velocity.y * this._decceleration.y,
87 | velocity.z * this._decceleration.z
88 | );
89 | frameDecceleration.multiplyScalar(timeInSeconds);
90 | frameDecceleration.z = Math.sign(frameDecceleration.z) * Math.min(
91 | Math.abs(frameDecceleration.z), Math.abs(velocity.z));
92 |
93 | velocity.add(frameDecceleration);
94 |
95 | const controlObject = this._target;
96 | const _Q = new THREE.Quaternion();
97 | const _A = new THREE.Vector3();
98 | const _R = controlObject.quaternion.clone();
99 |
100 | const acc = this._acceleration.clone();
101 | if (this._input._keys.shift) {
102 | acc.multiplyScalar(2.0);
103 | }
104 |
105 | if (this._stateMachine._currentState.Name == 'dance') {
106 | acc.multiplyScalar(0.0);
107 | }
108 |
109 | if (this._input._keys.forward) {
110 | velocity.z += acc.z * timeInSeconds;
111 | }
112 | if (this._input._keys.backward) {
113 | velocity.z -= acc.z * timeInSeconds;
114 | }
115 | if (this._input._keys.left) {
116 | _A.set(0, 1, 0);
117 | _Q.setFromAxisAngle(_A, 4.0 * Math.PI * timeInSeconds * this._acceleration.y);
118 | _R.multiply(_Q);
119 | }
120 | if (this._input._keys.right) {
121 | _A.set(0, 1, 0);
122 | _Q.setFromAxisAngle(_A, 4.0 * -Math.PI * timeInSeconds * this._acceleration.y);
123 | _R.multiply(_Q);
124 | }
125 |
126 | controlObject.quaternion.copy(_R);
127 |
128 | const oldPosition = new THREE.Vector3();
129 | oldPosition.copy(controlObject.position);
130 |
131 | const forward = new THREE.Vector3(0, 0, 1);
132 | forward.applyQuaternion(controlObject.quaternion);
133 | forward.normalize();
134 |
135 | const sideways = new THREE.Vector3(1, 0, 0);
136 | sideways.applyQuaternion(controlObject.quaternion);
137 | sideways.normalize();
138 |
139 | sideways.multiplyScalar(velocity.x * timeInSeconds);
140 | forward.multiplyScalar(velocity.z * timeInSeconds);
141 |
142 | controlObject.position.add(forward);
143 | controlObject.position.add(sideways);
144 |
145 | oldPosition.copy(controlObject.position);
146 |
147 | if (this._mixer) {
148 | this._mixer.update(timeInSeconds);
149 | }
150 | }
151 | };
152 |
153 | class BasicCharacterControllerInput {
154 | constructor() {
155 | this._Init();
156 | }
157 |
158 | _Init() {
159 | this._keys = {
160 | forward: false,
161 | backward: false,
162 | left: false,
163 | right: false,
164 | space: false,
165 | shift: false,
166 | };
167 | document.addEventListener('keydown', (e) => this._onKeyDown(e), false);
168 | document.addEventListener('keyup', (e) => this._onKeyUp(e), false);
169 | }
170 |
171 | _onKeyDown(event) {
172 | switch (event.keyCode) {
173 | case 87: // w
174 | this._keys.forward = true;
175 | break;
176 | case 65: // a
177 | this._keys.left = true;
178 | break;
179 | case 83: // s
180 | this._keys.backward = true;
181 | break;
182 | case 68: // d
183 | this._keys.right = true;
184 | break;
185 | case 32: // SPACE
186 | this._keys.space = true;
187 | break;
188 | case 16: // SHIFT
189 | this._keys.shift = true;
190 | break;
191 | }
192 | }
193 |
194 | _onKeyUp(event) {
195 | switch(event.keyCode) {
196 | case 87: // w
197 | this._keys.forward = false;
198 | break;
199 | case 65: // a
200 | this._keys.left = false;
201 | break;
202 | case 83: // s
203 | this._keys.backward = false;
204 | break;
205 | case 68: // d
206 | this._keys.right = false;
207 | break;
208 | case 32: // SPACE
209 | this._keys.space = false;
210 | break;
211 | case 16: // SHIFT
212 | this._keys.shift = false;
213 | break;
214 | }
215 | }
216 | };
217 |
218 |
219 | class FiniteStateMachine {
220 | constructor() {
221 | this._states = {};
222 | this._currentState = null;
223 | }
224 |
225 | _AddState(name, type) {
226 | this._states[name] = type;
227 | }
228 |
229 | SetState(name) {
230 | const prevState = this._currentState;
231 |
232 | if (prevState) {
233 | if (prevState.Name == name) {
234 | return;
235 | }
236 | prevState.Exit();
237 | }
238 |
239 | const state = new this._states[name](this);
240 |
241 | this._currentState = state;
242 | state.Enter(prevState);
243 | }
244 |
245 | Update(timeElapsed, input) {
246 | if (this._currentState) {
247 | this._currentState.Update(timeElapsed, input);
248 | }
249 | }
250 | };
251 |
252 |
253 | class CharacterFSM extends FiniteStateMachine {
254 | constructor(proxy) {
255 | super();
256 | this._proxy = proxy;
257 | this._Init();
258 | }
259 |
260 | _Init() {
261 | this._AddState('idle', IdleState);
262 | this._AddState('walk', WalkState);
263 | this._AddState('run', RunState);
264 | this._AddState('dance', DanceState);
265 | }
266 | };
267 |
268 |
269 | class State {
270 | constructor(parent) {
271 | this._parent = parent;
272 | }
273 |
274 | Enter() {}
275 | Exit() {}
276 | Update() {}
277 | };
278 |
279 |
280 | class DanceState extends State {
281 | constructor(parent) {
282 | super(parent);
283 |
284 | this._FinishedCallback = () => {
285 | this._Finished();
286 | }
287 | }
288 |
289 | get Name() {
290 | return 'dance';
291 | }
292 |
293 | Enter(prevState) {
294 | const curAction = this._parent._proxy._animations['dance'].action;
295 | const mixer = curAction.getMixer();
296 | mixer.addEventListener('finished', this._FinishedCallback);
297 |
298 | if (prevState) {
299 | const prevAction = this._parent._proxy._animations[prevState.Name].action;
300 |
301 | curAction.reset();
302 | curAction.setLoop(THREE.LoopOnce, 1);
303 | curAction.clampWhenFinished = true;
304 | curAction.crossFadeFrom(prevAction, 0.2, true);
305 | curAction.play();
306 | } else {
307 | curAction.play();
308 | }
309 | }
310 |
311 | _Finished() {
312 | this._Cleanup();
313 | this._parent.SetState('idle');
314 | }
315 |
316 | _Cleanup() {
317 | const action = this._parent._proxy._animations['dance'].action;
318 |
319 | action.getMixer().removeEventListener('finished', this._CleanupCallback);
320 | }
321 |
322 | Exit() {
323 | this._Cleanup();
324 | }
325 |
326 | Update(_) {
327 | }
328 | };
329 |
330 |
331 | class WalkState extends State {
332 | constructor(parent) {
333 | super(parent);
334 | }
335 |
336 | get Name() {
337 | return 'walk';
338 | }
339 |
340 | Enter(prevState) {
341 | const curAction = this._parent._proxy._animations['walk'].action;
342 | if (prevState) {
343 | const prevAction = this._parent._proxy._animations[prevState.Name].action;
344 |
345 | curAction.enabled = true;
346 |
347 | if (prevState.Name == 'run') {
348 | const ratio = curAction.getClip().duration / prevAction.getClip().duration;
349 | curAction.time = prevAction.time * ratio;
350 | } else {
351 | curAction.time = 0.0;
352 | curAction.setEffectiveTimeScale(1.0);
353 | curAction.setEffectiveWeight(1.0);
354 | }
355 |
356 | curAction.crossFadeFrom(prevAction, 0.5, true);
357 | curAction.play();
358 | } else {
359 | curAction.play();
360 | }
361 | }
362 |
363 | Exit() {
364 | }
365 |
366 | Update(timeElapsed, input) {
367 | if (input._keys.forward || input._keys.backward) {
368 | if (input._keys.shift) {
369 | this._parent.SetState('run');
370 | }
371 | return;
372 | }
373 |
374 | this._parent.SetState('idle');
375 | }
376 | };
377 |
378 |
379 | class RunState extends State {
380 | constructor(parent) {
381 | super(parent);
382 | }
383 |
384 | get Name() {
385 | return 'run';
386 | }
387 |
388 | Enter(prevState) {
389 | const curAction = this._parent._proxy._animations['run'].action;
390 | if (prevState) {
391 | const prevAction = this._parent._proxy._animations[prevState.Name].action;
392 |
393 | curAction.enabled = true;
394 |
395 | if (prevState.Name == 'walk') {
396 | const ratio = curAction.getClip().duration / prevAction.getClip().duration;
397 | curAction.time = prevAction.time * ratio;
398 | } else {
399 | curAction.time = 0.0;
400 | curAction.setEffectiveTimeScale(1.0);
401 | curAction.setEffectiveWeight(1.0);
402 | }
403 |
404 | curAction.crossFadeFrom(prevAction, 0.5, true);
405 | curAction.play();
406 | } else {
407 | curAction.play();
408 | }
409 | }
410 |
411 | Exit() {
412 | }
413 |
414 | Update(timeElapsed, input) {
415 | if (input._keys.forward || input._keys.backward) {
416 | if (!input._keys.shift) {
417 | this._parent.SetState('walk');
418 | }
419 | return;
420 | }
421 |
422 | this._parent.SetState('idle');
423 | }
424 | };
425 |
426 |
427 | class IdleState extends State {
428 | constructor(parent) {
429 | super(parent);
430 | }
431 |
432 | get Name() {
433 | return 'idle';
434 | }
435 |
436 | Enter(prevState) {
437 | const idleAction = this._parent._proxy._animations['idle'].action;
438 | if (prevState) {
439 | const prevAction = this._parent._proxy._animations[prevState.Name].action;
440 | idleAction.time = 0.0;
441 | idleAction.enabled = true;
442 | idleAction.setEffectiveTimeScale(1.0);
443 | idleAction.setEffectiveWeight(1.0);
444 | idleAction.crossFadeFrom(prevAction, 0.5, true);
445 | idleAction.play();
446 | } else {
447 | idleAction.play();
448 | }
449 | }
450 |
451 | Exit() {
452 | }
453 |
454 | Update(_, input) {
455 | if (input._keys.forward || input._keys.backward) {
456 | this._parent.SetState('walk');
457 | } else if (input._keys.space) {
458 | this._parent.SetState('dance');
459 | }
460 | }
461 | };
462 |
463 |
464 | class CharacterControllerDemo {
465 | constructor() {
466 | this._Initialize();
467 | }
468 |
469 | _Initialize() {
470 | this._threejs = new THREE.WebGLRenderer({
471 | antialias: true,
472 | });
473 | this._threejs.outputEncoding = THREE.sRGBEncoding;
474 | this._threejs.shadowMap.enabled = true;
475 | this._threejs.shadowMap.type = THREE.PCFSoftShadowMap;
476 | this._threejs.setPixelRatio(window.devicePixelRatio);
477 | this._threejs.setSize(window.innerWidth, window.innerHeight);
478 |
479 | document.body.appendChild(this._threejs.domElement);
480 |
481 | window.addEventListener('resize', () => {
482 | this._OnWindowResize();
483 | }, false);
484 |
485 | const fov = 60;
486 | const aspect = 1920 / 1080;
487 | const near = 1.0;
488 | const far = 1000.0;
489 | this._camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
490 | this._camera.position.set(25, 10, 25);
491 |
492 | this._scene = new THREE.Scene();
493 |
494 | let light = new THREE.DirectionalLight(0xFFFFFF, 1.0);
495 | light.position.set(-100, 100, 100);
496 | light.target.position.set(0, 0, 0);
497 | light.castShadow = true;
498 | light.shadow.bias = -0.001;
499 | light.shadow.mapSize.width = 4096;
500 | light.shadow.mapSize.height = 4096;
501 | light.shadow.camera.near = 0.1;
502 | light.shadow.camera.far = 500.0;
503 | light.shadow.camera.near = 0.5;
504 | light.shadow.camera.far = 500.0;
505 | light.shadow.camera.left = 50;
506 | light.shadow.camera.right = -50;
507 | light.shadow.camera.top = 50;
508 | light.shadow.camera.bottom = -50;
509 | this._scene.add(light);
510 |
511 | light = new THREE.AmbientLight(0xFFFFFF, 0.25);
512 | this._scene.add(light);
513 |
514 | const controls = new OrbitControls(
515 | this._camera, this._threejs.domElement);
516 | controls.target.set(0, 10, 0);
517 | controls.update();
518 |
519 | const loader = new THREE.CubeTextureLoader();
520 | const texture = loader.load([
521 | './resources/posx.jpg',
522 | './resources/negx.jpg',
523 | './resources/posy.jpg',
524 | './resources/negy.jpg',
525 | './resources/posz.jpg',
526 | './resources/negz.jpg',
527 | ]);
528 | texture.encoding = THREE.sRGBEncoding;
529 | this._scene.background = texture;
530 |
531 | const plane = new THREE.Mesh(
532 | new THREE.PlaneGeometry(100, 100, 10, 10),
533 | new THREE.MeshStandardMaterial({
534 | color: 0x808080,
535 | }));
536 | plane.castShadow = false;
537 | plane.receiveShadow = true;
538 | plane.rotation.x = -Math.PI / 2;
539 | this._scene.add(plane);
540 |
541 | this._mixers = [];
542 | this._previousRAF = null;
543 |
544 | this._LoadAnimatedModel();
545 | this._RAF();
546 | }
547 |
548 | _LoadAnimatedModel() {
549 | const params = {
550 | camera: this._camera,
551 | scene: this._scene,
552 | }
553 | this._controls = new BasicCharacterController(params);
554 | }
555 |
556 | _LoadAnimatedModelAndPlay(path, modelFile, animFile, offset) {
557 | const loader = new FBXLoader();
558 | loader.setPath(path);
559 | loader.load(modelFile, (fbx) => {
560 | fbx.scale.setScalar(0.1);
561 | fbx.traverse(c => {
562 | c.castShadow = true;
563 | });
564 | fbx.position.copy(offset);
565 |
566 | const anim = new FBXLoader();
567 | anim.setPath(path);
568 | anim.load(animFile, (anim) => {
569 | const m = new THREE.AnimationMixer(fbx);
570 | this._mixers.push(m);
571 | const idle = m.clipAction(anim.animations[0]);
572 | idle.play();
573 | });
574 | this._scene.add(fbx);
575 | });
576 | }
577 |
578 | _LoadModel() {
579 | const loader = new GLTFLoader();
580 | loader.load('./resources/thing.glb', (gltf) => {
581 | gltf.scene.traverse(c => {
582 | c.castShadow = true;
583 | });
584 | this._scene.add(gltf.scene);
585 | });
586 | }
587 |
588 | _OnWindowResize() {
589 | this._camera.aspect = window.innerWidth / window.innerHeight;
590 | this._camera.updateProjectionMatrix();
591 | this._threejs.setSize(window.innerWidth, window.innerHeight);
592 | }
593 |
594 | _RAF() {
595 | requestAnimationFrame((t) => {
596 | if (this._previousRAF === null) {
597 | this._previousRAF = t;
598 | }
599 |
600 | this._RAF();
601 |
602 | this._threejs.render(this._scene, this._camera);
603 | this._Step(t - this._previousRAF);
604 | this._previousRAF = t;
605 | });
606 | }
607 |
608 | _Step(timeElapsed) {
609 | const timeElapsedS = timeElapsed * 0.001;
610 | if (this._mixers) {
611 | this._mixers.map(m => m.update(timeElapsedS));
612 | }
613 |
614 | if (this._controls) {
615 | this._controls.Update(timeElapsedS);
616 | }
617 | }
618 | }
619 |
620 |
621 | let _APP = null;
622 |
623 | window.addEventListener('DOMContentLoaded', () => {
624 | _APP = new CharacterControllerDemo();
625 | });
626 |
--------------------------------------------------------------------------------
/resources/dancer/Silly Dancing.fbx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simondevyoutube/ThreeJS_Tutorial_CharacterController/b149e694e68791be0a11eff568cf9cafcb1b3e65/resources/dancer/Silly Dancing.fbx
--------------------------------------------------------------------------------
/resources/dancer/dance.fbx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simondevyoutube/ThreeJS_Tutorial_CharacterController/b149e694e68791be0a11eff568cf9cafcb1b3e65/resources/dancer/dance.fbx
--------------------------------------------------------------------------------
/resources/dancer/dancer.fbx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simondevyoutube/ThreeJS_Tutorial_CharacterController/b149e694e68791be0a11eff568cf9cafcb1b3e65/resources/dancer/dancer.fbx
--------------------------------------------------------------------------------
/resources/dancer/girl.fbx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simondevyoutube/ThreeJS_Tutorial_CharacterController/b149e694e68791be0a11eff568cf9cafcb1b3e65/resources/dancer/girl.fbx
--------------------------------------------------------------------------------
/resources/negx.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simondevyoutube/ThreeJS_Tutorial_CharacterController/b149e694e68791be0a11eff568cf9cafcb1b3e65/resources/negx.jpg
--------------------------------------------------------------------------------
/resources/negy.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simondevyoutube/ThreeJS_Tutorial_CharacterController/b149e694e68791be0a11eff568cf9cafcb1b3e65/resources/negy.jpg
--------------------------------------------------------------------------------
/resources/negz.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simondevyoutube/ThreeJS_Tutorial_CharacterController/b149e694e68791be0a11eff568cf9cafcb1b3e65/resources/negz.jpg
--------------------------------------------------------------------------------
/resources/posx.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simondevyoutube/ThreeJS_Tutorial_CharacterController/b149e694e68791be0a11eff568cf9cafcb1b3e65/resources/posx.jpg
--------------------------------------------------------------------------------
/resources/posy.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simondevyoutube/ThreeJS_Tutorial_CharacterController/b149e694e68791be0a11eff568cf9cafcb1b3e65/resources/posy.jpg
--------------------------------------------------------------------------------
/resources/posz.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simondevyoutube/ThreeJS_Tutorial_CharacterController/b149e694e68791be0a11eff568cf9cafcb1b3e65/resources/posz.jpg
--------------------------------------------------------------------------------
/resources/readme.txt:
--------------------------------------------------------------------------------
1 | Author
2 | ======
3 |
4 | This is the work of Emil Persson, aka Humus.
5 | http://www.humus.name
6 |
7 |
8 |
9 | License
10 | =======
11 |
12 | This work is licensed under a Creative Commons Attribution 3.0 Unported License.
13 | http://creativecommons.org/licenses/by/3.0/
14 |
--------------------------------------------------------------------------------
/resources/rocket/Rocket_Ship_01.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simondevyoutube/ThreeJS_Tutorial_CharacterController/b149e694e68791be0a11eff568cf9cafcb1b3e65/resources/rocket/Rocket_Ship_01.bin
--------------------------------------------------------------------------------
/resources/rocket/Rocket_Ship_01.gltf:
--------------------------------------------------------------------------------
1 | {
2 | "accessors" : [
3 | {
4 | "bufferView" : 0,
5 | "componentType" : 5123,
6 | "count" : 624,
7 | "max" : [ 623 ],
8 | "min" : [ 0 ],
9 | "name" : "buffer-0-accessor-indices-buffer-0-mesh-0",
10 | "type" : "SCALAR"
11 | },
12 | {
13 | "bufferView" : 2,
14 | "componentType" : 5126,
15 | "count" : 624,
16 | "max" : [ 3.294547080993652, 9.564169883728027, 3.294547080993652 ],
17 | "min" : [ -3.294547080993652, 0, -3.294547080993652 ],
18 | "name" : "buffer-0-accessor-position-buffer-0-mesh-0",
19 | "type" : "VEC3"
20 | },
21 | {
22 | "bufferView" : 2,
23 | "byteOffset" : 7488,
24 | "componentType" : 5126,
25 | "count" : 624,
26 | "max" : [ 1, 0.7847999930381775, 1 ],
27 | "min" : [ -1, -0.9914000034332275, -1 ],
28 | "name" : "buffer-0-accessor-normal-buffer-0-mesh-0",
29 | "type" : "VEC3"
30 | },
31 | {
32 | "bufferView" : 1,
33 | "componentType" : 5126,
34 | "count" : 0,
35 | "max" : [ 0, 0 ],
36 | "min" : [ 0, 0 ],
37 | "name" : "buffer-0-accessor-texcoord-buffer-0-mesh-0",
38 | "type" : "VEC2"
39 | },
40 | {
41 | "bufferView" : 3,
42 | "componentType" : 5126,
43 | "count" : 0,
44 | "max" : [ 0, 0, 0, 0 ],
45 | "min" : [ 0, 0, 0, 0 ],
46 | "name" : "buffer-0-accessor-color-buffer-0-mesh-0",
47 | "type" : "VEC4"
48 | },
49 | {
50 | "bufferView" : 0,
51 | "byteOffset" : 1248,
52 | "componentType" : 5123,
53 | "count" : 240,
54 | "max" : [ 239 ],
55 | "min" : [ 0 ],
56 | "name" : "buffer-0-accessor-indices-buffer-0-mesh-0",
57 | "type" : "SCALAR"
58 | },
59 | {
60 | "bufferView" : 2,
61 | "byteOffset" : 14976,
62 | "componentType" : 5126,
63 | "count" : 240,
64 | "max" : [ 1.958153963088989, 6.53810977935791, 1.958153963088989 ],
65 | "min" : [ -1.958153963088989, 0, -1.958153963088989 ],
66 | "name" : "buffer-0-accessor-position-buffer-0-mesh-0",
67 | "type" : "VEC3"
68 | },
69 | {
70 | "bufferView" : 2,
71 | "byteOffset" : 17856,
72 | "componentType" : 5126,
73 | "count" : 240,
74 | "max" : [ 0.9232000112533569, 0.1186000034213066, 0.9232000112533569 ],
75 | "min" : [ -0.9232000112533569, -1, -0.9232000112533569 ],
76 | "name" : "buffer-0-accessor-normal-buffer-0-mesh-0",
77 | "type" : "VEC3"
78 | },
79 | {
80 | "bufferView" : 1,
81 | "componentType" : 5126,
82 | "count" : 0,
83 | "max" : [ 0, 0 ],
84 | "min" : [ 0, 0 ],
85 | "name" : "buffer-0-accessor-texcoord-buffer-0-mesh-0",
86 | "type" : "VEC2"
87 | },
88 | {
89 | "bufferView" : 3,
90 | "componentType" : 5126,
91 | "count" : 0,
92 | "max" : [ 0, 0, 0, 0 ],
93 | "min" : [ 0, 0, 0, 0 ],
94 | "name" : "buffer-0-accessor-color-buffer-0-mesh-0",
95 | "type" : "VEC4"
96 | },
97 | {
98 | "bufferView" : 0,
99 | "byteOffset" : 1728,
100 | "componentType" : 5123,
101 | "count" : 1056,
102 | "max" : [ 1055 ],
103 | "min" : [ 0 ],
104 | "name" : "buffer-0-accessor-indices-buffer-0-mesh-0",
105 | "type" : "SCALAR"
106 | },
107 | {
108 | "bufferView" : 2,
109 | "byteOffset" : 20736,
110 | "componentType" : 5126,
111 | "count" : 1056,
112 | "max" : [ 2.062674045562744, 6.647388935089111, 2.062674045562744 ],
113 | "min" : [ -2.062674045562744, 0, -2.062674045562744 ],
114 | "name" : "buffer-0-accessor-position-buffer-0-mesh-0",
115 | "type" : "VEC3"
116 | },
117 | {
118 | "bufferView" : 2,
119 | "byteOffset" : 33408,
120 | "componentType" : 5126,
121 | "count" : 1056,
122 | "max" : [ 1, 1, 1 ],
123 | "min" : [ -1, -1, -1 ],
124 | "name" : "buffer-0-accessor-normal-buffer-0-mesh-0",
125 | "type" : "VEC3"
126 | },
127 | {
128 | "bufferView" : 1,
129 | "componentType" : 5126,
130 | "count" : 0,
131 | "max" : [ 0, 0 ],
132 | "min" : [ 0, 0 ],
133 | "name" : "buffer-0-accessor-texcoord-buffer-0-mesh-0",
134 | "type" : "VEC2"
135 | },
136 | {
137 | "bufferView" : 3,
138 | "componentType" : 5126,
139 | "count" : 0,
140 | "max" : [ 0, 0, 0, 0 ],
141 | "min" : [ 0, 0, 0, 0 ],
142 | "name" : "buffer-0-accessor-color-buffer-0-mesh-0",
143 | "type" : "VEC4"
144 | },
145 | {
146 | "bufferView" : 0,
147 | "byteOffset" : 3840,
148 | "componentType" : 5123,
149 | "count" : 480,
150 | "max" : [ 479 ],
151 | "min" : [ 0 ],
152 | "name" : "buffer-0-accessor-indices-buffer-0-mesh-0",
153 | "type" : "SCALAR"
154 | },
155 | {
156 | "bufferView" : 2,
157 | "byteOffset" : 46080,
158 | "componentType" : 5126,
159 | "count" : 480,
160 | "max" : [ 0.8525949716567993, 9.915228843688965, 0.8525949716567993 ],
161 | "min" : [ -0.8525949716567993, 0, -0.8525949716567993 ],
162 | "name" : "buffer-0-accessor-position-buffer-0-mesh-0",
163 | "type" : "VEC3"
164 | },
165 | {
166 | "bufferView" : 2,
167 | "byteOffset" : 51840,
168 | "componentType" : 5126,
169 | "count" : 480,
170 | "max" : [ 0.9239000082015991, 0.9775999784469604, 0.9239000082015991 ],
171 | "min" : [ -0.9239000082015991, -1, -0.9239000082015991 ],
172 | "name" : "buffer-0-accessor-normal-buffer-0-mesh-0",
173 | "type" : "VEC3"
174 | },
175 | {
176 | "bufferView" : 1,
177 | "componentType" : 5126,
178 | "count" : 0,
179 | "max" : [ 0, 0 ],
180 | "min" : [ 0, 0 ],
181 | "name" : "buffer-0-accessor-texcoord-buffer-0-mesh-0",
182 | "type" : "VEC2"
183 | },
184 | {
185 | "bufferView" : 3,
186 | "componentType" : 5126,
187 | "count" : 0,
188 | "max" : [ 0, 0, 0, 0 ],
189 | "min" : [ 0, 0, 0, 0 ],
190 | "name" : "buffer-0-accessor-color-buffer-0-mesh-0",
191 | "type" : "VEC4"
192 | },
193 | {
194 | "bufferView" : 0,
195 | "byteOffset" : 4800,
196 | "componentType" : 5123,
197 | "count" : 96,
198 | "max" : [ 95 ],
199 | "min" : [ 0 ],
200 | "name" : "buffer-0-accessor-indices-buffer-0-mesh-0",
201 | "type" : "SCALAR"
202 | },
203 | {
204 | "bufferView" : 2,
205 | "byteOffset" : 57600,
206 | "componentType" : 5126,
207 | "count" : 96,
208 | "max" : [ 1.929389953613281, 5.365962982177734, 1.92612898349762 ],
209 | "min" : [ -1.929389953613281, 0, -1.92612898349762 ],
210 | "name" : "buffer-0-accessor-position-buffer-0-mesh-0",
211 | "type" : "VEC3"
212 | },
213 | {
214 | "bufferView" : 2,
215 | "byteOffset" : 58752,
216 | "componentType" : 5126,
217 | "count" : 96,
218 | "max" : [ 1, 0, 1 ],
219 | "min" : [ -1, 0, -1 ],
220 | "name" : "buffer-0-accessor-normal-buffer-0-mesh-0",
221 | "type" : "VEC3"
222 | },
223 | {
224 | "bufferView" : 1,
225 | "componentType" : 5126,
226 | "count" : 0,
227 | "max" : [ 0, 0 ],
228 | "min" : [ 0, 0 ],
229 | "name" : "buffer-0-accessor-texcoord-buffer-0-mesh-0",
230 | "type" : "VEC2"
231 | },
232 | {
233 | "bufferView" : 3,
234 | "componentType" : 5126,
235 | "count" : 0,
236 | "max" : [ 0, 0, 0, 0 ],
237 | "min" : [ 0, 0, 0, 0 ],
238 | "name" : "buffer-0-accessor-color-buffer-0-mesh-0",
239 | "type" : "VEC4"
240 | }
241 | ],
242 | "asset" : {
243 | "generator" : "Obj2GltfConverter",
244 | "version" : "2.0"
245 | },
246 | "bufferViews" : [
247 | {
248 | "buffer" : 0,
249 | "byteLength" : 4992,
250 | "byteStride" : 0,
251 | "name" : "buffer-0-bufferview-ushort",
252 | "target" : 34963
253 | },
254 | {
255 | "buffer" : 0,
256 | "byteLength" : 1,
257 | "name" : "buffer-0-bufferview-vec2"
258 | },
259 | {
260 | "buffer" : 0,
261 | "byteLength" : 59904,
262 | "byteOffset" : 4992,
263 | "byteStride" : 12,
264 | "name" : "buffer-0-bufferview-vec3",
265 | "target" : 34962
266 | },
267 | {
268 | "buffer" : 0,
269 | "byteLength" : 1,
270 | "name" : "buffer-0-bufferview-vec4"
271 | }
272 | ],
273 | "buffers" : [
274 | {
275 | "byteLength" : 64896,
276 | "name" : "buffer-0",
277 | "uri" : "Rocket_Ship_01.bin"
278 | }
279 | ],
280 | "materials" : [
281 | {
282 | "doubleSided" : true,
283 | "name" : "F44336",
284 | "pbrMetallicRoughness" : {
285 | "baseColorFactor" : [ 0.956863, 0.262745, 0.211765, 1 ],
286 | "metallicFactor" : 0,
287 | "roughnessFactor" : 0.7448017359246658
288 | }
289 | },
290 | {
291 | "doubleSided" : true,
292 | "name" : "FFFFFF",
293 | "pbrMetallicRoughness" : {
294 | "metallicFactor" : 0,
295 | "roughnessFactor" : 0.7448017359246658
296 | }
297 | },
298 | {
299 | "doubleSided" : true,
300 | "name" : "455A64",
301 | "pbrMetallicRoughness" : {
302 | "baseColorFactor" : [ 0.270588, 0.352941, 0.392157, 1 ],
303 | "metallicFactor" : 0,
304 | "roughnessFactor" : 0.7448017359246658
305 | }
306 | },
307 | {
308 | "doubleSided" : true,
309 | "name" : "78909C",
310 | "pbrMetallicRoughness" : {
311 | "baseColorFactor" : [ 0.470588, 0.564706, 0.611765, 1 ],
312 | "metallicFactor" : 0,
313 | "roughnessFactor" : 0.7448017359246658
314 | }
315 | },
316 | {
317 | "doubleSided" : true,
318 | "name" : "80DEEA",
319 | "pbrMetallicRoughness" : {
320 | "baseColorFactor" : [ 0.501961, 0.870588, 0.917647, 1 ],
321 | "metallicFactor" : 0,
322 | "roughnessFactor" : 0.7448017359246658
323 | }
324 | }
325 | ],
326 | "meshes" : [
327 | {
328 | "name" : "buffer-0-mesh-0",
329 | "primitives" : [
330 | {
331 | "attributes" : {
332 | "NORMAL" : 2,
333 | "POSITION" : 1,
334 | "TEXCOORD_0" : 3
335 | },
336 | "indices" : 0,
337 | "material" : 0
338 | },
339 | {
340 | "attributes" : {
341 | "NORMAL" : 7,
342 | "POSITION" : 6,
343 | "TEXCOORD_0" : 8
344 | },
345 | "indices" : 5,
346 | "material" : 1
347 | },
348 | {
349 | "attributes" : {
350 | "NORMAL" : 12,
351 | "POSITION" : 11,
352 | "TEXCOORD_0" : 13
353 | },
354 | "indices" : 10,
355 | "material" : 2
356 | },
357 | {
358 | "attributes" : {
359 | "NORMAL" : 17,
360 | "POSITION" : 16,
361 | "TEXCOORD_0" : 18
362 | },
363 | "indices" : 15,
364 | "material" : 3
365 | },
366 | {
367 | "attributes" : {
368 | "NORMAL" : 22,
369 | "POSITION" : 21,
370 | "TEXCOORD_0" : 23
371 | },
372 | "indices" : 20,
373 | "material" : 4
374 | }
375 | ]
376 | }
377 | ],
378 | "nodes" : [
379 | {
380 | "mesh" : 0,
381 | "name" : "node-0"
382 | }
383 | ],
384 | "scenes" : [
385 | {
386 | "name" : "scene-0",
387 | "nodes" : [ 0 ]
388 | }
389 | ]
390 | }
391 |
--------------------------------------------------------------------------------
/resources/thing.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simondevyoutube/ThreeJS_Tutorial_CharacterController/b149e694e68791be0a11eff568cf9cafcb1b3e65/resources/thing.glb
--------------------------------------------------------------------------------
/resources/zombie/dance.fbx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simondevyoutube/ThreeJS_Tutorial_CharacterController/b149e694e68791be0a11eff568cf9cafcb1b3e65/resources/zombie/dance.fbx
--------------------------------------------------------------------------------
/resources/zombie/hiphop.fbx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simondevyoutube/ThreeJS_Tutorial_CharacterController/b149e694e68791be0a11eff568cf9cafcb1b3e65/resources/zombie/hiphop.fbx
--------------------------------------------------------------------------------
/resources/zombie/idle.fbx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simondevyoutube/ThreeJS_Tutorial_CharacterController/b149e694e68791be0a11eff568cf9cafcb1b3e65/resources/zombie/idle.fbx
--------------------------------------------------------------------------------
/resources/zombie/mremireh_o_desbiens.fbx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simondevyoutube/ThreeJS_Tutorial_CharacterController/b149e694e68791be0a11eff568cf9cafcb1b3e65/resources/zombie/mremireh_o_desbiens.fbx
--------------------------------------------------------------------------------
/resources/zombie/run.fbx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simondevyoutube/ThreeJS_Tutorial_CharacterController/b149e694e68791be0a11eff568cf9cafcb1b3e65/resources/zombie/run.fbx
--------------------------------------------------------------------------------
/resources/zombie/walk.fbx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simondevyoutube/ThreeJS_Tutorial_CharacterController/b149e694e68791be0a11eff568cf9cafcb1b3e65/resources/zombie/walk.fbx
--------------------------------------------------------------------------------