Skip to content

Commit 1c8be06

Browse files
committed
SkinnedMesh: Added serialization/deserialization.
1 parent cf0b35d commit 1c8be06

File tree

4 files changed

+230
-26
lines changed

4 files changed

+230
-26
lines changed

editor/js/Editor.js

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -664,10 +664,50 @@ Editor.prototype = {
664664

665665
} );
666666

667+
// animations
668+
669+
var animationsJSON = json.animations;
670+
671+
for ( var i = 0; i < animationsJSON.length; i ++ ) {
672+
673+
var objectJSON = animationsJSON[ i ];
674+
var animations = [];
675+
676+
for ( var j = 0; j < objectJSON.animations.length; j ++ ) {
677+
678+
animations.push( THREE.AnimationClip.parse( objectJSON.animations[ j ] ) );
679+
680+
}
681+
682+
this.animations[ objectJSON.uuid ] = animations;
683+
684+
}
685+
667686
},
668687

669688
toJSON: function () {
670689

690+
// animations
691+
692+
var animations = this.animations;
693+
var animationsJSON = [];
694+
695+
for ( var entry in animations ) {
696+
697+
var objectAnimations = animations[ entry ];
698+
var objectJSON = { uuid: entry, animations: [] };
699+
700+
for ( var i = 0; i < objectAnimations.length; i ++ ) {
701+
702+
var objectAnimation = objectAnimations[ i ];
703+
objectJSON.animations.push( THREE.AnimationClip.toJSON( objectAnimation ) );
704+
705+
}
706+
707+
animationsJSON.push( objectJSON );
708+
709+
}
710+
671711
// scripts clean up
672712

673713
var scene = this.scene;
@@ -701,7 +741,8 @@ Editor.prototype = {
701741
camera: this.camera.toJSON(),
702742
scene: this.scene.toJSON(),
703743
scripts: this.scripts,
704-
history: this.history.toJSON()
744+
history: this.history.toJSON(),
745+
animations: animationsJSON
705746

706747
};
707748

src/core/Object3D.js

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -658,7 +658,8 @@ Object3D.prototype = Object.assign( Object.create( EventDispatcher.prototype ),
658658
materials: {},
659659
textures: {},
660660
images: {},
661-
shapes: {}
661+
shapes: {},
662+
skeletons: {}
662663
};
663664

664665
output.metadata = {
@@ -743,6 +744,21 @@ Object3D.prototype = Object.assign( Object.create( EventDispatcher.prototype ),
743744

744745
}
745746

747+
if ( this.isSkinnedMesh ) {
748+
749+
object.bindMode = this.bindMode;
750+
object.bindMatrix = this.bindMatrix.toArray();
751+
752+
if ( this.skeleton !== undefined ) {
753+
754+
serialize( meta.skeletons, this.skeleton );
755+
756+
object.skeleton = this.skeleton.uuid;
757+
758+
}
759+
760+
}
761+
746762
if ( this.material !== undefined ) {
747763

748764
if ( Array.isArray( this.material ) ) {
@@ -786,12 +802,14 @@ Object3D.prototype = Object.assign( Object.create( EventDispatcher.prototype ),
786802
const textures = extractFromCache( meta.textures );
787803
const images = extractFromCache( meta.images );
788804
const shapes = extractFromCache( meta.shapes );
805+
const skeletons = extractFromCache( meta.skeletons );
789806

790807
if ( geometries.length > 0 ) output.geometries = geometries;
791808
if ( materials.length > 0 ) output.materials = materials;
792809
if ( textures.length > 0 ) output.textures = textures;
793810
if ( images.length > 0 ) output.images = images;
794811
if ( shapes.length > 0 ) output.shapes = shapes;
812+
if ( skeletons.length > 0 ) output.skeletons = skeletons;
795813

796814
}
797815

src/loaders/ObjectLoader.js

Lines changed: 81 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ import { LineLoop } from '../objects/LineLoop.js';
3030
import { LineSegments } from '../objects/LineSegments.js';
3131
import { LOD } from '../objects/LOD.js';
3232
import { Mesh } from '../objects/Mesh.js';
33+
import { SkinnedMesh } from '../objects/SkinnedMesh.js';
34+
import { Bone } from '../objects/Bone.js';
35+
import { Skeleton } from '../objects/Skeleton.js';
3336
import { Shape } from '../extras/core/Shape.js';
3437
import { Fog } from '../scenes/Fog.js';
3538
import { FogExp2 } from '../scenes/FogExp2.js';
@@ -110,7 +113,7 @@ class ObjectLoader extends Loader {
110113

111114
parse( json, onLoad ) {
112115

113-
const shapes = this.parseShape( json.shapes );
116+
const shapes = this.parseShapes( json.shapes );
114117
const geometries = this.parseGeometries( json.geometries, shapes );
115118

116119
const images = this.parseImages( json.images, function () {
@@ -123,6 +126,9 @@ class ObjectLoader extends Loader {
123126
const materials = this.parseMaterials( json.materials, textures );
124127

125128
const object = this.parseObject( json.object, geometries, materials );
129+
const skeletons = this.parseSkeletons( json.skeletons, object );
130+
131+
this.bindSkeletons( object, skeletons );
126132

127133
if ( json.animations ) {
128134

@@ -140,7 +146,7 @@ class ObjectLoader extends Loader {
140146

141147
}
142148

143-
parseShape( json ) {
149+
parseShapes( json ) {
144150

145151
const shapes = {};
146152

@@ -160,6 +166,37 @@ class ObjectLoader extends Loader {
160166

161167
}
162168

169+
parseSkeletons( json, object ) {
170+
171+
const skeletons = {};
172+
const bones = {};
173+
174+
// generate bone lookup table
175+
176+
object.traverse( function ( child ) {
177+
178+
if ( child.isBone ) bones[ child.uuid ] = child;
179+
180+
} );
181+
182+
// create skeletons
183+
184+
if ( json !== undefined ) {
185+
186+
for ( let i = 0, l = json.length; i < l; i ++ ) {
187+
188+
const skeleton = new Skeleton().fromJSON( json[ i ], bones );
189+
190+
skeletons[ skeleton.uuid ] = skeleton;
191+
192+
}
193+
194+
}
195+
196+
return skeletons;
197+
198+
}
199+
163200
parseGeometries( json, shapes ) {
164201

165202
const geometries = {};
@@ -826,7 +863,16 @@ class ObjectLoader extends Loader {
826863

827864
case 'SkinnedMesh':
828865

829-
console.warn( 'THREE.ObjectLoader.parseObject() does not support SkinnedMesh yet.' );
866+
geometry = getGeometry( data.geometry );
867+
material = getMaterial( data.material );
868+
869+
object = new SkinnedMesh( geometry, material );
870+
871+
if ( data.bindMode !== undefined ) object.bindMode = data.bindMode;
872+
if ( data.bindMatrix !== undefined ) object.bindMatrix.fromArray( data.bindMatrix );
873+
if ( data.skeleton !== undefined ) object.skeleton = data.skeleton;
874+
875+
break;
830876

831877
case 'Mesh':
832878

@@ -892,6 +938,12 @@ class ObjectLoader extends Loader {
892938

893939
break;
894940

941+
case 'Bone':
942+
943+
object = new Bone();
944+
945+
break;
946+
895947
default:
896948

897949
object = new Object3D();
@@ -974,6 +1026,32 @@ class ObjectLoader extends Loader {
9741026

9751027
}
9761028

1029+
bindSkeletons( object, skeletons ) {
1030+
1031+
if ( Object.keys( skeletons ).length === 0 ) return;
1032+
1033+
object.traverse( function ( child ) {
1034+
1035+
if ( child.isSkinnedMesh === true && child.skeleton !== undefined ) {
1036+
1037+
const skeleton = skeletons[ child.skeleton ];
1038+
1039+
if ( skeleton === undefined ) {
1040+
1041+
console.warn( 'THREE.ObjectLoader: No skeleton found with UUID:', child.skeleton );
1042+
1043+
} else {
1044+
1045+
child.bind( skeleton, child.bindMatrix );
1046+
1047+
}
1048+
1049+
}
1050+
1051+
} );
1052+
1053+
}
1054+
9771055
/* DEPRECATED */
9781056

9791057
setTexturePath( value ) {

src/objects/Skeleton.js

Lines changed: 88 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,63 @@
1+
import { Bone } from './Bone.js';
12
import { Matrix4 } from '../math/Matrix4.js';
3+
import { MathUtils } from '../math/MathUtils.js';
24

35
const _offsetMatrix = new Matrix4();
46
const _identityMatrix = new Matrix4();
57

6-
function Skeleton( bones, boneInverses ) {
8+
function Skeleton( bones = [], boneInverses = [] ) {
79

8-
// copy the bone array
9-
10-
bones = bones || [];
10+
this.uuid = MathUtils.generateUUID();
1111

1212
this.bones = bones.slice( 0 );
13-
this.boneMatrices = new Float32Array( this.bones.length * 16 );
13+
this.boneInverses = boneInverses;
1414

1515
this.frame = - 1;
1616

17-
// use the supplied bone inverses or calculate the inverses
17+
this.init();
18+
19+
}
20+
21+
Object.assign( Skeleton.prototype, {
22+
23+
init: function () {
1824

19-
if ( boneInverses === undefined ) {
25+
const bones = this.bones;
26+
const boneInverses = this.boneInverses;
2027

21-
this.calculateInverses();
28+
this.boneMatrices = new Float32Array( bones.length * 16 );
2229

23-
} else {
30+
// calculate inverse bone matrices if necessary
2431

25-
if ( this.bones.length === boneInverses.length ) {
32+
if ( boneInverses.length === 0 ) {
2633

27-
this.boneInverses = boneInverses.slice( 0 );
34+
this.calculateInverses();
2835

2936
} else {
3037

31-
console.warn( 'THREE.Skeleton boneInverses is the wrong length.' );
38+
// handle special case
3239

33-
this.boneInverses = [];
40+
if ( bones.length !== boneInverses.length ) {
3441

35-
for ( let i = 0, il = this.bones.length; i < il; i ++ ) {
42+
console.warn( 'THREE.Skeleton: Number of inverse bone matrices does not match amount of bones.' );
3643

37-
this.boneInverses.push( new Matrix4() );
44+
this.boneInverses = [];
3845

39-
}
46+
for ( let i = 0, il = this.bones.length; i < il; i ++ ) {
4047

41-
}
48+
this.boneInverses.push( new Matrix4() );
4249

43-
}
50+
}
4451

45-
}
52+
}
4653

47-
Object.assign( Skeleton.prototype, {
54+
}
55+
56+
},
4857

4958
calculateInverses: function () {
5059

51-
this.boneInverses = [];
60+
this.boneInverses.length = 0;
5261

5362
for ( let i = 0, il = this.bones.length; i < il; i ++ ) {
5463

@@ -171,6 +180,64 @@ Object.assign( Skeleton.prototype, {
171180

172181
}
173182

183+
},
184+
185+
fromJSON: function ( json, bones ) {
186+
187+
this.uuid = json.uuid;
188+
189+
for ( let i = 0, l = json.bones.length; i < l; i ++ ) {
190+
191+
const uuid = json.bones[ i ];
192+
let bone = bones[ uuid ];
193+
194+
if ( bone === undefined ) {
195+
196+
console.warn( 'THREE.Skeleton: No bone found with UUID:', uuid );
197+
bone = new Bone();
198+
199+
}
200+
201+
this.bones.push( bone );
202+
this.boneInverses.push( new Matrix4().fromArray( json.boneInverses[ i ] ) );
203+
204+
}
205+
206+
this.init();
207+
208+
return this;
209+
210+
},
211+
212+
toJSON: function () {
213+
214+
const data = {
215+
metadata: {
216+
version: 4.5,
217+
type: 'Skeleton',
218+
generator: 'Skeleton.toJSON'
219+
},
220+
bones: [],
221+
boneInverses: []
222+
};
223+
224+
data.uuid = this.uuid;
225+
226+
const bones = this.bones;
227+
const boneInverses = this.boneInverses;
228+
229+
for ( let i = 0, l = bones.length; i < l; i ++ ) {
230+
231+
const bone = bones[ i ];
232+
data.bones.push( bone.uuid );
233+
234+
const boneInverse = boneInverses[ i ];
235+
data.boneInverses.push( boneInverse.toArray() );
236+
237+
}
238+
239+
return data;
240+
174241
}
175242

176243
} );

0 commit comments

Comments
 (0)