OSDN Git Service

three.jsをThirdPartyに追加
[webglgame/webgl_framework.git] / webglFramework / Thirdparty / three.js-master / examples / webgl_animation_skinning_blending.html
1 <!DOCTYPE html>
2 <html lang="en">
3         <head>
4                 <title>three.js webgl - animation - skinning</title>
5                 <meta charset="utf-8">
6                 <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
7                 <style>
8                         body {
9                                 color: #fff;
10                                 font-family:Monospace;
11                                 font-size:13px;
12                                 text-align:center;
13                                 background-color: #fff;
14                                 margin: 0px;
15                                 overflow: hidden;
16                         }
17                         #info {
18                                 position: absolute;
19                                 top: 0px; width: 100%;
20                                 padding: 5px;
21                         }
22                         a {
23                                 color: #bbb;
24                         }
25                         .ac {  /* prevent dat-gui from being selected */
26                                 -webkit-user-select: none;
27                                 -moz-user-select: none;
28                                 -ms-user-select: none;
29                                 user-select: none;
30                         }
31                         .no-pointer-events {
32                                 pointer-events: none;
33                         }
34                         .control-disabled {
35                                 color: #888;
36                                 text-decoration: line-through;
37                         }
38                 </style>
39         </head>
40         <body>
41                 <div id="container"></div>
42                 <div id="info">
43                         <a href="http://threejs.org" target="_blank" rel="noopener">three.js</a> - Skeletal Animation Blending
44                         (model from <a href="http://realitymeltdown.com" target="_blank" rel="noopener">realitymeltdown.com</a>)
45                         <br><br>camera orbit/zoom/pan with left/middle/right mouse button
46                         <br>Note: crossfades are possible with blend weights being set to (1,0,0), (0,1,0) or (0,0,1)
47                 </div>
48
49                 <script src="../build/three.js"></script>
50
51                 <script src="js/Detector.js"></script>
52                 <script src="js/libs/stats.min.js"></script>
53                 <script src="js/controls/OrbitControls.js"></script>
54                 <script src="js/libs/dat.gui.min.js"></script>
55
56                 <script>
57
58                         if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
59
60                         var container = document.getElementById( 'container' );
61
62                         var scene, renderer, camera, controls, stats;
63                         var mesh, skeleton, mixer;
64
65                         var crossFadeControls = [];
66
67                         var idleAction, walkAction, runAction;
68                         var idleWeight, walkWeight, runWeight;
69                         var actions;
70                         var settings;
71
72                         var clock = new THREE.Clock();
73
74                         var singleStepMode = false;
75                         var sizeOfNextStep = 0;
76
77                         var url = 'models/skinned/marine/marine_anims_core.json';
78
79
80                         // Initialize stats (fps display)
81
82                         stats = new Stats();
83                         container.appendChild( stats.dom );
84
85
86                         // Initialize scene, light and renderer
87
88                         scene = new THREE.Scene();
89                         scene.background = new THREE.Color( 0x333333 );
90                         scene.add( new THREE.AmbientLight( 0xffffff ) );
91
92                         renderer = new THREE.WebGLRenderer( { antialias: true } );
93                         renderer.setPixelRatio( window.devicePixelRatio );
94                         renderer.setSize( window.innerWidth, window.innerHeight );
95
96                         container.appendChild( renderer.domElement );
97
98
99                         // Load skinned mesh
100
101                         new THREE.ObjectLoader().load( url, function ( loadedObject ) {
102
103                                 loadedObject.traverse( function ( child ) {
104
105                                         if ( child instanceof THREE.SkinnedMesh ) {
106
107                                                 mesh = child;
108
109                                         }
110
111                                 } );
112
113                                 if ( mesh === undefined ) {
114
115                                         alert( 'Unable to find a SkinnedMesh in this place:\n\n' + url + '\n\n' );
116                                         return;
117
118                                 }
119
120
121                                 // Add mesh and skeleton helper to scene
122
123                                 mesh.rotation.y = - 135 * Math.PI / 180;
124                                 scene.add( mesh );
125
126                                 skeleton = new THREE.SkeletonHelper( mesh );
127                                 skeleton.visible = false;
128                                 scene.add( skeleton );
129
130
131                                 // Initialize camera and camera controls
132
133                                 var radius = mesh.geometry.boundingSphere.radius;
134
135                                 var aspect = window.innerWidth / window.innerHeight;
136                                 camera = new THREE.PerspectiveCamera( 45, aspect, 1, 10000 );
137                                 camera.position.set( 0.0, radius, radius * 3.5 );
138
139                                 controls = new THREE.OrbitControls( camera, renderer.domElement );
140                                 controls.target.set( 0, radius, 0 );
141                                 controls.update();
142
143
144                                 // Create the control panel
145
146                                 createPanel();
147
148
149                                 // Initialize mixer and clip actions
150
151                                 mixer = new THREE.AnimationMixer( mesh );
152
153                                 idleAction = mixer.clipAction( 'idle' );
154                                 walkAction = mixer.clipAction( 'walk' );
155                                 runAction = mixer.clipAction( 'run' );
156                                 actions = [ idleAction, walkAction, runAction ];
157
158                                 activateAllActions();
159
160
161                                 // Listen on window resizing and start the render loop
162
163                                 window.addEventListener( 'resize', onWindowResize, false );
164                                 animate();
165
166
167                         } );
168
169
170                         function createPanel() {
171
172                                 var panel = new dat.GUI( { width: 310 } );
173
174                                 var folder1 = panel.addFolder( 'Visibility' );
175                                 var folder2 = panel.addFolder( 'Activation/Deactivation' );
176                                 var folder3 = panel.addFolder( 'Pausing/Stepping' );
177                                 var folder4 = panel.addFolder( 'Crossfading' );
178                                 var folder5 = panel.addFolder( 'Blend Weights' );
179                                 var folder6 = panel.addFolder( 'General Speed' );
180
181                                 settings = {
182                                         'show model':            true,
183                                         'show skeleton':         false,
184                                         'deactivate all':        deactivateAllActions,
185                                         'activate all':          activateAllActions,
186                                         'pause/continue':        pauseContinue,
187                                         'make single step':      toSingleStepMode,
188                                         'modify step size':      0.05,
189                                         'from walk to idle':     function () { prepareCrossFade( walkAction, idleAction, 1.0 ) },
190                                         'from idle to walk':     function () { prepareCrossFade( idleAction, walkAction, 0.5 ) },
191                                         'from walk to run':      function () { prepareCrossFade( walkAction, runAction, 2.5 ) },
192                                         'from run to walk':      function () { prepareCrossFade( runAction, walkAction, 5.0 ) },
193                                         'use default duration':  true,
194                                         'set custom duration':   3.5,
195                                         'modify idle weight':    0.0,
196                                         'modify walk weight':    1.0,
197                                         'modify run weight':     0.0,
198                                         'modify time scale':     1.0
199                                 };
200
201                                 folder1.add( settings, 'show model' ).onChange( showModel );
202                                 folder1.add( settings, 'show skeleton' ).onChange( showSkeleton );
203                                 folder2.add( settings, 'deactivate all' );
204                                 folder2.add( settings, 'activate all' );
205                                 folder3.add( settings, 'pause/continue' );
206                                 folder3.add( settings, 'make single step' );
207                                 folder3.add( settings, 'modify step size', 0.01, 0.1, 0.001 );
208                                 crossFadeControls.push( folder4.add( settings, 'from walk to idle' ) );
209                                 crossFadeControls.push( folder4.add( settings, 'from idle to walk' ) );
210                                 crossFadeControls.push( folder4.add( settings, 'from walk to run' ) );
211                                 crossFadeControls.push( folder4.add( settings, 'from run to walk' ) );
212                                 folder4.add( settings, 'use default duration' );
213                                 folder4.add( settings, 'set custom duration', 0, 10, 0.01 );
214                                 folder5.add( settings, 'modify idle weight', 0.0, 1.0, 0.01 ).listen().onChange( function ( weight ) { setWeight( idleAction, weight ) } );
215                                 folder5.add( settings, 'modify walk weight', 0.0, 1.0, 0.01 ).listen().onChange( function ( weight ) { setWeight( walkAction, weight ) } );
216                                 folder5.add( settings, 'modify run weight', 0.0, 1.0, 0.01 ).listen().onChange( function ( weight ) { setWeight( runAction, weight ) } );
217                                 folder6.add( settings, 'modify time scale', 0.0, 1.5, 0.01 ).onChange( modifyTimeScale );
218
219                                 folder1.open();
220                                 folder2.open();
221                                 folder3.open();
222                                 folder4.open();
223                                 folder5.open();
224                                 folder6.open();
225
226                                 crossFadeControls.forEach( function ( control ) {
227
228                                         control.classList1 = control.domElement.parentElement.parentElement.classList;
229                                         control.classList2 = control.domElement.previousElementSibling.classList;
230
231                                         control.setDisabled = function () {
232
233                                                 control.classList1.add( 'no-pointer-events' );
234                                                 control.classList2.add( 'control-disabled' );
235
236                                         };
237
238                                         control.setEnabled = function () {
239
240                                                 control.classList1.remove( 'no-pointer-events' );
241                                                 control.classList2.remove( 'control-disabled' );
242
243                                         };
244
245                                 } );
246
247                         }
248
249
250                         function showModel( visibility ) {
251
252                                 mesh.visible = visibility;
253
254                         }
255
256
257                         function showSkeleton( visibility ) {
258
259                                 skeleton.visible = visibility;
260
261                         }
262
263
264                         function modifyTimeScale( speed ) {
265
266                                 mixer.timeScale = speed;
267
268                         }
269
270
271                         function deactivateAllActions() {
272
273                                 actions.forEach( function ( action ) {
274
275                                         action.stop();
276
277                                 } );
278
279                         }
280
281
282                         function activateAllActions() {
283
284                                 setWeight( idleAction, settings[ 'modify idle weight' ] );
285                                 setWeight( walkAction, settings[ 'modify walk weight' ] );
286                                 setWeight( runAction, settings[ 'modify run weight' ] );
287
288                                 actions.forEach( function ( action ) {
289
290                                         action.play();
291
292                                 } );
293
294                         }
295
296
297                         function pauseContinue() {
298
299                                 if ( singleStepMode ) {
300
301                                         singleStepMode = false;
302                                         unPauseAllActions();
303
304                                 } else {
305
306                                         if ( idleAction.paused ) {
307
308                                                 unPauseAllActions();
309
310                                         } else {
311
312                                                 pauseAllActions();
313
314                                         }
315
316                                 }
317
318                         }
319
320
321                         function pauseAllActions() {
322
323                                 actions.forEach( function ( action ) {
324
325                                         action.paused = true;
326
327                                 } );
328
329                         }
330
331
332                         function unPauseAllActions() {
333
334                                 actions.forEach( function ( action ) {
335
336                                         action.paused = false;
337
338                                 } );
339
340                         }
341
342
343                         function toSingleStepMode() {
344
345                                 unPauseAllActions();
346
347                                 singleStepMode = true;
348                                 sizeOfNextStep = settings[ 'modify step size' ];
349
350                         }
351
352
353                         function prepareCrossFade( startAction, endAction, defaultDuration ) {
354
355                                 // Switch default / custom crossfade duration (according to the user's choice)
356
357                                 var duration = setCrossFadeDuration( defaultDuration );
358
359                                 // Make sure that we don't go on in singleStepMode, and that all actions are unpaused
360
361                                 singleStepMode = false;
362                                 unPauseAllActions();
363
364                                 // If the current action is 'idle' (duration 4 sec), execute the crossfade immediately;
365                                 // else wait until the current action has finished its current loop
366
367                                 if ( startAction === idleAction ) {
368
369                                         executeCrossFade( startAction, endAction, duration );
370
371                                 } else {
372
373                                         synchronizeCrossFade( startAction, endAction, duration );
374
375                                 }
376
377                         }
378
379
380                         function setCrossFadeDuration( defaultDuration ) {
381
382                                 // Switch default crossfade duration <-> custom crossfade duration
383
384                                 if ( settings[ 'use default duration' ] ) {
385
386                                         return defaultDuration;
387
388                                 } else {
389
390                                         return settings[ 'set custom duration' ];
391
392                                 }
393
394                         }
395
396
397                         function synchronizeCrossFade( startAction, endAction, duration ) {
398
399                                 mixer.addEventListener( 'loop', onLoopFinished );
400
401                                 function onLoopFinished( event ) {
402
403                                         if ( event.action === startAction ) {
404
405                                                 mixer.removeEventListener( 'loop', onLoopFinished );
406
407                                                 executeCrossFade( startAction, endAction, duration );
408
409                                         }
410
411                                 }
412
413                         }
414
415
416                         function executeCrossFade( startAction, endAction, duration ) {
417
418                                 // Not only the start action, but also the end action must get a weight of 1 before fading
419                                 // (concerning the start action this is already guaranteed in this place)
420
421                                 setWeight( endAction, 1 );
422                                 endAction.time = 0;
423
424                                 // Crossfade with warping - you can also try without warping by setting the third parameter to false
425
426                                 startAction.crossFadeTo( endAction, duration, true );
427
428                         }
429
430
431                         // This function is needed, since animationAction.crossFadeTo() disables its start action and sets
432                         // the start action's timeScale to ((start animation's duration) / (end animation's duration))
433
434                         function setWeight( action, weight ) {
435
436                                 action.enabled = true;
437                                 action.setEffectiveTimeScale( 1 );
438                                 action.setEffectiveWeight( weight );
439
440                         }
441
442
443                         // Called by the render loop
444
445                         function updateWeightSliders() {
446
447                                 settings[ 'modify idle weight' ] = idleWeight;
448                                 settings[ 'modify walk weight' ] = walkWeight;
449                                 settings[ 'modify run weight' ] = runWeight;
450
451                         }
452
453
454                         // Called by the render loop
455
456                         function updateCrossFadeControls() {
457
458                                 crossFadeControls.forEach( function ( control ) {
459
460                                         control.setDisabled();
461
462                                 } );
463
464                                 if ( idleWeight === 1 && walkWeight === 0 && runWeight === 0 ) {
465
466                                         crossFadeControls[ 1 ].setEnabled();
467
468                                 }
469
470                                 if ( idleWeight === 0 && walkWeight === 1 && runWeight === 0 ) {
471
472                                         crossFadeControls[ 0 ].setEnabled();
473                                         crossFadeControls[ 2 ].setEnabled();
474
475                                 }
476
477                                 if ( idleWeight === 0 && walkWeight === 0 && runWeight === 1 ) {
478
479                                         crossFadeControls[ 3 ].setEnabled();
480
481                                 }
482
483                         }
484
485
486                         function onWindowResize() {
487
488                                 camera.aspect = window.innerWidth / window.innerHeight;
489                                 camera.updateProjectionMatrix();
490
491                                 renderer.setSize( window.innerWidth, window.innerHeight );
492
493                         }
494
495
496                         function animate() {
497
498                                 // Render loop
499
500                                 requestAnimationFrame( animate );
501
502                                 idleWeight = idleAction.getEffectiveWeight();
503                                 walkWeight = walkAction.getEffectiveWeight();
504                                 runWeight = runAction.getEffectiveWeight();
505
506                                 // Update the panel values if weights are modified from "outside" (by crossfadings)
507
508                                 updateWeightSliders();
509
510                                 // Enable/disable crossfade controls according to current weight values
511
512                                 updateCrossFadeControls();
513
514                                 // Get the time elapsed since the last frame, used for mixer update (if not in single step mode)
515
516                                 var mixerUpdateDelta = clock.getDelta();
517
518                                 // If in single step mode, make one step and then do nothing (until the user clicks again)
519
520                                 if ( singleStepMode ) {
521
522                                         mixerUpdateDelta = sizeOfNextStep;
523                                         sizeOfNextStep = 0;
524
525                                 }
526
527                                 // Update the animation mixer, the stats panel, and render this frame
528
529                                 mixer.update( mixerUpdateDelta );
530
531                                 stats.update();
532
533                                 renderer.render( scene, camera );
534
535                         }
536
537                 </script>
538
539         </body>
540 </html>