@ -2101,80 +2101,10 @@ Error EditorSceneImporterGLTF::_reparent_non_joint_skeleton_subtrees(GLTFState &
subtree_set . get_members ( subtree_nodes , subtree_root ) ;
for ( int subtree_i = 0 ; subtree_i < subtree_nodes . size ( ) ; + + subtree_i ) {
ERR_FAIL_COND_V ( _reparent_to_fake_joint ( state , skeleton , subtree_nodes [ subtree_i ] ) , FAILED ) ;
// We modified the tree, recompute all the heights
_compute_node_heights ( state ) ;
}
}
return OK ;
}
Error EditorSceneImporterGLTF : : _reparent_to_fake_joint ( GLTFState & state , GLTFSkeleton & skeleton , const GLTFNodeIndex node_index ) {
GLTFNode * node = state . nodes [ node_index ] ;
// Can we just "steal" this joint if it is just a spatial node?
if ( node - > skin < 0 & & node - > mesh < 0 & & node - > camera < 0 ) {
node - > joint = true ;
// Add the joint to the skeletons joints
skeleton . joints . push_back ( node_index ) ;
return OK ;
}
GLTFNode * fake_joint = memnew ( GLTFNode ) ;
const GLTFNodeIndex fake_joint_index = state . nodes . size ( ) ;
state . nodes . push_back ( fake_joint ) ;
// We better not be a joint, or we messed up in our logic
if ( node - > joint )
return FAILED ;
fake_joint - > translation = node - > translation ;
fake_joint - > rotation = node - > rotation ;
fake_joint - > scale = node - > scale ;
fake_joint - > xform = node - > xform ;
fake_joint - > joint = true ;
// We can use the exact same name here, because the joint will be inside a skeleton and not the scene
fake_joint - > name = node - > name ;
// Clear the nodes transforms, since it will be parented to the fake joint
node - > translation = Vector3 ( 0 , 0 , 0 ) ;
node - > rotation = Quat ( ) ;
node - > scale = Vector3 ( 1 , 1 , 1 ) ;
node - > xform = Transform ( ) ;
// Transfer the node children to the fake joint
for ( int child_i = 0 ; child_i < node - > children . size ( ) ; + + child_i ) {
GLTFNode * child = state . nodes [ node - > children [ child_i ] ] ;
child - > parent = fake_joint_index ;
}
fake_joint - > children = node - > children ;
node - > children . clear ( ) ;
// add the fake joint to the parent and remove the original joint
if ( node - > parent > = 0 ) {
GLTFNode * parent = state . nodes [ node - > parent ] ;
parent - > children . erase ( node_index ) ;
parent - > children . push_back ( fake_joint_index ) ;
fake_joint - > parent = node - > parent ;
}
// Add the node to the fake joint
fake_joint - > children . push_back ( node_index ) ;
node - > parent = fake_joint_index ;
node - > fake_joint_parent = fake_joint_index ;
// Add the fake joint to the skeletons joints
skeleton . joints . push_back ( fake_joint_index ) ;
// Replace skin_skeletons with fake joints if we must.
for ( GLTFSkinIndex skin_i = 0 ; skin_i < state . skins . size ( ) ; + + skin_i ) {
GLTFSkin & skin = state . skins . write [ skin_i ] ;
if ( skin . skin_root = = node_index ) {
skin . skin_root = fake_joint_index ;
GLTFNode * node = state . nodes [ subtree_nodes [ subtree_i ] ] ;
node - > joint = true ;
// Add the joint to the skeletons joints
skeleton . joints . push_back ( subtree_nodes [ subtree_i ] ) ;
}
}
@ -2675,11 +2605,9 @@ void EditorSceneImporterGLTF::_assign_scene_names(GLTFState &state) {
}
}
BoneAttachment * EditorSceneImporterGLTF : : _generate_bone_attachment ( GLTFState & state , Skeleton * skeleton , const GLTFNodeIndex node_index ) {
BoneAttachment * EditorSceneImporterGLTF : : _generate_bone_attachment ( GLTFState & state , Skeleton * skeleton , const GLTFNodeIndex node_index , const GLTFNodeIndex bone_index ) {
const GLTFNode * gltf_node = state . nodes [ node_index ] ;
const GLTFNode * bone_node = state . nodes [ gltf_node - > parent ] ;
const GLTFNode * bone_node = state . nodes [ bone_index ] ;
BoneAttachment * bone_attachment = memnew ( BoneAttachment ) ;
print_verbose ( " glTF: Creating bone attachment for: " + gltf_node - > name ) ;
@ -2712,7 +2640,7 @@ MeshInstance *EditorSceneImporterGLTF::_generate_mesh_instance(GLTFState &state,
return mi ;
}
Light * EditorSceneImporterGLTF : : _generate_light ( GLTFState & state , Node * scene_parent , const GLTFNodeIndex node_index ) {
Spatial * EditorSceneImporterGLTF : : _generate_light ( GLTFState & state , Node * scene_parent , const GLTFNodeIndex node_index ) {
const GLTFNode * gltf_node = state . nodes [ node_index ] ;
ERR_FAIL_INDEX_V ( gltf_node - > light , state . lights . size ( ) , nullptr ) ;
@ -2761,7 +2689,7 @@ Light *EditorSceneImporterGLTF::_generate_light(GLTFState &state, Node *scene_pa
light - > set_param ( SpotLight : : PARAM_SPOT_ATTENUATION , angle_attenuation ) ;
return light ;
}
return nullptr ;
return memnew ( Spatial ) ;
}
Camera * EditorSceneImporterGLTF : : _generate_camera ( GLTFState & state , Node * scene_parent , const GLTFNodeIndex node_index ) {
@ -2795,31 +2723,22 @@ void EditorSceneImporterGLTF::_generate_scene_node(GLTFState &state, Node *scene
const GLTFNode * gltf_node = state . nodes [ node_index ] ;
if ( gltf_node - > skeleton > = 0 ) {
_generate_skeleton_bone_node ( state , scene_parent , scene_root , node_index ) ;
return ;
}
Spatial * current_node = nullptr ;
// Is our parent a skeleton
Skeleton * active_skeleton = Object : : cast_to < Skeleton > ( scene_parent ) ;
if ( gltf_node - > skeleton > = 0 ) {
Skeleton * skeleton = state . skeletons [ gltf_node - > skeleton ] . godot_skeleton ;
if ( active_skeleton ! = skeleton ) {
ERR_FAIL_COND_MSG ( active_skeleton ! = nullptr , " glTF: Generating scene detected direct parented Skeletons " ) ;
// Add it to the scene if it has not already been added
if ( skeleton - > get_parent ( ) = = nullptr ) {
scene_parent - > add_child ( skeleton ) ;
skeleton - > set_owner ( scene_root ) ;
}
}
const bool non_bone_parented_to_skeleton = active_skeleton ;
active_skeleton = skeleton ;
current_node = skeleton ;
}
// If we have an active skeleton, and the node is node skinned, we need to create a bone attachment
if ( current_node = = nullptr & & active_skeleton ! = nullptr & & gltf_node - > skin < 0 ) {
BoneAttachment * bone_attachment = _generate_bone_attachment ( state , active_skeleton , node_index ) ;
// skinned meshes must not be placed in a bone attachment.
if ( non_bone_parented_to_skeleton & & gltf_node - > skin < 0 ) {
// Bone Attachment - Parent Case
BoneAttachment * bone_attachment = _generate_bone_attachment ( state , active_skeleton , node_index , gltf_node - > parent ) ;
scene_parent - > add_child ( bone_attachment ) ;
bone_attachment - > set_owner ( scene_root ) ;
@ -2833,20 +2752,100 @@ void EditorSceneImporterGLTF::_generate_scene_node(GLTFState &state, Node *scene
}
// We still have not managed to make a node
if ( current_node = = nullptr ) {
if ( gltf_node - > mesh > = 0 ) {
current_node = _generate_mesh_instance ( state , scene_parent , node_index ) ;
} else if ( gltf_node - > camera > = 0 ) {
current_node = _generate_camera ( state , scene_parent , node_index ) ;
} else if ( gltf_node - > light > = 0 ) {
current_node = _generate_light ( state , scene_parent , node_index ) ;
} else {
current_node = _generate_spatial ( state , scene_parent , node_index ) ;
}
scene_parent - > add_child ( current_node ) ;
current_node - > set_owner ( scene_root ) ;
current_node - > set_transform ( gltf_node - > xform ) ;
if ( state . use_legacy_names ) {
current_node - > set_name ( _legacy_validate_node_name ( gltf_node - > name ) ) ;
} else {
current_node - > set_name ( gltf_node - > name ) ;
}
state . scene_nodes . insert ( node_index , current_node ) ;
for ( int i = 0 ; i < gltf_node - > children . size ( ) ; + + i ) {
_generate_scene_node ( state , current_node , scene_root , gltf_node - > children [ i ] ) ;
}
}
void EditorSceneImporterGLTF : : _generate_skeleton_bone_node ( GLTFState & state , Node * scene_parent , Spatial * scene_root , const GLTFNodeIndex node_index ) {
const GLTFNode * gltf_node = state . nodes [ node_index ] ;
Spatial * current_node = nullptr ;
Skeleton * skeleton = state . skeletons [ gltf_node - > skeleton ] . godot_skeleton ;
// In this case, this node is already a bone in skeleton.
const bool is_skinned_mesh = ( gltf_node - > skin > = 0 & & gltf_node - > mesh > = 0 ) ;
const bool requires_extra_node = ( gltf_node - > mesh > = 0 | | gltf_node - > camera > = 0 | | gltf_node - > light > = 0 ) ;
Skeleton * active_skeleton = Object : : cast_to < Skeleton > ( scene_parent ) ;
if ( active_skeleton ! = skeleton ) {
if ( active_skeleton ) {
// Bone Attachment - Direct Parented Skeleton Case
BoneAttachment * bone_attachment = _generate_bone_attachment ( state , active_skeleton , node_index , gltf_node - > parent ) ;
scene_parent - > add_child ( bone_attachment ) ;
bone_attachment - > set_owner ( scene_root ) ;
// There is no gltf_node that represent this, so just directly create a unique name
bone_attachment - > set_name ( _gen_unique_name ( state , " BoneAttachment " ) ) ;
// We change the scene_parent to our bone attachment now. We do not set current_node because we want to make the node
// and attach it to the bone_attachment
scene_parent = bone_attachment ;
WARN_PRINT ( vformat ( " glTF: Generating scene detected direct parented Skeletons at node %d " , node_index ) ) ;
}
// Add it to the scene if it has not already been added
if ( skeleton - > get_parent ( ) = = nullptr ) {
scene_parent - > add_child ( skeleton ) ;
skeleton - > set_owner ( scene_root ) ;
}
}
active_skeleton = skeleton ;
current_node = skeleton ;
// If we have an active skeleton, and the node is node skinned, we need to create a bone attachment
if ( requires_extra_node ) {
// skinned meshes must not be placed in a bone attachment.
if ( ! is_skinned_mesh ) {
BoneAttachment * bone_attachment = _generate_bone_attachment ( state , active_skeleton , node_index , node_index ) ;
scene_parent - > add_child ( bone_attachment ) ;
bone_attachment - > set_owner ( scene_root ) ;
// There is no gltf_node that represent this, so just directly create a unique name
bone_attachment - > set_name ( _gen_unique_name ( state , " BoneAttachment " ) ) ;
// We change the scene_parent to our bone attachment now. We do not set current_node because we want to make the node
// and attach it to the bone_attachment
scene_parent = bone_attachment ;
current_node = nullptr ;
}
// We still have not managed to make a node
if ( gltf_node - > mesh > = 0 ) {
current_node = _generate_mesh_instance ( state , scene_parent , node_index ) ;
} else if ( gltf_node - > camera > = 0 ) {
current_node = _generate_camera ( state , scene_parent , node_index ) ;
} else if ( gltf_node - > light > = 0 ) {
current_node = _generate_light ( state , scene_parent , node_index ) ;
} else {
current_node = _generate_spatial ( state , scene_parent , node_index ) ;
}
scene_parent - > add_child ( current_node ) ;
current_node - > set_owner ( scene_root ) ;
current_node - > set_transform ( gltf_node - > xform ) ;
// Do not set transform here. Transform is already applied to our bone.
if ( state . use_legacy_names ) {
current_node - > set_name ( _legacy_validate_node_name ( gltf_node - > name ) ) ;
} else {
@ -2857,7 +2856,7 @@ void EditorSceneImporterGLTF::_generate_scene_node(GLTFState &state, Node *scene
state . scene_nodes . insert ( node_index , current_node ) ;
for ( int i = 0 ; i < gltf_node - > children . size ( ) ; + + i ) {
_generate_scene_node ( state , current_node , scene_root , gltf_node - > children [ i ] ) ;
_generate_scene_node ( state , active_skeleton , scene_root , gltf_node - > children [ i ] ) ;
}
}
@ -3012,26 +3011,30 @@ void EditorSceneImporterGLTF::_import_animation(GLTFState &state, AnimationPlaye
for ( Map < int , GLTFAnimation : : Track > : : Element * E = anim . tracks . front ( ) ; E ; E = E - > next ( ) ) {
const GLTFAnimation : : Track & track = E - > get ( ) ;
//need to find the path
//need to find the path : for skeletons, weight tracks will affect the mesh
NodePath node_path ;
//for skeletons, transform tracks always affect bones
NodePath transform_node_path ;
GLTFNodeIndex node_index = E - > key ( ) ;
if ( state . nodes [ node_index ] - > fake_joint_parent > = 0 ) {
// Should be same as parent
node_index = state . nodes [ node_index ] - > fake_joint_parent ;
}
const GLTFNode * node = state . nodes [ E - > key ( ) ] ;
Node * root = ap - > get_parent ( ) ;
ERR_FAIL_COND ( root = = nullptr ) ;
Map < GLTFNodeIndex , Node * > : : Element * node_element = state . scene_nodes . find ( node_index ) ;
ERR_CONTINUE_MSG ( node_element = = nullptr , vformat ( " Unable to find node %d for animation " , node_index ) ) ;
node_path = root - > get_path_to ( node_element - > get ( ) ) ;
if ( node - > skeleton > = 0 ) {
const Skeleton * sk = Object : : cast_to < Skeleton > ( state . scene_nodes . find ( node_index ) - > get ( ) ) ;
const Skeleton * sk = state. skeletons [ node - > skeleton ] . godot_skeleton ;
ERR_FAIL_COND ( sk = = nullptr ) ;
const String path = ap - > get_parent ( ) - > get_path_to ( sk ) ;
const String bone = node - > name ;
node_path = path + " : " + bone ;
transform_ node_path = path + " : " + bone ;
} else {
node_path = ap - > get_parent ( ) - > get_path_to ( state . scene_nodes . find ( node_index ) - > get ( ) ) ;
transform_node_path = node_path ;
}
for ( int i = 0 ; i < track . rotation_track . times . size ( ) ; i + + ) {
@ -3050,11 +3053,13 @@ void EditorSceneImporterGLTF::_import_animation(GLTFState &state, AnimationPlaye
}
}
if ( track . rotation_track . values . size ( ) | | track . translation_track . values . size ( ) | | track . scale_track . values . size ( ) ) {
// Animated TRS properties will not affect a skinned mesh.
const bool transform_affects_skinned_mesh_instance = node - > skeleton < 0 & & node - > skin > = 0 ;
if ( ( track . rotation_track . values . size ( ) | | track . translation_track . values . size ( ) | | track . scale_track . values . size ( ) ) & & ! transform_affects_skinned_mesh_instance ) {
//make transform track
int track_idx = animation - > get_track_count ( ) ;
animation - > add_track ( Animation : : TYPE_TRANSFORM ) ;
animation - > track_set_path ( track_idx , node_path) ;
animation - > track_set_path ( track_idx , transform_ node_path) ;
animation - > track_set_imported ( track_idx , true ) ;
//first determine animation length