Skip to content

Commit e717440

Browse files
committed
Merge pull request #106446 from zeux/simp-colors
Use vertex colors (if present) as attributes during simplification
2 parents da9fb81 + 9a8348c commit e717440

File tree

1 file changed

+41
-12
lines changed

1 file changed

+41
-12
lines changed

scene/resources/3d/importer_mesh.cpp

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,7 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, Array p_bone_transf
314314
Vector<Vector2> uv2s = surfaces[i].arrays[RS::ARRAY_TEX_UV2];
315315
Vector<int> bones = surfaces[i].arrays[RS::ARRAY_BONES];
316316
Vector<float> weights = surfaces[i].arrays[RS::ARRAY_WEIGHTS];
317+
Vector<Color> colors = surfaces[i].arrays[RS::ARRAY_COLOR];
317318

318319
unsigned int index_count = indices.size();
319320
unsigned int vertex_count = vertices.size();
@@ -368,6 +369,7 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, Array p_bone_transf
368369
const Vector2 *uvs_ptr = uvs.ptr();
369370
const Vector2 *uv2s_ptr = uv2s.ptr();
370371
const float *tangents_ptr = tangents.ptr();
372+
const Color *colors_ptr = colors.ptr();
371373

372374
for (unsigned int j = 0; j < vertex_count; j++) {
373375
const Vector3 &v = vertices_ptr[j];
@@ -385,7 +387,8 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, Array p_bone_transf
385387
bool is_tang_aligned = !tangents_ptr || (tangents_ptr[j * 4 + 3] < 0) == (tangents_ptr[idx.second * 4 + 3] < 0);
386388
ERR_FAIL_INDEX(idx.second, normals.size());
387389
bool is_normals_close = normals[idx.second].dot(n) > normal_merge_threshold;
388-
if (is_uvs_close && is_uv2s_close && is_normals_close && is_tang_aligned) {
390+
bool is_col_close = (!colors_ptr || colors_ptr[j].is_equal_approx(colors_ptr[idx.second]));
391+
if (is_uvs_close && is_uv2s_close && is_normals_close && is_tang_aligned && is_col_close) {
389392
vertex_remap.push_back(idx.first);
390393
merged_normals[idx.first] += normals[idx.second];
391394
merged_normals_counts[idx.first]++;
@@ -424,23 +427,50 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, Array p_bone_transf
424427
unsigned int merged_vertex_count = merged_vertices.size();
425428
const Vector3 *merged_vertices_ptr = merged_vertices.ptr();
426429
const int32_t *merged_indices_ptr = merged_indices.ptr();
430+
Vector3 *merged_normals_ptr = merged_normals.ptr();
427431

428432
{
429433
const int *counts_ptr = merged_normals_counts.ptr();
430-
Vector3 *merged_normals_ptrw = merged_normals.ptr();
431434
for (unsigned int j = 0; j < merged_vertex_count; j++) {
432-
merged_normals_ptrw[j] /= counts_ptr[j];
435+
merged_normals_ptr[j] /= counts_ptr[j];
433436
}
434437
}
435438

436-
const float normal_weights[3] = {
437-
// Give some weight to normal preservation, may be worth exposing as an import setting
438-
2.0f, 2.0f, 2.0f
439-
};
440-
441439
Vector<float> merged_vertices_f32 = vector3_to_float32_array(merged_vertices_ptr, merged_vertex_count);
442440
float scale = SurfaceTool::simplify_scale_func(merged_vertices_f32.ptr(), merged_vertex_count, sizeof(float) * 3);
443441

442+
const size_t attrib_count = 6; // 3 for normal + 3 for color (if present)
443+
444+
float attrib_weights[attrib_count] = {};
445+
446+
// Give more weight to normal preservation
447+
attrib_weights[0] = attrib_weights[1] = attrib_weights[2] = 2.0f;
448+
449+
// Give some weight to colors but only if present to avoid redundant computations during simplification
450+
if (colors_ptr) {
451+
attrib_weights[3] = attrib_weights[4] = attrib_weights[5] = 1.0f;
452+
}
453+
454+
LocalVector<float> merged_attribs;
455+
merged_attribs.resize(merged_vertex_count * attrib_count);
456+
float *merged_attribs_ptr = merged_attribs.ptr();
457+
458+
memset(merged_attribs_ptr, 0, merged_attribs.size() * sizeof(float));
459+
460+
for (unsigned int j = 0; j < merged_vertex_count; ++j) {
461+
merged_attribs_ptr[j * attrib_count + 0] = merged_normals_ptr[j].x;
462+
merged_attribs_ptr[j * attrib_count + 1] = merged_normals_ptr[j].y;
463+
merged_attribs_ptr[j * attrib_count + 2] = merged_normals_ptr[j].z;
464+
465+
if (colors_ptr) {
466+
unsigned int rj = vertex_inverse_remap[j];
467+
468+
merged_attribs_ptr[j * attrib_count + 3] = colors_ptr[rj].r;
469+
merged_attribs_ptr[j * attrib_count + 4] = colors_ptr[rj].g;
470+
merged_attribs_ptr[j * attrib_count + 5] = colors_ptr[rj].b;
471+
}
472+
}
473+
444474
unsigned int index_target = 12; // Start with the smallest target, 4 triangles
445475
unsigned int last_index_count = 0;
446476

@@ -451,17 +481,16 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, Array p_bone_transf
451481
PackedInt32Array new_indices;
452482
new_indices.resize(index_count);
453483

454-
Vector<float> merged_normals_f32 = vector3_to_float32_array(merged_normals.ptr(), merged_normals.size());
455484
const int simplify_options = SurfaceTool::SIMPLIFY_LOCK_BORDER;
456485

457486
size_t new_index_count = SurfaceTool::simplify_with_attrib_func(
458487
(unsigned int *)new_indices.ptrw(),
459488
(const uint32_t *)merged_indices_ptr, index_count,
460489
merged_vertices_f32.ptr(), merged_vertex_count,
461490
sizeof(float) * 3, // Vertex stride
462-
merged_normals_f32.ptr(),
463-
sizeof(float) * 3, // Attribute stride
464-
normal_weights, 3,
491+
merged_attribs_ptr,
492+
sizeof(float) * attrib_count, // Attribute stride
493+
attrib_weights, attrib_count,
465494
nullptr, // Vertex lock
466495
index_target,
467496
max_mesh_error,

0 commit comments

Comments
 (0)