|
@@ -20,7 +20,7 @@
|
|
|
padding: 5px;
|
|
|
}
|
|
|
a {
|
|
|
- color: #bbb;
|
|
|
+ color: #ff0000;
|
|
|
}
|
|
|
.ac { /* prevent dat-gui from being selected */
|
|
|
-webkit-user-select: none;
|
|
@@ -40,17 +40,16 @@
|
|
|
<body>
|
|
|
<div id="container"></div>
|
|
|
<div id="info">
|
|
|
- <a href="http://threejs.org" target="_blank" rel="noopener">three.js</a> - Skeletal Animation Blending
|
|
|
- (model from <a href="http://realitymeltdown.com" target="_blank" rel="noopener">realitymeltdown.com</a>)
|
|
|
- <br><br>camera orbit/zoom/pan with left/middle/right mouse button
|
|
|
- <br>Note: crossfades are possible with blend weights being set to (1,0,0), (0,1,0) or (0,0,1)
|
|
|
+ <a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> - Skeletal Animation Blending
|
|
|
+ (model from <a href="https://www.mixamo.com/" target="_blank" rel="noopener">mixamo.com</a>)
|
|
|
+ <br/><br/>Note: crossfades are possible with blend weights being set to (1,0,0), (0,1,0) or (0,0,1)
|
|
|
</div>
|
|
|
|
|
|
<script src="../build/three.js"></script>
|
|
|
|
|
|
<script src="js/WebGL.js"></script>
|
|
|
<script src="js/libs/stats.min.js"></script>
|
|
|
- <script src="js/controls/OrbitControls.js"></script>
|
|
|
+ <script src="js/loaders/GLTFLoader.js"></script>
|
|
|
<script src="js/libs/dat.gui.min.js"></script>
|
|
|
|
|
|
<script>
|
|
@@ -61,115 +60,113 @@
|
|
|
|
|
|
}
|
|
|
|
|
|
- var container = document.getElementById( 'container' );
|
|
|
-
|
|
|
- var scene, renderer, camera, controls, stats;
|
|
|
- var mesh, skeleton, mixer;
|
|
|
+ var scene, renderer, camera, stats;
|
|
|
+ var model, skeleton, mixer, clock;
|
|
|
|
|
|
var crossFadeControls = [];
|
|
|
|
|
|
var idleAction, walkAction, runAction;
|
|
|
var idleWeight, walkWeight, runWeight;
|
|
|
- var actions;
|
|
|
- var settings;
|
|
|
-
|
|
|
- var clock = new THREE.Clock();
|
|
|
+ var actions, settings;
|
|
|
|
|
|
var singleStepMode = false;
|
|
|
var sizeOfNextStep = 0;
|
|
|
|
|
|
- var url = 'models/skinned/marine/marine_anims_core.json';
|
|
|
-
|
|
|
-
|
|
|
- // Initialize stats (fps display)
|
|
|
-
|
|
|
- stats = new Stats();
|
|
|
- container.appendChild( stats.dom );
|
|
|
-
|
|
|
-
|
|
|
- // Initialize scene, light and renderer
|
|
|
+ init();
|
|
|
|
|
|
- scene = new THREE.Scene();
|
|
|
- scene.background = new THREE.Color( 0x333333 );
|
|
|
- scene.add( new THREE.AmbientLight( 0xffffff ) );
|
|
|
+ function init() {
|
|
|
|
|
|
- renderer = new THREE.WebGLRenderer( { antialias: true } );
|
|
|
- renderer.setPixelRatio( window.devicePixelRatio );
|
|
|
- renderer.setSize( window.innerWidth, window.innerHeight );
|
|
|
+ var container = document.getElementById( 'container' );
|
|
|
|
|
|
- container.appendChild( renderer.domElement );
|
|
|
+ camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 1000 );
|
|
|
+ camera.position.set( 1, 2, - 3 );
|
|
|
+ camera.lookAt( 0, 1, 0 );
|
|
|
|
|
|
+ clock = new THREE.Clock();
|
|
|
|
|
|
- // Load skinned mesh
|
|
|
+ scene = new THREE.Scene();
|
|
|
+ scene.background = new THREE.Color( 0xa0a0a0 );
|
|
|
+ scene.fog = new THREE.Fog( 0xa0a0a0, 10, 50 );
|
|
|
|
|
|
- new THREE.ObjectLoader().load( url, function ( loadedObject ) {
|
|
|
+ var hemiLight = new THREE.HemisphereLight( 0xffffff, 0x444444 );
|
|
|
+ hemiLight.position.set( 0, 20, 0 );
|
|
|
+ scene.add( hemiLight );
|
|
|
|
|
|
- loadedObject.traverse( function ( child ) {
|
|
|
+ var dirLight = new THREE.DirectionalLight( 0xffffff );
|
|
|
+ dirLight.position.set( - 3, 10, - 10 );
|
|
|
+ dirLight.castShadow = true;
|
|
|
+ dirLight.shadow.camera.top = 2;
|
|
|
+ dirLight.shadow.camera.bottom = - 2;
|
|
|
+ dirLight.shadow.camera.left = - 2;
|
|
|
+ dirLight.shadow.camera.right = 2;
|
|
|
+ dirLight.shadow.camera.near = 0.1;
|
|
|
+ dirLight.shadow.camera.far = 40;
|
|
|
+ scene.add( dirLight );
|
|
|
|
|
|
- if ( child instanceof THREE.SkinnedMesh ) {
|
|
|
+ // scene.add( new THREE.CameraHelper( light.shadow.camera ) );
|
|
|
|
|
|
- mesh = child;
|
|
|
+ // ground
|
|
|
|
|
|
- }
|
|
|
-
|
|
|
- } );
|
|
|
-
|
|
|
- if ( mesh === undefined ) {
|
|
|
-
|
|
|
- alert( 'Unable to find a SkinnedMesh in this place:\n\n' + url + '\n\n' );
|
|
|
- return;
|
|
|
+ var mesh = new THREE.Mesh( new THREE.PlaneBufferGeometry( 100, 100 ), new THREE.MeshPhongMaterial( { color: 0x999999, depthWrite: false } ) );
|
|
|
+ mesh.rotation.x = - Math.PI / 2;
|
|
|
+ mesh.receiveShadow = true;
|
|
|
+ scene.add( mesh );
|
|
|
|
|
|
- }
|
|
|
+ var loader = new THREE.GLTFLoader();
|
|
|
+ loader.load( 'models/gltf/Soldier.glb', function ( gltf ) {
|
|
|
|
|
|
+ model = gltf.scene;
|
|
|
+ scene.add( model );
|
|
|
|
|
|
- // Add mesh and skeleton helper to scene
|
|
|
+ model.traverse( function ( object ) {
|
|
|
|
|
|
- mesh.rotation.y = - 135 * Math.PI / 180;
|
|
|
- scene.add( mesh );
|
|
|
+ if ( object.isMesh ) object.castShadow = true;
|
|
|
|
|
|
- skeleton = new THREE.SkeletonHelper( mesh );
|
|
|
- skeleton.visible = false;
|
|
|
- scene.add( skeleton );
|
|
|
+ } );
|
|
|
|
|
|
+ //
|
|
|
|
|
|
- // Initialize camera and camera controls
|
|
|
+ skeleton = new THREE.SkeletonHelper( model );
|
|
|
+ skeleton.visible = false;
|
|
|
+ scene.add( skeleton );
|
|
|
|
|
|
- var radius = mesh.geometry.boundingSphere.radius;
|
|
|
+ //
|
|
|
|
|
|
- var aspect = window.innerWidth / window.innerHeight;
|
|
|
- camera = new THREE.PerspectiveCamera( 45, aspect, 1, 10000 );
|
|
|
- camera.position.set( 0.0, radius, radius * 3.5 );
|
|
|
+ createPanel();
|
|
|
|
|
|
- controls = new THREE.OrbitControls( camera, renderer.domElement );
|
|
|
- controls.target.set( 0, radius, 0 );
|
|
|
- controls.update();
|
|
|
|
|
|
+ //
|
|
|
|
|
|
- // Create the control panel
|
|
|
+ var animations = gltf.animations;
|
|
|
|
|
|
- createPanel();
|
|
|
+ mixer = new THREE.AnimationMixer( model );
|
|
|
|
|
|
+ idleAction = mixer.clipAction( animations[ 0 ] );
|
|
|
+ walkAction = mixer.clipAction( animations[ 3 ] );
|
|
|
+ runAction = mixer.clipAction( animations[ 1 ] );
|
|
|
|
|
|
- // Initialize mixer and clip actions
|
|
|
+ actions = [ idleAction, walkAction, runAction ];
|
|
|
|
|
|
- mixer = new THREE.AnimationMixer( mesh );
|
|
|
+ activateAllActions();
|
|
|
|
|
|
- idleAction = mixer.clipAction( 'idle' );
|
|
|
- walkAction = mixer.clipAction( 'walk' );
|
|
|
- runAction = mixer.clipAction( 'run' );
|
|
|
- actions = [ idleAction, walkAction, runAction ];
|
|
|
+ animate();
|
|
|
|
|
|
- activateAllActions();
|
|
|
+ } );
|
|
|
|
|
|
+ renderer = new THREE.WebGLRenderer( { antialias: true } );
|
|
|
+ renderer.setPixelRatio( window.devicePixelRatio );
|
|
|
+ renderer.setSize( window.innerWidth, window.innerHeight );
|
|
|
+ renderer.gammaOutput = true;
|
|
|
+ renderer.gammaFactor = 2.2;
|
|
|
+ renderer.shadowMap.enabled = true;
|
|
|
+ container.appendChild( renderer.domElement );
|
|
|
|
|
|
- // Listen on window resizing and start the render loop
|
|
|
+ stats = new Stats();
|
|
|
+ container.appendChild( stats.dom );
|
|
|
|
|
|
window.addEventListener( 'resize', onWindowResize, false );
|
|
|
- animate();
|
|
|
-
|
|
|
-
|
|
|
- } );
|
|
|
|
|
|
+ }
|
|
|
|
|
|
function createPanel() {
|
|
|
|
|
@@ -281,7 +278,7 @@
|
|
|
|
|
|
function showModel( visibility ) {
|
|
|
|
|
|
- mesh.visible = visibility;
|
|
|
+ model.visible = visibility;
|
|
|
|
|
|
}
|
|
|
|
|
@@ -310,7 +307,6 @@
|
|
|
|
|
|
}
|
|
|
|
|
|
-
|
|
|
function activateAllActions() {
|
|
|
|
|
|
setWeight( idleAction, settings[ 'modify idle weight' ] );
|
|
@@ -325,7 +321,6 @@
|
|
|
|
|
|
}
|
|
|
|
|
|
-
|
|
|
function pauseContinue() {
|
|
|
|
|
|
if ( singleStepMode ) {
|
|
@@ -349,7 +344,6 @@
|
|
|
|
|
|
}
|
|
|
|
|
|
-
|
|
|
function pauseAllActions() {
|
|
|
|
|
|
actions.forEach( function ( action ) {
|
|
@@ -360,7 +354,6 @@
|
|
|
|
|
|
}
|
|
|
|
|
|
-
|
|
|
function unPauseAllActions() {
|
|
|
|
|
|
actions.forEach( function ( action ) {
|
|
@@ -371,7 +364,6 @@
|
|
|
|
|
|
}
|
|
|
|
|
|
-
|
|
|
function toSingleStepMode() {
|
|
|
|
|
|
unPauseAllActions();
|
|
@@ -381,7 +373,6 @@
|
|
|
|
|
|
}
|
|
|
|
|
|
-
|
|
|
function prepareCrossFade( startAction, endAction, defaultDuration ) {
|
|
|
|
|
|
// Switch default / custom crossfade duration (according to the user's choice)
|