From 37afa965a4a1cb8053d449f72cb533a441279af2 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 13 Feb 2017 12:00:10 +0100 Subject: [PATCH] Fix T50655: Pointiness is too slow to calculate Optimize vertex de-duplication the same way as we do doe Remove Doubles. --- intern/cycles/blender/blender_mesh.cpp | 76 +++++++++++++++++++++----- 1 file changed, 63 insertions(+), 13 deletions(-) diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp index a87f1724e81..e269be61791 100644 --- a/intern/cycles/blender/blender_mesh.cpp +++ b/intern/cycles/blender/blender_mesh.cpp @@ -27,6 +27,7 @@ #include "subd_patch.h" #include "subd_split.h" +#include "util_algorithm.h" #include "util_foreach.h" #include "util_logging.h" #include "util_math.h" @@ -525,6 +526,31 @@ static void attr_create_uv_map(Scene *scene, } /* Create vertex pointiness attributes. */ + +/* Compare vertices by sum of their coordinates. */ +class VertexAverageComparator { +public: + VertexAverageComparator(const array& verts) + : verts_(verts) { + } + + bool operator()(const int& vert_idx_a, const int& vert_idx_b) + { + const float3 &vert_a = verts_[vert_idx_a]; + const float3 &vert_b = verts_[vert_idx_b]; + if(vert_a == vert_b) { + /* Special case for doubles, so we ensure ordering. */ + return vert_idx_a > vert_idx_b; + } + const float x1 = vert_a.x + vert_a.y + vert_a.z; + const float x2 = vert_b.x + vert_b.y + vert_b.z; + return x1 < x2; + } + +protected: + const array& verts_; +}; + static void attr_create_pointiness(Scene *scene, Mesh *mesh, BL::Mesh& b_mesh, @@ -534,37 +560,59 @@ static void attr_create_pointiness(Scene *scene, return; } const int num_verts = b_mesh.vertices.length(); - AttributeSet& attributes = (subdivision)? mesh->subd_attributes: mesh->attributes; - Attribute *attr = attributes.add(ATTR_STD_POINTINESS); - float *data = attr->data_float(); /* STEP 1: Find out duplicated vertices and point duplicates to a single * original vertex. */ + vector sorted_vert_indeices(num_verts); + for (int vert_index = 0; vert_index < num_verts; ++vert_index) { + sorted_vert_indeices[vert_index] = vert_index; + } + VertexAverageComparator compare(mesh->verts); + sort(sorted_vert_indeices.begin(), sorted_vert_indeices.end(), compare); /* This array stores index of the original vertex for the given vertex * index. */ vector vert_orig_index(num_verts); - for (int vert_index = 0; vert_index < num_verts; ++vert_index) { + for (int sorted_vert_index = 0; + sorted_vert_index < num_verts; + ++sorted_vert_index) + { + const int vert_index = sorted_vert_indeices[sorted_vert_index]; const float3 &vert_co = mesh->verts[vert_index]; bool found = false; - int other_vert_index; - for(other_vert_index = 0; - other_vert_index < vert_index; - ++other_vert_index) + for(int other_sorted_vert_index = sorted_vert_index + 1; + other_sorted_vert_index < num_verts; + ++other_sorted_vert_index) { + const int other_vert_index = + sorted_vert_indeices[other_sorted_vert_index]; const float3 &other_vert_co = mesh->verts[other_vert_index]; + /* We are too far away now, we wouldn't have duplicate. */ + if ((other_vert_co.x + other_vert_co.y + other_vert_co.z) - + (vert_co.x + vert_co.y + vert_co.z) > 0.0f) + { + break; + } + /* Found duplicate. */ if(other_vert_co == vert_co) { found = true; + vert_orig_index[vert_index] = other_vert_index; break; } } - if(found) { - vert_orig_index[vert_index] = other_vert_index; - } - else { + if(!found) { vert_orig_index[vert_index] = vert_index; } } + /* Make sure we always points to the very first orig vertex. */ + for(int vert_index = 0; vert_index < num_verts; ++vert_index) { + int orig_index = vert_orig_index[vert_index]; + while(orig_index != vert_orig_index[orig_index]) { + orig_index = vert_orig_index[orig_index]; + } + vert_orig_index[vert_index] = orig_index; + } + sorted_vert_indeices.free_memory(); /* STEP 2: Calculate vertex normals taking into account their possible * duplicates which gets "welded" together. */ @@ -623,6 +671,9 @@ static void attr_create_pointiness(Scene *scene, } } /* STEP 3: Blur vertices to approximate 2 ring neighborhood. */ + AttributeSet& attributes = (subdivision)? mesh->subd_attributes: mesh->attributes; + Attribute *attr = attributes.add(ATTR_STD_POINTINESS); + float *data = attr->data_float(); memcpy(data, &raw_data[0], sizeof(float) * raw_data.size()); memset(&counter[0], 0, sizeof(int) * counter.size()); edge_index = 0; @@ -1234,4 +1285,3 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob, } CCL_NAMESPACE_END -