From cc64872b88fc9842c0af3e155d08bc61473bf7e7 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Sun, 21 Jan 2018 15:19:34 +0100 Subject: [PATCH] Fix T49159: missing Cycles tangents for adaptive subdivision. --- intern/cycles/blender/blender_mesh.cpp | 252 +++++++++++++++++-------- 1 file changed, 176 insertions(+), 76 deletions(-) diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp index d2757851877..3bd83b39dfa 100644 --- a/intern/cycles/blender/blender_mesh.cpp +++ b/intern/cycles/blender/blender_mesh.cpp @@ -79,7 +79,7 @@ inline void face_split_tri_indices(const int face_flag, struct MikkUserData { MikkUserData(const BL::Mesh& b_mesh, - BL::MeshTextureFaceLayer *layer, + const char *layer_name, const Mesh *mesh, float3 *tangent, float *tangent_sign) @@ -89,16 +89,19 @@ struct MikkUserData { tangent(tangent), tangent_sign(tangent_sign) { - Attribute *attr_vN = mesh->attributes.find(ATTR_STD_VERTEX_NORMAL); + const AttributeSet& attributes = (mesh->subd_faces.size()) ? + mesh->subd_attributes : mesh->attributes; + + Attribute *attr_vN = attributes.find(ATTR_STD_VERTEX_NORMAL); vertex_normal = attr_vN->data_float3(); - if(layer == NULL) { - Attribute *attr_orco = mesh->attributes.find(ATTR_STD_GENERATED); + if(layer_name == NULL) { + Attribute *attr_orco = 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())); + Attribute *attr_uv = attributes.find(ustring(layer_name)); if(attr_uv != NULL) { texface = attr_uv->data_float3(); } @@ -120,13 +123,47 @@ struct MikkUserData { static int mikk_get_num_faces(const SMikkTSpaceContext *context) { const MikkUserData *userdata = (const MikkUserData *)context->m_pUserData; - return userdata->mesh->num_triangles(); + if(userdata->mesh->subd_faces.size()) { + return userdata->mesh->subd_faces.size(); + } + else { + 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) { - return 3; + const MikkUserData *userdata = (const MikkUserData *)context->m_pUserData; + if(userdata->mesh->subd_faces.size()) { + const Mesh *mesh = userdata->mesh; + return mesh->subd_faces[face_num].num_corners; + } + else { + return 3; + } +} + +static int mikk_vertex_index(const Mesh *mesh, const int face_num, const int vert_num) +{ + if(mesh->subd_faces.size()) { + const Mesh::SubdFace& face = mesh->subd_faces[face_num]; + return mesh->subd_face_corners[face.start_corner + vert_num]; + } + else { + return mesh->triangles[face_num * 3 + vert_num]; + } +} + +static int mikk_corner_index(const Mesh *mesh, const int face_num, const int vert_num) +{ + if(mesh->subd_faces.size()) { + const Mesh::SubdFace& face = mesh->subd_faces[face_num]; + return face.start_corner + vert_num; + } + else { + return face_num * 3 + vert_num; + } } static void mikk_get_position(const SMikkTSpaceContext *context, @@ -135,9 +172,8 @@ static void mikk_get_position(const SMikkTSpaceContext *context, { 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]; - + const int vertex_index = mikk_vertex_index(mesh, face_num, vert_num); + const float3 vP = mesh->verts[vertex_index]; P[0] = vP.x; P[1] = vP.y; P[2] = vP.z; @@ -148,15 +184,15 @@ static void mikk_get_texture_coordinate(const SMikkTSpaceContext *context, const int face_num, const int vert_num) { const MikkUserData *userdata = (const MikkUserData *)context->m_pUserData; + const Mesh *mesh = userdata->mesh; if(userdata->texface != NULL) { - const size_t corner_index = face_num * 3 + vert_num; + const int corner_index = mikk_corner_index(mesh, face_num, vert_num); float3 tfuv = userdata->texface[corner_index]; uv[0] = tfuv.x; uv[1] = tfuv.y; } else if(userdata->orco != NULL) { - const Mesh *mesh = userdata->mesh; - const size_t vertex_index = mesh->triangles[face_num * 3 + vert_num]; + const int vertex_index = mikk_vertex_index(mesh, face_num, 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; @@ -177,13 +213,25 @@ static void mikk_get_normal(const SMikkTSpaceContext *context, float N[3], const MikkUserData *userdata = (const MikkUserData *)context->m_pUserData; const Mesh *mesh = userdata->mesh; float3 vN; - if(mesh->smooth[face_num]) { - const size_t vert_index = mesh->triangles[face_num * 3 + vert_num]; - vN = userdata->vertex_normal[vert_index]; + if(mesh->subd_faces.size()) { + const Mesh::SubdFace& face = mesh->subd_faces[face_num]; + if(face.smooth) { + const int vertex_index = mikk_vertex_index(mesh, face_num, vert_num); + vN = userdata->vertex_normal[vertex_index]; + } + else { + vN = face.normal(mesh); + } } else { - const Mesh::Triangle tri = mesh->get_triangle(face_num); - vN = tri.compute_normal(&mesh->verts[0]); + if(mesh->smooth[face_num]) { + const int vertex_index = mikk_vertex_index(mesh, face_num, vert_num); + vN = userdata->vertex_normal[vertex_index]; + } + else { + const Mesh::Triangle tri = mesh->get_triangle(face_num); + vN = tri.compute_normal(&mesh->verts[0]); + } } N[0] = vN.x; N[1] = vN.y; @@ -196,7 +244,8 @@ static void mikk_set_tangent_space(const SMikkTSpaceContext *context, const int face_num, const int vert_num) { MikkUserData *userdata = (MikkUserData *)context->m_pUserData; - const size_t corner_index = face_num * 3 + vert_num; + const Mesh *mesh = userdata->mesh; + const int corner_index = mikk_corner_index(mesh, face_num, 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; @@ -204,27 +253,27 @@ static void mikk_set_tangent_space(const SMikkTSpaceContext *context, } static void mikk_compute_tangents(const BL::Mesh& b_mesh, - BL::MeshTextureFaceLayer *b_layer, + const char *layer_name, Mesh *mesh, bool need_sign, bool active_render) { /* Create tangent attributes. */ + AttributeSet& attributes = (mesh->subd_faces.size()) ? + mesh->subd_attributes : mesh->attributes; Attribute *attr; ustring name; - if(b_layer != NULL) { - name = ustring((string(b_layer->name().c_str()) + ".tangent").c_str()); + if(layer_name != NULL) { + name = ustring((string(layer_name) + ".tangent").c_str()); } else { name = ustring("orco.tangent"); } if(active_render) { - attr = mesh->attributes.add(ATTR_STD_UV_TANGENT, name); + attr = attributes.add(ATTR_STD_UV_TANGENT, name); } else { - attr = mesh->attributes.add(name, - TypeDesc::TypeVector, - ATTR_ELEMENT_CORNER); + attr = attributes.add(name, TypeDesc::TypeVector, ATTR_ELEMENT_CORNER); } float3 *tangent = attr->data_float3(); /* Create bitangent sign attribute. */ @@ -232,8 +281,8 @@ static void mikk_compute_tangents(const BL::Mesh& b_mesh, if(need_sign) { Attribute *attr_sign; ustring name_sign; - if(b_layer != NULL) { - name_sign = ustring((string(b_layer->name().c_str()) + + if(layer_name != NULL) { + name_sign = ustring((string(layer_name) + ".tangent_sign").c_str()); } else { @@ -241,18 +290,17 @@ static void mikk_compute_tangents(const BL::Mesh& b_mesh, } if(active_render) { - attr_sign = mesh->attributes.add(ATTR_STD_UV_TANGENT_SIGN, - name_sign); + attr_sign = attributes.add(ATTR_STD_UV_TANGENT_SIGN, name_sign); } else { - attr_sign = mesh->attributes.add(name_sign, - TypeDesc::TypeFloat, - ATTR_ELEMENT_CORNER); + attr_sign = 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); + MikkUserData userdata(b_mesh, layer_name, mesh, tangent, tangent_sign); /* Setup interface. */ SMikkTSpaceInterface sm_interface; memset(&sm_interface, 0, sizeof(sm_interface)); @@ -399,45 +447,9 @@ static void attr_create_uv_map(Scene *scene, Mesh *mesh, BL::Mesh& b_mesh, const vector& nverts, - const vector& face_flags, - bool subdivision, - bool subdivide_uvs) + const vector& face_flags) { - if(subdivision) { - BL::Mesh::uv_layers_iterator l; - int i = 0; - - for(b_mesh.uv_layers.begin(l); l != b_mesh.uv_layers.end(); ++l, ++i) { - bool active_render = b_mesh.uv_textures[i].active_render(); - AttributeStandard std = (active_render)? ATTR_STD_UV: ATTR_STD_NONE; - ustring name = ustring(l->name().c_str()); - - /* UV map */ - if(mesh->need_attribute(scene, name) || mesh->need_attribute(scene, std)) { - Attribute *attr; - - if(active_render) - attr = mesh->subd_attributes.add(std, name); - else - attr = mesh->subd_attributes.add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CORNER); - - if(subdivide_uvs) { - attr->flags |= ATTR_SUBDIVIDED; - } - - BL::Mesh::polygons_iterator p; - float3 *fdata = attr->data_float3(); - - for(b_mesh.polygons.begin(p); p != b_mesh.polygons.end(); ++p) { - int n = p->loop_total(); - for(int j = 0; j < n; j++) { - *(fdata++) = get_float3(l->data[p->loop_start() + j].uv()); - } - } - } - } - } - else if(b_mesh.tessface_uv_textures.length() != 0) { + if(b_mesh.tessface_uv_textures.length() != 0) { BL::Mesh::tessface_uv_textures_iterator l; for(b_mesh.tessface_uv_textures.begin(l); l != b_mesh.tessface_uv_textures.end(); ++l) { @@ -512,7 +524,7 @@ static void attr_create_uv_map(Scene *scene, bool need_sign = (mesh->need_attribute(scene, sign_name) || mesh->need_attribute(scene, sign_std)); mikk_compute_tangents(b_mesh, - &(*l), + l->name().c_str(), mesh, need_sign, active_render); @@ -532,6 +544,88 @@ static void attr_create_uv_map(Scene *scene, } } +static void attr_create_subd_uv_map(Scene *scene, + Mesh *mesh, + BL::Mesh& b_mesh, + const vector& nverts, + const vector& face_flags, + bool subdivide_uvs) +{ + if(b_mesh.uv_layers.length() != 0) { + BL::Mesh::uv_layers_iterator l; + int i = 0; + + for(b_mesh.uv_layers.begin(l); l != b_mesh.uv_layers.end(); ++l, ++i) { + bool active_render = b_mesh.uv_textures[i].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)); + + Attribute *uv_attr = NULL; + + /* UV map */ + if(need_uv || need_tangent) { + if(active_render) + uv_attr = mesh->subd_attributes.add(uv_std, uv_name); + else + uv_attr = mesh->subd_attributes.add(uv_name, TypeDesc::TypePoint, ATTR_ELEMENT_CORNER); + + if(subdivide_uvs) { + uv_attr->flags |= ATTR_SUBDIVIDED; + } + + BL::Mesh::polygons_iterator p; + float3 *fdata = uv_attr->data_float3(); + + for(b_mesh.polygons.begin(p); p != b_mesh.polygons.end(); ++p) { + int n = p->loop_total(); + for(int j = 0; j < n; j++) { + *(fdata++) = get_float3(l->data[p->loop_start() + j].uv()); + } + } + } + + /* UV tangent */ + 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->name().c_str(), + mesh, + need_sign, + active_render); + } + /* Remove temporarily created UV attribute. */ + if(!need_uv && uv_attr != NULL) { + mesh->subd_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, need_sign, true); + if(!mesh->need_attribute(scene, ATTR_STD_GENERATED)) { + mesh->subd_attributes.remove(ATTR_STD_GENERATED); + } + } +} + /* Create vertex pointiness attributes. */ /* Compare vertices by sum of their coordinates. */ @@ -857,7 +951,13 @@ static void create_mesh(Scene *scene, */ 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); + + if(subdivision) { + attr_create_subd_uv_map(scene, mesh, b_mesh, nverts, face_flags, subdivide_uvs); + } + else { + attr_create_uv_map(scene, mesh, b_mesh, nverts, face_flags); + } /* for volume objects, create a matrix to transform from object space to * mesh texture space. this does not work with deformations but that can