Fix (partial) T47198: Cycles have broken UVs in some degenerated quads cases

The issue was discontinuity in logic when importing vertices from blender
and then importing data layers regardless of how we split the face. Quite
interesting we didn't notice this issue before.

Thanks Bastien for the investigation, based on D1742 but redid it to make
patch a bit more clear to follow.
This commit is contained in:
Sergey Sharybin 2016-01-20 09:13:04 +01:00
parent 7e9feac3e0
commit a6eae73391

@ -35,6 +35,48 @@
CCL_NAMESPACE_BEGIN CCL_NAMESPACE_BEGIN
/* Per-face bit flags. */
enum {
/* Face has no special flags. */
FACE_FLAG_NONE = (0 << 0),
/* Quad face was split using 1-3 diagonal. */
FACE_FLAG_DIVIDE_13 = (1 << 0),
/* Quad face was split using 2-4 diagonal. */
FACE_FLAG_DIVIDE_24 = (1 << 1),
};
/* Get vertex indices to create triangles from a given face.
*
* 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,
int tri_a[3],
int tri_b[3])
{
if(face_flag & FACE_FLAG_DIVIDE_24) {
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;
}
}
else /*if(face_flag & FACE_FLAG_DIVIDE_13)*/ {
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;
}
}
}
/* Tangent Space */ /* Tangent Space */
struct MikkUserData { struct MikkUserData {
@ -140,7 +182,13 @@ 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, const vector<int>& nverts, bool need_sign, bool active_render) static void mikk_compute_tangents(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 */ /* setup userdata */
MikkUserData userdata(b_mesh, b_layer, nverts.size()); MikkUserData userdata(b_mesh, b_layer, nverts.size());
@ -199,28 +247,31 @@ static void mikk_compute_tangents(BL::Mesh b_mesh, BL::MeshTextureFaceLayer *b_l
} }
for(int i = 0; i < nverts.size(); i++) { for(int i = 0; i < nverts.size(); i++) {
tangent[0] = float4_to_float3(userdata.tangent[i*4 + 0]); int tri_a[3], tri_b[3];
tangent[1] = float4_to_float3(userdata.tangent[i*4 + 1]); face_split_tri_indices(nverts[i], face_flags[i], tri_a, tri_b);
tangent[2] = float4_to_float3(userdata.tangent[i*4 + 2]);
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; tangent += 3;
if(tangent_sign) { if(tangent_sign) {
tangent_sign[0] = userdata.tangent[i*4 + 0].w; tangent_sign[0] = userdata.tangent[i*4 + tri_a[0]].w;
tangent_sign[1] = userdata.tangent[i*4 + 1].w; tangent_sign[1] = userdata.tangent[i*4 + tri_a[1]].w;
tangent_sign[2] = userdata.tangent[i*4 + 2].w; tangent_sign[2] = userdata.tangent[i*4 + tri_a[2]].w;
tangent_sign += 3; tangent_sign += 3;
} }
if(nverts[i] == 4) { if(nverts[i] == 4) {
tangent[0] = float4_to_float3(userdata.tangent[i*4 + 0]); tangent[0] = float4_to_float3(userdata.tangent[i*4 + tri_b[0]]);
tangent[1] = float4_to_float3(userdata.tangent[i*4 + 2]); tangent[1] = float4_to_float3(userdata.tangent[i*4 + tri_b[1]]);
tangent[2] = float4_to_float3(userdata.tangent[i*4 + 3]); tangent[2] = float4_to_float3(userdata.tangent[i*4 + tri_b[2]]);
tangent += 3; tangent += 3;
if(tangent_sign) { if(tangent_sign) {
tangent_sign[0] = userdata.tangent[i*4 + 0].w; tangent_sign[0] = userdata.tangent[i*4 + tri_b[0]].w;
tangent_sign[1] = userdata.tangent[i*4 + 2].w; tangent_sign[1] = userdata.tangent[i*4 + tri_b[1]].w;
tangent_sign[2] = userdata.tangent[i*4 + 3].w; tangent_sign[2] = userdata.tangent[i*4 + tri_b[2]].w;
tangent_sign += 3; tangent_sign += 3;
} }
} }
@ -273,7 +324,8 @@ static void create_mesh_volume_attributes(Scene *scene, BL::Object b_ob, Mesh *m
static void attr_create_vertex_color(Scene *scene, static void attr_create_vertex_color(Scene *scene,
Mesh *mesh, Mesh *mesh,
BL::Mesh b_mesh, BL::Mesh b_mesh,
const vector<int>& nverts) const vector<int>& nverts,
const vector<int>& face_flags)
{ {
BL::Mesh::tessface_vertex_colors_iterator l; BL::Mesh::tessface_vertex_colors_iterator l;
for(b_mesh.tessface_vertex_colors.begin(l); l != b_mesh.tessface_vertex_colors.end(); ++l) { for(b_mesh.tessface_vertex_colors.begin(l); l != b_mesh.tessface_vertex_colors.end(); ++l) {
@ -288,14 +340,25 @@ static void attr_create_vertex_color(Scene *scene,
size_t i = 0; size_t i = 0;
for(l->data.begin(c); c != l->data.end(); ++c, ++i) { for(l->data.begin(c); c != l->data.end(); ++c, ++i) {
cdata[0] = color_float_to_byte(color_srgb_to_scene_linear(get_float3(c->color1()))); int tri_a[3], tri_b[3];
cdata[1] = color_float_to_byte(color_srgb_to_scene_linear(get_float3(c->color2()))); face_split_tri_indices(nverts[i], face_flags[i], tri_a, tri_b);
cdata[2] = color_float_to_byte(color_srgb_to_scene_linear(get_float3(c->color3())));
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())));
if(nverts[i] == 4) {
colors[3] = color_float_to_byte(color_srgb_to_scene_linear(get_float3(c->color4())));
}
cdata[0] = colors[tri_a[0]];
cdata[1] = colors[tri_a[1]];
cdata[2] = colors[tri_a[2]];
if(nverts[i] == 4) { if(nverts[i] == 4) {
cdata[3] = cdata[0]; cdata[3] = colors[tri_b[0]];
cdata[4] = cdata[2]; cdata[4] = colors[tri_b[1]];
cdata[5] = color_float_to_byte(color_srgb_to_scene_linear(get_float3(c->color4()))); cdata[5] = colors[tri_b[2]];
cdata += 6; cdata += 6;
} }
else else
@ -308,7 +371,8 @@ static void attr_create_vertex_color(Scene *scene,
static void attr_create_uv_map(Scene *scene, static void attr_create_uv_map(Scene *scene,
Mesh *mesh, Mesh *mesh,
BL::Mesh b_mesh, BL::Mesh b_mesh,
const vector<int>& nverts) const vector<int>& nverts,
const vector<int>& face_flags)
{ {
if(b_mesh.tessface_uv_textures.length() != 0) { if(b_mesh.tessface_uv_textures.length() != 0) {
BL::Mesh::tessface_uv_textures_iterator l; BL::Mesh::tessface_uv_textures_iterator l;
@ -332,15 +396,26 @@ static void attr_create_uv_map(Scene *scene,
size_t i = 0; size_t i = 0;
for(l->data.begin(t); t != l->data.end(); ++t, ++i) { for(l->data.begin(t); t != l->data.end(); ++t, ++i) {
fdata[0] = get_float3(t->uv1()); int tri_a[3], tri_b[3];
fdata[1] = get_float3(t->uv2()); face_split_tri_indices(nverts[i], face_flags[i], tri_a, tri_b);
fdata[2] = get_float3(t->uv3());
float3 uvs[4];
uvs[0] = get_float3(t->uv1());
uvs[1] = get_float3(t->uv2());
uvs[2] = get_float3(t->uv3());
if(nverts[i] == 4) {
uvs[3] = get_float3(t->uv4());
}
fdata[0] = uvs[tri_a[0]];
fdata[1] = uvs[tri_a[1]];
fdata[2] = uvs[tri_a[2]];
fdata += 3; fdata += 3;
if(nverts[i] == 4) { if(nverts[i] == 4) {
fdata[0] = get_float3(t->uv1()); fdata[0] = uvs[tri_b[0]];
fdata[1] = get_float3(t->uv3()); fdata[1] = uvs[tri_b[0]];
fdata[2] = get_float3(t->uv4()); fdata[2] = uvs[tri_b[0]];
fdata += 3; fdata += 3;
} }
} }
@ -355,13 +430,25 @@ static void attr_create_uv_map(Scene *scene,
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,
face_flags,
need_sign,
active_render);
} }
} }
} }
else if(mesh->need_attribute(scene, ATTR_STD_UV_TANGENT)) { else if(mesh->need_attribute(scene, ATTR_STD_UV_TANGENT)) {
bool need_sign = mesh->need_attribute(scene, ATTR_STD_UV_TANGENT_SIGN); bool need_sign = mesh->need_attribute(scene, ATTR_STD_UV_TANGENT_SIGN);
mikk_compute_tangents(b_mesh, NULL, mesh, nverts, need_sign, true); mikk_compute_tangents(b_mesh,
NULL,
mesh,
nverts,
face_flags,
need_sign,
true);
} }
} }
@ -482,6 +569,7 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<
/* create faces */ /* create faces */
vector<int> nverts(numfaces); vector<int> nverts(numfaces);
vector<int> face_flags(numfaces, FACE_FLAG_NONE);
int fi = 0, ti = 0; int fi = 0, ti = 0;
for(b_mesh.tessfaces.begin(f); f != b_mesh.tessfaces.end(); ++f, ++fi) { for(b_mesh.tessfaces.begin(f); f != b_mesh.tessfaces.end(); ++f, ++fi) {
@ -519,10 +607,12 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<
{ {
mesh->set_triangle(ti++, vi[0], vi[1], vi[3], shader, smooth); mesh->set_triangle(ti++, vi[0], vi[1], vi[3], shader, smooth);
mesh->set_triangle(ti++, vi[2], vi[3], vi[1], shader, smooth); mesh->set_triangle(ti++, vi[2], vi[3], vi[1], shader, smooth);
face_flags[fi] |= FACE_FLAG_DIVIDE_24;
} }
else { else {
mesh->set_triangle(ti++, vi[0], vi[1], vi[2], shader, smooth); mesh->set_triangle(ti++, vi[0], vi[1], vi[2], shader, smooth);
mesh->set_triangle(ti++, vi[0], vi[2], vi[3], shader, smooth); mesh->set_triangle(ti++, vi[0], vi[2], vi[3], shader, smooth);
face_flags[fi] |= FACE_FLAG_DIVIDE_13;
} }
} }
else else
@ -534,8 +624,8 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<
/* Create all needed attributes. /* Create all needed attributes.
* The calculate functions will check whether they're needed or not. * The calculate functions will check whether they're needed or not.
*/ */
attr_create_vertex_color(scene, mesh, b_mesh, nverts); attr_create_vertex_color(scene, mesh, b_mesh, nverts, face_flags);
attr_create_uv_map(scene, mesh, b_mesh, nverts); attr_create_uv_map(scene, mesh, b_mesh, nverts, face_flags);
/* 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