static void multires_reshape_propagate_prepare(MultiresPropagateData *data, Mesh *coarse_mesh, const int reshape_level, const int top_level) { BLI_assert(reshape_level <= top_level); memset(data, 0, sizeof(*data)); data->num_grids = coarse_mesh->totloop; data->reshape_level = reshape_level; data->top_level = top_level; if (reshape_level == top_level) { /* Nothing to do, reshape will happen on the whole grid content. */ return; } data->mdisps = CustomData_get_layer(&coarse_mesh->ldata, CD_MDISPS); data->grid_paint_mask = CustomData_get_layer(&coarse_mesh->ldata, CD_GRID_PAINT_MASK); data->top_grid_size = BKE_subdiv_grid_size_from_level(top_level); data->reshape_grid_size = BKE_subdiv_grid_size_from_level(reshape_level); /* Initialize keys to access CCG at different levels. */ multires_reshape_init_level_key(&data->reshape_level_key, data, data->reshape_level); multires_reshape_init_level_key(&data->top_level_key, data, data->top_level); /* Make a copy of grids before reshaping, so we can calculate deltas * later on. */ multires_reshape_store_original_grids(data); }
static void data_transfer_dtdata_type_preprocess( Object *UNUSED(ob_src), Object *UNUSED(ob_dst), DerivedMesh *dm_src, DerivedMesh *dm_dst, Mesh *me_dst, const int dtdata_type, const bool dirty_nors_dst, const bool use_split_nors_src, const float split_angle_src) { if (dtdata_type == DT_TYPE_LNOR) { /* Compute custom normals into regular loop normals, which will be used for the transfer. */ MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert; const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert; MEdge *edges_dst = dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge; const int num_edges_dst = dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge; MPoly *polys_dst = dm_dst ? dm_dst->getPolyArray(dm_dst) : me_dst->mpoly; const int num_polys_dst = dm_dst ? dm_dst->getNumPolys(dm_dst) : me_dst->totpoly; MLoop *loops_dst = dm_dst ? dm_dst->getLoopArray(dm_dst) : me_dst->mloop; const int num_loops_dst = dm_dst ? dm_dst->getNumLoops(dm_dst) : me_dst->totloop; CustomData *pdata_dst = dm_dst ? dm_dst->getPolyDataLayout(dm_dst) : &me_dst->pdata; CustomData *ldata_dst = dm_dst ? dm_dst->getLoopDataLayout(dm_dst) : &me_dst->ldata; const bool use_split_nors_dst = (me_dst->flag & ME_AUTOSMOOTH) != 0; const float split_angle_dst = me_dst->smoothresh; dm_src->calcLoopNormals(dm_src, use_split_nors_src, split_angle_src); if (dm_dst) { dm_dst->calcLoopNormals(dm_dst, use_split_nors_dst, split_angle_dst); } else { float (*poly_nors_dst)[3]; float (*loop_nors_dst)[3]; short (*custom_nors_dst)[2] = CustomData_get_layer(ldata_dst, CD_CUSTOMLOOPNORMAL); /* Cache poly nors into a temp CDLayer. */ poly_nors_dst = CustomData_get_layer(pdata_dst, CD_NORMAL); if (dirty_nors_dst || !poly_nors_dst) { if (!poly_nors_dst) { poly_nors_dst = CustomData_add_layer(pdata_dst, CD_NORMAL, CD_CALLOC, NULL, num_polys_dst); CustomData_set_layer_flag(pdata_dst, CD_NORMAL, CD_FLAG_TEMPORARY); } BKE_mesh_calc_normals_poly(verts_dst, num_verts_dst, loops_dst, polys_dst, num_loops_dst, num_polys_dst, poly_nors_dst, true); } /* Cache loop nors into a temp CDLayer. */ loop_nors_dst = CustomData_get_layer(ldata_dst, CD_NORMAL); if (dirty_nors_dst || loop_nors_dst) { if (!loop_nors_dst) { loop_nors_dst = CustomData_add_layer(ldata_dst, CD_NORMAL, CD_CALLOC, NULL, num_loops_dst); CustomData_set_layer_flag(ldata_dst, CD_NORMAL, CD_FLAG_TEMPORARY); } BKE_mesh_normals_loop_split(verts_dst, num_verts_dst, edges_dst, num_edges_dst, loops_dst, loop_nors_dst, num_loops_dst, polys_dst, (const float (*)[3])poly_nors_dst, num_polys_dst, use_split_nors_dst, split_angle_dst, NULL, custom_nors_dst, NULL); } } } }
static void mesh_calc_edges(Mesh *mesh) { CustomData edata; EdgeHashIterator *ehi; MFace *mf = mesh->mface; MEdge *med; EdgeHash *eh = BLI_edgehash_new(); int i, *index, totedge, totface = mesh->totface; for (i = 0; i < totface; i++, mf++) { if (!BLI_edgehash_haskey(eh, mf->v1, mf->v2)) BLI_edgehash_insert(eh, mf->v1, mf->v2, NULL); if (!BLI_edgehash_haskey(eh, mf->v2, mf->v3)) BLI_edgehash_insert(eh, mf->v2, mf->v3, NULL); if (mf->v4) { if (!BLI_edgehash_haskey(eh, mf->v3, mf->v4)) BLI_edgehash_insert(eh, mf->v3, mf->v4, NULL); if (!BLI_edgehash_haskey(eh, mf->v4, mf->v1)) BLI_edgehash_insert(eh, mf->v4, mf->v1, NULL); } else { if (!BLI_edgehash_haskey(eh, mf->v3, mf->v1)) BLI_edgehash_insert(eh, mf->v3, mf->v1, NULL); } } totedge = BLI_edgehash_size(eh); /* write new edges into a temporary CustomData */ memset(&edata, 0, sizeof(edata)); CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, NULL, totedge); ehi = BLI_edgehashIterator_new(eh); med = CustomData_get_layer(&edata, CD_MEDGE); for(i = 0; !BLI_edgehashIterator_isDone(ehi); BLI_edgehashIterator_step(ehi), ++i, ++med, ++index) { BLI_edgehashIterator_getKey(ehi, (int*)&med->v1, (int*)&med->v2); med->flag = ME_EDGEDRAW|ME_EDGERENDER; } BLI_edgehashIterator_free(ehi); /* free old CustomData and assign new one */ CustomData_free(&mesh->edata, mesh->totedge); mesh->edata = edata; mesh->totedge = totedge; mesh->medge = CustomData_get_layer(&mesh->edata, CD_MEDGE); BLI_edgehash_free(eh, NULL); }
static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *dm, ModifierApplyFlag flag) { MultiresModifierData *mmd = (MultiresModifierData *)md; DerivedMesh *result; Mesh *me = (Mesh *)ob->data; const int useRenderParams = flag & MOD_APPLY_RENDER; if (mmd->totlvl) { if (!CustomData_get_layer(&me->ldata, CD_MDISPS)) { /* multires always needs a displacement layer */ CustomData_add_layer(&me->ldata, CD_MDISPS, CD_CALLOC, NULL, me->totloop); } } result = multires_dm_create_from_derived(mmd, 0, dm, ob, useRenderParams); if (result == dm) return dm; if(useRenderParams || !(flag & MOD_APPLY_USECACHE)) { DerivedMesh *cddm; cddm = CDDM_copy(result); /* copy hidden flag to vertices */ if (!useRenderParams) { struct MDisps *mdisps; mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS); if (mdisps) { subsurf_copy_grid_hidden(result, me->mpoly, cddm->getVertArray(cddm), mdisps); BKE_mesh_flush_hidden_from_verts(cddm->getVertArray(cddm), cddm->getLoopArray(cddm), cddm->getEdgeArray(cddm), cddm->getNumEdges(cddm), cddm->getPolyArray(cddm), cddm->getNumPolys(cddm)); } } result->release(result); result = cddm; } return result; }
static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *dm, int useRenderParams, int isFinalCalc) { SculptSession *ss= ob->sculpt; int sculpting= (ob->mode & OB_MODE_SCULPT) && ss; MultiresModifierData *mmd = (MultiresModifierData*)md; DerivedMesh *result; Mesh *me= (Mesh*)ob->data; if(mmd->totlvl) { if(!CustomData_get_layer(&me->fdata, CD_MDISPS)) { /* multires always needs a displacement layer */ CustomData_add_layer(&me->fdata, CD_MDISPS, CD_CALLOC, NULL, me->totface); } } result = multires_dm_create_from_derived(mmd, 0, dm, ob, useRenderParams, isFinalCalc); if(result == dm) return dm; if(useRenderParams || !isFinalCalc) { DerivedMesh *cddm= CDDM_copy(result); result->release(result); result= cddm; } else if(sculpting) { /* would be created on the fly too, just nicer this way on first stroke after e.g. switching levels */ ss->pbvh= result->getPBVH(ob, result); } return result; }
static void count_images(MultiresBakeRender *bkr) { int a, totface; DerivedMesh *dm = bkr->lores_dm; MTFace *mtface = CustomData_get_layer(&dm->faceData, CD_MTFACE); bkr->image.first = bkr->image.last = NULL; bkr->tot_image = 0; totface = dm->getNumTessFaces(dm); for (a = 0; a < totface; a++) mtface[a].tpage->id.flag &= ~LIB_DOIT; for (a = 0; a < totface; a++) { Image *ima = mtface[a].tpage; if ((ima->id.flag & LIB_DOIT) == 0) { LinkData *data = BLI_genericNodeN(ima); BLI_addtail(&bkr->image, data); bkr->tot_image++; ima->id.flag |= LIB_DOIT; } } for (a = 0; a < totface; a++) mtface[a].tpage->id.flag &= ~LIB_DOIT; }
static void mask_init_data(SubdivCCGMaskEvaluator *mask_evaluator, const Mesh *mesh) { GridPaintMaskData *data = mask_evaluator->user_data; data->mpoly = mesh->mpoly; data->grid_paint_mask = CustomData_get_layer(&mesh->ldata, CD_GRID_PAINT_MASK); mask_data_init_mapping(mask_evaluator, mesh); }
/* Check poly normals and new loop normals are compatible, otherwise flip polygons * (and invert matching poly normals). */ static bool polygons_check_flip( MLoop *mloop, float (*nos)[3], CustomData *ldata, MPoly *mpoly, float (*polynors)[3], const int num_polys) { MPoly *mp; MDisps *mdisp = CustomData_get_layer(ldata, CD_MDISPS); int i; bool flipped = false; for (i = 0, mp = mpoly; i < num_polys; i++, mp++) { float norsum[3] = {0.0f}; float (*no)[3]; int j; for (j = 0, no = &nos[mp->loopstart]; j < mp->totloop; j++, no++) { add_v3_v3(norsum, *no); } if (!normalize_v3(norsum)) { continue; } /* If average of new loop normals is opposed to polygon normal, flip polygon. */ if (dot_v3v3(polynors[i], norsum) < 0.0f) { BKE_mesh_polygon_flip_ex(mp, mloop, ldata, nos, mdisp, true); negate_v3(polynors[i]); flipped = true; } } return flipped; }
static DerivedMesh *generate_ocean_geometry(OceanModifierData *omd) { DerivedMesh *result; GenerateOceanGeometryData gogd; int num_verts; int num_polys; const bool use_threading = omd->resolution > 4; gogd.rx = omd->resolution * omd->resolution; gogd.ry = omd->resolution * omd->resolution; gogd.res_x = gogd.rx * omd->repeat_x; gogd.res_y = gogd.ry * omd->repeat_y; num_verts = (gogd.res_x + 1) * (gogd.res_y + 1); num_polys = gogd.res_x * gogd.res_y; gogd.sx = omd->size * omd->spatial_size; gogd.sy = omd->size * omd->spatial_size; gogd.ox = -gogd.sx / 2.0f; gogd.oy = -gogd.sy / 2.0f; gogd.sx /= gogd.rx; gogd.sy /= gogd.ry; result = CDDM_new(num_verts, 0, 0, num_polys * 4, num_polys); gogd.mverts = CDDM_get_verts(result); gogd.mpolys = CDDM_get_polys(result); gogd.mloops = CDDM_get_loops(result); gogd.origindex = CustomData_get_layer(&result->polyData, CD_ORIGINDEX); /* create vertices */ BLI_task_parallel_range(0, gogd.res_y + 1, &gogd, generate_ocean_geometry_vertices, use_threading); /* create faces */ BLI_task_parallel_range(0, gogd.res_y, &gogd, generate_ocean_geometry_polygons, use_threading); CDDM_calc_edges(result); /* add uvs */ if (CustomData_number_of_layers(&result->loopData, CD_MLOOPUV) < MAX_MTFACE) { gogd.mloopuvs = CustomData_add_layer(&result->loopData, CD_MLOOPUV, CD_CALLOC, NULL, num_polys * 4); CustomData_add_layer(&result->polyData, CD_MTEXPOLY, CD_CALLOC, NULL, num_polys); if (gogd.mloopuvs) { /* unlikely to fail */ gogd.ix = 1.0 / gogd.rx; gogd.iy = 1.0 / gogd.ry; BLI_task_parallel_range(0, gogd.res_y, &gogd, generate_ocean_geometry_uvs, use_threading); } } result->dirty |= DM_DIRTY_NORMALS; return result; }
static void multires_reshape_ensure_displacement_grids(Mesh *mesh, const int grid_level) { const int num_grids = mesh->totloop; MDisps *mdisps = CustomData_get_layer(&mesh->ldata, CD_MDISPS); for (int grid_index = 0; grid_index < num_grids; grid_index++) { multires_reshape_ensure_displacement_grid(&mdisps[grid_index], grid_level); } }
void GeometryExporter::create_normals(std::vector<Normal> &normals, std::vector<BCPolygonNormalsIndices> &polygons_normals, Mesh *me) { std::map<Normal, unsigned int> shared_normal_indices; int last_normal_index = -1; MVert *verts = me->mvert; MLoop *mloops = me->mloop; float(*lnors)[3]; BKE_mesh_calc_normals_split(me); if (CustomData_has_layer(&me->ldata, CD_NORMAL)) { lnors = (float(*)[3])CustomData_get_layer(&me->ldata, CD_NORMAL); } for (int poly_index = 0; poly_index < me->totpoly; poly_index++) { MPoly *mpoly = &me->mpoly[poly_index]; if (!(mpoly->flag & ME_SMOOTH)) { // For flat faces use face normal as vertex normal: float vector[3]; BKE_mesh_calc_poly_normal(mpoly, mloops+mpoly->loopstart, verts, vector); Normal n = { vector[0], vector[1], vector[2] }; normals.push_back(n); last_normal_index++; } MLoop *mloop = mloops + mpoly->loopstart; BCPolygonNormalsIndices poly_indices; for (int loop_index = 0; loop_index < mpoly->totloop; loop_index++) { unsigned int loop_idx = mpoly->loopstart + loop_index; if (mpoly->flag & ME_SMOOTH) { float normalized[3]; normalize_v3_v3(normalized, lnors[loop_idx]); Normal n = { normalized[0], normalized[1], normalized[2] }; if (shared_normal_indices.find(n) != shared_normal_indices.end()) { poly_indices.add_index(shared_normal_indices[n]); } else { last_normal_index++; poly_indices.add_index(last_normal_index); shared_normal_indices[n] = last_normal_index; normals.push_back(n); } } else { poly_indices.add_index(last_normal_index); } } polygons_normals.push_back(poly_indices); } }
static void rna_Mesh_normals_split_custom_do(Mesh *mesh, float (*custom_loopnors)[3], const bool use_vertices) { float (*polynors)[3]; short (*clnors)[2]; const int numloops = mesh->totloop; bool free_polynors = false; clnors = CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL); if (clnors) { memset(clnors, 0, sizeof(*clnors) * numloops); } else { clnors = CustomData_add_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL, CD_DEFAULT, NULL, numloops); } if (CustomData_has_layer(&mesh->pdata, CD_NORMAL)) { polynors = CustomData_get_layer(&mesh->pdata, CD_NORMAL); } else { polynors = MEM_mallocN(sizeof(float[3]) * mesh->totpoly, __func__); BKE_mesh_calc_normals_poly( mesh->mvert, NULL, mesh->totvert, mesh->mloop, mesh->mpoly, mesh->totloop, mesh->totpoly, polynors, false); free_polynors = true; } if (use_vertices) { BKE_mesh_normals_loop_custom_from_vertices_set( mesh->mvert, custom_loopnors, mesh->totvert, mesh->medge, mesh->totedge, mesh->mloop, mesh->totloop, mesh->mpoly, (const float (*)[3])polynors, mesh->totpoly, clnors); } else { BKE_mesh_normals_loop_custom_set( mesh->mvert, mesh->totvert, mesh->medge, mesh->totedge, mesh->mloop, custom_loopnors, mesh->totloop, mesh->mpoly, (const float (*)[3])polynors, mesh->totpoly, clnors); } if (free_polynors) { MEM_freeN(polynors); } }
bool BKE_subdiv_ccg_mask_init_from_paint(SubdivCCGMaskEvaluator *mask_evaluator, const struct Mesh *mesh) { GridPaintMask *grid_paint_mask = CustomData_get_layer(&mesh->ldata, CD_GRID_PAINT_MASK); if (grid_paint_mask == NULL) { return false; } /* Allocate all required memory. */ mask_evaluator->user_data = MEM_callocN(sizeof(GridPaintMaskData), "mask from grid data"); mask_init_data(mask_evaluator, mesh); mask_init_functions(mask_evaluator); return true; }
static void data_transfer_dtdata_type_postprocess( Object *UNUSED(ob_src), Object *UNUSED(ob_dst), DerivedMesh *UNUSED(dm_src), DerivedMesh *dm_dst, Mesh *me_dst, const int dtdata_type, const bool changed) { if (dtdata_type == DT_TYPE_LNOR) { /* Bake edited destination loop normals into custom normals again. */ MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert; const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert; MEdge *edges_dst = dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge; const int num_edges_dst = dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge; MPoly *polys_dst = dm_dst ? dm_dst->getPolyArray(dm_dst) : me_dst->mpoly; const int num_polys_dst = dm_dst ? dm_dst->getNumPolys(dm_dst) : me_dst->totpoly; MLoop *loops_dst = dm_dst ? dm_dst->getLoopArray(dm_dst) : me_dst->mloop; const int num_loops_dst = dm_dst ? dm_dst->getNumLoops(dm_dst) : me_dst->totloop; CustomData *pdata_dst = dm_dst ? dm_dst->getPolyDataLayout(dm_dst) : &me_dst->pdata; CustomData *ldata_dst = dm_dst ? dm_dst->getLoopDataLayout(dm_dst) : &me_dst->ldata; const float (*poly_nors_dst)[3] = CustomData_get_layer(pdata_dst, CD_NORMAL); float (*loop_nors_dst)[3] = CustomData_get_layer(ldata_dst, CD_NORMAL); short (*custom_nors_dst)[2] = CustomData_get_layer(ldata_dst, CD_CUSTOMLOOPNORMAL); BLI_assert(poly_nors_dst); if (!changed) { return; } if (!custom_nors_dst) { custom_nors_dst = CustomData_add_layer(ldata_dst, CD_CUSTOMLOOPNORMAL, CD_CALLOC, NULL, num_loops_dst); } /* Note loop_nors_dst contains our custom normals as transferred from source... */ BKE_mesh_normals_loop_custom_set(verts_dst, num_verts_dst, edges_dst, num_edges_dst, loops_dst, loop_nors_dst, num_loops_dst, polys_dst, poly_nors_dst, num_polys_dst, custom_nors_dst); } }
void mesh_update_customdata_pointers(Mesh *me) { me->mvert = CustomData_get_layer(&me->vdata, CD_MVERT); me->dvert = CustomData_get_layer(&me->vdata, CD_MDEFORMVERT); me->msticky = CustomData_get_layer(&me->vdata, CD_MSTICKY); me->medge = CustomData_get_layer(&me->edata, CD_MEDGE); me->mface = CustomData_get_layer(&me->fdata, CD_MFACE); me->mcol = CustomData_get_layer(&me->fdata, CD_MCOL); me->mtface = CustomData_get_layer(&me->fdata, CD_MTFACE); }
/* MultiresBake callback for normals' baking general idea: - find coord and normal of point with specified UV in hi-res mesh - multiply it by tangmat - vector in color space would be norm(vec) /2 + (0.5, 0.5, 0.5) */ static void apply_tangmat_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm, const void *UNUSED(bake_data), const int face_index, const int lvl, const float st[2], float tangmat[3][3], const int x, const int y) { MTFace *mtface= CustomData_get_layer(&lores_dm->faceData, CD_MTFACE); MFace mface; Image *ima= mtface[face_index].tpage; ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL); float uv[2], *st0, *st1, *st2, *st3; int pixel= ibuf->x*y + x; float n[3], vec[3], tmp[3]= {0.5, 0.5, 0.5}; lores_dm->getFace(lores_dm, face_index, &mface); st0= mtface[face_index].uv[0]; st1= mtface[face_index].uv[1]; st2= mtface[face_index].uv[2]; if(mface.v4) { st3= mtface[face_index].uv[3]; resolve_quad_uv(uv, st, st0, st1, st2, st3); } else resolve_tri_uv(uv, st, st0, st1, st2); CLAMP(uv[0], 0.0f, 1.0f); CLAMP(uv[1], 0.0f, 1.0f); get_ccgdm_data(lores_dm, hires_dm, lvl, face_index, uv[0], uv[1], NULL, n); mul_v3_m3v3(vec, tangmat, n); normalize_v3(vec); mul_v3_fl(vec, 0.5); add_v3_v3(vec, tmp); if(ibuf->rect_float) { float *rrgbf= ibuf->rect_float + pixel*4; rrgbf[0]= vec[0]; rrgbf[1]= vec[1]; rrgbf[2]= vec[2]; rrgbf[3]= 1.0f; ibuf->userflags= IB_RECT_INVALID; } else { char *rrgb= (char*)ibuf->rect + pixel*4; rrgb[0]= FTOCHAR(vec[0]); rrgb[1]= FTOCHAR(vec[1]); rrgb[2]= FTOCHAR(vec[2]); rrgb[3]= 255; } }
/* MultiresBake callback for normals' baking * general idea: * - find coord and normal of point with specified UV in hi-res mesh * - multiply it by tangmat * - vector in color space would be norm(vec) /2 + (0.5, 0.5, 0.5) */ static void apply_tangmat_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm, const void *bake_data, ImBuf *ibuf, const int face_index, const int lvl, const float st[2], float tangmat[3][3], const int x, const int y) { MTFace *mtface = CustomData_get_layer(&lores_dm->faceData, CD_MTFACE); MFace mface; MNormalBakeData *normal_data = (MNormalBakeData *)bake_data; float uv[2], *st0, *st1, *st2, *st3; int pixel = ibuf->x * y + x; float n[3], vec[3], tmp[3] = {0.5, 0.5, 0.5}; lores_dm->getTessFace(lores_dm, face_index, &mface); st0 = mtface[face_index].uv[0]; st1 = mtface[face_index].uv[1]; st2 = mtface[face_index].uv[2]; if (mface.v4) { st3 = mtface[face_index].uv[3]; resolve_quad_uv(uv, st, st0, st1, st2, st3); } else resolve_tri_uv(uv, st, st0, st1, st2); CLAMP(uv[0], 0.0f, 1.0f); CLAMP(uv[1], 0.0f, 1.0f); get_ccgdm_data(lores_dm, hires_dm, normal_data->orig_index_mf_to_mpoly, normal_data->orig_index_mp_to_orig, lvl, face_index, uv[0], uv[1], NULL, n); mul_v3_m3v3(vec, tangmat, n); normalize_v3(vec); mul_v3_fl(vec, 0.5); add_v3_v3(vec, tmp); if (ibuf->rect_float) { float *rrgbf = ibuf->rect_float + pixel * 4; rrgbf[0] = vec[0]; rrgbf[1] = vec[1]; rrgbf[2] = vec[2]; rrgbf[3] = 1.0f; } else { unsigned char *rrgb = (unsigned char *)ibuf->rect + pixel * 4; rgb_float_to_uchar(rrgb, vec); rrgb[3] = 255; } }
/* copy the face flags, most importantly selection from the mesh to the final derived mesh, * use in object mode when selecting faces (while painting) */ void paintface_flush_flags(Object *ob, short flag) { Mesh *me = BKE_mesh_from_object(ob); DerivedMesh *dm = ob->derivedFinal; MPoly *polys, *mp_orig; const int *index_array = NULL; int totpoly; int i; BLI_assert((flag & ~(SELECT | ME_HIDE)) == 0); if (me == NULL) return; /* note, call #BKE_mesh_flush_hidden_from_verts_ex first when changing hidden flags */ /* we could call this directly in all areas that change selection, * since this could become slow for realtime updates (circle-select for eg) */ if (flag & SELECT) { BKE_mesh_flush_select_from_polys(me); } if (dm == NULL) return; /* Mesh polys => Final derived polys */ if ((index_array = CustomData_get_layer(&dm->polyData, CD_ORIGINDEX))) { polys = dm->getPolyArray(dm); totpoly = dm->getNumPolys(dm); /* loop over final derived polys */ for (i = 0; i < totpoly; i++) { if (index_array[i] != ORIGINDEX_NONE) { /* Copy flags onto the final derived poly from the original mesh poly */ mp_orig = me->mpoly + index_array[i]; polys[i].flag = mp_orig->flag; } } } if (flag & ME_HIDE) { /* draw-object caches hidden faces, force re-generation T46867 */ GPU_drawobject_free(dm); } }
/* (similar to void paintface_flush_flags(Object *ob)) * copy the vertex flags, most importantly selection from the mesh to the final derived mesh, * use in object mode when selecting vertices (while painting) */ void paintvert_flush_flags(Object *ob) { Mesh *me = BKE_mesh_from_object(ob); Mesh *me_eval = ob->runtime.mesh_eval; MVert *mvert_eval, *mv; const int *index_array = NULL; int totvert; int i; if (me == NULL) { return; } /* we could call this directly in all areas that change selection, * since this could become slow for realtime updates (circle-select for eg) */ BKE_mesh_flush_select_from_verts(me); if (me_eval == NULL) { return; } index_array = CustomData_get_layer(&me_eval->vdata, CD_ORIGINDEX); mvert_eval = me_eval->mvert; totvert = me_eval->totvert; mv = mvert_eval; if (index_array) { int orig_index; for (i = 0; i < totvert; i++, mv++) { orig_index = index_array[i]; if (orig_index != ORIGINDEX_NONE) { mv->flag = me->mvert[index_array[i]].flag; } } } else { for (i = 0; i < totvert; i++, mv++) { mv->flag = me->mvert[i].flag; } } BKE_mesh_batch_cache_dirty_tag(me, BKE_MESH_BATCH_DIRTY_ALL); }
static void partialvis_update_mesh(Object *ob, PBVH *pbvh, PBVHNode *node, PartialVisAction action, PartialVisArea area, float planes[4][4]) { Mesh *me = ob->data; MVert *mvert; float *paint_mask; int *vert_indices; int totvert, i; bool any_changed = false, any_visible = false; BKE_pbvh_node_num_verts(pbvh, node, NULL, &totvert); BKE_pbvh_node_get_verts(pbvh, node, &vert_indices, &mvert); paint_mask = CustomData_get_layer(&me->vdata, CD_PAINT_MASK); sculpt_undo_push_node(ob, node, SCULPT_UNDO_HIDDEN); for (i = 0; i < totvert; i++) { MVert *v = &mvert[vert_indices[i]]; float vmask = paint_mask ? paint_mask[vert_indices[i]] : 0; /* hide vertex if in the hide volume */ if (is_effected(area, planes, v->co, vmask)) { if (action == PARTIALVIS_HIDE) v->flag |= ME_HIDE; else v->flag &= ~ME_HIDE; any_changed = true; } if (!(v->flag & ME_HIDE)) any_visible = true; } if (any_changed) { BKE_pbvh_node_mark_rebuild_draw(node); BKE_pbvh_node_fully_hidden_set(node, !any_visible); } }
static void rna_Mesh_calc_tangents(Mesh *mesh, ReportList *reports, const char *uvmap) { float (*r_looptangents)[4]; if (CustomData_has_layer(&mesh->ldata, CD_MLOOPTANGENT)) { r_looptangents = CustomData_get_layer(&mesh->ldata, CD_MLOOPTANGENT); memset(r_looptangents, 0, sizeof(float[4]) * mesh->totloop); } else { r_looptangents = CustomData_add_layer(&mesh->ldata, CD_MLOOPTANGENT, CD_CALLOC, NULL, mesh->totloop); CustomData_set_layer_flag(&mesh->ldata, CD_MLOOPTANGENT, CD_FLAG_TEMPORARY); } /* Compute loop normals if needed. */ if (!CustomData_has_layer(&mesh->ldata, CD_NORMAL)) { BKE_mesh_calc_normals_split(mesh); } BKE_mesh_loop_tangents(mesh, uvmap, r_looptangents, reports); }
static void multires_reshape_ensure_mask_grids(Mesh *mesh, const int grid_level) { GridPaintMask *grid_paint_masks = CustomData_get_layer(&mesh->ldata, CD_GRID_PAINT_MASK); if (grid_paint_masks == NULL) { return; } const int num_grids = mesh->totloop; const int grid_size = BKE_subdiv_grid_size_from_level(grid_level); const int grid_area = grid_size * grid_size; for (int grid_index = 0; grid_index < num_grids; grid_index++) { GridPaintMask *grid_paint_mask = &grid_paint_masks[grid_index]; if (grid_paint_mask->level == grid_level) { continue; } grid_paint_mask->level = grid_level; if (grid_paint_mask->data) { MEM_freeN(grid_paint_mask->data); } grid_paint_mask->data = MEM_calloc_arrayN(grid_area, sizeof(float), "gpm.data"); } }
static bool multires_reshape_from_vertcos(struct Depsgraph *depsgraph, Object *object, const MultiresModifierData *mmd, const float (*deformed_verts)[3], const int num_deformed_verts, const bool use_render_params) { Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); Mesh *coarse_mesh = object->data; MDisps *mdisps = CustomData_get_layer(&coarse_mesh->ldata, CD_MDISPS); /* Pick maximum between multires level and dispalcement level. * This is because mesh can be used by objects with multires at different * levels. * * TODO(sergey): At this point it should be possible to always use * mdisps->level. */ const int top_level = max_ii(mmd->totlvl, mdisps->level); /* Make sure displacement grids are ready. */ multires_reshape_ensure_grids(coarse_mesh, top_level); /* Initialize subdivision surface. */ Subdiv *subdiv = multires_create_subdiv_for_reshape(depsgraph, object, mmd); if (subdiv == NULL) { return false; } /* Construct context. */ MultiresReshapeFromDeformedVertsContext reshape_deformed_verts_ctx = { .reshape_ctx = { .subdiv = subdiv, .coarse_mesh = coarse_mesh, .mdisps = mdisps, .grid_paint_mask = NULL, .top_grid_size = BKE_subdiv_grid_size_from_level(top_level), .top_level = top_level, .face_ptex_offset = BKE_subdiv_face_ptex_offset_get(subdiv), }, .deformed_verts = deformed_verts, .num_deformed_verts = num_deformed_verts, };
void RE_bake_pixels_populate( Mesh *me, BakePixel pixel_array[], const size_t num_pixels, const BakeImages *bake_images, const char *uv_layer) { BakeDataZSpan bd; size_t i; int a, p_id; MTFace *mtface; MFace *mface; /* we can't bake in edit mode */ if (me->edit_btmesh) return; bd.pixel_array = pixel_array; bd.zspan = MEM_callocN(sizeof(ZSpan) * bake_images->size, "bake zspan"); /* initialize all pixel arrays so we know which ones are 'blank' */ for (i = 0; i < num_pixels; i++) { pixel_array[i].primitive_id = -1; } for (i = 0; i < bake_images->size; i++) { zbuf_alloc_span(&bd.zspan[i], bake_images->data[i].width, bake_images->data[i].height, R.clipcrop); } if ((uv_layer == NULL) || (uv_layer[0] == '\0')) { mtface = CustomData_get_layer(&me->fdata, CD_MTFACE); } else { int uv_id = CustomData_get_named_layer(&me->fdata, CD_MTFACE, uv_layer); mtface = CustomData_get_layer_n(&me->fdata, CD_MTFACE, uv_id); } mface = CustomData_get_layer(&me->fdata, CD_MFACE); if (mtface == NULL) return; p_id = -1; for (i = 0; i < me->totface; i++) { float vec[4][2]; MTFace *mtf = &mtface[i]; MFace *mf = &mface[i]; int mat_nr = mf->mat_nr; int image_id = bake_images->lookup[mat_nr]; bd.bk_image = &bake_images->data[image_id]; bd.primitive_id = ++p_id; for (a = 0; a < 4; a++) { /* Note, workaround for pixel aligned UVs which are common and can screw up our intersection tests * where a pixel gets in between 2 faces or the middle of a quad, * camera aligned quads also have this problem but they are less common. * Add a small offset to the UVs, fixes bug #18685 - Campbell */ vec[a][0] = mtf->uv[a][0] * (float)bd.bk_image->width - (0.5f + 0.001f); vec[a][1] = mtf->uv[a][1] * (float)bd.bk_image->height - (0.5f + 0.002f); } bake_differentials(&bd, vec[0], vec[1], vec[2]); zspan_scanconvert(&bd.zspan[image_id], (void *)&bd, vec[0], vec[1], vec[2], store_bake_pixel); /* 4 vertices in the face */ if (mf->v4 != 0) { bd.primitive_id = ++p_id; bake_differentials(&bd, vec[0], vec[2], vec[3]); zspan_scanconvert(&bd.zspan[image_id], (void *)&bd, vec[0], vec[2], vec[3], store_bake_pixel); } } for (i = 0; i < bake_images->size; i++) { zbuf_free_span(&bd.zspan[i]); } MEM_freeN(bd.zspan); }
/** * This function populates an array of verts for the triangles of a mesh * Tangent and Normals are also stored */ static void mesh_calc_tri_tessface( TriTessFace *triangles, Mesh *me, bool tangent, DerivedMesh *dm) { int i; MVert *mvert; TSpace *tspace; float *precomputed_normals = NULL; bool calculate_normal; const int tottri = poly_to_tri_count(me->totpoly, me->totloop); MLoopTri *looptri; /* calculate normal for each polygon only once */ unsigned int mpoly_prev = UINT_MAX; float no[3]; mvert = CustomData_get_layer(&me->vdata, CD_MVERT); looptri = MEM_mallocN(sizeof(*looptri) * tottri, __func__); if (tangent) { DM_ensure_normals(dm); DM_calc_loop_tangents(dm); precomputed_normals = dm->getPolyDataArray(dm, CD_NORMAL); calculate_normal = precomputed_normals ? false : true; tspace = dm->getLoopDataArray(dm, CD_TANGENT); BLI_assert(tspace); } BKE_mesh_recalc_looptri( me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, looptri); for (i = 0; i < tottri; i++) { MLoopTri *lt = &looptri[i]; MPoly *mp = &me->mpoly[lt->poly]; triangles[i].mverts[0] = &mvert[me->mloop[lt->tri[0]].v]; triangles[i].mverts[1] = &mvert[me->mloop[lt->tri[1]].v]; triangles[i].mverts[2] = &mvert[me->mloop[lt->tri[2]].v]; triangles[i].is_smooth = (mp->flag & ME_SMOOTH) != 0; if (tangent) { triangles[i].tspace[0] = &tspace[lt->tri[0]]; triangles[i].tspace[1] = &tspace[lt->tri[1]]; triangles[i].tspace[2] = &tspace[lt->tri[2]]; if (calculate_normal) { if (lt->poly != mpoly_prev) { const MPoly *mp = &me->mpoly[lt->poly]; BKE_mesh_calc_poly_normal(mp, &me->mloop[mp->loopstart], me->mvert, no); mpoly_prev = lt->poly; } copy_v3_v3(triangles[i].normal, no); } else { copy_v3_v3(triangles[i].normal, &precomputed_normals[lt->poly]); } } } MEM_freeN(looptri); }
bool data_transfer_layersmapping_vgroups( ListBase *r_map, const int mix_mode, const float mix_factor, const float *mix_weights, const int num_elem_dst, const bool use_create, const bool use_delete, Object *ob_src, Object *ob_dst, CustomData *cd_src, CustomData *cd_dst, const bool use_dupref_dst, const int fromlayers, const int tolayers) { int idx_src, idx_dst; MDeformVert *data_src, *data_dst = NULL; const size_t elem_size = sizeof(*((MDeformVert *)NULL)); /* Note: VGroups are a bit hairy, since their layout is defined on object level (ob->defbase), while their actual * data is a (mesh) CD layer. * This implies we may have to handle data layout itself while having NULL data itself, * and even have to support NULL data_src in transfer data code (we always create a data_dst, though). */ if (BLI_listbase_is_empty(&ob_src->defbase)) { if (use_delete) { BKE_object_defgroup_remove_all(ob_dst); } return true; } data_src = CustomData_get_layer(cd_src, CD_MDEFORMVERT); data_dst = CustomData_get_layer(cd_dst, CD_MDEFORMVERT); if (data_dst && use_dupref_dst && r_map) { /* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */ data_dst = CustomData_duplicate_referenced_layer(cd_dst, CD_MDEFORMVERT, num_elem_dst); } if (fromlayers == DT_LAYERS_ACTIVE_SRC || fromlayers >= 0) { /* Note: use_delete has not much meaning in this case, ignored. */ if (fromlayers >= 0) { idx_src = fromlayers; BLI_assert(idx_src < BLI_listbase_count(&ob_src->defbase)); } else if ((idx_src = ob_src->actdef - 1) == -1) { return false; } if (tolayers >= 0) { /* Note: in this case we assume layer exists! */ idx_dst = tolayers; BLI_assert(idx_dst < BLI_listbase_count(&ob_dst->defbase)); } else if (tolayers == DT_LAYERS_ACTIVE_DST) { if ((idx_dst = ob_dst->actdef - 1) == -1) { bDeformGroup *dg_src; if (!use_create) { return true; } dg_src = BLI_findlink(&ob_src->defbase, idx_src); BKE_object_defgroup_add_name(ob_dst, dg_src->name); idx_dst = ob_dst->actdef - 1; } } else if (tolayers == DT_LAYERS_INDEX_DST) { int num = BLI_listbase_count(&ob_src->defbase); idx_dst = idx_src; if (num <= idx_dst) { if (!use_create) { return true; } /* Create as much vgroups as necessary! */ for (; num <= idx_dst; num++) { BKE_object_defgroup_add(ob_dst); } } } else if (tolayers == DT_LAYERS_NAME_DST) { bDeformGroup *dg_src = BLI_findlink(&ob_src->defbase, idx_src); if ((idx_dst = defgroup_name_index(ob_dst, dg_src->name)) == -1) { if (!use_create) { return true; } BKE_object_defgroup_add_name(ob_dst, dg_src->name); idx_dst = ob_dst->actdef - 1; } } else { return false; } if (r_map) { /* At this stage, we **need** a valid CD_MDEFORMVERT layer on dest! * use_create is not relevant in this case */ if (!data_dst) { data_dst = CustomData_add_layer(cd_dst, CD_MDEFORMVERT, CD_CALLOC, NULL, num_elem_dst); } data_transfer_layersmapping_add_item(r_map, CD_FAKE_MDEFORMVERT, mix_mode, mix_factor, mix_weights, data_src, data_dst, idx_src, idx_dst, elem_size, 0, 0, 0, vgroups_datatransfer_interp, NULL); } } else { int num_src, num_sel_unused; bool *use_layers_src = NULL; bool ret = false; switch (fromlayers) { case DT_LAYERS_ALL_SRC: use_layers_src = BKE_object_defgroup_subset_from_select_type(ob_src, WT_VGROUP_ALL, &num_src, &num_sel_unused); break; case DT_LAYERS_VGROUP_SRC_BONE_SELECT: use_layers_src = BKE_object_defgroup_subset_from_select_type(ob_src, WT_VGROUP_BONE_SELECT, &num_src, &num_sel_unused); break; case DT_LAYERS_VGROUP_SRC_BONE_DEFORM: use_layers_src = BKE_object_defgroup_subset_from_select_type(ob_src, WT_VGROUP_BONE_DEFORM, &num_src, &num_sel_unused); break; } if (use_layers_src) { ret = data_transfer_layersmapping_vgroups_multisrc_to_dst( r_map, mix_mode, mix_factor, mix_weights, num_elem_dst, use_create, use_delete, ob_src, ob_dst, data_src, data_dst, cd_src, cd_dst, use_dupref_dst, tolayers, use_layers_src, num_src); } MEM_SAFE_FREE(use_layers_src); return ret; } return true; }
/* dm must be a CDDerivedMesh */ static void displaceModifier_do( DisplaceModifierData *dmd, Object *ob, DerivedMesh *dm, float (*vertexCos)[3], int numVerts) { int i; MVert *mvert; MDeformVert *dvert; int direction = dmd->direction; int defgrp_index; float (*tex_co)[3]; float weight = 1.0f; /* init value unused but some compilers may complain */ const float delta_fixed = 1.0f - dmd->midlevel; /* when no texture is used, we fallback to white */ float (*vert_clnors)[3] = NULL; if (!dmd->texture && dmd->direction == MOD_DISP_DIR_RGB_XYZ) return; if (dmd->strength == 0.0f) return; mvert = CDDM_get_verts(dm); modifier_get_vgroup(ob, dm, dmd->defgrp_name, &dvert, &defgrp_index); if (dmd->texture) { tex_co = MEM_callocN(sizeof(*tex_co) * numVerts, "displaceModifier_do tex_co"); get_texture_coords((MappingInfoModifierData *)dmd, ob, dm, vertexCos, tex_co, numVerts); modifier_init_texture(dmd->modifier.scene, dmd->texture); } else { tex_co = NULL; } if (direction == MOD_DISP_DIR_CLNOR) { CustomData *ldata = dm->getLoopDataLayout(dm); if (CustomData_has_layer(ldata, CD_CUSTOMLOOPNORMAL)) { float (*clnors)[3] = NULL; if ((dm->dirty & DM_DIRTY_NORMALS) || !CustomData_has_layer(ldata, CD_NORMAL)) { dm->calcLoopNormals(dm, true, (float)M_PI); } clnors = CustomData_get_layer(ldata, CD_NORMAL); vert_clnors = MEM_mallocN(sizeof(*vert_clnors) * (size_t)numVerts, __func__); BKE_mesh_normals_loop_to_vertex(numVerts, dm->getLoopArray(dm), dm->getNumLoops(dm), (const float (*)[3])clnors, vert_clnors); } else { direction = MOD_DISP_DIR_NOR; } } for (i = 0; i < numVerts; i++) { TexResult texres; float strength = dmd->strength; float delta; if (dvert) { weight = defvert_find_weight(dvert + i, defgrp_index); if (weight == 0.0f) continue; } if (dmd->texture) { texres.nor = NULL; BKE_texture_get_value(dmd->modifier.scene, dmd->texture, tex_co[i], &texres, false); delta = texres.tin - dmd->midlevel; } else { delta = delta_fixed; /* (1.0f - dmd->midlevel) */ /* never changes */ } if (dvert) strength *= weight; delta *= strength; CLAMP(delta, -10000, 10000); switch (direction) { case MOD_DISP_DIR_X: vertexCos[i][0] += delta; break; case MOD_DISP_DIR_Y: vertexCos[i][1] += delta; break; case MOD_DISP_DIR_Z: vertexCos[i][2] += delta; break; case MOD_DISP_DIR_RGB_XYZ: vertexCos[i][0] += (texres.tr - dmd->midlevel) * strength; vertexCos[i][1] += (texres.tg - dmd->midlevel) * strength; vertexCos[i][2] += (texres.tb - dmd->midlevel) * strength; break; case MOD_DISP_DIR_NOR: vertexCos[i][0] += delta * (mvert[i].no[0] / 32767.0f); vertexCos[i][1] += delta * (mvert[i].no[1] / 32767.0f); vertexCos[i][2] += delta * (mvert[i].no[2] / 32767.0f); break; case MOD_DISP_DIR_CLNOR: madd_v3_v3fl(vertexCos[i], vert_clnors[i], delta); break; } } if (tex_co) { MEM_freeN(tex_co); } if (vert_clnors) { MEM_freeN(vert_clnors); } }
/* MultiresBake callback for heights baking * general idea: * - find coord of point with specified UV in hi-res mesh (let's call it p1) * - find coord of point and normal with specified UV in lo-res mesh (or subdivided lo-res * mesh to make texture smoother) let's call this point p0 and n. * - height wound be dot(n, p1-p0) */ static void apply_heights_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm, const void *bake_data, ImBuf *ibuf, const int face_index, const int lvl, const float st[2], float UNUSED(tangmat[3][3]), const int x, const int y) { MTFace *mtface = CustomData_get_layer(&lores_dm->faceData, CD_MTFACE); MFace mface; MHeightBakeData *height_data = (MHeightBakeData *)bake_data; float uv[2], *st0, *st1, *st2, *st3; int pixel = ibuf->x * y + x; float vec[3], p0[3], p1[3], n[3], len; lores_dm->getTessFace(lores_dm, face_index, &mface); st0 = mtface[face_index].uv[0]; st1 = mtface[face_index].uv[1]; st2 = mtface[face_index].uv[2]; if (mface.v4) { st3 = mtface[face_index].uv[3]; resolve_quad_uv(uv, st, st0, st1, st2, st3); } else resolve_tri_uv(uv, st, st0, st1, st2); CLAMP(uv[0], 0.0f, 1.0f); CLAMP(uv[1], 0.0f, 1.0f); get_ccgdm_data(lores_dm, hires_dm, height_data->orig_index_mf_to_mpoly, height_data->orig_index_mf_to_mpoly, lvl, face_index, uv[0], uv[1], p1, 0); if (height_data->ssdm) { get_ccgdm_data(lores_dm, height_data->ssdm, height_data->orig_index_mf_to_mpoly, height_data->orig_index_mf_to_mpoly, 0, face_index, uv[0], uv[1], p0, n); } else { lores_dm->getTessFace(lores_dm, face_index, &mface); if (mface.v4) { interp_bilinear_mface(lores_dm, &mface, uv[0], uv[1], 1, p0); interp_bilinear_mface(lores_dm, &mface, uv[0], uv[1], 0, n); } else { interp_barycentric_mface(lores_dm, &mface, uv[0], uv[1], 1, p0); interp_barycentric_mface(lores_dm, &mface, uv[0], uv[1], 0, n); } } sub_v3_v3v3(vec, p1, p0); len = dot_v3v3(n, vec); height_data->heights[pixel] = len; if (len < height_data->height_min) height_data->height_min = len; if (len > height_data->height_max) height_data->height_max = len; if (ibuf->rect_float) { float *rrgbf = ibuf->rect_float + pixel * 4; rrgbf[3] = 1.0f; } else { char *rrgb = (char *)ibuf->rect + pixel * 4; rrgb[3] = 255; } }
static DerivedMesh *generate_ocean_geometry(OceanModifierData *omd) { DerivedMesh *result; MVert *mverts; MPoly *mpolys; MLoop *mloops; int *origindex; int cdlayer; const int rx = omd->resolution * omd->resolution; const int ry = omd->resolution * omd->resolution; const int res_x = rx * omd->repeat_x; const int res_y = ry * omd->repeat_y; const int num_verts = (res_x + 1) * (res_y + 1); /* const int num_edges = (res_x * res_y * 2) + res_x + res_y; */ /* UNUSED BMESH */ const int num_faces = res_x * res_y; float sx = omd->size * omd->spatial_size; float sy = omd->size * omd->spatial_size; const float ox = -sx / 2.0f; const float oy = -sy / 2.0f; float ix, iy; int x, y; sx /= rx; sy /= ry; result = CDDM_new(num_verts, 0, 0, num_faces * 4, num_faces); mverts = CDDM_get_verts(result); mpolys = CDDM_get_polys(result); mloops = CDDM_get_loops(result); origindex = CustomData_get_layer(&result->polyData, CD_ORIGINDEX); /* create vertices */ #pragma omp parallel for private(x, y) if (rx > OMP_MIN_RES) for (y = 0; y <= res_y; y++) { for (x = 0; x <= res_x; x++) { const int i = y * (res_x + 1) + x; float *co = mverts[i].co; co[0] = ox + (x * sx); co[1] = oy + (y * sy); co[2] = 0; } } /* create faces */ #pragma omp parallel for private(x, y) if (rx > OMP_MIN_RES) for (y = 0; y < res_y; y++) { for (x = 0; x < res_x; x++) { const int fi = y * res_x + x; const int vi = y * (res_x + 1) + x; MPoly *mp = &mpolys[fi]; MLoop *ml = &mloops[fi * 4]; ml->v = vi; ml++; ml->v = vi + 1; ml++; ml->v = vi + 1 + res_x + 1; ml++; ml->v = vi + res_x + 1; ml++; mp->loopstart = fi * 4; mp->totloop = 4; mp->flag |= ME_SMOOTH; /* generated geometry does not map to original faces */ origindex[fi] = ORIGINDEX_NONE; } } CDDM_calc_edges(result); /* add uvs */ cdlayer = CustomData_number_of_layers(&result->loopData, CD_MLOOPUV); if (cdlayer < MAX_MTFACE) { MLoopUV *mloopuvs = CustomData_add_layer(&result->loopData, CD_MLOOPUV, CD_CALLOC, NULL, num_faces * 4); CustomData_add_layer(&result->polyData, CD_MTEXPOLY, CD_CALLOC, NULL, num_faces); if (mloopuvs) { /* unlikely to fail */ ix = 1.0 / rx; iy = 1.0 / ry; #pragma omp parallel for private(x, y) if (rx > OMP_MIN_RES) for (y = 0; y < res_y; y++) { for (x = 0; x < res_x; x++) { const int i = y * res_x + x; MLoopUV *luv = &mloopuvs[i * 4]; luv->uv[0] = x * ix; luv->uv[1] = y * iy; luv++; luv->uv[0] = (x + 1) * ix; luv->uv[1] = y * iy; luv++; luv->uv[0] = (x + 1) * ix; luv->uv[1] = (y + 1) * iy; luv++; luv->uv[0] = x * ix; luv->uv[1] = (y + 1) * iy; luv++; } } } } result->dirty |= DM_DIRTY_NORMALS; return result; }
static void apply_ao_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm, const void *bake_data, ImBuf *ibuf, const int face_index, const int lvl, const float st[2], float UNUSED(tangmat[3][3]), const int x, const int y) { MAOBakeData *ao_data = (MAOBakeData *) bake_data; MTFace *mtface = CustomData_get_layer(&lores_dm->faceData, CD_MTFACE); MFace mface; int i, k, perm_offs; float pos[3], nrm[3]; float cen[3]; float axisX[3], axisY[3], axisZ[3]; float shadow = 0; float value; int pixel = ibuf->x * y + x; float uv[2], *st0, *st1, *st2, *st3; lores_dm->getTessFace(lores_dm, face_index, &mface); st0 = mtface[face_index].uv[0]; st1 = mtface[face_index].uv[1]; st2 = mtface[face_index].uv[2]; if (mface.v4) { st3 = mtface[face_index].uv[3]; resolve_quad_uv(uv, st, st0, st1, st2, st3); } else resolve_tri_uv(uv, st, st0, st1, st2); CLAMP(uv[0], 0.0f, 1.0f); CLAMP(uv[1], 0.0f, 1.0f); get_ccgdm_data(lores_dm, hires_dm, ao_data->orig_index_mf_to_mpoly, ao_data->orig_index_mp_to_orig, lvl, face_index, uv[0], uv[1], pos, nrm); /* offset ray origin by user bias along normal */ for (i = 0; i < 3; i++) cen[i] = pos[i] + ao_data->bias * nrm[i]; /* build tangent frame */ for (i = 0; i < 3; i++) axisZ[i] = nrm[i]; build_coordinate_frame(axisX, axisY, axisZ); /* static noise */ perm_offs = (get_ao_random2(get_ao_random1(x) + y)) & (MAX_NUMBER_OF_AO_RAYS - 1); /* importance sample shadow rays (cosine weighted) */ for (i = 0; i < ao_data->number_of_rays; i++) { int hit_something; /* use N-Rooks to distribute our N ray samples across * a multi-dimensional domain (2D) */ const unsigned short I = ao_data->permutation_table_1[(i + perm_offs) % ao_data->number_of_rays]; const unsigned short J = ao_data->permutation_table_2[i]; const float JitPh = (get_ao_random2(I + perm_offs) & (MAX_NUMBER_OF_AO_RAYS-1))/((float) MAX_NUMBER_OF_AO_RAYS); const float JitTh = (get_ao_random1(J + perm_offs) & (MAX_NUMBER_OF_AO_RAYS-1))/((float) MAX_NUMBER_OF_AO_RAYS); const float SiSqPhi = (I + JitPh) / ao_data->number_of_rays; const float Theta = (float)(2 * M_PI) * ((J + JitTh) / ao_data->number_of_rays); /* this gives results identical to the so-called cosine * weighted distribution relative to the north pole. */ float SiPhi = sqrt(SiSqPhi); float CoPhi = SiSqPhi < 1.0f ? sqrtf(1.0f - SiSqPhi) : 0; float CoThe = cos(Theta); float SiThe = sin(Theta); const float dx = CoThe * CoPhi; const float dy = SiThe * CoPhi; const float dz = SiPhi; /* transform ray direction out of tangent frame */ float dv[3]; for (k = 0; k < 3; k++) dv[k] = axisX[k] * dx + axisY[k] * dy + axisZ[k] * dz; hit_something = trace_ao_ray(ao_data, cen, dv); if (hit_something != 0) shadow += 1; } value = 1.0f - (shadow / ao_data->number_of_rays); if (ibuf->rect_float) { float *rrgbf = ibuf->rect_float + pixel * 4; rrgbf[0] = rrgbf[1] = rrgbf[2] = value; rrgbf[3] = 1.0f; } else { unsigned char *rrgb = (unsigned char *) ibuf->rect + pixel * 4; rrgb[0] = rrgb[1] = rrgb[2] = FTOCHAR(value); rrgb[3] = 255; } }