2021-03-19 13:57:52 +01:00
/*************************************************************************/
/* scene_import_settings.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* 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. */
/*************************************************************************/
# include "scene_import_settings.h"
# include "editor/editor_node.h"
# include "editor/editor_scale.h"
2021-09-21 03:24:31 +02:00
# include "scene/3d/importer_mesh_instance_3d.h"
# include "scene/resources/importer_mesh.h"
2021-03-19 13:57:52 +01:00
# include "scene/resources/surface_tool.h"
class SceneImportSettingsData : public Object {
GDCLASS ( SceneImportSettingsData , Object )
friend class SceneImportSettings ;
Map < StringName , Variant > * settings = nullptr ;
Map < StringName , Variant > current ;
Map < StringName , Variant > defaults ;
List < ResourceImporter : : ImportOption > options ;
ResourceImporterScene : : InternalImportCategory category = ResourceImporterScene : : INTERNAL_IMPORT_CATEGORY_MAX ;
bool _set ( const StringName & p_name , const Variant & p_value ) {
if ( settings ) {
if ( defaults . has ( p_name ) & & defaults [ p_name ] = = p_value ) {
settings - > erase ( p_name ) ;
} else {
( * settings ) [ p_name ] = p_value ;
}
current [ p_name ] = p_value ;
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 ( ResourceImporterScene : : get_singleton ( ) - > get_internal_option_update_view_required ( category , p_name , current ) ) {
SceneImportSettings : : get_singleton ( ) - > update_view ( ) ;
}
2021-03-19 13:57:52 +01:00
return true ;
}
return false ;
}
bool _get ( const StringName & p_name , Variant & r_ret ) const {
if ( settings ) {
if ( settings - > has ( p_name ) ) {
r_ret = ( * settings ) [ p_name ] ;
return true ;
}
}
if ( defaults . has ( p_name ) ) {
r_ret = defaults [ p_name ] ;
return true ;
}
return false ;
}
void _get_property_list ( List < PropertyInfo > * p_list ) const {
2021-07-16 05:45:57 +02:00
for ( const ResourceImporter : : ImportOption & E : options ) {
if ( ResourceImporterScene : : get_singleton ( ) - > get_internal_option_visibility ( category , E . option . name , current ) ) {
p_list - > push_back ( E . option ) ;
2021-03-19 13:57:52 +01:00
}
}
}
} ;
void SceneImportSettings : : _fill_material ( Tree * p_tree , const Ref < Material > & p_material , TreeItem * p_parent ) {
String import_id ;
bool has_import_id = false ;
if ( p_material - > has_meta ( " import_id " ) ) {
import_id = p_material - > get_meta ( " import_id " ) ;
has_import_id = true ;
2021-12-09 10:42:46 +01:00
} else if ( ! p_material - > get_name ( ) . is_empty ( ) ) {
2021-03-19 13:57:52 +01:00
import_id = p_material - > get_name ( ) ;
has_import_id = true ;
} else {
import_id = " @MATERIAL: " + itos ( material_set . size ( ) ) ;
}
if ( ! material_map . has ( import_id ) ) {
MaterialData md ;
md . has_import_id = has_import_id ;
md . material = p_material ;
_load_default_subresource_settings ( md . settings , " materials " , import_id , ResourceImporterScene : : INTERNAL_IMPORT_CATEGORY_MATERIAL ) ;
material_map [ import_id ] = md ;
}
MaterialData & material_data = material_map [ import_id ] ;
2021-07-17 23:22:52 +02:00
Ref < Texture2D > icon = get_theme_icon ( SNAME ( " StandardMaterial3D " ) , SNAME ( " EditorIcons " ) ) ;
2021-03-19 13:57:52 +01:00
TreeItem * item = p_tree - > create_item ( p_parent ) ;
item - > set_text ( 0 , p_material - > get_name ( ) ) ;
item - > set_icon ( 0 , icon ) ;
bool created = false ;
if ( ! material_set . has ( p_material ) ) {
material_set . insert ( p_material ) ;
created = true ;
}
item - > set_meta ( " type " , " Material " ) ;
item - > set_meta ( " import_id " , import_id ) ;
item - > set_tooltip ( 0 , vformat ( TTR ( " Import ID: %s " ) , import_id ) ) ;
item - > set_selectable ( 0 , true ) ;
if ( p_tree = = scene_tree ) {
material_data . scene_node = item ;
} else if ( p_tree = = mesh_tree ) {
material_data . mesh_node = item ;
} else {
material_data . material_node = item ;
}
if ( created ) {
_fill_material ( material_tree , p_material , material_tree - > get_root ( ) ) ;
}
}
void SceneImportSettings : : _fill_mesh ( Tree * p_tree , const Ref < Mesh > & p_mesh , TreeItem * p_parent ) {
String import_id ;
bool has_import_id = false ;
if ( p_mesh - > has_meta ( " import_id " ) ) {
import_id = p_mesh - > get_meta ( " import_id " ) ;
has_import_id = true ;
2021-12-09 10:42:46 +01:00
} else if ( ! p_mesh - > get_name ( ) . is_empty ( ) ) {
2021-03-19 13:57:52 +01:00
import_id = p_mesh - > get_name ( ) ;
has_import_id = true ;
} else {
import_id = " @MESH: " + itos ( mesh_set . size ( ) ) ;
}
if ( ! mesh_map . has ( import_id ) ) {
MeshData md ;
md . has_import_id = has_import_id ;
md . mesh = p_mesh ;
_load_default_subresource_settings ( md . settings , " meshes " , import_id , ResourceImporterScene : : INTERNAL_IMPORT_CATEGORY_MESH ) ;
mesh_map [ import_id ] = md ;
}
MeshData & mesh_data = mesh_map [ import_id ] ;
2021-07-17 23:22:52 +02:00
Ref < Texture2D > icon = get_theme_icon ( SNAME ( " Mesh " ) , SNAME ( " EditorIcons " ) ) ;
2021-03-19 13:57:52 +01:00
TreeItem * item = p_tree - > create_item ( p_parent ) ;
item - > set_text ( 0 , p_mesh - > get_name ( ) ) ;
item - > set_icon ( 0 , icon ) ;
bool created = false ;
if ( ! mesh_set . has ( p_mesh ) ) {
mesh_set . insert ( p_mesh ) ;
created = true ;
}
item - > set_meta ( " type " , " Mesh " ) ;
item - > set_meta ( " import_id " , import_id ) ;
item - > set_tooltip ( 0 , vformat ( TTR ( " Import ID: %s " ) , import_id ) ) ;
item - > set_selectable ( 0 , true ) ;
if ( p_tree = = scene_tree ) {
mesh_data . scene_node = item ;
} else {
mesh_data . mesh_node = item ;
}
item - > set_collapsed ( true ) ;
for ( int i = 0 ; i < p_mesh - > get_surface_count ( ) ; i + + ) {
Ref < Material > mat = p_mesh - > surface_get_material ( i ) ;
if ( mat . is_valid ( ) ) {
_fill_material ( p_tree , mat , item ) ;
}
}
if ( created ) {
_fill_mesh ( mesh_tree , p_mesh , mesh_tree - > get_root ( ) ) ;
}
}
void SceneImportSettings : : _fill_animation ( Tree * p_tree , const Ref < Animation > & p_anim , const String & p_name , TreeItem * p_parent ) {
if ( ! animation_map . has ( p_name ) ) {
AnimationData ad ;
ad . animation = p_anim ;
_load_default_subresource_settings ( ad . settings , " animations " , p_name , ResourceImporterScene : : INTERNAL_IMPORT_CATEGORY_ANIMATION ) ;
animation_map [ p_name ] = ad ;
}
AnimationData & animation_data = animation_map [ p_name ] ;
2021-07-17 23:22:52 +02:00
Ref < Texture2D > icon = get_theme_icon ( SNAME ( " Animation " ) , SNAME ( " EditorIcons " ) ) ;
2021-03-19 13:57:52 +01:00
TreeItem * item = p_tree - > create_item ( p_parent ) ;
item - > set_text ( 0 , p_name ) ;
item - > set_icon ( 0 , icon ) ;
item - > set_meta ( " type " , " Animation " ) ;
item - > set_meta ( " import_id " , p_name ) ;
item - > set_selectable ( 0 , true ) ;
animation_data . scene_node = item ;
}
void SceneImportSettings : : _fill_scene ( Node * p_node , TreeItem * p_parent_item ) {
String import_id ;
if ( p_node - > has_meta ( " import_id " ) ) {
import_id = p_node - > get_meta ( " import_id " ) ;
} else {
import_id = " PATH: " + String ( scene - > get_path_to ( p_node ) ) ;
p_node - > set_meta ( " import_id " , import_id ) ;
}
2021-09-21 03:24:31 +02:00
ImporterMeshInstance3D * src_mesh_node = Object : : cast_to < ImporterMeshInstance3D > ( p_node ) ;
2021-03-19 13:57:52 +01:00
if ( src_mesh_node ) {
MeshInstance3D * mesh_node = memnew ( MeshInstance3D ) ;
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 ( ) ) {
2021-09-21 03:24:31 +02:00
Ref < ImporterMesh > editor_mesh = src_mesh_node - > get_mesh ( ) ;
2021-03-19 13:57:52 +01:00
mesh_node - > set_mesh ( editor_mesh - > get_mesh ( ) ) ;
}
p_node - > replace_by ( mesh_node ) ;
memdelete ( p_node ) ;
p_node = mesh_node ;
}
String type = p_node - > get_class ( ) ;
2021-07-17 23:22:52 +02:00
if ( ! has_theme_icon ( type , SNAME ( " EditorIcons " ) ) ) {
2021-03-19 13:57:52 +01:00
type = " Node3D " ;
}
2021-07-17 23:22:52 +02:00
Ref < Texture2D > icon = get_theme_icon ( type , SNAME ( " EditorIcons " ) ) ;
2021-03-19 13:57:52 +01:00
TreeItem * item = scene_tree - > create_item ( p_parent_item ) ;
item - > set_text ( 0 , p_node - > get_name ( ) ) ;
if ( p_node = = scene ) {
2021-07-17 23:22:52 +02:00
icon = get_theme_icon ( SNAME ( " PackedScene " ) , SNAME ( " EditorIcons " ) ) ;
2021-03-19 13:57:52 +01:00
item - > set_text ( 0 , " Scene " ) ;
}
item - > set_icon ( 0 , icon ) ;
item - > set_meta ( " type " , " Node " ) ;
item - > set_meta ( " class " , type ) ;
item - > set_meta ( " import_id " , import_id ) ;
item - > set_tooltip ( 0 , vformat ( TTR ( " Type: %s \n Import ID: %s " ) , type , import_id ) ) ;
item - > set_selectable ( 0 , true ) ;
if ( ! node_map . has ( import_id ) ) {
NodeData nd ;
if ( p_node ! = scene ) {
ResourceImporterScene : : InternalImportCategory category ;
if ( src_mesh_node ) {
category = ResourceImporterScene : : INTERNAL_IMPORT_CATEGORY_MESH_3D_NODE ;
} else if ( Object : : cast_to < AnimationPlayer > ( p_node ) ) {
category = ResourceImporterScene : : INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE ;
} else {
category = ResourceImporterScene : : INTERNAL_IMPORT_CATEGORY_NODE ;
}
_load_default_subresource_settings ( nd . settings , " nodes " , import_id , category ) ;
}
node_map [ import_id ] = nd ;
}
NodeData & node_data = node_map [ import_id ] ;
node_data . node = p_node ;
node_data . scene_node = item ;
AnimationPlayer * anim_node = Object : : cast_to < AnimationPlayer > ( p_node ) ;
if ( anim_node ) {
List < StringName > animations ;
anim_node - > get_animation_list ( & animations ) ;
2021-07-24 15:46:25 +02:00
for ( const StringName & E : animations ) {
2021-07-16 05:45:57 +02:00
_fill_animation ( scene_tree , anim_node - > get_animation ( E ) , E , item ) ;
2021-03-19 13:57:52 +01:00
}
}
for ( int i = 0 ; i < p_node - > get_child_count ( ) ; i + + ) {
_fill_scene ( p_node - > get_child ( i ) , item ) ;
}
MeshInstance3D * mesh_node = Object : : cast_to < MeshInstance3D > ( p_node ) ;
if ( mesh_node & & mesh_node - > get_mesh ( ) . is_valid ( ) ) {
_fill_mesh ( scene_tree , mesh_node - > get_mesh ( ) , item ) ;
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
// Add the collider view.
MeshInstance3D * collider_view = memnew ( MeshInstance3D ) ;
collider_view - > set_name ( " collider_view " ) ;
collider_view - > set_visible ( false ) ;
2021-10-21 16:46:07 +02:00
mesh_node - > add_child ( collider_view , 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
collider_view - > set_owner ( mesh_node ) ;
2020-10-17 07:08:21 +02:00
Transform3D accum_xform ;
2021-03-19 13:57:52 +01:00
Node3D * base = mesh_node ;
while ( base ) {
accum_xform = base - > get_transform ( ) * accum_xform ;
base = Object : : cast_to < Node3D > ( base - > get_parent ( ) ) ;
}
AABB aabb = accum_xform . xform ( mesh_node - > get_mesh ( ) - > get_aabb ( ) ) ;
if ( first_aabb ) {
contents_aabb = aabb ;
first_aabb = false ;
} else {
contents_aabb . merge_with ( aabb ) ;
}
}
}
void SceneImportSettings : : _update_scene ( ) {
scene_tree - > clear ( ) ;
material_tree - > clear ( ) ;
mesh_tree - > clear ( ) ;
2021-05-20 12:07:26 +02:00
//hidden roots
2021-03-19 13:57:52 +01:00
material_tree - > create_item ( ) ;
mesh_tree - > create_item ( ) ;
_fill_scene ( scene , nullptr ) ;
}
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 SceneImportSettings : : _update_view_gizmos ( ) {
for ( const KeyValue < String , NodeData > & e : node_map ) {
bool generate_collider = false ;
if ( e . value . settings . has ( SNAME ( " generate/physics " ) ) ) {
generate_collider = e . value . settings [ SNAME ( " generate/physics " ) ] ;
}
MeshInstance3D * mesh_node = Object : : cast_to < MeshInstance3D > ( e . value . node ) ;
if ( mesh_node = = nullptr | | mesh_node - > get_mesh ( ) . is_null ( ) ) {
// Nothing to do
continue ;
}
MeshInstance3D * collider_view = static_cast < MeshInstance3D * > ( mesh_node - > find_node ( " collider_view " ) ) ;
CRASH_COND_MSG ( collider_view = = nullptr , " This is unreachable, since the collider view is always created even when the collision is not used! If this is triggered there is a bug on the function `_fill_scene`. " ) ;
collider_view - > set_visible ( generate_collider ) ;
if ( generate_collider ) {
// This collider_view doesn't have a mesh so we need to generate a new one.
// Generate the mesh collider.
Vector < Ref < Shape3D > > shapes = ResourceImporterScene : : get_collision_shapes ( mesh_node - > get_mesh ( ) , e . value . settings ) ;
const Transform3D transform = ResourceImporterScene : : get_collision_shapes_transform ( e . value . settings ) ;
Ref < ArrayMesh > collider_view_mesh ;
collider_view_mesh . instantiate ( ) ;
for ( Ref < Shape3D > shape : shapes ) {
Ref < ArrayMesh > debug_shape_mesh ;
if ( shape . is_valid ( ) ) {
debug_shape_mesh = shape - > get_debug_mesh ( ) ;
}
if ( debug_shape_mesh . is_valid ( ) ) {
collider_view_mesh - > add_surface_from_arrays (
debug_shape_mesh - > surface_get_primitive_type ( 0 ) ,
debug_shape_mesh - > surface_get_arrays ( 0 ) ) ;
collider_view_mesh - > surface_set_material (
collider_view_mesh - > get_surface_count ( ) - 1 ,
collider_mat ) ;
}
}
collider_view - > set_mesh ( collider_view_mesh ) ;
collider_view - > set_transform ( transform ) ;
}
}
}
2021-03-19 13:57:52 +01:00
void SceneImportSettings : : _update_camera ( ) {
AABB camera_aabb ;
float rot_x = cam_rot_x ;
float rot_y = cam_rot_y ;
float zoom = cam_zoom ;
2021-12-09 10:42:46 +01:00
if ( selected_type = = " Node " | | selected_type . is_empty ( ) ) {
2021-03-19 13:57:52 +01:00
camera_aabb = contents_aabb ;
} else {
if ( mesh_preview - > get_mesh ( ) . is_valid ( ) ) {
camera_aabb = mesh_preview - > get_transform ( ) . xform ( mesh_preview - > get_mesh ( ) - > get_aabb ( ) ) ;
} else {
camera_aabb = AABB ( Vector3 ( - 1 , - 1 , - 1 ) , Vector3 ( 2 , 2 , 2 ) ) ;
}
if ( selected_type = = " Mesh " & & mesh_map . has ( selected_id ) ) {
const MeshData & md = mesh_map [ selected_id ] ;
rot_x = md . cam_rot_x ;
rot_y = md . cam_rot_y ;
zoom = md . cam_zoom ;
} else if ( selected_type = = " Material " & & material_map . has ( selected_id ) ) {
const MaterialData & md = material_map [ selected_id ] ;
rot_x = md . cam_rot_x ;
rot_y = md . cam_rot_y ;
zoom = md . cam_zoom ;
}
}
2021-09-20 20:48:52 +02:00
Vector3 center = camera_aabb . get_center ( ) ;
2021-03-19 13:57:52 +01:00
float camera_size = camera_aabb . get_longest_axis_size ( ) ;
camera - > set_orthogonal ( camera_size * zoom , 0.0001 , camera_size * 2 ) ;
2020-10-17 07:08:21 +02:00
Transform3D xf ;
2021-03-19 13:57:52 +01:00
xf . basis = Basis ( Vector3 ( 0 , 1 , 0 ) , rot_y ) * Basis ( Vector3 ( 1 , 0 , 0 ) , rot_x ) ;
xf . origin = center ;
xf . translate ( 0 , 0 , camera_size ) ;
camera - > set_transform ( xf ) ;
}
void SceneImportSettings : : _load_default_subresource_settings ( Map < StringName , Variant > & settings , const String & p_type , const String & p_import_id , ResourceImporterScene : : InternalImportCategory p_category ) {
if ( base_subresource_settings . has ( p_type ) ) {
Dictionary d = base_subresource_settings [ p_type ] ;
if ( d . has ( p_import_id ) ) {
d = d [ p_import_id ] ;
List < ResourceImporterScene : : ImportOption > options ;
ResourceImporterScene : : get_singleton ( ) - > get_internal_import_options ( p_category , & options ) ;
2021-07-24 15:46:25 +02:00
for ( const ResourceImporterScene : : ImportOption & E : options ) {
2021-07-16 05:45:57 +02:00
String key = E . option . name ;
2021-03-19 13:57:52 +01:00
if ( d . has ( key ) ) {
settings [ key ] = d [ key ] ;
}
}
}
}
}
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 SceneImportSettings : : update_view ( ) {
_update_view_gizmos ( ) ;
}
2021-03-19 13:57:52 +01:00
void SceneImportSettings : : open_settings ( const String & p_path ) {
if ( scene ) {
memdelete ( scene ) ;
scene = nullptr ;
}
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
scene_import_settings_data - > settings = nullptr ;
2021-03-19 13:57:52 +01:00
scene = ResourceImporterScene : : get_singleton ( ) - > pre_import ( p_path ) ;
if ( scene = = nullptr ) {
EditorNode : : get_singleton ( ) - > show_warning ( TTR ( " Error opening scene " ) ) ;
return ;
}
base_path = p_path ;
material_set . clear ( ) ;
mesh_set . clear ( ) ;
material_map . clear ( ) ;
mesh_map . clear ( ) ;
node_map . clear ( ) ;
defaults . clear ( ) ;
selected_id = " " ;
selected_type = " " ;
cam_rot_x = - Math_PI / 4 ;
cam_rot_y = - Math_PI / 4 ;
cam_zoom = 1 ;
{
base_subresource_settings . clear ( ) ;
Ref < ConfigFile > config ;
2021-06-18 00:03:09 +02:00
config . instantiate ( ) ;
2021-03-19 13:57:52 +01:00
Error err = config - > load ( p_path + " .import " ) ;
if ( err = = OK ) {
List < String > keys ;
config - > get_section_keys ( " params " , & keys ) ;
2021-07-24 15:46:25 +02:00
for ( const String & E : keys ) {
2021-07-16 05:45:57 +02:00
Variant value = config - > get_value ( " params " , E ) ;
if ( E = = " _subresources " ) {
2021-03-19 13:57:52 +01:00
base_subresource_settings = value ;
} else {
2021-07-16 05:45:57 +02:00
defaults [ E ] = value ;
2021-03-19 13:57:52 +01:00
}
}
}
}
first_aabb = true ;
_update_scene ( ) ;
base_viewport - > add_child ( scene ) ;
if ( first_aabb ) {
contents_aabb = AABB ( Vector3 ( - 1 , - 1 , - 1 ) , Vector3 ( 2 , 2 , 2 ) ) ;
first_aabb = false ;
}
popup_centered_ratio ( ) ;
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
_update_view_gizmos ( ) ;
2021-03-19 13:57:52 +01:00
_update_camera ( ) ;
set_title ( vformat ( TTR ( " Advanced Import Settings for '%s' " ) , base_path . get_file ( ) ) ) ;
}
SceneImportSettings * SceneImportSettings : : singleton = nullptr ;
SceneImportSettings * SceneImportSettings : : get_singleton ( ) {
return singleton ;
}
void SceneImportSettings : : _select ( Tree * p_from , String p_type , String p_id ) {
selecting = true ;
if ( p_type = = " Node " ) {
node_selected - > hide ( ) ; //always hide just in case
mesh_preview - > hide ( ) ;
if ( Object : : cast_to < Node3D > ( scene ) ) {
Object : : cast_to < Node3D > ( scene ) - > show ( ) ;
}
//NodeData &nd=node_map[p_id];
material_tree - > deselect_all ( ) ;
mesh_tree - > deselect_all ( ) ;
NodeData & nd = node_map [ p_id ] ;
MeshInstance3D * mi = Object : : cast_to < MeshInstance3D > ( nd . node ) ;
if ( mi ) {
Ref < Mesh > base_mesh = mi - > get_mesh ( ) ;
if ( base_mesh . is_valid ( ) ) {
AABB aabb = base_mesh - > get_aabb ( ) ;
2020-10-17 07:08:21 +02:00
Transform3D aabb_xf ;
2021-03-19 13:57:52 +01:00
aabb_xf . basis . scale ( aabb . size ) ;
aabb_xf . origin = aabb . position ;
aabb_xf = mi - > get_global_transform ( ) * aabb_xf ;
node_selected - > set_transform ( aabb_xf ) ;
node_selected - > show ( ) ;
}
}
if ( nd . node = = scene ) {
scene_import_settings_data - > settings = & defaults ;
scene_import_settings_data - > category = ResourceImporterScene : : INTERNAL_IMPORT_CATEGORY_MAX ;
} else {
scene_import_settings_data - > settings = & nd . settings ;
if ( mi ) {
scene_import_settings_data - > category = ResourceImporterScene : : INTERNAL_IMPORT_CATEGORY_MESH_3D_NODE ;
} else if ( Object : : cast_to < AnimationPlayer > ( nd . node ) ) {
scene_import_settings_data - > category = ResourceImporterScene : : INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE ;
} else {
scene_import_settings_data - > category = ResourceImporterScene : : INTERNAL_IMPORT_CATEGORY_NODE ;
}
}
} else if ( p_type = = " Animation " ) {
node_selected - > hide ( ) ; //always hide just in case
mesh_preview - > hide ( ) ;
if ( Object : : cast_to < Node3D > ( scene ) ) {
Object : : cast_to < Node3D > ( scene ) - > show ( ) ;
}
//NodeData &nd=node_map[p_id];
material_tree - > deselect_all ( ) ;
mesh_tree - > deselect_all ( ) ;
AnimationData & ad = animation_map [ p_id ] ;
scene_import_settings_data - > settings = & ad . settings ;
scene_import_settings_data - > category = ResourceImporterScene : : INTERNAL_IMPORT_CATEGORY_ANIMATION ;
} else if ( p_type = = " Mesh " ) {
node_selected - > hide ( ) ;
if ( Object : : cast_to < Node3D > ( scene ) ) {
Object : : cast_to < Node3D > ( scene ) - > hide ( ) ;
}
MeshData & md = mesh_map [ p_id ] ;
if ( p_from ! = mesh_tree ) {
md . mesh_node - > uncollapse_tree ( ) ;
md . mesh_node - > select ( 0 ) ;
mesh_tree - > ensure_cursor_is_visible ( ) ;
}
if ( p_from ! = scene_tree ) {
md . scene_node - > uncollapse_tree ( ) ;
md . scene_node - > select ( 0 ) ;
scene_tree - > ensure_cursor_is_visible ( ) ;
}
mesh_preview - > set_mesh ( md . mesh ) ;
mesh_preview - > show ( ) ;
material_tree - > deselect_all ( ) ;
scene_import_settings_data - > settings = & md . settings ;
scene_import_settings_data - > category = ResourceImporterScene : : INTERNAL_IMPORT_CATEGORY_MESH ;
} else if ( p_type = = " Material " ) {
node_selected - > hide ( ) ;
if ( Object : : cast_to < Node3D > ( scene ) ) {
Object : : cast_to < Node3D > ( scene ) - > hide ( ) ;
}
mesh_preview - > show ( ) ;
MaterialData & md = material_map [ p_id ] ;
material_preview - > set_material ( md . material ) ;
mesh_preview - > set_mesh ( material_preview ) ;
if ( p_from ! = mesh_tree ) {
md . mesh_node - > uncollapse_tree ( ) ;
md . mesh_node - > select ( 0 ) ;
mesh_tree - > ensure_cursor_is_visible ( ) ;
}
if ( p_from ! = scene_tree ) {
md . scene_node - > uncollapse_tree ( ) ;
md . scene_node - > select ( 0 ) ;
scene_tree - > ensure_cursor_is_visible ( ) ;
}
if ( p_from ! = material_tree ) {
md . material_node - > uncollapse_tree ( ) ;
md . material_node - > select ( 0 ) ;
material_tree - > ensure_cursor_is_visible ( ) ;
}
scene_import_settings_data - > settings = & md . settings ;
scene_import_settings_data - > category = ResourceImporterScene : : INTERNAL_IMPORT_CATEGORY_MATERIAL ;
}
selected_type = p_type ;
selected_id = p_id ;
selecting = false ;
_update_camera ( ) ;
List < ResourceImporter : : ImportOption > options ;
if ( scene_import_settings_data - > category = = ResourceImporterScene : : INTERNAL_IMPORT_CATEGORY_MAX ) {
2021-11-14 18:02:38 +01:00
ResourceImporterScene : : get_singleton ( ) - > get_import_options ( base_path , & options ) ;
2021-03-19 13:57:52 +01:00
} else {
ResourceImporterScene : : get_singleton ( ) - > get_internal_import_options ( scene_import_settings_data - > category , & options ) ;
}
scene_import_settings_data - > defaults . clear ( ) ;
scene_import_settings_data - > current . clear ( ) ;
2021-07-24 15:46:25 +02:00
for ( const ResourceImporter : : ImportOption & E : options ) {
2021-07-16 05:45:57 +02:00
scene_import_settings_data - > defaults [ E . option . name ] = E . default_value ;
2021-03-19 13:57:52 +01:00
//needed for visibility toggling (fails if something is missing)
2021-07-16 05:45:57 +02:00
if ( scene_import_settings_data - > settings - > has ( E . option . name ) ) {
scene_import_settings_data - > current [ E . option . name ] = ( * scene_import_settings_data - > settings ) [ E . option . name ] ;
2021-03-19 13:57:52 +01:00
} else {
2021-07-16 05:45:57 +02:00
scene_import_settings_data - > current [ E . option . name ] = E . default_value ;
2021-03-19 13:57:52 +01:00
}
}
scene_import_settings_data - > options = options ;
inspector - > edit ( scene_import_settings_data ) ;
scene_import_settings_data - > notify_property_list_changed ( ) ;
}
void SceneImportSettings : : _material_tree_selected ( ) {
if ( selecting ) {
return ;
}
TreeItem * item = material_tree - > get_selected ( ) ;
String type = item - > get_meta ( " type " ) ;
String import_id = item - > get_meta ( " import_id " ) ;
_select ( material_tree , type , import_id ) ;
}
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
2021-03-19 13:57:52 +01:00
void SceneImportSettings : : _mesh_tree_selected ( ) {
if ( selecting ) {
return ;
}
TreeItem * item = mesh_tree - > get_selected ( ) ;
String type = item - > get_meta ( " type " ) ;
String import_id = item - > get_meta ( " import_id " ) ;
_select ( mesh_tree , type , import_id ) ;
}
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
2021-03-19 13:57:52 +01:00
void SceneImportSettings : : _scene_tree_selected ( ) {
if ( selecting ) {
return ;
}
TreeItem * item = scene_tree - > get_selected ( ) ;
String type = item - > get_meta ( " type " ) ;
String import_id = item - > get_meta ( " import_id " ) ;
_select ( scene_tree , type , import_id ) ;
}
void SceneImportSettings : : _viewport_input ( const Ref < InputEvent > & p_input ) {
float * rot_x = & cam_rot_x ;
float * rot_y = & cam_rot_y ;
float * zoom = & cam_zoom ;
if ( selected_type = = " Mesh " & & mesh_map . has ( selected_id ) ) {
MeshData & md = mesh_map [ selected_id ] ;
rot_x = & md . cam_rot_x ;
rot_y = & md . cam_rot_y ;
zoom = & md . cam_zoom ;
} else if ( selected_type = = " Material " & & material_map . has ( selected_id ) ) {
MaterialData & md = material_map [ selected_id ] ;
rot_x = & md . cam_rot_x ;
rot_y = & md . cam_rot_y ;
zoom = & md . cam_zoom ;
}
Ref < InputEventMouseMotion > mm = p_input ;
2021-08-13 23:31:57 +02:00
if ( mm . is_valid ( ) & & ( mm - > get_button_mask ( ) & MouseButton : : MASK_LEFT ) ! = MouseButton : : NONE ) {
2021-03-19 13:57:52 +01:00
( * rot_x ) - = mm - > get_relative ( ) . y * 0.01 * EDSCALE ;
( * rot_y ) - = mm - > get_relative ( ) . x * 0.01 * EDSCALE ;
( * rot_x ) = CLAMP ( ( * rot_x ) , - Math_PI / 2 , Math_PI / 2 ) ;
_update_camera ( ) ;
}
Ref < InputEventMouseButton > mb = p_input ;
2021-08-13 23:31:57 +02:00
if ( mb . is_valid ( ) & & mb - > get_button_index ( ) = = MouseButton : : WHEEL_DOWN ) {
2021-03-19 13:57:52 +01:00
( * zoom ) * = 1.1 ;
if ( ( * zoom ) > 10.0 ) {
( * zoom ) = 10.0 ;
}
_update_camera ( ) ;
}
2021-08-13 23:31:57 +02:00
if ( mb . is_valid ( ) & & mb - > get_button_index ( ) = = MouseButton : : WHEEL_UP ) {
2021-03-19 13:57:52 +01:00
( * zoom ) / = 1.1 ;
if ( ( * zoom ) < 0.1 ) {
( * zoom ) = 0.1 ;
}
_update_camera ( ) ;
}
}
void SceneImportSettings : : _re_import ( ) {
Map < StringName , Variant > main_settings ;
main_settings = defaults ;
main_settings . erase ( " _subresources " ) ;
Dictionary nodes ;
Dictionary materials ;
Dictionary meshes ;
Dictionary animations ;
Dictionary subresources ;
2021-08-09 22:13:42 +02:00
for ( KeyValue < String , NodeData > & E : node_map ) {
if ( E . value . settings . size ( ) ) {
2021-03-19 13:57:52 +01:00
Dictionary d ;
2021-08-09 22:13:42 +02:00
for ( const KeyValue < StringName , Variant > & F : E . value . settings ) {
d [ String ( F . key ) ] = F . value ;
2021-03-19 13:57:52 +01:00
}
2021-08-09 22:13:42 +02:00
nodes [ E . key ] = d ;
2021-03-19 13:57:52 +01:00
}
}
if ( nodes . size ( ) ) {
subresources [ " nodes " ] = nodes ;
}
2021-08-09 22:13:42 +02:00
for ( KeyValue < String , MaterialData > & E : material_map ) {
if ( E . value . settings . size ( ) ) {
2021-03-19 13:57:52 +01:00
Dictionary d ;
2021-08-09 22:13:42 +02:00
for ( const KeyValue < StringName , Variant > & F : E . value . settings ) {
d [ String ( F . key ) ] = F . value ;
2021-03-19 13:57:52 +01:00
}
2021-08-09 22:13:42 +02:00
materials [ E . key ] = d ;
2021-03-19 13:57:52 +01:00
}
}
if ( materials . size ( ) ) {
subresources [ " materials " ] = materials ;
}
2021-08-09 22:13:42 +02:00
for ( KeyValue < String , MeshData > & E : mesh_map ) {
if ( E . value . settings . size ( ) ) {
2021-03-19 13:57:52 +01:00
Dictionary d ;
2021-08-09 22:13:42 +02:00
for ( const KeyValue < StringName , Variant > & F : E . value . settings ) {
d [ String ( F . key ) ] = F . value ;
2021-03-19 13:57:52 +01:00
}
2021-08-09 22:13:42 +02:00
meshes [ E . key ] = d ;
2021-03-19 13:57:52 +01:00
}
}
if ( meshes . size ( ) ) {
subresources [ " meshes " ] = meshes ;
}
2021-08-09 22:13:42 +02:00
for ( KeyValue < String , AnimationData > & E : animation_map ) {
if ( E . value . settings . size ( ) ) {
2021-03-19 13:57:52 +01:00
Dictionary d ;
2021-08-09 22:13:42 +02:00
for ( const KeyValue < StringName , Variant > & F : E . value . settings ) {
d [ String ( F . key ) ] = F . value ;
2021-03-19 13:57:52 +01:00
}
2021-08-09 22:13:42 +02:00
animations [ E . key ] = d ;
2021-03-19 13:57:52 +01:00
}
}
if ( animations . size ( ) ) {
subresources [ " animations " ] = animations ;
}
if ( subresources . size ( ) ) {
main_settings [ " _subresources " ] = subresources ;
}
EditorFileSystem : : get_singleton ( ) - > reimport_file_with_custom_parameters ( base_path , " scene " , main_settings ) ;
}
void SceneImportSettings : : _notification ( int p_what ) {
if ( p_what = = NOTIFICATION_READY ) {
connect ( " confirmed " , callable_mp ( this , & SceneImportSettings : : _re_import ) ) ;
}
}
void SceneImportSettings : : _menu_callback ( int p_id ) {
switch ( p_id ) {
case ACTION_EXTRACT_MATERIALS : {
save_path - > set_text ( TTR ( " Select folder to extract material resources " ) ) ;
external_extension_type - > select ( 0 ) ;
} break ;
case ACTION_CHOOSE_MESH_SAVE_PATHS : {
save_path - > set_text ( TTR ( " Select folder where mesh resources will save on import " ) ) ;
external_extension_type - > select ( 1 ) ;
} break ;
case ACTION_CHOOSE_ANIMATION_SAVE_PATHS : {
save_path - > set_text ( TTR ( " Select folder where animations will save on import " ) ) ;
external_extension_type - > select ( 1 ) ;
} break ;
}
save_path - > set_current_dir ( base_path . get_base_dir ( ) ) ;
current_action = p_id ;
save_path - > popup_centered_ratio ( ) ;
}
void SceneImportSettings : : _save_path_changed ( const String & p_path ) {
save_path_item - > set_text ( 1 , p_path ) ;
if ( FileAccess : : exists ( p_path ) ) {
save_path_item - > set_text ( 2 , " Warning: File exists " ) ;
save_path_item - > set_tooltip ( 2 , TTR ( " Existing file with the same name will be replaced. " ) ) ;
2021-07-17 23:22:52 +02:00
save_path_item - > set_icon ( 2 , get_theme_icon ( SNAME ( " StatusWarning " ) , SNAME ( " EditorIcons " ) ) ) ;
2021-03-19 13:57:52 +01:00
} else {
save_path_item - > set_text ( 2 , " Will create new File " ) ;
2021-07-17 23:22:52 +02:00
save_path_item - > set_icon ( 2 , get_theme_icon ( SNAME ( " StatusSuccess " ) , SNAME ( " EditorIcons " ) ) ) ;
2021-03-19 13:57:52 +01:00
}
}
void SceneImportSettings : : _browse_save_callback ( Object * p_item , int p_column , int p_id ) {
TreeItem * item = Object : : cast_to < TreeItem > ( p_item ) ;
String path = item - > get_text ( 1 ) ;
item_save_path - > set_current_file ( path ) ;
save_path_item = item ;
item_save_path - > popup_centered_ratio ( ) ;
}
void SceneImportSettings : : _save_dir_callback ( const String & p_path ) {
external_path_tree - > clear ( ) ;
TreeItem * root = external_path_tree - > create_item ( ) ;
save_path_items . clear ( ) ;
switch ( current_action ) {
case ACTION_EXTRACT_MATERIALS : {
2021-08-09 22:13:42 +02:00
for ( const KeyValue < String , MaterialData > & E : material_map ) {
MaterialData & md = material_map [ E . key ] ;
2021-03-19 13:57:52 +01:00
TreeItem * item = external_path_tree - > create_item ( root ) ;
String name = md . material_node - > get_text ( 0 ) ;
item - > set_cell_mode ( 0 , TreeItem : : CELL_MODE_CHECK ) ;
2021-07-17 23:22:52 +02:00
item - > set_icon ( 0 , get_theme_icon ( SNAME ( " StandardMaterial3D " ) , SNAME ( " EditorIcons " ) ) ) ;
2021-03-19 13:57:52 +01:00
item - > set_text ( 0 , name ) ;
if ( md . has_import_id ) {
if ( md . settings . has ( " use_external/enabled " ) & & bool ( md . settings [ " use_external/enabled " ] ) ) {
item - > set_text ( 2 , " Already External " ) ;
item - > set_tooltip ( 2 , TTR ( " This material already references an external file, no action will be taken. \n Disable the external property for it to be extracted again. " ) ) ;
} else {
2021-08-09 22:13:42 +02:00
item - > set_metadata ( 0 , E . key ) ;
2021-03-19 13:57:52 +01:00
item - > set_editable ( 0 , true ) ;
item - > set_checked ( 0 , true ) ;
String path = p_path . plus_file ( name ) ;
if ( external_extension_type - > get_selected ( ) = = 0 ) {
path + = " .tres " ;
} else {
path + = " .res " ;
}
item - > set_text ( 1 , path ) ;
if ( FileAccess : : exists ( path ) ) {
item - > set_text ( 2 , " Warning: File exists " ) ;
item - > set_tooltip ( 2 , TTR ( " Existing file with the same name will be replaced. " ) ) ;
2021-07-17 23:22:52 +02:00
item - > set_icon ( 2 , get_theme_icon ( SNAME ( " StatusWarning " ) , SNAME ( " EditorIcons " ) ) ) ;
2021-03-19 13:57:52 +01:00
} else {
item - > set_text ( 2 , " Will create new File " ) ;
2021-07-17 23:22:52 +02:00
item - > set_icon ( 2 , get_theme_icon ( SNAME ( " StatusSuccess " ) , SNAME ( " EditorIcons " ) ) ) ;
2021-03-19 13:57:52 +01:00
}
2021-07-17 23:22:52 +02:00
item - > add_button ( 1 , get_theme_icon ( SNAME ( " Folder " ) , SNAME ( " EditorIcons " ) ) ) ;
2021-03-19 13:57:52 +01:00
}
} else {
item - > set_text ( 2 , " No import ID " ) ;
item - > set_tooltip ( 2 , TTR ( " Material has no name nor any other way to identify on re-import. \n Please name it or ensure it is exported with an unique ID. " ) ) ;
2021-07-17 23:22:52 +02:00
item - > set_icon ( 2 , get_theme_icon ( SNAME ( " StatusError " ) , SNAME ( " EditorIcons " ) ) ) ;
2021-03-19 13:57:52 +01:00
}
save_path_items . push_back ( item ) ;
}
external_paths - > set_title ( TTR ( " Extract Materials to Resource Files " ) ) ;
external_paths - > get_ok_button ( ) - > set_text ( TTR ( " Extract " ) ) ;
} break ;
case ACTION_CHOOSE_MESH_SAVE_PATHS : {
2021-08-09 22:13:42 +02:00
for ( const KeyValue < String , MeshData > & E : mesh_map ) {
MeshData & md = mesh_map [ E . key ] ;
2021-03-19 13:57:52 +01:00
TreeItem * item = external_path_tree - > create_item ( root ) ;
String name = md . mesh_node - > get_text ( 0 ) ;
item - > set_cell_mode ( 0 , TreeItem : : CELL_MODE_CHECK ) ;
2021-07-17 23:22:52 +02:00
item - > set_icon ( 0 , get_theme_icon ( SNAME ( " Mesh " ) , SNAME ( " EditorIcons " ) ) ) ;
2021-03-19 13:57:52 +01:00
item - > set_text ( 0 , name ) ;
if ( md . has_import_id ) {
if ( md . settings . has ( " save_to_file/enabled " ) & & bool ( md . settings [ " save_to_file/enabled " ] ) ) {
item - > set_text ( 2 , " Already Saving " ) ;
item - > set_tooltip ( 2 , TTR ( " This mesh already saves to an external resource, no action will be taken. " ) ) ;
} else {
2021-08-09 22:13:42 +02:00
item - > set_metadata ( 0 , E . key ) ;
2021-03-19 13:57:52 +01:00
item - > set_editable ( 0 , true ) ;
item - > set_checked ( 0 , true ) ;
String path = p_path . plus_file ( name ) ;
if ( external_extension_type - > get_selected ( ) = = 0 ) {
path + = " .tres " ;
} else {
path + = " .res " ;
}
item - > set_text ( 1 , path ) ;
if ( FileAccess : : exists ( path ) ) {
item - > set_text ( 2 , " Warning: File exists " ) ;
item - > set_tooltip ( 2 , TTR ( " Existing file with the same name will be replaced on import. " ) ) ;
2021-07-17 23:22:52 +02:00
item - > set_icon ( 2 , get_theme_icon ( SNAME ( " StatusWarning " ) , SNAME ( " EditorIcons " ) ) ) ;
2021-03-19 13:57:52 +01:00
} else {
item - > set_text ( 2 , " Will save to new File " ) ;
2021-07-17 23:22:52 +02:00
item - > set_icon ( 2 , get_theme_icon ( SNAME ( " StatusSuccess " ) , SNAME ( " EditorIcons " ) ) ) ;
2021-03-19 13:57:52 +01:00
}
2021-07-17 23:22:52 +02:00
item - > add_button ( 1 , get_theme_icon ( SNAME ( " Folder " ) , SNAME ( " EditorIcons " ) ) ) ;
2021-03-19 13:57:52 +01:00
}
} else {
item - > set_text ( 2 , " No import ID " ) ;
item - > set_tooltip ( 2 , TTR ( " Mesh has no name nor any other way to identify on re-import. \n Please name it or ensure it is exported with an unique ID. " ) ) ;
2021-07-17 23:22:52 +02:00
item - > set_icon ( 2 , get_theme_icon ( SNAME ( " StatusError " ) , SNAME ( " EditorIcons " ) ) ) ;
2021-03-19 13:57:52 +01:00
}
save_path_items . push_back ( item ) ;
}
external_paths - > set_title ( TTR ( " Set paths to save meshes as resource files on Reimport " ) ) ;
external_paths - > get_ok_button ( ) - > set_text ( TTR ( " Set Paths " ) ) ;
} break ;
case ACTION_CHOOSE_ANIMATION_SAVE_PATHS : {
2021-08-09 22:13:42 +02:00
for ( const KeyValue < String , AnimationData > & E : animation_map ) {
AnimationData & ad = animation_map [ E . key ] ;
2021-03-19 13:57:52 +01:00
TreeItem * item = external_path_tree - > create_item ( root ) ;
String name = ad . scene_node - > get_text ( 0 ) ;
item - > set_cell_mode ( 0 , TreeItem : : CELL_MODE_CHECK ) ;
2021-07-17 23:22:52 +02:00
item - > set_icon ( 0 , get_theme_icon ( SNAME ( " Animation " ) , SNAME ( " EditorIcons " ) ) ) ;
2021-03-19 13:57:52 +01:00
item - > set_text ( 0 , name ) ;
if ( ad . settings . has ( " save_to_file/enabled " ) & & bool ( ad . settings [ " save_to_file/enabled " ] ) ) {
item - > set_text ( 2 , " Already Saving " ) ;
item - > set_tooltip ( 2 , TTR ( " This animation already saves to an external resource, no action will be taken. " ) ) ;
} else {
2021-08-09 22:13:42 +02:00
item - > set_metadata ( 0 , E . key ) ;
2021-03-19 13:57:52 +01:00
item - > set_editable ( 0 , true ) ;
item - > set_checked ( 0 , true ) ;
String path = p_path . plus_file ( name ) ;
if ( external_extension_type - > get_selected ( ) = = 0 ) {
path + = " .tres " ;
} else {
path + = " .res " ;
}
item - > set_text ( 1 , path ) ;
if ( FileAccess : : exists ( path ) ) {
item - > set_text ( 2 , " Warning: File exists " ) ;
item - > set_tooltip ( 2 , TTR ( " Existing file with the same name will be replaced on import. " ) ) ;
2021-07-17 23:22:52 +02:00
item - > set_icon ( 2 , get_theme_icon ( SNAME ( " StatusWarning " ) , SNAME ( " EditorIcons " ) ) ) ;
2021-03-19 13:57:52 +01:00
} else {
item - > set_text ( 2 , " Will save to new File " ) ;
2021-07-17 23:22:52 +02:00
item - > set_icon ( 2 , get_theme_icon ( SNAME ( " StatusSuccess " ) , SNAME ( " EditorIcons " ) ) ) ;
2021-03-19 13:57:52 +01:00
}
2021-07-17 23:22:52 +02:00
item - > add_button ( 1 , get_theme_icon ( SNAME ( " Folder " ) , SNAME ( " EditorIcons " ) ) ) ;
2021-03-19 13:57:52 +01:00
}
save_path_items . push_back ( item ) ;
}
external_paths - > set_title ( TTR ( " Set paths to save animations as resource files on Reimport " ) ) ;
external_paths - > get_ok_button ( ) - > set_text ( TTR ( " Set Paths " ) ) ;
} break ;
}
external_paths - > popup_centered_ratio ( ) ;
}
void SceneImportSettings : : _save_dir_confirm ( ) {
for ( int i = 0 ; i < save_path_items . size ( ) ; i + + ) {
TreeItem * item = save_path_items [ i ] ;
if ( ! item - > is_checked ( 0 ) ) {
continue ; //ignore
}
String path = item - > get_text ( 1 ) ;
if ( ! path . is_resource_file ( ) ) {
continue ;
}
String id = item - > get_metadata ( 0 ) ;
switch ( current_action ) {
case ACTION_EXTRACT_MATERIALS : {
ERR_CONTINUE ( ! material_map . has ( id ) ) ;
MaterialData & md = material_map [ id ] ;
Error err = ResourceSaver : : save ( path , md . material ) ;
if ( err ! = OK ) {
EditorNode : : get_singleton ( ) - > add_io_error ( TTR ( " Can't make material external to file, write error: " ) + " \n \t " + path ) ;
continue ;
}
md . settings [ " use_external/enabled " ] = true ;
md . settings [ " use_external/path " ] = path ;
} break ;
case ACTION_CHOOSE_MESH_SAVE_PATHS : {
ERR_CONTINUE ( ! mesh_map . has ( id ) ) ;
MeshData & md = mesh_map [ id ] ;
md . settings [ " save_to_file/enabled " ] = true ;
md . settings [ " save_to_file/path " ] = path ;
} break ;
case ACTION_CHOOSE_ANIMATION_SAVE_PATHS : {
ERR_CONTINUE ( ! animation_map . has ( id ) ) ;
AnimationData & ad = animation_map [ id ] ;
ad . settings [ " save_to_file/enabled " ] = true ;
ad . settings [ " save_to_file/path " ] = path ;
} break ;
}
}
if ( current_action = = ACTION_EXTRACT_MATERIALS ) {
//as this happens right now, the scene needs to be saved and reimported.
_re_import ( ) ;
open_settings ( base_path ) ;
} else {
scene_import_settings_data - > notify_property_list_changed ( ) ;
}
}
SceneImportSettings : : SceneImportSettings ( ) {
singleton = this ;
VBoxContainer * main_vb = memnew ( VBoxContainer ) ;
add_child ( main_vb ) ;
HBoxContainer * menu_hb = memnew ( HBoxContainer ) ;
main_vb - > add_child ( menu_hb ) ;
action_menu = memnew ( MenuButton ) ;
action_menu - > set_text ( TTR ( " Actions... " ) ) ;
menu_hb - > add_child ( action_menu ) ;
action_menu - > get_popup ( ) - > add_item ( TTR ( " Extract Materials " ) , ACTION_EXTRACT_MATERIALS ) ;
action_menu - > get_popup ( ) - > add_separator ( ) ;
action_menu - > get_popup ( ) - > add_item ( TTR ( " Set Animation Save Paths " ) , ACTION_CHOOSE_ANIMATION_SAVE_PATHS ) ;
action_menu - > get_popup ( ) - > add_item ( TTR ( " Set Mesh Save Paths " ) , ACTION_CHOOSE_MESH_SAVE_PATHS ) ;
action_menu - > get_popup ( ) - > connect ( " id_pressed " , callable_mp ( this , & SceneImportSettings : : _menu_callback ) ) ;
tree_split = memnew ( HSplitContainer ) ;
main_vb - > add_child ( tree_split ) ;
tree_split - > set_v_size_flags ( Control : : SIZE_EXPAND_FILL ) ;
data_mode = memnew ( TabContainer ) ;
tree_split - > add_child ( data_mode ) ;
data_mode - > set_custom_minimum_size ( Size2 ( 300 * EDSCALE , 0 ) ) ;
property_split = memnew ( HSplitContainer ) ;
tree_split - > add_child ( property_split ) ;
property_split - > set_h_size_flags ( Control : : SIZE_EXPAND_FILL ) ;
scene_tree = memnew ( Tree ) ;
scene_tree - > set_name ( TTR ( " Scene " ) ) ;
data_mode - > add_child ( scene_tree ) ;
scene_tree - > connect ( " cell_selected " , callable_mp ( this , & SceneImportSettings : : _scene_tree_selected ) ) ;
mesh_tree = memnew ( Tree ) ;
mesh_tree - > set_name ( TTR ( " Meshes " ) ) ;
data_mode - > add_child ( mesh_tree ) ;
mesh_tree - > set_hide_root ( true ) ;
mesh_tree - > connect ( " cell_selected " , callable_mp ( this , & SceneImportSettings : : _mesh_tree_selected ) ) ;
material_tree = memnew ( Tree ) ;
material_tree - > set_name ( TTR ( " Materials " ) ) ;
data_mode - > add_child ( material_tree ) ;
material_tree - > connect ( " cell_selected " , callable_mp ( this , & SceneImportSettings : : _material_tree_selected ) ) ;
material_tree - > set_hide_root ( true ) ;
SubViewportContainer * vp_container = memnew ( SubViewportContainer ) ;
vp_container - > set_h_size_flags ( Control : : SIZE_EXPAND_FILL ) ;
vp_container - > set_custom_minimum_size ( Size2 ( 10 , 10 ) ) ;
vp_container - > set_stretch ( true ) ;
vp_container - > connect ( " gui_input " , callable_mp ( this , & SceneImportSettings : : _viewport_input ) ) ;
property_split - > add_child ( vp_container ) ;
base_viewport = memnew ( SubViewport ) ;
vp_container - > add_child ( base_viewport ) ;
base_viewport - > set_use_own_world_3d ( true ) ;
camera = memnew ( Camera3D ) ;
base_viewport - > add_child ( camera ) ;
camera - > make_current ( ) ;
light = memnew ( DirectionalLight3D ) ;
2020-10-17 07:08:21 +02:00
light - > set_transform ( Transform3D ( ) . looking_at ( Vector3 ( - 1 , - 2 , - 0.6 ) , Vector3 ( 0 , 1 , 0 ) ) ) ;
2021-03-19 13:57:52 +01:00
base_viewport - > add_child ( light ) ;
light - > set_shadow ( true ) ;
{
Ref < StandardMaterial3D > selection_mat ;
2021-06-18 00:03:09 +02:00
selection_mat . instantiate ( ) ;
2021-03-19 13:57:52 +01:00
selection_mat - > set_shading_mode ( StandardMaterial3D : : SHADING_MODE_UNSHADED ) ;
selection_mat - > set_albedo ( Color ( 1 , 0.8 , 1.0 ) ) ;
Ref < SurfaceTool > st ;
2021-06-18 00:03:09 +02:00
st . instantiate ( ) ;
2021-03-19 13:57:52 +01:00
st - > begin ( Mesh : : PRIMITIVE_LINES ) ;
AABB base_aabb ;
base_aabb . size = Vector3 ( 1 , 1 , 1 ) ;
for ( int i = 0 ; i < 12 ; i + + ) {
Vector3 a , b ;
base_aabb . get_edge ( i , a , b ) ;
st - > add_vertex ( a ) ;
st - > add_vertex ( a . lerp ( b , 0.2 ) ) ;
st - > add_vertex ( b ) ;
st - > add_vertex ( b . lerp ( a , 0.2 ) ) ;
}
2021-06-18 00:03:09 +02:00
selection_mesh . instantiate ( ) ;
2021-03-19 13:57:52 +01:00
st - > commit ( selection_mesh ) ;
selection_mesh - > surface_set_material ( 0 , selection_mat ) ;
node_selected = memnew ( MeshInstance3D ) ;
node_selected - > set_mesh ( selection_mesh ) ;
base_viewport - > add_child ( node_selected ) ;
node_selected - > hide ( ) ;
}
{
mesh_preview = memnew ( MeshInstance3D ) ;
base_viewport - > add_child ( mesh_preview ) ;
mesh_preview - > hide ( ) ;
2021-06-18 00:03:09 +02:00
material_preview . instantiate ( ) ;
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
{
collider_mat . instantiate ( ) ;
collider_mat - > set_shading_mode ( StandardMaterial3D : : SHADING_MODE_UNSHADED ) ;
collider_mat - > set_albedo ( Color ( 0.5 , 0.5 , 1.0 ) ) ;
}
2021-03-19 13:57:52 +01:00
inspector = memnew ( EditorInspector ) ;
inspector - > set_custom_minimum_size ( Size2 ( 300 * EDSCALE , 0 ) ) ;
property_split - > add_child ( inspector ) ;
scene_import_settings_data = memnew ( SceneImportSettingsData ) ;
get_ok_button ( ) - > set_text ( TTR ( " Reimport " ) ) ;
get_cancel_button ( ) - > set_text ( TTR ( " Close " ) ) ;
external_paths = memnew ( ConfirmationDialog ) ;
add_child ( external_paths ) ;
external_path_tree = memnew ( Tree ) ;
external_paths - > add_child ( external_path_tree ) ;
external_path_tree - > connect ( " button_pressed " , callable_mp ( this , & SceneImportSettings : : _browse_save_callback ) ) ;
external_paths - > connect ( " confirmed " , callable_mp ( this , & SceneImportSettings : : _save_dir_confirm ) ) ;
external_path_tree - > set_columns ( 3 ) ;
external_path_tree - > set_column_titles_visible ( true ) ;
external_path_tree - > set_column_expand ( 0 , true ) ;
2021-06-28 15:40:56 +02:00
external_path_tree - > set_column_custom_minimum_width ( 0 , 100 * EDSCALE ) ;
2021-03-19 13:57:52 +01:00
external_path_tree - > set_column_title ( 0 , TTR ( " Resource " ) ) ;
external_path_tree - > set_column_expand ( 1 , true ) ;
2021-06-28 15:40:56 +02:00
external_path_tree - > set_column_custom_minimum_width ( 1 , 100 * EDSCALE ) ;
2021-03-19 13:57:52 +01:00
external_path_tree - > set_column_title ( 1 , TTR ( " Path " ) ) ;
external_path_tree - > set_column_expand ( 2 , false ) ;
2021-06-28 15:40:56 +02:00
external_path_tree - > set_column_custom_minimum_width ( 2 , 200 * EDSCALE ) ;
2021-03-19 13:57:52 +01:00
external_path_tree - > set_column_title ( 2 , TTR ( " Status " ) ) ;
save_path = memnew ( EditorFileDialog ) ;
save_path - > set_file_mode ( EditorFileDialog : : FILE_MODE_OPEN_DIR ) ;
HBoxContainer * extension_hb = memnew ( HBoxContainer ) ;
save_path - > get_vbox ( ) - > add_child ( extension_hb ) ;
extension_hb - > add_spacer ( ) ;
extension_hb - > add_child ( memnew ( Label ( TTR ( " Save Extension: " ) ) ) ) ;
external_extension_type = memnew ( OptionButton ) ;
extension_hb - > add_child ( external_extension_type ) ;
external_extension_type - > add_item ( TTR ( " Text: *.tres " ) ) ;
external_extension_type - > add_item ( TTR ( " Binary: *.res " ) ) ;
external_path_tree - > set_hide_root ( true ) ;
add_child ( save_path ) ;
item_save_path = memnew ( EditorFileDialog ) ;
item_save_path - > set_file_mode ( EditorFileDialog : : FILE_MODE_SAVE_FILE ) ;
item_save_path - > add_filter ( " *.tres;Text Resource " ) ;
item_save_path - > add_filter ( " *.res;Binary Resource " ) ;
add_child ( item_save_path ) ;
item_save_path - > connect ( " file_selected " , callable_mp ( this , & SceneImportSettings : : _save_path_changed ) ) ;
save_path - > connect ( " dir_selected " , callable_mp ( this , & SceneImportSettings : : _save_dir_callback ) ) ;
}
SceneImportSettings : : ~ SceneImportSettings ( ) {
memdelete ( scene_import_settings_data ) ;
}