2020-12-21 07:39:32 -08:00
/**************************************************************************/
2021-09-20 18:24:31 -07:00
/* importer_mesh.cpp */
2020-12-21 07:39:32 -08:00
/**************************************************************************/
/* 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. */
/**************************************************************************/
2021-09-20 18:24:31 -07:00
# include "importer_mesh.h"
2020-12-21 07:39:32 -08:00
2022-10-24 21:40:34 +01:00
# include "core/io/marshalls.h"
2021-09-07 17:44:50 +02:00
# include "core/math/random_pcg.h"
2020-12-21 07:39:32 -08:00
# include "scene/resources/surface_tool.h"
2025-02-27 19:01:23 -03:00
# ifndef PHYSICS_3D_DISABLED
# include "core/math/convex_hull.h"
# endif // PHYSICS_3D_DISABLED
2024-07-26 17:04:56 +09:00
String ImporterMesh : : validate_blend_shape_name ( const String & p_name ) {
2024-05-28 12:15:00 +02:00
return p_name . replace_char ( ' : ' , ' _ ' ) ;
2024-07-26 17:04:56 +09:00
}
2021-09-20 18:24:31 -07:00
void ImporterMesh : : add_blend_shape ( const String & p_name ) {
2020-12-21 07:39:32 -08:00
ERR_FAIL_COND ( surfaces . size ( ) > 0 ) ;
2024-07-26 17:04:56 +09:00
blend_shapes . push_back ( validate_blend_shape_name ( p_name ) ) ;
2020-12-21 07:39:32 -08:00
}
2021-09-20 18:24:31 -07:00
int ImporterMesh : : get_blend_shape_count ( ) const {
2020-12-21 07:39:32 -08:00
return blend_shapes . size ( ) ;
}
2021-09-20 18:24:31 -07:00
String ImporterMesh : : get_blend_shape_name ( int p_blend_shape ) const {
2020-12-21 07:39:32 -08:00
ERR_FAIL_INDEX_V ( p_blend_shape , blend_shapes . size ( ) , String ( ) ) ;
return blend_shapes [ p_blend_shape ] ;
}
2021-09-20 18:24:31 -07:00
void ImporterMesh : : set_blend_shape_mode ( Mesh : : BlendShapeMode p_blend_shape_mode ) {
2020-12-21 07:39:32 -08:00
blend_shape_mode = p_blend_shape_mode ;
}
2021-09-20 18:24:31 -07:00
Mesh : : BlendShapeMode ImporterMesh : : get_blend_shape_mode ( ) const {
2020-12-21 07:39:32 -08:00
return blend_shape_mode ;
}
2023-08-29 21:04:32 +02:00
void ImporterMesh : : add_surface ( Mesh : : PrimitiveType p_primitive , const Array & p_arrays , const TypedArray < Array > & p_blend_shapes , const Dictionary & p_lods , const Ref < Material > & p_material , const String & p_name , const uint64_t p_flags ) {
2020-12-21 07:39:32 -08:00
ERR_FAIL_COND ( p_blend_shapes . size ( ) ! = blend_shapes . size ( ) ) ;
ERR_FAIL_COND ( p_arrays . size ( ) ! = Mesh : : ARRAY_MAX ) ;
Surface s ;
s . primitive = p_primitive ;
s . arrays = p_arrays ;
s . name = p_name ;
2021-09-08 21:29:14 -07:00
s . flags = p_flags ;
2020-12-21 07:39:32 -08:00
2020-12-24 00:01:07 -08:00
Vector < Vector3 > vertex_array = p_arrays [ Mesh : : ARRAY_VERTEX ] ;
int vertex_count = vertex_array . size ( ) ;
ERR_FAIL_COND ( vertex_count = = 0 ) ;
2020-12-21 07:39:32 -08:00
for ( int i = 0 ; i < blend_shapes . size ( ) ; i + + ) {
Array bsdata = p_blend_shapes [ i ] ;
ERR_FAIL_COND ( bsdata . size ( ) ! = Mesh : : ARRAY_MAX ) ;
2020-12-24 00:01:07 -08:00
Vector < Vector3 > vertex_data = bsdata [ Mesh : : ARRAY_VERTEX ] ;
ERR_FAIL_COND ( vertex_data . size ( ) ! = vertex_count ) ;
2020-12-21 07:39:32 -08:00
Surface : : BlendShape bs ;
bs . arrays = bsdata ;
s . blend_shape_data . push_back ( bs ) ;
}
2025-03-12 06:43:48 +08:00
for ( const KeyValue < Variant , Variant > & kv : p_lods ) {
ERR_CONTINUE ( ! kv . key . is_num ( ) ) ;
2020-12-21 07:39:32 -08:00
Surface : : LOD lod ;
2025-03-12 06:43:48 +08:00
lod . distance = kv . key ;
lod . indices = kv . value ;
2024-01-19 13:21:39 +01:00
ERR_CONTINUE ( lod . indices . is_empty ( ) ) ;
2020-12-21 07:39:32 -08:00
s . lods . push_back ( lod ) ;
}
s . material = p_material ;
surfaces . push_back ( s ) ;
mesh . unref ( ) ;
}
2021-09-20 18:24:31 -07:00
int ImporterMesh : : get_surface_count ( ) const {
2020-12-21 07:39:32 -08:00
return surfaces . size ( ) ;
}
2021-09-20 18:24:31 -07:00
Mesh : : PrimitiveType ImporterMesh : : get_surface_primitive_type ( int p_surface ) {
2020-12-21 07:39:32 -08:00
ERR_FAIL_INDEX_V ( p_surface , surfaces . size ( ) , Mesh : : PRIMITIVE_MAX ) ;
return surfaces [ p_surface ] . primitive ;
}
2021-09-20 18:24:31 -07:00
Array ImporterMesh : : get_surface_arrays ( int p_surface ) const {
2020-12-21 07:39:32 -08:00
ERR_FAIL_INDEX_V ( p_surface , surfaces . size ( ) , Array ( ) ) ;
return surfaces [ p_surface ] . arrays ;
}
2021-09-20 18:24:31 -07:00
String ImporterMesh : : get_surface_name ( int p_surface ) const {
2020-12-21 07:39:32 -08:00
ERR_FAIL_INDEX_V ( p_surface , surfaces . size ( ) , String ( ) ) ;
return surfaces [ p_surface ] . name ;
}
2021-09-20 18:24:31 -07:00
void ImporterMesh : : set_surface_name ( int p_surface , const String & p_name ) {
2021-08-22 18:11:57 -07:00
ERR_FAIL_INDEX ( p_surface , surfaces . size ( ) ) ;
surfaces . write [ p_surface ] . name = p_name ;
mesh . unref ( ) ;
}
2021-09-20 18:24:31 -07:00
Array ImporterMesh : : get_surface_blend_shape_arrays ( int p_surface , int p_blend_shape ) const {
2020-12-21 07:39:32 -08:00
ERR_FAIL_INDEX_V ( p_surface , surfaces . size ( ) , Array ( ) ) ;
ERR_FAIL_INDEX_V ( p_blend_shape , surfaces [ p_surface ] . blend_shape_data . size ( ) , Array ( ) ) ;
return surfaces [ p_surface ] . blend_shape_data [ p_blend_shape ] . arrays ;
}
2021-09-20 18:24:31 -07:00
int ImporterMesh : : get_surface_lod_count ( int p_surface ) const {
2020-12-21 07:39:32 -08:00
ERR_FAIL_INDEX_V ( p_surface , surfaces . size ( ) , 0 ) ;
return surfaces [ p_surface ] . lods . size ( ) ;
}
2021-09-20 18:24:31 -07:00
Vector < int > ImporterMesh : : get_surface_lod_indices ( int p_surface , int p_lod ) const {
2020-12-21 07:39:32 -08:00
ERR_FAIL_INDEX_V ( p_surface , surfaces . size ( ) , Vector < int > ( ) ) ;
ERR_FAIL_INDEX_V ( p_lod , surfaces [ p_surface ] . lods . size ( ) , Vector < int > ( ) ) ;
return surfaces [ p_surface ] . lods [ p_lod ] . indices ;
}
2021-09-20 18:24:31 -07:00
float ImporterMesh : : get_surface_lod_size ( int p_surface , int p_lod ) const {
2020-12-21 07:39:32 -08:00
ERR_FAIL_INDEX_V ( p_surface , surfaces . size ( ) , 0 ) ;
ERR_FAIL_INDEX_V ( p_lod , surfaces [ p_surface ] . lods . size ( ) , 0 ) ;
return surfaces [ p_surface ] . lods [ p_lod ] . distance ;
}
2023-08-29 21:04:32 +02:00
uint64_t ImporterMesh : : get_surface_format ( int p_surface ) const {
2021-09-08 21:29:14 -07:00
ERR_FAIL_INDEX_V ( p_surface , surfaces . size ( ) , 0 ) ;
return surfaces [ p_surface ] . flags ;
}
2021-09-20 18:24:31 -07:00
Ref < Material > ImporterMesh : : get_surface_material ( int p_surface ) const {
2020-12-21 07:39:32 -08:00
ERR_FAIL_INDEX_V ( p_surface , surfaces . size ( ) , Ref < Material > ( ) ) ;
return surfaces [ p_surface ] . material ;
}
2021-09-20 18:24:31 -07:00
void ImporterMesh : : set_surface_material ( int p_surface , const Ref < Material > & p_material ) {
2021-03-19 09:57:52 -03:00
ERR_FAIL_INDEX ( p_surface , surfaces . size ( ) ) ;
surfaces . write [ p_surface ] . material = p_material ;
2021-08-22 18:11:57 -07:00
mesh . unref ( ) ;
2021-03-19 09:57:52 -03:00
}
2024-11-03 11:57:07 -08:00
template < typename T >
static Vector < T > _remap_array ( Vector < T > p_array , const Vector < uint32_t > & p_remap , uint32_t p_vertex_count ) {
ERR_FAIL_COND_V ( p_array . size ( ) % p_remap . size ( ) ! = 0 , p_array ) ;
int num_elements = p_array . size ( ) / p_remap . size ( ) ;
T * data = p_array . ptrw ( ) ;
SurfaceTool : : remap_vertex_func ( data , data , p_remap . size ( ) , sizeof ( T ) * num_elements , p_remap . ptr ( ) ) ;
p_array . resize ( p_vertex_count * num_elements ) ;
return p_array ;
}
static void _remap_arrays ( Array & r_arrays , const Vector < uint32_t > & p_remap , uint32_t p_vertex_count ) {
for ( int i = 0 ; i < r_arrays . size ( ) ; i + + ) {
if ( i = = RS : : ARRAY_INDEX ) {
continue ;
}
switch ( r_arrays [ i ] . get_type ( ) ) {
case Variant : : NIL :
break ;
case Variant : : PACKED_VECTOR3_ARRAY :
r_arrays [ i ] = _remap_array < Vector3 > ( r_arrays [ i ] , p_remap , p_vertex_count ) ;
break ;
case Variant : : PACKED_VECTOR2_ARRAY :
r_arrays [ i ] = _remap_array < Vector2 > ( r_arrays [ i ] , p_remap , p_vertex_count ) ;
break ;
case Variant : : PACKED_FLOAT32_ARRAY :
r_arrays [ i ] = _remap_array < float > ( r_arrays [ i ] , p_remap , p_vertex_count ) ;
break ;
case Variant : : PACKED_INT32_ARRAY :
r_arrays [ i ] = _remap_array < int32_t > ( r_arrays [ i ] , p_remap , p_vertex_count ) ;
break ;
case Variant : : PACKED_BYTE_ARRAY :
r_arrays [ i ] = _remap_array < uint8_t > ( r_arrays [ i ] , p_remap , p_vertex_count ) ;
break ;
case Variant : : PACKED_COLOR_ARRAY :
r_arrays [ i ] = _remap_array < Color > ( r_arrays [ i ] , p_remap , p_vertex_count ) ;
break ;
default :
ERR_FAIL_MSG ( " Unhandled array type. " ) ;
}
}
}
void ImporterMesh : : optimize_indices ( ) {
2024-07-11 15:44:30 -07:00
if ( ! SurfaceTool : : optimize_vertex_cache_func ) {
return ;
}
2024-11-03 11:57:07 -08:00
if ( ! SurfaceTool : : optimize_vertex_fetch_remap_func | | ! SurfaceTool : : remap_vertex_func | | ! SurfaceTool : : remap_index_func ) {
return ;
}
2024-07-11 15:44:30 -07:00
for ( int i = 0 ; i < surfaces . size ( ) ; i + + ) {
if ( surfaces [ i ] . primitive ! = Mesh : : PRIMITIVE_TRIANGLES ) {
continue ;
}
Vector < Vector3 > vertices = surfaces [ i ] . arrays [ RS : : ARRAY_VERTEX ] ;
PackedInt32Array indices = surfaces [ i ] . arrays [ RS : : ARRAY_INDEX ] ;
unsigned int index_count = indices . size ( ) ;
unsigned int vertex_count = vertices . size ( ) ;
if ( index_count = = 0 ) {
continue ;
}
2024-11-03 11:57:07 -08:00
// Optimize indices for vertex cache to establish final triangle order.
2024-07-11 15:44:30 -07:00
int * indices_ptr = indices . ptrw ( ) ;
SurfaceTool : : optimize_vertex_cache_func ( ( unsigned int * ) indices_ptr , ( const unsigned int * ) indices_ptr , index_count , vertex_count ) ;
2024-11-03 11:57:07 -08:00
surfaces . write [ i ] . arrays [ RS : : ARRAY_INDEX ] = indices ;
for ( int j = 0 ; j < surfaces [ i ] . lods . size ( ) ; + + j ) {
Surface : : LOD & lod = surfaces . write [ i ] . lods . write [ j ] ;
int * lod_indices_ptr = lod . indices . ptrw ( ) ;
SurfaceTool : : optimize_vertex_cache_func ( ( unsigned int * ) lod_indices_ptr , ( const unsigned int * ) lod_indices_ptr , lod . indices . size ( ) , vertex_count ) ;
}
2024-07-11 15:44:30 -07:00
2024-11-03 11:57:07 -08:00
// Concatenate indices for all LODs in the order of coarse->fine; this establishes the effective order of vertices,
// and is important to optimize for vertex fetch (all GPUs) and shading (Mali GPUs)
PackedInt32Array merged_indices ;
for ( int j = surfaces [ i ] . lods . size ( ) - 1 ; j > = 0 ; - - j ) {
merged_indices . append_array ( surfaces [ i ] . lods [ j ] . indices ) ;
}
merged_indices . append_array ( indices ) ;
// Generate remap array that establishes optimal vertex order according to the order of indices above.
Vector < uint32_t > remap ;
remap . resize ( vertex_count ) ;
unsigned int new_vertex_count = SurfaceTool : : optimize_vertex_fetch_remap_func ( remap . ptrw ( ) , ( const unsigned int * ) merged_indices . ptr ( ) , merged_indices . size ( ) , vertex_count ) ;
// We need to remap all vertex and index arrays in lockstep according to the remap.
SurfaceTool : : remap_index_func ( ( unsigned int * ) indices_ptr , ( const unsigned int * ) indices_ptr , index_count , remap . ptr ( ) ) ;
2024-07-11 15:44:30 -07:00
surfaces . write [ i ] . arrays [ RS : : ARRAY_INDEX ] = indices ;
2024-11-03 11:57:07 -08:00
for ( int j = 0 ; j < surfaces [ i ] . lods . size ( ) ; + + j ) {
Surface : : LOD & lod = surfaces . write [ i ] . lods . write [ j ] ;
int * lod_indices_ptr = lod . indices . ptrw ( ) ;
SurfaceTool : : remap_index_func ( ( unsigned int * ) lod_indices_ptr , ( const unsigned int * ) lod_indices_ptr , lod . indices . size ( ) , remap . ptr ( ) ) ;
}
_remap_arrays ( surfaces . write [ i ] . arrays , remap , new_vertex_count ) ;
for ( int j = 0 ; j < surfaces [ i ] . blend_shape_data . size ( ) ; j + + ) {
_remap_arrays ( surfaces . write [ i ] . blend_shape_data . write [ j ] . arrays , remap , new_vertex_count ) ;
}
}
if ( shadow_mesh . is_valid ( ) ) {
shadow_mesh - > optimize_indices ( ) ;
2024-07-11 15:44:30 -07:00
}
}
2022-09-07 20:13:10 +01:00
# define VERTEX_SKIN_FUNC(bone_count, vert_idx, read_array, write_array, transform_array, bone_array, weight_array) \
2022-11-14 18:21:06 +01:00
Vector3 transformed_vert ; \
2022-09-07 20:13:10 +01:00
for ( unsigned int weight_idx = 0 ; weight_idx < bone_count ; weight_idx + + ) { \
int bone_idx = bone_array [ vert_idx * bone_count + weight_idx ] ; \
float w = weight_array [ vert_idx * bone_count + weight_idx ] ; \
if ( w < FLT_EPSILON ) { \
continue ; \
} \
ERR_FAIL_INDEX ( bone_idx , static_cast < int > ( transform_array . size ( ) ) ) ; \
transformed_vert + = transform_array [ bone_idx ] . xform ( read_array [ vert_idx ] ) * w ; \
} \
write_array [ vert_idx ] = transformed_vert ;
2024-10-28 10:14:04 -07:00
void ImporterMesh : : generate_lods ( float p_normal_merge_angle , Array p_bone_transform_array ) {
2021-01-09 10:04:09 -08:00
if ( ! SurfaceTool : : simplify_scale_func ) {
return ;
}
2021-09-07 17:44:50 +02:00
if ( ! SurfaceTool : : simplify_with_attrib_func ) {
2021-01-09 10:04:09 -08:00
return ;
}
2020-12-21 07:39:32 -08:00
2022-09-07 20:13:10 +01:00
LocalVector < Transform3D > bone_transform_vector ;
for ( int i = 0 ; i < p_bone_transform_array . size ( ) ; i + + ) {
ERR_FAIL_COND ( p_bone_transform_array [ i ] . get_type ( ) ! = Variant : : TRANSFORM3D ) ;
bone_transform_vector . push_back ( p_bone_transform_array [ i ] ) ;
}
2020-12-21 07:39:32 -08:00
for ( int i = 0 ; i < surfaces . size ( ) ; i + + ) {
if ( surfaces [ i ] . primitive ! = Mesh : : PRIMITIVE_TRIANGLES ) {
continue ;
}
surfaces . write [ i ] . lods . clear ( ) ;
Vector < Vector3 > vertices = surfaces [ i ] . arrays [ RS : : ARRAY_VERTEX ] ;
2021-09-07 17:44:50 +02:00
PackedInt32Array indices = surfaces [ i ] . arrays [ RS : : ARRAY_INDEX ] ;
Vector < Vector3 > normals = surfaces [ i ] . arrays [ RS : : ARRAY_NORMAL ] ;
2024-07-23 16:27:28 -07:00
Vector < float > tangents = surfaces [ i ] . arrays [ RS : : ARRAY_TANGENT ] ;
2021-09-07 17:44:50 +02:00
Vector < Vector2 > uvs = surfaces [ i ] . arrays [ RS : : ARRAY_TEX_UV ] ;
2022-02-25 17:36:40 -08:00
Vector < Vector2 > uv2s = surfaces [ i ] . arrays [ RS : : ARRAY_TEX_UV2 ] ;
2022-09-07 20:13:10 +01:00
Vector < int > bones = surfaces [ i ] . arrays [ RS : : ARRAY_BONES ] ;
Vector < float > weights = surfaces [ i ] . arrays [ RS : : ARRAY_WEIGHTS ] ;
2025-05-15 18:10:35 +03:00
Vector < Color > colors = surfaces [ i ] . arrays [ RS : : ARRAY_COLOR ] ;
2021-09-07 17:44:50 +02:00
unsigned int index_count = indices . size ( ) ;
unsigned int vertex_count = vertices . size ( ) ;
if ( index_count = = 0 ) {
2020-12-21 07:39:32 -08:00
continue ; //no lods if no indices
}
2025-08-16 00:33:06 -07:00
ERR_FAIL_COND_MSG ( index_count % 3 ! = 0 , " ImporterMesh::generate_lods: Indexed triangle meshes MUST have an index array with a size that is a multiple of 3, but got " + itos ( index_count ) + " indices. Cannot generate LODs for this invalid mesh. " ) ;
2021-09-07 17:44:50 +02:00
2020-12-21 07:39:32 -08:00
const Vector3 * vertices_ptr = vertices . ptr ( ) ;
2021-09-07 17:44:50 +02:00
const int * indices_ptr = indices . ptr ( ) ;
if ( normals . is_empty ( ) ) {
2022-02-19 13:30:17 +08:00
normals . resize ( index_count ) ;
2021-09-07 17:44:50 +02:00
Vector3 * n_ptr = normals . ptrw ( ) ;
for ( unsigned int j = 0 ; j < index_count ; j + = 3 ) {
const Vector3 & v0 = vertices_ptr [ indices_ptr [ j + 0 ] ] ;
const Vector3 & v1 = vertices_ptr [ indices_ptr [ j + 1 ] ] ;
const Vector3 & v2 = vertices_ptr [ indices_ptr [ j + 2 ] ] ;
Vector3 n = vec3_cross ( v0 - v2 , v0 - v1 ) . normalized ( ) ;
n_ptr [ j + 0 ] = n ;
n_ptr [ j + 1 ] = n ;
n_ptr [ j + 2 ] = n ;
2021-04-09 22:44:36 -07:00
}
2021-09-07 17:44:50 +02:00
}
2025-08-22 20:26:47 -07:00
bool deformable = bones . size ( ) > 0 | | blend_shapes . size ( ) > 0 ;
2022-09-07 20:13:10 +01:00
if ( bones . size ( ) > 0 & & weights . size ( ) & & bone_transform_vector . size ( ) > 0 ) {
Vector3 * vertices_ptrw = vertices . ptrw ( ) ;
// Apply bone transforms to regular surface.
unsigned int bone_weight_length = surfaces [ i ] . flags & Mesh : : ARRAY_FLAG_USE_8_BONE_WEIGHTS ? 8 : 4 ;
const int * bo = bones . ptr ( ) ;
const float * we = weights . ptr ( ) ;
for ( unsigned int j = 0 ; j < vertex_count ; j + + ) {
VERTEX_SKIN_FUNC ( bone_weight_length , j , vertices_ptr , vertices_ptrw , bone_transform_vector , bo , we )
}
vertices_ptr = vertices . ptr ( ) ;
}
2022-08-13 17:45:42 +02:00
float normal_merge_threshold = Math : : cos ( Math : : deg_to_rad ( p_normal_merge_angle ) ) ;
2021-09-07 17:44:50 +02:00
const Vector3 * normals_ptr = normals . ptr ( ) ;
2022-05-13 15:04:37 +02:00
HashMap < Vector3 , LocalVector < Pair < int , int > > > unique_vertices ;
2021-09-07 17:44:50 +02:00
LocalVector < int > vertex_remap ;
LocalVector < int > vertex_inverse_remap ;
LocalVector < Vector3 > merged_vertices ;
LocalVector < Vector3 > merged_normals ;
LocalVector < int > merged_normals_counts ;
const Vector2 * uvs_ptr = uvs . ptr ( ) ;
2022-02-25 17:36:40 -08:00
const Vector2 * uv2s_ptr = uv2s . ptr ( ) ;
2024-07-23 16:27:28 -07:00
const float * tangents_ptr = tangents . ptr ( ) ;
2025-05-15 18:10:35 +03:00
const Color * colors_ptr = colors . ptr ( ) ;
2021-09-07 17:44:50 +02:00
for ( unsigned int j = 0 ; j < vertex_count ; j + + ) {
const Vector3 & v = vertices_ptr [ j ] ;
const Vector3 & n = normals_ptr [ j ] ;
2022-05-13 15:04:37 +02:00
HashMap < Vector3 , LocalVector < Pair < int , int > > > : : Iterator E = unique_vertices . find ( v ) ;
2021-09-07 17:44:50 +02:00
if ( E ) {
2022-05-13 15:04:37 +02:00
const LocalVector < Pair < int , int > > & close_verts = E - > value ;
2021-09-07 17:44:50 +02:00
bool found = false ;
2022-12-29 01:24:45 +01:00
for ( const Pair < int , int > & idx : close_verts ) {
2022-02-25 17:36:40 -08:00
bool is_uvs_close = ( ! uvs_ptr | | uvs_ptr [ j ] . distance_squared_to ( uvs_ptr [ idx . second ] ) < CMP_EPSILON2 ) ;
bool is_uv2s_close = ( ! uv2s_ptr | | uv2s_ptr [ j ] . distance_squared_to ( uv2s_ptr [ idx . second ] ) < CMP_EPSILON2 ) ;
2024-07-23 16:27:28 -07:00
bool is_tang_aligned = ! tangents_ptr | | ( tangents_ptr [ j * 4 + 3 ] < 0 ) = = ( tangents_ptr [ idx . second * 4 + 3 ] < 0 ) ;
2022-04-09 08:11:22 -07:00
ERR_FAIL_INDEX ( idx . second , normals . size ( ) ) ;
2022-02-25 17:36:40 -08:00
bool is_normals_close = normals [ idx . second ] . dot ( n ) > normal_merge_threshold ;
2025-05-15 18:10:35 +03:00
bool is_col_close = ( ! colors_ptr | | colors_ptr [ j ] . is_equal_approx ( colors_ptr [ idx . second ] ) ) ;
if ( is_uvs_close & & is_uv2s_close & & is_normals_close & & is_tang_aligned & & is_col_close ) {
2021-09-07 17:44:50 +02:00
vertex_remap . push_back ( idx . first ) ;
merged_normals [ idx . first ] + = normals [ idx . second ] ;
merged_normals_counts [ idx . first ] + + ;
found = true ;
break ;
}
}
if ( ! found ) {
int vcount = merged_vertices . size ( ) ;
unique_vertices [ v ] . push_back ( Pair < int , int > ( vcount , j ) ) ;
vertex_inverse_remap . push_back ( j ) ;
merged_vertices . push_back ( v ) ;
vertex_remap . push_back ( vcount ) ;
merged_normals . push_back ( normals_ptr [ j ] ) ;
merged_normals_counts . push_back ( 1 ) ;
}
} else {
int vcount = merged_vertices . size ( ) ;
unique_vertices [ v ] = LocalVector < Pair < int , int > > ( ) ;
unique_vertices [ v ] . push_back ( Pair < int , int > ( vcount , j ) ) ;
vertex_inverse_remap . push_back ( j ) ;
merged_vertices . push_back ( v ) ;
vertex_remap . push_back ( vcount ) ;
merged_normals . push_back ( normals_ptr [ j ] ) ;
merged_normals_counts . push_back ( 1 ) ;
}
}
LocalVector < int > merged_indices ;
merged_indices . resize ( index_count ) ;
for ( unsigned int j = 0 ; j < index_count ; j + + ) {
merged_indices [ j ] = vertex_remap [ indices [ j ] ] ;
}
unsigned int merged_vertex_count = merged_vertices . size ( ) ;
const Vector3 * merged_vertices_ptr = merged_vertices . ptr ( ) ;
2025-05-15 18:10:35 +03:00
Vector3 * merged_normals_ptr = merged_normals . ptr ( ) ;
2021-09-07 17:44:50 +02:00
{
const int * counts_ptr = merged_normals_counts . ptr ( ) ;
for ( unsigned int j = 0 ; j < merged_vertex_count ; j + + ) {
2025-05-15 18:10:35 +03:00
merged_normals_ptr [ j ] / = counts_ptr [ j ] ;
2021-04-09 22:44:36 -07:00
}
}
2021-09-07 17:44:50 +02:00
2022-10-24 21:40:34 +01:00
Vector < float > merged_vertices_f32 = vector3_to_float32_array ( merged_vertices_ptr , merged_vertex_count ) ;
float scale = SurfaceTool : : simplify_scale_func ( merged_vertices_f32 . ptr ( ) , merged_vertex_count , sizeof ( float ) * 3 ) ;
2021-09-07 17:44:50 +02:00
2025-05-15 18:10:35 +03:00
const size_t attrib_count = 6 ; // 3 for normal + 3 for color (if present)
float attrib_weights [ attrib_count ] = { } ;
2025-05-18 17:38:54 +03:00
// Give some weight to normal preservation
attrib_weights [ 0 ] = attrib_weights [ 1 ] = attrib_weights [ 2 ] = 1.0f ;
2025-05-15 18:10:35 +03:00
// Give some weight to colors but only if present to avoid redundant computations during simplification
if ( colors_ptr ) {
attrib_weights [ 3 ] = attrib_weights [ 4 ] = attrib_weights [ 5 ] = 1.0f ;
}
LocalVector < float > merged_attribs ;
merged_attribs . resize ( merged_vertex_count * attrib_count ) ;
float * merged_attribs_ptr = merged_attribs . ptr ( ) ;
memset ( merged_attribs_ptr , 0 , merged_attribs . size ( ) * sizeof ( float ) ) ;
for ( unsigned int j = 0 ; j < merged_vertex_count ; + + j ) {
merged_attribs_ptr [ j * attrib_count + 0 ] = merged_normals_ptr [ j ] . x ;
merged_attribs_ptr [ j * attrib_count + 1 ] = merged_normals_ptr [ j ] . y ;
merged_attribs_ptr [ j * attrib_count + 2 ] = merged_normals_ptr [ j ] . z ;
if ( colors_ptr ) {
unsigned int rj = vertex_inverse_remap [ j ] ;
merged_attribs_ptr [ j * attrib_count + 3 ] = colors_ptr [ rj ] . r ;
merged_attribs_ptr [ j * attrib_count + 4 ] = colors_ptr [ rj ] . g ;
merged_attribs_ptr [ j * attrib_count + 5 ] = colors_ptr [ rj ] . b ;
}
}
2025-08-27 08:26:15 -07:00
print_verbose ( " LOD Generation: Triangles " + itos ( index_count / 3 ) + " , vertices " + itos ( vertex_count ) + " (merged " + itos ( merged_vertex_count ) + " ) " + ( deformable ? " , deformable " : " " ) ) ;
2021-09-07 17:44:50 +02:00
2025-08-27 08:26:15 -07:00
const float max_mesh_error = 1.0f ; // We only need LODs that can be selected by error threshold.
const unsigned min_target_indices = 12 ;
LocalVector < int > current_indices = merged_indices ;
float current_error = 0.0f ;
2025-08-27 08:51:21 -07:00
bool allow_prune = true ;
2025-08-27 08:26:15 -07:00
while ( current_indices . size ( ) > min_target_indices * 2 ) {
unsigned int current_index_count = current_indices . size ( ) ;
unsigned int target_index_count = MAX ( ( ( current_index_count / 3 ) / 2 ) * 3 , min_target_indices ) ;
2022-10-24 21:40:34 +01:00
2021-09-07 17:44:50 +02:00
PackedInt32Array new_indices ;
2025-08-27 08:26:15 -07:00
new_indices . resize ( current_index_count ) ;
2021-09-07 17:44:50 +02:00
2025-08-27 08:26:15 -07:00
int simplify_options = SurfaceTool : : SIMPLIFY_SPARSE ; // Does not change appearance, but speeds up subsequent iterations.
2025-08-22 20:26:47 -07:00
// Lock geometric boundary in case the mesh is composed of multiple material subsets.
simplify_options | = SurfaceTool : : SIMPLIFY_LOCK_BORDER ;
2025-08-27 08:51:21 -07:00
if ( allow_prune ) {
// Remove small disconnected components.
simplify_options | = SurfaceTool : : SIMPLIFY_PRUNE ;
}
2025-08-22 20:26:47 -07:00
if ( deformable ) {
// Improves appearance of deformable objects after deformation by using more regular tessellation.
simplify_options | = SurfaceTool : : SIMPLIFY_REGULARIZE ;
}
2022-10-24 21:40:34 +01:00
2025-08-27 08:26:15 -07:00
float step_error = 0.0f ;
2022-10-24 21:40:34 +01:00
size_t new_index_count = SurfaceTool : : simplify_with_attrib_func (
( unsigned int * ) new_indices . ptrw ( ) ,
2025-08-27 08:26:15 -07:00
( const uint32_t * ) current_indices . ptr ( ) , current_index_count ,
2022-10-24 21:40:34 +01:00
merged_vertices_f32 . ptr ( ) , merged_vertex_count ,
sizeof ( float ) * 3 , // Vertex stride
2025-05-15 18:10:35 +03:00
merged_attribs_ptr ,
sizeof ( float ) * attrib_count , // Attribute stride
attrib_weights , attrib_count ,
2024-10-25 10:41:51 -07:00
nullptr , // Vertex lock
2025-08-27 08:26:15 -07:00
target_index_count ,
2022-10-24 21:40:34 +01:00
max_mesh_error ,
2022-12-22 16:22:33 +01:00
simplify_options ,
2025-08-27 08:26:15 -07:00
& step_error ) ;
2021-09-07 17:44:50 +02:00
2025-08-27 08:51:21 -07:00
if ( new_index_count = = 0 & & allow_prune ) {
// If the best result the simplifier could arrive at with pruning enabled is 0 triangles, there might still be an opportunity
// to reduce the number of triangles further *without* completely decimating the mesh. It will be impossible to reach the target
// this way - if the target was reachable without going down to 0, the simplifier would have done it! - but we might still be able
// to get one more slightly lower level if we retry without pruning.
allow_prune = false ;
continue ;
}
2025-08-27 08:26:15 -07:00
// Accumulate error over iterations. Usually, it's correct to use step_error as is; however, on coarse LODs, we may start
// getting *smaller* relative error compared to the previous LOD. To make sure the error is monotonic and strictly increasing,
// and to limit the switching (pop) distance, we ensure the error grows by an arbitrary factor each iteration.
current_error = MAX ( current_error * 1.5f , step_error ) ;
new_indices . resize ( new_index_count ) ;
current_indices = new_indices ;
2021-09-07 17:44:50 +02:00
2025-08-27 08:26:15 -07:00
if ( new_index_count = = 0 | | ( new_index_count > = current_index_count * 0.75f ) ) {
print_verbose ( " LOD stop: got " + itos ( new_index_count / 3 ) + " triangles when asking for " + itos ( target_index_count / 3 ) ) ;
2021-04-09 22:44:36 -07:00
break ;
2021-01-09 10:04:09 -08:00
}
2025-08-27 08:26:15 -07:00
if ( current_error > max_mesh_error ) {
print_verbose ( " LOD stop: reached " + rtos ( current_error ) + " cumulative error (step error " + rtos ( step_error ) + " ) " ) ;
2023-08-09 21:27:58 -05:00
break ;
}
2021-09-07 17:44:50 +02:00
2025-08-27 08:26:15 -07:00
// We need to remap the LOD indices back to the original vertex array; note that we already copied new_indices into current_indices for subsequent iteration.
2021-09-07 17:44:50 +02:00
{
int * ptrw = new_indices . ptrw ( ) ;
for ( unsigned int j = 0 ; j < new_index_count ; j + + ) {
2024-06-28 18:32:59 -07:00
ptrw [ j ] = vertex_inverse_remap [ ptrw [ j ] ] ;
2021-09-07 17:44:50 +02:00
}
}
Surface : : LOD lod ;
2025-08-27 08:26:15 -07:00
lod . distance = MAX ( current_error * scale , CMP_EPSILON2 ) ;
2020-12-21 07:39:32 -08:00
lod . indices = new_indices ;
surfaces . write [ i ] . lods . push_back ( lod ) ;
2021-09-07 17:44:50 +02:00
2025-08-27 08:26:15 -07:00
print_verbose ( " LOD " + itos ( surfaces . write [ i ] . lods . size ( ) ) + " : " + itos ( new_index_count / 3 ) + " triangles, error " + rtos ( current_error ) + " (step error " + rtos ( step_error ) + " ) " ) ;
2021-09-07 17:44:50 +02:00
}
surfaces . write [ i ] . lods . sort_custom < Surface : : LODComparator > ( ) ;
2020-12-21 07:39:32 -08:00
}
}
2024-06-28 18:32:59 -07:00
void ImporterMesh : : _generate_lods_bind ( float p_normal_merge_angle , float p_normal_split_angle , Array p_skin_pose_transform_array ) {
2024-10-28 10:14:04 -07:00
// p_normal_split_angle is unused, but kept for compatibility
generate_lods ( p_normal_merge_angle , p_skin_pose_transform_array ) ;
2024-06-28 18:32:59 -07:00
}
2021-09-20 18:24:31 -07:00
bool ImporterMesh : : has_mesh ( ) const {
2020-12-21 07:39:32 -08:00
return mesh . is_valid ( ) ;
}
2021-09-20 18:24:31 -07:00
Ref < ArrayMesh > ImporterMesh : : get_mesh ( const Ref < ArrayMesh > & p_base ) {
2024-01-19 13:21:39 +01:00
ERR_FAIL_COND_V ( surfaces . is_empty ( ) , Ref < ArrayMesh > ( ) ) ;
2020-12-21 07:39:32 -08:00
if ( mesh . is_null ( ) ) {
2021-03-19 09:57:52 -03:00
if ( p_base . is_valid ( ) ) {
mesh = p_base ;
}
if ( mesh . is_null ( ) ) {
2021-06-17 16:03:09 -06:00
mesh . instantiate ( ) ;
2021-03-19 09:57:52 -03:00
}
mesh - > set_name ( get_name ( ) ) ;
if ( has_meta ( " import_id " ) ) {
mesh - > set_meta ( " import_id " , get_meta ( " import_id " ) ) ;
}
2020-12-21 07:39:32 -08:00
for ( int i = 0 ; i < blend_shapes . size ( ) ; i + + ) {
mesh - > add_blend_shape ( blend_shapes [ i ] ) ;
}
mesh - > set_blend_shape_mode ( blend_shape_mode ) ;
for ( int i = 0 ; i < surfaces . size ( ) ; i + + ) {
Array bs_data ;
if ( surfaces [ i ] . blend_shape_data . size ( ) ) {
for ( int j = 0 ; j < surfaces [ i ] . blend_shape_data . size ( ) ; j + + ) {
bs_data . push_back ( surfaces [ i ] . blend_shape_data [ j ] . arrays ) ;
}
}
Dictionary lods ;
if ( surfaces [ i ] . lods . size ( ) ) {
for ( int j = 0 ; j < surfaces [ i ] . lods . size ( ) ; j + + ) {
lods [ surfaces [ i ] . lods [ j ] . distance ] = surfaces [ i ] . lods [ j ] . indices ;
}
}
2021-09-08 21:29:14 -07:00
mesh - > add_surface_from_arrays ( surfaces [ i ] . primitive , surfaces [ i ] . arrays , bs_data , lods , surfaces [ i ] . flags ) ;
2020-12-21 07:39:32 -08:00
if ( surfaces [ i ] . material . is_valid ( ) ) {
mesh - > surface_set_material ( mesh - > get_surface_count ( ) - 1 , surfaces [ i ] . material ) ;
}
2021-12-09 03:42:46 -06:00
if ( ! surfaces [ i ] . name . is_empty ( ) ) {
2020-12-21 07:39:32 -08:00
mesh - > surface_set_name ( mesh - > get_surface_count ( ) - 1 , surfaces [ i ] . name ) ;
}
}
2021-01-25 12:20:11 -03:00
2021-03-19 09:57:52 -03:00
mesh - > set_lightmap_size_hint ( lightmap_size_hint ) ;
2021-01-25 12:20:11 -03:00
if ( shadow_mesh . is_valid ( ) ) {
Ref < ArrayMesh > shadow = shadow_mesh - > get_mesh ( ) ;
mesh - > set_shadow_mesh ( shadow ) ;
}
2020-12-21 07:39:32 -08:00
}
return mesh ;
}
2021-09-20 18:24:31 -07:00
void ImporterMesh : : clear ( ) {
2020-12-21 07:39:32 -08:00
surfaces . clear ( ) ;
blend_shapes . clear ( ) ;
mesh . unref ( ) ;
}
2021-09-20 18:24:31 -07:00
void ImporterMesh : : create_shadow_mesh ( ) {
2021-01-25 12:20:11 -03:00
if ( shadow_mesh . is_valid ( ) ) {
shadow_mesh . unref ( ) ;
}
//no shadow mesh for blendshapes
if ( blend_shapes . size ( ) > 0 ) {
return ;
}
//no shadow mesh for skeletons
for ( int i = 0 ; i < surfaces . size ( ) ; i + + ) {
if ( surfaces [ i ] . arrays [ RS : : ARRAY_BONES ] . get_type ( ) ! = Variant : : NIL ) {
return ;
}
if ( surfaces [ i ] . arrays [ RS : : ARRAY_WEIGHTS ] . get_type ( ) ! = Variant : : NIL ) {
return ;
}
}
2021-06-17 16:03:09 -06:00
shadow_mesh . instantiate ( ) ;
2021-01-25 12:20:11 -03:00
for ( int i = 0 ; i < surfaces . size ( ) ; i + + ) {
LocalVector < int > vertex_remap ;
Vector < Vector3 > new_vertices ;
Vector < Vector3 > vertices = surfaces [ i ] . arrays [ RS : : ARRAY_VERTEX ] ;
int vertex_count = vertices . size ( ) ;
{
2022-05-13 15:04:37 +02:00
HashMap < Vector3 , int > unique_vertices ;
2021-01-25 12:20:11 -03:00
const Vector3 * vptr = vertices . ptr ( ) ;
for ( int j = 0 ; j < vertex_count ; j + + ) {
2021-09-07 17:44:50 +02:00
const Vector3 & v = vptr [ j ] ;
2021-01-25 12:20:11 -03:00
2022-05-13 15:04:37 +02:00
HashMap < Vector3 , int > : : Iterator E = unique_vertices . find ( v ) ;
2021-01-25 12:20:11 -03:00
if ( E ) {
2022-05-13 15:04:37 +02:00
vertex_remap . push_back ( E - > value ) ;
2021-01-25 12:20:11 -03:00
} else {
int vcount = unique_vertices . size ( ) ;
unique_vertices [ v ] = vcount ;
vertex_remap . push_back ( vcount ) ;
new_vertices . push_back ( v ) ;
}
}
}
Array new_surface ;
new_surface . resize ( RS : : ARRAY_MAX ) ;
Dictionary lods ;
// print_line("original vertex count: " + itos(vertices.size()) + " new vertex count: " + itos(new_vertices.size()));
new_surface [ RS : : ARRAY_VERTEX ] = new_vertices ;
Vector < int > indices = surfaces [ i ] . arrays [ RS : : ARRAY_INDEX ] ;
if ( indices . size ( ) ) {
int index_count = indices . size ( ) ;
const int * index_rptr = indices . ptr ( ) ;
Vector < int > new_indices ;
new_indices . resize ( indices . size ( ) ) ;
int * index_wptr = new_indices . ptrw ( ) ;
for ( int j = 0 ; j < index_count ; j + + ) {
int index = index_rptr [ j ] ;
ERR_FAIL_INDEX ( index , vertex_count ) ;
index_wptr [ j ] = vertex_remap [ index ] ;
}
new_surface [ RS : : ARRAY_INDEX ] = new_indices ;
// Make sure the same LODs as the full version are used.
// This makes it more coherent between rendered model and its shadows.
for ( int j = 0 ; j < surfaces [ i ] . lods . size ( ) ; j + + ) {
indices = surfaces [ i ] . lods [ j ] . indices ;
index_count = indices . size ( ) ;
index_rptr = indices . ptr ( ) ;
new_indices . resize ( indices . size ( ) ) ;
index_wptr = new_indices . ptrw ( ) ;
for ( int k = 0 ; k < index_count ; k + + ) {
2021-09-07 17:44:50 +02:00
int index = index_rptr [ k ] ;
2021-01-25 12:20:11 -03:00
ERR_FAIL_INDEX ( index , vertex_count ) ;
2021-09-07 17:44:50 +02:00
index_wptr [ k ] = vertex_remap [ index ] ;
2021-01-25 12:20:11 -03:00
}
lods [ surfaces [ i ] . lods [ j ] . distance ] = new_indices ;
}
}
2021-09-08 21:29:14 -07:00
shadow_mesh - > add_surface ( surfaces [ i ] . primitive , new_surface , Array ( ) , lods , Ref < Material > ( ) , surfaces [ i ] . name , surfaces [ i ] . flags ) ;
2021-01-25 12:20:11 -03:00
}
}
2021-09-20 18:24:31 -07:00
Ref < ImporterMesh > ImporterMesh : : get_shadow_mesh ( ) const {
2021-01-25 12:20:11 -03:00
return shadow_mesh ;
}
2021-09-20 18:24:31 -07:00
void ImporterMesh : : _set_data ( const Dictionary & p_data ) {
2020-12-21 07:39:32 -08:00
clear ( ) ;
if ( p_data . has ( " blend_shape_names " ) ) {
blend_shapes = p_data [ " blend_shape_names " ] ;
}
if ( p_data . has ( " surfaces " ) ) {
Array surface_arr = p_data [ " surfaces " ] ;
for ( int i = 0 ; i < surface_arr . size ( ) ; i + + ) {
Dictionary s = surface_arr [ i ] ;
ERR_CONTINUE ( ! s . has ( " primitive " ) ) ;
ERR_CONTINUE ( ! s . has ( " arrays " ) ) ;
Mesh : : PrimitiveType prim = Mesh : : PrimitiveType ( int ( s [ " primitive " ] ) ) ;
ERR_CONTINUE ( prim > = Mesh : : PRIMITIVE_MAX ) ;
Array arr = s [ " arrays " ] ;
Dictionary lods ;
2022-09-29 12:53:28 +03:00
String surf_name ;
2020-12-21 07:39:32 -08:00
if ( s . has ( " name " ) ) {
2022-09-29 12:53:28 +03:00
surf_name = s [ " name " ] ;
2020-12-21 07:39:32 -08:00
}
if ( s . has ( " lods " ) ) {
lods = s [ " lods " ] ;
}
2021-09-07 17:44:50 +02:00
Array b_shapes ;
if ( s . has ( " b_shapes " ) ) {
b_shapes = s [ " b_shapes " ] ;
2020-12-21 07:39:32 -08:00
}
Ref < Material > material ;
if ( s . has ( " material " ) ) {
material = s [ " material " ] ;
}
2023-10-13 21:59:56 -06:00
uint64_t flags = 0 ;
2021-09-08 21:29:14 -07:00
if ( s . has ( " flags " ) ) {
flags = s [ " flags " ] ;
}
2022-09-29 12:53:28 +03:00
add_surface ( prim , arr , b_shapes , lods , material , surf_name , flags ) ;
2020-12-21 07:39:32 -08:00
}
}
}
2021-09-20 18:24:31 -07:00
Dictionary ImporterMesh : : _get_data ( ) const {
2020-12-21 07:39:32 -08:00
Dictionary data ;
if ( blend_shapes . size ( ) ) {
data [ " blend_shape_names " ] = blend_shapes ;
}
Array surface_arr ;
for ( int i = 0 ; i < surfaces . size ( ) ; i + + ) {
Dictionary d ;
d [ " primitive " ] = surfaces [ i ] . primitive ;
d [ " arrays " ] = surfaces [ i ] . arrays ;
if ( surfaces [ i ] . blend_shape_data . size ( ) ) {
Array bs_data ;
for ( int j = 0 ; j < surfaces [ i ] . blend_shape_data . size ( ) ; j + + ) {
bs_data . push_back ( surfaces [ i ] . blend_shape_data [ j ] . arrays ) ;
}
d [ " blend_shapes " ] = bs_data ;
}
if ( surfaces [ i ] . lods . size ( ) ) {
Dictionary lods ;
for ( int j = 0 ; j < surfaces [ i ] . lods . size ( ) ; j + + ) {
lods [ surfaces [ i ] . lods [ j ] . distance ] = surfaces [ i ] . lods [ j ] . indices ;
}
d [ " lods " ] = lods ;
}
if ( surfaces [ i ] . material . is_valid ( ) ) {
d [ " material " ] = surfaces [ i ] . material ;
}
2021-12-09 03:42:46 -06:00
if ( ! surfaces [ i ] . name . is_empty ( ) ) {
2020-12-21 07:39:32 -08:00
d [ " name " ] = surfaces [ i ] . name ;
}
2023-10-13 21:59:56 -06:00
d [ " flags " ] = surfaces [ i ] . flags ;
2021-09-08 21:29:14 -07:00
2020-12-21 07:39:32 -08:00
surface_arr . push_back ( d ) ;
}
data [ " surfaces " ] = surface_arr ;
return data ;
}
2021-09-20 18:24:31 -07:00
Vector < Face3 > ImporterMesh : : get_faces ( ) const {
2021-03-19 09:57:52 -03:00
Vector < Face3 > faces ;
for ( int i = 0 ; i < surfaces . size ( ) ; i + + ) {
if ( surfaces [ i ] . primitive = = Mesh : : PRIMITIVE_TRIANGLES ) {
Vector < Vector3 > vertices = surfaces [ i ] . arrays [ Mesh : : ARRAY_VERTEX ] ;
Vector < int > indices = surfaces [ i ] . arrays [ Mesh : : ARRAY_INDEX ] ;
if ( indices . size ( ) ) {
for ( int j = 0 ; j < indices . size ( ) ; j + = 3 ) {
Face3 f ;
f . vertex [ 0 ] = vertices [ indices [ j + 0 ] ] ;
f . vertex [ 1 ] = vertices [ indices [ j + 1 ] ] ;
f . vertex [ 2 ] = vertices [ indices [ j + 2 ] ] ;
faces . push_back ( f ) ;
}
} else {
for ( int j = 0 ; j < vertices . size ( ) ; j + = 3 ) {
Face3 f ;
f . vertex [ 0 ] = vertices [ j + 0 ] ;
f . vertex [ 1 ] = vertices [ j + 1 ] ;
f . vertex [ 2 ] = vertices [ j + 2 ] ;
faces . push_back ( f ) ;
}
}
}
}
return faces ;
}
2025-02-27 19:01:23 -03:00
# ifndef PHYSICS_3D_DISABLED
2023-01-26 16:10:26 +01:00
Vector < Ref < Shape3D > > ImporterMesh : : convex_decompose ( const Ref < MeshConvexDecompositionSettings > & p_settings ) const {
2023-06-06 14:59:54 +02:00
ERR_FAIL_NULL_V ( Mesh : : convex_decomposition_function , Vector < Ref < Shape3D > > ( ) ) ;
2021-03-19 09:57:52 -03:00
const Vector < Face3 > faces = get_faces ( ) ;
2021-09-14 17:14:06 -07:00
int face_count = faces . size ( ) ;
Vector < Vector3 > vertices ;
uint32_t vertex_count = 0 ;
vertices . resize ( face_count * 3 ) ;
Vector < uint32_t > indices ;
indices . resize ( face_count * 3 ) ;
{
2022-05-13 15:04:37 +02:00
HashMap < Vector3 , uint32_t > vertex_map ;
2021-09-14 17:14:06 -07:00
Vector3 * vertex_w = vertices . ptrw ( ) ;
uint32_t * index_w = indices . ptrw ( ) ;
for ( int i = 0 ; i < face_count ; i + + ) {
for ( int j = 0 ; j < 3 ; j + + ) {
const Vector3 & vertex = faces [ i ] . vertex [ j ] ;
2022-05-13 15:04:37 +02:00
HashMap < Vector3 , uint32_t > : : Iterator found_vertex = vertex_map . find ( vertex ) ;
2021-09-14 17:14:06 -07:00
uint32_t index ;
if ( found_vertex ) {
2022-05-13 15:04:37 +02:00
index = found_vertex - > value ;
2021-09-14 17:14:06 -07:00
} else {
2023-12-01 16:38:08 -05:00
index = vertex_count + + ;
2021-09-14 17:14:06 -07:00
vertex_map [ vertex ] = index ;
vertex_w [ index ] = vertex ;
}
index_w [ i * 3 + j ] = index ;
}
}
}
vertices . resize ( vertex_count ) ;
2021-03-19 09:57:52 -03:00
2021-09-14 17:14:06 -07:00
Vector < Vector < Vector3 > > decomposed = Mesh : : convex_decomposition_function ( ( real_t * ) vertices . ptr ( ) , vertex_count , indices . ptr ( ) , face_count , p_settings , nullptr ) ;
2021-03-19 09:57:52 -03:00
Vector < Ref < Shape3D > > ret ;
for ( int i = 0 ; i < decomposed . size ( ) ; i + + ) {
Ref < ConvexPolygonShape3D > shape ;
2021-06-17 16:03:09 -06:00
shape . instantiate ( ) ;
2021-09-14 17:14:06 -07:00
shape - > set_points ( decomposed [ i ] ) ;
2021-03-19 09:57:52 -03:00
ret . push_back ( shape ) ;
}
return ret ;
}
2023-02-23 11:07:48 +01:00
Ref < ConvexPolygonShape3D > ImporterMesh : : create_convex_shape ( bool p_clean , bool p_simplify ) const {
if ( p_simplify ) {
2023-01-26 16:10:26 +01:00
Ref < MeshConvexDecompositionSettings > settings ;
settings . instantiate ( ) ;
settings - > set_max_convex_hulls ( 1 ) ;
2023-02-23 11:07:48 +01:00
Vector < Ref < Shape3D > > decomposed = convex_decompose ( settings ) ;
if ( decomposed . size ( ) = = 1 ) {
return decomposed [ 0 ] ;
} else {
ERR_PRINT ( " Convex shape simplification failed, falling back to simpler process. " ) ;
}
}
Vector < Vector3 > vertices ;
for ( int i = 0 ; i < get_surface_count ( ) ; i + + ) {
Array a = get_surface_arrays ( i ) ;
ERR_FAIL_COND_V ( a . is_empty ( ) , Ref < ConvexPolygonShape3D > ( ) ) ;
Vector < Vector3 > v = a [ Mesh : : ARRAY_VERTEX ] ;
vertices . append_array ( v ) ;
}
Ref < ConvexPolygonShape3D > shape = memnew ( ConvexPolygonShape3D ) ;
if ( p_clean ) {
Geometry3D : : MeshData md ;
Error err = ConvexHullComputer : : convex_hull ( vertices , md ) ;
if ( err = = OK ) {
shape - > set_points ( md . vertices ) ;
return shape ;
} else {
ERR_PRINT ( " Convex shape cleaning failed, falling back to simpler process. " ) ;
}
}
shape - > set_points ( vertices ) ;
return shape ;
}
2022-11-25 11:43:06 -06:00
Ref < ConcavePolygonShape3D > ImporterMesh : : create_trimesh_shape ( ) const {
2021-03-19 09:57:52 -03:00
Vector < Face3 > faces = get_faces ( ) ;
2025-03-20 00:07:31 +08:00
if ( faces . is_empty ( ) ) {
2022-11-25 11:43:06 -06:00
return Ref < ConcavePolygonShape3D > ( ) ;
2021-03-19 09:57:52 -03:00
}
Vector < Vector3 > face_points ;
face_points . resize ( faces . size ( ) * 3 ) ;
for ( int i = 0 ; i < face_points . size ( ) ; i + = 3 ) {
Face3 f = faces . get ( i / 3 ) ;
face_points . set ( i , f . vertex [ 0 ] ) ;
face_points . set ( i + 1 , f . vertex [ 1 ] ) ;
face_points . set ( i + 2 , f . vertex [ 2 ] ) ;
}
Ref < ConcavePolygonShape3D > shape = memnew ( ConcavePolygonShape3D ) ;
shape - > set_faces ( face_points ) ;
return shape ;
}
2025-02-27 19:01:23 -03:00
# endif // PHYSICS_3D_DISABLED
2021-03-19 09:57:52 -03:00
2021-09-20 18:24:31 -07:00
Ref < NavigationMesh > ImporterMesh : : create_navigation_mesh ( ) {
2021-03-19 09:57:52 -03:00
Vector < Face3 > faces = get_faces ( ) ;
2025-03-20 00:07:31 +08:00
if ( faces . is_empty ( ) ) {
2021-03-19 09:57:52 -03:00
return Ref < NavigationMesh > ( ) ;
}
2022-05-13 15:04:37 +02:00
HashMap < Vector3 , int > unique_vertices ;
2024-06-14 18:48:45 +01:00
Vector < Vector < int > > face_polygons ;
face_polygons . resize ( faces . size ( ) ) ;
2021-03-19 09:57:52 -03:00
for ( int i = 0 ; i < faces . size ( ) ; i + + ) {
2024-06-14 18:48:45 +01:00
Vector < int > face_indices ;
face_indices . resize ( 3 ) ;
2021-03-19 09:57:52 -03:00
for ( int j = 0 ; j < 3 ; j + + ) {
Vector3 v = faces [ i ] . vertex [ j ] ;
int idx ;
if ( unique_vertices . has ( v ) ) {
idx = unique_vertices [ v ] ;
} else {
idx = unique_vertices . size ( ) ;
unique_vertices [ v ] = idx ;
}
2024-06-14 18:48:45 +01:00
face_indices . write [ j ] = idx ;
2021-03-19 09:57:52 -03:00
}
2024-06-14 18:48:45 +01:00
face_polygons . write [ i ] = face_indices ;
2021-03-19 09:57:52 -03:00
}
Vector < Vector3 > vertices ;
vertices . resize ( unique_vertices . size ( ) ) ;
2021-08-09 14:13:42 -06:00
for ( const KeyValue < Vector3 , int > & E : unique_vertices ) {
vertices . write [ E . value ] = E . key ;
2021-03-19 09:57:52 -03:00
}
Ref < NavigationMesh > nm ;
2021-06-17 16:03:09 -06:00
nm . instantiate ( ) ;
2024-06-14 18:48:45 +01:00
nm - > set_data ( vertices , face_polygons ) ;
2021-03-19 09:57:52 -03:00
return nm ;
}
2021-04-25 23:36:39 +02:00
extern bool ( * array_mesh_lightmap_unwrap_callback ) ( float p_texel_size , const float * p_vertices , const float * p_normals , int p_vertex_count , const int * p_indices , int p_index_count , const uint8_t * p_cache_data , bool * r_use_cache , uint8_t * * r_mesh_cache , int * r_mesh_cache_size , float * * r_uv , int * * r_vertex , int * r_vertex_count , int * * r_index , int * r_index_count , int * r_size_hint_x , int * r_size_hint_y ) ;
2021-03-19 09:57:52 -03:00
2021-10-14 14:34:27 -03:00
struct EditorSceneFormatImporterMeshLightmapSurface {
2021-03-19 09:57:52 -03:00
Ref < Material > material ;
LocalVector < SurfaceTool : : Vertex > vertices ;
Mesh : : PrimitiveType primitive = Mesh : : PrimitiveType : : PRIMITIVE_MAX ;
2023-08-29 21:04:32 +02:00
uint64_t format = 0 ;
2021-03-19 09:57:52 -03:00
String name ;
} ;
2023-01-30 22:37:38 -08:00
static const uint32_t custom_shift [ RS : : ARRAY_CUSTOM_COUNT ] = { Mesh : : ARRAY_FORMAT_CUSTOM0_SHIFT , Mesh : : ARRAY_FORMAT_CUSTOM1_SHIFT , Mesh : : ARRAY_FORMAT_CUSTOM2_SHIFT , Mesh : : ARRAY_FORMAT_CUSTOM3_SHIFT } ;
2021-09-20 18:24:31 -07:00
Error ImporterMesh : : lightmap_unwrap_cached ( const Transform3D & p_base_transform , float p_texel_size , const Vector < uint8_t > & p_src_cache , Vector < uint8_t > & r_dst_cache ) {
2023-06-06 14:59:54 +02:00
ERR_FAIL_NULL_V ( array_mesh_lightmap_unwrap_callback , ERR_UNCONFIGURED ) ;
2021-03-19 09:57:52 -03:00
ERR_FAIL_COND_V_MSG ( blend_shapes . size ( ) ! = 0 , ERR_UNAVAILABLE , " Can't unwrap mesh with blend shapes. " ) ;
2021-04-25 23:36:39 +02:00
LocalVector < float > vertices ;
LocalVector < float > normals ;
LocalVector < int > indices ;
LocalVector < float > uv ;
LocalVector < Pair < int , int > > uv_indices ;
2021-03-19 09:57:52 -03:00
2021-10-14 14:34:27 -03:00
Vector < EditorSceneFormatImporterMeshLightmapSurface > lightmap_surfaces ;
2021-03-19 09:57:52 -03:00
// Keep only the scale
2021-04-25 23:36:39 +02:00
Basis basis = p_base_transform . get_basis ( ) ;
2022-05-03 07:50:35 -05:00
Vector3 scale = Vector3 ( basis . get_column ( 0 ) . length ( ) , basis . get_column ( 1 ) . length ( ) , basis . get_column ( 2 ) . length ( ) ) ;
2021-04-25 23:36:39 +02:00
2020-10-17 01:08:21 -04:00
Transform3D transform ;
2021-04-25 23:36:39 +02:00
transform . scale ( scale ) ;
2021-03-19 09:57:52 -03:00
Basis normal_basis = transform . basis . inverse ( ) . transposed ( ) ;
for ( int i = 0 ; i < get_surface_count ( ) ; i + + ) {
2021-10-14 14:34:27 -03:00
EditorSceneFormatImporterMeshLightmapSurface s ;
2021-03-19 09:57:52 -03:00
s . primitive = get_surface_primitive_type ( i ) ;
ERR_FAIL_COND_V_MSG ( s . primitive ! = Mesh : : PRIMITIVE_TRIANGLES , ERR_UNAVAILABLE , " Only triangles are supported for lightmap unwrap. " ) ;
Array arrays = get_surface_arrays ( i ) ;
s . material = get_surface_material ( i ) ;
s . name = get_surface_name ( i ) ;
2024-04-17 22:05:42 -07:00
SurfaceTool : : create_vertex_array_from_arrays ( arrays , s . vertices , & s . format ) ;
2021-03-19 09:57:52 -03:00
2021-04-25 23:36:39 +02:00
PackedVector3Array rvertices = arrays [ Mesh : : ARRAY_VERTEX ] ;
2021-03-19 09:57:52 -03:00
int vc = rvertices . size ( ) ;
2021-04-25 23:36:39 +02:00
PackedVector3Array rnormals = arrays [ Mesh : : ARRAY_NORMAL ] ;
2021-03-19 09:57:52 -03:00
2022-04-09 08:11:22 -07:00
if ( ! rnormals . size ( ) ) {
continue ;
}
2021-03-19 09:57:52 -03:00
int vertex_ofs = vertices . size ( ) / 3 ;
vertices . resize ( ( vertex_ofs + vc ) * 3 ) ;
normals . resize ( ( vertex_ofs + vc ) * 3 ) ;
uv_indices . resize ( vertex_ofs + vc ) ;
for ( int j = 0 ; j < vc ; j + + ) {
2021-04-25 23:36:39 +02:00
Vector3 v = transform . xform ( rvertices [ j ] ) ;
Vector3 n = normal_basis . xform ( rnormals [ j ] ) . normalized ( ) ;
vertices [ ( j + vertex_ofs ) * 3 + 0 ] = v . x ;
vertices [ ( j + vertex_ofs ) * 3 + 1 ] = v . y ;
vertices [ ( j + vertex_ofs ) * 3 + 2 ] = v . z ;
normals [ ( j + vertex_ofs ) * 3 + 0 ] = n . x ;
normals [ ( j + vertex_ofs ) * 3 + 1 ] = n . y ;
normals [ ( j + vertex_ofs ) * 3 + 2 ] = n . z ;
uv_indices [ j + vertex_ofs ] = Pair < int , int > ( i , j ) ;
2021-03-19 09:57:52 -03:00
}
2021-04-25 23:36:39 +02:00
PackedInt32Array rindices = arrays [ Mesh : : ARRAY_INDEX ] ;
2021-03-19 09:57:52 -03:00
int ic = rindices . size ( ) ;
2021-04-25 23:36:39 +02:00
float eps = 1.19209290e-7 F ; // Taken from xatlas.h
2021-03-19 09:57:52 -03:00
if ( ic = = 0 ) {
for ( int j = 0 ; j < vc / 3 ; j + + ) {
2021-04-25 23:36:39 +02:00
Vector3 p0 = transform . xform ( rvertices [ j * 3 + 0 ] ) ;
Vector3 p1 = transform . xform ( rvertices [ j * 3 + 1 ] ) ;
Vector3 p2 = transform . xform ( rvertices [ j * 3 + 2 ] ) ;
if ( ( p0 - p1 ) . length_squared ( ) < eps | | ( p1 - p2 ) . length_squared ( ) < eps | | ( p2 - p0 ) . length_squared ( ) < eps ) {
2021-03-19 09:57:52 -03:00
continue ;
}
indices . push_back ( vertex_ofs + j * 3 + 0 ) ;
indices . push_back ( vertex_ofs + j * 3 + 1 ) ;
indices . push_back ( vertex_ofs + j * 3 + 2 ) ;
}
} else {
for ( int j = 0 ; j < ic / 3 ; j + + ) {
2022-04-09 08:11:22 -07:00
ERR_FAIL_INDEX_V ( rindices [ j * 3 + 0 ] , rvertices . size ( ) , ERR_INVALID_DATA ) ;
ERR_FAIL_INDEX_V ( rindices [ j * 3 + 1 ] , rvertices . size ( ) , ERR_INVALID_DATA ) ;
ERR_FAIL_INDEX_V ( rindices [ j * 3 + 2 ] , rvertices . size ( ) , ERR_INVALID_DATA ) ;
2021-04-25 23:36:39 +02:00
Vector3 p0 = transform . xform ( rvertices [ rindices [ j * 3 + 0 ] ] ) ;
Vector3 p1 = transform . xform ( rvertices [ rindices [ j * 3 + 1 ] ] ) ;
Vector3 p2 = transform . xform ( rvertices [ rindices [ j * 3 + 2 ] ] ) ;
if ( ( p0 - p1 ) . length_squared ( ) < eps | | ( p1 - p2 ) . length_squared ( ) < eps | | ( p2 - p0 ) . length_squared ( ) < eps ) {
2021-03-19 09:57:52 -03:00
continue ;
}
2021-04-25 23:36:39 +02:00
indices . push_back ( vertex_ofs + rindices [ j * 3 + 0 ] ) ;
indices . push_back ( vertex_ofs + rindices [ j * 3 + 1 ] ) ;
indices . push_back ( vertex_ofs + rindices [ j * 3 + 2 ] ) ;
2021-03-19 09:57:52 -03:00
}
}
lightmap_surfaces . push_back ( s ) ;
}
//unwrap
2021-04-25 23:36:39 +02:00
bool use_cache = true ; // Used to request cache generation and to know if cache was used
uint8_t * gen_cache ;
int gen_cache_size ;
2021-03-19 09:57:52 -03:00
float * gen_uvs ;
int * gen_vertices ;
int * gen_indices ;
int gen_vertex_count ;
int gen_index_count ;
int size_x ;
int size_y ;
2021-04-25 23:36:39 +02:00
bool ok = array_mesh_lightmap_unwrap_callback ( p_texel_size , vertices . ptr ( ) , normals . ptr ( ) , vertices . size ( ) / 3 , indices . ptr ( ) , indices . size ( ) , p_src_cache . ptr ( ) , & use_cache , & gen_cache , & gen_cache_size , & gen_uvs , & gen_vertices , & gen_vertex_count , & gen_indices , & gen_index_count , & size_x , & size_y ) ;
2021-03-19 09:57:52 -03:00
if ( ! ok ) {
return ERR_CANT_CREATE ;
}
//create surfacetools for each surface..
2021-04-25 23:36:39 +02:00
LocalVector < Ref < SurfaceTool > > surfaces_tools ;
2021-03-19 09:57:52 -03:00
for ( int i = 0 ; i < lightmap_surfaces . size ( ) ; i + + ) {
Ref < SurfaceTool > st ;
2021-06-17 16:03:09 -06:00
st . instantiate ( ) ;
2023-09-18 11:21:29 +03:00
st - > set_skin_weight_count ( ( lightmap_surfaces [ i ] . format & Mesh : : ARRAY_FLAG_USE_8_BONE_WEIGHTS ) ? SurfaceTool : : SKIN_8_WEIGHTS : SurfaceTool : : SKIN_4_WEIGHTS ) ;
2021-03-19 09:57:52 -03:00
st - > begin ( Mesh : : PRIMITIVE_TRIANGLES ) ;
st - > set_material ( lightmap_surfaces [ i ] . material ) ;
st - > set_meta ( " name " , lightmap_surfaces [ i ] . name ) ;
2023-01-30 22:37:38 -08:00
for ( int custom_i = 0 ; custom_i < RS : : ARRAY_CUSTOM_COUNT ; custom_i + + ) {
st - > set_custom_format ( custom_i , ( SurfaceTool : : CustomFormat ) ( ( lightmap_surfaces [ i ] . format > > custom_shift [ custom_i ] ) & RS : : ARRAY_FORMAT_CUSTOM_MASK ) ) ;
}
2021-03-19 09:57:52 -03:00
surfaces_tools . push_back ( st ) ; //stay there
}
2023-01-30 22:37:38 -08:00
//remove surfaces
clear ( ) ;
2021-03-19 09:57:52 -03:00
print_verbose ( " Mesh: Gen indices: " + itos ( gen_index_count ) ) ;
2021-04-25 23:36:39 +02:00
2021-03-19 09:57:52 -03:00
//go through all indices
for ( int i = 0 ; i < gen_index_count ; i + = 3 ) {
2021-04-25 23:36:39 +02:00
ERR_FAIL_INDEX_V ( gen_vertices [ gen_indices [ i + 0 ] ] , ( int ) uv_indices . size ( ) , ERR_BUG ) ;
ERR_FAIL_INDEX_V ( gen_vertices [ gen_indices [ i + 1 ] ] , ( int ) uv_indices . size ( ) , ERR_BUG ) ;
ERR_FAIL_INDEX_V ( gen_vertices [ gen_indices [ i + 2 ] ] , ( int ) uv_indices . size ( ) , ERR_BUG ) ;
2021-03-19 09:57:52 -03:00
ERR_FAIL_COND_V ( uv_indices [ gen_vertices [ gen_indices [ i + 0 ] ] ] . first ! = uv_indices [ gen_vertices [ gen_indices [ i + 1 ] ] ] . first | | uv_indices [ gen_vertices [ gen_indices [ i + 0 ] ] ] . first ! = uv_indices [ gen_vertices [ gen_indices [ i + 2 ] ] ] . first , ERR_BUG ) ;
int surface = uv_indices [ gen_vertices [ gen_indices [ i + 0 ] ] ] . first ;
for ( int j = 0 ; j < 3 ; j + + ) {
SurfaceTool : : Vertex v = lightmap_surfaces [ surface ] . vertices [ uv_indices [ gen_vertices [ gen_indices [ i + j ] ] ] . second ] ;
if ( lightmap_surfaces [ surface ] . format & Mesh : : ARRAY_FORMAT_COLOR ) {
2021-04-25 23:36:39 +02:00
surfaces_tools [ surface ] - > set_color ( v . color ) ;
2021-03-19 09:57:52 -03:00
}
if ( lightmap_surfaces [ surface ] . format & Mesh : : ARRAY_FORMAT_TEX_UV ) {
2021-04-25 23:36:39 +02:00
surfaces_tools [ surface ] - > set_uv ( v . uv ) ;
2021-03-19 09:57:52 -03:00
}
if ( lightmap_surfaces [ surface ] . format & Mesh : : ARRAY_FORMAT_NORMAL ) {
2021-04-25 23:36:39 +02:00
surfaces_tools [ surface ] - > set_normal ( v . normal ) ;
2021-03-19 09:57:52 -03:00
}
if ( lightmap_surfaces [ surface ] . format & Mesh : : ARRAY_FORMAT_TANGENT ) {
Plane t ;
t . normal = v . tangent ;
t . d = v . binormal . dot ( v . normal . cross ( v . tangent ) ) < 0 ? - 1 : 1 ;
2021-04-25 23:36:39 +02:00
surfaces_tools [ surface ] - > set_tangent ( t ) ;
2021-03-19 09:57:52 -03:00
}
if ( lightmap_surfaces [ surface ] . format & Mesh : : ARRAY_FORMAT_BONES ) {
2021-04-25 23:36:39 +02:00
surfaces_tools [ surface ] - > set_bones ( v . bones ) ;
2021-03-19 09:57:52 -03:00
}
if ( lightmap_surfaces [ surface ] . format & Mesh : : ARRAY_FORMAT_WEIGHTS ) {
2021-04-25 23:36:39 +02:00
surfaces_tools [ surface ] - > set_weights ( v . weights ) ;
2021-03-19 09:57:52 -03:00
}
2023-01-30 22:37:38 -08:00
for ( int custom_i = 0 ; custom_i < RS : : ARRAY_CUSTOM_COUNT ; custom_i + + ) {
if ( ( lightmap_surfaces [ surface ] . format > > custom_shift [ custom_i ] ) & RS : : ARRAY_FORMAT_CUSTOM_MASK ) {
surfaces_tools [ surface ] - > set_custom ( custom_i , v . custom [ custom_i ] ) ;
}
}
2021-03-19 09:57:52 -03:00
Vector2 uv2 ( gen_uvs [ gen_indices [ i + j ] * 2 + 0 ] , gen_uvs [ gen_indices [ i + j ] * 2 + 1 ] ) ;
2021-04-25 23:36:39 +02:00
surfaces_tools [ surface ] - > set_uv2 ( uv2 ) ;
2021-03-19 09:57:52 -03:00
2021-04-25 23:36:39 +02:00
surfaces_tools [ surface ] - > add_vertex ( v . vertex ) ;
2021-03-19 09:57:52 -03:00
}
}
//generate surfaces
2023-01-30 22:37:38 -08:00
for ( int i = 0 ; i < lightmap_surfaces . size ( ) ; i + + ) {
Ref < SurfaceTool > & tool = surfaces_tools [ i ] ;
2022-12-29 01:24:45 +01:00
tool - > index ( ) ;
Array arrays = tool - > commit_to_arrays ( ) ;
2023-09-18 11:21:29 +03:00
uint64_t format = lightmap_surfaces [ i ] . format ;
if ( tool - > get_skin_weight_count ( ) = = SurfaceTool : : SKIN_8_WEIGHTS ) {
format | = RS : : ARRAY_FLAG_USE_8_BONE_WEIGHTS ;
} else {
format & = ~ RS : : ARRAY_FLAG_USE_8_BONE_WEIGHTS ;
}
add_surface ( tool - > get_primitive_type ( ) , arrays , Array ( ) , Dictionary ( ) , tool - > get_material ( ) , tool - > get_meta ( " name " ) , format ) ;
2021-03-19 09:57:52 -03:00
}
set_lightmap_size_hint ( Size2 ( size_x , size_y ) ) ;
2021-04-25 23:36:39 +02:00
if ( gen_cache_size > 0 ) {
r_dst_cache . resize ( gen_cache_size ) ;
memcpy ( r_dst_cache . ptrw ( ) , gen_cache , gen_cache_size ) ;
memfree ( gen_cache ) ;
}
if ( ! use_cache ) {
// Cache was not used, free the buffers
memfree ( gen_vertices ) ;
memfree ( gen_indices ) ;
memfree ( gen_uvs ) ;
2021-03-19 09:57:52 -03:00
}
return OK ;
}
2021-09-20 18:24:31 -07:00
void ImporterMesh : : set_lightmap_size_hint ( const Size2i & p_size ) {
2021-03-19 09:57:52 -03:00
lightmap_size_hint = p_size ;
}
2021-09-20 18:24:31 -07:00
Size2i ImporterMesh : : get_lightmap_size_hint ( ) const {
2021-03-19 09:57:52 -03:00
return lightmap_size_hint ;
}
2021-09-20 18:24:31 -07:00
void ImporterMesh : : _bind_methods ( ) {
ClassDB : : bind_method ( D_METHOD ( " add_blend_shape " , " name " ) , & ImporterMesh : : add_blend_shape ) ;
ClassDB : : bind_method ( D_METHOD ( " get_blend_shape_count " ) , & ImporterMesh : : get_blend_shape_count ) ;
ClassDB : : bind_method ( D_METHOD ( " get_blend_shape_name " , " blend_shape_idx " ) , & ImporterMesh : : get_blend_shape_name ) ;
2020-12-21 07:39:32 -08:00
2021-09-20 18:24:31 -07:00
ClassDB : : bind_method ( D_METHOD ( " set_blend_shape_mode " , " mode " ) , & ImporterMesh : : set_blend_shape_mode ) ;
ClassDB : : bind_method ( D_METHOD ( " get_blend_shape_mode " ) , & ImporterMesh : : get_blend_shape_mode ) ;
2020-12-21 07:39:32 -08:00
2022-08-31 19:24:04 +02:00
ClassDB : : bind_method ( D_METHOD ( " add_surface " , " primitive " , " arrays " , " blend_shapes " , " lods " , " material " , " name " , " flags " ) , & ImporterMesh : : add_surface , DEFVAL ( TypedArray < Array > ( ) ) , DEFVAL ( Dictionary ( ) ) , DEFVAL ( Ref < Material > ( ) ) , DEFVAL ( String ( ) ) , DEFVAL ( 0 ) ) ;
2020-12-21 07:39:32 -08:00
2021-09-20 18:24:31 -07:00
ClassDB : : bind_method ( D_METHOD ( " get_surface_count " ) , & ImporterMesh : : get_surface_count ) ;
ClassDB : : bind_method ( D_METHOD ( " get_surface_primitive_type " , " surface_idx " ) , & ImporterMesh : : get_surface_primitive_type ) ;
ClassDB : : bind_method ( D_METHOD ( " get_surface_name " , " surface_idx " ) , & ImporterMesh : : get_surface_name ) ;
ClassDB : : bind_method ( D_METHOD ( " get_surface_arrays " , " surface_idx " ) , & ImporterMesh : : get_surface_arrays ) ;
ClassDB : : bind_method ( D_METHOD ( " get_surface_blend_shape_arrays " , " surface_idx " , " blend_shape_idx " ) , & ImporterMesh : : get_surface_blend_shape_arrays ) ;
ClassDB : : bind_method ( D_METHOD ( " get_surface_lod_count " , " surface_idx " ) , & ImporterMesh : : get_surface_lod_count ) ;
ClassDB : : bind_method ( D_METHOD ( " get_surface_lod_size " , " surface_idx " , " lod_idx " ) , & ImporterMesh : : get_surface_lod_size ) ;
ClassDB : : bind_method ( D_METHOD ( " get_surface_lod_indices " , " surface_idx " , " lod_idx " ) , & ImporterMesh : : get_surface_lod_indices ) ;
ClassDB : : bind_method ( D_METHOD ( " get_surface_material " , " surface_idx " ) , & ImporterMesh : : get_surface_material ) ;
ClassDB : : bind_method ( D_METHOD ( " get_surface_format " , " surface_idx " ) , & ImporterMesh : : get_surface_format ) ;
2020-12-21 07:39:32 -08:00
2021-09-20 18:24:31 -07:00
ClassDB : : bind_method ( D_METHOD ( " set_surface_name " , " surface_idx " , " name " ) , & ImporterMesh : : set_surface_name ) ;
ClassDB : : bind_method ( D_METHOD ( " set_surface_material " , " surface_idx " , " material " ) , & ImporterMesh : : set_surface_material ) ;
2021-08-22 18:11:57 -07:00
2024-06-28 18:32:59 -07:00
ClassDB : : bind_method ( D_METHOD ( " generate_lods " , " normal_merge_angle " , " normal_split_angle " , " bone_transform_array " ) , & ImporterMesh : : _generate_lods_bind ) ;
2021-09-20 18:24:31 -07:00
ClassDB : : bind_method ( D_METHOD ( " get_mesh " , " base_mesh " ) , & ImporterMesh : : get_mesh , DEFVAL ( Ref < ArrayMesh > ( ) ) ) ;
ClassDB : : bind_method ( D_METHOD ( " clear " ) , & ImporterMesh : : clear ) ;
2020-12-21 07:39:32 -08:00
2021-09-20 18:24:31 -07:00
ClassDB : : bind_method ( D_METHOD ( " _set_data " , " data " ) , & ImporterMesh : : _set_data ) ;
ClassDB : : bind_method ( D_METHOD ( " _get_data " ) , & ImporterMesh : : _get_data ) ;
2020-12-21 07:39:32 -08:00
2021-09-20 18:24:31 -07:00
ClassDB : : bind_method ( D_METHOD ( " set_lightmap_size_hint " , " size " ) , & ImporterMesh : : set_lightmap_size_hint ) ;
ClassDB : : bind_method ( D_METHOD ( " get_lightmap_size_hint " ) , & ImporterMesh : : get_lightmap_size_hint ) ;
2021-03-19 09:57:52 -03:00
2024-07-30 18:24:04 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : DICTIONARY , " _data " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL ) , " _set_data " , " _get_data " ) ;
2020-12-21 07:39:32 -08:00
}