void get_texture_coords(MappingInfoModifierData *dmd, Object *ob, DerivedMesh *dm, float (*co)[3], float (*texco)[3], int numVerts) { int i; int texmapping = dmd->texmapping; float mapob_imat[4][4]; if (texmapping == MOD_DISP_MAP_OBJECT) { if (dmd->map_object) invert_m4_m4(mapob_imat, dmd->map_object->obmat); else /* if there is no map object, default to local */ texmapping = MOD_DISP_MAP_LOCAL; } /* UVs need special handling, since they come from faces */ if (texmapping == MOD_DISP_MAP_UV) { if (CustomData_has_layer(&dm->loopData, CD_MLOOPUV)) { MPoly *mpoly = dm->getPolyArray(dm); MPoly *mp; MLoop *mloop = dm->getLoopArray(dm); char *done = MEM_callocN(sizeof(*done) * numVerts, "get_texture_coords done"); int numPolys = dm->getNumPolys(dm); char uvname[MAX_CUSTOMDATA_LAYER_NAME]; MLoopUV *mloop_uv; CustomData_validate_layer_name(&dm->loopData, CD_MLOOPUV, dmd->uvlayer_name, uvname); mloop_uv = CustomData_get_layer_named(&dm->loopData, CD_MLOOPUV, uvname); /* verts are given the UV from the first face that uses them */ for (i = 0, mp = mpoly; i < numPolys; ++i, ++mp) { unsigned int fidx = mp->totloop - 1; do { unsigned int lidx = mp->loopstart + fidx; unsigned int vidx = mloop[lidx].v; if (done[vidx] == 0) { /* remap UVs from [0, 1] to [-1, 1] */ texco[vidx][0] = (mloop_uv[lidx].uv[0] * 2.0f) - 1.0f; texco[vidx][1] = (mloop_uv[lidx].uv[1] * 2.0f) - 1.0f; done[vidx] = 1; } } while (fidx--); } MEM_freeN(done); return; } else /* if there are no UVs, default to local */ texmapping = MOD_DISP_MAP_LOCAL; } for (i = 0; i < numVerts; ++i, ++co, ++texco) { switch (texmapping) { case MOD_DISP_MAP_LOCAL: copy_v3_v3(*texco, *co); break; case MOD_DISP_MAP_GLOBAL: mul_v3_m4v3(*texco, ob->obmat, *co); break; case MOD_DISP_MAP_OBJECT: mul_v3_m4v3(*texco, ob->obmat, *co); mul_m4_v3(mapob_imat, *texco); break; } } }
static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *dm, ModifierApplyFlag UNUSED(flag)) { UVWarpModifierData *umd = (UVWarpModifierData *) md; int i, numPolys, numLoops; MPoly *mpoly; MLoop *mloop; MLoopUV *mloopuv; MDeformVert *dvert; int defgrp_index; char uvname[MAX_CUSTOMDATA_LAYER_NAME]; float mat_src[4][4]; float mat_dst[4][4]; float imat_dst[4][4]; float warp_mat[4][4]; const int axis_u = umd->axis_u; const int axis_v = umd->axis_v; /* make sure there are UV Maps available */ if (!CustomData_has_layer(&dm->loopData, CD_MLOOPUV)) { return dm; } else if (ELEM(NULL, umd->object_src, umd->object_dst)) { modifier_setError(md, "From/To objects must be set"); return dm; } /* make sure anything moving UVs is available */ matrix_from_obj_pchan(mat_src, umd->object_src, umd->bone_src); matrix_from_obj_pchan(mat_dst, umd->object_dst, umd->bone_dst); invert_m4_m4(imat_dst, mat_dst); mul_m4_m4m4(warp_mat, imat_dst, mat_src); /* apply warp */ if (!is_zero_v2(umd->center)) { float mat_cent[4][4]; float imat_cent[4][4]; unit_m4(mat_cent); mat_cent[3][axis_u] = umd->center[0]; mat_cent[3][axis_v] = umd->center[1]; invert_m4_m4(imat_cent, mat_cent); mul_m4_m4m4(warp_mat, warp_mat, imat_cent); mul_m4_m4m4(warp_mat, mat_cent, warp_mat); } /* make sure we're using an existing layer */ CustomData_validate_layer_name(&dm->loopData, CD_MLOOPUV, umd->uvlayer_name, uvname); numPolys = dm->getNumPolys(dm); numLoops = dm->getNumLoops(dm); mpoly = dm->getPolyArray(dm); mloop = dm->getLoopArray(dm); /* make sure we are not modifying the original UV map */ mloopuv = CustomData_duplicate_referenced_layer_named(&dm->loopData, CD_MLOOPUV, uvname, numLoops); modifier_get_vgroup(ob, dm, umd->vgroup_name, &dvert, &defgrp_index); if (dvert) { #pragma omp parallel for if (numPolys > OMP_LIMIT) for (i = 0; i < numPolys; i++) { float uv[2]; MPoly *mp = &mpoly[i]; MLoop *ml = &mloop[mp->loopstart]; MLoopUV *mluv = &mloopuv[mp->loopstart]; int l; for (l = 0; l < mp->totloop; l++, ml++, mluv++) { const float weight = defvert_find_weight(&dvert[ml->v], defgrp_index); uv_warp_from_mat4_pair(uv, mluv->uv, warp_mat, axis_u, axis_v); interp_v2_v2v2(mluv->uv, mluv->uv, uv, weight); } } } else { #pragma omp parallel for if (numPolys > OMP_LIMIT) for (i = 0; i < numPolys; i++) { MPoly *mp = &mpoly[i]; // MLoop *ml = &mloop[mp->loopstart]; MLoopUV *mluv = &mloopuv[mp->loopstart]; int l; for (l = 0; l < mp->totloop; l++, /* ml++, */ mluv++) { uv_warp_from_mat4_pair(mluv->uv, mluv->uv, warp_mat, axis_u, axis_v); } } } dm->dirty |= DM_DIRTY_TESS_CDLAYERS; return dm; }
static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd, Object *ob, DerivedMesh *dm) { float (*coords)[3], (*co)[3]; MLoopUV *mloop_uv; MTexPoly *mtexpoly, *mt = NULL; int i, numVerts, numPolys, numLoops; Image *image = umd->image; MPoly *mpoly, *mp; MLoop *mloop; const bool override_image = (umd->flags & MOD_UVPROJECT_OVERRIDEIMAGE) != 0; Projector projectors[MOD_UVPROJECT_MAXPROJECTORS]; int num_projectors = 0; char uvname[MAX_CUSTOMDATA_LAYER_NAME]; float aspx = umd->aspectx ? umd->aspectx : 1.0f; float aspy = umd->aspecty ? umd->aspecty : 1.0f; float scax = umd->scalex ? umd->scalex : 1.0f; float scay = umd->scaley ? umd->scaley : 1.0f; int free_uci = 0; for (i = 0; i < umd->num_projectors; ++i) if (umd->projectors[i]) projectors[num_projectors++].ob = umd->projectors[i]; if (num_projectors == 0) return dm; /* make sure there are UV Maps available */ if (!CustomData_has_layer(&dm->loopData, CD_MLOOPUV)) return dm; /* make sure we're using an existing layer */ CustomData_validate_layer_name(&dm->loopData, CD_MLOOPUV, umd->uvlayer_name, uvname); /* calculate a projection matrix and normal for each projector */ for (i = 0; i < num_projectors; ++i) { float tmpmat[4][4]; float offsetmat[4][4]; Camera *cam = NULL; /* calculate projection matrix */ invert_m4_m4(projectors[i].projmat, projectors[i].ob->obmat); projectors[i].uci = NULL; if (projectors[i].ob->type == OB_CAMERA) { cam = (Camera *)projectors[i].ob->data; if (cam->type == CAM_PANO) { projectors[i].uci = BLI_uvproject_camera_info(projectors[i].ob, NULL, aspx, aspy); BLI_uvproject_camera_info_scale(projectors[i].uci, scax, scay); free_uci = 1; } else { CameraParams params; /* setup parameters */ BKE_camera_params_init(¶ms); BKE_camera_params_from_object(¶ms, projectors[i].ob); /* compute matrix, viewplane, .. */ BKE_camera_params_compute_viewplane(¶ms, 1, 1, aspx, aspy); /* scale the view-plane */ params.viewplane.xmin *= scax; params.viewplane.xmax *= scax; params.viewplane.ymin *= scay; params.viewplane.ymax *= scay; BKE_camera_params_compute_matrix(¶ms); mul_m4_m4m4(tmpmat, params.winmat, projectors[i].projmat); } } else { copy_m4_m4(tmpmat, projectors[i].projmat); } unit_m4(offsetmat); mul_mat3_m4_fl(offsetmat, 0.5); offsetmat[3][0] = offsetmat[3][1] = offsetmat[3][2] = 0.5; mul_m4_m4m4(projectors[i].projmat, offsetmat, tmpmat); /* calculate worldspace projector normal (for best projector test) */ projectors[i].normal[0] = 0; projectors[i].normal[1] = 0; projectors[i].normal[2] = 1; mul_mat3_m4_v3(projectors[i].ob->obmat, projectors[i].normal); } numPolys = dm->getNumPolys(dm); numLoops = dm->getNumLoops(dm); /* make sure we are not modifying the original UV map */ mloop_uv = CustomData_duplicate_referenced_layer_named(&dm->loopData, CD_MLOOPUV, uvname, numLoops); /* can be NULL */ mt = mtexpoly = CustomData_duplicate_referenced_layer_named(&dm->polyData, CD_MTEXPOLY, uvname, numPolys); numVerts = dm->getNumVerts(dm); coords = MEM_mallocN(sizeof(*coords) * numVerts, "uvprojectModifier_do coords"); dm->getVertCos(dm, coords); /* convert coords to world space */ for (i = 0, co = coords; i < numVerts; ++i, ++co) mul_m4_v3(ob->obmat, *co); /* if only one projector, project coords to UVs */ if (num_projectors == 1 && projectors[0].uci == NULL) for (i = 0, co = coords; i < numVerts; ++i, ++co) mul_project_m4_v3(projectors[0].projmat, *co); mpoly = dm->getPolyArray(dm); mloop = dm->getLoopArray(dm); /* apply coords as UVs, and apply image if tfaces are new */ for (i = 0, mp = mpoly; i < numPolys; ++i, ++mp, ++mt) { if (override_image || !image || (mtexpoly == NULL || mt->tpage == image)) { if (num_projectors == 1) { if (projectors[0].uci) { unsigned int fidx = mp->totloop - 1; do { unsigned int lidx = mp->loopstart + fidx; unsigned int vidx = mloop[lidx].v; BLI_uvproject_from_camera(mloop_uv[lidx].uv, coords[vidx], projectors[0].uci); } while (fidx--); } else { /* apply transformed coords as UVs */ unsigned int fidx = mp->totloop - 1; do { unsigned int lidx = mp->loopstart + fidx; unsigned int vidx = mloop[lidx].v; copy_v2_v2(mloop_uv[lidx].uv, coords[vidx]); } while (fidx--); } } else { /* multiple projectors, select the closest to face normal direction */ float face_no[3]; int j; Projector *best_projector; float best_dot; /* get the untransformed face normal */ BKE_mesh_calc_poly_normal_coords(mp, mloop + mp->loopstart, (const float (*)[3])coords, face_no); /* find the projector which the face points at most directly * (projector normal with largest dot product is best) */ best_dot = dot_v3v3(projectors[0].normal, face_no); best_projector = &projectors[0]; for (j = 1; j < num_projectors; ++j) { float tmp_dot = dot_v3v3(projectors[j].normal, face_no); if (tmp_dot > best_dot) { best_dot = tmp_dot; best_projector = &projectors[j]; } } if (best_projector->uci) { unsigned int fidx = mp->totloop - 1; do { unsigned int lidx = mp->loopstart + fidx; unsigned int vidx = mloop[lidx].v; BLI_uvproject_from_camera(mloop_uv[lidx].uv, coords[vidx], best_projector->uci); } while (fidx--); } else { unsigned int fidx = mp->totloop - 1; do { unsigned int lidx = mp->loopstart + fidx; unsigned int vidx = mloop[lidx].v; mul_v2_project_m4_v3(mloop_uv[lidx].uv, best_projector->projmat, coords[vidx]); } while (fidx--); } } } if (override_image && mtexpoly) { mt->tpage = image; } } MEM_freeN(coords); if (free_uci) { int j; for (j = 0; j < num_projectors; ++j) { if (projectors[j].uci) { MEM_freeN(projectors[j].uci); } } } /* Mark tessellated CD layers as dirty. */ dm->dirty |= DM_DIRTY_TESS_CDLAYERS; return dm; }
static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *dm, ModifierApplyFlag UNUSED(flag)) { UVWarpModifierData *umd = (UVWarpModifierData *) md; int numPolys, numLoops; MPoly *mpoly; MLoop *mloop; MLoopUV *mloopuv; MDeformVert *dvert; int defgrp_index; char uvname[MAX_CUSTOMDATA_LAYER_NAME]; float mat_src[4][4]; float mat_dst[4][4]; float imat_dst[4][4]; float warp_mat[4][4]; const int axis_u = umd->axis_u; const int axis_v = umd->axis_v; /* make sure there are UV Maps available */ if (!CustomData_has_layer(&dm->loopData, CD_MLOOPUV)) { return dm; } else if (ELEM(NULL, umd->object_src, umd->object_dst)) { modifier_setError(md, "From/To objects must be set"); return dm; } /* make sure anything moving UVs is available */ matrix_from_obj_pchan(mat_src, umd->object_src, umd->bone_src); matrix_from_obj_pchan(mat_dst, umd->object_dst, umd->bone_dst); invert_m4_m4(imat_dst, mat_dst); mul_m4_m4m4(warp_mat, imat_dst, mat_src); /* apply warp */ if (!is_zero_v2(umd->center)) { float mat_cent[4][4]; float imat_cent[4][4]; unit_m4(mat_cent); mat_cent[3][axis_u] = umd->center[0]; mat_cent[3][axis_v] = umd->center[1]; invert_m4_m4(imat_cent, mat_cent); mul_m4_m4m4(warp_mat, warp_mat, imat_cent); mul_m4_m4m4(warp_mat, mat_cent, warp_mat); } /* make sure we're using an existing layer */ CustomData_validate_layer_name(&dm->loopData, CD_MLOOPUV, umd->uvlayer_name, uvname); numPolys = dm->getNumPolys(dm); numLoops = dm->getNumLoops(dm); mpoly = dm->getPolyArray(dm); mloop = dm->getLoopArray(dm); /* make sure we are not modifying the original UV map */ mloopuv = CustomData_duplicate_referenced_layer_named(&dm->loopData, CD_MLOOPUV, uvname, numLoops); modifier_get_vgroup(ob, dm, umd->vgroup_name, &dvert, &defgrp_index); UVWarpData data = {.mpoly = mpoly, .mloop = mloop, .mloopuv = mloopuv, .dvert = dvert, .defgrp_index = defgrp_index, .warp_mat = warp_mat, .axis_u = axis_u, .axis_v = axis_v}; BLI_task_parallel_range(0, numPolys, &data, uv_warp_compute, numPolys > 1000); dm->dirty |= DM_DIRTY_TESS_CDLAYERS; return dm; }