@ -2894,8 +2894,8 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) {
}
blend_weights . write [ j ] = weights [ j ] ;
}
mesh - > set_blend_weights ( blend_weights ) ;
}
mesh - > set_blend_weights ( blend_weights ) ;
mesh - > set_mesh ( import_mesh ) ;
state - > meshes . push_back ( mesh ) ;
@ -4196,80 +4196,10 @@ Error GLTFDocument::_reparent_non_joint_skeleton_subtrees(Ref<GLTFState> state,
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 GLTFDocument : : _reparent_to_fake_joint ( Ref < GLTFState > state , Ref < GLTFSkeleton > skeleton , const GLTFNodeIndex node_index ) {
Ref < 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 - > set_name ( node - > get_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 ) {
Ref < 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 ) {
Ref < 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 ) {
Ref < GLTFSkin > skin = state - > skins . write [ skin_i ] ;
if ( skin - > skin_root = = node_index ) {
skin - > skin_root = fake_joint_index ;
Ref < 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 ] ) ;
}
}
@ -5016,9 +4946,9 @@ void GLTFDocument::_assign_scene_names(Ref<GLTFState> state) {
}
}
BoneAttachment * GLTFDocument : : _generate_bone_attachment ( Ref < GLTFState > state , Skeleton * skeleton , const GLTFNodeIndex node_index ) {
BoneAttachment * GLTFDocument : : _generate_bone_attachment ( Ref < GLTFState > state , Skeleton * skeleton , const GLTFNodeIndex node_index , const GLTFNodeIndex bone_index ) {
Ref < GLTFNode > gltf_node = state - > nodes [ node_index ] ;
Ref < GLTFNode > bone_node = state - > nodes [ gltf_node- > parent ] ;
Ref < GLTFNode > bone_node = state - > nodes [ bone_index ] ;
BoneAttachment * bone_attachment = memnew ( BoneAttachment ) ;
print_verbose ( " glTF: Creating bone attachment for: " + gltf_node - > get_name ( ) ) ;
@ -5106,7 +5036,7 @@ Spatial *GLTFDocument::_generate_mesh_instance(Ref<GLTFState> state, Node *scene
return mi ;
}
Light * GLTFDocument : : _generate_light ( Ref < GLTFState > state , Node * scene_parent , const GLTFNodeIndex node_index ) {
Spatial * GLTFDocument : : _generate_light ( Ref < GLTFState > state , Node * scene_parent , const GLTFNodeIndex node_index ) {
Ref < GLTFNode > gltf_node = state - > nodes [ node_index ] ;
ERR_FAIL_INDEX_V ( gltf_node - > light , state - > lights . size ( ) , nullptr ) ;
@ -5155,7 +5085,7 @@ Light *GLTFDocument::_generate_light(Ref<GLTFState> state, Node *scene_parent, c
light - > set_param ( SpotLight : : PARAM_SPOT_ATTENUATION , angle_attenuation ) ;
return light ;
}
return nullptr ;
return memnew ( Spatial ) ;
}
Camera * GLTFDocument : : _generate_camera ( Ref < GLTFState > state , Node * scene_parent , const GLTFNodeIndex node_index ) {
@ -5526,32 +5456,102 @@ void GLTFDocument::_convert_mesh_to_gltf(Node *p_scene_parent, Ref<GLTFState> st
void GLTFDocument : : _generate_scene_node ( Ref < GLTFState > state , Node * scene_parent , Spatial * scene_root , const GLTFNodeIndex node_index ) {
Ref < 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 ;
const bool non_bone_parented_to_skeleton = active_skeleton ;
if ( active_skeleton ! = skeleton ) {
ERR_FAIL_COND_MSG ( active_skeleton ! = nullptr , " glTF: Generating scene detected direct parented Skeletons " ) ;
// If we have an active skeleton, and the node is node skinned, we need to create 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 ) ;
// 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 ) ;
}
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 ;
}
// 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 ) ;
if ( current_node ! = scene_root ) {
current_node - > set_owner ( scene_root ) ;
}
current_node - > set_transform ( gltf_node - > xform ) ;
current_node - > set_name ( gltf_node - > get_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 GLTFDocument : : _generate_skeleton_bone_node ( Ref < GLTFState > state , Node * scene_parent , Spatial * scene_root , const GLTFNodeIndex node_index ) {
Ref < 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 ) ) ;
}
active_skeleton = skeleton ;
current_node = skeleton ;
// 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 ) ;
}
}
// If we have an active skeleton, and the node is node skinned, we need to create a bone attachment
if ( current_node = = nullptr | | gltf_node - > mesh > = 0 | | gltf_node - > camera > = 0 | | gltf_node - > light > = 0 ) {
if ( active_skeleton ! = nullptr & & gltf_node - > skin < 0 ) {
BoneAttachment * bone_attachment = _generate_bone_attachment ( state , active_skeleton , node_index ) ;
active_skeleton = skeleton ;
current_node = skeleton ;
if ( requires_extra_node ) {
// skinned meshes must not be placed in a bone attachment.
if ( ! is_skinned_mesh ) {
// Bone Attachment - Same Node Case
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 ) ;
@ -5573,17 +5573,11 @@ void GLTFDocument::_generate_scene_node(Ref<GLTFState> state, Node *scene_parent
current_node = _generate_light ( state , scene_parent , node_index ) ;
}
if ( ! current_node ) {
current_node = _generate_spatial ( state , scene_parent , node_index ) ;
}
scene_parent - > add_child ( current_node ) ;
if ( current_node ! = scene_root ) {
current_node - > set_owner ( scene_root ) ;
}
if ( use_xform ) {
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 - > get_name ( ) ) ) ;
} else {
@ -5594,7 +5588,7 @@ void GLTFDocument::_generate_scene_node(Ref<GLTFState> state, Node *scene_parent
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 ] ) ;
}
}
@ -5735,28 +5729,30 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap,
for ( Map < int , GLTFAnimation : : Track > : : Element * track_i = anim - > get_tracks ( ) . front ( ) ; track_i ; track_i = track_i - > next ( ) ) {
const GLTFAnimation : : Track & track = track_i - > 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 = track_i - > 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 Ref < GLTFNode > gltf_node = state - > nodes [ track_i - > 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 ( gltf_node - > skeleton > = 0 ) {
const Skeleton * sk = state - > skeletons [ gltf_node - > skeleton ] - > godot_skeleton ;
ERR_FAIL_COND ( sk = = nullptr ) ;
const String path = ap - > get_parent ( ) - > get_path_to ( sk ) ;
const String bone = gltf_node - > get_name ( ) ;
node_path = path + " : " + bone ;
transform_ node_path = path + " : " + bone ;
} else {
Node * root = ap - > get_parent ( ) ;
Node * godot_node = state - > scene_nodes . find ( node_index ) - > get ( ) ;
node_path = root - > get_path_to ( godot_node ) ;
transform_node_path = node_path ;
}
for ( int i = 0 ; i < track . rotation_track . times . size ( ) ; i + + ) {
@ -5775,11 +5771,13 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap,
}
}
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 = gltf_node - > skeleton < 0 & & gltf_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) ;
//first determine animation length
const double increment = 1.0 / bake_fps ;