Changeset View
Changeset View
Standalone View
Standalone View
intern/cycles/blender/mesh.cpp
| Show All 18 Lines | |||||
| #include "util/algorithm.h" | #include "util/algorithm.h" | ||||
| #include "util/color.h" | #include "util/color.h" | ||||
| #include "util/disjoint_set.h" | #include "util/disjoint_set.h" | ||||
| #include "util/foreach.h" | #include "util/foreach.h" | ||||
| #include "util/hash.h" | #include "util/hash.h" | ||||
| #include "util/log.h" | #include "util/log.h" | ||||
| #include "util/math.h" | #include "util/math.h" | ||||
| #include "mikktspace.h" | #include "mikktspace.hh" | ||||
| #include "DNA_meshdata_types.h" | #include "DNA_meshdata_types.h" | ||||
| CCL_NAMESPACE_BEGIN | CCL_NAMESPACE_BEGIN | ||||
| /* Tangent Space */ | /* Tangent Space */ | ||||
| struct MikkUserData { | template<bool is_subd> struct MikkMeshWrapper { | ||||
| MikkUserData(const BL::Mesh &b_mesh, | MikkMeshWrapper(const BL::Mesh &b_mesh, | ||||
| const char *layer_name, | const char *layer_name, | ||||
| const Mesh *mesh, | const Mesh *mesh, | ||||
| float3 *tangent, | float3 *tangent, | ||||
| float *tangent_sign) | float *tangent_sign) | ||||
| : mesh(mesh), texface(NULL), orco(NULL), tangent(tangent), tangent_sign(tangent_sign) | : mesh(mesh), texface(NULL), orco(NULL), tangent(tangent), tangent_sign(tangent_sign) | ||||
| { | { | ||||
| const AttributeSet &attributes = (mesh->get_num_subd_faces()) ? mesh->subd_attributes : | const AttributeSet &attributes = is_subd ? mesh->subd_attributes : mesh->attributes; | ||||
| mesh->attributes; | |||||
| Attribute *attr_vN = attributes.find(ATTR_STD_VERTEX_NORMAL); | Attribute *attr_vN = attributes.find(ATTR_STD_VERTEX_NORMAL); | ||||
| vertex_normal = attr_vN->data_float3(); | vertex_normal = attr_vN->data_float3(); | ||||
| if (layer_name == NULL) { | if (layer_name == NULL) { | ||||
| Attribute *attr_orco = attributes.find(ATTR_STD_GENERATED); | Attribute *attr_orco = attributes.find(ATTR_STD_GENERATED); | ||||
| if (attr_orco) { | if (attr_orco) { | ||||
| orco = attr_orco->data_float3(); | orco = attr_orco->data_float3(); | ||||
| float3 orco_size; | |||||
| mesh_texture_space(*(BL::Mesh *)&b_mesh, orco_loc, orco_size); | mesh_texture_space(*(BL::Mesh *)&b_mesh, orco_loc, orco_size); | ||||
| inv_orco_size = 1.0f / orco_size; | |||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| Attribute *attr_uv = attributes.find(ustring(layer_name)); | Attribute *attr_uv = attributes.find(ustring(layer_name)); | ||||
| if (attr_uv != NULL) { | if (attr_uv != NULL) { | ||||
| texface = attr_uv->data_float2(); | texface = attr_uv->data_float2(); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| const Mesh *mesh; | int GetNumFaces() | ||||
| int num_faces; | |||||
| float3 *vertex_normal; | |||||
| float2 *texface; | |||||
| float3 *orco; | |||||
| float3 orco_loc, orco_size; | |||||
| float3 *tangent; | |||||
| float *tangent_sign; | |||||
| }; | |||||
| static int mikk_get_num_faces(const SMikkTSpaceContext *context) | |||||
| { | { | ||||
| const MikkUserData *userdata = (const MikkUserData *)context->m_pUserData; | if constexpr (is_subd) { | ||||
sergey: Here and in other places suggest to `if constexpr (is_subd)` | |||||
| if (userdata->mesh->get_num_subd_faces()) { | return mesh->get_num_subd_faces(); | ||||
| return userdata->mesh->get_num_subd_faces(); | |||||
| } | } | ||||
| else { | else { | ||||
| return userdata->mesh->num_triangles(); | return mesh->num_triangles(); | ||||
| } | } | ||||
| } | } | ||||
| static int mikk_get_num_verts_of_face(const SMikkTSpaceContext *context, const int face_num) | int GetNumVerticesOfFace(const int face_num) | ||||
| { | { | ||||
| const MikkUserData *userdata = (const MikkUserData *)context->m_pUserData; | if constexpr (is_subd) { | ||||
| if (userdata->mesh->get_num_subd_faces()) { | |||||
| const Mesh *mesh = userdata->mesh; | |||||
| return mesh->get_subd_num_corners()[face_num]; | return mesh->get_subd_num_corners()[face_num]; | ||||
| } | } | ||||
| else { | else { | ||||
| return 3; | return 3; | ||||
| } | } | ||||
| } | } | ||||
| static int mikk_vertex_index(const Mesh *mesh, const int face_num, const int vert_num) | int CornerIndex(const int face_num, const int vert_num) | ||||
| { | { | ||||
| if (mesh->get_num_subd_faces()) { | if constexpr (is_subd) { | ||||
| const Mesh::SubdFace &face = mesh->get_subd_face(face_num); | const Mesh::SubdFace &face = mesh->get_subd_face(face_num); | ||||
| return mesh->get_subd_face_corners()[face.start_corner + vert_num]; | return face.start_corner + vert_num; | ||||
| } | } | ||||
| else { | else { | ||||
| return mesh->get_triangles()[face_num * 3 + vert_num]; | return face_num * 3 + vert_num; | ||||
| } | } | ||||
| } | } | ||||
| static int mikk_corner_index(const Mesh *mesh, const int face_num, const int vert_num) | int VertexIndex(const int face_num, const int vert_num) | ||||
| { | { | ||||
| if (mesh->get_num_subd_faces()) { | int corner = CornerIndex(face_num, vert_num); | ||||
| const Mesh::SubdFace &face = mesh->get_subd_face(face_num); | if constexpr (is_subd) { | ||||
| return face.start_corner + vert_num; | return mesh->get_subd_face_corners()[corner]; | ||||
| } | } | ||||
| else { | else { | ||||
| return face_num * 3 + vert_num; | return mesh->get_triangles()[corner]; | ||||
| } | } | ||||
| } | } | ||||
| static void mikk_get_position(const SMikkTSpaceContext *context, | mikk::float3 GetPosition(const int face_num, const int vert_num) | ||||
| float P[3], | { | ||||
| const int face_num, | const float3 vP = mesh->get_verts()[VertexIndex(face_num, vert_num)]; | ||||
| const int vert_num) | return mikk::float3(vP.x, vP.y, vP.z); | ||||
| { | } | ||||
| const MikkUserData *userdata = (const MikkUserData *)context->m_pUserData; | |||||
| const Mesh *mesh = userdata->mesh; | mikk::float3 GetTexCoord(const int face_num, const int vert_num) | ||||
| const int vertex_index = mikk_vertex_index(mesh, face_num, vert_num); | { | ||||
| const float3 vP = mesh->get_verts()[vertex_index]; | /* TODO: Check whether introducing a template boolean in order to | ||||
Not Done Inline ActionsIt might worth specializing the implementation further, avoiding per-vertex branching. sergey: It might worth specializing the implementation further, avoiding per-vertex branching.
Maybe… | |||||
| P[0] = vP.x; | * turn this into a constexpr is worth it. */ | ||||
| P[1] = vP.y; | if (texface != NULL) { | ||||
| P[2] = vP.z; | const int corner_index = CornerIndex(face_num, vert_num); | ||||
| } | float2 tfuv = texface[corner_index]; | ||||
| return mikk::float3(tfuv.x, tfuv.y, 1.0f); | |||||
| static void mikk_get_texture_coordinate(const SMikkTSpaceContext *context, | } | ||||
| float uv[2], | else if (orco != NULL) { | ||||
| const int face_num, | const int vertex_index = VertexIndex(face_num, vert_num); | ||||
| const int vert_num) | const float2 uv = map_to_sphere((orco[vertex_index] + orco_loc) * inv_orco_size); | ||||
| { | return mikk::float3(uv.x, uv.y, 1.0f); | ||||
| const MikkUserData *userdata = (const MikkUserData *)context->m_pUserData; | } | ||||
| const Mesh *mesh = userdata->mesh; | else { | ||||
| if (userdata->texface != NULL) { | return mikk::float3(0.0f, 0.0f, 1.0f); | ||||
| const int corner_index = mikk_corner_index(mesh, face_num, vert_num); | |||||
| float2 tfuv = userdata->texface[corner_index]; | |||||
| uv[0] = tfuv.x; | |||||
| uv[1] = tfuv.y; | |||||
| } | |||||
| else if (userdata->orco != NULL) { | |||||
| 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; | |||||
| 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, | mikk::float3 GetNormal(const int face_num, const int vert_num) | ||||
| float N[3], | |||||
| const int face_num, | |||||
| const int vert_num) | |||||
| { | { | ||||
| const MikkUserData *userdata = (const MikkUserData *)context->m_pUserData; | |||||
| const Mesh *mesh = userdata->mesh; | |||||
| float3 vN; | float3 vN; | ||||
| if (mesh->get_num_subd_faces()) { | if (is_subd) { | ||||
| const Mesh::SubdFace &face = mesh->get_subd_face(face_num); | const Mesh::SubdFace &face = mesh->get_subd_face(face_num); | ||||
| if (face.smooth) { | if (face.smooth) { | ||||
| const int vertex_index = mikk_vertex_index(mesh, face_num, vert_num); | const int vertex_index = VertexIndex(face_num, vert_num); | ||||
| vN = userdata->vertex_normal[vertex_index]; | vN = vertex_normal[vertex_index]; | ||||
| } | } | ||||
| else { | else { | ||||
| vN = face.normal(mesh); | vN = face.normal(mesh); | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| if (mesh->get_smooth()[face_num]) { | if (mesh->get_smooth()[face_num]) { | ||||
| const int vertex_index = mikk_vertex_index(mesh, face_num, vert_num); | const int vertex_index = VertexIndex(face_num, vert_num); | ||||
| vN = userdata->vertex_normal[vertex_index]; | vN = vertex_normal[vertex_index]; | ||||
| } | } | ||||
| else { | else { | ||||
| const Mesh::Triangle tri = mesh->get_triangle(face_num); | const Mesh::Triangle tri = mesh->get_triangle(face_num); | ||||
| vN = tri.compute_normal(&mesh->get_verts()[0]); | vN = tri.compute_normal(&mesh->get_verts()[0]); | ||||
| } | } | ||||
| } | } | ||||
| N[0] = vN.x; | return mikk::float3(vN.x, vN.y, vN.z); | ||||
| N[1] = vN.y; | } | ||||
| N[2] = vN.z; | |||||
| } | void SetTangentSpace(const int face_num, const int vert_num, mikk::float3 T, bool orientation) | ||||
| { | |||||
| static void mikk_set_tangent_space(const SMikkTSpaceContext *context, | const int corner_index = CornerIndex(face_num, vert_num); | ||||
| const float T[], | tangent[corner_index] = make_float3(T.x, T.y, T.z); | ||||
| const float sign, | if (tangent_sign != NULL) { | ||||
| const int face_num, | tangent_sign[corner_index] = orientation ? 1.0f : -1.0f; | ||||
| const int vert_num) | |||||
| { | |||||
| MikkUserData *userdata = (MikkUserData *)context->m_pUserData; | |||||
| 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; | |||||
| } | } | ||||
| } | } | ||||
| const Mesh *mesh; | |||||
| int num_faces; | |||||
| float3 *vertex_normal; | |||||
| float2 *texface; | |||||
| float3 *orco; | |||||
| float3 orco_loc, inv_orco_size; | |||||
| float3 *tangent; | |||||
| float *tangent_sign; | |||||
| }; | |||||
| static void mikk_compute_tangents( | static void mikk_compute_tangents( | ||||
| const BL::Mesh &b_mesh, const char *layer_name, Mesh *mesh, bool need_sign, bool active_render) | const BL::Mesh &b_mesh, const char *layer_name, Mesh *mesh, bool need_sign, bool active_render) | ||||
| { | { | ||||
| /* Create tangent attributes. */ | /* Create tangent attributes. */ | ||||
| AttributeSet &attributes = (mesh->get_num_subd_faces()) ? mesh->subd_attributes : | const bool is_subd = mesh->get_num_subd_faces(); | ||||
| mesh->attributes; | AttributeSet &attributes = is_subd ? mesh->subd_attributes : mesh->attributes; | ||||
| Attribute *attr; | Attribute *attr; | ||||
| ustring name; | ustring name; | ||||
| if (layer_name != NULL) { | if (layer_name != NULL) { | ||||
| name = ustring((string(layer_name) + ".tangent").c_str()); | name = ustring((string(layer_name) + ".tangent").c_str()); | ||||
| } | } | ||||
| else { | else { | ||||
| name = ustring("orco.tangent"); | name = ustring("orco.tangent"); | ||||
| } | } | ||||
| Show All 19 Lines | if (need_sign) { | ||||
| if (active_render) { | if (active_render) { | ||||
| attr_sign = attributes.add(ATTR_STD_UV_TANGENT_SIGN, name_sign); | attr_sign = attributes.add(ATTR_STD_UV_TANGENT_SIGN, name_sign); | ||||
| } | } | ||||
| else { | else { | ||||
| attr_sign = 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(); | tangent_sign = attr_sign->data_float(); | ||||
| } | } | ||||
| /* Setup userdata. */ | /* Setup userdata. */ | ||||
| MikkUserData userdata(b_mesh, layer_name, mesh, tangent, tangent_sign); | if (is_subd) { | ||||
| /* Setup interface. */ | MikkMeshWrapper<true> userdata(b_mesh, layer_name, mesh, tangent, tangent_sign); | ||||
| 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. */ | /* Compute tangents. */ | ||||
| genTangSpaceDefault(&context); | mikk::Mikktspace(userdata).genTangSpace(); | ||||
| } | |||||
| else { | |||||
| MikkMeshWrapper<false> userdata(b_mesh, layer_name, mesh, tangent, tangent_sign); | |||||
| /* Compute tangents. */ | |||||
| mikk::Mikktspace(userdata).genTangSpace(); | |||||
| } | |||||
| } | } | ||||
| template<typename TypeInCycles, typename GetValueAtIndex> | template<typename TypeInCycles, typename GetValueAtIndex> | ||||
| static void fill_generic_attribute(BL::Mesh &b_mesh, | static void fill_generic_attribute(BL::Mesh &b_mesh, | ||||
| TypeInCycles *data, | TypeInCycles *data, | ||||
| const BL::Attribute::domain_enum b_domain, | const BL::Attribute::domain_enum b_domain, | ||||
| const bool subdivision, | const bool subdivision, | ||||
| const GetValueAtIndex &get_value_at_index) | const GetValueAtIndex &get_value_at_index) | ||||
| ▲ Show 20 Lines • Show All 1,080 Lines • Show Last 20 Lines | |||||
Here and in other places suggest to if constexpr (is_subd)