2017-03-05 15:47:28 +01:00
/**************************************************************************/
/* resource_importer_scene.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
2018-01-05 00:50:27 +01:00
2017-02-04 13:48:04 +01:00
# include "resource_importer_scene.h"
2021-12-14 06:34:18 +01:00
# include "core/error/error_macros.h"
2023-10-23 21:26:38 +02:00
# include "core/io/dir_access.h"
2018-09-11 18:13:45 +02:00
# include "core/io/resource_saver.h"
2023-09-06 21:02:52 +02:00
# include "core/object/script_language.h"
2017-03-05 14:21:25 +01:00
# include "editor/editor_node.h"
2023-04-30 23:13:28 +02:00
# include "editor/editor_settings.h"
2021-10-09 08:12:51 +02:00
# include "editor/import/3d/scene_import_settings.h"
2021-09-21 03:24:31 +02:00
# include "scene/3d/importer_mesh_instance_3d.h"
2020-03-26 22:49:16 +01:00
# include "scene/3d/mesh_instance_3d.h"
2021-03-08 09:47:18 +01:00
# include "scene/3d/navigation_region_3d.h"
2022-02-04 16:28:18 +01:00
# include "scene/3d/occluder_instance_3d.h"
2024-02-26 07:15:31 +01:00
# include "scene/3d/physics/area_3d.h"
# include "scene/3d/physics/collision_shape_3d.h"
# include "scene/3d/physics/physics_body_3d.h"
# include "scene/3d/physics/static_body_3d.h"
# include "scene/3d/physics/vehicle_body_3d.h"
2017-09-08 13:06:09 +02:00
# include "scene/animation/animation_player.h"
2021-08-13 18:42:45 +02:00
# include "scene/resources/3d/box_shape_3d.h"
# include "scene/resources/3d/importer_mesh.h"
# include "scene/resources/3d/separation_ray_shape_3d.h"
# include "scene/resources/3d/sphere_shape_3d.h"
# include "scene/resources/3d/world_boundary_shape_3d.h"
2017-09-08 13:06:09 +02:00
# include "scene/resources/animation.h"
2024-02-25 17:06:37 +01:00
# include "scene/resources/bone_map.h"
2020-01-21 21:32:27 +01:00
# include "scene/resources/packed_scene.h"
2019-02-12 17:18:13 +01:00
# include "scene/resources/resource_format_text.h"
2020-12-17 19:56:59 +01:00
# include "scene/resources/surface_tool.h"
2017-02-04 13:48:04 +01:00
2021-10-14 19:34:27 +02:00
uint32_t EditorSceneFormatImporter : : get_import_flags ( ) const {
2023-01-15 20:33:20 +01:00
uint32_t ret ;
2021-08-22 03:52:44 +02:00
if ( GDVIRTUAL_CALL ( _get_import_flags , ret ) ) {
return ret ;
2017-12-07 19:44:20 +01:00
}
ERR_FAIL_V ( 0 ) ;
}
2020-05-14 14:29:06 +02:00
2021-10-14 19:34:27 +02:00
void EditorSceneFormatImporter : : get_extensions ( List < String > * r_extensions ) const {
2021-08-22 03:52:44 +02:00
Vector < String > arr ;
if ( GDVIRTUAL_CALL ( _get_extensions , arr ) ) {
2017-12-09 18:11:26 +01:00
for ( int i = 0 ; i < arr . size ( ) ; i + + ) {
2017-12-07 19:44:20 +01:00
r_extensions - > push_back ( arr [ i ] ) ;
}
return ;
}
ERR_FAIL ( ) ;
}
2020-05-14 14:29:06 +02:00
2022-11-14 20:14:52 +01:00
Node * EditorSceneFormatImporter : : import_scene ( const String & p_path , uint32_t p_flags , const HashMap < StringName , Variant > & p_options , List < String > * r_missing_deps , Error * r_err ) {
2021-12-14 06:34:18 +01:00
Dictionary options_dict ;
for ( const KeyValue < StringName , Variant > & elem : p_options ) {
options_dict [ elem . key ] = elem . value ;
}
Object * ret = nullptr ;
2022-11-14 20:14:52 +01:00
if ( GDVIRTUAL_CALL ( _import_scene , p_path , p_flags , options_dict , ret ) ) {
2021-08-22 03:52:44 +02:00
return Object : : cast_to < Node > ( ret ) ;
2017-12-07 19:44:20 +01:00
}
2020-04-02 01:20:12 +02:00
ERR_FAIL_V ( nullptr ) ;
2017-12-07 19:44:20 +01:00
}
2021-11-14 18:02:38 +01:00
void EditorSceneFormatImporter : : get_import_options ( const String & p_path , List < ResourceImporter : : ImportOption > * r_options ) {
GDVIRTUAL_CALL ( _get_import_options , p_path ) ;
}
2022-05-13 15:04:37 +02:00
Variant EditorSceneFormatImporter : : get_option_visibility ( const String & p_path , bool p_for_animation , const String & p_option , const HashMap < StringName , Variant > & p_options ) {
2021-11-14 18:02:38 +01:00
Variant ret ;
2022-04-12 16:07:09 +02:00
GDVIRTUAL_CALL ( _get_option_visibility , p_path , p_for_animation , p_option , ret ) ;
2021-11-14 18:02:38 +01:00
return ret ;
}
2021-10-14 19:34:27 +02:00
void EditorSceneFormatImporter : : _bind_methods ( ) {
2021-08-22 03:52:44 +02:00
GDVIRTUAL_BIND ( _get_import_flags ) ;
GDVIRTUAL_BIND ( _get_extensions ) ;
2022-11-14 20:14:52 +01:00
GDVIRTUAL_BIND ( _import_scene , " path " , " flags " , " options " ) ;
2021-11-14 18:02:38 +01:00
GDVIRTUAL_BIND ( _get_import_options , " path " ) ;
2022-04-12 16:07:09 +02:00
GDVIRTUAL_BIND ( _get_option_visibility , " path " , " for_animation " , " option " ) ;
2017-12-07 19:44:20 +01:00
2017-12-09 18:11:26 +01:00
BIND_CONSTANT ( IMPORT_SCENE ) ;
BIND_CONSTANT ( IMPORT_ANIMATION ) ;
BIND_CONSTANT ( IMPORT_FAIL_ON_MISSING_DEPENDENCIES ) ;
2021-03-19 13:57:52 +01:00
BIND_CONSTANT ( IMPORT_GENERATE_TANGENT_ARRAYS ) ;
BIND_CONSTANT ( IMPORT_USE_NAMED_SKIN_BINDS ) ;
2022-04-12 16:07:09 +02:00
BIND_CONSTANT ( IMPORT_DISCARD_MESHES_AND_MATERIALS ) ;
2023-08-29 21:04:32 +02:00
BIND_CONSTANT ( IMPORT_FORCE_DISABLE_MESH_COMPRESSION ) ;
2017-12-07 19:44:20 +01:00
}
/////////////////////////////////
2017-02-04 13:48:04 +01:00
void EditorScenePostImport : : _bind_methods ( ) {
2021-08-22 03:52:44 +02:00
GDVIRTUAL_BIND ( _post_import , " scene " )
2018-01-20 00:48:44 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_source_file " ) , & EditorScenePostImport : : get_source_file ) ;
2017-02-04 13:48:04 +01:00
}
Node * EditorScenePostImport : : post_import ( Node * p_scene ) {
2021-08-22 03:52:44 +02:00
Object * ret ;
if ( GDVIRTUAL_CALL ( _post_import , p_scene , ret ) ) {
return Object : : cast_to < Node > ( ret ) ;
2020-05-14 16:41:43 +02:00
}
2017-02-04 13:48:04 +01:00
return p_scene ;
}
2018-01-20 00:48:44 +01:00
String EditorScenePostImport : : get_source_file ( ) const {
return source_file ;
}
2021-03-19 13:57:52 +01:00
void EditorScenePostImport : : init ( const String & p_source_file ) {
2018-01-20 00:48:44 +01:00
source_file = p_source_file ;
}
2017-02-04 13:48:04 +01:00
EditorScenePostImport : : EditorScenePostImport ( ) {
}
2021-10-14 19:34:27 +02:00
///////////////////////////////////////////////////////
Variant EditorScenePostImportPlugin : : get_option_value ( const StringName & p_name ) const {
ERR_FAIL_COND_V_MSG ( current_options = = nullptr & & current_options_dict = = nullptr , Variant ( ) , " get_option_value called from a function where option values are not available. " ) ;
ERR_FAIL_COND_V_MSG ( current_options & & ! current_options - > has ( p_name ) , Variant ( ) , " get_option_value called with unexisting option argument: " + String ( p_name ) ) ;
ERR_FAIL_COND_V_MSG ( current_options_dict & & ! current_options_dict - > has ( p_name ) , Variant ( ) , " get_option_value called with unexisting option argument: " + String ( p_name ) ) ;
2022-07-06 22:11:09 +02:00
if ( current_options & & current_options - > has ( p_name ) ) {
return ( * current_options ) [ p_name ] ;
2021-10-14 19:34:27 +02:00
}
2022-07-06 22:11:09 +02:00
if ( current_options_dict & & current_options_dict - > has ( p_name ) ) {
return ( * current_options_dict ) [ p_name ] ;
2021-10-14 19:34:27 +02:00
}
return Variant ( ) ;
}
2024-02-15 17:25:58 +01:00
void EditorScenePostImportPlugin : : add_import_option ( const String & p_name , const Variant & p_default_value ) {
2023-09-09 17:24:40 +02:00
ERR_FAIL_NULL_MSG ( current_option_list , " add_import_option() can only be called from get_import_options(). " ) ;
2021-10-14 19:34:27 +02:00
add_import_option_advanced ( p_default_value . get_type ( ) , p_name , p_default_value ) ;
}
2024-02-15 17:25:58 +01:00
void EditorScenePostImportPlugin : : add_import_option_advanced ( Variant : : Type p_type , const String & p_name , const Variant & p_default_value , PropertyHint p_hint , const String & p_hint_string , int p_usage_flags ) {
2023-09-09 17:24:40 +02:00
ERR_FAIL_NULL_MSG ( current_option_list , " add_import_option_advanced() can only be called from get_import_options(). " ) ;
2021-10-14 19:34:27 +02:00
current_option_list - > push_back ( ResourceImporter : : ImportOption ( PropertyInfo ( p_type , p_name , p_hint , p_hint_string , p_usage_flags ) , p_default_value ) ) ;
}
void EditorScenePostImportPlugin : : get_internal_import_options ( InternalImportCategory p_category , List < ResourceImporter : : ImportOption > * r_options ) {
current_option_list = r_options ;
GDVIRTUAL_CALL ( _get_internal_import_options , p_category ) ;
current_option_list = nullptr ;
}
2022-05-13 15:04:37 +02:00
Variant EditorScenePostImportPlugin : : get_internal_option_visibility ( InternalImportCategory p_category , bool p_for_animation , const String & p_option , const HashMap < StringName , Variant > & p_options ) const {
2021-10-14 19:34:27 +02:00
current_options = & p_options ;
Variant ret ;
2022-04-12 16:07:09 +02:00
GDVIRTUAL_CALL ( _get_internal_option_visibility , p_category , p_for_animation , p_option , ret ) ;
2021-10-14 19:34:27 +02:00
current_options = nullptr ;
return ret ;
}
2022-05-13 15:04:37 +02:00
Variant EditorScenePostImportPlugin : : get_internal_option_update_view_required ( InternalImportCategory p_category , const String & p_option , const HashMap < StringName , Variant > & p_options ) const {
2021-10-14 19:34:27 +02:00
current_options = & p_options ;
Variant ret ;
GDVIRTUAL_CALL ( _get_internal_option_update_view_required , p_category , p_option , ret ) ;
current_options = nullptr ;
return ret ;
}
2022-05-03 01:43:50 +02:00
void EditorScenePostImportPlugin : : internal_process ( InternalImportCategory p_category , Node * p_base_scene , Node * p_node , Ref < Resource > p_resource , const Dictionary & p_options ) {
2021-10-14 19:34:27 +02:00
current_options_dict = & p_options ;
GDVIRTUAL_CALL ( _internal_process , p_category , p_base_scene , p_node , p_resource ) ;
current_options_dict = nullptr ;
}
2021-11-14 18:02:38 +01:00
void EditorScenePostImportPlugin : : get_import_options ( const String & p_path , List < ResourceImporter : : ImportOption > * r_options ) {
2021-10-14 19:34:27 +02:00
current_option_list = r_options ;
2021-11-14 18:02:38 +01:00
GDVIRTUAL_CALL ( _get_import_options , p_path ) ;
2021-10-14 19:34:27 +02:00
current_option_list = nullptr ;
}
2022-05-13 15:04:37 +02:00
Variant EditorScenePostImportPlugin : : get_option_visibility ( const String & p_path , bool p_for_animation , const String & p_option , const HashMap < StringName , Variant > & p_options ) const {
2021-10-14 19:34:27 +02:00
current_options = & p_options ;
Variant ret ;
2022-04-12 16:07:09 +02:00
GDVIRTUAL_CALL ( _get_option_visibility , p_path , p_for_animation , p_option , ret ) ;
2021-10-14 19:34:27 +02:00
current_options = nullptr ;
return ret ;
}
2022-05-13 15:04:37 +02:00
void EditorScenePostImportPlugin : : pre_process ( Node * p_scene , const HashMap < StringName , Variant > & p_options ) {
2021-10-14 19:34:27 +02:00
current_options = & p_options ;
GDVIRTUAL_CALL ( _pre_process , p_scene ) ;
current_options = nullptr ;
}
2022-05-13 15:04:37 +02:00
void EditorScenePostImportPlugin : : post_process ( Node * p_scene , const HashMap < StringName , Variant > & p_options ) {
2021-10-14 19:34:27 +02:00
current_options = & p_options ;
GDVIRTUAL_CALL ( _post_process , p_scene ) ;
current_options = nullptr ;
}
void EditorScenePostImportPlugin : : _bind_methods ( ) {
ClassDB : : bind_method ( D_METHOD ( " get_option_value " , " name " ) , & EditorScenePostImportPlugin : : get_option_value ) ;
ClassDB : : bind_method ( D_METHOD ( " add_import_option " , " name " , " value " ) , & EditorScenePostImportPlugin : : add_import_option ) ;
ClassDB : : bind_method ( D_METHOD ( " add_import_option_advanced " , " type " , " name " , " default_value " , " hint " , " hint_string " , " usage_flags " ) , & EditorScenePostImportPlugin : : add_import_option_advanced , DEFVAL ( PROPERTY_HINT_NONE ) , DEFVAL ( " " ) , DEFVAL ( PROPERTY_USAGE_DEFAULT ) ) ;
GDVIRTUAL_BIND ( _get_internal_import_options , " category " ) ;
2022-04-12 16:07:09 +02:00
GDVIRTUAL_BIND ( _get_internal_option_visibility , " category " , " for_animation " , " option " ) ;
2021-10-14 19:34:27 +02:00
GDVIRTUAL_BIND ( _get_internal_option_update_view_required , " category " , " option " ) ;
GDVIRTUAL_BIND ( _internal_process , " category " , " base_node " , " node " , " resource " ) ;
2021-11-14 18:02:38 +01:00
GDVIRTUAL_BIND ( _get_import_options , " path " ) ;
2022-04-12 16:07:09 +02:00
GDVIRTUAL_BIND ( _get_option_visibility , " path " , " for_animation " , " option " ) ;
2021-10-14 19:34:27 +02:00
GDVIRTUAL_BIND ( _pre_process , " scene " ) ;
GDVIRTUAL_BIND ( _post_process , " scene " ) ;
BIND_ENUM_CONSTANT ( INTERNAL_IMPORT_CATEGORY_NODE ) ;
BIND_ENUM_CONSTANT ( INTERNAL_IMPORT_CATEGORY_MESH_3D_NODE ) ;
BIND_ENUM_CONSTANT ( INTERNAL_IMPORT_CATEGORY_MESH ) ;
BIND_ENUM_CONSTANT ( INTERNAL_IMPORT_CATEGORY_MATERIAL ) ;
BIND_ENUM_CONSTANT ( INTERNAL_IMPORT_CATEGORY_ANIMATION ) ;
BIND_ENUM_CONSTANT ( INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE ) ;
2022-06-27 10:06:50 +02:00
BIND_ENUM_CONSTANT ( INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE ) ;
2021-10-14 19:34:27 +02:00
BIND_ENUM_CONSTANT ( INTERNAL_IMPORT_CATEGORY_MAX ) ;
}
/////////////////////////////////////////////////////////
2017-02-04 13:48:04 +01:00
String ResourceImporterScene : : get_importer_name ( ) const {
2022-04-12 16:07:09 +02:00
return animation_importer ? " animation_library " : " scene " ;
2017-02-04 13:48:04 +01:00
}
String ResourceImporterScene : : get_visible_name ( ) const {
2022-04-12 16:07:09 +02:00
return animation_importer ? " Animation Library " : " Scene " ;
2017-02-04 13:48:04 +01:00
}
void ResourceImporterScene : : get_recognized_extensions ( List < String > * p_extensions ) const {
2023-10-08 07:48:53 +02:00
get_scene_importer_extensions ( p_extensions ) ;
2017-02-04 13:48:04 +01:00
}
String ResourceImporterScene : : get_save_extension ( ) const {
2022-04-12 16:07:09 +02:00
return animation_importer ? " res " : " scn " ;
2017-02-04 13:48:04 +01:00
}
String ResourceImporterScene : : get_resource_type ( ) const {
2022-04-12 16:07:09 +02:00
return animation_importer ? " AnimationLibrary " : " PackedScene " ;
2017-02-04 13:48:04 +01:00
}
2020-12-02 02:40:47 +01:00
int ResourceImporterScene : : get_format_version ( ) const {
return 1 ;
}
2022-05-13 15:04:37 +02:00
bool ResourceImporterScene : : get_option_visibility ( const String & p_path , const String & p_option , const HashMap < StringName , Variant > & p_options ) const {
2022-04-12 16:07:09 +02:00
if ( animation_importer ) {
if ( p_option = = " animation/import " ) { // Option ignored, animation always imported.
return false ;
}
} else if ( p_option . begins_with ( " animation/ " ) ) {
2020-05-14 16:41:43 +02:00
if ( p_option ! = " animation/import " & & ! bool ( p_options [ " animation/import " ] ) ) {
2017-02-04 13:48:04 +01:00
return false ;
2020-05-14 16:41:43 +02:00
}
2017-07-23 23:48:05 +02:00
}
2024-05-21 12:19:35 +02:00
if ( animation_importer & & ( p_option = = " nodes/root_type " | | p_option = = " nodes/root_name " | | p_option . begins_with ( " meshes/ " ) | | p_option . begins_with ( " skins/ " ) ) ) {
2022-04-12 16:07:09 +02:00
return false ; // Nothing to do here for animations.
}
2022-01-26 00:33:47 +01:00
if ( p_option = = " meshes/lightmap_texel_size " & & int ( p_options [ " meshes/light_baking " ] ) ! = 2 ) {
// Only display the lightmap texel size import option when using the Static Lightmaps light baking mode.
2017-12-09 18:11:26 +01:00
return false ;
}
2021-10-14 19:34:27 +02:00
for ( int i = 0 ; i < post_importer_plugins . size ( ) ; i + + ) {
2022-04-12 16:07:09 +02:00
Variant ret = post_importer_plugins . write [ i ] - > get_option_visibility ( p_path , animation_importer , p_option , p_options ) ;
2021-11-14 18:02:38 +01:00
if ( ret . get_type ( ) = = Variant : : BOOL ) {
return ret ;
}
}
2023-10-08 07:48:53 +02:00
for ( Ref < EditorSceneFormatImporter > importer : scene_importers ) {
2022-04-12 16:07:09 +02:00
Variant ret = importer - > get_option_visibility ( p_path , animation_importer , p_option , p_options ) ;
2021-10-14 19:34:27 +02:00
if ( ret . get_type ( ) = = Variant : : BOOL ) {
return ret ;
}
}
2017-02-04 13:48:04 +01:00
return true ;
}
int ResourceImporterScene : : get_preset_count ( ) const {
2021-03-19 13:57:52 +01:00
return 0 ;
2017-02-04 13:48:04 +01:00
}
2020-05-14 14:29:06 +02:00
2017-02-04 13:48:04 +01:00
String ResourceImporterScene : : get_preset_name ( int p_idx ) const {
2021-03-19 13:57:52 +01:00
return String ( ) ;
2017-02-04 13:48:04 +01:00
}
2024-03-18 04:29:29 +01:00
void ResourceImporterScene : : _pre_fix_global ( Node * p_scene , const HashMap < StringName , Variant > & p_options ) const {
if ( p_options . has ( " animation/import_rest_as_RESET " ) & & ( bool ) p_options [ " animation/import_rest_as_RESET " ] ) {
TypedArray < Node > anim_players = p_scene - > find_children ( " * " , " AnimationPlayer " ) ;
if ( anim_players . is_empty ( ) ) {
AnimationPlayer * anim_player = memnew ( AnimationPlayer ) ;
anim_player - > set_name ( " AnimationPlayer " ) ;
p_scene - > add_child ( anim_player ) ;
anim_player - > set_owner ( p_scene ) ;
anim_players . append ( anim_player ) ;
}
Ref < Animation > reset_anim ;
for ( int i = 0 ; i < anim_players . size ( ) ; i + + ) {
AnimationPlayer * player = cast_to < AnimationPlayer > ( anim_players [ i ] ) ;
2024-05-13 16:56:03 +02:00
if ( player - > has_animation ( SceneStringName ( RESET ) ) ) {
reset_anim = player - > get_animation ( SceneStringName ( RESET ) ) ;
2024-03-18 04:29:29 +01:00
break ;
}
}
if ( reset_anim . is_null ( ) ) {
AnimationPlayer * anim_player = cast_to < AnimationPlayer > ( anim_players [ 0 ] ) ;
reset_anim . instantiate ( ) ;
Ref < AnimationLibrary > anim_library ;
if ( anim_player - > has_animation_library ( StringName ( ) ) ) {
anim_library = anim_player - > get_animation_library ( StringName ( ) ) ;
} else {
anim_library . instantiate ( ) ;
anim_player - > add_animation_library ( StringName ( ) , anim_library ) ;
}
2024-05-13 16:56:03 +02:00
anim_library - > add_animation ( SceneStringName ( RESET ) , reset_anim ) ;
2024-03-18 04:29:29 +01:00
}
TypedArray < Node > skeletons = p_scene - > find_children ( " * " , " Skeleton3D " ) ;
for ( int i = 0 ; i < skeletons . size ( ) ; i + + ) {
Skeleton3D * skeleton = cast_to < Skeleton3D > ( skeletons [ i ] ) ;
NodePath skeleton_path = p_scene - > get_path_to ( skeleton ) ;
HashSet < NodePath > existing_pos_tracks ;
HashSet < NodePath > existing_rot_tracks ;
for ( int trk_i = 0 ; trk_i < reset_anim - > get_track_count ( ) ; trk_i + + ) {
NodePath np = reset_anim - > track_get_path ( trk_i ) ;
if ( reset_anim - > track_get_type ( trk_i ) = = Animation : : TYPE_POSITION_3D ) {
existing_pos_tracks . insert ( np ) ;
}
if ( reset_anim - > track_get_type ( trk_i ) = = Animation : : TYPE_ROTATION_3D ) {
existing_rot_tracks . insert ( np ) ;
}
}
for ( int bone_i = 0 ; bone_i < skeleton - > get_bone_count ( ) ; bone_i + + ) {
NodePath bone_path ( skeleton_path . get_names ( ) , Vector < StringName > { skeleton - > get_bone_name ( bone_i ) } , false ) ;
if ( ! existing_pos_tracks . has ( bone_path ) ) {
int pos_t = reset_anim - > add_track ( Animation : : TYPE_POSITION_3D ) ;
reset_anim - > track_set_path ( pos_t , bone_path ) ;
reset_anim - > position_track_insert_key ( pos_t , 0.0 , skeleton - > get_bone_rest ( bone_i ) . origin ) ;
reset_anim - > track_set_imported ( pos_t , true ) ;
}
if ( ! existing_rot_tracks . has ( bone_path ) ) {
int rot_t = reset_anim - > add_track ( Animation : : TYPE_ROTATION_3D ) ;
reset_anim - > track_set_path ( rot_t , bone_path ) ;
reset_anim - > rotation_track_insert_key ( rot_t , 0.0 , skeleton - > get_bone_rest ( bone_i ) . basis . get_rotation_quaternion ( ) ) ;
reset_anim - > track_set_imported ( rot_t , true ) ;
}
}
}
}
}
2017-02-04 13:48:04 +01:00
static bool _teststr ( const String & p_what , const String & p_str ) {
2018-07-02 10:54:14 +02:00
String what = p_what ;
2018-07-02 07:02:32 +02:00
2023-07-05 06:32:47 +02:00
// Remove trailing spaces and numbers, some apps like blender add ".number" to duplicates
// (dot is replaced with _ as invalid character) so also compensate for this.
while ( what . length ( ) & & ( is_digit ( what [ what . length ( ) - 1 ] ) | | what [ what . length ( ) - 1 ] < = 32 | | what [ what . length ( ) - 1 ] = = ' _ ' ) ) {
2018-07-02 10:54:14 +02:00
what = what . substr ( 0 , what . length ( ) - 1 ) ;
2018-07-02 07:02:32 +02:00
}
2024-05-06 10:26:10 +02:00
if ( what . containsn ( " $ " + p_str ) ) { // Blender and other stuff.
2017-02-04 13:48:04 +01:00
return true ;
2020-05-14 16:41:43 +02:00
}
if ( what . to_lower ( ) . ends_with ( " - " + p_str ) ) { //collada only supports "_" and "-" besides letters
2017-02-04 13:48:04 +01:00
return true ;
2020-05-14 16:41:43 +02:00
}
if ( what . to_lower ( ) . ends_with ( " _ " + p_str ) ) { //collada only supports "_" and "-" besides letters
2017-02-04 13:48:04 +01:00
return true ;
2020-05-14 16:41:43 +02:00
}
2017-02-04 13:48:04 +01:00
return false ;
}
static String _fixstr ( const String & p_what , const String & p_str ) {
2018-07-02 10:54:14 +02:00
String what = p_what ;
2023-07-05 06:32:47 +02:00
// Remove trailing spaces and numbers, some apps like blender add ".number" to duplicates
// (dot is replaced with _ as invalid character) so also compensate for this.
while ( what . length ( ) & & ( is_digit ( what [ what . length ( ) - 1 ] ) | | what [ what . length ( ) - 1 ] < = 32 | | what [ what . length ( ) - 1 ] = = ' _ ' ) ) {
2018-07-02 10:54:14 +02:00
what = what . substr ( 0 , what . length ( ) - 1 ) ;
}
String end = p_what . substr ( what . length ( ) , p_what . length ( ) - what . length ( ) ) ;
2024-05-06 10:26:10 +02:00
if ( what . containsn ( " $ " + p_str ) ) { // Blender and other stuff.
2018-07-02 10:54:14 +02:00
return what . replace ( " $ " + p_str , " " ) + end ;
2020-05-14 16:41:43 +02:00
}
if ( what . to_lower ( ) . ends_with ( " - " + p_str ) ) { //collada only supports "_" and "-" besides letters
2018-07-02 10:54:14 +02:00
return what . substr ( 0 , what . length ( ) - ( p_str . length ( ) + 1 ) ) + end ;
2020-05-14 16:41:43 +02:00
}
if ( what . to_lower ( ) . ends_with ( " _ " + p_str ) ) { //collada only supports "_" and "-" besides letters
2018-07-02 10:54:14 +02:00
return what . substr ( 0 , what . length ( ) - ( p_str . length ( ) + 1 ) ) + end ;
2020-05-14 16:41:43 +02:00
}
2018-07-02 10:54:14 +02:00
return what ;
2017-02-04 13:48:04 +01:00
}
2021-09-21 03:24:31 +02:00
static void _pre_gen_shape_list ( Ref < ImporterMesh > & mesh , Vector < Ref < Shape3D > > & r_shape_list , bool p_convex ) {
2023-09-09 17:24:40 +02:00
ERR_FAIL_NULL_MSG ( mesh , " Cannot generate shape list with null mesh value. " ) ;
2021-03-19 13:57:52 +01:00
if ( ! p_convex ) {
2022-11-25 18:43:06 +01:00
Ref < ConcavePolygonShape3D > shape = mesh - > create_trimesh_shape ( ) ;
2021-03-19 13:57:52 +01:00
r_shape_list . push_back ( shape ) ;
} else {
Improve collision generation usability in the new 3D scene import workflow.
With this PR it's possible to add a collision during the Mesh import, directly in editor.
To generate the shape is possible to chose between the following options:
- Decompose Convex: The Mesh is decomposed in one or many Convex Shapes (Using the VHACD library).
- Simple Convex: Is generated a convex shape that enclose the entire mesh.
- Trimesh: Generate a trimesh shape using the Mesh faces.
- Box: Add a primitive box shape, where you can tweak the `size`, `position`, `rotation`.
- Sphere: Add a primitive sphere shape, where you can tweak the `radius`, `position`, `rotation`.
- Cylinder: Add a primitive cylinder shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
- Capsule: Add a primitive capsule shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
It's also possible to chose the generated body, so you can create:
- Rigid Body
- Static Body
- Area
2021-08-22 18:19:13 +02:00
Vector < Ref < Shape3D > > cd ;
2023-02-23 11:07:48 +01:00
cd . push_back ( mesh - > create_convex_shape ( true , /*Passing false, otherwise VHACD will be used to simplify (Decompose) the Mesh.*/ false ) ) ;
2021-03-19 13:57:52 +01:00
if ( cd . size ( ) ) {
for ( int i = 0 ; i < cd . size ( ) ; i + + ) {
r_shape_list . push_back ( cd [ i ] ) ;
}
}
}
}
2022-02-04 08:34:59 +01:00
struct ScalableNodeCollection {
HashSet < Node3D * > node_3ds ;
HashSet < Ref < ImporterMesh > > importer_meshes ;
HashSet < Ref < Skin > > skins ;
HashSet < Ref < Animation > > animations ;
} ;
void _rescale_importer_mesh ( Vector3 p_scale , Ref < ImporterMesh > p_mesh , bool is_shadow = false ) {
// MESH and SKIN data divide, to compensate for object position multiplying.
const int surf_count = p_mesh - > get_surface_count ( ) ;
const int blendshape_count = p_mesh - > get_blend_shape_count ( ) ;
struct LocalSurfData {
Mesh : : PrimitiveType prim = { } ;
Array arr ;
Array bsarr ;
Dictionary lods ;
String name ;
Ref < Material > mat ;
2023-10-12 22:01:41 +02:00
uint64_t fmt_compress_flags = 0 ;
2022-02-04 08:34:59 +01:00
} ;
Vector < LocalSurfData > surf_data_by_mesh ;
Vector < String > blendshape_names ;
for ( int bsidx = 0 ; bsidx < blendshape_count ; bsidx + + ) {
blendshape_names . append ( p_mesh - > get_blend_shape_name ( bsidx ) ) ;
}
for ( int surf_idx = 0 ; surf_idx < surf_count ; surf_idx + + ) {
Mesh : : PrimitiveType prim = p_mesh - > get_surface_primitive_type ( surf_idx ) ;
2023-10-12 22:01:41 +02:00
const uint64_t fmt_compress_flags = p_mesh - > get_surface_format ( surf_idx ) ;
2022-02-04 08:34:59 +01:00
Array arr = p_mesh - > get_surface_arrays ( surf_idx ) ;
String name = p_mesh - > get_surface_name ( surf_idx ) ;
2022-11-14 18:21:06 +01:00
Dictionary lods ;
2022-02-04 08:34:59 +01:00
Ref < Material > mat = p_mesh - > get_surface_material ( surf_idx ) ;
{
Vector < Vector3 > vertex_array = arr [ ArrayMesh : : ARRAY_VERTEX ] ;
for ( int vert_arr_i = 0 ; vert_arr_i < vertex_array . size ( ) ; vert_arr_i + + ) {
vertex_array . write [ vert_arr_i ] = vertex_array [ vert_arr_i ] * p_scale ;
}
arr [ ArrayMesh : : ARRAY_VERTEX ] = vertex_array ;
}
Array blendshapes ;
for ( int bsidx = 0 ; bsidx < blendshape_count ; bsidx + + ) {
Array current_bsarr = p_mesh - > get_surface_blend_shape_arrays ( surf_idx , bsidx ) ;
Vector < Vector3 > current_bs_vertex_array = current_bsarr [ ArrayMesh : : ARRAY_VERTEX ] ;
int current_bs_vert_arr_len = current_bs_vertex_array . size ( ) ;
for ( int32_t bs_vert_arr_i = 0 ; bs_vert_arr_i < current_bs_vert_arr_len ; bs_vert_arr_i + + ) {
current_bs_vertex_array . write [ bs_vert_arr_i ] = current_bs_vertex_array [ bs_vert_arr_i ] * p_scale ;
}
current_bsarr [ ArrayMesh : : ARRAY_VERTEX ] = current_bs_vertex_array ;
blendshapes . push_back ( current_bsarr ) ;
}
LocalSurfData surf_data_dictionary = LocalSurfData ( ) ;
surf_data_dictionary . prim = prim ;
surf_data_dictionary . arr = arr ;
surf_data_dictionary . bsarr = blendshapes ;
surf_data_dictionary . lods = lods ;
surf_data_dictionary . fmt_compress_flags = fmt_compress_flags ;
surf_data_dictionary . name = name ;
surf_data_dictionary . mat = mat ;
surf_data_by_mesh . push_back ( surf_data_dictionary ) ;
}
p_mesh - > clear ( ) ;
for ( int bsidx = 0 ; bsidx < blendshape_count ; bsidx + + ) {
p_mesh - > add_blend_shape ( blendshape_names [ bsidx ] ) ;
}
for ( int surf_idx = 0 ; surf_idx < surf_count ; surf_idx + + ) {
const Mesh : : PrimitiveType prim = surf_data_by_mesh [ surf_idx ] . prim ;
const Array arr = surf_data_by_mesh [ surf_idx ] . arr ;
const Array bsarr = surf_data_by_mesh [ surf_idx ] . bsarr ;
const Dictionary lods = surf_data_by_mesh [ surf_idx ] . lods ;
2023-10-12 22:01:41 +02:00
const uint64_t fmt_compress_flags = surf_data_by_mesh [ surf_idx ] . fmt_compress_flags ;
2022-02-04 08:34:59 +01:00
const String name = surf_data_by_mesh [ surf_idx ] . name ;
const Ref < Material > mat = surf_data_by_mesh [ surf_idx ] . mat ;
p_mesh - > add_surface ( prim , arr , bsarr , lods , mat , name , fmt_compress_flags ) ;
}
if ( ! is_shadow & & p_mesh - > get_shadow_mesh ( ) ! = p_mesh & & p_mesh - > get_shadow_mesh ( ) . is_valid ( ) ) {
_rescale_importer_mesh ( p_scale , p_mesh - > get_shadow_mesh ( ) , true ) ;
}
}
void _rescale_skin ( Vector3 p_scale , Ref < Skin > p_skin ) {
// MESH and SKIN data divide, to compensate for object position multiplying.
for ( int i = 0 ; i < p_skin - > get_bind_count ( ) ; i + + ) {
Transform3D transform = p_skin - > get_bind_pose ( i ) ;
p_skin - > set_bind_pose ( i , Transform3D ( transform . basis , p_scale * transform . origin ) ) ;
}
}
void _rescale_animation ( Vector3 p_scale , Ref < Animation > p_animation ) {
for ( int track_idx = 0 ; track_idx < p_animation - > get_track_count ( ) ; track_idx + + ) {
if ( p_animation - > track_get_type ( track_idx ) = = Animation : : TYPE_POSITION_3D ) {
for ( int key_idx = 0 ; key_idx < p_animation - > track_get_key_count ( track_idx ) ; key_idx + + ) {
Vector3 value = p_animation - > track_get_key_value ( track_idx , key_idx ) ;
value = p_scale * value ;
p_animation - > track_set_key_value ( track_idx , key_idx , value ) ;
}
}
}
}
2023-02-06 00:29:19 +01:00
void _apply_scale_to_scalable_node_collection ( ScalableNodeCollection & p_collection , Vector3 p_scale ) {
for ( Node3D * node_3d : p_collection . node_3ds ) {
node_3d - > set_position ( p_scale * node_3d - > get_position ( ) ) ;
Skeleton3D * skeleton_3d = Object : : cast_to < Skeleton3D > ( node_3d ) ;
if ( skeleton_3d ) {
for ( int i = 0 ; i < skeleton_3d - > get_bone_count ( ) ; i + + ) {
Transform3D rest = skeleton_3d - > get_bone_rest ( i ) ;
2024-02-16 14:25:15 +01:00
Vector3 position = skeleton_3d - > get_bone_pose_position ( i ) ;
2023-02-06 00:29:19 +01:00
skeleton_3d - > set_bone_rest ( i , Transform3D ( rest . basis , p_scale * rest . origin ) ) ;
2024-02-16 14:25:15 +01:00
skeleton_3d - > set_bone_pose_position ( i , p_scale * position ) ;
2022-02-04 08:34:59 +01:00
}
}
}
2023-02-06 00:29:19 +01:00
for ( Ref < ImporterMesh > mesh : p_collection . importer_meshes ) {
2022-02-04 08:34:59 +01:00
_rescale_importer_mesh ( p_scale , mesh , false ) ;
}
2023-02-06 00:29:19 +01:00
for ( Ref < Skin > skin : p_collection . skins ) {
2022-02-04 08:34:59 +01:00
_rescale_skin ( p_scale , skin ) ;
}
2023-02-06 00:29:19 +01:00
for ( Ref < Animation > animation : p_collection . animations ) {
2022-02-04 08:34:59 +01:00
_rescale_animation ( p_scale , animation ) ;
}
}
2023-02-06 00:29:19 +01:00
void _populate_scalable_nodes_collection ( Node * p_node , ScalableNodeCollection & p_collection ) {
2022-02-04 08:34:59 +01:00
if ( ! p_node ) {
return ;
}
Node3D * node_3d = Object : : cast_to < Node3D > ( p_node ) ;
if ( node_3d ) {
2023-02-06 00:29:19 +01:00
p_collection . node_3ds . insert ( node_3d ) ;
2022-02-04 08:34:59 +01:00
ImporterMeshInstance3D * mesh_instance_3d = Object : : cast_to < ImporterMeshInstance3D > ( p_node ) ;
if ( mesh_instance_3d ) {
Ref < ImporterMesh > mesh = mesh_instance_3d - > get_mesh ( ) ;
if ( mesh . is_valid ( ) ) {
2023-02-06 00:29:19 +01:00
p_collection . importer_meshes . insert ( mesh ) ;
2022-02-04 08:34:59 +01:00
}
Ref < Skin > skin = mesh_instance_3d - > get_skin ( ) ;
if ( skin . is_valid ( ) ) {
2023-02-06 00:29:19 +01:00
p_collection . skins . insert ( skin ) ;
2022-02-04 08:34:59 +01:00
}
}
}
AnimationPlayer * animation_player = Object : : cast_to < AnimationPlayer > ( p_node ) ;
if ( animation_player ) {
List < StringName > animation_list ;
animation_player - > get_animation_list ( & animation_list ) ;
for ( const StringName & E : animation_list ) {
Ref < Animation > animation = animation_player - > get_animation ( E ) ;
2023-02-06 00:29:19 +01:00
p_collection . animations . insert ( animation ) ;
2022-02-04 08:34:59 +01:00
}
}
for ( int i = 0 ; i < p_node - > get_child_count ( ) ; i + + ) {
Node * child = p_node - > get_child ( i ) ;
2023-02-06 00:29:19 +01:00
_populate_scalable_nodes_collection ( child , p_collection ) ;
2022-02-04 08:34:59 +01:00
}
}
2023-02-06 00:29:19 +01:00
void _apply_permanent_scale_to_descendants ( Node * p_root_node , Vector3 p_scale ) {
2022-02-04 08:34:59 +01:00
ScalableNodeCollection scalable_node_collection ;
2023-02-06 00:29:19 +01:00
_populate_scalable_nodes_collection ( p_root_node , scalable_node_collection ) ;
_apply_scale_to_scalable_node_collection ( scalable_node_collection , p_scale ) ;
2022-02-04 08:34:59 +01:00
}
2022-05-13 15:04:37 +02:00
Node * ResourceImporterScene : : _pre_fix_node ( Node * p_node , Node * p_root , HashMap < Ref < ImporterMesh > , Vector < Ref < Shape3D > > > & r_collision_map , Pair < PackedVector3Array , PackedInt32Array > * r_occluder_arrays , List < Pair < NodePath , Node * > > & r_node_renames ) {
2020-10-24 00:57:48 +02:00
// Children first.
2017-02-04 13:48:04 +01:00
for ( int i = 0 ; i < p_node - > get_child_count ( ) ; i + + ) {
2022-02-04 16:28:18 +01:00
Node * r = _pre_fix_node ( p_node - > get_child ( i ) , p_root , r_collision_map , r_occluder_arrays , r_node_renames ) ;
2017-02-04 13:48:04 +01:00
if ( ! r ) {
2020-10-24 00:57:48 +02:00
i - - ; // Was erased.
2017-02-04 13:48:04 +01:00
}
}
String name = p_node - > get_name ( ) ;
2020-10-24 00:57:48 +02:00
NodePath original_path = p_root - > get_path_to ( p_node ) ; // Used to detect renames due to import hints.
2017-02-04 13:48:04 +01:00
bool isroot = p_node = = p_root ;
if ( ! isroot & & _teststr ( name , " noimp " ) ) {
2023-02-27 17:24:03 +01:00
p_node - > set_owner ( nullptr ) ;
2017-02-04 13:48:04 +01:00
memdelete ( p_node ) ;
2020-04-02 01:20:12 +02:00
return nullptr ;
2017-02-04 13:48:04 +01:00
}
2021-09-21 03:24:31 +02:00
if ( Object : : cast_to < ImporterMeshInstance3D > ( p_node ) ) {
ImporterMeshInstance3D * mi = Object : : cast_to < ImporterMeshInstance3D > ( p_node ) ;
2017-02-04 13:48:04 +01:00
2021-09-21 03:24:31 +02:00
Ref < ImporterMesh > m = mi - > get_mesh ( ) ;
2017-02-04 13:48:04 +01:00
if ( m . is_valid ( ) ) {
for ( int i = 0 ; i < m - > get_surface_count ( ) ; i + + ) {
2021-03-19 13:57:52 +01:00
Ref < BaseMaterial3D > mat = m - > get_surface_material ( i ) ;
2020-05-14 16:41:43 +02:00
if ( ! mat . is_valid ( ) ) {
2017-02-04 13:48:04 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2017-02-04 13:48:04 +01:00
if ( _teststr ( mat - > get_name ( ) , " alpha " ) ) {
2021-03-19 13:57:52 +01:00
mat - > set_transparency ( BaseMaterial3D : : TRANSPARENCY_ALPHA ) ;
2017-02-04 13:48:04 +01:00
mat - > set_name ( _fixstr ( mat - > get_name ( ) , " alpha " ) ) ;
}
if ( _teststr ( mat - > get_name ( ) , " vcol " ) ) {
2021-03-19 13:57:52 +01:00
mat - > set_flag ( BaseMaterial3D : : FLAG_ALBEDO_FROM_VERTEX_COLOR , true ) ;
mat - > set_flag ( BaseMaterial3D : : FLAG_SRGB_VERTEX_COLOR , true ) ;
2017-02-04 13:48:04 +01:00
mat - > set_name ( _fixstr ( mat - > get_name ( ) , " vcol " ) ) ;
}
}
}
}
2017-08-24 22:58:51 +02:00
if ( Object : : cast_to < AnimationPlayer > ( p_node ) ) {
AnimationPlayer * ap = Object : : cast_to < AnimationPlayer > ( p_node ) ;
2017-02-04 13:48:04 +01:00
2020-10-24 00:57:48 +02:00
// Node paths in animation tracks are relative to the following path (this is used to fix node paths below).
2023-07-20 17:34:06 +02:00
Node * ap_root = ap - > get_node ( ap - > get_root_node ( ) ) ;
2020-10-24 00:57:48 +02:00
NodePath path_prefix = p_root - > get_path_to ( ap_root ) ;
bool nodes_were_renamed = r_node_renames . size ( ) ! = 0 ;
2017-02-04 13:48:04 +01:00
List < StringName > anims ;
ap - > get_animation_list ( & anims ) ;
2021-07-24 15:46:25 +02:00
for ( const StringName & E : anims ) {
2021-07-16 05:45:57 +02:00
Ref < Animation > anim = ap - > get_animation ( E ) ;
2017-02-04 13:48:04 +01:00
ERR_CONTINUE ( anim . is_null ( ) ) ;
2020-10-24 00:57:48 +02:00
// Remove animation tracks referencing non-importable nodes.
2017-02-04 13:48:04 +01:00
for ( int i = 0 ; i < anim - > get_track_count ( ) ; i + + ) {
NodePath path = anim - > track_get_path ( i ) ;
for ( int j = 0 ; j < path . get_name_count ( ) ; j + + ) {
String node = path . get_name ( j ) ;
if ( _teststr ( node , " noimp " ) ) {
anim - > remove_track ( i ) ;
i - - ;
break ;
}
}
}
2021-03-19 13:57:52 +01:00
2020-10-24 00:57:48 +02:00
// Fix node paths in animations, in case nodes were renamed earlier due to import hints.
if ( nodes_were_renamed ) {
for ( int i = 0 ; i < anim - > get_track_count ( ) ; i + + ) {
NodePath path = anim - > track_get_path ( i ) ;
// Convert track path to absolute node path without subnames (some manual work because we are not in the scene tree).
Vector < StringName > absolute_path_names = path_prefix . get_names ( ) ;
absolute_path_names . append_array ( path . get_names ( ) ) ;
NodePath absolute_path ( absolute_path_names , false ) ;
absolute_path . simplify ( ) ;
// Fix paths to renamed nodes.
for ( const Pair < NodePath , Node * > & F : r_node_renames ) {
if ( F . first = = absolute_path ) {
NodePath new_path ( ap_root - > get_path_to ( F . second ) . get_names ( ) , path . get_subnames ( ) , false ) ;
print_verbose ( vformat ( " Fix: Correcting node path in animation track: %s should be %s " , path , new_path ) ) ;
anim - > track_set_path ( i , new_path ) ;
break ; // Only one match is possible.
}
}
}
}
2021-07-16 05:45:57 +02:00
String animname = E ;
2021-03-19 13:57:52 +01:00
const int loop_string_count = 3 ;
2021-10-15 15:25:00 +02:00
static const char * loop_strings [ loop_string_count ] = { " loop_mode " , " loop " , " cycle " } ;
2021-03-19 13:57:52 +01:00
for ( int i = 0 ; i < loop_string_count ; i + + ) {
if ( _teststr ( animname , loop_strings [ i ] ) ) {
2022-05-04 20:53:48 +02:00
anim - > set_loop_mode ( Animation : : LOOP_LINEAR ) ;
2021-03-19 13:57:52 +01:00
animname = _fixstr ( animname , loop_strings [ i ] ) ;
2022-04-07 13:49:28 +02:00
Ref < AnimationLibrary > library = ap - > get_animation_library ( ap - > find_animation_library ( anim ) ) ;
library - > rename_animation ( E , animname ) ;
2021-03-19 13:57:52 +01:00
}
}
2017-02-04 13:48:04 +01:00
}
}
2017-11-16 14:06:30 +01:00
if ( _teststr ( name , " colonly " ) | | _teststr ( name , " convcolonly " ) ) {
2020-05-14 16:41:43 +02:00
if ( isroot ) {
2017-02-04 13:48:04 +01:00
return p_node ;
2020-05-14 16:41:43 +02:00
}
2020-10-24 00:57:48 +02:00
String fixed_name ;
if ( _teststr ( name , " colonly " ) ) {
fixed_name = _fixstr ( name , " colonly " ) ;
} else if ( _teststr ( name , " convcolonly " ) ) {
fixed_name = _fixstr ( name , " convcolonly " ) ;
}
2023-10-22 05:31:28 +02:00
if ( fixed_name . is_empty ( ) ) {
p_node - > set_owner ( nullptr ) ;
memdelete ( p_node ) ;
ERR_FAIL_V_MSG ( nullptr , vformat ( " Skipped node `%s` because its name is empty after removing the suffix. " , name ) ) ;
}
2020-10-24 00:57:48 +02:00
2021-09-21 03:24:31 +02:00
ImporterMeshInstance3D * mi = Object : : cast_to < ImporterMeshInstance3D > ( p_node ) ;
2017-09-06 23:50:18 +02:00
if ( mi ) {
2021-09-21 03:24:31 +02:00
Ref < ImporterMesh > mesh = mi - > get_mesh ( ) ;
2019-04-10 22:46:04 +02:00
if ( mesh . is_valid ( ) ) {
Improve collision generation usability in the new 3D scene import workflow.
With this PR it's possible to add a collision during the Mesh import, directly in editor.
To generate the shape is possible to chose between the following options:
- Decompose Convex: The Mesh is decomposed in one or many Convex Shapes (Using the VHACD library).
- Simple Convex: Is generated a convex shape that enclose the entire mesh.
- Trimesh: Generate a trimesh shape using the Mesh faces.
- Box: Add a primitive box shape, where you can tweak the `size`, `position`, `rotation`.
- Sphere: Add a primitive sphere shape, where you can tweak the `radius`, `position`, `rotation`.
- Cylinder: Add a primitive cylinder shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
- Capsule: Add a primitive capsule shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
It's also possible to chose the generated body, so you can create:
- Rigid Body
- Static Body
- Area
2021-08-22 18:19:13 +02:00
Vector < Ref < Shape3D > > shapes ;
2022-02-04 16:28:18 +01:00
if ( r_collision_map . has ( mesh ) ) {
shapes = r_collision_map [ mesh ] ;
2019-04-10 22:46:04 +02:00
} else if ( _teststr ( name , " colonly " ) ) {
2021-03-19 13:57:52 +01:00
_pre_gen_shape_list ( mesh , shapes , false ) ;
2022-02-04 16:28:18 +01:00
r_collision_map [ mesh ] = shapes ;
2019-04-10 22:46:04 +02:00
} else if ( _teststr ( name , " convcolonly " ) ) {
2021-03-19 13:57:52 +01:00
_pre_gen_shape_list ( mesh , shapes , true ) ;
2022-02-04 16:28:18 +01:00
r_collision_map [ mesh ] = shapes ;
2018-10-07 16:18:27 +02:00
}
2017-11-16 14:06:30 +01:00
2019-04-10 22:46:04 +02:00
if ( shapes . size ( ) ) {
2020-03-26 22:49:16 +01:00
StaticBody3D * col = memnew ( StaticBody3D ) ;
2019-04-10 22:46:04 +02:00
col - > set_transform ( mi - > get_transform ( ) ) ;
col - > set_name ( fixed_name ) ;
2024-01-25 18:01:56 +01:00
_copy_meta ( p_node , col ) ;
2019-04-10 22:46:04 +02:00
p_node - > replace_by ( col ) ;
2023-02-27 17:24:03 +01:00
p_node - > set_owner ( nullptr ) ;
2019-04-10 22:46:04 +02:00
memdelete ( p_node ) ;
p_node = col ;
2021-03-23 08:08:06 +01:00
_add_shapes ( col , shapes ) ;
2019-04-10 22:46:04 +02:00
}
2018-10-07 16:18:27 +02:00
}
2019-04-10 22:46:04 +02:00
2017-02-04 13:48:04 +01:00
} else if ( p_node - > has_meta ( " empty_draw_type " ) ) {
String empty_draw_type = String ( p_node - > get_meta ( " empty_draw_type " ) ) ;
2020-03-26 22:49:16 +01:00
StaticBody3D * sb = memnew ( StaticBody3D ) ;
2020-10-24 00:57:48 +02:00
sb - > set_name ( fixed_name ) ;
2020-03-26 22:49:16 +01:00
Object : : cast_to < Node3D > ( sb ) - > set_transform ( Object : : cast_to < Node3D > ( p_node ) - > get_transform ( ) ) ;
2024-01-25 18:01:56 +01:00
_copy_meta ( p_node , sb ) ;
2017-02-04 13:48:04 +01:00
p_node - > replace_by ( sb ) ;
2023-02-27 17:24:03 +01:00
p_node - > set_owner ( nullptr ) ;
2017-02-04 13:48:04 +01:00
memdelete ( p_node ) ;
2020-10-24 00:57:48 +02:00
p_node = sb ;
2020-03-26 22:49:16 +01:00
CollisionShape3D * colshape = memnew ( CollisionShape3D ) ;
2017-02-04 13:48:04 +01:00
if ( empty_draw_type = = " CUBE " ) {
2020-03-26 22:49:16 +01:00
BoxShape3D * boxShape = memnew ( BoxShape3D ) ;
2020-12-07 18:52:11 +01:00
boxShape - > set_size ( Vector3 ( 2 , 2 , 2 ) ) ;
2017-02-04 13:48:04 +01:00
colshape - > set_shape ( boxShape ) ;
2021-08-17 19:15:11 +02:00
} else if ( empty_draw_type = = " SINGLE_ARROW " ) {
2021-08-19 20:21:56 +02:00
SeparationRayShape3D * rayShape = memnew ( SeparationRayShape3D ) ;
2021-08-17 19:15:11 +02:00
rayShape - > set_length ( 1 ) ;
colshape - > set_shape ( rayShape ) ;
Object : : cast_to < Node3D > ( sb ) - > rotate_x ( Math_PI / 2 ) ;
2017-02-04 13:48:04 +01:00
} else if ( empty_draw_type = = " IMAGE " ) {
2021-09-14 19:52:35 +02:00
WorldBoundaryShape3D * world_boundary_shape = memnew ( WorldBoundaryShape3D ) ;
colshape - > set_shape ( world_boundary_shape ) ;
2017-02-04 13:48:04 +01:00
} else {
2020-03-26 22:49:16 +01:00
SphereShape3D * sphereShape = memnew ( SphereShape3D ) ;
2017-02-04 13:48:04 +01:00
sphereShape - > set_radius ( 1 ) ;
colshape - > set_shape ( sphereShape ) ;
}
2021-10-21 16:46:07 +02:00
sb - > add_child ( colshape , true ) ;
2017-02-04 13:48:04 +01:00
colshape - > set_owner ( sb - > get_owner ( ) ) ;
}
2021-09-21 03:24:31 +02:00
} else if ( _teststr ( name , " rigid " ) & & Object : : cast_to < ImporterMeshInstance3D > ( p_node ) ) {
2020-05-14 16:41:43 +02:00
if ( isroot ) {
2017-02-04 13:48:04 +01:00
return p_node ;
2020-05-14 16:41:43 +02:00
}
2017-02-04 13:48:04 +01:00
2021-09-21 03:24:31 +02:00
ImporterMeshInstance3D * mi = Object : : cast_to < ImporterMeshInstance3D > ( p_node ) ;
Ref < ImporterMesh > mesh = mi - > get_mesh ( ) ;
2019-04-10 22:46:04 +02:00
if ( mesh . is_valid ( ) ) {
Improve collision generation usability in the new 3D scene import workflow.
With this PR it's possible to add a collision during the Mesh import, directly in editor.
To generate the shape is possible to chose between the following options:
- Decompose Convex: The Mesh is decomposed in one or many Convex Shapes (Using the VHACD library).
- Simple Convex: Is generated a convex shape that enclose the entire mesh.
- Trimesh: Generate a trimesh shape using the Mesh faces.
- Box: Add a primitive box shape, where you can tweak the `size`, `position`, `rotation`.
- Sphere: Add a primitive sphere shape, where you can tweak the `radius`, `position`, `rotation`.
- Cylinder: Add a primitive cylinder shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
- Capsule: Add a primitive capsule shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
It's also possible to chose the generated body, so you can create:
- Rigid Body
- Static Body
- Area
2021-08-22 18:19:13 +02:00
Vector < Ref < Shape3D > > shapes ;
2022-02-04 16:28:18 +01:00
if ( r_collision_map . has ( mesh ) ) {
shapes = r_collision_map [ mesh ] ;
2019-04-10 22:46:04 +02:00
} else {
Fix Static & Rigid body generation on mesh import.
The function `_gen_shape_list` is using the resource `Res<Mesh>`, but during the import phase the resource used is instead `Ref<EditorSceneImporterMesh>`.
Note: the `Ref<EditorSceneImporterMesh>` is an intermediate resource, that will be used to create a `Res<Mesh>` at the end of the import process. `Ref<EditorSceneImporterMesh>` and `Ref<Mesh>` are not inheriting each other, so the internal cast done by `Ref<>` during the assignment, is always null:
```c++
Ref<EditorSceneImporterMesh> import_mesh(/* Assume it's initialized */);
CRASH_NOW(import_mesh.is_null());
Ref<Mesh> mesh = import_mesh;
CRASH_NOW(mesh.is_null()); // <--- Here we have a crash, since it's impossible perform the above cast, and the `mesh` is always null.
```
Here the full list of call to `_gen_shape_list`, where we can notice that a `Ref<EditorSceneImporterMesh>` is passed:
- https://github.com/AndreaCatania/godot/blob/master/editor/import/resource_importer_scene.cpp#L428
- https://github.com/AndreaCatania/godot/blob/master/editor/import/resource_importer_scene.cpp#L454-L458
- https://github.com/AndreaCatania/godot/blob/master/editor/import/resource_importer_scene.cpp#L512-L516
As you can notice, we always pass the following mesh: `Ref<EditorSceneImporterMesh> mesh = mi->get_mesh();`.
We already have the function `_pre_gen_shape_list` that executes the exact same job but using the correct type; Since there is no further usage of the function `_gen_shape_list` in the code base, I think it's just some leftover code, so I removed it entirely to use the proper function.
2021-07-24 08:39:18 +02:00
_pre_gen_shape_list ( mesh , shapes , true ) ;
2019-04-10 22:46:04 +02:00
}
2022-08-25 19:35:52 +02:00
RigidBody3D * rigid_body = memnew ( RigidBody3D ) ;
2021-09-14 20:44:30 +02:00
rigid_body - > set_name ( _fixstr ( name , " rigid_body " ) ) ;
2024-01-25 18:01:56 +01:00
_copy_meta ( p_node , rigid_body ) ;
2019-04-10 22:46:04 +02:00
p_node - > replace_by ( rigid_body ) ;
rigid_body - > set_transform ( mi - > get_transform ( ) ) ;
p_node = rigid_body ;
2020-10-17 07:08:21 +02:00
mi - > set_transform ( Transform3D ( ) ) ;
2021-10-21 16:46:07 +02:00
rigid_body - > add_child ( mi , true ) ;
2019-04-10 22:46:04 +02:00
mi - > set_owner ( rigid_body - > get_owner ( ) ) ;
2021-03-23 08:08:06 +01:00
_add_shapes ( rigid_body , shapes ) ;
2019-04-10 22:46:04 +02:00
}
2017-02-04 13:48:04 +01:00
2021-09-21 03:24:31 +02:00
} else if ( ( _teststr ( name , " col " ) | | ( _teststr ( name , " convcol " ) ) ) & & Object : : cast_to < ImporterMeshInstance3D > ( p_node ) ) {
ImporterMeshInstance3D * mi = Object : : cast_to < ImporterMeshInstance3D > ( p_node ) ;
2017-02-04 13:48:04 +01:00
2021-09-21 03:24:31 +02:00
Ref < ImporterMesh > mesh = mi - > get_mesh ( ) ;
2019-04-10 22:46:04 +02:00
if ( mesh . is_valid ( ) ) {
Improve collision generation usability in the new 3D scene import workflow.
With this PR it's possible to add a collision during the Mesh import, directly in editor.
To generate the shape is possible to chose between the following options:
- Decompose Convex: The Mesh is decomposed in one or many Convex Shapes (Using the VHACD library).
- Simple Convex: Is generated a convex shape that enclose the entire mesh.
- Trimesh: Generate a trimesh shape using the Mesh faces.
- Box: Add a primitive box shape, where you can tweak the `size`, `position`, `rotation`.
- Sphere: Add a primitive sphere shape, where you can tweak the `radius`, `position`, `rotation`.
- Cylinder: Add a primitive cylinder shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
- Capsule: Add a primitive capsule shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
It's also possible to chose the generated body, so you can create:
- Rigid Body
- Static Body
- Area
2021-08-22 18:19:13 +02:00
Vector < Ref < Shape3D > > shapes ;
2019-04-10 22:46:04 +02:00
String fixed_name ;
2022-02-04 16:28:18 +01:00
if ( r_collision_map . has ( mesh ) ) {
shapes = r_collision_map [ mesh ] ;
2019-04-10 22:46:04 +02:00
} else if ( _teststr ( name , " col " ) ) {
Fix Static & Rigid body generation on mesh import.
The function `_gen_shape_list` is using the resource `Res<Mesh>`, but during the import phase the resource used is instead `Ref<EditorSceneImporterMesh>`.
Note: the `Ref<EditorSceneImporterMesh>` is an intermediate resource, that will be used to create a `Res<Mesh>` at the end of the import process. `Ref<EditorSceneImporterMesh>` and `Ref<Mesh>` are not inheriting each other, so the internal cast done by `Ref<>` during the assignment, is always null:
```c++
Ref<EditorSceneImporterMesh> import_mesh(/* Assume it's initialized */);
CRASH_NOW(import_mesh.is_null());
Ref<Mesh> mesh = import_mesh;
CRASH_NOW(mesh.is_null()); // <--- Here we have a crash, since it's impossible perform the above cast, and the `mesh` is always null.
```
Here the full list of call to `_gen_shape_list`, where we can notice that a `Ref<EditorSceneImporterMesh>` is passed:
- https://github.com/AndreaCatania/godot/blob/master/editor/import/resource_importer_scene.cpp#L428
- https://github.com/AndreaCatania/godot/blob/master/editor/import/resource_importer_scene.cpp#L454-L458
- https://github.com/AndreaCatania/godot/blob/master/editor/import/resource_importer_scene.cpp#L512-L516
As you can notice, we always pass the following mesh: `Ref<EditorSceneImporterMesh> mesh = mi->get_mesh();`.
We already have the function `_pre_gen_shape_list` that executes the exact same job but using the correct type; Since there is no further usage of the function `_gen_shape_list` in the code base, I think it's just some leftover code, so I removed it entirely to use the proper function.
2021-07-24 08:39:18 +02:00
_pre_gen_shape_list ( mesh , shapes , false ) ;
2022-02-04 16:28:18 +01:00
r_collision_map [ mesh ] = shapes ;
2019-04-10 22:46:04 +02:00
} else if ( _teststr ( name , " convcol " ) ) {
Fix Static & Rigid body generation on mesh import.
The function `_gen_shape_list` is using the resource `Res<Mesh>`, but during the import phase the resource used is instead `Ref<EditorSceneImporterMesh>`.
Note: the `Ref<EditorSceneImporterMesh>` is an intermediate resource, that will be used to create a `Res<Mesh>` at the end of the import process. `Ref<EditorSceneImporterMesh>` and `Ref<Mesh>` are not inheriting each other, so the internal cast done by `Ref<>` during the assignment, is always null:
```c++
Ref<EditorSceneImporterMesh> import_mesh(/* Assume it's initialized */);
CRASH_NOW(import_mesh.is_null());
Ref<Mesh> mesh = import_mesh;
CRASH_NOW(mesh.is_null()); // <--- Here we have a crash, since it's impossible perform the above cast, and the `mesh` is always null.
```
Here the full list of call to `_gen_shape_list`, where we can notice that a `Ref<EditorSceneImporterMesh>` is passed:
- https://github.com/AndreaCatania/godot/blob/master/editor/import/resource_importer_scene.cpp#L428
- https://github.com/AndreaCatania/godot/blob/master/editor/import/resource_importer_scene.cpp#L454-L458
- https://github.com/AndreaCatania/godot/blob/master/editor/import/resource_importer_scene.cpp#L512-L516
As you can notice, we always pass the following mesh: `Ref<EditorSceneImporterMesh> mesh = mi->get_mesh();`.
We already have the function `_pre_gen_shape_list` that executes the exact same job but using the correct type; Since there is no further usage of the function `_gen_shape_list` in the code base, I think it's just some leftover code, so I removed it entirely to use the proper function.
2021-07-24 08:39:18 +02:00
_pre_gen_shape_list ( mesh , shapes , true ) ;
2022-02-04 16:28:18 +01:00
r_collision_map [ mesh ] = shapes ;
2018-07-02 10:54:14 +02:00
}
2017-11-16 14:06:30 +01:00
2019-04-10 22:46:04 +02:00
if ( _teststr ( name , " col " ) ) {
fixed_name = _fixstr ( name , " col " ) ;
} else if ( _teststr ( name , " convcol " ) ) {
fixed_name = _fixstr ( name , " convcol " ) ;
2018-07-02 10:54:14 +02:00
}
2017-11-16 14:06:30 +01:00
2021-12-09 10:42:46 +01:00
if ( ! fixed_name . is_empty ( ) ) {
2019-04-10 22:46:04 +02:00
if ( mi - > get_parent ( ) & & ! mi - > get_parent ( ) - > has_node ( fixed_name ) ) {
mi - > set_name ( fixed_name ) ;
}
}
if ( shapes . size ( ) ) {
2020-03-26 22:49:16 +01:00
StaticBody3D * col = memnew ( StaticBody3D ) ;
2021-10-21 16:46:07 +02:00
mi - > add_child ( col , true ) ;
2019-04-10 22:46:04 +02:00
col - > set_owner ( mi - > get_owner ( ) ) ;
2017-02-04 13:48:04 +01:00
2021-03-23 08:08:06 +01:00
_add_shapes ( col , shapes ) ;
2019-04-10 22:46:04 +02:00
}
}
2017-02-04 13:48:04 +01:00
2021-09-21 03:24:31 +02:00
} else if ( _teststr ( name , " navmesh " ) & & Object : : cast_to < ImporterMeshInstance3D > ( p_node ) ) {
2020-05-14 16:41:43 +02:00
if ( isroot ) {
2017-02-04 13:48:04 +01:00
return p_node ;
2020-05-14 16:41:43 +02:00
}
2017-02-04 13:48:04 +01:00
2021-09-21 03:24:31 +02:00
ImporterMeshInstance3D * mi = Object : : cast_to < ImporterMeshInstance3D > ( p_node ) ;
2017-02-04 13:48:04 +01:00
2021-09-21 03:24:31 +02:00
Ref < ImporterMesh > mesh = mi - > get_mesh ( ) ;
2020-04-02 01:20:12 +02:00
ERR_FAIL_COND_V ( mesh . is_null ( ) , nullptr ) ;
2020-03-26 22:49:16 +01:00
NavigationRegion3D * nmi = memnew ( NavigationRegion3D ) ;
2017-02-04 13:48:04 +01:00
nmi - > set_name ( _fixstr ( name , " navmesh " ) ) ;
2021-03-19 13:57:52 +01:00
Ref < NavigationMesh > nmesh = mesh - > create_navigation_mesh ( ) ;
2017-02-04 13:48:04 +01:00
nmi - > set_navigation_mesh ( nmesh ) ;
2020-03-26 22:49:16 +01:00
Object : : cast_to < Node3D > ( nmi ) - > set_transform ( mi - > get_transform ( ) ) ;
2024-01-25 18:01:56 +01:00
_copy_meta ( p_node , nmi ) ;
2017-02-04 13:48:04 +01:00
p_node - > replace_by ( nmi ) ;
2023-02-27 17:24:03 +01:00
p_node - > set_owner ( nullptr ) ;
2017-02-04 13:48:04 +01:00
memdelete ( p_node ) ;
p_node = nmi ;
2022-02-04 16:28:18 +01:00
} else if ( _teststr ( name , " occ " ) | | _teststr ( name , " occonly " ) ) {
if ( isroot ) {
return p_node ;
}
ImporterMeshInstance3D * mi = Object : : cast_to < ImporterMeshInstance3D > ( p_node ) ;
if ( mi ) {
Ref < ImporterMesh > mesh = mi - > get_mesh ( ) ;
2017-02-04 13:48:04 +01:00
2022-02-04 16:28:18 +01:00
if ( mesh . is_valid ( ) ) {
if ( r_occluder_arrays ) {
OccluderInstance3D : : bake_single_node ( mi , 0.0f , r_occluder_arrays - > first , r_occluder_arrays - > second ) ;
}
if ( _teststr ( name , " occ " ) ) {
String fixed_name = _fixstr ( name , " occ " ) ;
if ( ! fixed_name . is_empty ( ) ) {
if ( mi - > get_parent ( ) & & ! mi - > get_parent ( ) - > has_node ( fixed_name ) ) {
mi - > set_name ( fixed_name ) ;
}
}
} else {
2023-02-27 17:24:03 +01:00
p_node - > set_owner ( nullptr ) ;
2022-02-04 16:28:18 +01:00
memdelete ( p_node ) ;
p_node = nullptr ;
}
}
}
2022-06-11 17:05:58 +02:00
} else if ( _teststr ( name , " vehicle " ) ) {
if ( isroot ) {
return p_node ;
}
Node * owner = p_node - > get_owner ( ) ;
Node3D * s = Object : : cast_to < Node3D > ( p_node ) ;
VehicleBody3D * bv = memnew ( VehicleBody3D ) ;
String n = _fixstr ( p_node - > get_name ( ) , " vehicle " ) ;
bv - > set_name ( n ) ;
2024-01-25 18:01:56 +01:00
_copy_meta ( p_node , bv ) ;
2022-06-11 17:05:58 +02:00
p_node - > replace_by ( bv ) ;
p_node - > set_name ( n ) ;
bv - > add_child ( p_node ) ;
bv - > set_owner ( owner ) ;
p_node - > set_owner ( owner ) ;
bv - > set_transform ( s - > get_transform ( ) ) ;
s - > set_transform ( Transform3D ( ) ) ;
p_node = bv ;
} else if ( _teststr ( name , " wheel " ) ) {
if ( isroot ) {
return p_node ;
}
Node * owner = p_node - > get_owner ( ) ;
Node3D * s = Object : : cast_to < Node3D > ( p_node ) ;
VehicleWheel3D * bv = memnew ( VehicleWheel3D ) ;
String n = _fixstr ( p_node - > get_name ( ) , " wheel " ) ;
bv - > set_name ( n ) ;
2024-01-25 18:01:56 +01:00
_copy_meta ( p_node , bv ) ;
2022-06-11 17:05:58 +02:00
p_node - > replace_by ( bv ) ;
p_node - > set_name ( n ) ;
bv - > add_child ( p_node ) ;
bv - > set_owner ( owner ) ;
p_node - > set_owner ( owner ) ;
bv - > set_transform ( s - > get_transform ( ) ) ;
s - > set_transform ( Transform3D ( ) ) ;
p_node = bv ;
2021-09-21 03:24:31 +02:00
} else if ( Object : : cast_to < ImporterMeshInstance3D > ( p_node ) ) {
2017-11-16 14:06:30 +01:00
//last attempt, maybe collision inside the mesh data
2017-02-04 13:48:04 +01:00
2021-09-21 03:24:31 +02:00
ImporterMeshInstance3D * mi = Object : : cast_to < ImporterMeshInstance3D > ( p_node ) ;
2017-02-04 13:48:04 +01:00
2021-09-21 03:24:31 +02:00
Ref < ImporterMesh > mesh = mi - > get_mesh ( ) ;
2017-02-04 13:48:04 +01:00
if ( ! mesh . is_null ( ) ) {
Improve collision generation usability in the new 3D scene import workflow.
With this PR it's possible to add a collision during the Mesh import, directly in editor.
To generate the shape is possible to chose between the following options:
- Decompose Convex: The Mesh is decomposed in one or many Convex Shapes (Using the VHACD library).
- Simple Convex: Is generated a convex shape that enclose the entire mesh.
- Trimesh: Generate a trimesh shape using the Mesh faces.
- Box: Add a primitive box shape, where you can tweak the `size`, `position`, `rotation`.
- Sphere: Add a primitive sphere shape, where you can tweak the `radius`, `position`, `rotation`.
- Cylinder: Add a primitive cylinder shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
- Capsule: Add a primitive capsule shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
It's also possible to chose the generated body, so you can create:
- Rigid Body
- Static Body
- Area
2021-08-22 18:19:13 +02:00
Vector < Ref < Shape3D > > shapes ;
2022-02-04 16:28:18 +01:00
if ( r_collision_map . has ( mesh ) ) {
shapes = r_collision_map [ mesh ] ;
2019-04-10 22:46:04 +02:00
} else if ( _teststr ( mesh - > get_name ( ) , " col " ) ) {
Fix Static & Rigid body generation on mesh import.
The function `_gen_shape_list` is using the resource `Res<Mesh>`, but during the import phase the resource used is instead `Ref<EditorSceneImporterMesh>`.
Note: the `Ref<EditorSceneImporterMesh>` is an intermediate resource, that will be used to create a `Res<Mesh>` at the end of the import process. `Ref<EditorSceneImporterMesh>` and `Ref<Mesh>` are not inheriting each other, so the internal cast done by `Ref<>` during the assignment, is always null:
```c++
Ref<EditorSceneImporterMesh> import_mesh(/* Assume it's initialized */);
CRASH_NOW(import_mesh.is_null());
Ref<Mesh> mesh = import_mesh;
CRASH_NOW(mesh.is_null()); // <--- Here we have a crash, since it's impossible perform the above cast, and the `mesh` is always null.
```
Here the full list of call to `_gen_shape_list`, where we can notice that a `Ref<EditorSceneImporterMesh>` is passed:
- https://github.com/AndreaCatania/godot/blob/master/editor/import/resource_importer_scene.cpp#L428
- https://github.com/AndreaCatania/godot/blob/master/editor/import/resource_importer_scene.cpp#L454-L458
- https://github.com/AndreaCatania/godot/blob/master/editor/import/resource_importer_scene.cpp#L512-L516
As you can notice, we always pass the following mesh: `Ref<EditorSceneImporterMesh> mesh = mi->get_mesh();`.
We already have the function `_pre_gen_shape_list` that executes the exact same job but using the correct type; Since there is no further usage of the function `_gen_shape_list` in the code base, I think it's just some leftover code, so I removed it entirely to use the proper function.
2021-07-24 08:39:18 +02:00
_pre_gen_shape_list ( mesh , shapes , false ) ;
2022-02-04 16:28:18 +01:00
r_collision_map [ mesh ] = shapes ;
2019-04-10 22:46:04 +02:00
mesh - > set_name ( _fixstr ( mesh - > get_name ( ) , " col " ) ) ;
} else if ( _teststr ( mesh - > get_name ( ) , " convcol " ) ) {
Fix Static & Rigid body generation on mesh import.
The function `_gen_shape_list` is using the resource `Res<Mesh>`, but during the import phase the resource used is instead `Ref<EditorSceneImporterMesh>`.
Note: the `Ref<EditorSceneImporterMesh>` is an intermediate resource, that will be used to create a `Res<Mesh>` at the end of the import process. `Ref<EditorSceneImporterMesh>` and `Ref<Mesh>` are not inheriting each other, so the internal cast done by `Ref<>` during the assignment, is always null:
```c++
Ref<EditorSceneImporterMesh> import_mesh(/* Assume it's initialized */);
CRASH_NOW(import_mesh.is_null());
Ref<Mesh> mesh = import_mesh;
CRASH_NOW(mesh.is_null()); // <--- Here we have a crash, since it's impossible perform the above cast, and the `mesh` is always null.
```
Here the full list of call to `_gen_shape_list`, where we can notice that a `Ref<EditorSceneImporterMesh>` is passed:
- https://github.com/AndreaCatania/godot/blob/master/editor/import/resource_importer_scene.cpp#L428
- https://github.com/AndreaCatania/godot/blob/master/editor/import/resource_importer_scene.cpp#L454-L458
- https://github.com/AndreaCatania/godot/blob/master/editor/import/resource_importer_scene.cpp#L512-L516
As you can notice, we always pass the following mesh: `Ref<EditorSceneImporterMesh> mesh = mi->get_mesh();`.
We already have the function `_pre_gen_shape_list` that executes the exact same job but using the correct type; Since there is no further usage of the function `_gen_shape_list` in the code base, I think it's just some leftover code, so I removed it entirely to use the proper function.
2021-07-24 08:39:18 +02:00
_pre_gen_shape_list ( mesh , shapes , true ) ;
2022-02-04 16:28:18 +01:00
r_collision_map [ mesh ] = shapes ;
2019-04-10 22:46:04 +02:00
mesh - > set_name ( _fixstr ( mesh - > get_name ( ) , " convcol " ) ) ;
2022-02-04 16:28:18 +01:00
} else if ( _teststr ( mesh - > get_name ( ) , " occ " ) ) {
if ( r_occluder_arrays ) {
OccluderInstance3D : : bake_single_node ( mi , 0.0f , r_occluder_arrays - > first , r_occluder_arrays - > second ) ;
}
mesh - > set_name ( _fixstr ( mesh - > get_name ( ) , " occ " ) ) ;
2019-04-10 22:46:04 +02:00
}
2017-11-16 14:06:30 +01:00
2019-04-10 22:46:04 +02:00
if ( shapes . size ( ) ) {
2020-03-26 22:49:16 +01:00
StaticBody3D * col = memnew ( StaticBody3D ) ;
2021-10-21 16:46:07 +02:00
p_node - > add_child ( col , true ) ;
2019-04-10 22:46:04 +02:00
col - > set_owner ( p_node - > get_owner ( ) ) ;
2017-11-16 14:06:30 +01:00
2021-03-23 08:08:06 +01:00
_add_shapes ( col , shapes ) ;
2017-02-04 13:48:04 +01:00
}
}
}
2020-10-24 00:57:48 +02:00
if ( p_node ) {
NodePath new_path = p_root - > get_path_to ( p_node ) ;
if ( new_path ! = original_path ) {
print_verbose ( vformat ( " Fix: Renamed %s to %s " , original_path , new_path ) ) ;
r_node_renames . push_back ( { original_path , p_node } ) ;
}
}
2017-02-04 13:48:04 +01:00
return p_node ;
}
2022-07-26 11:48:08 +02:00
Node * ResourceImporterScene : : _pre_fix_animations ( Node * p_node , Node * p_root , const Dictionary & p_node_data , const Dictionary & p_animation_data , float p_animation_fps ) {
// children first
for ( int i = 0 ; i < p_node - > get_child_count ( ) ; i + + ) {
Node * r = _pre_fix_animations ( p_node - > get_child ( i ) , p_root , p_node_data , p_animation_data , p_animation_fps ) ;
if ( ! r ) {
i - - ; //was erased
}
}
String import_id = p_node - > get_meta ( " import_id " , " PATH: " + p_root - > get_path_to ( p_node ) ) ;
Dictionary node_settings ;
if ( p_node_data . has ( import_id ) ) {
node_settings = p_node_data [ import_id ] ;
}
{
//make sure this is unique
node_settings = node_settings . duplicate ( true ) ;
//fill node settings for this node with default values
List < ImportOption > iopts ;
get_internal_import_options ( INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE , & iopts ) ;
for ( const ImportOption & E : iopts ) {
if ( ! node_settings . has ( E . option . name ) ) {
node_settings [ E . option . name ] = E . default_value ;
}
}
}
if ( Object : : cast_to < AnimationPlayer > ( p_node ) ) {
AnimationPlayer * ap = Object : : cast_to < AnimationPlayer > ( p_node ) ;
2022-10-10 22:59:57 +02:00
List < StringName > anims ;
ap - > get_animation_list ( & anims ) ;
2022-07-26 11:48:08 +02:00
2022-10-10 22:59:57 +02:00
AnimationImportTracks import_tracks_mode [ TRACK_CHANNEL_MAX ] = {
AnimationImportTracks ( int ( node_settings [ " import_tracks/position " ] ) ) ,
AnimationImportTracks ( int ( node_settings [ " import_tracks/rotation " ] ) ) ,
AnimationImportTracks ( int ( node_settings [ " import_tracks/scale " ] ) )
} ;
2023-06-21 00:49:38 +02:00
if ( ! anims . is_empty ( ) & & ( import_tracks_mode [ 0 ] ! = ANIMATION_IMPORT_TRACKS_IF_PRESENT | | import_tracks_mode [ 1 ] ! = ANIMATION_IMPORT_TRACKS_IF_PRESENT | | import_tracks_mode [ 2 ] ! = ANIMATION_IMPORT_TRACKS_IF_PRESENT ) ) {
2022-10-10 22:59:57 +02:00
_optimize_track_usage ( ap , import_tracks_mode ) ;
}
2022-07-26 11:48:08 +02:00
}
return p_node ;
}
2024-03-31 08:45:22 +02:00
Node * ResourceImporterScene : : _post_fix_animations ( Node * p_node , Node * p_root , const Dictionary & p_node_data , const Dictionary & p_animation_data , float p_animation_fps , bool p_remove_immutable_tracks ) {
2022-07-26 11:48:08 +02:00
// children first
for ( int i = 0 ; i < p_node - > get_child_count ( ) ; i + + ) {
2024-03-31 08:45:22 +02:00
Node * r = _post_fix_animations ( p_node - > get_child ( i ) , p_root , p_node_data , p_animation_data , p_animation_fps , p_remove_immutable_tracks ) ;
2022-07-26 11:48:08 +02:00
if ( ! r ) {
i - - ; //was erased
}
}
String import_id = p_node - > get_meta ( " import_id " , " PATH: " + p_root - > get_path_to ( p_node ) ) ;
Dictionary node_settings ;
if ( p_node_data . has ( import_id ) ) {
node_settings = p_node_data [ import_id ] ;
}
{
//make sure this is unique
node_settings = node_settings . duplicate ( true ) ;
//fill node settings for this node with default values
List < ImportOption > iopts ;
get_internal_import_options ( INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE , & iopts ) ;
for ( const ImportOption & E : iopts ) {
if ( ! node_settings . has ( E . option . name ) ) {
node_settings [ E . option . name ] = E . default_value ;
}
}
}
if ( Object : : cast_to < AnimationPlayer > ( p_node ) ) {
AnimationPlayer * ap = Object : : cast_to < AnimationPlayer > ( p_node ) ;
2024-03-31 08:45:22 +02:00
List < StringName > anims ;
ap - > get_animation_list ( & anims ) ;
if ( p_remove_immutable_tracks ) {
AnimationImportTracks import_tracks_mode [ TRACK_CHANNEL_MAX ] = {
AnimationImportTracks ( int ( node_settings [ " import_tracks/position " ] ) ) ,
AnimationImportTracks ( int ( node_settings [ " import_tracks/rotation " ] ) ) ,
AnimationImportTracks ( int ( node_settings [ " import_tracks/scale " ] ) )
} ;
HashMap < NodePath , bool > used_tracks [ TRACK_CHANNEL_MAX ] ;
for ( const StringName & name : anims ) {
Ref < Animation > anim = ap - > get_animation ( name ) ;
int track_count = anim - > get_track_count ( ) ;
LocalVector < int > tracks_to_keep ;
for ( int track_i = 0 ; track_i < track_count ; track_i + + ) {
tracks_to_keep . push_back ( track_i ) ;
int track_channel_type = 0 ;
switch ( anim - > track_get_type ( track_i ) ) {
case Animation : : TYPE_POSITION_3D :
track_channel_type = TRACK_CHANNEL_POSITION ;
break ;
case Animation : : TYPE_ROTATION_3D :
track_channel_type = TRACK_CHANNEL_ROTATION ;
break ;
case Animation : : TYPE_SCALE_3D :
track_channel_type = TRACK_CHANNEL_SCALE ;
break ;
default :
continue ;
}
AnimationImportTracks track_mode = import_tracks_mode [ track_channel_type ] ;
NodePath path = anim - > track_get_path ( track_i ) ;
Node * n = p_root - > get_node ( path ) ;
Node3D * n3d = Object : : cast_to < Node3D > ( n ) ;
Skeleton3D * skel = Object : : cast_to < Skeleton3D > ( n ) ;
bool keep_track = false ;
Vector3 loc ;
Quaternion rot ;
Vector3 scale ;
if ( skel & & path . get_subname_count ( ) > 0 ) {
StringName bone = path . get_subname ( 0 ) ;
int bone_idx = skel - > find_bone ( bone ) ;
if ( bone_idx = = - 1 ) {
continue ;
}
// Note that this is using get_bone_pose to update the bone pose cache.
Transform3D bone_rest = skel - > get_bone_rest ( bone_idx ) ;
loc = bone_rest . origin / skel - > get_motion_scale ( ) ;
rot = bone_rest . basis . get_rotation_quaternion ( ) ;
scale = bone_rest . basis . get_scale ( ) ;
} else if ( n3d ) {
loc = n3d - > get_position ( ) ;
rot = n3d - > get_transform ( ) . basis . get_rotation_quaternion ( ) ;
scale = n3d - > get_scale ( ) ;
} else {
continue ;
}
if ( track_mode = = ANIMATION_IMPORT_TRACKS_IF_PRESENT_FOR_ALL ) {
if ( used_tracks [ track_channel_type ] . has ( path ) ) {
if ( used_tracks [ track_channel_type ] [ path ] ) {
continue ;
}
} else {
used_tracks [ track_channel_type ] . insert ( path , false ) ;
}
}
for ( int key_i = 0 ; key_i < anim - > track_get_key_count ( track_i ) & & ! keep_track ; key_i + + ) {
switch ( track_channel_type ) {
case TRACK_CHANNEL_POSITION : {
Vector3 key_pos ;
anim - > position_track_get_key ( track_i , key_i , & key_pos ) ;
if ( ! key_pos . is_equal_approx ( loc ) ) {
keep_track = true ;
if ( track_mode = = ANIMATION_IMPORT_TRACKS_IF_PRESENT_FOR_ALL ) {
used_tracks [ track_channel_type ] [ path ] = true ;
}
}
} break ;
case TRACK_CHANNEL_ROTATION : {
Quaternion key_rot ;
anim - > rotation_track_get_key ( track_i , key_i , & key_rot ) ;
if ( ! key_rot . is_equal_approx ( rot ) ) {
keep_track = true ;
if ( track_mode = = ANIMATION_IMPORT_TRACKS_IF_PRESENT_FOR_ALL ) {
used_tracks [ track_channel_type ] [ path ] = true ;
}
}
} break ;
case TRACK_CHANNEL_SCALE : {
Vector3 key_scl ;
anim - > scale_track_get_key ( track_i , key_i , & key_scl ) ;
if ( ! key_scl . is_equal_approx ( scale ) ) {
keep_track = true ;
if ( track_mode = = ANIMATION_IMPORT_TRACKS_IF_PRESENT_FOR_ALL ) {
used_tracks [ track_channel_type ] [ path ] = true ;
}
}
} break ;
default :
break ;
}
}
if ( track_mode ! = ANIMATION_IMPORT_TRACKS_IF_PRESENT_FOR_ALL & & ! keep_track ) {
tracks_to_keep . remove_at ( tracks_to_keep . size ( ) - 1 ) ;
}
}
for ( int dst_track_i = 0 ; dst_track_i < ( int ) tracks_to_keep . size ( ) ; dst_track_i + + ) {
int src_track_i = tracks_to_keep [ dst_track_i ] ;
if ( src_track_i ! = dst_track_i ) {
anim - > track_swap ( src_track_i , dst_track_i ) ;
}
}
for ( int track_i = track_count - 1 ; track_i > = ( int ) tracks_to_keep . size ( ) ; track_i - - ) {
anim - > remove_track ( track_i ) ;
}
}
for ( const StringName & name : anims ) {
Ref < Animation > anim = ap - > get_animation ( name ) ;
int track_count = anim - > get_track_count ( ) ;
LocalVector < int > tracks_to_keep ;
for ( int track_i = 0 ; track_i < track_count ; track_i + + ) {
tracks_to_keep . push_back ( track_i ) ;
int track_channel_type = 0 ;
switch ( anim - > track_get_type ( track_i ) ) {
case Animation : : TYPE_POSITION_3D :
track_channel_type = TRACK_CHANNEL_POSITION ;
break ;
case Animation : : TYPE_ROTATION_3D :
track_channel_type = TRACK_CHANNEL_ROTATION ;
break ;
case Animation : : TYPE_SCALE_3D :
track_channel_type = TRACK_CHANNEL_SCALE ;
break ;
default :
continue ;
}
AnimationImportTracks track_mode = import_tracks_mode [ track_channel_type ] ;
if ( track_mode = = ANIMATION_IMPORT_TRACKS_IF_PRESENT_FOR_ALL ) {
NodePath path = anim - > track_get_path ( track_i ) ;
if ( used_tracks [ track_channel_type ] . has ( path ) & & ! used_tracks [ track_channel_type ] [ path ] ) {
tracks_to_keep . remove_at ( tracks_to_keep . size ( ) - 1 ) ;
}
}
}
for ( int dst_track_i = 0 ; dst_track_i < ( int ) tracks_to_keep . size ( ) ; dst_track_i + + ) {
int src_track_i = tracks_to_keep [ dst_track_i ] ;
if ( src_track_i ! = dst_track_i ) {
anim - > track_swap ( src_track_i , dst_track_i ) ;
}
}
for ( int track_i = track_count - 1 ; track_i > = ( int ) tracks_to_keep . size ( ) ; track_i - - ) {
anim - > remove_track ( track_i ) ;
}
}
}
2022-07-26 11:48:08 +02:00
bool use_optimizer = node_settings [ " optimizer/enabled " ] ;
2022-08-07 03:55:37 +02:00
float anim_optimizer_linerr = node_settings [ " optimizer/max_velocity_error " ] ;
2022-07-26 11:48:08 +02:00
float anim_optimizer_angerr = node_settings [ " optimizer/max_angular_error " ] ;
2022-08-07 03:55:37 +02:00
int anim_optimizer_preerr = node_settings [ " optimizer/max_precision_error " ] ;
2022-07-26 11:48:08 +02:00
if ( use_optimizer ) {
2022-08-07 03:55:37 +02:00
_optimize_animations ( ap , anim_optimizer_linerr , anim_optimizer_angerr , anim_optimizer_preerr ) ;
2022-07-26 11:48:08 +02:00
}
bool use_compression = node_settings [ " compression/enabled " ] ;
int anim_compression_page_size = node_settings [ " compression/page_size " ] ;
if ( use_compression ) {
_compress_animations ( ap , anim_compression_page_size ) ;
}
for ( const StringName & name : anims ) {
Ref < Animation > anim = ap - > get_animation ( name ) ;
2023-10-09 11:47:41 +02:00
Array animation_slices ;
2022-07-26 11:48:08 +02:00
if ( p_animation_data . has ( name ) ) {
Dictionary anim_settings = p_animation_data [ name ] ;
2023-10-09 11:47:41 +02:00
{
int slices_count = anim_settings [ " slices/amount " ] ;
for ( int i = 0 ; i < slices_count ; i + + ) {
String slice_name = anim_settings [ " slice_ " + itos ( i + 1 ) + " /name " ] ;
int from_frame = anim_settings [ " slice_ " + itos ( i + 1 ) + " /start_frame " ] ;
int end_frame = anim_settings [ " slice_ " + itos ( i + 1 ) + " /end_frame " ] ;
Animation : : LoopMode loop_mode = static_cast < Animation : : LoopMode > ( ( int ) anim_settings [ " slice_ " + itos ( i + 1 ) + " /loop_mode " ] ) ;
bool save_to_file = anim_settings [ " slice_ " + itos ( i + 1 ) + " /save_to_file/enabled " ] ;
String save_to_path = anim_settings [ " slice_ " + itos ( i + 1 ) + " /save_to_file/path " ] ;
bool save_to_file_keep_custom = anim_settings [ " slice_ " + itos ( i + 1 ) + " /save_to_file/keep_custom_tracks " ] ;
animation_slices . push_back ( slice_name ) ;
animation_slices . push_back ( from_frame / p_animation_fps ) ;
animation_slices . push_back ( end_frame / p_animation_fps ) ;
animation_slices . push_back ( loop_mode ) ;
animation_slices . push_back ( save_to_file ) ;
animation_slices . push_back ( save_to_path ) ;
animation_slices . push_back ( save_to_file_keep_custom ) ;
}
if ( animation_slices . size ( ) > 0 ) {
_create_slices ( ap , anim , animation_slices , true ) ;
}
}
2022-07-26 11:48:08 +02:00
{
//fill with default values
List < ImportOption > iopts ;
get_internal_import_options ( INTERNAL_IMPORT_CATEGORY_ANIMATION , & iopts ) ;
for ( const ImportOption & F : iopts ) {
if ( ! anim_settings . has ( F . option . name ) ) {
anim_settings [ F . option . name ] = F . default_value ;
}
}
}
anim - > set_loop_mode ( static_cast < Animation : : LoopMode > ( ( int ) anim_settings [ " settings/loop_mode " ] ) ) ;
bool save = anim_settings [ " save_to_file/enabled " ] ;
String path = anim_settings [ " save_to_file/path " ] ;
bool keep_custom = anim_settings [ " save_to_file/keep_custom_tracks " ] ;
Ref < Animation > saved_anim = _save_animation_to_file ( anim , save , path , keep_custom ) ;
if ( saved_anim ! = anim ) {
Ref < AnimationLibrary > al = ap - > get_animation_library ( ap - > find_animation_library ( anim ) ) ;
al - > add_animation ( name , saved_anim ) ; //replace
}
}
}
}
return p_node ;
}
2023-01-28 12:31:20 +01:00
Node * ResourceImporterScene : : _post_fix_node ( Node * p_node , Node * p_root , HashMap < Ref < ImporterMesh > , Vector < Ref < Shape3D > > > & collision_map , Pair < PackedVector3Array , PackedInt32Array > & r_occluder_arrays , HashSet < Ref < ImporterMesh > > & r_scanned_meshes , const Dictionary & p_node_data , const Dictionary & p_material_data , const Dictionary & p_animation_data , float p_animation_fps , float p_applied_root_scale ) {
2021-03-19 13:57:52 +01:00
// children first
for ( int i = 0 ; i < p_node - > get_child_count ( ) ; i + + ) {
2023-01-28 12:31:20 +01:00
Node * r = _post_fix_node ( p_node - > get_child ( i ) , p_root , collision_map , r_occluder_arrays , r_scanned_meshes , p_node_data , p_material_data , p_animation_data , p_animation_fps , p_applied_root_scale ) ;
2021-03-19 13:57:52 +01:00
if ( ! r ) {
i - - ; //was erased
}
}
bool isroot = p_node = = p_root ;
2022-04-01 20:30:23 +02:00
String import_id = p_node - > get_meta ( " import_id " , " PATH: " + p_root - > get_path_to ( p_node ) ) ;
2021-03-19 13:57:52 +01:00
Dictionary node_settings ;
if ( p_node_data . has ( import_id ) ) {
node_settings = p_node_data [ import_id ] ;
}
if ( ! isroot & & ( node_settings . has ( " import/skip_import " ) & & bool ( node_settings [ " import/skip_import " ] ) ) ) {
2023-02-27 17:24:03 +01:00
p_node - > set_owner ( nullptr ) ;
2021-03-19 13:57:52 +01:00
memdelete ( p_node ) ;
return nullptr ;
}
2022-06-27 10:06:50 +02:00
{
//make sure this is unique
node_settings = node_settings . duplicate ( true ) ;
//fill node settings for this node with default values
List < ImportOption > iopts ;
if ( Object : : cast_to < ImporterMeshInstance3D > ( p_node ) ) {
get_internal_import_options ( INTERNAL_IMPORT_CATEGORY_MESH_3D_NODE , & iopts ) ;
} else if ( Object : : cast_to < AnimationPlayer > ( p_node ) ) {
get_internal_import_options ( INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE , & iopts ) ;
} else if ( Object : : cast_to < Skeleton3D > ( p_node ) ) {
get_internal_import_options ( INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE , & iopts ) ;
} else {
get_internal_import_options ( INTERNAL_IMPORT_CATEGORY_NODE , & iopts ) ;
}
for ( const ImportOption & E : iopts ) {
if ( ! node_settings . has ( E . option . name ) ) {
node_settings [ E . option . name ] = E . default_value ;
}
}
}
2021-10-14 19:34:27 +02:00
{
ObjectID node_id = p_node - > get_instance_id ( ) ;
for ( int i = 0 ; i < post_importer_plugins . size ( ) ; i + + ) {
2022-05-03 01:43:50 +02:00
post_importer_plugins . write [ i ] - > internal_process ( EditorScenePostImportPlugin : : INTERNAL_IMPORT_CATEGORY_NODE , p_root , p_node , Ref < Resource > ( ) , node_settings ) ;
2021-10-14 19:34:27 +02:00
if ( ObjectDB : : get_instance ( node_id ) = = nullptr ) { //may have been erased, so do not continue
break ;
}
}
}
if ( Object : : cast_to < ImporterMeshInstance3D > ( p_node ) ) {
ObjectID node_id = p_node - > get_instance_id ( ) ;
for ( int i = 0 ; i < post_importer_plugins . size ( ) ; i + + ) {
2022-05-03 01:43:50 +02:00
post_importer_plugins . write [ i ] - > internal_process ( EditorScenePostImportPlugin : : INTERNAL_IMPORT_CATEGORY_MESH_3D_NODE , p_root , p_node , Ref < Resource > ( ) , node_settings ) ;
2021-10-14 19:34:27 +02:00
if ( ObjectDB : : get_instance ( node_id ) = = nullptr ) { //may have been erased, so do not continue
break ;
}
}
}
2022-06-27 10:06:50 +02:00
if ( Object : : cast_to < Skeleton3D > ( p_node ) ) {
2024-02-25 17:06:37 +01:00
Ref < Animation > rest_animation ;
float rest_animation_timestamp = 0.0 ;
Skeleton3D * skeleton = Object : : cast_to < Skeleton3D > ( p_node ) ;
if ( skeleton ! = nullptr & & int ( node_settings . get ( " rest_pose/load_pose " , 0 ) ) ! = 0 ) {
String selected_animation_name = node_settings . get ( " rest_pose/selected_animation " , String ( ) ) ;
if ( int ( node_settings [ " rest_pose/load_pose " ] ) = = 1 ) {
TypedArray < Node > children = p_root - > find_children ( " * " , " AnimationPlayer " , true , false ) ;
for ( int node_i = 0 ; node_i < children . size ( ) ; node_i + + ) {
AnimationPlayer * anim_player = cast_to < AnimationPlayer > ( children [ node_i ] ) ;
ERR_CONTINUE ( anim_player = = nullptr ) ;
List < StringName > anim_list ;
anim_player - > get_animation_list ( & anim_list ) ;
if ( anim_list . size ( ) = = 1 ) {
2024-04-15 15:18:34 +02:00
selected_animation_name = anim_list . front ( ) - > get ( ) ;
2024-02-25 17:06:37 +01:00
}
rest_animation = anim_player - > get_animation ( selected_animation_name ) ;
if ( rest_animation . is_valid ( ) ) {
break ;
}
}
} else if ( int ( node_settings [ " rest_pose/load_pose " ] ) = = 2 ) {
Object * external_object = node_settings . get ( " rest_pose/external_animation_library " , Variant ( ) ) ;
rest_animation = external_object ;
if ( rest_animation . is_null ( ) ) {
Ref < AnimationLibrary > library ( external_object ) ;
if ( library . is_valid ( ) ) {
List < StringName > anim_list ;
library - > get_animation_list ( & anim_list ) ;
if ( anim_list . size ( ) = = 1 ) {
2024-04-15 15:18:34 +02:00
selected_animation_name = String ( anim_list . front ( ) - > get ( ) ) ;
2024-02-25 17:06:37 +01:00
}
rest_animation = library - > get_animation ( selected_animation_name ) ;
}
}
}
rest_animation_timestamp = double ( node_settings . get ( " rest_pose/selected_timestamp " , 0.0 ) ) ;
if ( rest_animation . is_valid ( ) ) {
for ( int track_i = 0 ; track_i < rest_animation - > get_track_count ( ) ; track_i + + ) {
NodePath path = rest_animation - > track_get_path ( track_i ) ;
StringName node_path = path . get_concatenated_names ( ) ;
if ( String ( node_path ) . begins_with ( " % " ) ) {
continue ; // Unique node names are commonly used with retargeted animations, which we do not want to use.
}
StringName skeleton_bone = path . get_concatenated_subnames ( ) ;
if ( skeleton_bone = = StringName ( ) ) {
continue ;
}
int bone_idx = skeleton - > find_bone ( skeleton_bone ) ;
if ( bone_idx = = - 1 ) {
continue ;
}
switch ( rest_animation - > track_get_type ( track_i ) ) {
case Animation : : TYPE_POSITION_3D : {
Vector3 bone_position = rest_animation - > position_track_interpolate ( track_i , rest_animation_timestamp ) ;
skeleton - > set_bone_rest ( bone_idx , Transform3D ( skeleton - > get_bone_rest ( bone_idx ) . basis , bone_position ) ) ;
} break ;
case Animation : : TYPE_ROTATION_3D : {
Quaternion bone_rotation = rest_animation - > rotation_track_interpolate ( track_i , rest_animation_timestamp ) ;
Transform3D current_rest = skeleton - > get_bone_rest ( bone_idx ) ;
skeleton - > set_bone_rest ( bone_idx , Transform3D ( Basis ( bone_rotation ) . scaled ( current_rest . basis . get_scale ( ) ) , current_rest . origin ) ) ;
} break ;
default :
break ;
}
}
}
}
2022-06-27 10:06:50 +02:00
ObjectID node_id = p_node - > get_instance_id ( ) ;
for ( int i = 0 ; i < post_importer_plugins . size ( ) ; i + + ) {
post_importer_plugins . write [ i ] - > internal_process ( EditorScenePostImportPlugin : : INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE , p_root , p_node , Ref < Resource > ( ) , node_settings ) ;
if ( ObjectDB : : get_instance ( node_id ) = = nullptr ) { //may have been erased, so do not continue
break ;
}
}
}
2021-09-21 03:24:31 +02:00
if ( Object : : cast_to < ImporterMeshInstance3D > ( p_node ) ) {
ImporterMeshInstance3D * mi = Object : : cast_to < ImporterMeshInstance3D > ( p_node ) ;
2021-03-19 13:57:52 +01:00
2021-09-21 03:24:31 +02:00
Ref < ImporterMesh > m = mi - > get_mesh ( ) ;
2021-03-19 13:57:52 +01:00
if ( m . is_valid ( ) ) {
if ( ! r_scanned_meshes . has ( m ) ) {
for ( int i = 0 ; i < m - > get_surface_count ( ) ; i + + ) {
Ref < Material > mat = m - > get_surface_material ( i ) ;
if ( mat . is_valid ( ) ) {
2022-04-01 20:30:23 +02:00
String mat_id = mat - > get_meta ( " import_id " , mat - > get_name ( ) ) ;
2021-03-19 13:57:52 +01:00
2021-12-09 10:42:46 +01:00
if ( ! mat_id . is_empty ( ) & & p_material_data . has ( mat_id ) ) {
2021-03-19 13:57:52 +01:00
Dictionary matdata = p_material_data [ mat_id ] ;
2022-06-27 10:06:50 +02:00
{
//fill node settings for this node with default values
List < ImportOption > iopts ;
get_internal_import_options ( INTERNAL_IMPORT_CATEGORY_MATERIAL , & iopts ) ;
for ( const ImportOption & E : iopts ) {
if ( ! matdata . has ( E . option . name ) ) {
matdata [ E . option . name ] = E . default_value ;
}
}
}
2021-10-14 19:34:27 +02:00
for ( int j = 0 ; j < post_importer_plugins . size ( ) ; j + + ) {
post_importer_plugins . write [ j ] - > internal_process ( EditorScenePostImportPlugin : : INTERNAL_IMPORT_CATEGORY_MATERIAL , p_root , p_node , mat , matdata ) ;
}
2021-03-19 13:57:52 +01:00
if ( matdata . has ( " use_external/enabled " ) & & bool ( matdata [ " use_external/enabled " ] ) & & matdata . has ( " use_external/path " ) ) {
String path = matdata [ " use_external/path " ] ;
Ref < Material > external_mat = ResourceLoader : : load ( path ) ;
if ( external_mat . is_valid ( ) ) {
m - > set_surface_material ( i , external_mat ) ;
}
}
}
}
}
r_scanned_meshes . insert ( m ) ;
}
if ( node_settings . has ( " generate/physics " ) ) {
Improve collision generation usability in the new 3D scene import workflow.
With this PR it's possible to add a collision during the Mesh import, directly in editor.
To generate the shape is possible to chose between the following options:
- Decompose Convex: The Mesh is decomposed in one or many Convex Shapes (Using the VHACD library).
- Simple Convex: Is generated a convex shape that enclose the entire mesh.
- Trimesh: Generate a trimesh shape using the Mesh faces.
- Box: Add a primitive box shape, where you can tweak the `size`, `position`, `rotation`.
- Sphere: Add a primitive sphere shape, where you can tweak the `radius`, `position`, `rotation`.
- Cylinder: Add a primitive cylinder shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
- Capsule: Add a primitive capsule shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
It's also possible to chose the generated body, so you can create:
- Rigid Body
- Static Body
- Area
2021-08-22 18:19:13 +02:00
int mesh_physics_mode = MeshPhysicsMode : : MESH_PHYSICS_DISABLED ;
const bool generate_collider = node_settings [ " generate/physics " ] ;
if ( generate_collider ) {
mesh_physics_mode = MeshPhysicsMode : : MESH_PHYSICS_MESH_AND_STATIC_COLLIDER ;
if ( node_settings . has ( " physics/body_type " ) ) {
const BodyType body_type = ( BodyType ) node_settings [ " physics/body_type " ] . operator int ( ) ;
switch ( body_type ) {
case BODY_TYPE_STATIC :
mesh_physics_mode = MeshPhysicsMode : : MESH_PHYSICS_MESH_AND_STATIC_COLLIDER ;
break ;
case BODY_TYPE_DYNAMIC :
mesh_physics_mode = MeshPhysicsMode : : MESH_PHYSICS_RIGID_BODY_AND_MESH ;
break ;
case BODY_TYPE_AREA :
mesh_physics_mode = MeshPhysicsMode : : MESH_PHYSICS_AREA_ONLY ;
break ;
}
}
}
2021-03-19 13:57:52 +01:00
Improve collision generation usability in the new 3D scene import workflow.
With this PR it's possible to add a collision during the Mesh import, directly in editor.
To generate the shape is possible to chose between the following options:
- Decompose Convex: The Mesh is decomposed in one or many Convex Shapes (Using the VHACD library).
- Simple Convex: Is generated a convex shape that enclose the entire mesh.
- Trimesh: Generate a trimesh shape using the Mesh faces.
- Box: Add a primitive box shape, where you can tweak the `size`, `position`, `rotation`.
- Sphere: Add a primitive sphere shape, where you can tweak the `radius`, `position`, `rotation`.
- Cylinder: Add a primitive cylinder shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
- Capsule: Add a primitive capsule shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
It's also possible to chose the generated body, so you can create:
- Rigid Body
- Static Body
- Area
2021-08-22 18:19:13 +02:00
if ( mesh_physics_mode ! = MeshPhysicsMode : : MESH_PHYSICS_DISABLED ) {
Vector < Ref < Shape3D > > shapes ;
2021-03-19 13:57:52 +01:00
if ( collision_map . has ( m ) ) {
shapes = collision_map [ m ] ;
} else {
Improve collision generation usability in the new 3D scene import workflow.
With this PR it's possible to add a collision during the Mesh import, directly in editor.
To generate the shape is possible to chose between the following options:
- Decompose Convex: The Mesh is decomposed in one or many Convex Shapes (Using the VHACD library).
- Simple Convex: Is generated a convex shape that enclose the entire mesh.
- Trimesh: Generate a trimesh shape using the Mesh faces.
- Box: Add a primitive box shape, where you can tweak the `size`, `position`, `rotation`.
- Sphere: Add a primitive sphere shape, where you can tweak the `radius`, `position`, `rotation`.
- Cylinder: Add a primitive cylinder shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
- Capsule: Add a primitive capsule shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
It's also possible to chose the generated body, so you can create:
- Rigid Body
- Static Body
- Area
2021-08-22 18:19:13 +02:00
shapes = get_collision_shapes (
2023-02-23 11:07:48 +01:00
m ,
2023-01-28 12:31:20 +01:00
node_settings ,
p_applied_root_scale ) ;
2021-03-19 13:57:52 +01:00
}
if ( shapes . size ( ) ) {
CollisionObject3D * base = nullptr ;
switch ( mesh_physics_mode ) {
case MESH_PHYSICS_MESH_AND_STATIC_COLLIDER : {
StaticBody3D * col = memnew ( StaticBody3D ) ;
2021-10-21 16:46:07 +02:00
p_node - > add_child ( col , true ) ;
Improve collision generation usability in the new 3D scene import workflow.
With this PR it's possible to add a collision during the Mesh import, directly in editor.
To generate the shape is possible to chose between the following options:
- Decompose Convex: The Mesh is decomposed in one or many Convex Shapes (Using the VHACD library).
- Simple Convex: Is generated a convex shape that enclose the entire mesh.
- Trimesh: Generate a trimesh shape using the Mesh faces.
- Box: Add a primitive box shape, where you can tweak the `size`, `position`, `rotation`.
- Sphere: Add a primitive sphere shape, where you can tweak the `radius`, `position`, `rotation`.
- Cylinder: Add a primitive cylinder shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
- Capsule: Add a primitive capsule shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
It's also possible to chose the generated body, so you can create:
- Rigid Body
- Static Body
- Area
2021-08-22 18:19:13 +02:00
col - > set_owner ( p_node - > get_owner ( ) ) ;
col - > set_transform ( get_collision_shapes_transform ( node_settings ) ) ;
2023-01-28 12:31:20 +01:00
col - > set_position ( p_applied_root_scale * col - > get_position ( ) ) ;
2023-05-27 00:33:01 +02:00
const Ref < PhysicsMaterial > & pmo = node_settings [ " physics/physics_material_override " ] ;
if ( ! pmo . is_null ( ) ) {
col - > set_physics_material_override ( pmo ) ;
}
2021-03-19 13:57:52 +01:00
base = col ;
} break ;
case MESH_PHYSICS_RIGID_BODY_AND_MESH : {
2022-08-25 19:35:52 +02:00
RigidBody3D * rigid_body = memnew ( RigidBody3D ) ;
2021-03-19 13:57:52 +01:00
rigid_body - > set_name ( p_node - > get_name ( ) ) ;
2024-01-25 18:01:56 +01:00
_copy_meta ( p_node , rigid_body ) ;
2021-03-19 13:57:52 +01:00
p_node - > replace_by ( rigid_body ) ;
Improve collision generation usability in the new 3D scene import workflow.
With this PR it's possible to add a collision during the Mesh import, directly in editor.
To generate the shape is possible to chose between the following options:
- Decompose Convex: The Mesh is decomposed in one or many Convex Shapes (Using the VHACD library).
- Simple Convex: Is generated a convex shape that enclose the entire mesh.
- Trimesh: Generate a trimesh shape using the Mesh faces.
- Box: Add a primitive box shape, where you can tweak the `size`, `position`, `rotation`.
- Sphere: Add a primitive sphere shape, where you can tweak the `radius`, `position`, `rotation`.
- Cylinder: Add a primitive cylinder shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
- Capsule: Add a primitive capsule shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
It's also possible to chose the generated body, so you can create:
- Rigid Body
- Static Body
- Area
2021-08-22 18:19:13 +02:00
rigid_body - > set_transform ( mi - > get_transform ( ) * get_collision_shapes_transform ( node_settings ) ) ;
2023-01-28 12:31:20 +01:00
rigid_body - > set_position ( p_applied_root_scale * rigid_body - > get_position ( ) ) ;
2021-03-19 13:57:52 +01:00
p_node = rigid_body ;
2020-10-17 07:08:21 +02:00
mi - > set_transform ( Transform3D ( ) ) ;
2021-10-21 16:46:07 +02:00
rigid_body - > add_child ( mi , true ) ;
2021-03-19 13:57:52 +01:00
mi - > set_owner ( rigid_body - > get_owner ( ) ) ;
2023-05-27 00:33:01 +02:00
const Ref < PhysicsMaterial > & pmo = node_settings [ " physics/physics_material_override " ] ;
if ( ! pmo . is_null ( ) ) {
rigid_body - > set_physics_material_override ( pmo ) ;
}
2021-03-19 13:57:52 +01:00
base = rigid_body ;
} break ;
case MESH_PHYSICS_STATIC_COLLIDER_ONLY : {
StaticBody3D * col = memnew ( StaticBody3D ) ;
Improve collision generation usability in the new 3D scene import workflow.
With this PR it's possible to add a collision during the Mesh import, directly in editor.
To generate the shape is possible to chose between the following options:
- Decompose Convex: The Mesh is decomposed in one or many Convex Shapes (Using the VHACD library).
- Simple Convex: Is generated a convex shape that enclose the entire mesh.
- Trimesh: Generate a trimesh shape using the Mesh faces.
- Box: Add a primitive box shape, where you can tweak the `size`, `position`, `rotation`.
- Sphere: Add a primitive sphere shape, where you can tweak the `radius`, `position`, `rotation`.
- Cylinder: Add a primitive cylinder shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
- Capsule: Add a primitive capsule shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
It's also possible to chose the generated body, so you can create:
- Rigid Body
- Static Body
- Area
2021-08-22 18:19:13 +02:00
col - > set_transform ( mi - > get_transform ( ) * get_collision_shapes_transform ( node_settings ) ) ;
2023-01-28 12:31:20 +01:00
col - > set_position ( p_applied_root_scale * col - > get_position ( ) ) ;
2021-03-19 13:57:52 +01:00
col - > set_name ( p_node - > get_name ( ) ) ;
2024-01-25 18:01:56 +01:00
_copy_meta ( p_node , col ) ;
2021-03-19 13:57:52 +01:00
p_node - > replace_by ( col ) ;
2023-02-27 17:24:03 +01:00
p_node - > set_owner ( nullptr ) ;
2021-03-19 13:57:52 +01:00
memdelete ( p_node ) ;
p_node = col ;
2023-05-27 00:33:01 +02:00
const Ref < PhysicsMaterial > & pmo = node_settings [ " physics/physics_material_override " ] ;
if ( ! pmo . is_null ( ) ) {
col - > set_physics_material_override ( pmo ) ;
}
2021-03-19 13:57:52 +01:00
base = col ;
} break ;
case MESH_PHYSICS_AREA_ONLY : {
Area3D * area = memnew ( Area3D ) ;
Improve collision generation usability in the new 3D scene import workflow.
With this PR it's possible to add a collision during the Mesh import, directly in editor.
To generate the shape is possible to chose between the following options:
- Decompose Convex: The Mesh is decomposed in one or many Convex Shapes (Using the VHACD library).
- Simple Convex: Is generated a convex shape that enclose the entire mesh.
- Trimesh: Generate a trimesh shape using the Mesh faces.
- Box: Add a primitive box shape, where you can tweak the `size`, `position`, `rotation`.
- Sphere: Add a primitive sphere shape, where you can tweak the `radius`, `position`, `rotation`.
- Cylinder: Add a primitive cylinder shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
- Capsule: Add a primitive capsule shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
It's also possible to chose the generated body, so you can create:
- Rigid Body
- Static Body
- Area
2021-08-22 18:19:13 +02:00
area - > set_transform ( mi - > get_transform ( ) * get_collision_shapes_transform ( node_settings ) ) ;
2023-01-28 12:31:20 +01:00
area - > set_position ( p_applied_root_scale * area - > get_position ( ) ) ;
2021-03-19 13:57:52 +01:00
area - > set_name ( p_node - > get_name ( ) ) ;
2024-01-25 18:01:56 +01:00
_copy_meta ( p_node , area ) ;
2021-03-19 13:57:52 +01:00
p_node - > replace_by ( area ) ;
2023-02-27 17:24:03 +01:00
p_node - > set_owner ( nullptr ) ;
2021-03-19 13:57:52 +01:00
memdelete ( p_node ) ;
p_node = area ;
base = area ;
} break ;
}
2023-05-27 00:33:01 +02:00
base - > set_collision_layer ( node_settings [ " physics/layer " ] ) ;
base - > set_collision_mask ( node_settings [ " physics/mask " ] ) ;
2021-07-24 15:46:25 +02:00
for ( const Ref < Shape3D > & E : shapes ) {
2021-03-19 13:57:52 +01:00
CollisionShape3D * cshape = memnew ( CollisionShape3D ) ;
2021-07-16 05:45:57 +02:00
cshape - > set_shape ( E ) ;
2021-10-21 16:46:07 +02:00
base - > add_child ( cshape , true ) ;
2021-03-19 13:57:52 +01:00
cshape - > set_owner ( base - > get_owner ( ) ) ;
}
}
}
}
}
}
//navmesh (node may have changed type above)
2021-09-21 03:24:31 +02:00
if ( Object : : cast_to < ImporterMeshInstance3D > ( p_node ) ) {
ImporterMeshInstance3D * mi = Object : : cast_to < ImporterMeshInstance3D > ( p_node ) ;
2021-03-19 13:57:52 +01:00
2021-09-21 03:24:31 +02:00
Ref < ImporterMesh > m = mi - > get_mesh ( ) ;
2021-03-19 13:57:52 +01:00
if ( m . is_valid ( ) ) {
if ( node_settings . has ( " generate/navmesh " ) ) {
int navmesh_mode = node_settings [ " generate/navmesh " ] ;
if ( navmesh_mode ! = NAVMESH_DISABLED ) {
NavigationRegion3D * nmi = memnew ( NavigationRegion3D ) ;
Ref < NavigationMesh > nmesh = m - > create_navigation_mesh ( ) ;
nmi - > set_navigation_mesh ( nmesh ) ;
if ( navmesh_mode = = NAVMESH_NAVMESH_ONLY ) {
nmi - > set_transform ( mi - > get_transform ( ) ) ;
2024-01-25 18:01:56 +01:00
_copy_meta ( p_node , nmi ) ;
2021-03-19 13:57:52 +01:00
p_node - > replace_by ( nmi ) ;
2023-02-27 17:24:03 +01:00
p_node - > set_owner ( nullptr ) ;
2021-03-19 13:57:52 +01:00
memdelete ( p_node ) ;
p_node = nmi ;
} else {
2021-10-21 16:46:07 +02:00
mi - > add_child ( nmi , true ) ;
2021-03-19 13:57:52 +01:00
nmi - > set_owner ( mi - > get_owner ( ) ) ;
}
}
}
}
}
2022-02-04 16:28:18 +01:00
if ( Object : : cast_to < ImporterMeshInstance3D > ( p_node ) ) {
ImporterMeshInstance3D * mi = Object : : cast_to < ImporterMeshInstance3D > ( p_node ) ;
Ref < ImporterMesh > m = mi - > get_mesh ( ) ;
if ( m . is_valid ( ) ) {
if ( node_settings . has ( " generate/occluder " ) ) {
int occluder_mode = node_settings [ " generate/occluder " ] ;
if ( occluder_mode ! = OCCLUDER_DISABLED ) {
float simplification_dist = 0.0f ;
if ( node_settings . has ( " occluder/simplification_distance " ) ) {
simplification_dist = node_settings [ " occluder/simplification_distance " ] ;
}
OccluderInstance3D : : bake_single_node ( mi , simplification_dist , r_occluder_arrays . first , r_occluder_arrays . second ) ;
if ( occluder_mode = = OCCLUDER_OCCLUDER_ONLY ) {
2023-02-27 17:24:03 +01:00
p_node - > set_owner ( nullptr ) ;
2022-02-04 16:28:18 +01:00
memdelete ( p_node ) ;
p_node = nullptr ;
}
}
}
}
}
2023-06-28 18:09:23 +02:00
if ( Object : : cast_to < ImporterMeshInstance3D > ( p_node ) ) {
ImporterMeshInstance3D * mi = Object : : cast_to < ImporterMeshInstance3D > ( p_node ) ;
if ( node_settings . has ( " mesh_instance/layers " ) ) {
mi - > set_layer_mask ( node_settings [ " mesh_instance/layers " ] ) ;
}
if ( node_settings . has ( " mesh_instance/visibility_range_begin " ) ) {
mi - > set_visibility_range_begin ( node_settings [ " mesh_instance/visibility_range_begin " ] ) ;
}
if ( node_settings . has ( " mesh_instance/visibility_range_begin_margin " ) ) {
mi - > set_visibility_range_begin_margin ( node_settings [ " mesh_instance/visibility_range_begin_margin " ] ) ;
}
if ( node_settings . has ( " mesh_instance/visibility_range_end " ) ) {
mi - > set_visibility_range_end ( node_settings [ " mesh_instance/visibility_range_end " ] ) ;
}
if ( node_settings . has ( " mesh_instance/visibility_range_end_margin " ) ) {
mi - > set_visibility_range_end_margin ( node_settings [ " mesh_instance/visibility_range_end_margin " ] ) ;
}
if ( node_settings . has ( " mesh_instance/visibility_range_fade_mode " ) ) {
const GeometryInstance3D : : VisibilityRangeFadeMode range_fade_mode = ( GeometryInstance3D : : VisibilityRangeFadeMode ) node_settings [ " mesh_instance/visibility_range_fade_mode " ] . operator int ( ) ;
mi - > set_visibility_range_fade_mode ( range_fade_mode ) ;
}
if ( node_settings . has ( " mesh_instance/cast_shadow " ) ) {
const GeometryInstance3D : : ShadowCastingSetting cast_shadows = ( GeometryInstance3D : : ShadowCastingSetting ) node_settings [ " mesh_instance/cast_shadow " ] . operator int ( ) ;
mi - > set_cast_shadows_setting ( cast_shadows ) ;
}
}
2021-03-19 13:57:52 +01:00
if ( Object : : cast_to < AnimationPlayer > ( p_node ) ) {
AnimationPlayer * ap = Object : : cast_to < AnimationPlayer > ( p_node ) ;
2021-10-14 19:34:27 +02:00
for ( int i = 0 ; i < post_importer_plugins . size ( ) ; i + + ) {
2022-05-03 01:43:50 +02:00
post_importer_plugins . write [ i ] - > internal_process ( EditorScenePostImportPlugin : : INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE , p_root , p_node , Ref < Resource > ( ) , node_settings ) ;
2021-10-14 19:34:27 +02:00
}
if ( post_importer_plugins . size ( ) ) {
List < StringName > anims ;
ap - > get_animation_list ( & anims ) ;
for ( const StringName & name : anims ) {
if ( p_animation_data . has ( name ) ) {
Ref < Animation > anim = ap - > get_animation ( name ) ;
Dictionary anim_settings = p_animation_data [ name ] ;
{
//fill with default values
List < ImportOption > iopts ;
get_internal_import_options ( INTERNAL_IMPORT_CATEGORY_ANIMATION , & iopts ) ;
for ( const ImportOption & F : iopts ) {
if ( ! anim_settings . has ( F . option . name ) ) {
anim_settings [ F . option . name ] = F . default_value ;
}
}
}
for ( int i = 0 ; i < post_importer_plugins . size ( ) ; i + + ) {
2022-10-23 17:19:10 +02:00
post_importer_plugins . write [ i ] - > internal_process ( EditorScenePostImportPlugin : : INTERNAL_IMPORT_CATEGORY_ANIMATION , p_root , p_node , anim , anim_settings ) ;
2021-10-14 19:34:27 +02:00
}
}
}
}
2020-05-14 16:41:43 +02:00
}
2017-02-04 13:48:04 +01:00
2021-03-19 13:57:52 +01:00
return p_node ;
}
2024-02-15 17:25:58 +01:00
Ref < Animation > ResourceImporterScene : : _save_animation_to_file ( Ref < Animation > anim , bool p_save_to_file , const String & p_save_to_path , bool p_keep_custom_tracks ) {
2021-03-19 13:57:52 +01:00
if ( ! p_save_to_file | | ! p_save_to_path . is_resource_file ( ) ) {
return anim ;
}
if ( FileAccess : : exists ( p_save_to_path ) & & p_keep_custom_tracks ) {
// Copy custom animation tracks from previously imported files.
Ref < Animation > old_anim = ResourceLoader : : load ( p_save_to_path , " Animation " , ResourceFormatLoader : : CACHE_MODE_IGNORE ) ;
if ( old_anim . is_valid ( ) ) {
for ( int i = 0 ; i < old_anim - > get_track_count ( ) ; i + + ) {
if ( ! old_anim - > track_is_imported ( i ) ) {
old_anim - > copy_track ( i , anim ) ;
}
}
2021-10-15 15:25:00 +02:00
anim - > set_loop_mode ( old_anim - > get_loop_mode ( ) ) ;
2021-03-19 13:57:52 +01:00
}
}
2017-02-04 13:48:04 +01:00
2021-03-19 13:57:52 +01:00
if ( ResourceCache : : has ( p_save_to_path ) ) {
2022-06-22 13:46:46 +02:00
Ref < Animation > old_anim = ResourceCache : : get_ref ( p_save_to_path ) ;
2021-03-19 13:57:52 +01:00
if ( old_anim . is_valid ( ) ) {
old_anim - > copy_from ( anim ) ;
anim = old_anim ;
}
}
anim - > set_path ( p_save_to_path , true ) ; // Set path to save externally.
2022-06-03 01:33:42 +02:00
Error err = ResourceSaver : : save ( anim , p_save_to_path , ResourceSaver : : FLAG_CHANGE_PATH ) ;
2021-03-19 13:57:52 +01:00
ERR_FAIL_COND_V_MSG ( err ! = OK , anim , " Saving of animation failed: " + p_save_to_path ) ;
return anim ;
}
2022-10-10 22:59:57 +02:00
void ResourceImporterScene : : _create_slices ( AnimationPlayer * ap , Ref < Animation > anim , const Array & p_slices , bool p_bake_all ) {
Ref < AnimationLibrary > al = ap - > get_animation_library ( ap - > find_animation_library ( anim ) ) ;
for ( int i = 0 ; i < p_slices . size ( ) ; i + = 7 ) {
String name = p_slices [ i ] ;
float from = p_slices [ i + 1 ] ;
float to = p_slices [ i + 2 ] ;
Animation : : LoopMode loop_mode = static_cast < Animation : : LoopMode > ( ( int ) p_slices [ i + 3 ] ) ;
bool save_to_file = p_slices [ i + 4 ] ;
String save_to_path = p_slices [ i + 5 ] ;
bool keep_current = p_slices [ i + 6 ] ;
2020-05-14 16:41:43 +02:00
if ( from > = to ) {
2017-02-04 13:48:04 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2017-02-04 13:48:04 +01:00
Ref < Animation > new_anim = memnew ( Animation ) ;
2022-10-10 22:59:57 +02:00
for ( int j = 0 ; j < anim - > get_track_count ( ) ; j + + ) {
2017-02-04 13:48:04 +01:00
List < float > keys ;
2022-10-10 22:59:57 +02:00
int kc = anim - > track_get_key_count ( j ) ;
2017-02-04 13:48:04 +01:00
int dtrack = - 1 ;
for ( int k = 0 ; k < kc ; k + + ) {
2022-10-10 22:59:57 +02:00
float kt = anim - > track_get_key_time ( j , k ) ;
2017-02-04 13:48:04 +01:00
if ( kt > = from & & kt < to ) {
//found a key within range, so create track
if ( dtrack = = - 1 ) {
2022-10-10 22:59:57 +02:00
new_anim - > add_track ( anim - > track_get_type ( j ) ) ;
2017-02-04 13:48:04 +01:00
dtrack = new_anim - > get_track_count ( ) - 1 ;
2022-10-10 22:59:57 +02:00
new_anim - > track_set_path ( dtrack , anim - > track_get_path ( j ) ) ;
2023-11-18 16:36:33 +01:00
new_anim - > track_set_imported ( dtrack , true ) ;
2017-02-04 13:48:04 +01:00
if ( kt > ( from + 0.01 ) & & k > 0 ) {
2022-10-10 22:59:57 +02:00
if ( anim - > track_get_type ( j ) = = Animation : : TYPE_POSITION_3D ) {
2017-02-04 13:48:04 +01:00
Vector3 p ;
2023-02-21 03:26:23 +01:00
anim - > try_position_track_interpolate ( j , from , & p ) ;
Remove animation 3D transform track, replace by loc/rot/scale tracks.
* `Animation.TYPE_TRANSFORM3D` track is gone.
* Added POSITION_3D, ROTATION_3D, SCALE_3D tracks.
* GLTF2, Collada, FBX importers will only import the track types found.
* Skeleton3D bone poses are now Pos/Rot/Scale, pose matrix removed.
* AnimationPlayer and AnimationTree animate these tracks separately, only when found.
* Removed BakeReset code, is useless with these changes.
This is the first in a series of commits designed to make the animation system in Godot more useful, which includes:
* Better compatibility with Autodesk products
* Better reusability of animations across models (including retargeting).
* Proper animation compression.
* etc.
*Note* GLTF2 animation saving went broken with this PR, needs to be fixed in a subsequent one.
2021-10-12 00:20:58 +02:00
new_anim - > position_track_insert_key ( dtrack , 0 , p ) ;
2022-10-10 22:59:57 +02:00
} else if ( anim - > track_get_type ( j ) = = Animation : : TYPE_ROTATION_3D ) {
Remove animation 3D transform track, replace by loc/rot/scale tracks.
* `Animation.TYPE_TRANSFORM3D` track is gone.
* Added POSITION_3D, ROTATION_3D, SCALE_3D tracks.
* GLTF2, Collada, FBX importers will only import the track types found.
* Skeleton3D bone poses are now Pos/Rot/Scale, pose matrix removed.
* AnimationPlayer and AnimationTree animate these tracks separately, only when found.
* Removed BakeReset code, is useless with these changes.
This is the first in a series of commits designed to make the animation system in Godot more useful, which includes:
* Better compatibility with Autodesk products
* Better reusability of animations across models (including retargeting).
* Proper animation compression.
* etc.
*Note* GLTF2 animation saving went broken with this PR, needs to be fixed in a subsequent one.
2021-10-12 00:20:58 +02:00
Quaternion r ;
2023-02-21 03:26:23 +01:00
anim - > try_rotation_track_interpolate ( j , from , & r ) ;
Remove animation 3D transform track, replace by loc/rot/scale tracks.
* `Animation.TYPE_TRANSFORM3D` track is gone.
* Added POSITION_3D, ROTATION_3D, SCALE_3D tracks.
* GLTF2, Collada, FBX importers will only import the track types found.
* Skeleton3D bone poses are now Pos/Rot/Scale, pose matrix removed.
* AnimationPlayer and AnimationTree animate these tracks separately, only when found.
* Removed BakeReset code, is useless with these changes.
This is the first in a series of commits designed to make the animation system in Godot more useful, which includes:
* Better compatibility with Autodesk products
* Better reusability of animations across models (including retargeting).
* Proper animation compression.
* etc.
*Note* GLTF2 animation saving went broken with this PR, needs to be fixed in a subsequent one.
2021-10-12 00:20:58 +02:00
new_anim - > rotation_track_insert_key ( dtrack , 0 , r ) ;
2022-10-10 22:59:57 +02:00
} else if ( anim - > track_get_type ( j ) = = Animation : : TYPE_SCALE_3D ) {
2017-02-04 13:48:04 +01:00
Vector3 s ;
2023-02-21 03:26:23 +01:00
anim - > try_scale_track_interpolate ( j , from , & s ) ;
Remove animation 3D transform track, replace by loc/rot/scale tracks.
* `Animation.TYPE_TRANSFORM3D` track is gone.
* Added POSITION_3D, ROTATION_3D, SCALE_3D tracks.
* GLTF2, Collada, FBX importers will only import the track types found.
* Skeleton3D bone poses are now Pos/Rot/Scale, pose matrix removed.
* AnimationPlayer and AnimationTree animate these tracks separately, only when found.
* Removed BakeReset code, is useless with these changes.
This is the first in a series of commits designed to make the animation system in Godot more useful, which includes:
* Better compatibility with Autodesk products
* Better reusability of animations across models (including retargeting).
* Proper animation compression.
* etc.
*Note* GLTF2 animation saving went broken with this PR, needs to be fixed in a subsequent one.
2021-10-12 00:20:58 +02:00
new_anim - > scale_track_insert_key ( dtrack , 0 , s ) ;
2022-10-10 22:59:57 +02:00
} else if ( anim - > track_get_type ( j ) = = Animation : : TYPE_VALUE ) {
Variant var = anim - > value_track_interpolate ( j , from ) ;
2019-04-24 01:34:37 +02:00
new_anim - > track_insert_key ( dtrack , 0 , var ) ;
2022-10-10 22:59:57 +02:00
} else if ( anim - > track_get_type ( j ) = = Animation : : TYPE_BLEND_SHAPE ) {
2021-10-16 00:04:35 +02:00
float interp ;
2023-02-21 03:26:23 +01:00
anim - > try_blend_shape_track_interpolate ( j , from , & interp ) ;
2021-10-16 00:04:35 +02:00
new_anim - > blend_shape_track_insert_key ( dtrack , 0 , interp ) ;
2019-04-24 01:34:37 +02:00
}
2017-02-04 13:48:04 +01:00
}
}
2022-10-10 22:59:57 +02:00
if ( anim - > track_get_type ( j ) = = Animation : : TYPE_POSITION_3D ) {
2017-02-04 13:48:04 +01:00
Vector3 p ;
2022-10-10 22:59:57 +02:00
anim - > position_track_get_key ( j , k , & p ) ;
Remove animation 3D transform track, replace by loc/rot/scale tracks.
* `Animation.TYPE_TRANSFORM3D` track is gone.
* Added POSITION_3D, ROTATION_3D, SCALE_3D tracks.
* GLTF2, Collada, FBX importers will only import the track types found.
* Skeleton3D bone poses are now Pos/Rot/Scale, pose matrix removed.
* AnimationPlayer and AnimationTree animate these tracks separately, only when found.
* Removed BakeReset code, is useless with these changes.
This is the first in a series of commits designed to make the animation system in Godot more useful, which includes:
* Better compatibility with Autodesk products
* Better reusability of animations across models (including retargeting).
* Proper animation compression.
* etc.
*Note* GLTF2 animation saving went broken with this PR, needs to be fixed in a subsequent one.
2021-10-12 00:20:58 +02:00
new_anim - > position_track_insert_key ( dtrack , kt - from , p ) ;
2022-10-10 22:59:57 +02:00
} else if ( anim - > track_get_type ( j ) = = Animation : : TYPE_ROTATION_3D ) {
Remove animation 3D transform track, replace by loc/rot/scale tracks.
* `Animation.TYPE_TRANSFORM3D` track is gone.
* Added POSITION_3D, ROTATION_3D, SCALE_3D tracks.
* GLTF2, Collada, FBX importers will only import the track types found.
* Skeleton3D bone poses are now Pos/Rot/Scale, pose matrix removed.
* AnimationPlayer and AnimationTree animate these tracks separately, only when found.
* Removed BakeReset code, is useless with these changes.
This is the first in a series of commits designed to make the animation system in Godot more useful, which includes:
* Better compatibility with Autodesk products
* Better reusability of animations across models (including retargeting).
* Proper animation compression.
* etc.
*Note* GLTF2 animation saving went broken with this PR, needs to be fixed in a subsequent one.
2021-10-12 00:20:58 +02:00
Quaternion r ;
2022-10-10 22:59:57 +02:00
anim - > rotation_track_get_key ( j , k , & r ) ;
Remove animation 3D transform track, replace by loc/rot/scale tracks.
* `Animation.TYPE_TRANSFORM3D` track is gone.
* Added POSITION_3D, ROTATION_3D, SCALE_3D tracks.
* GLTF2, Collada, FBX importers will only import the track types found.
* Skeleton3D bone poses are now Pos/Rot/Scale, pose matrix removed.
* AnimationPlayer and AnimationTree animate these tracks separately, only when found.
* Removed BakeReset code, is useless with these changes.
This is the first in a series of commits designed to make the animation system in Godot more useful, which includes:
* Better compatibility with Autodesk products
* Better reusability of animations across models (including retargeting).
* Proper animation compression.
* etc.
*Note* GLTF2 animation saving went broken with this PR, needs to be fixed in a subsequent one.
2021-10-12 00:20:58 +02:00
new_anim - > rotation_track_insert_key ( dtrack , kt - from , r ) ;
2022-10-10 22:59:57 +02:00
} else if ( anim - > track_get_type ( j ) = = Animation : : TYPE_SCALE_3D ) {
2017-02-04 13:48:04 +01:00
Vector3 s ;
2022-10-10 22:59:57 +02:00
anim - > scale_track_get_key ( j , k , & s ) ;
Remove animation 3D transform track, replace by loc/rot/scale tracks.
* `Animation.TYPE_TRANSFORM3D` track is gone.
* Added POSITION_3D, ROTATION_3D, SCALE_3D tracks.
* GLTF2, Collada, FBX importers will only import the track types found.
* Skeleton3D bone poses are now Pos/Rot/Scale, pose matrix removed.
* AnimationPlayer and AnimationTree animate these tracks separately, only when found.
* Removed BakeReset code, is useless with these changes.
This is the first in a series of commits designed to make the animation system in Godot more useful, which includes:
* Better compatibility with Autodesk products
* Better reusability of animations across models (including retargeting).
* Proper animation compression.
* etc.
*Note* GLTF2 animation saving went broken with this PR, needs to be fixed in a subsequent one.
2021-10-12 00:20:58 +02:00
new_anim - > scale_track_insert_key ( dtrack , kt - from , s ) ;
2022-10-10 22:59:57 +02:00
} else if ( anim - > track_get_type ( j ) = = Animation : : TYPE_VALUE ) {
Variant var = anim - > track_get_key_value ( j , k ) ;
2019-04-24 01:34:37 +02:00
new_anim - > track_insert_key ( dtrack , kt - from , var ) ;
2022-10-10 22:59:57 +02:00
} else if ( anim - > track_get_type ( j ) = = Animation : : TYPE_BLEND_SHAPE ) {
2021-10-16 00:04:35 +02:00
float interp ;
2022-10-10 22:59:57 +02:00
anim - > blend_shape_track_get_key ( j , k , & interp ) ;
2021-10-16 00:04:35 +02:00
new_anim - > blend_shape_track_insert_key ( dtrack , kt - from , interp ) ;
2019-04-24 01:34:37 +02:00
}
2017-02-04 13:48:04 +01:00
}
if ( dtrack ! = - 1 & & kt > = to ) {
2022-10-10 22:59:57 +02:00
if ( anim - > track_get_type ( j ) = = Animation : : TYPE_POSITION_3D ) {
2017-02-04 13:48:04 +01:00
Vector3 p ;
2023-02-21 03:26:23 +01:00
anim - > try_position_track_interpolate ( j , to , & p ) ;
Remove animation 3D transform track, replace by loc/rot/scale tracks.
* `Animation.TYPE_TRANSFORM3D` track is gone.
* Added POSITION_3D, ROTATION_3D, SCALE_3D tracks.
* GLTF2, Collada, FBX importers will only import the track types found.
* Skeleton3D bone poses are now Pos/Rot/Scale, pose matrix removed.
* AnimationPlayer and AnimationTree animate these tracks separately, only when found.
* Removed BakeReset code, is useless with these changes.
This is the first in a series of commits designed to make the animation system in Godot more useful, which includes:
* Better compatibility with Autodesk products
* Better reusability of animations across models (including retargeting).
* Proper animation compression.
* etc.
*Note* GLTF2 animation saving went broken with this PR, needs to be fixed in a subsequent one.
2021-10-12 00:20:58 +02:00
new_anim - > position_track_insert_key ( dtrack , to - from , p ) ;
2022-10-10 22:59:57 +02:00
} else if ( anim - > track_get_type ( j ) = = Animation : : TYPE_ROTATION_3D ) {
Remove animation 3D transform track, replace by loc/rot/scale tracks.
* `Animation.TYPE_TRANSFORM3D` track is gone.
* Added POSITION_3D, ROTATION_3D, SCALE_3D tracks.
* GLTF2, Collada, FBX importers will only import the track types found.
* Skeleton3D bone poses are now Pos/Rot/Scale, pose matrix removed.
* AnimationPlayer and AnimationTree animate these tracks separately, only when found.
* Removed BakeReset code, is useless with these changes.
This is the first in a series of commits designed to make the animation system in Godot more useful, which includes:
* Better compatibility with Autodesk products
* Better reusability of animations across models (including retargeting).
* Proper animation compression.
* etc.
*Note* GLTF2 animation saving went broken with this PR, needs to be fixed in a subsequent one.
2021-10-12 00:20:58 +02:00
Quaternion r ;
2023-02-21 03:26:23 +01:00
anim - > try_rotation_track_interpolate ( j , to , & r ) ;
Remove animation 3D transform track, replace by loc/rot/scale tracks.
* `Animation.TYPE_TRANSFORM3D` track is gone.
* Added POSITION_3D, ROTATION_3D, SCALE_3D tracks.
* GLTF2, Collada, FBX importers will only import the track types found.
* Skeleton3D bone poses are now Pos/Rot/Scale, pose matrix removed.
* AnimationPlayer and AnimationTree animate these tracks separately, only when found.
* Removed BakeReset code, is useless with these changes.
This is the first in a series of commits designed to make the animation system in Godot more useful, which includes:
* Better compatibility with Autodesk products
* Better reusability of animations across models (including retargeting).
* Proper animation compression.
* etc.
*Note* GLTF2 animation saving went broken with this PR, needs to be fixed in a subsequent one.
2021-10-12 00:20:58 +02:00
new_anim - > rotation_track_insert_key ( dtrack , to - from , r ) ;
2022-10-10 22:59:57 +02:00
} else if ( anim - > track_get_type ( j ) = = Animation : : TYPE_SCALE_3D ) {
2017-02-04 13:48:04 +01:00
Vector3 s ;
2023-02-21 03:26:23 +01:00
anim - > try_scale_track_interpolate ( j , to , & s ) ;
Remove animation 3D transform track, replace by loc/rot/scale tracks.
* `Animation.TYPE_TRANSFORM3D` track is gone.
* Added POSITION_3D, ROTATION_3D, SCALE_3D tracks.
* GLTF2, Collada, FBX importers will only import the track types found.
* Skeleton3D bone poses are now Pos/Rot/Scale, pose matrix removed.
* AnimationPlayer and AnimationTree animate these tracks separately, only when found.
* Removed BakeReset code, is useless with these changes.
This is the first in a series of commits designed to make the animation system in Godot more useful, which includes:
* Better compatibility with Autodesk products
* Better reusability of animations across models (including retargeting).
* Proper animation compression.
* etc.
*Note* GLTF2 animation saving went broken with this PR, needs to be fixed in a subsequent one.
2021-10-12 00:20:58 +02:00
new_anim - > scale_track_insert_key ( dtrack , to - from , s ) ;
2022-10-10 22:59:57 +02:00
} else if ( anim - > track_get_type ( j ) = = Animation : : TYPE_VALUE ) {
Variant var = anim - > value_track_interpolate ( j , to ) ;
2019-04-24 01:34:37 +02:00
new_anim - > track_insert_key ( dtrack , to - from , var ) ;
2022-10-10 22:59:57 +02:00
} else if ( anim - > track_get_type ( j ) = = Animation : : TYPE_BLEND_SHAPE ) {
2021-10-16 00:04:35 +02:00
float interp ;
2023-02-21 03:26:23 +01:00
anim - > try_blend_shape_track_interpolate ( j , to , & interp ) ;
2021-10-16 00:04:35 +02:00
new_anim - > blend_shape_track_insert_key ( dtrack , to - from , interp ) ;
2019-04-24 01:34:37 +02:00
}
2017-02-04 13:48:04 +01:00
}
}
if ( dtrack = = - 1 & & p_bake_all ) {
2022-10-10 22:59:57 +02:00
new_anim - > add_track ( anim - > track_get_type ( j ) ) ;
2017-02-04 13:48:04 +01:00
dtrack = new_anim - > get_track_count ( ) - 1 ;
2022-10-10 22:59:57 +02:00
new_anim - > track_set_path ( dtrack , anim - > track_get_path ( j ) ) ;
2023-11-18 16:36:33 +01:00
new_anim - > track_set_imported ( dtrack , true ) ;
2022-10-10 22:59:57 +02:00
if ( anim - > track_get_type ( j ) = = Animation : : TYPE_POSITION_3D ) {
2017-02-04 13:48:04 +01:00
Vector3 p ;
2023-02-21 03:26:23 +01:00
anim - > try_position_track_interpolate ( j , from , & p ) ;
Remove animation 3D transform track, replace by loc/rot/scale tracks.
* `Animation.TYPE_TRANSFORM3D` track is gone.
* Added POSITION_3D, ROTATION_3D, SCALE_3D tracks.
* GLTF2, Collada, FBX importers will only import the track types found.
* Skeleton3D bone poses are now Pos/Rot/Scale, pose matrix removed.
* AnimationPlayer and AnimationTree animate these tracks separately, only when found.
* Removed BakeReset code, is useless with these changes.
This is the first in a series of commits designed to make the animation system in Godot more useful, which includes:
* Better compatibility with Autodesk products
* Better reusability of animations across models (including retargeting).
* Proper animation compression.
* etc.
*Note* GLTF2 animation saving went broken with this PR, needs to be fixed in a subsequent one.
2021-10-12 00:20:58 +02:00
new_anim - > position_track_insert_key ( dtrack , 0 , p ) ;
2023-02-21 03:26:23 +01:00
anim - > try_position_track_interpolate ( j , to , & p ) ;
Remove animation 3D transform track, replace by loc/rot/scale tracks.
* `Animation.TYPE_TRANSFORM3D` track is gone.
* Added POSITION_3D, ROTATION_3D, SCALE_3D tracks.
* GLTF2, Collada, FBX importers will only import the track types found.
* Skeleton3D bone poses are now Pos/Rot/Scale, pose matrix removed.
* AnimationPlayer and AnimationTree animate these tracks separately, only when found.
* Removed BakeReset code, is useless with these changes.
This is the first in a series of commits designed to make the animation system in Godot more useful, which includes:
* Better compatibility with Autodesk products
* Better reusability of animations across models (including retargeting).
* Proper animation compression.
* etc.
*Note* GLTF2 animation saving went broken with this PR, needs to be fixed in a subsequent one.
2021-10-12 00:20:58 +02:00
new_anim - > position_track_insert_key ( dtrack , to - from , p ) ;
2022-10-10 22:59:57 +02:00
} else if ( anim - > track_get_type ( j ) = = Animation : : TYPE_ROTATION_3D ) {
Remove animation 3D transform track, replace by loc/rot/scale tracks.
* `Animation.TYPE_TRANSFORM3D` track is gone.
* Added POSITION_3D, ROTATION_3D, SCALE_3D tracks.
* GLTF2, Collada, FBX importers will only import the track types found.
* Skeleton3D bone poses are now Pos/Rot/Scale, pose matrix removed.
* AnimationPlayer and AnimationTree animate these tracks separately, only when found.
* Removed BakeReset code, is useless with these changes.
This is the first in a series of commits designed to make the animation system in Godot more useful, which includes:
* Better compatibility with Autodesk products
* Better reusability of animations across models (including retargeting).
* Proper animation compression.
* etc.
*Note* GLTF2 animation saving went broken with this PR, needs to be fixed in a subsequent one.
2021-10-12 00:20:58 +02:00
Quaternion r ;
2023-02-21 03:26:23 +01:00
anim - > try_rotation_track_interpolate ( j , from , & r ) ;
Remove animation 3D transform track, replace by loc/rot/scale tracks.
* `Animation.TYPE_TRANSFORM3D` track is gone.
* Added POSITION_3D, ROTATION_3D, SCALE_3D tracks.
* GLTF2, Collada, FBX importers will only import the track types found.
* Skeleton3D bone poses are now Pos/Rot/Scale, pose matrix removed.
* AnimationPlayer and AnimationTree animate these tracks separately, only when found.
* Removed BakeReset code, is useless with these changes.
This is the first in a series of commits designed to make the animation system in Godot more useful, which includes:
* Better compatibility with Autodesk products
* Better reusability of animations across models (including retargeting).
* Proper animation compression.
* etc.
*Note* GLTF2 animation saving went broken with this PR, needs to be fixed in a subsequent one.
2021-10-12 00:20:58 +02:00
new_anim - > rotation_track_insert_key ( dtrack , 0 , r ) ;
2023-02-21 03:26:23 +01:00
anim - > try_rotation_track_interpolate ( j , to , & r ) ;
Remove animation 3D transform track, replace by loc/rot/scale tracks.
* `Animation.TYPE_TRANSFORM3D` track is gone.
* Added POSITION_3D, ROTATION_3D, SCALE_3D tracks.
* GLTF2, Collada, FBX importers will only import the track types found.
* Skeleton3D bone poses are now Pos/Rot/Scale, pose matrix removed.
* AnimationPlayer and AnimationTree animate these tracks separately, only when found.
* Removed BakeReset code, is useless with these changes.
This is the first in a series of commits designed to make the animation system in Godot more useful, which includes:
* Better compatibility with Autodesk products
* Better reusability of animations across models (including retargeting).
* Proper animation compression.
* etc.
*Note* GLTF2 animation saving went broken with this PR, needs to be fixed in a subsequent one.
2021-10-12 00:20:58 +02:00
new_anim - > rotation_track_insert_key ( dtrack , to - from , r ) ;
2022-10-10 22:59:57 +02:00
} else if ( anim - > track_get_type ( j ) = = Animation : : TYPE_SCALE_3D ) {
2017-02-04 13:48:04 +01:00
Vector3 s ;
2023-02-21 03:26:23 +01:00
anim - > try_scale_track_interpolate ( j , from , & s ) ;
Remove animation 3D transform track, replace by loc/rot/scale tracks.
* `Animation.TYPE_TRANSFORM3D` track is gone.
* Added POSITION_3D, ROTATION_3D, SCALE_3D tracks.
* GLTF2, Collada, FBX importers will only import the track types found.
* Skeleton3D bone poses are now Pos/Rot/Scale, pose matrix removed.
* AnimationPlayer and AnimationTree animate these tracks separately, only when found.
* Removed BakeReset code, is useless with these changes.
This is the first in a series of commits designed to make the animation system in Godot more useful, which includes:
* Better compatibility with Autodesk products
* Better reusability of animations across models (including retargeting).
* Proper animation compression.
* etc.
*Note* GLTF2 animation saving went broken with this PR, needs to be fixed in a subsequent one.
2021-10-12 00:20:58 +02:00
new_anim - > scale_track_insert_key ( dtrack , 0 , s ) ;
2023-02-21 03:26:23 +01:00
anim - > try_scale_track_interpolate ( j , to , & s ) ;
Remove animation 3D transform track, replace by loc/rot/scale tracks.
* `Animation.TYPE_TRANSFORM3D` track is gone.
* Added POSITION_3D, ROTATION_3D, SCALE_3D tracks.
* GLTF2, Collada, FBX importers will only import the track types found.
* Skeleton3D bone poses are now Pos/Rot/Scale, pose matrix removed.
* AnimationPlayer and AnimationTree animate these tracks separately, only when found.
* Removed BakeReset code, is useless with these changes.
This is the first in a series of commits designed to make the animation system in Godot more useful, which includes:
* Better compatibility with Autodesk products
* Better reusability of animations across models (including retargeting).
* Proper animation compression.
* etc.
*Note* GLTF2 animation saving went broken with this PR, needs to be fixed in a subsequent one.
2021-10-12 00:20:58 +02:00
new_anim - > scale_track_insert_key ( dtrack , to - from , s ) ;
2022-10-10 22:59:57 +02:00
} else if ( anim - > track_get_type ( j ) = = Animation : : TYPE_VALUE ) {
Variant var = anim - > value_track_interpolate ( j , from ) ;
2019-04-24 01:34:37 +02:00
new_anim - > track_insert_key ( dtrack , 0 , var ) ;
2022-10-10 22:59:57 +02:00
Variant to_var = anim - > value_track_interpolate ( j , to ) ;
2019-04-24 01:34:37 +02:00
new_anim - > track_insert_key ( dtrack , to - from , to_var ) ;
2022-10-10 22:59:57 +02:00
} else if ( anim - > track_get_type ( j ) = = Animation : : TYPE_BLEND_SHAPE ) {
2021-10-16 00:04:35 +02:00
float interp ;
2023-02-21 03:26:23 +01:00
anim - > try_blend_shape_track_interpolate ( j , from , & interp ) ;
2021-10-16 00:04:35 +02:00
new_anim - > blend_shape_track_insert_key ( dtrack , 0 , interp ) ;
2023-02-21 03:26:23 +01:00
anim - > try_blend_shape_track_interpolate ( j , to , & interp ) ;
2021-10-16 00:04:35 +02:00
new_anim - > blend_shape_track_insert_key ( dtrack , to - from , interp ) ;
2019-04-24 01:34:37 +02:00
}
2017-02-04 13:48:04 +01:00
}
}
2021-10-15 15:25:00 +02:00
new_anim - > set_loop_mode ( loop_mode ) ;
2017-02-04 13:48:04 +01:00
new_anim - > set_length ( to - from ) ;
2024-04-19 11:05:46 +02:00
new_anim - > set_step ( anim - > get_step ( ) ) ;
2022-04-07 13:49:28 +02:00
al - > add_animation ( name , new_anim ) ;
2017-02-04 13:48:04 +01:00
2021-03-19 13:57:52 +01:00
Ref < Animation > saved_anim = _save_animation_to_file ( new_anim , save_to_file , save_to_path , keep_current ) ;
if ( saved_anim ! = new_anim ) {
2022-04-07 13:49:28 +02:00
al - > add_animation ( name , saved_anim ) ;
2017-02-04 13:48:04 +01:00
}
}
2022-10-10 22:59:57 +02:00
al - > remove_animation ( ap - > find_animation ( anim ) ) ; // Remove original animation (no longer needed).
2017-02-04 13:48:04 +01:00
}
2022-08-07 03:55:37 +02:00
void ResourceImporterScene : : _optimize_animations ( AnimationPlayer * anim , float p_max_vel_error , float p_max_ang_error , int p_prc_error ) {
2017-02-04 13:48:04 +01:00
List < StringName > anim_names ;
anim - > get_animation_list ( & anim_names ) ;
2021-07-24 15:46:25 +02:00
for ( const StringName & E : anim_names ) {
2021-07-16 05:45:57 +02:00
Ref < Animation > a = anim - > get_animation ( E ) ;
2022-08-07 03:55:37 +02:00
a - > optimize ( p_max_vel_error , p_max_ang_error , p_prc_error ) ;
2017-02-04 13:48:04 +01:00
}
}
2021-10-21 01:42:22 +02:00
void ResourceImporterScene : : _compress_animations ( AnimationPlayer * anim , int p_page_size_kb ) {
List < StringName > anim_names ;
anim - > get_animation_list ( & anim_names ) ;
for ( const StringName & E : anim_names ) {
Ref < Animation > a = anim - > get_animation ( E ) ;
a - > compress ( p_page_size_kb * 1024 ) ;
}
}
2021-03-19 13:57:52 +01:00
void ResourceImporterScene : : get_internal_import_options ( InternalImportCategory p_category , List < ImportOption > * r_options ) const {
switch ( p_category ) {
case INTERNAL_IMPORT_CATEGORY_NODE : {
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : BOOL , " import/skip_import " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED ) , false ) ) ;
} break ;
case INTERNAL_IMPORT_CATEGORY_MESH_3D_NODE : {
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : BOOL , " import/skip_import " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED ) , false ) ) ;
Improve collision generation usability in the new 3D scene import workflow.
With this PR it's possible to add a collision during the Mesh import, directly in editor.
To generate the shape is possible to chose between the following options:
- Decompose Convex: The Mesh is decomposed in one or many Convex Shapes (Using the VHACD library).
- Simple Convex: Is generated a convex shape that enclose the entire mesh.
- Trimesh: Generate a trimesh shape using the Mesh faces.
- Box: Add a primitive box shape, where you can tweak the `size`, `position`, `rotation`.
- Sphere: Add a primitive sphere shape, where you can tweak the `radius`, `position`, `rotation`.
- Cylinder: Add a primitive cylinder shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
- Capsule: Add a primitive capsule shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
It's also possible to chose the generated body, so you can create:
- Rigid Body
- Static Body
- Area
2021-08-22 18:19:13 +02:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : BOOL , " generate/physics " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED ) , false ) ) ;
2021-03-19 13:57:52 +01:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : INT , " generate/navmesh " , PROPERTY_HINT_ENUM , " Disabled,Mesh + NavMesh,NavMesh Only " ) , 0 ) ) ;
Improve collision generation usability in the new 3D scene import workflow.
With this PR it's possible to add a collision during the Mesh import, directly in editor.
To generate the shape is possible to chose between the following options:
- Decompose Convex: The Mesh is decomposed in one or many Convex Shapes (Using the VHACD library).
- Simple Convex: Is generated a convex shape that enclose the entire mesh.
- Trimesh: Generate a trimesh shape using the Mesh faces.
- Box: Add a primitive box shape, where you can tweak the `size`, `position`, `rotation`.
- Sphere: Add a primitive sphere shape, where you can tweak the `radius`, `position`, `rotation`.
- Cylinder: Add a primitive cylinder shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
- Capsule: Add a primitive capsule shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
It's also possible to chose the generated body, so you can create:
- Rigid Body
- Static Body
- Area
2021-08-22 18:19:13 +02:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : INT , " physics/body_type " , PROPERTY_HINT_ENUM , " Static,Dynamic,Area " ) , 0 ) ) ;
2024-03-13 23:56:05 +01:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : INT , " physics/shape_type " , PROPERTY_HINT_ENUM , " Decompose Convex,Simple Convex,Trimesh,Box,Sphere,Cylinder,Capsule " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED ) , 2 ) ) ;
2023-05-27 00:33:01 +02:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : OBJECT , " physics/physics_material_override " , PROPERTY_HINT_RESOURCE_TYPE , " PhysicsMaterial " ) , Variant ( ) ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : INT , " physics/layer " , PROPERTY_HINT_LAYERS_3D_PHYSICS ) , 1 ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : INT , " physics/mask " , PROPERTY_HINT_LAYERS_3D_PHYSICS ) , 1 ) ) ;
Improve collision generation usability in the new 3D scene import workflow.
With this PR it's possible to add a collision during the Mesh import, directly in editor.
To generate the shape is possible to chose between the following options:
- Decompose Convex: The Mesh is decomposed in one or many Convex Shapes (Using the VHACD library).
- Simple Convex: Is generated a convex shape that enclose the entire mesh.
- Trimesh: Generate a trimesh shape using the Mesh faces.
- Box: Add a primitive box shape, where you can tweak the `size`, `position`, `rotation`.
- Sphere: Add a primitive sphere shape, where you can tweak the `radius`, `position`, `rotation`.
- Cylinder: Add a primitive cylinder shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
- Capsule: Add a primitive capsule shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
It's also possible to chose the generated body, so you can create:
- Rigid Body
- Static Body
- Area
2021-08-22 18:19:13 +02:00
2023-06-28 18:09:23 +02:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : INT , " mesh_instance/layers " , PROPERTY_HINT_LAYERS_3D_RENDER ) , 1 ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : FLOAT , " mesh_instance/visibility_range_begin " , PROPERTY_HINT_RANGE , " 0.0,4096.0,0.01,or_greater,suffix:m " ) , 0.0f ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : FLOAT , " mesh_instance/visibility_range_begin_margin " , PROPERTY_HINT_RANGE , " 0.0,4096.0,0.01,or_greater,suffix:m " ) , 0.0f ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : FLOAT , " mesh_instance/visibility_range_end " , PROPERTY_HINT_RANGE , " 0.0,4096.0,0.01,or_greater,suffix:m " ) , 0.0f ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : FLOAT , " mesh_instance/visibility_range_end_margin " , PROPERTY_HINT_RANGE , " 0.0,4096.0,0.01,or_greater,suffix:m " ) , 0.0f ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : INT , " mesh_instance/visibility_range_fade_mode " , PROPERTY_HINT_ENUM , " Disabled,Self,Dependencies " ) , GeometryInstance3D : : VISIBILITY_RANGE_FADE_DISABLED ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : INT , " mesh_instance/cast_shadow " , PROPERTY_HINT_ENUM , " Off,On,Double-Sided,Shadows Only " ) , GeometryInstance3D : : SHADOW_CASTING_SETTING_ON ) ) ;
Improve collision generation usability in the new 3D scene import workflow.
With this PR it's possible to add a collision during the Mesh import, directly in editor.
To generate the shape is possible to chose between the following options:
- Decompose Convex: The Mesh is decomposed in one or many Convex Shapes (Using the VHACD library).
- Simple Convex: Is generated a convex shape that enclose the entire mesh.
- Trimesh: Generate a trimesh shape using the Mesh faces.
- Box: Add a primitive box shape, where you can tweak the `size`, `position`, `rotation`.
- Sphere: Add a primitive sphere shape, where you can tweak the `radius`, `position`, `rotation`.
- Cylinder: Add a primitive cylinder shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
- Capsule: Add a primitive capsule shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
It's also possible to chose the generated body, so you can create:
- Rigid Body
- Static Body
- Area
2021-08-22 18:19:13 +02:00
// Decomposition
2023-01-26 16:10:26 +01:00
Ref < MeshConvexDecompositionSettings > decomposition_default = Ref < MeshConvexDecompositionSettings > ( ) ;
decomposition_default . instantiate ( ) ;
Improve collision generation usability in the new 3D scene import workflow.
With this PR it's possible to add a collision during the Mesh import, directly in editor.
To generate the shape is possible to chose between the following options:
- Decompose Convex: The Mesh is decomposed in one or many Convex Shapes (Using the VHACD library).
- Simple Convex: Is generated a convex shape that enclose the entire mesh.
- Trimesh: Generate a trimesh shape using the Mesh faces.
- Box: Add a primitive box shape, where you can tweak the `size`, `position`, `rotation`.
- Sphere: Add a primitive sphere shape, where you can tweak the `radius`, `position`, `rotation`.
- Cylinder: Add a primitive cylinder shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
- Capsule: Add a primitive capsule shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
It's also possible to chose the generated body, so you can create:
- Rigid Body
- Static Body
- Area
2021-08-22 18:19:13 +02:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : BOOL , " decomposition/advanced " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED ) , false ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : INT , " decomposition/precision " , PROPERTY_HINT_RANGE , " 1,10,1 " ) , 5 ) ) ;
2023-01-26 16:10:26 +01:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : FLOAT , " decomposition/max_concavity " , PROPERTY_HINT_RANGE , " 0.0,1.0,0.001 " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED ) , decomposition_default - > get_max_concavity ( ) ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : FLOAT , " decomposition/symmetry_planes_clipping_bias " , PROPERTY_HINT_RANGE , " 0.0,1.0,0.001 " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED ) , decomposition_default - > get_symmetry_planes_clipping_bias ( ) ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : FLOAT , " decomposition/revolution_axes_clipping_bias " , PROPERTY_HINT_RANGE , " 0.0,1.0,0.001 " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED ) , decomposition_default - > get_revolution_axes_clipping_bias ( ) ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : FLOAT , " decomposition/min_volume_per_convex_hull " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED ) , decomposition_default - > get_min_volume_per_convex_hull ( ) ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : INT , " decomposition/resolution " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED ) , decomposition_default - > get_resolution ( ) ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : INT , " decomposition/max_num_vertices_per_convex_hull " , PROPERTY_HINT_RANGE , " 5,512,1 " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED ) , decomposition_default - > get_max_num_vertices_per_convex_hull ( ) ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : INT , " decomposition/plane_downsampling " , PROPERTY_HINT_RANGE , " 1,16,1 " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED ) , decomposition_default - > get_plane_downsampling ( ) ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : INT , " decomposition/convexhull_downsampling " , PROPERTY_HINT_RANGE , " 1,16,1 " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED ) , decomposition_default - > get_convex_hull_downsampling ( ) ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : BOOL , " decomposition/normalize_mesh " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED ) , decomposition_default - > get_normalize_mesh ( ) ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : INT , " decomposition/mode " , PROPERTY_HINT_ENUM , " Voxel,Tetrahedron " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED ) , static_cast < int > ( decomposition_default - > get_mode ( ) ) ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : BOOL , " decomposition/convexhull_approximation " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED ) , decomposition_default - > get_convex_hull_approximation ( ) ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : INT , " decomposition/max_convex_hulls " , PROPERTY_HINT_RANGE , " 1,100,1 " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED ) , decomposition_default - > get_max_convex_hulls ( ) ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : BOOL , " decomposition/project_hull_vertices " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED ) , decomposition_default - > get_project_hull_vertices ( ) ) ) ;
Improve collision generation usability in the new 3D scene import workflow.
With this PR it's possible to add a collision during the Mesh import, directly in editor.
To generate the shape is possible to chose between the following options:
- Decompose Convex: The Mesh is decomposed in one or many Convex Shapes (Using the VHACD library).
- Simple Convex: Is generated a convex shape that enclose the entire mesh.
- Trimesh: Generate a trimesh shape using the Mesh faces.
- Box: Add a primitive box shape, where you can tweak the `size`, `position`, `rotation`.
- Sphere: Add a primitive sphere shape, where you can tweak the `radius`, `position`, `rotation`.
- Cylinder: Add a primitive cylinder shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
- Capsule: Add a primitive capsule shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
It's also possible to chose the generated body, so you can create:
- Rigid Body
- Static Body
- Area
2021-08-22 18:19:13 +02:00
// Primitives: Box, Sphere, Cylinder, Capsule.
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : VECTOR3 , " primitive/size " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED ) , Vector3 ( 2.0 , 2.0 , 2.0 ) ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : FLOAT , " primitive/height " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED ) , 1.0 ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : FLOAT , " primitive/radius " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED ) , 1.0 ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : VECTOR3 , " primitive/position " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED ) , Vector3 ( ) ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : VECTOR3 , " primitive/rotation " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED ) , Vector3 ( ) ) ) ;
2022-02-04 16:28:18 +01:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : INT , " generate/occluder " , PROPERTY_HINT_ENUM , " Disabled,Mesh + Occluder,Occluder Only " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED ) , 0 ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : FLOAT , " occluder/simplification_distance " , PROPERTY_HINT_RANGE , " 0.0,2.0,0.01 " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED ) , 0.1f ) ) ;
2021-03-19 13:57:52 +01:00
} break ;
case INTERNAL_IMPORT_CATEGORY_MESH : {
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : BOOL , " save_to_file/enabled " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED ) , false ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : STRING , " save_to_file/path " , PROPERTY_HINT_SAVE_FILE , " *.res,*.tres " ) , " " ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : INT , " generate/shadow_meshes " , PROPERTY_HINT_ENUM , " Default,Enable,Disable " ) , 0 ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : INT , " generate/lightmap_uv " , PROPERTY_HINT_ENUM , " Default,Enable,Disable " ) , 0 ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : INT , " generate/lods " , PROPERTY_HINT_ENUM , " Default,Enable,Disable " ) , 0 ) ) ;
2021-09-07 17:44:50 +02:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : FLOAT , " lods/normal_split_angle " , PROPERTY_HINT_RANGE , " 0,180,0.1,degrees " ) , 25.0f ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : FLOAT , " lods/normal_merge_angle " , PROPERTY_HINT_RANGE , " 0,180,0.1,degrees " ) , 60.0f ) ) ;
2024-06-29 03:32:59 +02:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : BOOL , " lods/raycast_normals " , PROPERTY_HINT_NONE , " " ) , false ) ) ;
2021-03-19 13:57:52 +01:00
} break ;
case INTERNAL_IMPORT_CATEGORY_MATERIAL : {
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : BOOL , " use_external/enabled " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED ) , false ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : STRING , " use_external/path " , PROPERTY_HINT_FILE , " *.material,*.res,*.tres " ) , " " ) ) ;
} break ;
case INTERNAL_IMPORT_CATEGORY_ANIMATION : {
2021-11-19 15:56:14 +01:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : INT , " settings/loop_mode " , PROPERTY_HINT_ENUM , " None,Linear,Pingpong " ) , 0 ) ) ;
2021-03-19 13:57:52 +01:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : BOOL , " save_to_file/enabled " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED ) , false ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : STRING , " save_to_file/path " , PROPERTY_HINT_SAVE_FILE , " *.res,*.tres " ) , " " ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : BOOL , " save_to_file/keep_custom_tracks " ) , " " ) ) ;
2022-10-10 22:59:57 +02:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : INT , " slices/amount " , PROPERTY_HINT_RANGE , " 0,256,1 " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED ) , 0 ) ) ;
for ( int i = 0 ; i < 256 ; i + + ) {
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : STRING , " slice_ " + itos ( i + 1 ) + " /name " ) , " " ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : INT , " slice_ " + itos ( i + 1 ) + " /start_frame " ) , 0 ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : INT , " slice_ " + itos ( i + 1 ) + " /end_frame " ) , 0 ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : INT , " slice_ " + itos ( i + 1 ) + " /loop_mode " , PROPERTY_HINT_ENUM , " None,Linear,Pingpong " ) , 0 ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : BOOL , " slice_ " + itos ( i + 1 ) + " /save_to_file/enabled " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED ) , false ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : STRING , " slice_ " + itos ( i + 1 ) + " /save_to_file/path " , PROPERTY_HINT_SAVE_FILE , " .res,*.tres " ) , " " ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : BOOL , " slice_ " + itos ( i + 1 ) + " /save_to_file/keep_custom_tracks " ) , false ) ) ;
}
2021-03-19 13:57:52 +01:00
} break ;
case INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE : {
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : BOOL , " import/skip_import " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED ) , false ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : BOOL , " optimizer/enabled " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED ) , true ) ) ;
2022-08-07 03:55:37 +02:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : FLOAT , " optimizer/max_velocity_error " , PROPERTY_HINT_RANGE , " 0,1,0.01 " ) , 0.01 ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : FLOAT , " optimizer/max_angular_error " , PROPERTY_HINT_RANGE , " 0,1,0.01 " ) , 0.01 ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : INT , " optimizer/max_precision_error " , PROPERTY_HINT_NONE , " 1,6,1 " ) , 3 ) ) ;
2021-10-21 01:42:22 +02:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : BOOL , " compression/enabled " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED ) , false ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : INT , " compression/page_size " , PROPERTY_HINT_RANGE , " 4,512,1,suffix:kb " ) , 8 ) ) ;
2021-10-13 23:40:55 +02:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : INT , " import_tracks/position " , PROPERTY_HINT_ENUM , " IfPresent,IfPresentForAll,Never " ) , 1 ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : INT , " import_tracks/rotation " , PROPERTY_HINT_ENUM , " IfPresent,IfPresentForAll,Never " ) , 1 ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : INT , " import_tracks/scale " , PROPERTY_HINT_ENUM , " IfPresent,IfPresentForAll,Never " ) , 1 ) ) ;
2021-03-19 13:57:52 +01:00
} break ;
2022-06-27 10:06:50 +02:00
case INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE : {
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : BOOL , " import/skip_import " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED ) , false ) ) ;
2024-02-25 17:06:37 +01:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : INT , " rest_pose/load_pose " , PROPERTY_HINT_ENUM , " Default Pose,Use AnimationPlayer,Load External Animation " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED ) , 0 ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : OBJECT , " rest_pose/external_animation_library " , PROPERTY_HINT_RESOURCE_TYPE , " Animation,AnimationLibrary " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED ) , Variant ( ) ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : STRING , " rest_pose/selected_animation " , PROPERTY_HINT_ENUM , " " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED ) , " " ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : FLOAT , " rest_pose/selected_timestamp " , PROPERTY_HINT_RANGE , " 0,1,0.001,or_greater,suffix:s " , PROPERTY_USAGE_DEFAULT ) , 0.0f ) ) ;
String mismatched_or_empty_profile_warning = String (
" The external rest animation is missing some bones. "
" Consider disabling Remove Immutable Tracks on the other file. " ) ; // TODO: translate.
r_options - > push_back ( ImportOption (
PropertyInfo (
Variant : : STRING , U " rest_pose/ \u26A0 _validation_warning/mismatched_or_empty_profile " ,
PROPERTY_HINT_MULTILINE_TEXT , " " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_READ_ONLY ) ,
Variant ( mismatched_or_empty_profile_warning ) ) ) ;
String profile_must_not_be_retargeted_warning = String (
" This external rest animation appears to have been imported with a BoneMap. "
" Disable the bone map when exporting a rest animation from the reference model. " ) ; // TODO: translate.
r_options - > push_back ( ImportOption (
PropertyInfo (
Variant : : STRING , U " rest_pose/ \u26A0 _validation_warning/profile_must_not_be_retargeted " ,
PROPERTY_HINT_MULTILINE_TEXT , " " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_READ_ONLY ) ,
Variant ( profile_must_not_be_retargeted_warning ) ) ) ;
String no_animation_warning = String (
" Select an animation: Find a FBX or glTF in a compatible rest pose "
" and export a compatible animation from its import settings. " ) ; // TODO: translate.
r_options - > push_back ( ImportOption (
PropertyInfo (
Variant : : STRING , U " rest_pose//no_animation_chosen " ,
PROPERTY_HINT_MULTILINE_TEXT , " " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_READ_ONLY ) ,
Variant ( no_animation_warning ) ) ) ;
2022-06-27 10:06:50 +02:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : OBJECT , " retarget/bone_map " , PROPERTY_HINT_RESOURCE_TYPE , " BoneMap " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED ) , Variant ( ) ) ) ;
} break ;
2021-03-19 13:57:52 +01:00
default : {
2017-12-09 18:11:26 +01:00
}
}
2021-10-14 19:34:27 +02:00
for ( int i = 0 ; i < post_importer_plugins . size ( ) ; i + + ) {
post_importer_plugins . write [ i ] - > get_internal_import_options ( EditorScenePostImportPlugin : : InternalImportCategory ( p_category ) , r_options ) ;
}
2017-12-09 18:11:26 +01:00
}
2022-05-13 15:04:37 +02:00
bool ResourceImporterScene : : get_internal_option_visibility ( InternalImportCategory p_category , const String & p_option , const HashMap < StringName , Variant > & p_options ) const {
2021-03-19 13:57:52 +01:00
if ( p_options . has ( " import/skip_import " ) & & p_option ! = " import/skip_import " & & bool ( p_options [ " import/skip_import " ] ) ) {
return false ; //if skip import
}
switch ( p_category ) {
case INTERNAL_IMPORT_CATEGORY_NODE : {
} break ;
case INTERNAL_IMPORT_CATEGORY_MESH_3D_NODE : {
Improve collision generation usability in the new 3D scene import workflow.
With this PR it's possible to add a collision during the Mesh import, directly in editor.
To generate the shape is possible to chose between the following options:
- Decompose Convex: The Mesh is decomposed in one or many Convex Shapes (Using the VHACD library).
- Simple Convex: Is generated a convex shape that enclose the entire mesh.
- Trimesh: Generate a trimesh shape using the Mesh faces.
- Box: Add a primitive box shape, where you can tweak the `size`, `position`, `rotation`.
- Sphere: Add a primitive sphere shape, where you can tweak the `radius`, `position`, `rotation`.
- Cylinder: Add a primitive cylinder shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
- Capsule: Add a primitive capsule shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
It's also possible to chose the generated body, so you can create:
- Rigid Body
- Static Body
- Area
2021-08-22 18:19:13 +02:00
const bool generate_physics =
p_options . has ( " generate/physics " ) & &
p_options [ " generate/physics " ] . operator bool ( ) ;
2024-05-06 16:20:20 +02:00
if ( p_option . contains ( " physics/ " ) ) {
Improve collision generation usability in the new 3D scene import workflow.
With this PR it's possible to add a collision during the Mesh import, directly in editor.
To generate the shape is possible to chose between the following options:
- Decompose Convex: The Mesh is decomposed in one or many Convex Shapes (Using the VHACD library).
- Simple Convex: Is generated a convex shape that enclose the entire mesh.
- Trimesh: Generate a trimesh shape using the Mesh faces.
- Box: Add a primitive box shape, where you can tweak the `size`, `position`, `rotation`.
- Sphere: Add a primitive sphere shape, where you can tweak the `radius`, `position`, `rotation`.
- Cylinder: Add a primitive cylinder shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
- Capsule: Add a primitive capsule shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
It's also possible to chose the generated body, so you can create:
- Rigid Body
- Static Body
- Area
2021-08-22 18:19:13 +02:00
// Show if need to generate collisions.
return generate_physics ;
}
2024-05-06 16:20:20 +02:00
if ( p_option . contains ( " decomposition/ " ) ) {
Improve collision generation usability in the new 3D scene import workflow.
With this PR it's possible to add a collision during the Mesh import, directly in editor.
To generate the shape is possible to chose between the following options:
- Decompose Convex: The Mesh is decomposed in one or many Convex Shapes (Using the VHACD library).
- Simple Convex: Is generated a convex shape that enclose the entire mesh.
- Trimesh: Generate a trimesh shape using the Mesh faces.
- Box: Add a primitive box shape, where you can tweak the `size`, `position`, `rotation`.
- Sphere: Add a primitive sphere shape, where you can tweak the `radius`, `position`, `rotation`.
- Cylinder: Add a primitive cylinder shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
- Capsule: Add a primitive capsule shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
It's also possible to chose the generated body, so you can create:
- Rigid Body
- Static Body
- Area
2021-08-22 18:19:13 +02:00
// Show if need to generate collisions.
if ( generate_physics & &
// Show if convex is enabled.
p_options [ " physics/shape_type " ] = = Variant ( SHAPE_TYPE_DECOMPOSE_CONVEX ) ) {
if ( p_option = = " decomposition/advanced " ) {
return true ;
}
const bool decomposition_advanced =
p_options . has ( " decomposition/advanced " ) & &
p_options [ " decomposition/advanced " ] . operator bool ( ) ;
if ( p_option = = " decomposition/precision " ) {
return ! decomposition_advanced ;
} else {
return decomposition_advanced ;
}
}
return false ;
}
if ( p_option = = " primitive/position " | | p_option = = " primitive/rotation " ) {
const ShapeType physics_shape = ( ShapeType ) p_options [ " physics/shape_type " ] . operator int ( ) ;
return generate_physics & &
2021-10-28 15:19:35 +02:00
physics_shape > = SHAPE_TYPE_BOX ;
Improve collision generation usability in the new 3D scene import workflow.
With this PR it's possible to add a collision during the Mesh import, directly in editor.
To generate the shape is possible to chose between the following options:
- Decompose Convex: The Mesh is decomposed in one or many Convex Shapes (Using the VHACD library).
- Simple Convex: Is generated a convex shape that enclose the entire mesh.
- Trimesh: Generate a trimesh shape using the Mesh faces.
- Box: Add a primitive box shape, where you can tweak the `size`, `position`, `rotation`.
- Sphere: Add a primitive sphere shape, where you can tweak the `radius`, `position`, `rotation`.
- Cylinder: Add a primitive cylinder shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
- Capsule: Add a primitive capsule shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
It's also possible to chose the generated body, so you can create:
- Rigid Body
- Static Body
- Area
2021-08-22 18:19:13 +02:00
}
if ( p_option = = " primitive/size " ) {
const ShapeType physics_shape = ( ShapeType ) p_options [ " physics/shape_type " ] . operator int ( ) ;
return generate_physics & &
2021-10-28 15:19:35 +02:00
physics_shape = = SHAPE_TYPE_BOX ;
Improve collision generation usability in the new 3D scene import workflow.
With this PR it's possible to add a collision during the Mesh import, directly in editor.
To generate the shape is possible to chose between the following options:
- Decompose Convex: The Mesh is decomposed in one or many Convex Shapes (Using the VHACD library).
- Simple Convex: Is generated a convex shape that enclose the entire mesh.
- Trimesh: Generate a trimesh shape using the Mesh faces.
- Box: Add a primitive box shape, where you can tweak the `size`, `position`, `rotation`.
- Sphere: Add a primitive sphere shape, where you can tweak the `radius`, `position`, `rotation`.
- Cylinder: Add a primitive cylinder shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
- Capsule: Add a primitive capsule shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
It's also possible to chose the generated body, so you can create:
- Rigid Body
- Static Body
- Area
2021-08-22 18:19:13 +02:00
}
if ( p_option = = " primitive/radius " ) {
const ShapeType physics_shape = ( ShapeType ) p_options [ " physics/shape_type " ] . operator int ( ) ;
2021-10-28 15:19:35 +02:00
return generate_physics & &
( physics_shape = = SHAPE_TYPE_SPHERE | |
physics_shape = = SHAPE_TYPE_CYLINDER | |
physics_shape = = SHAPE_TYPE_CAPSULE ) ;
Improve collision generation usability in the new 3D scene import workflow.
With this PR it's possible to add a collision during the Mesh import, directly in editor.
To generate the shape is possible to chose between the following options:
- Decompose Convex: The Mesh is decomposed in one or many Convex Shapes (Using the VHACD library).
- Simple Convex: Is generated a convex shape that enclose the entire mesh.
- Trimesh: Generate a trimesh shape using the Mesh faces.
- Box: Add a primitive box shape, where you can tweak the `size`, `position`, `rotation`.
- Sphere: Add a primitive sphere shape, where you can tweak the `radius`, `position`, `rotation`.
- Cylinder: Add a primitive cylinder shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
- Capsule: Add a primitive capsule shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
It's also possible to chose the generated body, so you can create:
- Rigid Body
- Static Body
- Area
2021-08-22 18:19:13 +02:00
}
if ( p_option = = " primitive/height " ) {
const ShapeType physics_shape = ( ShapeType ) p_options [ " physics/shape_type " ] . operator int ( ) ;
return generate_physics & &
2021-10-28 15:19:35 +02:00
( physics_shape = = SHAPE_TYPE_CYLINDER | |
physics_shape = = SHAPE_TYPE_CAPSULE ) ;
Improve collision generation usability in the new 3D scene import workflow.
With this PR it's possible to add a collision during the Mesh import, directly in editor.
To generate the shape is possible to chose between the following options:
- Decompose Convex: The Mesh is decomposed in one or many Convex Shapes (Using the VHACD library).
- Simple Convex: Is generated a convex shape that enclose the entire mesh.
- Trimesh: Generate a trimesh shape using the Mesh faces.
- Box: Add a primitive box shape, where you can tweak the `size`, `position`, `rotation`.
- Sphere: Add a primitive sphere shape, where you can tweak the `radius`, `position`, `rotation`.
- Cylinder: Add a primitive cylinder shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
- Capsule: Add a primitive capsule shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
It's also possible to chose the generated body, so you can create:
- Rigid Body
- Static Body
- Area
2021-08-22 18:19:13 +02:00
}
2022-02-04 16:28:18 +01:00
if ( p_option = = " occluder/simplification_distance " ) {
// Show only if occluder generation is enabled
return p_options . has ( " generate/occluder " ) & & p_options [ " generate/occluder " ] . operator signed int ( ) ! = OCCLUDER_DISABLED ;
}
2021-03-19 13:57:52 +01:00
} break ;
case INTERNAL_IMPORT_CATEGORY_MESH : {
2024-04-16 00:07:11 +02:00
if ( p_option = = " save_to_file/path " ) {
2021-03-19 13:57:52 +01:00
return p_options [ " save_to_file/enabled " ] ;
}
} break ;
case INTERNAL_IMPORT_CATEGORY_MATERIAL : {
if ( p_option = = " use_external/path " ) {
return p_options [ " use_external/enabled " ] ;
}
} break ;
case INTERNAL_IMPORT_CATEGORY_ANIMATION : {
if ( p_option = = " save_to_file/path " | | p_option = = " save_to_file/keep_custom_tracks " ) {
return p_options [ " save_to_file/enabled " ] ;
}
2022-10-10 22:59:57 +02:00
if ( p_option . begins_with ( " slice_ " ) ) {
int max_slice = p_options [ " slices/amount " ] ;
int slice = p_option . get_slice ( " _ " , 1 ) . to_int ( ) - 1 ;
if ( slice > = max_slice ) {
return false ;
}
}
2021-03-19 13:57:52 +01:00
} break ;
case INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE : {
2021-10-21 01:42:22 +02:00
if ( p_option . begins_with ( " optimizer/ " ) & & p_option ! = " optimizer/enabled " & & ! bool ( p_options [ " optimizer/enabled " ] ) ) {
return false ;
}
if ( p_option . begins_with ( " compression/ " ) & & p_option ! = " compression/enabled " & & ! bool ( p_options [ " compression/enabled " ] ) ) {
2021-03-19 13:57:52 +01:00
return false ;
2017-09-08 13:06:09 +02:00
}
2021-03-19 13:57:52 +01:00
} break ;
2022-06-27 10:06:50 +02:00
case INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE : {
2024-02-25 17:06:37 +01:00
const bool use_retarget = Object : : cast_to < BoneMap > ( p_options [ " retarget/bone_map " ] . get_validated_object ( ) ) ! = nullptr ;
if ( ! use_retarget & & p_option ! = " retarget/bone_map " & & p_option . begins_with ( " retarget/ " ) ) {
return false ;
}
int rest_warning = 0 ;
if ( p_option . begins_with ( " rest_pose/ " ) ) {
if ( ! p_options . has ( " rest_pose/load_pose " ) | | int ( p_options [ " rest_pose/load_pose " ] ) = = 0 ) {
if ( p_option ! = " rest_pose/load_pose " ) {
return false ;
}
} else if ( int ( p_options [ " rest_pose/load_pose " ] ) = = 1 ) {
if ( p_option = = " rest_pose/external_animation_library " ) {
return false ;
}
} else if ( int ( p_options [ " rest_pose/load_pose " ] ) = = 2 ) {
Object * res = p_options [ " rest_pose/external_animation_library " ] ;
Ref < Animation > anim ( res ) ;
if ( anim . is_valid ( ) & & p_option = = " rest_pose/selected_animation " ) {
return false ;
}
Ref < AnimationLibrary > library ( res ) ;
String selected_animation_name = p_options [ " rest_pose/selected_animation " ] ;
if ( library . is_valid ( ) ) {
List < StringName > anim_list ;
library - > get_animation_list ( & anim_list ) ;
if ( anim_list . size ( ) = = 1 ) {
2024-04-15 15:18:34 +02:00
selected_animation_name = String ( anim_list . front ( ) - > get ( ) ) ;
2024-02-25 17:06:37 +01:00
}
if ( library - > has_animation ( selected_animation_name ) ) {
anim = library - > get_animation ( selected_animation_name ) ;
}
}
int found_bone_count = 0 ;
Ref < BoneMap > bone_map ;
Ref < SkeletonProfile > prof ;
if ( p_options . has ( " retarget/bone_map " ) ) {
bone_map = p_options [ " retarget/bone_map " ] ;
}
if ( bone_map . is_valid ( ) ) {
prof = bone_map - > get_profile ( ) ;
}
if ( anim . is_valid ( ) ) {
HashSet < StringName > target_bones ;
if ( bone_map . is_valid ( ) & & prof . is_valid ( ) ) {
for ( int target_i = 0 ; target_i < prof - > get_bone_size ( ) ; target_i + + ) {
StringName skeleton_bone_name = bone_map - > get_skeleton_bone_name ( prof - > get_bone_name ( target_i ) ) ;
if ( skeleton_bone_name ) {
target_bones . insert ( skeleton_bone_name ) ;
}
}
}
for ( int track_i = 0 ; track_i < anim - > get_track_count ( ) ; track_i + + ) {
if ( anim - > track_get_type ( track_i ) ! = Animation : : TYPE_POSITION_3D & & anim - > track_get_type ( track_i ) ! = Animation : : TYPE_ROTATION_3D ) {
continue ;
}
NodePath path = anim - > track_get_path ( track_i ) ;
StringName node_path = path . get_concatenated_names ( ) ;
StringName skeleton_bone = path . get_concatenated_subnames ( ) ;
if ( skeleton_bone ) {
if ( String ( node_path ) . begins_with ( " % " ) ) {
rest_warning = 1 ;
}
if ( target_bones . has ( skeleton_bone ) ) {
target_bones . erase ( skeleton_bone ) ;
}
found_bone_count + + ;
}
}
if ( ( found_bone_count < 15 | | ! target_bones . is_empty ( ) ) & & rest_warning ! = 1 ) {
rest_warning = 2 ; // heuristic: animation targeted too few bones.
}
} else {
rest_warning = 3 ;
}
}
if ( p_option . begins_with ( " rest_pose/ " ) & & p_option . ends_with ( " profile_must_not_be_retargeted " ) ) {
return rest_warning = = 1 ;
}
if ( p_option . begins_with ( " rest_pose/ " ) & & p_option . ends_with ( " mismatched_or_empty_profile " ) ) {
return rest_warning = = 2 ;
}
if ( p_option . begins_with ( " rest_pose/ " ) & & p_option . ends_with ( " no_animation_chosen " ) ) {
return rest_warning = = 3 ;
}
2022-06-27 10:06:50 +02:00
}
} break ;
2021-03-19 13:57:52 +01:00
default : {
2017-02-05 00:31:15 +01:00
}
}
2021-10-14 19:34:27 +02:00
for ( int i = 0 ; i < post_importer_plugins . size ( ) ; i + + ) {
2022-04-12 16:07:09 +02:00
Variant ret = post_importer_plugins . write [ i ] - > get_internal_option_visibility ( EditorScenePostImportPlugin : : InternalImportCategory ( p_category ) , animation_importer , p_option , p_options ) ;
2021-10-14 19:34:27 +02:00
if ( ret . get_type ( ) = = Variant : : BOOL ) {
return ret ;
}
}
2021-03-19 13:57:52 +01:00
return true ;
2017-02-05 00:31:15 +01:00
}
2022-05-13 15:04:37 +02:00
bool ResourceImporterScene : : get_internal_option_update_view_required ( InternalImportCategory p_category , const String & p_option , const HashMap < StringName , Variant > & p_options ) const {
Improve collision generation usability in the new 3D scene import workflow.
With this PR it's possible to add a collision during the Mesh import, directly in editor.
To generate the shape is possible to chose between the following options:
- Decompose Convex: The Mesh is decomposed in one or many Convex Shapes (Using the VHACD library).
- Simple Convex: Is generated a convex shape that enclose the entire mesh.
- Trimesh: Generate a trimesh shape using the Mesh faces.
- Box: Add a primitive box shape, where you can tweak the `size`, `position`, `rotation`.
- Sphere: Add a primitive sphere shape, where you can tweak the `radius`, `position`, `rotation`.
- Cylinder: Add a primitive cylinder shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
- Capsule: Add a primitive capsule shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
It's also possible to chose the generated body, so you can create:
- Rigid Body
- Static Body
- Area
2021-08-22 18:19:13 +02:00
switch ( p_category ) {
case INTERNAL_IMPORT_CATEGORY_NODE : {
} break ;
case INTERNAL_IMPORT_CATEGORY_MESH_3D_NODE : {
if (
p_option = = " generate/physics " | |
p_option = = " physics/shape_type " | |
2024-05-06 16:20:20 +02:00
p_option . contains ( " decomposition/ " ) | |
p_option . contains ( " primitive/ " ) ) {
Improve collision generation usability in the new 3D scene import workflow.
With this PR it's possible to add a collision during the Mesh import, directly in editor.
To generate the shape is possible to chose between the following options:
- Decompose Convex: The Mesh is decomposed in one or many Convex Shapes (Using the VHACD library).
- Simple Convex: Is generated a convex shape that enclose the entire mesh.
- Trimesh: Generate a trimesh shape using the Mesh faces.
- Box: Add a primitive box shape, where you can tweak the `size`, `position`, `rotation`.
- Sphere: Add a primitive sphere shape, where you can tweak the `radius`, `position`, `rotation`.
- Cylinder: Add a primitive cylinder shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
- Capsule: Add a primitive capsule shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
It's also possible to chose the generated body, so you can create:
- Rigid Body
- Static Body
- Area
2021-08-22 18:19:13 +02:00
return true ;
}
} break ;
case INTERNAL_IMPORT_CATEGORY_MESH : {
} break ;
case INTERNAL_IMPORT_CATEGORY_MATERIAL : {
} break ;
case INTERNAL_IMPORT_CATEGORY_ANIMATION : {
} break ;
case INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE : {
} break ;
2022-06-27 10:06:50 +02:00
case INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE : {
} break ;
Improve collision generation usability in the new 3D scene import workflow.
With this PR it's possible to add a collision during the Mesh import, directly in editor.
To generate the shape is possible to chose between the following options:
- Decompose Convex: The Mesh is decomposed in one or many Convex Shapes (Using the VHACD library).
- Simple Convex: Is generated a convex shape that enclose the entire mesh.
- Trimesh: Generate a trimesh shape using the Mesh faces.
- Box: Add a primitive box shape, where you can tweak the `size`, `position`, `rotation`.
- Sphere: Add a primitive sphere shape, where you can tweak the `radius`, `position`, `rotation`.
- Cylinder: Add a primitive cylinder shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
- Capsule: Add a primitive capsule shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
It's also possible to chose the generated body, so you can create:
- Rigid Body
- Static Body
- Area
2021-08-22 18:19:13 +02:00
default : {
}
}
2021-10-14 19:34:27 +02:00
for ( int i = 0 ; i < post_importer_plugins . size ( ) ; i + + ) {
Variant ret = post_importer_plugins . write [ i ] - > get_internal_option_update_view_required ( EditorScenePostImportPlugin : : InternalImportCategory ( p_category ) , p_option , p_options ) ;
if ( ret . get_type ( ) = = Variant : : BOOL ) {
return ret ;
}
}
Improve collision generation usability in the new 3D scene import workflow.
With this PR it's possible to add a collision during the Mesh import, directly in editor.
To generate the shape is possible to chose between the following options:
- Decompose Convex: The Mesh is decomposed in one or many Convex Shapes (Using the VHACD library).
- Simple Convex: Is generated a convex shape that enclose the entire mesh.
- Trimesh: Generate a trimesh shape using the Mesh faces.
- Box: Add a primitive box shape, where you can tweak the `size`, `position`, `rotation`.
- Sphere: Add a primitive sphere shape, where you can tweak the `radius`, `position`, `rotation`.
- Cylinder: Add a primitive cylinder shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
- Capsule: Add a primitive capsule shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
It's also possible to chose the generated body, so you can create:
- Rigid Body
- Static Body
- Area
2021-08-22 18:19:13 +02:00
return false ;
}
2021-11-14 18:02:38 +01:00
void ResourceImporterScene : : get_import_options ( const String & p_path , List < ImportOption > * r_options , int p_preset ) const {
2023-07-22 02:07:00 +02:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : STRING , " nodes/root_type " , PROPERTY_HINT_TYPE_STRING , " Node " ) , " " ) ) ;
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : STRING , " nodes/root_name " ) , " " ) ) ;
2017-02-04 13:48:04 +01:00
List < String > script_extentions ;
ResourceLoader : : get_recognized_extensions_for_type ( " Script " , & script_extentions ) ;
String script_ext_hint ;
2021-07-24 15:46:25 +02:00
for ( const String & E : script_extentions ) {
2021-12-09 10:42:46 +01:00
if ( ! script_ext_hint . is_empty ( ) ) {
2017-02-04 13:48:04 +01:00
script_ext_hint + = " , " ;
2020-05-14 16:41:43 +02:00
}
2021-07-16 05:45:57 +02:00
script_ext_hint + = " *. " + E ;
2017-02-04 13:48:04 +01:00
}
2024-05-20 11:56:57 +02:00
bool trimming_defaults_on = p_path . get_extension ( ) . to_lower ( ) = = " fbx " ;
2017-02-04 13:48:04 +01:00
2022-02-04 08:34:59 +01:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : BOOL , " nodes/apply_root_scale " ) , true ) ) ;
Variant: Added 64-bit packed arrays, renamed Variant::REAL to FLOAT.
- Renames PackedIntArray to PackedInt32Array.
- Renames PackedFloatArray to PackedFloat32Array.
- Adds PackedInt64Array and PackedFloat64Array.
- Renames Variant::REAL to Variant::FLOAT for consistency.
Packed arrays are for storing large amount of data and creating stuff like
meshes, buffers. textures, etc. Forcing them to be 64 is a huge waste of
memory. That said, many users requested the ability to have 64 bits packed
arrays for their games, so this is just an optional added type.
For Variant, the float datatype is always 64 bits, and exposed as `float`.
We still have `real_t` which is the datatype that can change from 32 to 64
bits depending on a compile flag (not entirely working right now, but that's
the idea). It affects math related datatypes and code only.
Neither Variant nor PackedArray make use of real_t, which is only intended
for math precision, so the term is removed from there to keep only float.
2020-02-24 19:20:53 +01:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : FLOAT , " nodes/root_scale " , PROPERTY_HINT_RANGE , " 0.001,1000,0.001 " ) , 1.0 ) ) ;
2024-02-25 09:36:39 +01:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : BOOL , " nodes/import_as_skeleton_bones " ) , false ) ) ;
2017-08-18 13:25:04 +02:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : BOOL , " meshes/ensure_tangents " ) , true ) ) ;
2020-12-17 19:56:59 +01:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : BOOL , " meshes/generate_lods " ) , true ) ) ;
2021-01-25 16:20:11 +01:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : BOOL , " meshes/create_shadow_meshes " ) , true ) ) ;
2023-11-22 15:16:53 +01:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : INT , " meshes/light_baking " , PROPERTY_HINT_ENUM , " Disabled,Static,Static Lightmaps,Dynamic " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED ) , 1 ) ) ;
2022-02-14 00:14:01 +01:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : FLOAT , " meshes/lightmap_texel_size " , PROPERTY_HINT_RANGE , " 0.001,100,0.001 " ) , 0.2 ) ) ;
2023-08-29 21:04:32 +02:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : BOOL , " meshes/force_disable_compression " ) , false ) ) ;
2020-02-21 11:27:48 +01:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : BOOL , " skins/use_named_skins " ) , true ) ) ;
2021-03-19 13:57:52 +01:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : BOOL , " animation/import " ) , true ) ) ;
2021-07-10 02:32:53 +02:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : FLOAT , " animation/fps " , PROPERTY_HINT_RANGE , " 1,120,1 " ) , 30 ) ) ;
2024-05-20 11:56:57 +02:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : BOOL , " animation/trimming " ) , trimming_defaults_on ) ) ;
2023-01-30 00:49:55 +01:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : BOOL , " animation/remove_immutable_tracks " ) , true ) ) ;
2024-03-18 04:29:29 +01:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : BOOL , " animation/import_rest_as_RESET " ) , false ) ) ;
2021-03-19 13:57:52 +01:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : STRING , " import_script/path " , PROPERTY_HINT_FILE , script_ext_hint ) , " " ) ) ;
2021-11-03 23:06:17 +01:00
r_options - > push_back ( ImportOption ( PropertyInfo ( Variant : : DICTIONARY , " _subresources " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NO_EDITOR ) , Dictionary ( ) ) ) ;
2021-10-14 19:34:27 +02:00
for ( int i = 0 ; i < post_importer_plugins . size ( ) ; i + + ) {
2021-11-14 18:02:38 +01:00
post_importer_plugins . write [ i ] - > get_import_options ( p_path , r_options ) ;
}
2023-10-08 07:48:53 +02:00
for ( Ref < EditorSceneFormatImporter > importer_elem : scene_importers ) {
2022-01-19 12:03:47 +01:00
importer_elem - > get_import_options ( p_path , r_options ) ;
2021-10-14 19:34:27 +02:00
}
2017-02-04 13:48:04 +01:00
}
2017-02-05 00:31:15 +01:00
2023-10-31 23:55:15 +01:00
void ResourceImporterScene : : handle_compatibility_options ( HashMap < StringName , Variant > & p_import_params ) const {
2023-10-08 07:48:53 +02:00
for ( Ref < EditorSceneFormatImporter > importer_elem : scene_importers ) {
2023-10-31 23:55:15 +01:00
importer_elem - > handle_compatibility_options ( p_import_params ) ;
}
}
2017-07-23 23:48:05 +02:00
void ResourceImporterScene : : _replace_owner ( Node * p_node , Node * p_scene , Node * p_new_owner ) {
if ( p_node ! = p_new_owner & & p_node - > get_owner ( ) = = p_scene ) {
p_node - > set_owner ( p_new_owner ) ;
}
for ( int i = 0 ; i < p_node - > get_child_count ( ) ; i + + ) {
Node * n = p_node - > get_child ( i ) ;
_replace_owner ( n , p_scene , p_new_owner ) ;
}
2017-12-07 19:44:20 +01:00
}
2022-09-07 21:13:10 +02:00
Array ResourceImporterScene : : _get_skinned_pose_transforms ( ImporterMeshInstance3D * p_src_mesh_node ) {
Array skin_pose_transform_array ;
const Ref < Skin > skin = p_src_mesh_node - > get_skin ( ) ;
if ( skin . is_valid ( ) ) {
NodePath skeleton_path = p_src_mesh_node - > get_skeleton_path ( ) ;
const Node * node = p_src_mesh_node - > get_node_or_null ( skeleton_path ) ;
const Skeleton3D * skeleton = Object : : cast_to < Skeleton3D > ( node ) ;
if ( skeleton ) {
int bind_count = skin - > get_bind_count ( ) ;
for ( int i = 0 ; i < bind_count ; i + + ) {
Transform3D bind_pose = skin - > get_bind_pose ( i ) ;
String bind_name = skin - > get_bind_name ( i ) ;
int bone_idx = bind_name . is_empty ( ) ? skin - > get_bind_bone ( i ) : skeleton - > find_bone ( bind_name ) ;
ERR_FAIL_COND_V ( bone_idx > = skeleton - > get_bone_count ( ) , Array ( ) ) ;
Transform3D bp_global_rest ;
if ( bone_idx > = 0 ) {
bp_global_rest = skeleton - > get_bone_global_pose ( bone_idx ) ;
} else {
bp_global_rest = skeleton - > get_bone_global_pose ( i ) ;
}
skin_pose_transform_array . push_back ( bp_global_rest * bind_pose ) ;
}
}
}
return skin_pose_transform_array ;
}
2023-11-14 02:21:25 +01:00
Node * ResourceImporterScene : : _generate_meshes ( Node * p_node , const Dictionary & p_mesh_data , bool p_generate_lods , bool p_create_shadow_meshes , LightBakeMode p_light_bake_mode , float p_lightmap_texel_size , const Vector < uint8_t > & p_src_lightmap_cache , Vector < Vector < uint8_t > > & r_lightmap_caches ) {
2021-09-21 03:24:31 +02:00
ImporterMeshInstance3D * src_mesh_node = Object : : cast_to < ImporterMeshInstance3D > ( p_node ) ;
2020-12-21 16:39:32 +01:00
if ( src_mesh_node ) {
2020-12-12 13:06:59 +01:00
//is mesh
MeshInstance3D * mesh_node = memnew ( MeshInstance3D ) ;
2020-12-21 16:39:32 +01:00
mesh_node - > set_name ( src_mesh_node - > get_name ( ) ) ;
mesh_node - > set_transform ( src_mesh_node - > get_transform ( ) ) ;
mesh_node - > set_skin ( src_mesh_node - > get_skin ( ) ) ;
mesh_node - > set_skeleton_path ( src_mesh_node - > get_skeleton_path ( ) ) ;
if ( src_mesh_node - > get_mesh ( ) . is_valid ( ) ) {
Ref < ArrayMesh > mesh ;
if ( ! src_mesh_node - > get_mesh ( ) - > has_mesh ( ) ) {
//do mesh processing
2021-03-19 13:57:52 +01:00
bool generate_lods = p_generate_lods ;
2021-09-07 17:44:50 +02:00
float split_angle = 25.0f ;
float merge_angle = 60.0f ;
2024-06-29 03:32:59 +02:00
bool raycast_normals = false ;
2021-03-19 13:57:52 +01:00
bool create_shadow_meshes = p_create_shadow_meshes ;
bool bake_lightmaps = p_light_bake_mode = = LIGHT_BAKE_STATIC_LIGHTMAPS ;
String save_to_file ;
2022-04-01 20:30:23 +02:00
String mesh_id = src_mesh_node - > get_mesh ( ) - > get_meta ( " import_id " , src_mesh_node - > get_mesh ( ) - > get_name ( ) ) ;
2021-03-19 13:57:52 +01:00
2021-12-09 10:42:46 +01:00
if ( ! mesh_id . is_empty ( ) & & p_mesh_data . has ( mesh_id ) ) {
2021-03-19 13:57:52 +01:00
Dictionary mesh_settings = p_mesh_data [ mesh_id ] ;
2022-06-27 10:06:50 +02:00
{
//fill node settings for this node with default values
List < ImportOption > iopts ;
get_internal_import_options ( INTERNAL_IMPORT_CATEGORY_MESH , & iopts ) ;
for ( const ImportOption & E : iopts ) {
if ( ! mesh_settings . has ( E . option . name ) ) {
mesh_settings [ E . option . name ] = E . default_value ;
}
}
}
2021-03-19 13:57:52 +01:00
if ( mesh_settings . has ( " generate/shadow_meshes " ) ) {
int shadow_meshes = mesh_settings [ " generate/shadow_meshes " ] ;
if ( shadow_meshes = = MESH_OVERRIDE_ENABLE ) {
create_shadow_meshes = true ;
} else if ( shadow_meshes = = MESH_OVERRIDE_DISABLE ) {
create_shadow_meshes = false ;
}
}
if ( mesh_settings . has ( " generate/lightmap_uv " ) ) {
int lightmap_uv = mesh_settings [ " generate/lightmap_uv " ] ;
if ( lightmap_uv = = MESH_OVERRIDE_ENABLE ) {
bake_lightmaps = true ;
} else if ( lightmap_uv = = MESH_OVERRIDE_DISABLE ) {
bake_lightmaps = false ;
}
}
if ( mesh_settings . has ( " generate/lods " ) ) {
int lods = mesh_settings [ " generate/lods " ] ;
if ( lods = = MESH_OVERRIDE_ENABLE ) {
generate_lods = true ;
} else if ( lods = = MESH_OVERRIDE_DISABLE ) {
generate_lods = false ;
}
}
2021-09-07 17:44:50 +02:00
if ( mesh_settings . has ( " lods/normal_split_angle " ) ) {
split_angle = mesh_settings [ " lods/normal_split_angle " ] ;
}
if ( mesh_settings . has ( " lods/normal_merge_angle " ) ) {
merge_angle = mesh_settings [ " lods/normal_merge_angle " ] ;
}
2024-06-29 03:32:59 +02:00
if ( mesh_settings . has ( " lods/raycast_normals " ) ) {
raycast_normals = mesh_settings [ " lods/raycast_normals " ] ;
}
2024-02-25 17:06:37 +01:00
if ( bool ( mesh_settings . get ( " save_to_file/enabled " , false ) ) ) {
save_to_file = mesh_settings . get ( " save_to_file/path " , String ( ) ) ;
2021-03-19 13:57:52 +01:00
if ( ! save_to_file . is_resource_file ( ) ) {
save_to_file = " " ;
}
}
2021-10-14 19:34:27 +02:00
for ( int i = 0 ; i < post_importer_plugins . size ( ) ; i + + ) {
post_importer_plugins . write [ i ] - > internal_process ( EditorScenePostImportPlugin : : INTERNAL_IMPORT_CATEGORY_MESH , nullptr , src_mesh_node , src_mesh_node - > get_mesh ( ) , mesh_settings ) ;
}
2021-03-19 13:57:52 +01:00
}
if ( bake_lightmaps ) {
2020-10-17 07:08:21 +02:00
Transform3D xf ;
2021-03-19 13:57:52 +01:00
Node3D * n = src_mesh_node ;
while ( n ) {
xf = n - > get_transform ( ) * xf ;
2021-06-09 13:06:38 +02:00
n = n - > get_parent_node_3d ( ) ;
2021-03-19 13:57:52 +01:00
}
2021-04-25 23:36:39 +02:00
Vector < uint8_t > lightmap_cache ;
src_mesh_node - > get_mesh ( ) - > lightmap_unwrap_cached ( xf , p_lightmap_texel_size , p_src_lightmap_cache , lightmap_cache ) ;
if ( ! lightmap_cache . is_empty ( ) ) {
if ( r_lightmap_caches . is_empty ( ) ) {
r_lightmap_caches . push_back ( lightmap_cache ) ;
} else {
String new_md5 = String : : md5 ( lightmap_cache . ptr ( ) ) ; // MD5 is stored at the beginning of the cache data
for ( int i = 0 ; i < r_lightmap_caches . size ( ) ; i + + ) {
String md5 = String : : md5 ( r_lightmap_caches [ i ] . ptr ( ) ) ;
if ( new_md5 < md5 ) {
r_lightmap_caches . insert ( i , lightmap_cache ) ;
break ;
}
if ( new_md5 = = md5 ) {
break ;
}
}
}
}
2021-03-19 13:57:52 +01:00
}
2022-02-26 02:36:40 +01:00
if ( generate_lods ) {
2022-09-07 21:13:10 +02:00
Array skin_pose_transform_array = _get_skinned_pose_transforms ( src_mesh_node ) ;
2024-06-29 03:32:59 +02:00
src_mesh_node - > get_mesh ( ) - > generate_lods ( merge_angle , split_angle , skin_pose_transform_array , raycast_normals ) ;
2022-02-26 02:36:40 +01:00
}
if ( create_shadow_meshes ) {
src_mesh_node - > get_mesh ( ) - > create_shadow_mesh ( ) ;
}
2021-12-09 10:42:46 +01:00
if ( ! save_to_file . is_empty ( ) ) {
2022-06-22 13:46:46 +02:00
Ref < Mesh > existing = ResourceCache : : get_ref ( save_to_file ) ;
2021-03-19 13:57:52 +01:00
if ( existing . is_valid ( ) ) {
//if somehow an existing one is useful, create
existing - > reset_state ( ) ;
}
mesh = src_mesh_node - > get_mesh ( ) - > get_mesh ( existing ) ;
2022-06-03 01:33:42 +02:00
ResourceSaver : : save ( mesh , save_to_file ) ; //override
2021-03-19 13:57:52 +01:00
mesh - > set_path ( save_to_file , true ) ; //takeover existing, if needed
} else {
mesh = src_mesh_node - > get_mesh ( ) - > get_mesh ( ) ;
}
} else {
mesh = src_mesh_node - > get_mesh ( ) - > get_mesh ( ) ;
2020-12-21 16:39:32 +01:00
}
2021-01-25 16:20:11 +01:00
2020-12-21 16:39:32 +01:00
if ( mesh . is_valid ( ) ) {
2024-01-25 18:01:56 +01:00
_copy_meta ( src_mesh_node - > get_mesh ( ) . ptr ( ) , mesh . ptr ( ) ) ;
2020-12-21 16:39:32 +01:00
mesh_node - > set_mesh ( mesh ) ;
for ( int i = 0 ; i < mesh - > get_surface_count ( ) ; i + + ) {
2021-04-14 05:45:16 +02:00
mesh_node - > set_surface_override_material ( i , src_mesh_node - > get_surface_material ( i ) ) ;
2020-12-21 16:39:32 +01:00
}
2020-12-17 19:56:59 +01:00
}
2020-12-12 13:06:59 +01:00
}
2021-03-19 13:57:52 +01:00
switch ( p_light_bake_mode ) {
case LIGHT_BAKE_DISABLED : {
mesh_node - > set_gi_mode ( GeometryInstance3D : : GI_MODE_DISABLED ) ;
} break ;
case LIGHT_BAKE_DYNAMIC : {
mesh_node - > set_gi_mode ( GeometryInstance3D : : GI_MODE_DYNAMIC ) ;
} break ;
case LIGHT_BAKE_STATIC :
case LIGHT_BAKE_STATIC_LIGHTMAPS : {
2021-11-26 17:47:37 +01:00
mesh_node - > set_gi_mode ( GeometryInstance3D : : GI_MODE_STATIC ) ;
2021-03-19 13:57:52 +01:00
} break ;
}
2023-06-28 18:09:23 +02:00
mesh_node - > set_layer_mask ( src_mesh_node - > get_layer_mask ( ) ) ;
mesh_node - > set_cast_shadows_setting ( src_mesh_node - > get_cast_shadows_setting ( ) ) ;
mesh_node - > set_visibility_range_begin ( src_mesh_node - > get_visibility_range_begin ( ) ) ;
mesh_node - > set_visibility_range_begin_margin ( src_mesh_node - > get_visibility_range_begin_margin ( ) ) ;
mesh_node - > set_visibility_range_end ( src_mesh_node - > get_visibility_range_end ( ) ) ;
mesh_node - > set_visibility_range_end_margin ( src_mesh_node - > get_visibility_range_end_margin ( ) ) ;
mesh_node - > set_visibility_range_fade_mode ( src_mesh_node - > get_visibility_range_fade_mode ( ) ) ;
2024-01-25 18:01:56 +01:00
_copy_meta ( p_node , mesh_node ) ;
2020-12-12 13:06:59 +01:00
p_node - > replace_by ( mesh_node ) ;
2023-02-27 17:24:03 +01:00
p_node - > set_owner ( nullptr ) ;
2020-12-12 13:06:59 +01:00
memdelete ( p_node ) ;
p_node = mesh_node ;
}
for ( int i = 0 ; i < p_node - > get_child_count ( ) ; i + + ) {
2021-04-25 23:36:39 +02:00
_generate_meshes ( p_node - > get_child ( i ) , p_mesh_data , p_generate_lods , p_create_shadow_meshes , p_light_bake_mode , p_lightmap_texel_size , p_src_lightmap_cache , r_lightmap_caches ) ;
2020-12-12 13:06:59 +01:00
}
2023-11-14 02:21:25 +01:00
return p_node ;
2020-12-12 13:06:59 +01:00
}
2021-03-19 13:57:52 +01:00
Improve collision generation usability in the new 3D scene import workflow.
With this PR it's possible to add a collision during the Mesh import, directly in editor.
To generate the shape is possible to chose between the following options:
- Decompose Convex: The Mesh is decomposed in one or many Convex Shapes (Using the VHACD library).
- Simple Convex: Is generated a convex shape that enclose the entire mesh.
- Trimesh: Generate a trimesh shape using the Mesh faces.
- Box: Add a primitive box shape, where you can tweak the `size`, `position`, `rotation`.
- Sphere: Add a primitive sphere shape, where you can tweak the `radius`, `position`, `rotation`.
- Cylinder: Add a primitive cylinder shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
- Capsule: Add a primitive capsule shape, where you can tweak the `height`, `radius`, `position`, `rotation`.
It's also possible to chose the generated body, so you can create:
- Rigid Body
- Static Body
- Area
2021-08-22 18:19:13 +02:00
void ResourceImporterScene : : _add_shapes ( Node * p_node , const Vector < Ref < Shape3D > > & p_shapes ) {
2021-07-16 05:45:57 +02:00
for ( const Ref < Shape3D > & E : p_shapes ) {
2021-03-23 08:08:06 +01:00
CollisionShape3D * cshape = memnew ( CollisionShape3D ) ;
2021-07-16 05:45:57 +02:00
cshape - > set_shape ( E ) ;
2021-10-21 16:46:07 +02:00
p_node - > add_child ( cshape , true ) ;
2021-03-23 08:08:06 +01:00
cshape - > set_owner ( p_node - > get_owner ( ) ) ;
}
}
2024-01-25 18:01:56 +01:00
void ResourceImporterScene : : _copy_meta ( Object * p_src_object , Object * p_dst_object ) {
List < StringName > meta_list ;
p_src_object - > get_meta_list ( & meta_list ) ;
for ( const StringName & meta_key : meta_list ) {
Variant meta_value = p_src_object - > get_meta ( meta_key ) ;
p_dst_object - > set_meta ( meta_key , meta_value ) ;
}
}
2021-10-13 23:40:55 +02:00
void ResourceImporterScene : : _optimize_track_usage ( AnimationPlayer * p_player , AnimationImportTracks * p_track_actions ) {
List < StringName > anims ;
p_player - > get_animation_list ( & anims ) ;
Node * parent = p_player - > get_parent ( ) ;
2023-09-09 17:24:40 +02:00
ERR_FAIL_NULL ( parent ) ;
2022-05-08 10:09:19 +02:00
HashMap < NodePath , uint32_t > used_tracks [ TRACK_CHANNEL_MAX ] ;
2021-10-13 23:40:55 +02:00
bool tracks_to_add = false ;
2021-10-16 00:04:35 +02:00
static const Animation : : TrackType track_types [ TRACK_CHANNEL_MAX ] = { Animation : : TYPE_POSITION_3D , Animation : : TYPE_ROTATION_3D , Animation : : TYPE_SCALE_3D , Animation : : TYPE_BLEND_SHAPE } ;
2021-10-13 23:40:55 +02:00
for ( const StringName & I : anims ) {
Ref < Animation > anim = p_player - > get_animation ( I ) ;
for ( int i = 0 ; i < anim - > get_track_count ( ) ; i + + ) {
for ( int j = 0 ; j < TRACK_CHANNEL_MAX ; j + + ) {
if ( anim - > track_get_type ( i ) ! = track_types [ j ] ) {
continue ;
}
switch ( p_track_actions [ j ] ) {
case ANIMATION_IMPORT_TRACKS_IF_PRESENT : {
// Do Nothing.
} break ;
case ANIMATION_IMPORT_TRACKS_IF_PRESENT_FOR_ALL : {
used_tracks [ j ] . insert ( anim - > track_get_path ( i ) , 0 ) ;
tracks_to_add = true ;
} break ;
case ANIMATION_IMPORT_TRACKS_NEVER : {
anim - > remove_track ( i ) ;
i - - ;
} break ;
}
}
}
}
if ( ! tracks_to_add ) {
return ;
}
uint32_t pass = 0 ;
for ( const StringName & I : anims ) {
Ref < Animation > anim = p_player - > get_animation ( I ) ;
for ( int j = 0 ; j < TRACK_CHANNEL_MAX ; j + + ) {
if ( p_track_actions [ j ] ! = ANIMATION_IMPORT_TRACKS_IF_PRESENT_FOR_ALL ) {
continue ;
}
pass + + ;
for ( int i = 0 ; i < anim - > get_track_count ( ) ; i + + ) {
if ( anim - > track_get_type ( i ) ! = track_types [ j ] ) {
continue ;
}
NodePath path = anim - > track_get_path ( i ) ;
ERR_CONTINUE ( ! used_tracks [ j ] . has ( path ) ) ; // Should never happen.
used_tracks [ j ] [ path ] = pass ;
}
2022-05-08 10:09:19 +02:00
for ( const KeyValue < NodePath , uint32_t > & J : used_tracks [ j ] ) {
if ( J . value = = pass ) {
2021-10-13 23:40:55 +02:00
continue ;
}
2022-05-08 10:09:19 +02:00
NodePath path = J . key ;
2021-10-13 23:40:55 +02:00
Node * n = parent - > get_node ( path ) ;
2021-10-16 00:04:35 +02:00
if ( j = = TRACK_CHANNEL_BLEND_SHAPE ) {
MeshInstance3D * mi = Object : : cast_to < MeshInstance3D > ( n ) ;
if ( mi & & path . get_subname_count ( ) > 0 ) {
StringName bs = path . get_subname ( 0 ) ;
bool valid ;
float value = mi - > get ( bs , & valid ) ;
if ( valid ) {
int track_idx = anim - > add_track ( track_types [ j ] ) ;
anim - > track_set_path ( track_idx , path ) ;
anim - > track_set_imported ( track_idx , true ) ;
anim - > blend_shape_track_insert_key ( track_idx , 0 , value ) ;
}
2021-10-13 23:40:55 +02:00
}
2021-10-16 00:04:35 +02:00
2021-10-13 23:40:55 +02:00
} else {
2021-10-16 00:04:35 +02:00
Skeleton3D * skel = Object : : cast_to < Skeleton3D > ( n ) ;
Node3D * n3d = Object : : cast_to < Node3D > ( n ) ;
Vector3 loc ;
Quaternion rot ;
Vector3 scale ;
if ( skel & & path . get_subname_count ( ) > 0 ) {
StringName bone = path . get_subname ( 0 ) ;
int bone_idx = skel - > find_bone ( bone ) ;
if ( bone_idx = = - 1 ) {
continue ;
}
2022-01-19 20:46:17 +01:00
// Note that this is using get_bone_pose to update the bone pose cache.
_ALLOW_DISCARD_ skel - > get_bone_pose ( bone_idx ) ;
2021-10-16 00:04:35 +02:00
loc = skel - > get_bone_pose_position ( bone_idx ) ;
rot = skel - > get_bone_pose_rotation ( bone_idx ) ;
scale = skel - > get_bone_pose_scale ( bone_idx ) ;
} else if ( n3d ) {
loc = n3d - > get_position ( ) ;
rot = n3d - > get_transform ( ) . basis . get_rotation_quaternion ( ) ;
scale = n3d - > get_scale ( ) ;
} else {
continue ;
}
2021-10-13 23:40:55 +02:00
2021-10-16 00:04:35 +02:00
// Ensure insertion keeps tracks together and ordered by type (loc/rot/scale)
int insert_at_pos = - 1 ;
for ( int k = 0 ; k < anim - > get_track_count ( ) ; k + + ) {
NodePath tpath = anim - > track_get_path ( k ) ;
if ( path = = tpath ) {
Animation : : TrackType ttype = anim - > track_get_type ( k ) ;
if ( insert_at_pos = = - 1 ) {
// First insert, determine whether replacing or kicking back
if ( track_types [ j ] < ttype ) {
insert_at_pos = k ;
break ; // No point in continuing.
} else {
insert_at_pos = k + 1 ;
}
} else if ( ttype < track_types [ j ] ) {
// Kick back.
2021-10-13 23:40:55 +02:00
insert_at_pos = k + 1 ;
}
2021-10-16 00:04:35 +02:00
} else if ( insert_at_pos > = 0 ) {
break ;
2021-10-13 23:40:55 +02:00
}
}
2021-10-16 00:04:35 +02:00
int track_idx = anim - > add_track ( track_types [ j ] , insert_at_pos ) ;
anim - > track_set_path ( track_idx , path ) ;
anim - > track_set_imported ( track_idx , true ) ;
switch ( j ) {
case TRACK_CHANNEL_POSITION : {
anim - > position_track_insert_key ( track_idx , 0 , loc ) ;
} break ;
case TRACK_CHANNEL_ROTATION : {
anim - > rotation_track_insert_key ( track_idx , 0 , rot ) ;
} break ;
case TRACK_CHANNEL_SCALE : {
anim - > scale_track_insert_key ( track_idx , 0 , scale ) ;
} break ;
default : {
}
2021-10-13 23:40:55 +02:00
}
}
}
}
}
}
2022-07-01 14:03:40 +02:00
Node * ResourceImporterScene : : pre_import ( const String & p_source_file , const HashMap < StringName , Variant > & p_options ) {
2021-10-14 19:34:27 +02:00
Ref < EditorSceneFormatImporter > importer ;
2021-03-19 13:57:52 +01:00
String ext = p_source_file . get_extension ( ) . to_lower ( ) ;
2023-02-13 04:27:12 +01:00
// TRANSLATORS: This is an editor progress label.
2021-03-19 13:57:52 +01:00
EditorProgress progress ( " pre-import " , TTR ( " Pre-Import Scene " ) , 0 ) ;
progress . step ( TTR ( " Importing Scene... " ) , 0 ) ;
2023-10-08 07:48:53 +02:00
for ( Ref < EditorSceneFormatImporter > importer_elem : scene_importers ) {
2021-03-19 13:57:52 +01:00
List < String > extensions ;
2022-01-19 12:03:47 +01:00
importer_elem - > get_extensions ( & extensions ) ;
2021-03-19 13:57:52 +01:00
2021-07-24 20:30:43 +02:00
for ( const String & F : extensions ) {
2021-07-16 05:45:57 +02:00
if ( F . to_lower ( ) = = ext ) {
2022-01-19 12:03:47 +01:00
importer = importer_elem ;
2021-03-19 13:57:52 +01:00
break ;
}
}
if ( importer . is_valid ( ) ) {
break ;
}
}
ERR_FAIL_COND_V ( ! importer . is_valid ( ) , nullptr ) ;
2021-03-24 00:46:22 +01:00
Error err = OK ;
2023-01-31 08:37:55 +01:00
2023-11-06 09:22:32 +01:00
Node * scene = importer - > import_scene ( p_source_file , EditorSceneFormatImporter : : IMPORT_ANIMATION | EditorSceneFormatImporter : : IMPORT_GENERATE_TANGENT_ARRAYS | EditorSceneFormatImporter : : IMPORT_FORCE_DISABLE_MESH_COMPRESSION , p_options , nullptr , & err ) ;
2021-03-19 13:57:52 +01:00
if ( ! scene | | err ! = OK ) {
return nullptr ;
}
2024-03-18 04:29:29 +01:00
_pre_fix_global ( scene , p_options ) ;
2022-05-13 15:04:37 +02:00
HashMap < Ref < ImporterMesh > , Vector < Ref < Shape3D > > > collision_map ;
2020-10-24 00:57:48 +02:00
List < Pair < NodePath , Node * > > node_renames ;
2022-02-04 16:28:18 +01:00
_pre_fix_node ( scene , scene , collision_map , nullptr , node_renames ) ;
2021-03-19 13:57:52 +01:00
return scene ;
}
2023-10-23 21:26:38 +02:00
Error ResourceImporterScene : : _check_resource_save_paths ( const Dictionary & p_data ) {
Array keys = p_data . keys ( ) ;
for ( int i = 0 ; i < keys . size ( ) ; i + + ) {
const Dictionary & settings = p_data [ keys [ i ] ] ;
if ( bool ( settings . get ( " save_to_file/enabled " , false ) ) & & settings . has ( " save_to_file/path " ) ) {
const String & save_path = settings [ " save_to_file/path " ] ;
ERR_FAIL_COND_V ( ! save_path . is_empty ( ) & & ! DirAccess : : exists ( save_path . get_base_dir ( ) ) , ERR_FILE_BAD_PATH ) ;
}
}
return OK ;
}
2022-05-13 15:04:37 +02:00
Error ResourceImporterScene : : import ( const String & p_source_file , const String & p_save_path , const HashMap < StringName , Variant > & p_options , List < String > * r_platform_variants , List < String > * r_gen_files , Variant * r_metadata ) {
2019-06-26 15:08:25 +02:00
const String & src_path = p_source_file ;
2017-02-04 13:48:04 +01:00
2021-10-14 19:34:27 +02:00
Ref < EditorSceneFormatImporter > importer ;
2017-02-04 13:48:04 +01:00
String ext = src_path . get_extension ( ) . to_lower ( ) ;
EditorProgress progress ( " import " , TTR ( " Import Scene " ) , 104 ) ;
2018-04-22 19:36:01 +02:00
progress . step ( TTR ( " Importing Scene... " ) , 0 ) ;
2017-02-04 13:48:04 +01:00
2023-10-08 07:48:53 +02:00
for ( Ref < EditorSceneFormatImporter > importer_elem : scene_importers ) {
2017-02-04 13:48:04 +01:00
List < String > extensions ;
2022-01-19 12:03:47 +01:00
importer_elem - > get_extensions ( & extensions ) ;
2017-02-04 13:48:04 +01:00
2021-07-24 20:30:43 +02:00
for ( const String & F : extensions ) {
2021-07-16 05:45:57 +02:00
if ( F . to_lower ( ) = = ext ) {
2022-01-19 12:03:47 +01:00
importer = importer_elem ;
2017-02-04 13:48:04 +01:00
break ;
}
}
2020-05-14 16:41:43 +02:00
if ( importer . is_valid ( ) ) {
2017-02-04 13:48:04 +01:00
break ;
2020-05-14 16:41:43 +02:00
}
2017-02-04 13:48:04 +01:00
}
ERR_FAIL_COND_V ( ! importer . is_valid ( ) , ERR_FILE_UNRECOGNIZED ) ;
2021-03-19 13:57:52 +01:00
int import_flags = 0 ;
2017-02-04 13:48:04 +01:00
2022-04-12 16:07:09 +02:00
if ( animation_importer ) {
2021-10-14 19:34:27 +02:00
import_flags | = EditorSceneFormatImporter : : IMPORT_ANIMATION ;
2022-04-12 16:07:09 +02:00
import_flags | = EditorSceneFormatImporter : : IMPORT_DISCARD_MESHES_AND_MATERIALS ;
} else {
if ( bool ( p_options [ " animation/import " ] ) ) {
import_flags | = EditorSceneFormatImporter : : IMPORT_ANIMATION ;
}
2020-05-14 16:41:43 +02:00
}
2017-02-04 13:48:04 +01:00
2020-05-14 16:41:43 +02:00
if ( bool ( p_options [ " skins/use_named_skins " ] ) ) {
2021-10-14 19:34:27 +02:00
import_flags | = EditorSceneFormatImporter : : IMPORT_USE_NAMED_SKIN_BINDS ;
2020-05-14 16:41:43 +02:00
}
2020-02-21 11:27:48 +01:00
2021-03-19 13:57:52 +01:00
bool ensure_tangents = p_options [ " meshes/ensure_tangents " ] ;
if ( ensure_tangents ) {
2021-10-14 19:34:27 +02:00
import_flags | = EditorSceneFormatImporter : : IMPORT_GENERATE_TANGENT_ARRAYS ;
2021-03-19 13:57:52 +01:00
}
2023-08-29 21:04:32 +02:00
bool force_disable_compression = p_options [ " meshes/force_disable_compression " ] ;
if ( force_disable_compression ) {
import_flags | = EditorSceneFormatImporter : : IMPORT_FORCE_DISABLE_MESH_COMPRESSION ;
}
2023-10-23 21:26:38 +02:00
Dictionary subresources = p_options [ " _subresources " ] ;
Dictionary node_data ;
if ( subresources . has ( " nodes " ) ) {
node_data = subresources [ " nodes " ] ;
}
Dictionary material_data ;
if ( subresources . has ( " materials " ) ) {
material_data = subresources [ " materials " ] ;
}
Dictionary animation_data ;
if ( subresources . has ( " animations " ) ) {
animation_data = subresources [ " animations " ] ;
}
Dictionary mesh_data ;
if ( subresources . has ( " meshes " ) ) {
mesh_data = subresources [ " meshes " ] ;
}
2017-02-04 13:48:04 +01:00
Error err = OK ;
2023-10-23 21:26:38 +02:00
// Check whether any of the meshes or animations have nonexistent save paths
// and if they do, fail the import immediately.
err = _check_resource_save_paths ( mesh_data ) ;
if ( err ! = OK ) {
return err ;
}
err = _check_resource_save_paths ( animation_data ) ;
if ( err ! = OK ) {
return err ;
}
2017-02-04 13:48:04 +01:00
List < String > missing_deps ; // for now, not much will be done with this
2022-11-14 20:14:52 +01:00
Node * scene = importer - > import_scene ( src_path , import_flags , p_options , & missing_deps , & err ) ;
2017-02-04 13:48:04 +01:00
if ( ! scene | | err ! = OK ) {
return err ;
}
2022-02-04 08:34:59 +01:00
bool apply_root = true ;
if ( p_options . has ( " nodes/apply_root_scale " ) ) {
apply_root = p_options [ " nodes/apply_root_scale " ] ;
}
real_t root_scale = 1 ;
if ( p_options . has ( " nodes/root_scale " ) ) {
root_scale = p_options [ " nodes/root_scale " ] ;
}
if ( Object : : cast_to < Node3D > ( scene ) ) {
2023-02-06 00:29:19 +01:00
Node3D * scene_3d = Object : : cast_to < Node3D > ( scene ) ;
Vector3 scale = Vector3 ( root_scale , root_scale , root_scale ) ;
if ( apply_root ) {
_apply_permanent_scale_to_descendants ( scene , scale ) ;
} else {
scene_3d - > scale ( scale ) ;
}
2022-02-04 08:34:59 +01:00
}
2021-03-19 13:57:52 +01:00
2024-03-18 04:29:29 +01:00
_pre_fix_global ( scene , p_options ) ;
2022-05-19 17:00:06 +02:00
HashSet < Ref < ImporterMesh > > scanned_meshes ;
2022-05-13 15:04:37 +02:00
HashMap < Ref < ImporterMesh > , Vector < Ref < Shape3D > > > collision_map ;
2022-02-04 16:28:18 +01:00
Pair < PackedVector3Array , PackedInt32Array > occluder_arrays ;
2020-10-24 00:57:48 +02:00
List < Pair < NodePath , Node * > > node_renames ;
2021-03-19 13:57:52 +01:00
2022-02-04 16:28:18 +01:00
_pre_fix_node ( scene , scene , collision_map , & occluder_arrays , node_renames ) ;
2021-10-14 19:34:27 +02:00
for ( int i = 0 ; i < post_importer_plugins . size ( ) ; i + + ) {
post_importer_plugins . write [ i ] - > pre_process ( scene , p_options ) ;
}
2022-11-14 20:14:52 +01:00
float fps = 30 ;
if ( p_options . has ( SNAME ( " animation/fps " ) ) ) {
fps = ( float ) p_options [ SNAME ( " animation/fps " ) ] ;
}
2024-03-31 08:45:22 +02:00
bool remove_immutable_tracks = p_options . has ( " animation/remove_immutable_tracks " ) ? ( bool ) p_options [ " animation/remove_immutable_tracks " ] : true ;
2022-07-26 11:48:08 +02:00
_pre_fix_animations ( scene , scene , node_data , animation_data , fps ) ;
2023-01-28 12:31:20 +01:00
_post_fix_node ( scene , scene , collision_map , occluder_arrays , scanned_meshes , node_data , material_data , animation_data , fps , apply_root ? root_scale : 1.0 ) ;
2024-03-31 08:45:22 +02:00
_post_fix_animations ( scene , scene , node_data , animation_data , fps , remove_immutable_tracks ) ;
2021-03-19 13:57:52 +01:00
2017-02-04 13:48:04 +01:00
String root_type = p_options [ " nodes/root_type " ] ;
2023-07-22 02:07:00 +02:00
if ( ! root_type . is_empty ( ) ) {
root_type = root_type . split ( " " ) [ 0 ] ; // Full root_type is "ClassName (filename.gd)" for a script global class.
Ref < Script > root_script = nullptr ;
if ( ScriptServer : : is_global_class ( root_type ) ) {
root_script = ResourceLoader : : load ( ScriptServer : : get_global_class_path ( root_type ) ) ;
root_type = ScriptServer : : get_global_class_base ( root_type ) ;
}
if ( scene - > get_class_name ( ) ! = root_type ) {
// If the user specified a Godot node type that does not match
// what the scene import gave us, replace the root node.
Node * base_node = Object : : cast_to < Node > ( ClassDB : : instantiate ( root_type ) ) ;
if ( base_node ) {
scene - > replace_by ( base_node ) ;
scene - > set_owner ( nullptr ) ;
memdelete ( scene ) ;
scene = base_node ;
}
}
if ( root_script . is_valid ( ) ) {
scene - > set_script ( Variant ( root_script ) ) ;
2017-02-04 13:48:04 +01:00
}
}
2023-07-22 02:07:00 +02:00
String root_name = p_options [ " nodes/root_name " ] ;
if ( ! root_name . is_empty ( ) & & root_name ! = " Scene Root " ) {
// TODO: Remove `&& root_name != "Scene Root"` for Godot 5.0.
// For backwards compatibility with existing .import files,
// treat "Scene Root" as having no root name override.
scene - > set_name ( root_name ) ;
} else if ( String ( scene - > get_name ( ) ) . is_empty ( ) ) {
2019-04-08 18:43:55 +02:00
scene - > set_name ( p_save_path . get_file ( ) . get_basename ( ) ) ;
2020-05-14 16:41:43 +02:00
}
2017-02-04 13:48:04 +01:00
2022-02-04 16:28:18 +01:00
if ( ! occluder_arrays . first . is_empty ( ) & & ! occluder_arrays . second . is_empty ( ) ) {
Ref < ArrayOccluder3D > occ = memnew ( ArrayOccluder3D ) ;
occ - > set_arrays ( occluder_arrays . first , occluder_arrays . second ) ;
OccluderInstance3D * occluder_instance = memnew ( OccluderInstance3D ) ;
occluder_instance - > set_occluder ( occ ) ;
scene - > add_child ( occluder_instance , true ) ;
occluder_instance - > set_owner ( scene ) ;
}
2020-12-17 19:56:59 +01:00
bool gen_lods = bool ( p_options [ " meshes/generate_lods " ] ) ;
2021-01-25 16:20:11 +01:00
bool create_shadow_meshes = bool ( p_options [ " meshes/create_shadow_meshes " ] ) ;
2017-11-25 05:29:15 +01:00
int light_bake_mode = p_options [ " meshes/light_baking " ] ;
2021-03-19 13:57:52 +01:00
float texel_size = p_options [ " meshes/lightmap_texel_size " ] ;
float lightmap_texel_size = MAX ( 0.001 , texel_size ) ;
2017-02-04 13:48:04 +01:00
2021-03-19 13:57:52 +01:00
Vector < uint8_t > src_lightmap_cache ;
2021-04-25 23:36:39 +02:00
Vector < Vector < uint8_t > > mesh_lightmap_caches ;
2017-02-04 13:48:04 +01:00
{
2022-11-21 14:04:01 +01:00
src_lightmap_cache = FileAccess : : get_file_as_bytes ( p_source_file + " .unwrap_cache " , & err ) ;
2021-03-19 13:57:52 +01:00
if ( err ! = OK ) {
src_lightmap_cache . clear ( ) ;
2017-02-04 13:48:04 +01:00
}
}
2023-11-14 02:21:25 +01:00
scene = _generate_meshes ( scene , mesh_data , gen_lods , create_shadow_meshes , LightBakeMode ( light_bake_mode ) , lightmap_texel_size , src_lightmap_cache , mesh_lightmap_caches ) ;
2017-02-04 13:48:04 +01:00
2021-04-25 23:36:39 +02:00
if ( mesh_lightmap_caches . size ( ) ) {
2022-03-23 10:08:58 +01:00
Ref < FileAccess > f = FileAccess : : open ( p_source_file + " .unwrap_cache " , FileAccess : : WRITE ) ;
if ( f . is_valid ( ) ) {
2021-04-25 23:36:39 +02:00
f - > store_32 ( mesh_lightmap_caches . size ( ) ) ;
for ( int i = 0 ; i < mesh_lightmap_caches . size ( ) ; i + + ) {
String md5 = String : : md5 ( mesh_lightmap_caches [ i ] . ptr ( ) ) ;
f - > store_buffer ( mesh_lightmap_caches [ i ] . ptr ( ) , mesh_lightmap_caches [ i ] . size ( ) ) ;
2020-04-22 15:34:00 +02:00
}
2017-12-09 18:11:26 +01:00
}
}
2021-04-25 23:36:39 +02:00
err = OK ;
2017-02-05 00:31:15 +01:00
2018-04-22 19:36:01 +02:00
progress . step ( TTR ( " Running Custom Script... " ) , 2 ) ;
2017-02-04 13:48:04 +01:00
2021-03-19 13:57:52 +01:00
String post_import_script_path = p_options [ " import_script/path " ] ;
2017-02-04 13:48:04 +01:00
Ref < EditorScenePostImport > post_import_script ;
2021-12-09 10:42:46 +01:00
if ( ! post_import_script_path . is_empty ( ) ) {
2017-02-04 13:48:04 +01:00
Ref < Script > scr = ResourceLoader : : load ( post_import_script_path ) ;
if ( ! scr . is_valid ( ) ) {
EditorNode : : add_io_error ( TTR ( " Couldn't load post-import script: " ) + " " + post_import_script_path ) ;
} else {
post_import_script = Ref < EditorScenePostImport > ( memnew ( EditorScenePostImport ) ) ;
2020-02-13 20:03:10 +01:00
post_import_script - > set_script ( scr ) ;
2017-02-04 13:48:04 +01:00
if ( ! post_import_script - > get_script_instance ( ) ) {
EditorNode : : add_io_error ( TTR ( " Invalid/broken script for post-import (check console): " ) + " " + post_import_script_path ) ;
post_import_script . unref ( ) ;
return ERR_CANT_CREATE ;
}
}
}
if ( post_import_script . is_valid ( ) ) {
2021-03-19 13:57:52 +01:00
post_import_script - > init ( p_source_file ) ;
2017-02-04 13:48:04 +01:00
scene = post_import_script - > post_import ( scene ) ;
if ( ! scene ) {
2020-05-11 21:09:36 +02:00
EditorNode : : add_io_error (
TTR ( " Error running post-import script: " ) + " " + post_import_script_path + " \n " +
2021-05-15 23:48:59 +02:00
TTR ( " Did you return a Node-derived object in the `_post_import()` method? " ) ) ;
2017-02-04 13:48:04 +01:00
return err ;
}
}
2021-10-14 19:34:27 +02:00
for ( int i = 0 ; i < post_importer_plugins . size ( ) ; i + + ) {
post_importer_plugins . write [ i ] - > post_process ( scene , p_options ) ;
}
2018-04-22 19:36:01 +02:00
progress . step ( TTR ( " Saving... " ) , 104 ) ;
2017-02-04 13:48:04 +01:00
2023-04-30 23:13:28 +02:00
int flags = 0 ;
if ( EDITOR_GET ( " filesystem/on_save/compress_binary_resources " ) ) {
flags | = ResourceSaver : : FLAG_COMPRESS ;
}
2022-04-12 16:07:09 +02:00
if ( animation_importer ) {
Ref < AnimationLibrary > library ;
for ( int i = 0 ; i < scene - > get_child_count ( ) ; i + + ) {
AnimationPlayer * ap = Object : : cast_to < AnimationPlayer > ( scene - > get_child ( i ) ) ;
if ( ap ) {
List < StringName > libs ;
ap - > get_animation_library_list ( & libs ) ;
if ( libs . size ( ) ) {
library = ap - > get_animation_library ( libs . front ( ) - > get ( ) ) ;
break ;
}
}
}
if ( ! library . is_valid ( ) ) {
library . instantiate ( ) ; // Will be empty
}
2023-04-30 23:13:28 +02:00
print_verbose ( " Saving animation to: " + p_save_path + " .res " ) ;
err = ResourceSaver : : save ( library , p_save_path + " .res " , flags ) ; //do not take over, let the changed files reload themselves
2022-04-12 16:07:09 +02:00
ERR_FAIL_COND_V_MSG ( err ! = OK , err , " Cannot save animation to file ' " + p_save_path + " .res'. " ) ;
} else {
Ref < PackedScene > packer = memnew ( PackedScene ) ;
packer - > pack ( scene ) ;
print_verbose ( " Saving scene to: " + p_save_path + " .scn " ) ;
2023-04-30 23:13:28 +02:00
err = ResourceSaver : : save ( packer , p_save_path + " .scn " , flags ) ; //do not take over, let the changed files reload themselves
2022-04-12 16:07:09 +02:00
ERR_FAIL_COND_V_MSG ( err ! = OK , err , " Cannot save scene to file ' " + p_save_path + " .scn'. " ) ;
}
2017-02-04 13:48:04 +01:00
memdelete ( scene ) ;
2017-08-31 23:57:03 +02:00
//this is not the time to reimport, wait until import process is done, import file is saved, etc.
//EditorNode::get_singleton()->reload_scene(p_source_file);
2017-02-04 13:48:04 +01:00
return OK ;
}
2022-04-12 16:07:09 +02:00
ResourceImporterScene * ResourceImporterScene : : scene_singleton = nullptr ;
ResourceImporterScene * ResourceImporterScene : : animation_singleton = nullptr ;
2023-10-08 07:48:53 +02:00
Vector < Ref < EditorSceneFormatImporter > > ResourceImporterScene : : scene_importers ;
2022-04-12 16:07:09 +02:00
Vector < Ref < EditorScenePostImportPlugin > > ResourceImporterScene : : post_importer_plugins ;
2017-02-04 13:48:04 +01:00
2023-10-31 23:55:15 +01:00
bool ResourceImporterScene : : has_advanced_options ( ) const {
2021-03-19 13:57:52 +01:00
return true ;
}
2023-10-08 07:48:53 +02:00
2023-10-31 23:55:15 +01:00
void ResourceImporterScene : : show_advanced_options ( const String & p_path ) {
2023-10-06 09:00:36 +02:00
SceneImportSettingsDialog : : get_singleton ( ) - > open_settings ( p_path , animation_importer ) ;
2021-03-19 13:57:52 +01:00
}
2023-08-07 17:00:46 +02:00
ResourceImporterScene : : ResourceImporterScene ( bool p_animation_import , bool p_singleton ) {
// This should only be set through the EditorNode.
if ( p_singleton ) {
if ( p_animation_import ) {
animation_singleton = this ;
} else {
scene_singleton = this ;
}
2022-04-12 16:07:09 +02:00
}
2023-08-07 17:00:46 +02:00
2022-04-12 16:07:09 +02:00
animation_importer = p_animation_import ;
2017-02-04 13:48:04 +01:00
}
2020-05-14 14:29:06 +02:00
2023-08-07 17:00:46 +02:00
ResourceImporterScene : : ~ ResourceImporterScene ( ) {
if ( animation_singleton = = this ) {
animation_singleton = nullptr ;
}
if ( scene_singleton = = this ) {
scene_singleton = nullptr ;
}
}
2023-10-08 07:48:53 +02:00
void ResourceImporterScene : : add_scene_importer ( Ref < EditorSceneFormatImporter > p_importer , bool p_first_priority ) {
2022-01-19 12:03:47 +01:00
ERR_FAIL_COND ( p_importer . is_null ( ) ) ;
2022-02-07 09:38:42 +01:00
if ( p_first_priority ) {
2023-10-08 07:48:53 +02:00
scene_importers . insert ( 0 , p_importer ) ;
2022-02-07 09:38:42 +01:00
} else {
2023-10-08 07:48:53 +02:00
scene_importers . push_back ( p_importer ) ;
2022-02-07 09:38:42 +01:00
}
2022-01-19 12:03:47 +01:00
}
void ResourceImporterScene : : remove_post_importer_plugin ( const Ref < EditorScenePostImportPlugin > & p_plugin ) {
post_importer_plugins . erase ( p_plugin ) ;
}
2022-02-07 09:38:42 +01:00
void ResourceImporterScene : : add_post_importer_plugin ( const Ref < EditorScenePostImportPlugin > & p_plugin , bool p_first_priority ) {
2022-01-19 12:03:47 +01:00
ERR_FAIL_COND ( p_plugin . is_null ( ) ) ;
2022-02-07 09:38:42 +01:00
if ( p_first_priority ) {
post_importer_plugins . insert ( 0 , p_plugin ) ;
} else {
post_importer_plugins . push_back ( p_plugin ) ;
}
2022-01-19 12:03:47 +01:00
}
2023-10-08 07:48:53 +02:00
void ResourceImporterScene : : remove_scene_importer ( Ref < EditorSceneFormatImporter > p_importer ) {
scene_importers . erase ( p_importer ) ;
2022-01-19 12:03:47 +01:00
}
2022-04-12 16:07:09 +02:00
void ResourceImporterScene : : clean_up_importer_plugins ( ) {
2023-10-08 07:48:53 +02:00
scene_importers . clear ( ) ;
2022-04-12 16:07:09 +02:00
post_importer_plugins . clear ( ) ;
}
2023-10-08 07:48:53 +02:00
void ResourceImporterScene : : get_scene_importer_extensions ( List < String > * p_extensions ) {
for ( Ref < EditorSceneFormatImporter > importer_elem : scene_importers ) {
importer_elem - > get_extensions ( p_extensions ) ;
}
}
2018-01-30 15:03:46 +01:00
///////////////////////////////////////
2021-10-14 19:34:27 +02:00
uint32_t EditorSceneFormatImporterESCN : : get_import_flags ( ) const {
2018-01-30 15:03:46 +01:00
return IMPORT_SCENE ;
}
2020-05-14 14:29:06 +02:00
2021-10-14 19:34:27 +02:00
void EditorSceneFormatImporterESCN : : get_extensions ( List < String > * r_extensions ) const {
2018-01-30 15:03:46 +01:00
r_extensions - > push_back ( " escn " ) ;
}
2020-05-14 14:29:06 +02:00
2022-11-14 20:14:52 +01:00
Node * EditorSceneFormatImporterESCN : : import_scene ( const String & p_path , uint32_t p_flags , const HashMap < StringName , Variant > & p_options , List < String > * r_missing_deps , Error * r_err ) {
2018-01-30 15:03:46 +01:00
Error error ;
Ref < PackedScene > ps = ResourceFormatLoaderText : : singleton - > load ( p_path , p_path , & error ) ;
2020-04-02 01:20:12 +02:00
ERR_FAIL_COND_V_MSG ( ! ps . is_valid ( ) , nullptr , " Cannot load scene as text resource from path ' " + p_path + " '. " ) ;
2021-06-18 00:03:09 +02:00
Node * scene = ps - > instantiate ( ) ;
2023-01-14 17:39:29 +01:00
TypedArray < Node > nodes = scene - > find_children ( " * " , " MeshInstance3D " ) ;
for ( int32_t node_i = 0 ; node_i < nodes . size ( ) ; node_i + + ) {
MeshInstance3D * mesh_3d = cast_to < MeshInstance3D > ( nodes [ node_i ] ) ;
Ref < ImporterMesh > mesh ;
mesh . instantiate ( ) ;
// Ignore the aabb, it will be recomputed.
ImporterMeshInstance3D * importer_mesh_3d = memnew ( ImporterMeshInstance3D ) ;
importer_mesh_3d - > set_name ( mesh_3d - > get_name ( ) ) ;
importer_mesh_3d - > set_transform ( mesh_3d - > get_relative_transform ( mesh_3d - > get_parent ( ) ) ) ;
importer_mesh_3d - > set_skin ( mesh_3d - > get_skin ( ) ) ;
importer_mesh_3d - > set_skeleton_path ( mesh_3d - > get_skeleton_path ( ) ) ;
Ref < ArrayMesh > array_mesh_3d_mesh = mesh_3d - > get_mesh ( ) ;
if ( array_mesh_3d_mesh . is_valid ( ) ) {
// For the MeshInstance3D nodes, we need to convert the ArrayMesh to an ImporterMesh specially.
mesh - > set_name ( array_mesh_3d_mesh - > get_name ( ) ) ;
for ( int32_t blend_i = 0 ; blend_i < array_mesh_3d_mesh - > get_blend_shape_count ( ) ; blend_i + + ) {
mesh - > add_blend_shape ( array_mesh_3d_mesh - > get_blend_shape_name ( blend_i ) ) ;
}
for ( int32_t surface_i = 0 ; surface_i < array_mesh_3d_mesh - > get_surface_count ( ) ; surface_i + + ) {
mesh - > add_surface ( array_mesh_3d_mesh - > surface_get_primitive_type ( surface_i ) ,
array_mesh_3d_mesh - > surface_get_arrays ( surface_i ) ,
array_mesh_3d_mesh - > surface_get_blend_shape_arrays ( surface_i ) ,
array_mesh_3d_mesh - > surface_get_lods ( surface_i ) ,
array_mesh_3d_mesh - > surface_get_material ( surface_i ) ,
array_mesh_3d_mesh - > surface_get_name ( surface_i ) ,
array_mesh_3d_mesh - > surface_get_format ( surface_i ) ) ;
}
mesh - > set_blend_shape_mode ( array_mesh_3d_mesh - > get_blend_shape_mode ( ) ) ;
importer_mesh_3d - > set_mesh ( mesh ) ;
mesh_3d - > replace_by ( importer_mesh_3d ) ;
continue ;
}
Ref < Mesh > mesh_3d_mesh = mesh_3d - > get_mesh ( ) ;
if ( mesh_3d_mesh . is_valid ( ) ) {
// For the MeshInstance3D nodes, we need to convert the Mesh to an ImporterMesh specially.
mesh - > set_name ( mesh_3d_mesh - > get_name ( ) ) ;
for ( int32_t surface_i = 0 ; surface_i < mesh_3d_mesh - > get_surface_count ( ) ; surface_i + + ) {
mesh - > add_surface ( mesh_3d_mesh - > surface_get_primitive_type ( surface_i ) ,
mesh_3d_mesh - > surface_get_arrays ( surface_i ) ,
Array ( ) ,
mesh_3d_mesh - > surface_get_lods ( surface_i ) ,
mesh_3d_mesh - > surface_get_material ( surface_i ) ,
mesh_3d_mesh - > surface_get_material ( surface_i ) . is_valid ( ) ? mesh_3d_mesh - > surface_get_material ( surface_i ) - > get_name ( ) : String ( ) ,
mesh_3d_mesh - > surface_get_format ( surface_i ) ) ;
}
importer_mesh_3d - > set_mesh ( mesh ) ;
mesh_3d - > replace_by ( importer_mesh_3d ) ;
continue ;
}
}
2023-09-09 17:24:40 +02:00
ERR_FAIL_NULL_V ( scene , nullptr ) ;
2018-01-30 15:03:46 +01:00
return scene ;
}