@@ -43,6 +43,7 @@ SurfaceTool::SimplifyScaleFunc SurfaceTool::simplify_scale_func = nullptr;
4343SurfaceTool::GenerateRemapFunc SurfaceTool::generate_remap_func = nullptr ;
4444SurfaceTool::RemapVertexFunc SurfaceTool::remap_vertex_func = nullptr ;
4545SurfaceTool::RemapIndexFunc SurfaceTool::remap_index_func = nullptr ;
46+ SurfaceTool::GenerateTangentsFunc SurfaceTool::generate_tangents_func = nullptr ;
4647
4748void SurfaceTool::strip_mesh_arrays (PackedVector3Array &r_vertices, PackedInt32Array &r_indices) {
4849 ERR_FAIL_COND_MSG (!generate_remap_func || !remap_vertex_func || !remap_index_func, " Meshoptimizer library is not initialized." );
@@ -1053,123 +1054,105 @@ void SurfaceTool::append_from(const Ref<Mesh> &p_existing, int p_surface, const
10531054 }
10541055}
10551056
1056- // mikktspace callbacks
1057- namespace {
1058- struct TangentGenerationContextUserData {
1059- LocalVector<SurfaceTool::Vertex> *vertices;
1060- LocalVector<int > *indices;
1057+ struct TangentVertex {
1058+ float position[3 ];
1059+ float normal[3 ];
1060+ float uv[2 ];
10611061};
1062- } // namespace
10631062
1064- int SurfaceTool::mikktGetNumFaces (const SMikkTSpaceContext *pContext) {
1065- TangentGenerationContextUserData &triangle_data = *reinterpret_cast <TangentGenerationContextUserData *>(pContext->m_pUserData );
1063+ static void _propagate_tangents_or_split (LocalVector<SurfaceTool::Vertex> &r_vertex_array, LocalVector<int > &r_index_array, const float *p_tangents, bool p_split) {
1064+ // Seed each vertex with one of its corner tangents; the loop below fixes any mismatches.
1065+ for (size_t i = 0 ; i < r_index_array.size (); i++) {
1066+ Vector4 tangent (p_tangents[i * 4 + 0 ], p_tangents[i * 4 + 1 ], p_tangents[i * 4 + 2 ], p_tangents[i * 4 + 3 ]);
1067+ r_vertex_array[r_index_array[i]].tangent = Vector4 (p_tangents[i * 4 + 0 ], p_tangents[i * 4 + 1 ], p_tangents[i * 4 + 2 ], p_tangents[i * 4 + 3 ]);
1068+ }
10661069
1067- if (triangle_data.indices ->size () > 0 ) {
1068- return triangle_data.indices ->size () / 3 ;
1069- } else {
1070- return triangle_data.vertices ->size () / 3 ;
1070+ if (!p_split) {
1071+ return ;
10711072 }
1072- }
10731073
1074- int SurfaceTool::mikktGetNumVerticesOfFace ( const SMikkTSpaceContext *pContext, const int iFace) {
1075- return 3 ; // always 3
1076- }
1074+ LocalVector< uint32_t > splits;
1075+ splits. resize (r_vertex_array. size ());
1076+ memset (splits. ptr (), - 1 , splits. size () * sizeof ( uint32_t )); // ~0u means "no split copy"
10771077
1078- void SurfaceTool::mikktGetPosition (const SMikkTSpaceContext *pContext, float fvPosOut[], const int iFace, const int iVert) {
1079- TangentGenerationContextUserData &triangle_data = *reinterpret_cast <TangentGenerationContextUserData *>(pContext->m_pUserData );
1080- Vector3 v;
1081- if (triangle_data.indices ->size () > 0 ) {
1082- uint32_t index = triangle_data.indices ->operator [](iFace * 3 + iVert);
1083- if (index < triangle_data.vertices ->size ()) {
1084- v = triangle_data.vertices ->operator [](index).vertex ;
1078+ for (size_t i = 0 ; i < r_index_array.size (); i++) {
1079+ // Walk the chain of split copies looking for a vertex whose tangent matches.
1080+ Vector4 tangent (p_tangents[i * 4 + 0 ], p_tangents[i * 4 + 1 ], p_tangents[i * 4 + 2 ], p_tangents[i * 4 + 3 ]);
1081+ uint32_t v = r_index_array[i];
1082+ while (v != ~0u && r_vertex_array[v].tangent != tangent) {
1083+ v = splits[v];
10851084 }
1086- } else {
1087- v = triangle_data.vertices ->operator [](iFace * 3 + iVert).vertex ;
1088- }
1089-
1090- fvPosOut[0 ] = v.x ;
1091- fvPosOut[1 ] = v.y ;
1092- fvPosOut[2 ] = v.z ;
1093- }
10941085
1095- void SurfaceTool::mikktGetNormal ( const SMikkTSpaceContext *pContext, float fvNormOut[], const int iFace, const int iVert) {
1096- TangentGenerationContextUserData &triangle_data = * reinterpret_cast <TangentGenerationContextUserData *>(pContext-> m_pUserData );
1097- Vector3 v ;
1098- if (triangle_data. indices -> size () > 0 ) {
1099- uint32_t index = triangle_data. indices -> operator [](iFace * 3 + iVert) ;
1100- if (index < triangle_data. vertices -> size ()) {
1101- v = triangle_data. vertices -> operator [](index). normal ;
1086+ // No match in chain: append a new split copy with the target tangent and chain it.
1087+ if (v == ~ 0u ) {
1088+ v = r_vertex_array. size () ;
1089+ r_vertex_array. push_back (r_vertex_array[r_index_array[i]]);
1090+ r_vertex_array[v]. tangent = tangent ;
1091+ splits. push_back (splits[r_index_array[i]]);
1092+ splits[r_index_array[i]] = v ;
11021093 }
1103- } else {
1104- v = triangle_data. vertices -> operator [](iFace * 3 + iVert). normal ;
1094+
1095+ r_index_array[i] = int (v) ;
11051096 }
1097+ }
11061098
1107- fvNormOut[0 ] = v.x ;
1108- fvNormOut[1 ] = v.y ;
1109- fvNormOut[2 ] = v.z ;
1099+ void SurfaceTool::_generate_tangents_bind () {
1100+ generate_tangents (/* split*/ false );
11101101}
11111102
1112- void SurfaceTool::mikktGetTexCoord (const SMikkTSpaceContext *pContext, float fvTexcOut[], const int iFace, const int iVert) {
1113- TangentGenerationContextUserData &triangle_data = *reinterpret_cast <TangentGenerationContextUserData *>(pContext->m_pUserData );
1114- Vector2 v;
1115- if (triangle_data.indices ->size () > 0 ) {
1116- uint32_t index = triangle_data.indices ->operator [](iFace * 3 + iVert);
1117- if (index < triangle_data.vertices ->size ()) {
1118- v = triangle_data.vertices ->operator [](index).uv ;
1119- }
1120- } else {
1121- v = triangle_data.vertices ->operator [](iFace * 3 + iVert).uv ;
1103+ void SurfaceTool::generate_tangents (bool p_split) {
1104+ ERR_FAIL_COND_MSG (!generate_tangents_func, " Meshoptimizer library is not initialized." );
1105+ ERR_FAIL_COND_MSG (!(format & Mesh::ARRAY_FORMAT_TEX_UV ), " UVs are required to generate tangents." );
1106+ ERR_FAIL_COND (!(format & Mesh::ARRAY_FORMAT_NORMAL ));
1107+ ERR_FAIL_COND (primitive != Mesh::PRIMITIVE_TRIANGLES );
1108+
1109+ if (vertex_array.is_empty ()) {
1110+ format |= Mesh::ARRAY_FORMAT_TANGENT ;
1111+ return ;
11221112 }
11231113
1124- fvTexcOut[0 ] = v.x ;
1125- fvTexcOut[1 ] = v.y ;
1126- }
1114+ size_t corner_count = index_array.size () > 0 ? index_array.size () : vertex_array.size ();
1115+ ERR_FAIL_COND (corner_count % 3 != 0 );
11271116
1128- void SurfaceTool::mikktSetTSpaceDefault (const SMikkTSpaceContext *pContext, const float fvTangent[], const float fvBiTangent[], const float fMagS , const float fMagT ,
1129- const tbool bIsOrientationPreserving, const int iFace, const int iVert) {
1130- TangentGenerationContextUserData &triangle_data = *reinterpret_cast <TangentGenerationContextUserData *>(pContext->m_pUserData );
1131- Vertex *vtx = nullptr ;
1132- if (triangle_data.indices ->size () > 0 ) {
1133- uint32_t index = triangle_data.indices ->operator [](iFace * 3 + iVert);
1134- if (index < triangle_data.vertices ->size ()) {
1135- vtx = &triangle_data.vertices ->operator [](index);
1136- }
1137- } else {
1138- vtx = &triangle_data.vertices ->operator [](iFace * 3 + iVert);
1139- }
1117+ // We can't operate on SurfaceTool::Vertex directly because in double-precision builds, vectors use double components
1118+ // So we convert the inputs to single precision floats before generating tangents.
1119+ LocalVector<TangentVertex> tangent_vertices;
1120+ tangent_vertices.resize (vertex_array.size ());
11401121
1141- if (vtx != nullptr ) {
1142- vtx->tangent = Vector4 (fvTangent[0 ], fvTangent[1 ], fvTangent[2 ], bIsOrientationPreserving ? 1 .0f : -1 .0f );
1122+ for (size_t i = 0 ; i < vertex_array.size (); i++) {
1123+ const Vertex &vertex = vertex_array[i];
1124+ TangentVertex &tangent_vertex = tangent_vertices[i];
1125+
1126+ tangent_vertex.position [0 ] = vertex.vertex .x ;
1127+ tangent_vertex.position [1 ] = vertex.vertex .y ;
1128+ tangent_vertex.position [2 ] = vertex.vertex .z ;
1129+ tangent_vertex.normal [0 ] = vertex.normal .x ;
1130+ tangent_vertex.normal [1 ] = vertex.normal .y ;
1131+ tangent_vertex.normal [2 ] = vertex.normal .z ;
1132+ tangent_vertex.uv [0 ] = vertex.uv .x ;
1133+ tangent_vertex.uv [1 ] = vertex.uv .y ;
11431134 }
1144- }
11451135
1146- void SurfaceTool::generate_tangents () {
1147- ERR_FAIL_COND_MSG (!(format & Mesh::ARRAY_FORMAT_TEX_UV ), " UVs are required to generate tangents." );
1148- ERR_FAIL_COND (!(format & Mesh::ARRAY_FORMAT_NORMAL ));
1136+ const TangentVertex *vertices = tangent_vertices.ptr ();
11491137
1150- SMikkTSpaceInterface mkif;
1151- mkif.m_getNormal = mikktGetNormal;
1152- mkif.m_getNumFaces = mikktGetNumFaces;
1153- mkif.m_getNumVerticesOfFace = mikktGetNumVerticesOfFace;
1154- mkif.m_getPosition = mikktGetPosition;
1155- mkif.m_getTexCoord = mikktGetTexCoord;
1156- mkif.m_setTSpace = mikktSetTSpaceDefault;
1157- mkif.m_setTSpaceBasic = nullptr ;
1138+ LocalVector<float > tangents;
1139+ tangents.resize (corner_count * 4 );
11581140
1159- SMikkTSpaceContext msc;
1160- msc.m_pInterface = &mkif;
1141+ generate_tangents_func (tangents.ptr (),
1142+ index_array.size () > 0 ? reinterpret_cast <const unsigned int *>(index_array.ptr ()) : nullptr , corner_count,
1143+ vertices->position , tangent_vertices.size (), sizeof (TangentVertex),
1144+ vertices->normal , sizeof (TangentVertex),
1145+ vertices->uv , sizeof (TangentVertex), 0 );
11611146
1162- TangentGenerationContextUserData triangle_data;
1163- triangle_data.vertices = &vertex_array;
1164- for (Vertex &vertex : vertex_array) {
1165- vertex.tangent = Vector4 ();
1147+ if (index_array.size () > 0 ) {
1148+ _propagate_tangents_or_split (vertex_array, index_array, tangents.ptr (), p_split);
1149+ } else {
1150+ for (size_t i = 0 ; i < corner_count; i++) {
1151+ Vector4 tangent (tangents[i * 4 + 0 ], tangents[i * 4 + 1 ], tangents[i * 4 + 2 ], tangents[i * 4 + 3 ]);
1152+ vertex_array[i].tangent = tangent;
1153+ }
11661154 }
1167- triangle_data.indices = &index_array;
1168- msc.m_pUserData = &triangle_data;
1169-
1170- bool res = genTangSpaceDefault (&msc);
11711155
1172- ERR_FAIL_COND (!res);
11731156 format |= Mesh::ARRAY_FORMAT_TANGENT ;
11741157}
11751158
@@ -1355,7 +1338,7 @@ void SurfaceTool::_bind_methods() {
13551338 ClassDB::bind_method (D_METHOD (" index" ), &SurfaceTool::index);
13561339 ClassDB::bind_method (D_METHOD (" deindex" ), &SurfaceTool::deindex);
13571340 ClassDB::bind_method (D_METHOD (" generate_normals" , " flip" ), &SurfaceTool::generate_normals, DEFVAL (false ));
1358- ClassDB::bind_method (D_METHOD (" generate_tangents" ), &SurfaceTool::generate_tangents );
1341+ ClassDB::bind_method (D_METHOD (" generate_tangents" ), &SurfaceTool::_generate_tangents_bind );
13591342
13601343 ClassDB::bind_method (D_METHOD (" optimize_indices_for_cache" ), &SurfaceTool::optimize_indices_for_cache);
13611344
0 commit comments