├── 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 --------------------------------------------------------------------------------