-
-
Notifications
You must be signed in to change notification settings - Fork 35.6k
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
SkinnedMesh/Skeleton serialization #11603
Changes from 3 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 |
---|---|---|
|
@@ -594,7 +594,8 @@ Object.assign( Object3D.prototype, EventDispatcher.prototype, { | |
geometries: {}, | ||
materials: {}, | ||
textures: {}, | ||
images: {} | ||
images: {}, | ||
skeletons: {} | ||
}; | ||
|
||
output.metadata = { | ||
|
@@ -620,6 +621,11 @@ Object.assign( Object3D.prototype, EventDispatcher.prototype, { | |
|
||
object.matrix = this.matrix.toArray(); | ||
|
||
// SkinnedMesh specific | ||
|
||
if ( this.bindMode !== undefined ) object.bindMode = this.bindMode; | ||
if ( this.bindMatrix !== undefined ) object.bindMatrix = this.bindMatrix.toArray(); | ||
|
||
// | ||
|
||
function serialize( library, element ) { | ||
|
@@ -662,6 +668,20 @@ Object.assign( Object3D.prototype, EventDispatcher.prototype, { | |
|
||
} | ||
|
||
// SkinnedMesh specific | ||
|
||
if ( this.skeleton !== undefined ) { | ||
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 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? 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? 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 :) 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? 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
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 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. 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 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 ) { | ||
|
@@ -682,11 +702,13 @@ Object.assign( Object3D.prototype, EventDispatcher.prototype, { | |
var materials = extractFromCache( meta.materials ); | ||
var textures = extractFromCache( meta.textures ); | ||
var images = extractFromCache( meta.images ); | ||
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 ( skeletons.length > 0 ) output.skeletons = skeletons; | ||
|
||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -31,6 +31,8 @@ import { LineSegments } from '../objects/LineSegments'; | |
import { LOD } from '../objects/LOD'; | ||
import { Mesh } from '../objects/Mesh'; | ||
import { SkinnedMesh } from '../objects/SkinnedMesh'; | ||
import { Skeleton } from '../objects/Skeleton'; | ||
import { Bone } from '../objects/Bone'; | ||
import { Fog } from '../scenes/Fog'; | ||
import { FogExp2 } from '../scenes/FogExp2'; | ||
import { HemisphereLight } from '../lights/HemisphereLight'; | ||
|
@@ -136,6 +138,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 ); | ||
|
@@ -519,6 +525,47 @@ Object.assign( ObjectLoader.prototype, { | |
|
||
}, | ||
|
||
parseSkeletons: function ( json, object ) { | ||
|
||
var skeletons = {}; | ||
|
||
if ( json === undefined ) return skeletons; | ||
|
||
for ( var i = 0; i < json.length; i ++ ) { | ||
|
||
var skeletonParams = json[ i ]; | ||
|
||
var uuid = skeletonParams.uuid; | ||
var boneParams = skeletonParams.bones; | ||
var boneInverseParams = skeletonParams.boneInverses; | ||
|
||
var bones = []; | ||
var boneInverses = []; | ||
|
||
for ( var j = 0, jl = boneParams.length; j < jl; j ++ ) { | ||
|
||
var bone = object.getObjectByProperty( 'uuid', boneParams[ j ] ); | ||
|
||
if ( bone === undefined ) { | ||
|
||
console.warn( 'THREE.ObjectLoader: Not found Bone whose uuid is ' + boneParams[ j ] ); | ||
bone = new Bone(); | ||
|
||
} | ||
|
||
bones.push( bone ); | ||
boneInverses.push( new Matrix4().fromArray( boneInverseParams[ j ] ) ); | ||
|
||
} | ||
|
||
skeletons[ uuid ] = new Skeleton( bones, boneInverses ); | ||
|
||
} | ||
|
||
return skeletons; | ||
|
||
}, | ||
|
||
parseObject: function () { | ||
|
||
var matrix = new Matrix4(); | ||
|
@@ -663,7 +710,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 tmpBones; | ||
|
||
// If data has skeleton, assumes bones are already in scene graph. | ||
// Then temporarily undefines geometry.bones not to create bones | ||
// in SkinnedMesh constructor. | ||
|
||
if ( data.skeleton !== undefined && geometry.bones !== undefined ) { | ||
|
||
tmpBones = geometry.bones; | ||
geometry.bones = undefined; | ||
|
||
} | ||
|
||
object = new SkinnedMesh( geometry, material ); | ||
|
||
// rebinds with skeleton whose uuid is data.skeleton later. | ||
if ( data.skeleton !== undefined ) object.skeletonUUID = data.skeleton; | ||
if ( data.bindMode !== undefined ) object.bindMode = data.bindMode; | ||
if ( data.bindMatrix !== undefined ) object.bindMatrix.fromArray( data.bindMatrix ); | ||
object.updateMatrixWorld( true ); | ||
|
||
if ( tmpBones !== undefined ) geometry.bones = tmpBones; | ||
|
||
break; | ||
|
||
case 'Mesh': | ||
|
||
|
@@ -682,6 +755,12 @@ Object.assign( ObjectLoader.prototype, { | |
|
||
break; | ||
|
||
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 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. 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! |
||
case 'Bone': | ||
|
||
object = new Bone(); | ||
|
||
break; | ||
|
||
case 'LOD': | ||
|
||
object = new LOD(); | ||
|
@@ -796,7 +875,35 @@ Object.assign( ObjectLoader.prototype, { | |
|
||
}; | ||
|
||
}() | ||
}(), | ||
|
||
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.sjeletonUUID ); | ||
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. Typo in 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. Sorry if im being a bit annoying :), i really want this PR to be merged i was comparing it to what i was doing on nunu xD 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! |
||
|
||
} 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.
bindMatrixInverse
is calculated frombindMatrix
inSkinnedMesh.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.
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?
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...