Fix T41174: Tangent space required UV map in Cycles

Now Cycles behaves in the same way as BI in terms of using
sphere projection of orco coordinates if there's no UV map
when calculating tangent space.
This commit is contained in:
Sergey Sharybin 2014-07-29 16:07:05 +06:00
parent a9c8a117a2
commit 946f291c46
2 changed files with 63 additions and 26 deletions

@ -35,14 +35,14 @@ CCL_NAMESPACE_BEGIN
/* Tangent Space */ /* Tangent Space */
struct MikkUserData { struct MikkUserData {
MikkUserData(const BL::Mesh mesh_, const BL::MeshTextureFaceLayer layer_, int num_faces_) MikkUserData(const BL::Mesh mesh_, BL::MeshTextureFaceLayer *layer_, int num_faces_)
: mesh(mesh_), layer(layer_), num_faces(num_faces_) : mesh(mesh_), layer(layer_), num_faces(num_faces_)
{ {
tangent.resize(num_faces*4); tangent.resize(num_faces*4);
} }
BL::Mesh mesh; BL::Mesh mesh;
BL::MeshTextureFaceLayer layer; BL::MeshTextureFaceLayer *layer;
int num_faces; int num_faces;
vector<float4> tangent; vector<float4> tangent;
}; };
@ -78,26 +78,34 @@ static void mikk_get_position(const SMikkTSpaceContext *context, float P[3], con
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; MikkUserData *userdata = (MikkUserData*)context->m_pUserData;
BL::MeshTextureFace tf = userdata->layer.data[face_num]; if(userdata->layer != NULL) {
float3 tfuv; BL::MeshTextureFace tf = userdata->layer->data[face_num];
float3 tfuv;
switch (vert_num) {
case 0: switch (vert_num) {
tfuv = get_float3(tf.uv1()); case 0:
break; tfuv = get_float3(tf.uv1());
case 1: break;
tfuv = get_float3(tf.uv2()); case 1:
break; tfuv = get_float3(tf.uv2());
case 2: break;
tfuv = get_float3(tf.uv3()); case 2:
break; tfuv = get_float3(tf.uv3());
default: break;
tfuv = get_float3(tf.uv4()); default:
break; tfuv = get_float3(tf.uv4());
break;
}
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());
map_to_sphere(&uv[0], &uv[1], orco[0], orco[1], orco[2]);
} }
uv[0] = tfuv.x;
uv[1] = tfuv.y;
} }
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)
@ -127,7 +135,7 @@ static void mikk_set_tangent_space(const SMikkTSpaceContext *context, const floa
userdata->tangent[face*4 + vert] = make_float4(T[0], T[1], T[2], sign); userdata->tangent[face*4 + vert] = make_float4(T[0], T[1], T[2], sign);
} }
static void mikk_compute_tangents(BL::Mesh b_mesh, BL::MeshTextureFaceLayer b_layer, Mesh *mesh, vector<int>& nverts, bool need_sign, bool active_render) static void mikk_compute_tangents(BL::Mesh b_mesh, BL::MeshTextureFaceLayer *b_layer, Mesh *mesh, vector<int>& nverts, bool need_sign, bool active_render)
{ {
/* setup userdata */ /* setup userdata */
MikkUserData userdata(b_mesh, b_layer, nverts.size()); MikkUserData userdata(b_mesh, b_layer, nverts.size());
@ -153,7 +161,11 @@ static void mikk_compute_tangents(BL::Mesh b_mesh, BL::MeshTextureFaceLayer b_la
/* create tangent attributes */ /* create tangent attributes */
Attribute *attr; Attribute *attr;
ustring name = ustring((string(b_layer.name().c_str()) + ".tangent").c_str()); ustring name;
if(b_layer != NULL)
name = ustring((string(b_layer->name().c_str()) + ".tangent").c_str());
else
name = ustring("orco.tangent");
if(active_render) if(active_render)
attr = mesh->attributes.add(ATTR_STD_UV_TANGENT, name); attr = mesh->attributes.add(ATTR_STD_UV_TANGENT, name);
@ -167,7 +179,11 @@ static void mikk_compute_tangents(BL::Mesh b_mesh, BL::MeshTextureFaceLayer b_la
if(need_sign) { if(need_sign) {
Attribute *attr_sign; Attribute *attr_sign;
ustring name_sign = ustring((string(b_layer.name().c_str()) + ".tangent_sign").c_str()); ustring name_sign;
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) if(active_render)
attr_sign = mesh->attributes.add(ATTR_STD_UV_TANGENT_SIGN, name_sign); attr_sign = mesh->attributes.add(ATTR_STD_UV_TANGENT_SIGN, name_sign);
@ -371,7 +387,7 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<
} }
/* create uv map attributes */ /* create uv map attributes */
{ if (b_mesh.tessface_uv_textures.length() != 0) {
BL::Mesh::tessface_uv_textures_iterator l; BL::Mesh::tessface_uv_textures_iterator l;
for(b_mesh.tessface_uv_textures.begin(l); l != b_mesh.tessface_uv_textures.end(); ++l) { for(b_mesh.tessface_uv_textures.begin(l); l != b_mesh.tessface_uv_textures.end(); ++l) {
@ -416,10 +432,14 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<
name = ustring((string(l->name().c_str()) + ".tangent_sign").c_str()); name = ustring((string(l->name().c_str()) + ".tangent_sign").c_str());
bool need_sign = (mesh->need_attribute(scene, name) || mesh->need_attribute(scene, std)); bool need_sign = (mesh->need_attribute(scene, name) || mesh->need_attribute(scene, std));
mikk_compute_tangents(b_mesh, *l, mesh, nverts, need_sign, active_render); mikk_compute_tangents(b_mesh, &(*l), mesh, nverts, need_sign, active_render);
} }
} }
} }
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, need_sign, true);
}
/* for volume objects, create a matrix to transform from object space to /* for volume objects, create a matrix to transform from object space to
* mesh texture space. this does not work with deformations but that can * mesh texture space. this does not work with deformations but that can

@ -1425,6 +1425,23 @@ ccl_device bool ray_quad_intersect(
return false; return false;
} }
/* projections */
ccl_device bool map_to_sphere(float *r_u, float *r_v,
const float x, const float y, const float z)
{
float len = sqrtf(x * x + y * y + z * z);
if (len > 0.0f) {
if (x == 0.0f && y == 0.0f) *r_u = 0.0f; /* othwise domain error */
else *r_u = (1.0f - atan2f(x, y) / (float)M_PI) / 2.0f;
*r_v = 1.0f - safe_acosf(z / len) / (float)M_PI;
return true;
}
else {
*r_v = *r_u = 0.0f; /* to avoid un-initialized variables */
return false;
}
}
CCL_NAMESPACE_END CCL_NAMESPACE_END
#endif /* __UTIL_MATH_H__ */ #endif /* __UTIL_MATH_H__ */