/** * This function returns the coordinate and normal of a barycentric u,v for a face defined by the primitive_id index. * The returned coordinate is extruded along the normal by cage_extrusion */ static void calc_point_from_barycentric_extrusion( TriTessFace *triangles, float mat[4][4], float imat[4][4], int primitive_id, float u, float v, float cage_extrusion, float r_co[3], float r_dir[3], const bool is_cage) { float data[3][3]; float coord[3]; float dir[3]; float cage[3]; bool is_smooth; TriTessFace *triangle = &triangles[primitive_id]; is_smooth = triangle->is_smooth || is_cage; copy_v3_v3(data[0], triangle->mverts[0]->co); copy_v3_v3(data[1], triangle->mverts[1]->co); copy_v3_v3(data[2], triangle->mverts[2]->co); interp_barycentric_tri_v3(data, u, v, coord); if (is_smooth) { normal_short_to_float_v3(data[0], triangle->mverts[0]->no); normal_short_to_float_v3(data[1], triangle->mverts[1]->no); normal_short_to_float_v3(data[2], triangle->mverts[2]->no); interp_barycentric_tri_v3(data, u, v, dir); normalize_v3(dir); } else { copy_v3_v3(dir, triangle->normal); } mul_v3_v3fl(cage, dir, cage_extrusion); add_v3_v3(coord, cage); normalize_v3(dir); negate_v3(dir); /* convert from local to world space */ mul_m4_v3(mat, coord); mul_transposed_mat3_m4_v3(imat, dir); normalize_v3(dir); copy_v3_v3(r_co, coord); copy_v3_v3(r_dir, dir); }
/** * This function returns the coordinate and normal of a barycentric u,v for a face defined by the primitive_id index. * The returned normal is actually the direction from the same barycentric coordinate in the cage to the base mesh * The returned coordinate is the point in the cage mesh */ static void calc_point_from_barycentric_cage( TriTessFace *triangles_low, TriTessFace *triangles_cage, float mat_low[4][4], float mat_cage[4][4], int primitive_id, float u, float v, float r_co[3], float r_dir[3]) { float data[2][3][3]; float coord[2][3]; float dir[3]; int i; TriTessFace *triangle[2]; triangle[0] = &triangles_low[primitive_id]; triangle[1] = &triangles_cage[primitive_id]; for (i = 0; i < 2; i++) { copy_v3_v3(data[i][0], triangle[i]->mverts[0]->co); copy_v3_v3(data[i][1], triangle[i]->mverts[1]->co); copy_v3_v3(data[i][2], triangle[i]->mverts[2]->co); interp_barycentric_tri_v3(data[i], u, v, coord[i]); } /* convert from local to world space */ mul_m4_v3(mat_low, coord[0]); mul_m4_v3(mat_cage, coord[1]); sub_v3_v3v3(dir, coord[0], coord[1]); normalize_v3(dir); copy_v3_v3(r_co, coord[1]); copy_v3_v3(r_dir, dir); }
/* mode = 0: interpolate normals, * mode = 1: interpolate coord */ static void interp_barycentric_mface(DerivedMesh *dm, MFace *mface, const float u, const float v, const int mode, float res[3]) { float data[3][3]; if (mode == 0) { dm->getVertNo(dm, mface->v1, data[0]); dm->getVertNo(dm, mface->v2, data[1]); dm->getVertNo(dm, mface->v3, data[2]); } else { dm->getVertCo(dm, mface->v1, data[0]); dm->getVertCo(dm, mface->v2, data[1]); dm->getVertCo(dm, mface->v3, data[2]); } interp_barycentric_tri_v3(data, u, v, res); }
/** * This function converts an object space normal map to a tangent space normal map for a given low poly mesh */ void RE_bake_normal_world_to_tangent( const BakePixel pixel_array[], const size_t num_pixels, const int depth, float result[], Mesh *me, const BakeNormalSwizzle normal_swizzle[3], float mat[4][4]) { size_t i; TriTessFace *triangles; DerivedMesh *dm = CDDM_from_mesh(me); triangles = MEM_mallocN(sizeof(TriTessFace) * (me->totface * 2), "MVerts Mesh"); mesh_calc_tri_tessface(triangles, me, true, dm); BLI_assert(num_pixels >= 3); for (i = 0; i < num_pixels; i++) { TriTessFace *triangle; float tangents[3][3]; float normals[3][3]; float signs[3]; int j; float tangent[3]; float normal[3]; float binormal[3]; float sign; float u, v, w; float tsm[3][3]; /* tangent space matrix */ float itsm[3][3]; size_t offset; float nor[3]; /* texture normal */ bool is_smooth; int primitive_id = pixel_array[i].primitive_id; offset = i * depth; if (primitive_id == -1) { copy_v3_fl3(&result[offset], 0.5f, 0.5f, 1.0f); continue; } triangle = &triangles[primitive_id]; is_smooth = triangle->is_smooth; for (j = 0; j < 3; j++) { const TSpace *ts; if (is_smooth) normal_short_to_float_v3(normals[j], triangle->mverts[j]->no); else normal[j] = triangle->normal[j]; ts = triangle->tspace[j]; copy_v3_v3(tangents[j], ts->tangent); signs[j] = ts->sign; } u = pixel_array[i].uv[0]; v = pixel_array[i].uv[1]; w = 1.0f - u - v; /* normal */ if (is_smooth) interp_barycentric_tri_v3(normals, u, v, normal); /* tangent */ interp_barycentric_tri_v3(tangents, u, v, tangent); /* sign */ /* The sign is the same at all face vertices for any non degenerate face. * Just in case we clamp the interpolated value though. */ sign = (signs[0] * u + signs[1] * v + signs[2] * w) < 0 ? (-1.0f) : 1.0f; /* binormal */ /* B = sign * cross(N, T) */ cross_v3_v3v3(binormal, normal, tangent); mul_v3_fl(binormal, sign); /* populate tangent space matrix */ copy_v3_v3(tsm[0], tangent); copy_v3_v3(tsm[1], binormal); copy_v3_v3(tsm[2], normal); /* texture values */ normal_uncompress(nor, &result[offset]); /* converts from world space to local space */ mul_transposed_mat3_m4_v3(mat, nor); invert_m3_m3(itsm, tsm); mul_m3_v3(itsm, nor); normalize_v3(nor); /* save back the values */ normal_compress(&result[offset], nor, normal_swizzle); } /* garbage collection */ MEM_freeN(triangles); if (dm) dm->release(dm); }