diff options
Diffstat (limited to 'intern/cycles/blender/blender_mesh.cpp')
-rw-r--r-- | intern/cycles/blender/blender_mesh.cpp | 765 |
1 files changed, 448 insertions, 317 deletions
diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp index b95365ddf22..ec0c58666a5 100644 --- a/intern/cycles/blender/blender_mesh.cpp +++ b/intern/cycles/blender/blender_mesh.cpp @@ -14,22 +14,22 @@ * limitations under the License. */ - -#include "mesh.h" -#include "object.h" -#include "scene.h" -#include "camera.h" +#include "render/mesh.h" +#include "render/object.h" +#include "render/scene.h" +#include "render/camera.h" -#include "blender_sync.h" -#include "blender_session.h" -#include "blender_util.h" +#include "blender/blender_sync.h" +#include "blender/blender_session.h" +#include "blender/blender_util.h" -#include "subd_patch.h" -#include "subd_split.h" +#include "subd/subd_patch.h" +#include "subd/subd_split.h" -#include "util_foreach.h" -#include "util_logging.h" -#include "util_math.h" +#include "util/util_algorithm.h" +#include "util/util_foreach.h" +#include "util/util_logging.h" +#include "util/util_math.h" #include "mikktspace.h" @@ -50,8 +50,7 @@ enum { * Two triangles has vertex indices in the original Blender-side face. * If face is already a quad tri_b will not be initialized. */ -inline void face_split_tri_indices(const int num_verts, - const int face_flag, +inline void face_split_tri_indices(const int face_flag, int tri_a[3], int tri_b[3]) { @@ -59,225 +58,217 @@ inline void face_split_tri_indices(const int num_verts, tri_a[0] = 0; tri_a[1] = 1; tri_a[2] = 3; - if(num_verts == 4) { - tri_b[0] = 2; - tri_b[1] = 3; - tri_b[2] = 1; - } + + tri_b[0] = 2; + tri_b[1] = 3; + tri_b[2] = 1; } - else /*if(face_flag & FACE_FLAG_DIVIDE_13)*/ { + else { + /* Quad with FACE_FLAG_DIVIDE_13 or single triangle. */ tri_a[0] = 0; tri_a[1] = 1; tri_a[2] = 2; - if(num_verts == 4) { - tri_b[0] = 0; - tri_b[1] = 2; - tri_b[2] = 3; - } + + tri_b[0] = 0; + tri_b[1] = 2; + tri_b[2] = 3; } } /* Tangent Space */ struct MikkUserData { - MikkUserData(const BL::Mesh& mesh_, - BL::MeshTextureFaceLayer *layer_, - int num_faces_) - : mesh(mesh_), layer(layer_), num_faces(num_faces_) + MikkUserData(const BL::Mesh& b_mesh, + BL::MeshTextureFaceLayer *layer, + const Mesh *mesh, + float3 *tangent, + float *tangent_sign) + : mesh(mesh), + texface(NULL), + orco(NULL), + tangent(tangent), + tangent_sign(tangent_sign) { - tangent.resize(num_faces*4); + Attribute *attr_vN = mesh->attributes.find(ATTR_STD_VERTEX_NORMAL); + vertex_normal = attr_vN->data_float3(); + + if(layer == NULL) { + Attribute *attr_orco = mesh->attributes.find(ATTR_STD_GENERATED); + orco = attr_orco->data_float3(); + mesh_texture_space(*(BL::Mesh*)&b_mesh, orco_loc, orco_size); + } + else { + Attribute *attr_uv = mesh->attributes.find(ustring(layer->name())); + if(attr_uv != NULL) { + texface = attr_uv->data_float3(); + } + } } - BL::Mesh mesh; - BL::MeshTextureFaceLayer *layer; + const Mesh *mesh; int num_faces; - vector<float4> tangent; + + float3 *vertex_normal; + float3 *texface; + float3 *orco; + float3 orco_loc, orco_size; + + float3 *tangent; + float *tangent_sign; }; static int mikk_get_num_faces(const SMikkTSpaceContext *context) { - MikkUserData *userdata = (MikkUserData*)context->m_pUserData; - return userdata->num_faces; + const MikkUserData *userdata = (const MikkUserData *)context->m_pUserData; + return userdata->mesh->num_triangles(); } -static int mikk_get_num_verts_of_face(const SMikkTSpaceContext *context, const int face_num) +static int mikk_get_num_verts_of_face(const SMikkTSpaceContext * /*context*/, + const int /*face_num*/) { - MikkUserData *userdata = (MikkUserData*)context->m_pUserData; - BL::MeshTessFace f = userdata->mesh.tessfaces[face_num]; - int4 vi = get_int4(f.vertices_raw()); - - return (vi[3] == 0)? 3: 4; + return 3; } -static void mikk_get_position(const SMikkTSpaceContext *context, float P[3], const int face_num, const int vert_num) +static void mikk_get_position(const SMikkTSpaceContext *context, + float P[3], + const int face_num, const int vert_num) { - MikkUserData *userdata = (MikkUserData*)context->m_pUserData; - BL::MeshTessFace f = userdata->mesh.tessfaces[face_num]; - int4 vi = get_int4(f.vertices_raw()); - BL::MeshVertex v = userdata->mesh.vertices[vi[vert_num]]; - float3 vP = get_float3(v.co()); + const MikkUserData *userdata = (const MikkUserData *)context->m_pUserData; + const Mesh *mesh = userdata->mesh; + const int vert_index = mesh->triangles[face_num * 3 + vert_num]; + const float3 vP = mesh->verts[vert_index]; P[0] = vP.x; P[1] = vP.y; P[2] = vP.z; } -static void mikk_get_texture_coordinate(const SMikkTSpaceContext *context, float uv[2], const int face_num, const int vert_num) +static void mikk_get_texture_coordinate(const SMikkTSpaceContext *context, + float uv[2], + const int face_num, const int vert_num) { - MikkUserData *userdata = (MikkUserData*)context->m_pUserData; - if(userdata->layer != NULL) { - BL::MeshTextureFace tf = userdata->layer->data[face_num]; - float3 tfuv; - - switch(vert_num) { - case 0: - tfuv = get_float3(tf.uv1()); - break; - case 1: - tfuv = get_float3(tf.uv2()); - break; - case 2: - tfuv = get_float3(tf.uv3()); - break; - default: - tfuv = get_float3(tf.uv4()); - break; - } - + const MikkUserData *userdata = (const MikkUserData *)context->m_pUserData; + if(userdata->texface != NULL) { + const size_t corner_index = face_num * 3 + vert_num; + float3 tfuv = userdata->texface[corner_index]; uv[0] = tfuv.x; uv[1] = tfuv.y; } - else { - int vert_idx = userdata->mesh.tessfaces[face_num].vertices()[vert_num]; - float3 orco = - get_float3(userdata->mesh.vertices[vert_idx].undeformed_co()); - float2 tmp = map_to_sphere(make_float3(orco[0], orco[1], orco[2])); + else if(userdata->orco != NULL) { + const Mesh *mesh = userdata->mesh; + const size_t vertex_index = mesh->triangles[face_num * 3 + vert_num]; + const float3 orco_loc = userdata->orco_loc; + const float3 orco_size = userdata->orco_size; + const float3 orco = (userdata->orco[vertex_index] + orco_loc) / orco_size; + + const float2 tmp = map_to_sphere(orco); uv[0] = tmp.x; uv[1] = tmp.y; } + else { + uv[0] = 0.0f; + uv[1] = 0.0f; + } } -static void mikk_get_normal(const SMikkTSpaceContext *context, float N[3], const int face_num, const int vert_num) +static void mikk_get_normal(const SMikkTSpaceContext *context, float N[3], + const int face_num, const int vert_num) { - MikkUserData *userdata = (MikkUserData*)context->m_pUserData; - BL::MeshTessFace f = userdata->mesh.tessfaces[face_num]; + const MikkUserData *userdata = (const MikkUserData *)context->m_pUserData; + const Mesh *mesh = userdata->mesh; float3 vN; - - if(f.use_smooth()) { - int4 vi = get_int4(f.vertices_raw()); - BL::MeshVertex v = userdata->mesh.vertices[vi[vert_num]]; - vN = get_float3(v.normal()); + if(mesh->smooth[face_num]) { + const size_t vert_index = mesh->triangles[face_num * 3 + vert_num]; + vN = userdata->vertex_normal[vert_index]; } else { - vN = get_float3(f.normal()); + const Mesh::Triangle tri = mesh->get_triangle(face_num); + vN = tri.compute_normal(&mesh->verts[0]); } - N[0] = vN.x; N[1] = vN.y; N[2] = vN.z; } -static void mikk_set_tangent_space(const SMikkTSpaceContext *context, const float T[], const float sign, const int face, const int vert) +static void mikk_set_tangent_space(const SMikkTSpaceContext *context, + const float T[], + const float sign, + const int face_num, const int vert_num) { - MikkUserData *userdata = (MikkUserData*)context->m_pUserData; - - userdata->tangent[face*4 + vert] = make_float4(T[0], T[1], T[2], sign); + MikkUserData *userdata = (MikkUserData *)context->m_pUserData; + const size_t corner_index = face_num * 3 + vert_num; + userdata->tangent[corner_index] = make_float3(T[0], T[1], T[2]); + if(userdata->tangent_sign != NULL) { + userdata->tangent_sign[corner_index] = sign; + } } -static void mikk_compute_tangents(BL::Mesh& b_mesh, +static void mikk_compute_tangents(const BL::Mesh& b_mesh, BL::MeshTextureFaceLayer *b_layer, Mesh *mesh, - const vector<int>& nverts, - const vector<int>& face_flags, bool need_sign, bool active_render) { - /* setup userdata */ - MikkUserData userdata(b_mesh, b_layer, nverts.size()); - - /* setup interface */ - SMikkTSpaceInterface sm_interface; - memset(&sm_interface, 0, sizeof(sm_interface)); - sm_interface.m_getNumFaces = mikk_get_num_faces; - sm_interface.m_getNumVerticesOfFace = mikk_get_num_verts_of_face; - sm_interface.m_getPosition = mikk_get_position; - sm_interface.m_getTexCoord = mikk_get_texture_coordinate; - sm_interface.m_getNormal = mikk_get_normal; - sm_interface.m_setTSpaceBasic = mikk_set_tangent_space; - - /* setup context */ - SMikkTSpaceContext context; - memset(&context, 0, sizeof(context)); - context.m_pUserData = &userdata; - context.m_pInterface = &sm_interface; - - /* compute tangents */ - genTangSpaceDefault(&context); - - /* create tangent attributes */ + /* Create tangent attributes. */ Attribute *attr; ustring name; - if(b_layer != NULL) + if(b_layer != NULL) { name = ustring((string(b_layer->name().c_str()) + ".tangent").c_str()); - else + } + else { name = ustring("orco.tangent"); - - if(active_render) + } + if(active_render) { attr = mesh->attributes.add(ATTR_STD_UV_TANGENT, name); - else - attr = mesh->attributes.add(name, TypeDesc::TypeVector, ATTR_ELEMENT_CORNER); - + } + else { + attr = mesh->attributes.add(name, + TypeDesc::TypeVector, + ATTR_ELEMENT_CORNER); + } float3 *tangent = attr->data_float3(); - - /* create bitangent sign attribute */ + /* Create bitangent sign attribute. */ float *tangent_sign = NULL; - if(need_sign) { Attribute *attr_sign; ustring name_sign; - if(b_layer != NULL) - name_sign = ustring((string(b_layer->name().c_str()) + ".tangent_sign").c_str()); - else + if(b_layer != NULL) { + name_sign = ustring((string(b_layer->name().c_str()) + + ".tangent_sign").c_str()); + } + else { name_sign = ustring("orco.tangent_sign"); - - if(active_render) - attr_sign = mesh->attributes.add(ATTR_STD_UV_TANGENT_SIGN, name_sign); - else - attr_sign = mesh->attributes.add(name_sign, TypeDesc::TypeFloat, ATTR_ELEMENT_CORNER); - - tangent_sign = attr_sign->data_float(); - } - - for(int i = 0; i < nverts.size(); i++) { - int tri_a[3], tri_b[3]; - face_split_tri_indices(nverts[i], face_flags[i], tri_a, tri_b); - - tangent[0] = float4_to_float3(userdata.tangent[i*4 + tri_a[0]]); - tangent[1] = float4_to_float3(userdata.tangent[i*4 + tri_a[1]]); - tangent[2] = float4_to_float3(userdata.tangent[i*4 + tri_a[2]]); - tangent += 3; - - if(tangent_sign) { - tangent_sign[0] = userdata.tangent[i*4 + tri_a[0]].w; - tangent_sign[1] = userdata.tangent[i*4 + tri_a[1]].w; - tangent_sign[2] = userdata.tangent[i*4 + tri_a[2]].w; - tangent_sign += 3; } - if(nverts[i] == 4) { - tangent[0] = float4_to_float3(userdata.tangent[i*4 + tri_b[0]]); - tangent[1] = float4_to_float3(userdata.tangent[i*4 + tri_b[1]]); - tangent[2] = float4_to_float3(userdata.tangent[i*4 + tri_b[2]]); - tangent += 3; - - if(tangent_sign) { - tangent_sign[0] = userdata.tangent[i*4 + tri_b[0]].w; - tangent_sign[1] = userdata.tangent[i*4 + tri_b[1]].w; - tangent_sign[2] = userdata.tangent[i*4 + tri_b[2]].w; - tangent_sign += 3; - } + if(active_render) { + attr_sign = mesh->attributes.add(ATTR_STD_UV_TANGENT_SIGN, + name_sign); + } + else { + attr_sign = mesh->attributes.add(name_sign, + TypeDesc::TypeFloat, + ATTR_ELEMENT_CORNER); } + tangent_sign = attr_sign->data_float(); } + /* Setup userdata. */ + MikkUserData userdata(b_mesh, b_layer, mesh, tangent, tangent_sign); + /* Setup interface. */ + SMikkTSpaceInterface sm_interface; + memset(&sm_interface, 0, sizeof(sm_interface)); + sm_interface.m_getNumFaces = mikk_get_num_faces; + sm_interface.m_getNumVerticesOfFace = mikk_get_num_verts_of_face; + sm_interface.m_getPosition = mikk_get_position; + sm_interface.m_getTexCoord = mikk_get_texture_coordinate; + sm_interface.m_getNormal = mikk_get_normal; + sm_interface.m_setTSpaceBasic = mikk_set_tangent_space; + /* Setup context. */ + SMikkTSpaceContext context; + memset(&context, 0, sizeof(context)); + context.m_pUserData = &userdata; + context.m_pInterface = &sm_interface; + /* Compute tangents. */ + genTangSpaceDefault(&context); } /* Create Volume Attribute */ @@ -292,7 +283,7 @@ static void create_mesh_volume_attribute(BL::Object& b_ob, if(!b_domain) return; - + Attribute *attr = mesh->attributes.add(std); VoxelAttribute *volume_data = attr->data_voxel(); bool is_float, is_linear; @@ -355,7 +346,7 @@ static void attr_create_vertex_color(Scene *scene, int n = p->loop_total(); for(int i = 0; i < n; i++) { float3 color = get_float3(l->data[p->loop_start() + i].color()); - *(cdata++) = color_float_to_byte(color_srgb_to_scene_linear(color)); + *(cdata++) = color_float_to_byte(color_srgb_to_scene_linear_v3(color)); } } } @@ -376,14 +367,14 @@ static void attr_create_vertex_color(Scene *scene, for(l->data.begin(c); c != l->data.end(); ++c, ++i) { int tri_a[3], tri_b[3]; - face_split_tri_indices(nverts[i], face_flags[i], tri_a, tri_b); + face_split_tri_indices(face_flags[i], tri_a, tri_b); uchar4 colors[4]; - colors[0] = color_float_to_byte(color_srgb_to_scene_linear(get_float3(c->color1()))); - colors[1] = color_float_to_byte(color_srgb_to_scene_linear(get_float3(c->color2()))); - colors[2] = color_float_to_byte(color_srgb_to_scene_linear(get_float3(c->color3()))); + colors[0] = color_float_to_byte(color_srgb_to_scene_linear_v3(get_float3(c->color1()))); + colors[1] = color_float_to_byte(color_srgb_to_scene_linear_v3(get_float3(c->color2()))); + colors[2] = color_float_to_byte(color_srgb_to_scene_linear_v3(get_float3(c->color3()))); if(nverts[i] == 4) { - colors[3] = color_float_to_byte(color_srgb_to_scene_linear(get_float3(c->color4()))); + colors[3] = color_float_to_byte(color_srgb_to_scene_linear_v3(get_float3(c->color4()))); } cdata[0] = colors[tri_a[0]]; @@ -450,26 +441,44 @@ static void attr_create_uv_map(Scene *scene, BL::Mesh::tessface_uv_textures_iterator l; for(b_mesh.tessface_uv_textures.begin(l); l != b_mesh.tessface_uv_textures.end(); ++l) { - bool active_render = l->active_render(); - AttributeStandard std = (active_render)? ATTR_STD_UV: ATTR_STD_NONE; - ustring name = ustring(l->name().c_str()); + const bool active_render = l->active_render(); + AttributeStandard uv_std = (active_render)? ATTR_STD_UV: ATTR_STD_NONE; + ustring uv_name = ustring(l->name().c_str()); + AttributeStandard tangent_std = (active_render)? ATTR_STD_UV_TANGENT + : ATTR_STD_NONE; + ustring tangent_name = ustring( + (string(l->name().c_str()) + ".tangent").c_str()); + + /* Denotes whether UV map was requested directly. */ + const bool need_uv = mesh->need_attribute(scene, uv_name) || + mesh->need_attribute(scene, uv_std); + /* Denotes whether tangent was requested directly. */ + const bool need_tangent = + mesh->need_attribute(scene, tangent_name) || + (active_render && mesh->need_attribute(scene, tangent_std)); /* UV map */ - if(mesh->need_attribute(scene, name) || mesh->need_attribute(scene, std)) { - Attribute *attr; - - if(active_render) - attr = mesh->attributes.add(std, name); - else - attr = mesh->attributes.add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CORNER); + /* NOTE: We create temporary UV layer if its needed for tangent but + * wasn't requested by other nodes in shaders. + */ + Attribute *uv_attr = NULL; + if(need_uv || need_tangent) { + if(active_render) { + uv_attr = mesh->attributes.add(uv_std, uv_name); + } + else { + uv_attr = mesh->attributes.add(uv_name, + TypeDesc::TypePoint, + ATTR_ELEMENT_CORNER); + } BL::MeshTextureFaceLayer::data_iterator t; - float3 *fdata = attr->data_float3(); + float3 *fdata = uv_attr->data_float3(); size_t i = 0; for(l->data.begin(t); t != l->data.end(); ++t, ++i) { int tri_a[3], tri_b[3]; - face_split_tri_indices(nverts[i], face_flags[i], tri_a, tri_b); + face_split_tri_indices(face_flags[i], tri_a, tri_b); float3 uvs[4]; uvs[0] = get_float3(t->uv1()); @@ -494,100 +503,210 @@ static void attr_create_uv_map(Scene *scene, } /* UV tangent */ - std = (active_render)? ATTR_STD_UV_TANGENT: ATTR_STD_NONE; - name = ustring((string(l->name().c_str()) + ".tangent").c_str()); - - if(mesh->need_attribute(scene, name) || (active_render && mesh->need_attribute(scene, std))) { - std = (active_render)? ATTR_STD_UV_TANGENT_SIGN: ATTR_STD_NONE; - name = ustring((string(l->name().c_str()) + ".tangent_sign").c_str()); - bool need_sign = (mesh->need_attribute(scene, name) || mesh->need_attribute(scene, std)); - + if(need_tangent) { + AttributeStandard sign_std = + (active_render)? ATTR_STD_UV_TANGENT_SIGN + : ATTR_STD_NONE; + ustring sign_name = ustring( + (string(l->name().c_str()) + ".tangent_sign").c_str()); + bool need_sign = (mesh->need_attribute(scene, sign_name) || + mesh->need_attribute(scene, sign_std)); mikk_compute_tangents(b_mesh, &(*l), mesh, - nverts, - face_flags, need_sign, active_render); } + /* Remove temporarily created UV attribute. */ + if(!need_uv && uv_attr != NULL) { + mesh->attributes.remove(uv_attr); + } } } else if(mesh->need_attribute(scene, ATTR_STD_UV_TANGENT)) { bool need_sign = mesh->need_attribute(scene, ATTR_STD_UV_TANGENT_SIGN); - mikk_compute_tangents(b_mesh, - NULL, - mesh, - nverts, - face_flags, - need_sign, - true); + mikk_compute_tangents(b_mesh, NULL, mesh, need_sign, true); + if(!mesh->need_attribute(scene, ATTR_STD_GENERATED)) { + mesh->attributes.remove(ATTR_STD_GENERATED); + } } } /* Create vertex pointiness attributes. */ + +/* Compare vertices by sum of their coordinates. */ +class VertexAverageComparator { +public: + VertexAverageComparator(const array<float3>& 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<float3>& verts_; +}; + static void attr_create_pointiness(Scene *scene, Mesh *mesh, BL::Mesh& b_mesh, bool subdivision) { - if(mesh->need_attribute(scene, ATTR_STD_POINTINESS)) { - const int numverts = b_mesh.vertices.length(); - AttributeSet& attributes = (subdivision)? mesh->subd_attributes: mesh->attributes; - Attribute *attr = attributes.add(ATTR_STD_POINTINESS); - float *data = attr->data_float(); - int *counter = new int[numverts]; - float *raw_data = new float[numverts]; - float3 *edge_accum = new float3[numverts]; - - /* Calculate pointiness using single ring neighborhood. */ - memset(counter, 0, sizeof(int) * numverts); - memset(raw_data, 0, sizeof(float) * numverts); - memset(edge_accum, 0, sizeof(float3) * numverts); - BL::Mesh::edges_iterator e; - int i = 0; - for(b_mesh.edges.begin(e); e != b_mesh.edges.end(); ++e, ++i) { - int v0 = b_mesh.edges[i].vertices()[0], - v1 = b_mesh.edges[i].vertices()[1]; - float3 co0 = get_float3(b_mesh.vertices[v0].co()), - co1 = get_float3(b_mesh.vertices[v1].co()); - float3 edge = normalize(co1 - co0); - edge_accum[v0] += edge; - edge_accum[v1] += -edge; - ++counter[v0]; - ++counter[v1]; - } - i = 0; - BL::Mesh::vertices_iterator v; - for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v, ++i) { - if(counter[i] > 0) { - float3 normal = get_float3(b_mesh.vertices[i].normal()); - float angle = safe_acosf(dot(normal, edge_accum[i] / counter[i])); - raw_data[i] = angle * M_1_PI_F; + if(!mesh->need_attribute(scene, ATTR_STD_POINTINESS)) { + return; + } + const int num_verts = b_mesh.vertices.length(); + if(num_verts == 0) { + return; + } + /* STEP 1: Find out duplicated vertices and point duplicates to a single + * original vertex. + */ + vector<int> 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<int> vert_orig_index(num_verts); + 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; + 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) > 3 * FLT_EPSILON) + { + break; } - else { - raw_data[i] = 0.0f; + /* Found duplicate. */ + if(len_squared(other_vert_co - vert_co) < FLT_EPSILON) { + found = true; + vert_orig_index[vert_index] = other_vert_index; + break; } } - - /* Blur vertices to approximate 2 ring neighborhood. */ - memset(counter, 0, sizeof(int) * numverts); - memcpy(data, raw_data, sizeof(float) * numverts); - i = 0; - for(b_mesh.edges.begin(e); e != b_mesh.edges.end(); ++e, ++i) { - int v0 = b_mesh.edges[i].vertices()[0], - v1 = b_mesh.edges[i].vertices()[1]; - data[v0] += raw_data[v1]; - data[v1] += raw_data[v0]; - ++counter[v0]; - ++counter[v1]; + if(!found) { + vert_orig_index[vert_index] = vert_index; } - for(i = 0; i < numverts; ++i) { - data[i] /= counter[i] + 1; + } + /* 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. + */ + vector<float3> vert_normal(num_verts, make_float3(0.0f, 0.0f, 0.0f)); + /* First we accumulate all vertex normals in the original index. */ + for(int vert_index = 0; vert_index < num_verts; ++vert_index) { + const float3 normal = get_float3(b_mesh.vertices[vert_index].normal()); + const int orig_index = vert_orig_index[vert_index]; + vert_normal[orig_index] += normal; + } + /* Then we normalize the accumulated result and flush it to all duplicates + * as well. + */ + for(int vert_index = 0; vert_index < num_verts; ++vert_index) { + const int orig_index = vert_orig_index[vert_index]; + vert_normal[vert_index] = normalize(vert_normal[orig_index]); + } + /* STEP 3: Calculate pointiness using single ring neighborhood. */ + vector<int> counter(num_verts, 0); + vector<float> raw_data(num_verts, 0.0f); + vector<float3> edge_accum(num_verts, make_float3(0.0f, 0.0f, 0.0f)); + BL::Mesh::edges_iterator e; + EdgeMap visited_edges; + int edge_index = 0; + memset(&counter[0], 0, sizeof(int) * counter.size()); + for(b_mesh.edges.begin(e); e != b_mesh.edges.end(); ++e, ++edge_index) { + const int v0 = vert_orig_index[b_mesh.edges[edge_index].vertices()[0]], + v1 = vert_orig_index[b_mesh.edges[edge_index].vertices()[1]]; + if(visited_edges.exists(v0, v1)) { + continue; + } + visited_edges.insert(v0, v1); + float3 co0 = get_float3(b_mesh.vertices[v0].co()), + co1 = get_float3(b_mesh.vertices[v1].co()); + float3 edge = normalize(co1 - co0); + edge_accum[v0] += edge; + edge_accum[v1] += -edge; + ++counter[v0]; + ++counter[v1]; + } + for(int vert_index = 0; vert_index < num_verts; ++vert_index) { + const int orig_index = vert_orig_index[vert_index]; + if(orig_index != vert_index) { + /* Skip duplicates, they'll be overwritten later on. */ + continue; + } + if(counter[vert_index] > 0) { + const float3 normal = vert_normal[vert_index]; + const float angle = + safe_acosf(dot(normal, + edge_accum[vert_index] / counter[vert_index])); + raw_data[vert_index] = angle * M_1_PI_F; + } + else { + raw_data[vert_index] = 0.0f; } - - delete [] counter; - delete [] raw_data; - delete [] edge_accum; + } + /* 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; + visited_edges.clear(); + for(b_mesh.edges.begin(e); e != b_mesh.edges.end(); ++e, ++edge_index) { + const int v0 = vert_orig_index[b_mesh.edges[edge_index].vertices()[0]], + v1 = vert_orig_index[b_mesh.edges[edge_index].vertices()[1]]; + if(visited_edges.exists(v0, v1)) { + continue; + } + visited_edges.insert(v0, v1); + data[v0] += raw_data[v1]; + data[v1] += raw_data[v0]; + ++counter[v0]; + ++counter[v1]; + } + for(int vert_index = 0; vert_index < num_verts; ++vert_index) { + data[vert_index] /= counter[vert_index] + 1; + } + /* STEP 4: Copy attribute to the duplicated vertices. */ + for(int vert_index = 0; vert_index < num_verts; ++vert_index) { + const int orig_index = vert_orig_index[vert_index]; + data[vert_index] = data[orig_index]; } } @@ -597,8 +716,8 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh& b_mesh, const vector<Shader*>& used_shaders, - bool subdivision=false, - bool subdivide_uvs=true) + bool subdivision = false, + bool subdivide_uvs = true) { /* count vertices and faces */ int numverts = b_mesh.vertices.length(); @@ -608,6 +727,11 @@ static void create_mesh(Scene *scene, int numngons = 0; bool use_loop_normals = b_mesh.use_auto_smooth() && (mesh->subdivision_type != Mesh::SUBDIVISION_CATMULL_CLARK); + /* If no faces, create empty mesh. */ + if(numfaces == 0) { + return; + } + BL::Mesh::vertices_iterator v; BL::Mesh::tessfaces_iterator f; BL::Mesh::polygons_iterator p; @@ -642,7 +766,13 @@ static void create_mesh(Scene *scene, N = attr_N->data_float3(); /* create generated coordinates from undeformed coordinates */ - if(mesh->need_attribute(scene, ATTR_STD_GENERATED)) { + const bool need_default_tangent = + (subdivision == false) && + (b_mesh.tessface_uv_textures.length() == 0) && + (mesh->need_attribute(scene, ATTR_STD_UV_TANGENT)); + if(mesh->need_attribute(scene, ATTR_STD_GENERATED) || + need_default_tangent) + { Attribute *attr = attributes.add(ATTR_STD_GENERATED); attr->flags |= ATTR_SUBDIVIDED; @@ -652,13 +782,11 @@ static void create_mesh(Scene *scene, float3 *generated = attr->data_float3(); size_t i = 0; - for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v) + for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v) { generated[i++] = get_float3(v->undeformed_co())*size - loc; + } } - /* Create needed vertex attributes. */ - attr_create_pointiness(scene, mesh, b_mesh, subdivision); - /* create faces */ vector<int> nverts(numfaces); vector<int> face_flags(numfaces, FACE_FLAG_NONE); @@ -671,28 +799,19 @@ static void create_mesh(Scene *scene, int shader = clamp(f->material_index(), 0, used_shaders.size()-1); bool smooth = f->use_smooth() || use_loop_normals; - /* split vertices if normal is different - * - * note all vertex attributes must have been set here so we can split - * and copy attributes in split_vertex without remapping later */ if(use_loop_normals) { BL::Array<float, 12> loop_normals = f->split_normals(); - for(int i = 0; i < n; i++) { - float3 loop_N = make_float3(loop_normals[i * 3], loop_normals[i * 3 + 1], loop_normals[i * 3 + 2]); - - if(N[vi[i]] != loop_N) { - int new_vi = mesh->split_vertex(vi[i]); - - /* set new normal and vertex index */ - N = attr_N->data_float3(); - N[new_vi] = loop_N; - vi[i] = new_vi; - } + N[vi[i]] = make_float3(loop_normals[i * 3], + loop_normals[i * 3 + 1], + loop_normals[i * 3 + 2]); } } - /* create triangles */ + /* Create triangles. + * + * NOTE: Autosmooth is already taken care about. + */ if(n == 4) { if(is_zero(cross(mesh->verts[vi[1]] - mesh->verts[vi[0]], mesh->verts[vi[2]] - mesh->verts[vi[0]])) || is_zero(cross(mesh->verts[vi[2]] - mesh->verts[vi[0]], mesh->verts[vi[3]] - mesh->verts[vi[0]]))) @@ -722,26 +841,10 @@ static void create_mesh(Scene *scene, int shader = clamp(p->material_index(), 0, used_shaders.size()-1); bool smooth = p->use_smooth() || use_loop_normals; - vi.reserve(n); + vi.resize(n); for(int i = 0; i < n; i++) { + /* NOTE: Autosmooth is already taken care about. */ vi[i] = b_mesh.loops[p->loop_start() + i].vertex_index(); - - /* split vertices if normal is different - * - * note all vertex attributes must have been set here so we can split - * and copy attributes in split_vertex without remapping later */ - if(use_loop_normals) { - float3 loop_N = get_float3(b_mesh.loops[p->loop_start() + i].normal()); - - if(N[vi[i]] != loop_N) { - int new_vi = mesh->split_vertex(vi[i]); - - /* set new normal and vertex index */ - N = attr_N->data_float3(); - N[new_vi] = loop_N; - vi[i] = new_vi; - } - } } /* create subd faces */ @@ -752,6 +855,7 @@ static void create_mesh(Scene *scene, /* Create all needed attributes. * The calculate functions will check whether they're needed or not. */ + attr_create_pointiness(scene, mesh, b_mesh, subdivision); attr_create_vertex_color(scene, mesh, b_mesh, nverts, face_flags, subdivision); attr_create_uv_map(scene, mesh, b_mesh, nverts, face_flags, subdivision, subdivide_uvs); @@ -897,7 +1001,7 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob, else used_shaders.push_back(scene->default_surface); } - + /* test if we need to sync */ int requested_geometry_flags = Mesh::GEOMETRY_NONE; if(render_layer.use_surfaces) { @@ -932,12 +1036,12 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob, /* ensure we only sync instanced meshes once */ if(mesh_synced.find(mesh) != mesh_synced.end()) return mesh; - + mesh_synced.insert(mesh); /* create derived mesh */ array<int> oldtriangle = mesh->triangles; - + /* compares curve_keys rather than strands in order to handle quick hair * adjustments in dynamic BVH - other methods could probably do this better*/ array<float3> oldcurve_keys = mesh->curve_keys; @@ -961,7 +1065,20 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob, mesh->subdivision_type = object_subdivision_type(b_ob, preview, experimental); - BL::Mesh b_mesh = object_to_mesh(b_data, b_ob, b_scene, true, !preview, need_undeformed, mesh->subdivision_type); + /* Disable adaptive subdivision while baking as the baking system + * currently doesnt support the topology and will crash. + */ + if(scene->bake_manager->get_baking()) { + mesh->subdivision_type = Mesh::SUBDIVISION_NONE; + } + + BL::Mesh b_mesh = object_to_mesh(b_data, + b_ob, + b_scene, + true, + !preview, + need_undeformed, + mesh->subdivision_type); if(b_mesh) { if(render_layer.use_surfaces && !hide_tris) { @@ -982,7 +1099,7 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob, } /* free derived mesh */ - b_data.meshes.remove(b_mesh, false); + b_data.meshes.remove(b_mesh, false, true, false); } } mesh->geometry_flags = requested_geometry_flags; @@ -1013,7 +1130,7 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob, if(memcmp(&oldcurve_radius[0], &mesh->curve_radius[0], sizeof(float)*oldcurve_radius.size()) != 0) rebuild = true; } - + mesh->tag_update(scene, rebuild); return mesh; @@ -1042,7 +1159,7 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob, if(scene->need_motion() == Scene::MOTION_BLUR) { if(!mesh->use_motion_blur) return; - + /* see if this mesh needs motion data at this time */ vector<float> object_times = object->motion_times(); bool found = false; @@ -1069,12 +1186,12 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob, } /* skip empty meshes */ - size_t numverts = mesh->verts.size(); - size_t numkeys = mesh->curve_keys.size(); + const size_t numverts = mesh->verts.size(); + const size_t numkeys = mesh->curve_keys.size(); if(!numverts && !numkeys) return; - + /* skip objects without deforming modifiers. this is not totally reliable, * would need a more extensive check to see which objects are animated */ BL::Mesh b_mesh(PointerRNA_NULL); @@ -1086,7 +1203,13 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob, if(ccl::BKE_object_is_deform_modified(b_ob, b_scene, preview)) { /* get derived mesh */ - b_mesh = object_to_mesh(b_data, b_ob, b_scene, true, !preview, false, false); + b_mesh = object_to_mesh(b_data, + b_ob, + b_scene, + true, + !preview, + false, + Mesh::SUBDIVISION_NONE); } if(!b_mesh) { @@ -1122,13 +1245,12 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob, /* TODO(sergey): Perform preliminary check for number of verticies. */ if(numverts) { - /* find attributes */ + /* Find attributes. */ Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); Attribute *attr_mN = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_NORMAL); Attribute *attr_N = mesh->attributes.find(ATTR_STD_VERTEX_NORMAL); bool new_attribute = false; - - /* add new attributes if they don't exist already */ + /* Add new attributes if they don't exist already. */ if(!attr_mP) { attr_mP = mesh->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION); if(attr_N) @@ -1136,31 +1258,32 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob, new_attribute = true; } - - /* load vertex data from mesh */ + /* Load vertex data from mesh. */ float3 *mP = attr_mP->data_float3() + time_index*numverts; float3 *mN = (attr_mN)? attr_mN->data_float3() + time_index*numverts: NULL; - + /* NOTE: We don't copy more that existing amount of vertices to prevent + * possible memory corruption. + */ BL::Mesh::vertices_iterator v; int i = 0; - for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end() && i < numverts; ++v, ++i) { mP[i] = get_float3(v->co()); if(mN) mN[i] = get_float3(v->normal()); } - - /* in case of new attribute, we verify if there really was any motion */ if(new_attribute) { + /* In case of new attribute, we verify if there really was any motion. */ if(b_mesh.vertices.length() != numverts || memcmp(mP, &mesh->verts[0], sizeof(float3)*numverts) == 0) { /* no motion, remove attributes again */ if(b_mesh.vertices.length() != numverts) { - VLOG(1) << "Topology differs, disabling motion blur."; + VLOG(1) << "Topology differs, disabling motion blur for object " + << b_ob.name(); } else { - VLOG(1) << "No actual deformation motion for object " << b_ob.name(); + VLOG(1) << "No actual deformation motion for object " + << b_ob.name(); } mesh->attributes.remove(ATTR_STD_MOTION_VERTEX_POSITION); if(attr_mN) @@ -1172,7 +1295,6 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob, * they had no motion, but we need them anyway now */ float3 *P = &mesh->verts[0]; float3 *N = (attr_N)? attr_N->data_float3(): NULL; - for(int step = 0; step < time_index; step++) { memcpy(attr_mP->data_float3() + step*numverts, P, sizeof(float3)*numverts); if(attr_mN) @@ -1180,6 +1302,16 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob, } } } + else { + if(b_mesh.vertices.length() != numverts) { + VLOG(1) << "Topology differs, discarding motion blur for object " + << b_ob.name() << " at time " << time_index; + memcpy(mP, &mesh->verts[0], sizeof(float3)*numverts); + if(mN != NULL) { + memcpy(mN, attr_N->data_float3(), sizeof(float3)*numverts); + } + } + } } /* hair motion */ @@ -1187,8 +1319,7 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob, sync_curves(mesh, b_mesh, b_ob, true, time_index); /* free derived mesh */ - b_data.meshes.remove(b_mesh, false); + b_data.meshes.remove(b_mesh, false, true, false); } CCL_NAMESPACE_END - |