-
-
Notifications
You must be signed in to change notification settings - Fork 36.1k
SkinnedMesh/Skeleton serialization #11603
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
37954e2
46d516a
5228523
daf7399
ae7b71d
a5e418d
e9e54cc
a78ddb5
af6d2aa
d5d283f
8a4da31
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -633,7 +633,8 @@ Object3D.prototype = Object.assign( Object.create( EventDispatcher.prototype ), | |
| materials: {}, | ||
| textures: {}, | ||
| images: {}, | ||
| shapes: {} | ||
| shapes: {}, | ||
| skeletons: {} | ||
| }; | ||
|
|
||
| output.metadata = { | ||
|
|
@@ -663,6 +664,11 @@ Object3D.prototype = Object.assign( Object.create( EventDispatcher.prototype ), | |
|
|
||
| if ( this.matrixAutoUpdate === false ) object.matrixAutoUpdate = false; | ||
|
|
||
| // SkinnedMesh specific | ||
|
|
||
| if ( this.bindMode !== undefined ) object.bindMode = this.bindMode; | ||
| if ( this.bindMatrix !== undefined ) object.bindMatrix = this.bindMatrix.toArray(); | ||
|
|
||
| // | ||
|
|
||
| function serialize( library, element ) { | ||
|
|
@@ -729,6 +735,20 @@ Object3D.prototype = Object.assign( Object.create( EventDispatcher.prototype ), | |
|
|
||
| } | ||
|
|
||
| // SkinnedMesh specific | ||
|
|
||
| if ( this.skeleton !== undefined ) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hi Why not move this to a toJSON inside SkinnedMesh i think it would make more sense to move mesh serialization specifics to the Mesh and SkinnedMesh objects! Thanks
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can wait until this gets merged and i can try to propose moving and cleanup these after maybe?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How do you do that?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. By moving that code to a toJSON method inside SkinnedMesh :)
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you try to make sample code and share with me?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Something like this
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I tried to do this once - it's trickier than it seems, because of how Ideally, since
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well im doing a ton in nunuStudio i have pretty much overrided more than half of the threejs serialization process to include resources, external lib data etc. There is some tricks to it sometimes (specially when working with object relations) but for these cases its pretty straight forward just call the thing on Object3D and add whatever you need to add, its always better and cleaner than filling Object3D serialization with a ton of verifications to decide whether or not to include a resource from a specific class.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, your code looks good, and this is definitely the way to go rather than piling it all into
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think your code is good enough. I don't really like making duplicated codes in |
||
|
|
||
| if ( meta.skeletons[ this.skeleton.uuid ] === undefined ) { | ||
|
|
||
| meta.skeletons[ this.skeleton.uuid ] = this.skeleton.toJSON( meta ); | ||
|
|
||
| } | ||
|
|
||
| object.skeleton = this.skeleton.uuid; | ||
|
|
||
| } | ||
|
|
||
| // | ||
|
|
||
| if ( this.children.length > 0 ) { | ||
|
|
@@ -750,12 +770,14 @@ Object3D.prototype = Object.assign( Object.create( EventDispatcher.prototype ), | |
| var textures = extractFromCache( meta.textures ); | ||
| var images = extractFromCache( meta.images ); | ||
| var shapes = extractFromCache( meta.shapes ); | ||
| var skeletons = extractFromCache( meta.skeletons ); | ||
|
|
||
| if ( geometries.length > 0 ) output.geometries = geometries; | ||
| if ( materials.length > 0 ) output.materials = materials; | ||
| if ( textures.length > 0 ) output.textures = textures; | ||
| if ( images.length > 0 ) output.images = images; | ||
| if ( shapes.length > 0 ) output.shapes = shapes; | ||
| if ( skeletons.length > 0 ) output.skeletons = skeletons; | ||
|
|
||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,6 +20,7 @@ import { | |
| LinearMipMapLinearFilter | ||
| } from '../constants.js'; | ||
| import { Color } from '../math/Color.js'; | ||
| import { Matrix4 } from '../math/Matrix4.js'; | ||
| import { Object3D } from '../core/Object3D.js'; | ||
| import { Group } from '../objects/Group.js'; | ||
| import { Sprite } from '../objects/Sprite.js'; | ||
|
|
@@ -31,6 +32,8 @@ import { LOD } from '../objects/LOD.js'; | |
| import { Mesh } from '../objects/Mesh.js'; | ||
| import { SkinnedMesh } from '../objects/SkinnedMesh.js'; | ||
| import { Shape } from '../extras/core/Shape.js'; | ||
| import { Bone } from '../objects/Bone.js'; | ||
| import { Skeleton } from '../objects/Skeleton.js'; | ||
| import { Fog } from '../scenes/Fog.js'; | ||
| import { FogExp2 } from '../scenes/FogExp2.js'; | ||
| import { HemisphereLight } from '../lights/HemisphereLight.js'; | ||
|
|
@@ -139,6 +142,10 @@ Object.assign( ObjectLoader.prototype, { | |
|
|
||
| var object = this.parseObject( json.object, geometries, materials ); | ||
|
|
||
| var skeletons = this.parseSkeletons( json.skeletons, object ); | ||
|
|
||
| this.bindSkeletons( object, skeletons ); | ||
|
|
||
| if ( json.animations ) { | ||
|
|
||
| object.animations = this.parseAnimations( json.animations ); | ||
|
|
@@ -587,6 +594,48 @@ Object.assign( ObjectLoader.prototype, { | |
|
|
||
| }, | ||
|
|
||
| parseSkeletons: function ( json, object ) { | ||
|
|
||
| var skeletons = {}; | ||
|
|
||
| if ( json === undefined ) return skeletons; | ||
|
|
||
| for ( var i = 0, il = json.length; i < il; i ++ ) { | ||
|
|
||
| var skeletonParams = json[ i ]; | ||
|
|
||
| var uuid = skeletonParams.uuid; | ||
| var boneUUIDs = skeletonParams.bones; | ||
| var boneInverseArrays = skeletonParams.boneInverses; | ||
|
|
||
| var bones = []; | ||
| var boneInverses = []; | ||
|
|
||
| for ( var j = 0, jl = boneUUIDs.length; j < jl; j ++ ) { | ||
|
|
||
| var boneUUID = boneUUIDs[ j ]; | ||
| var bone = object.getObjectByProperty( 'uuid', boneUUID ); | ||
|
|
||
| if ( bone === undefined ) { | ||
|
|
||
| console.warn( 'THREE.ObjectLoader: Not found Bone whose uuid is ' + boneUUID ); | ||
| bone = new Bone(); | ||
|
|
||
| } | ||
|
|
||
| bones.push( bone ); | ||
| boneInverses.push( new Matrix4().fromArray( boneInverseArrays[ j ] ) ); | ||
|
|
||
| } | ||
|
|
||
| skeletons[ uuid ] = new Skeleton( bones, boneInverses ); | ||
|
|
||
| } | ||
|
|
||
| return skeletons; | ||
|
|
||
| }, | ||
|
|
||
| parseObject: function ( data, geometries, materials ) { | ||
|
|
||
| var object; | ||
|
|
@@ -730,7 +779,33 @@ Object.assign( ObjectLoader.prototype, { | |
|
|
||
| case 'SkinnedMesh': | ||
|
|
||
| console.warn( 'THREE.ObjectLoader.parseObject() does not support SkinnedMesh yet.' ); | ||
| var geometry = getGeometry( data.geometry ); | ||
| var material = getMaterial( data.material ); | ||
|
|
||
| var currentBones; | ||
|
|
||
| // If data has skeleton, assuming bones are already in scene graph. | ||
| // Then temporarily undefining geometry.bones not to create duplicated | ||
| // bones in SkinnedMesh constructor. | ||
|
|
||
| if ( data.skeleton !== undefined && geometry.bones !== undefined ) { | ||
|
|
||
| currentBones = geometry.bones; | ||
| geometry.bones = undefined; | ||
|
|
||
| } | ||
|
|
||
| object = new SkinnedMesh( geometry, material ); | ||
|
|
||
| if ( data.bindMode !== undefined ) object.bindMode = data.bindMode; | ||
| if ( data.bindMatrix !== undefined ) object.bindMatrix.fromArray( data.bindMatrix ); | ||
|
|
||
| // .skeletonUUID is temporal. Deleting after binding the skeleton. | ||
| // See .bindSkeletons(). | ||
| if ( data.skeleton !== undefined ) object.skeletonUUID = data.skeleton; | ||
| if ( currentBones !== undefined ) geometry.bones = currentBones; | ||
|
|
||
| break; | ||
|
|
||
| case 'Mesh': | ||
|
|
||
|
|
@@ -749,6 +824,12 @@ Object.assign( ObjectLoader.prototype, { | |
|
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there a
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oops, thanks. I'll fix later.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed, thanks! |
||
| break; | ||
|
|
||
| case 'Bone': | ||
|
|
||
| object = new Bone(); | ||
|
|
||
| break; | ||
|
|
||
| case 'LOD': | ||
|
|
||
| object = new LOD(); | ||
|
|
@@ -868,6 +949,34 @@ Object.assign( ObjectLoader.prototype, { | |
|
|
||
| return object; | ||
|
|
||
| }, | ||
|
|
||
| bindSkeletons: function ( object, skeletons ) { | ||
|
|
||
| if ( Object.keys( skeletons ).length === 0 ) return; | ||
|
|
||
| object.traverse( function ( obj ) { | ||
|
|
||
| if ( obj.isSkinnedMesh === true && obj.skeletonUUID !== undefined ) { | ||
|
|
||
| var skeleton = skeletons[ obj.skeletonUUID ]; | ||
|
|
||
| if ( skeleton === undefined ) { | ||
|
|
||
| console.warn( 'THREE.ObjectLoader: Not found Skeleton whose uuid is ' + obj.skeletonUUID ); | ||
|
|
||
| } else { | ||
|
|
||
| obj.bind( skeleton, obj.bindMatrix ); | ||
|
|
||
| } | ||
|
|
||
| delete obj.skeletonUUID; | ||
|
|
||
| } | ||
|
|
||
| } ); | ||
|
|
||
| } | ||
|
|
||
| } ); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about
this.bindMatrixInverse? For the sake of completeness we should also regard this property.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bindMatrixInverseis calculated frombindMatrixinSkinnedMesh.bind()so I didn't think we need to serializebindMatrixInverse.Do you think we should do that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just prefer to serialize all public attributes. But your point of view is also valid. The current code is definitely correct. Because i don't have a strong opinion on this, i leave it up to you 😉
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, so let's keep this code so far.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would you please close change request?
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@takahirox I'm sorry! I've missed your comment. Approving...