Blender V4.3
multires_bake.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2012 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include <cstring>
10
11#include "MEM_guardedalloc.h"
12
13#include "DNA_scene_types.h"
14
15#include "BLI_listbase.h"
16#include "BLI_math_color.h"
17#include "BLI_math_geom.h"
18#include "BLI_math_matrix.h"
19#include "BLI_threads.h"
20
21#include "BKE_attribute.hh"
22#include "BKE_ccg.hh"
23#include "BKE_customdata.hh"
24#include "BKE_global.hh"
25#include "BKE_image.hh"
26#include "BKE_lib_id.hh"
27#include "BKE_mesh.hh"
29#include "BKE_mesh_tangent.hh"
30#include "BKE_modifier.hh"
31#include "BKE_multires.hh"
32#include "BKE_subsurf.hh"
33
34#include "DEG_depsgraph.hh"
35
36#include "RE_multires_bake.h"
37#include "RE_pipeline.h"
38#include "RE_texture_margin.h"
39
40#include "IMB_imbuf.hh"
41#include "IMB_imbuf_types.hh"
42
43using MPassKnownData = void (*)(blender::Span<blender::float3> vert_positions,
46 blender::Span<int> corner_verts,
48 blender::Span<int> tri_faces,
50 DerivedMesh *hires_dm,
51 void *thread_data,
52 void *bake_data,
53 ImBuf *ibuf,
54 const int face_index,
55 const int lvl,
56 const float st[2],
57 float tangmat[3][3],
58 const int x,
59 const int y);
60
61using MInitBakeData = void *(*)(MultiresBakeRender *bkr, ImBuf *ibuf);
62using MFreeBakeData = void (*)(void *bake_data);
63
67
99
100using MFlushPixel = void (*)(const MResolvePixelData *data, const int x, const int y);
101
109
115
119
124
126 const int tri_num,
127 const int vert_index,
128 float r_normal[3])
129{
130 const int face_index = data->tri_faces[tri_num];
131 const bool smoothnormal = !(data->sharp_faces && data->sharp_faces[face_index]);
132
133 if (smoothnormal) {
134 const int vi = data->corner_verts[data->corner_tris[tri_num][vert_index]];
135 copy_v3_v3(r_normal, data->vert_normals[vi]);
136 }
137 else {
138 copy_v3_v3(r_normal, data->face_normals[face_index]);
139 }
140}
141
142static void init_bake_rast(MBakeRast *bake_rast,
143 const ImBuf *ibuf,
144 const MResolvePixelData *data,
146 bool *do_update)
147{
148 BakeImBufuserData *userdata = (BakeImBufuserData *)ibuf->userdata;
149
150 memset(bake_rast, 0, sizeof(MBakeRast));
151
152 bake_rast->texels = userdata->mask_buffer;
153 bake_rast->w = ibuf->x;
154 bake_rast->h = ibuf->y;
155 bake_rast->data = data;
156 bake_rast->flush_pixel = flush_pixel;
157 bake_rast->do_update = do_update;
158}
159
160static void flush_pixel(const MResolvePixelData *data, const int x, const int y)
161{
162 const float st[2] = {(x + 0.5f) / data->w + data->uv_offset[0],
163 (y + 0.5f) / data->h + data->uv_offset[1]};
164 const float *st0, *st1, *st2;
165 const float *tang0, *tang1, *tang2;
166 float no0[3], no1[3], no2[3];
167 float fUV[2], from_tang[3][3], to_tang[3][3];
168 float u, v, w, sign;
169 int r;
170
171 st0 = data->uv_map[data->corner_tris[data->tri_index][0]];
172 st1 = data->uv_map[data->corner_tris[data->tri_index][1]];
173 st2 = data->uv_map[data->corner_tris[data->tri_index][2]];
174
175 multiresbake_get_normal(data, data->tri_index, 0, no0); /* can optimize these 3 into one call */
176 multiresbake_get_normal(data, data->tri_index, 1, no1);
177 multiresbake_get_normal(data, data->tri_index, 2, no2);
178
179 resolve_tri_uv_v2(fUV, st, st0, st1, st2);
180
181 u = fUV[0];
182 v = fUV[1];
183 w = 1 - u - v;
184
185 if (data->pvtangent) {
186 tang0 = data->pvtangent + data->corner_tris[data->tri_index][0] * 4;
187 tang1 = data->pvtangent + data->corner_tris[data->tri_index][1] * 4;
188 tang2 = data->pvtangent + data->corner_tris[data->tri_index][2] * 4;
189
190 /* the sign is the same at all face vertices for any non degenerate face.
191 * Just in case we clamp the interpolated value though. */
192 sign = (tang0[3] * u + tang1[3] * v + tang2[3] * w) < 0 ? (-1.0f) : 1.0f;
193
194 /* this sequence of math is designed specifically as is with great care
195 * to be compatible with our shader. Please don't change without good reason. */
196 for (r = 0; r < 3; r++) {
197 from_tang[0][r] = tang0[r] * u + tang1[r] * v + tang2[r] * w;
198 from_tang[2][r] = no0[r] * u + no1[r] * v + no2[r] * w;
199 }
200
201 cross_v3_v3v3(from_tang[1], from_tang[2], from_tang[0]); /* `B = sign * cross(N, T)` */
202 mul_v3_fl(from_tang[1], sign);
203 invert_m3_m3(to_tang, from_tang);
204 }
205 else {
206 zero_m3(to_tang);
207 }
208
209 data->pass_data(data->vert_positions,
210 data->vert_normals,
211 data->faces,
212 data->corner_verts,
213 data->corner_tris,
214 data->tri_faces,
215 data->uv_map,
216 data->hires_dm,
217 data->thread_data,
218 data->bake_data,
219 data->ibuf,
220 data->tri_index,
221 data->lvl,
222 st,
223 to_tang,
224 x,
225 y);
226}
227
228static void set_rast_triangle(const MBakeRast *bake_rast, const int x, const int y)
229{
230 const int w = bake_rast->w;
231 const int h = bake_rast->h;
232
233 if (x >= 0 && x < w && y >= 0 && y < h) {
234 if ((bake_rast->texels[y * w + x]) == 0) {
235 bake_rast->texels[y * w + x] = FILTER_MASK_USED;
236 flush_pixel(bake_rast->data, x, y);
237 if (bake_rast->do_update) {
238 *bake_rast->do_update = true;
239 }
240 }
241 }
242}
243
244static void rasterize_half(const MBakeRast *bake_rast,
245 const float s0_s,
246 const float t0_s,
247 const float s1_s,
248 const float t1_s,
249 const float s0_l,
250 const float t0_l,
251 const float s1_l,
252 const float t1_l,
253 const int y0_in,
254 const int y1_in,
255 const int is_mid_right)
256{
257 const int s_stable = fabsf(t1_s - t0_s) > FLT_EPSILON ? 1 : 0;
258 const int l_stable = fabsf(t1_l - t0_l) > FLT_EPSILON ? 1 : 0;
259 const int w = bake_rast->w;
260 const int h = bake_rast->h;
261 int y, y0, y1;
262
263 if (y1_in <= 0 || y0_in >= h) {
264 return;
265 }
266
267 y0 = y0_in < 0 ? 0 : y0_in;
268 y1 = y1_in >= h ? h : y1_in;
269
270 for (y = y0; y < y1; y++) {
271 /*-b(x-x0) + a(y-y0) = 0 */
272 int iXl, iXr, x;
273 float x_l = s_stable != 0 ? (s0_s + (((s1_s - s0_s) * (y - t0_s)) / (t1_s - t0_s))) : s0_s;
274 float x_r = l_stable != 0 ? (s0_l + (((s1_l - s0_l) * (y - t0_l)) / (t1_l - t0_l))) : s0_l;
275
276 if (is_mid_right != 0) {
277 std::swap(x_l, x_r);
278 }
279
280 iXl = int(ceilf(x_l));
281 iXr = int(ceilf(x_r));
282
283 if (iXr > 0 && iXl < w) {
284 iXl = iXl < 0 ? 0 : iXl;
285 iXr = iXr >= w ? w : iXr;
286
287 for (x = iXl; x < iXr; x++) {
288 set_rast_triangle(bake_rast, x, y);
289 }
290 }
291 }
292}
293
294static void bake_rasterize(const MBakeRast *bake_rast,
295 const float st0_in[2],
296 const float st1_in[2],
297 const float st2_in[2])
298{
299 const int w = bake_rast->w;
300 const int h = bake_rast->h;
301 float slo = st0_in[0] * w - 0.5f;
302 float tlo = st0_in[1] * h - 0.5f;
303 float smi = st1_in[0] * w - 0.5f;
304 float tmi = st1_in[1] * h - 0.5f;
305 float shi = st2_in[0] * w - 0.5f;
306 float thi = st2_in[1] * h - 0.5f;
307 int is_mid_right = 0, ylo, yhi, yhi_beg;
308
309 /* skip degenerates */
310 if ((slo == smi && tlo == tmi) || (slo == shi && tlo == thi) || (smi == shi && tmi == thi)) {
311 return;
312 }
313
314 /* sort by T */
315 if (tlo > tmi && tlo > thi) {
316 std::swap(shi, slo);
317 std::swap(thi, tlo);
318 }
319 else if (tmi > thi) {
320 std::swap(shi, smi);
321 std::swap(thi, tmi);
322 }
323
324 if (tlo > tmi) {
325 std::swap(slo, smi);
326 std::swap(tlo, tmi);
327 }
328
329 /* check if mid point is to the left or to the right of the lo-hi edge */
330 is_mid_right = (-(shi - slo) * (tmi - thi) + (thi - tlo) * (smi - shi)) > 0 ? 1 : 0;
331 ylo = int(ceilf(tlo));
332 yhi_beg = int(ceilf(tmi));
333 yhi = int(ceilf(thi));
334
335 // if (fTmi>ceilf(fTlo))
336 rasterize_half(bake_rast, slo, tlo, smi, tmi, slo, tlo, shi, thi, ylo, yhi_beg, is_mid_right);
337 rasterize_half(bake_rast, smi, tmi, shi, thi, slo, tlo, shi, thi, yhi_beg, yhi, is_mid_right);
338}
339
341{
342 if (!bkr->stop) {
343 /* this means baker is executed outside from job system */
344 return 0;
345 }
346
347 return *bkr->stop || G.is_break;
348}
349
350/* **** Threading routines **** */
351
357
359 /* this data is actually shared between all the threads */
365
366 /* thread-specific data */
369
370 /* displacement-specific data */
372};
373
375{
376 int face = -1;
377
378 /* TODO: it could worth making it so thread will handle neighbor faces
379 * for better memory cache utilization
380 */
381
382 BLI_spin_lock(&queue->spin);
383 if (queue->cur_tri < queue->tot_tri) {
384 face = queue->cur_tri;
385 queue->cur_tri++;
386 }
387 BLI_spin_unlock(&queue->spin);
388
389 return face;
390}
391
392static void *do_multires_bake_thread(void *data_v)
393{
394 MultiresBakeThread *handle = (MultiresBakeThread *)data_v;
395 MResolvePixelData *data = &handle->data;
396 MBakeRast *bake_rast = &handle->bake_rast;
397 MultiresBakeRender *bkr = handle->bkr;
398 int tri_index;
399
400 while ((tri_index = multires_bake_queue_next_tri(handle->queue)) >= 0) {
401 const blender::int3 &tri = data->corner_tris[tri_index];
402 const int face_i = data->tri_faces[tri_index];
403 const short mat_nr = data->material_indices == nullptr ? 0 : data->material_indices[face_i];
404
405 if (multiresbake_test_break(bkr)) {
406 break;
407 }
408
409 Image *tri_image = mat_nr < bkr->ob_image.len ? bkr->ob_image.array[mat_nr] : nullptr;
410 if (tri_image != handle->image) {
411 continue;
412 }
413
414 data->tri_index = tri_index;
415
416 float uv[3][2];
417 sub_v2_v2v2(uv[0], data->uv_map[tri[0]], data->uv_offset);
418 sub_v2_v2v2(uv[1], data->uv_map[tri[1]], data->uv_offset);
419 sub_v2_v2v2(uv[2], data->uv_map[tri[2]], data->uv_offset);
420
421 bake_rasterize(bake_rast, uv[0], uv[1], uv[2]);
422
423 /* tag image buffer for refresh */
424 if (data->ibuf->float_buffer.data) {
425 data->ibuf->userflags |= IB_RECT_INVALID;
426 }
427
428 data->ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
429
430 /* update progress */
431 BLI_spin_lock(&handle->queue->spin);
432 bkr->baked_faces++;
433
434 if (bkr->do_update) {
435 *bkr->do_update = true;
436 }
437
438 if (bkr->progress) {
439 *bkr->progress = (float(bkr->baked_objects) +
440 float(bkr->baked_faces) / handle->num_total_faces) /
441 bkr->tot_obj;
442 }
443 BLI_spin_unlock(&handle->queue->spin);
444 }
445
446 return nullptr;
447}
448
449/* some of arrays inside ccgdm are lazy-initialized, which will generally
450 * require lock around accessing such data
451 * this function will ensure all arrays are allocated before threading started
452 */
454{
455 CCGElem **grid_data;
456 CCGKey key;
457 int grid_size;
458 const int *grid_offset;
459
460 grid_size = dm->getGridSize(dm);
461 grid_data = dm->getGridData(dm);
462 grid_offset = dm->getGridOffset(dm);
463 dm->getGridKey(dm, &key);
464
465 (void)grid_size;
466 (void)grid_data;
467 (void)grid_offset;
468}
469
471 Image *ima,
473 ImBuf *ibuf,
474 bool require_tangent,
475 MPassKnownData passKnownData,
476 MInitBakeData initBakeData,
477 MFreeBakeData freeBakeData,
478 MultiresBakeResult *result)
479{
480 using namespace blender;
481 DerivedMesh *dm = bkr->lores_dm;
482 const int lvl = bkr->lvl;
483 if (dm->getNumPolys(dm) == 0) {
484 return;
485 }
486
487 MultiresBakeQueue queue;
488
489 const Span<float2> uv_map(
490 reinterpret_cast<const float2 *>(dm->getLoopDataArray(dm, CD_PROP_FLOAT2)),
491 dm->getNumLoops(dm));
492
493 float *pvtangent = nullptr;
494
495 ListBase threads;
496 int i, tot_thread = bkr->threads > 0 ? bkr->threads : BLI_system_thread_count();
497
498 void *bake_data = nullptr;
499
500 Mesh *temp_mesh = BKE_mesh_new_nomain(
501 dm->getNumVerts(dm), dm->getNumEdges(dm), dm->getNumPolys(dm), dm->getNumLoops(dm));
502 temp_mesh->vert_positions_for_write().copy_from(
503 {reinterpret_cast<const float3 *>(dm->getVertArray(dm)), temp_mesh->verts_num});
504 temp_mesh->edges_for_write().copy_from(
505 {reinterpret_cast<const int2 *>(dm->getEdgeArray(dm)), temp_mesh->edges_num});
506 temp_mesh->face_offsets_for_write().copy_from({dm->getPolyArray(dm), temp_mesh->faces_num + 1});
507 temp_mesh->corner_verts_for_write().copy_from(
508 {dm->getCornerVertArray(dm), temp_mesh->corners_num});
509 temp_mesh->corner_edges_for_write().copy_from(
510 {dm->getCornerEdgeArray(dm), temp_mesh->corners_num});
511
512 const Span<float3> positions = temp_mesh->vert_positions();
513 const OffsetIndices faces = temp_mesh->faces();
514 const Span<int> corner_verts = temp_mesh->corner_verts();
515 const Span<float3> vert_normals = temp_mesh->vert_normals();
516 const Span<float3> face_normals = temp_mesh->face_normals();
517 const Span<int3> corner_tris = temp_mesh->corner_tris();
518 const Span<int> tri_faces = temp_mesh->corner_tri_faces();
519
520 if (require_tangent) {
522 const bool *sharp_edges = static_cast<const bool *>(
524 const bool *sharp_faces = static_cast<const bool *>(
526
527 /* Copy sharp faces and edges, for corner normals domain and tangents
528 * to be computed correctly. */
529 if (sharp_edges) {
530 bke::MutableAttributeAccessor attributes = temp_mesh->attributes_for_write();
531 attributes.add<bool>("sharp_edge",
532 bke::AttrDomain::Edge,
534 Span<bool>(sharp_edges, temp_mesh->edges_num))));
535 }
536 if (sharp_faces) {
537 bke::MutableAttributeAccessor attributes = temp_mesh->attributes_for_write();
538 attributes.add<bool>("sharp_face",
539 bke::AttrDomain::Face,
541 Span<bool>(sharp_faces, temp_mesh->faces_num))));
542 }
543
544 const float3 *orco = static_cast<const float3 *>(dm->getVertDataArray(dm, CD_ORCO));
545
546 const Span<float3> corner_normals = temp_mesh->corner_normals();
548 faces,
549 dm->getCornerVertArray(dm),
550 corner_tris.data(),
551 tri_faces.data(),
552 corner_tris.size(),
553 sharp_faces ? Span(sharp_faces, faces.size()) : Span<bool>(),
554 &dm->loopData,
555 true,
556 nullptr,
557 0,
558 vert_normals,
559 face_normals,
560 corner_normals,
561 orco ? Span(orco, positions.size()) : Span<float3>(),
562 /* result */
563 &dm->loopData,
564 dm->getNumLoops(dm),
565 &dm->tangent_mask);
566 }
567
568 pvtangent = static_cast<float *>(DM_get_loop_data_layer(dm, CD_TANGENT));
569 }
570
571 /* all threads shares the same custom bake data */
572 if (initBakeData) {
573 bake_data = initBakeData(bkr, ibuf);
574 }
575
576 if (tot_thread > 1) {
577 BLI_threadpool_init(&threads, do_multires_bake_thread, tot_thread);
578 }
579
581
583
584 /* faces queue */
585 queue.cur_tri = 0;
586 queue.tot_tri = corner_tris.size();
587 BLI_spin_init(&queue.spin);
588
589 /* fill in threads handles */
590 for (i = 0; i < tot_thread; i++) {
591 MultiresBakeThread *handle = &handles[i];
592
593 handle->bkr = bkr;
594 handle->image = ima;
595 handle->num_total_faces = queue.tot_tri * BLI_listbase_count(&ima->tiles);
596 handle->queue = &queue;
597
598 handle->data.vert_positions = positions;
599 handle->data.faces = faces;
600 handle->data.corner_verts = corner_verts;
601 handle->data.corner_tris = corner_tris;
602 handle->data.tri_faces = tri_faces;
603 handle->data.vert_normals = vert_normals;
604 handle->data.face_normals = face_normals;
605 handle->data.material_indices = static_cast<const int *>(
606 CustomData_get_layer_named(&dm->polyData, CD_PROP_INT32, "material_index"));
607 handle->data.sharp_faces = static_cast<const bool *>(
609 handle->data.uv_map = uv_map;
610 BKE_image_get_tile_uv(ima, tile->tile_number, handle->data.uv_offset);
611 handle->data.pvtangent = pvtangent;
612 handle->data.w = ibuf->x;
613 handle->data.h = ibuf->y;
614 handle->data.hires_dm = bkr->hires_dm;
615 handle->data.lvl = lvl;
616 handle->data.pass_data = passKnownData;
617 handle->data.thread_data = handle;
618 handle->data.bake_data = bake_data;
619 handle->data.ibuf = ibuf;
620
621 handle->height_min = FLT_MAX;
622 handle->height_max = -FLT_MAX;
623
624 init_bake_rast(&handle->bake_rast, ibuf, &handle->data, flush_pixel, bkr->do_update);
625
626 if (tot_thread > 1) {
627 BLI_threadpool_insert(&threads, handle);
628 }
629 }
630
631 /* run threads */
632 if (tot_thread > 1) {
633 BLI_threadpool_end(&threads);
634 }
635 else {
636 do_multires_bake_thread(&handles[0]);
637 }
638
639 for (i = 0; i < tot_thread; i++) {
640 result->height_min = min_ff(result->height_min, handles[i].height_min);
641 result->height_max = max_ff(result->height_max, handles[i].height_max);
642 }
643
644 BLI_spin_end(&queue.spin);
645
646 /* finalize baking */
647 if (freeBakeData) {
648 freeBakeData(bake_data);
649 }
650
651 BKE_id_free(nullptr, temp_mesh);
652}
653
654/* mode = 0: interpolate normals,
655 * mode = 1: interpolate coord */
657 const CCGKey &key, CCGElem *grid, float crn_x, float crn_y, int mode, float res[3])
658{
659 int x0, x1, y0, y1;
660 float u, v;
661 float data[4][3];
662
663 x0 = int(crn_x);
664 x1 = x0 >= (key.grid_size - 1) ? (key.grid_size - 1) : (x0 + 1);
665
666 y0 = int(crn_y);
667 y1 = y0 >= (key.grid_size - 1) ? (key.grid_size - 1) : (y0 + 1);
668
669 u = crn_x - x0;
670 v = crn_y - y0;
671
672 if (mode == 0) {
673 copy_v3_v3(data[0], CCG_grid_elem_no(key, grid, x0, y0));
674 copy_v3_v3(data[1], CCG_grid_elem_no(key, grid, x1, y0));
675 copy_v3_v3(data[2], CCG_grid_elem_no(key, grid, x1, y1));
676 copy_v3_v3(data[3], CCG_grid_elem_no(key, grid, x0, y1));
677 }
678 else {
679 copy_v3_v3(data[0], CCG_grid_elem_co(key, grid, x0, y0));
680 copy_v3_v3(data[1], CCG_grid_elem_co(key, grid, x1, y0));
681 copy_v3_v3(data[2], CCG_grid_elem_co(key, grid, x1, y1));
682 copy_v3_v3(data[3], CCG_grid_elem_co(key, grid, x0, y1));
683 }
684
685 interp_bilinear_quad_v3(data, u, v, res);
686}
687
688static void get_ccgdm_data(const blender::OffsetIndices<int> lores_polys,
689 DerivedMesh *hidm,
690 const int *index_mp_to_orig,
691 const int lvl,
692 const int face_index,
693 const float u,
694 const float v,
695 float co[3],
696 float n[3])
697{
698 CCGElem **grid_data;
699 CCGKey key;
700 float crn_x, crn_y;
701 int grid_size, S, face_side;
702 int *grid_offset, g_index;
703
704 grid_size = hidm->getGridSize(hidm);
705 grid_data = hidm->getGridData(hidm);
706 grid_offset = hidm->getGridOffset(hidm);
707 hidm->getGridKey(hidm, &key);
708
709 if (lvl == 0) {
710 face_side = (grid_size << 1) - 1;
711
712 g_index = grid_offset[face_index];
713 S = mdisp_rot_face_to_crn(lores_polys[face_index].size(),
714 face_side,
715 u * (face_side - 1),
716 v * (face_side - 1),
717 &crn_x,
718 &crn_y);
719 }
720 else {
721 /* number of faces per grid side */
722 int polys_per_grid_side = (1 << (lvl - 1));
723 /* get the original cage face index */
724 int cage_face_index = index_mp_to_orig ? index_mp_to_orig[face_index] : face_index;
725 /* local offset in total cage face grids
726 * `(1 << (2 * lvl))` is number of all faces for one cage face */
727 int loc_cage_poly_ofs = face_index % (1 << (2 * lvl));
728 /* local offset in the vertex grid itself */
729 int cell_index = loc_cage_poly_ofs % (polys_per_grid_side * polys_per_grid_side);
730 int cell_side = (grid_size - 1) / polys_per_grid_side;
731 /* row and column based on grid side */
732 int row = cell_index / polys_per_grid_side;
733 int col = cell_index % polys_per_grid_side;
734
735 /* S is the vertex whose grid we are examining */
736 S = face_index / (1 << (2 * (lvl - 1))) - grid_offset[cage_face_index];
737 /* get offset of grid data for original cage face */
738 g_index = grid_offset[cage_face_index];
739
740 crn_y = (row * cell_side) + u * cell_side;
741 crn_x = (col * cell_side) + v * cell_side;
742 }
743
744 CLAMP(crn_x, 0.0f, grid_size);
745 CLAMP(crn_y, 0.0f, grid_size);
746
747 if (n != nullptr) {
748 interp_bilinear_grid(key, grid_data[g_index + S], crn_x, crn_y, 0, n);
749 }
750
751 if (co != nullptr) {
752 interp_bilinear_grid(key, grid_data[g_index + S], crn_x, crn_y, 1, co);
753 }
754}
755
756/* mode = 0: interpolate normals,
757 * mode = 1: interpolate coord */
758
760 const blender::Span<blender::float3> vert_normals,
761 const blender::Span<int> corner_verts,
762 const blender::IndexRange face,
763 const float u,
764 const float v,
765 const int mode,
766 float res[3])
767{
768 float data[4][3];
769
770 if (mode == 0) {
771 copy_v3_v3(data[0], vert_normals[corner_verts[face[0]]]);
772 copy_v3_v3(data[1], vert_normals[corner_verts[face[1]]]);
773 copy_v3_v3(data[2], vert_normals[corner_verts[face[2]]]);
774 copy_v3_v3(data[3], vert_normals[corner_verts[face[3]]]);
775 }
776 else {
777 copy_v3_v3(data[0], vert_positions[corner_verts[face[0]]]);
778 copy_v3_v3(data[1], vert_positions[corner_verts[face[1]]]);
779 copy_v3_v3(data[2], vert_positions[corner_verts[face[2]]]);
780 copy_v3_v3(data[3], vert_positions[corner_verts[face[3]]]);
781 }
782
783 interp_bilinear_quad_v3(data, u, v, res);
784}
785
787 const blender::Span<blender::float3> vert_normals,
788 const blender::Span<int> corner_verts,
789 const blender::int3 &corner_tri,
790 const float u,
791 const float v,
792 const int mode,
793 float res[3])
794{
795 float data[3][3];
796
797 if (mode == 0) {
798 copy_v3_v3(data[0], vert_normals[corner_verts[corner_tri[0]]]);
799 copy_v3_v3(data[1], vert_normals[corner_verts[corner_tri[1]]]);
800 copy_v3_v3(data[2], vert_normals[corner_verts[corner_tri[2]]]);
801 }
802 else {
803 copy_v3_v3(data[0], vert_positions[corner_verts[corner_tri[0]]]);
804 copy_v3_v3(data[1], vert_positions[corner_verts[corner_tri[1]]]);
805 copy_v3_v3(data[2], vert_positions[corner_verts[corner_tri[2]]]);
806 }
807
808 interp_barycentric_tri_v3(data, u, v, res);
809}
810
811/* **************** Displacement Baker **************** */
812
814{
815 MHeightBakeData *height_data;
816 DerivedMesh *lodm = bkr->lores_dm;
817 BakeImBufuserData *userdata = static_cast<BakeImBufuserData *>(ibuf->userdata);
818
819 if (userdata->displacement_buffer == nullptr) {
820 userdata->displacement_buffer = MEM_cnew_array<float>(ibuf->x * ibuf->y,
821 "MultiresBake heights");
822 }
823
824 height_data = MEM_cnew<MHeightBakeData>("MultiresBake heightData");
825
826 height_data->heights = userdata->displacement_buffer;
827
828 if (!bkr->use_lores_mesh) {
829 SubsurfModifierData smd = {{nullptr}};
830 int ss_lvl = bkr->tot_lvl - bkr->lvl;
831
832 CLAMP(ss_lvl, 0, 6);
833
834 if (ss_lvl > 0) {
835 smd.levels = smd.renderLevels = ss_lvl;
837 smd.quality = 3;
838
840 bkr->lores_dm, &smd, bkr->scene, nullptr, SubsurfFlags(0));
841 init_ccgdm_arrays(height_data->ssdm);
842 }
843 }
844
845 height_data->orig_index_mp_to_orig = static_cast<const int *>(
846 lodm->getPolyDataArray(lodm, CD_ORIGINDEX));
847
848 return (void *)height_data;
849}
850
851static void free_heights_data(void *bake_data)
852{
853 MHeightBakeData *height_data = (MHeightBakeData *)bake_data;
854
855 if (height_data->ssdm) {
856 height_data->ssdm->release(height_data->ssdm);
857 }
858
859 MEM_freeN(height_data);
860}
861
862/* MultiresBake callback for heights baking
863 * general idea:
864 * - find coord of point with specified UV in hi-res mesh (let's call it p1)
865 * - find coord of point and normal with specified UV in lo-res mesh (or subdivided lo-res
866 * mesh to make texture smoother) let's call this point p0 and n.
867 * - height wound be dot(n, p1-p0) */
869 const blender::Span<blender::float3> vert_normals,
870 const blender::OffsetIndices<int> faces,
871 const blender::Span<int> corner_verts,
872 const blender::Span<blender::int3> corner_tris,
873 const blender::Span<int> tri_faces,
875 DerivedMesh *hires_dm,
876 void *thread_data_v,
877 void *bake_data,
878 ImBuf *ibuf,
879 const int tri_index,
880 const int lvl,
881 const float st[2],
882 float /*tangmat*/[3][3],
883 const int x,
884 const int y)
885{
886 const blender::int3 &tri = corner_tris[tri_index];
887 const int face_i = tri_faces[tri_index];
888 const blender::IndexRange face = faces[face_i];
889 MHeightBakeData *height_data = (MHeightBakeData *)bake_data;
890 MultiresBakeThread *thread_data = (MultiresBakeThread *)thread_data_v;
891 float uv[2];
892 const float *st0, *st1, *st2, *st3;
893 int pixel = ibuf->x * y + x;
894 float vec[3], p0[3], p1[3], n[3], len;
895
896 /* ideally we would work on triangles only, however, we rely on quads to get orthogonal
897 * coordinates for use in grid space (triangle barycentric is not orthogonal) */
898 if (face.size() == 4) {
899 st0 = uv_map[face[0]];
900 st1 = uv_map[face[1]];
901 st2 = uv_map[face[2]];
902 st3 = uv_map[face[3]];
903 resolve_quad_uv_v2(uv, st, st0, st1, st2, st3);
904 }
905 else {
906 st0 = uv_map[tri[0]];
907 st1 = uv_map[tri[1]];
908 st2 = uv_map[tri[2]];
909 resolve_tri_uv_v2(uv, st, st0, st1, st2);
910 }
911
912 clamp_v2(uv, 0.0f, 1.0f);
913
915 faces, hires_dm, height_data->orig_index_mp_to_orig, lvl, face_i, uv[0], uv[1], p1, nullptr);
916
917 if (height_data->ssdm) {
918 get_ccgdm_data(faces,
919 height_data->ssdm,
920 height_data->orig_index_mp_to_orig,
921 0,
922 face_i,
923 uv[0],
924 uv[1],
925 p0,
926 n);
927 }
928 else {
929 if (face.size() == 4) {
930 interp_bilinear_mpoly(vert_positions, vert_normals, corner_verts, face, uv[0], uv[1], 1, p0);
931 interp_bilinear_mpoly(vert_positions, vert_normals, corner_verts, face, uv[0], uv[1], 0, n);
932 }
933 else {
935 vert_positions, vert_normals, corner_verts, tri, uv[0], uv[1], 1, p0);
937 vert_positions, vert_normals, corner_verts, tri, uv[0], uv[1], 0, n);
938 }
939 }
940
941 sub_v3_v3v3(vec, p1, p0);
942 len = dot_v3v3(n, vec);
943
944 height_data->heights[pixel] = len;
945
946 thread_data->height_min = min_ff(thread_data->height_min, len);
947 thread_data->height_max = max_ff(thread_data->height_max, len);
948
949 if (ibuf->float_buffer.data) {
950 float *rrgbf = ibuf->float_buffer.data + pixel * 4;
951 rrgbf[0] = rrgbf[1] = rrgbf[2] = len;
952 rrgbf[3] = 1.0f;
953 }
954 else {
955 uchar *rrgb = ibuf->byte_buffer.data + pixel * 4;
956 rrgb[0] = rrgb[1] = rrgb[2] = unit_float_to_uchar_clamp(len);
957 rrgb[3] = 255;
958 }
959}
960
961/* **************** Normal Maps Baker **************** */
962
963static void *init_normal_data(MultiresBakeRender *bkr, ImBuf * /*ibuf*/)
964{
965 MNormalBakeData *normal_data;
966 DerivedMesh *lodm = bkr->lores_dm;
967
968 normal_data = MEM_cnew<MNormalBakeData>("MultiresBake normalData");
969
970 normal_data->orig_index_mp_to_orig = static_cast<const int *>(
971 lodm->getPolyDataArray(lodm, CD_ORIGINDEX));
972
973 return (void *)normal_data;
974}
975
976static void free_normal_data(void *bake_data)
977{
978 MNormalBakeData *normal_data = (MNormalBakeData *)bake_data;
979
980 MEM_freeN(normal_data);
981}
982
991static void apply_tangmat_callback(const blender::Span<blender::float3> /*vert_positions*/,
992 const blender::Span<blender::float3> /*vert_normals*/,
993 const blender::OffsetIndices<int> faces,
994 const blender::Span<int> /*corner_verts*/,
995 const blender::Span<blender::int3> corner_tris,
996 const blender::Span<int> tri_faces,
998 DerivedMesh *hires_dm,
999 void * /*thread_data*/,
1000 void *bake_data,
1001 ImBuf *ibuf,
1002 const int tri_index,
1003 const int lvl,
1004 const float st[2],
1005 float tangmat[3][3],
1006 const int x,
1007 const int y)
1008{
1009 const blender::int3 &tri = corner_tris[tri_index];
1010 const int face_i = tri_faces[tri_index];
1011 const blender::IndexRange face = faces[face_i];
1012 MNormalBakeData *normal_data = (MNormalBakeData *)bake_data;
1013 float uv[2];
1014 const float *st0, *st1, *st2, *st3;
1015 int pixel = ibuf->x * y + x;
1016 float n[3], vec[3], tmp[3] = {0.5, 0.5, 0.5};
1017
1018 /* ideally we would work on triangles only, however, we rely on quads to get orthogonal
1019 * coordinates for use in grid space (triangle barycentric is not orthogonal) */
1020 if (face.size() == 4) {
1021 st0 = uv_map[face[0]];
1022 st1 = uv_map[face[1]];
1023 st2 = uv_map[face[2]];
1024 st3 = uv_map[face[3]];
1025 resolve_quad_uv_v2(uv, st, st0, st1, st2, st3);
1026 }
1027 else {
1028 st0 = uv_map[tri[0]];
1029 st1 = uv_map[tri[1]];
1030 st2 = uv_map[tri[2]];
1031 resolve_tri_uv_v2(uv, st, st0, st1, st2);
1032 }
1033
1034 clamp_v2(uv, 0.0f, 1.0f);
1035
1037 faces, hires_dm, normal_data->orig_index_mp_to_orig, lvl, face_i, uv[0], uv[1], nullptr, n);
1038
1039 mul_v3_m3v3(vec, tangmat, n);
1040 normalize_v3_length(vec, 0.5);
1041 add_v3_v3(vec, tmp);
1042
1043 if (ibuf->float_buffer.data) {
1044 float *rrgbf = ibuf->float_buffer.data + pixel * 4;
1045 rrgbf[0] = vec[0];
1046 rrgbf[1] = vec[1];
1047 rrgbf[2] = vec[2];
1048 rrgbf[3] = 1.0f;
1049 }
1050 else {
1051 uchar *rrgb = ibuf->byte_buffer.data + pixel * 4;
1052 rgb_float_to_uchar(rrgb, vec);
1053 rrgb[3] = 255;
1054 }
1055}
1056
1057/* TODO: restore ambient occlusion baking support, using BLI BVH? */
1058#if 0
1059/* **************** Ambient Occlusion Baker **************** */
1060
1061/* Must be a power of two. */
1062# define MAX_NUMBER_OF_AO_RAYS 1024
1063
1064static ushort ao_random_table_1[MAX_NUMBER_OF_AO_RAYS];
1065static ushort ao_random_table_2[MAX_NUMBER_OF_AO_RAYS];
1066
1067static void init_ao_random()
1068{
1069 int i;
1070
1071 for (i = 0; i < MAX_NUMBER_OF_AO_RAYS; i++) {
1072 ao_random_table_1[i] = rand() & 0xffff;
1073 ao_random_table_2[i] = rand() & 0xffff;
1074 }
1075}
1076
1077static ushort get_ao_random1(const int i)
1078{
1079 return ao_random_table_1[i & (MAX_NUMBER_OF_AO_RAYS - 1)];
1080}
1081
1082static ushort get_ao_random2(const int i)
1083{
1084 return ao_random_table_2[i & (MAX_NUMBER_OF_AO_RAYS - 1)];
1085}
1086
1087static void build_permutation_table(ushort permutation[],
1088 ushort temp_permutation[],
1089 const int number_of_rays,
1090 const int is_first_perm_table)
1091{
1092 int i, k;
1093
1094 for (i = 0; i < number_of_rays; i++) {
1095 temp_permutation[i] = i;
1096 }
1097
1098 for (i = 0; i < number_of_rays; i++) {
1099 const uint nr_entries_left = number_of_rays - i;
1100 ushort rnd = is_first_perm_table != false ? get_ao_random1(i) : get_ao_random2(i);
1101 const ushort entry = rnd % nr_entries_left;
1102
1103 /* pull entry */
1104 permutation[i] = temp_permutation[entry];
1105
1106 /* delete entry */
1107 for (k = entry; k < nr_entries_left - 1; k++) {
1108 temp_permutation[k] = temp_permutation[k + 1];
1109 }
1110 }
1111
1112 /* verify permutation table
1113 * every entry must appear exactly once
1114 */
1115# if 0
1116 for (i = 0; i < number_of_rays; i++)
1117 temp_permutation[i] = 0;
1118 for (i = 0; i < number_of_rays; i++)
1119 ++temp_permutation[permutation[i]];
1120 for (i = 0; i < number_of_rays; i++)
1121 BLI_assert(temp_permutation[i] == 1);
1122# endif
1123}
1124
1125static void create_ao_raytree(MultiresBakeRender *bkr, MAOBakeData *ao_data)
1126{
1127 DerivedMesh *hidm = bkr->hires_dm;
1128 RayObject *raytree;
1129 RayFace *face;
1130 CCGElem **grid_data;
1131 CCGKey key;
1132 int grids_num, grid_size /*, face_side */, faces_num;
1133 int i;
1134
1135 grids_num = hidm->getNumGrids(hidm);
1136 grid_size = hidm->getGridSize(hidm);
1137 grid_data = hidm->getGridData(hidm);
1138 hidm->getGridKey(hidm, &key);
1139
1140 // face_side = (grid_size << 1) - 1; /* UNUSED */
1141 faces_num = grids_num * (grid_size - 1) * (grid_size - 1);
1142
1143 raytree = ao_data->raytree = RE_rayobject_create(
1144 bkr->raytrace_structure, faces_num, bkr->octree_resolution);
1145 face = ao_data->rayfaces = (RayFace *)MEM_callocN(faces_num * sizeof(RayFace),
1146 "ObjectRen faces");
1147
1148 for (i = 0; i < grids_num; i++) {
1149 int x, y;
1150 for (x = 0; x < grid_size - 1; x++) {
1151 for (y = 0; y < grid_size - 1; y++) {
1152 float co[4][3];
1153
1154 copy_v3_v3(co[0], CCG_grid_elem_co(&key, grid_data[i], x, y));
1155 copy_v3_v3(co[1], CCG_grid_elem_co(&key, grid_data[i], x, y + 1));
1156 copy_v3_v3(co[2], CCG_grid_elem_co(&key, grid_data[i], x + 1, y + 1));
1157 copy_v3_v3(co[3], CCG_grid_elem_co(&key, grid_data[i], x + 1, y));
1158
1159 RE_rayface_from_coords(face, ao_data, face, co[0], co[1], co[2], co[3]);
1160 RE_rayobject_add(raytree, RE_rayobject_unalignRayFace(face));
1161
1162 face++;
1163 }
1164 }
1165 }
1166
1167 RE_rayobject_done(raytree);
1168}
1169
1170static void *init_ao_data(MultiresBakeRender *bkr, ImBuf * /*ibuf*/)
1171{
1172 MAOBakeData *ao_data;
1173 DerivedMesh *lodm = bkr->lores_dm;
1174 ushort *temp_permutation_table;
1175 size_t permutation_size;
1176
1177 init_ao_random();
1178
1179 ao_data = MEM_callocN(sizeof(MAOBakeData), "MultiresBake aoData");
1180
1181 ao_data->number_of_rays = bkr->number_of_rays;
1182 ao_data->bias = bkr->bias;
1183
1184 ao_data->orig_index_mp_to_orig = lodm->getPolyDataArray(lodm, CD_ORIGINDEX);
1185
1186 create_ao_raytree(bkr, ao_data);
1187
1188 /* initialize permutation tables */
1189 permutation_size = sizeof(ushort) * bkr->number_of_rays;
1190 ao_data->permutation_table_1 = MEM_callocN(permutation_size, "multires AO baker perm1");
1191 ao_data->permutation_table_2 = MEM_callocN(permutation_size, "multires AO baker perm2");
1192 temp_permutation_table = MEM_callocN(permutation_size, "multires AO baker temp perm");
1193
1194 build_permutation_table(
1195 ao_data->permutation_table_1, temp_permutation_table, bkr->number_of_rays, 1);
1196 build_permutation_table(
1197 ao_data->permutation_table_2, temp_permutation_table, bkr->number_of_rays, 0);
1198
1199 MEM_freeN(temp_permutation_table);
1200
1201 return (void *)ao_data;
1202}
1203
1204static void free_ao_data(void *bake_data)
1205{
1206 MAOBakeData *ao_data = (MAOBakeData *)bake_data;
1207
1208 RE_rayobject_free(ao_data->raytree);
1209 MEM_freeN(ao_data->rayfaces);
1210
1211 MEM_freeN(ao_data->permutation_table_1);
1212 MEM_freeN(ao_data->permutation_table_2);
1213
1214 MEM_freeN(ao_data);
1215}
1216
1217/* builds an X and a Y axis from the given Z axis */
1218static void build_coordinate_frame(float axisX[3], float axisY[3], const float axisZ[3])
1219{
1220 const float faX = fabsf(axisZ[0]);
1221 const float faY = fabsf(axisZ[1]);
1222 const float faZ = fabsf(axisZ[2]);
1223
1224 if (faX <= faY && faX <= faZ) {
1225 const float len = sqrtf(axisZ[1] * axisZ[1] + axisZ[2] * axisZ[2]);
1226 axisY[0] = 0;
1227 axisY[1] = axisZ[2] / len;
1228 axisY[2] = -axisZ[1] / len;
1229 cross_v3_v3v3(axisX, axisY, axisZ);
1230 }
1231 else if (faY <= faZ) {
1232 const float len = sqrtf(axisZ[0] * axisZ[0] + axisZ[2] * axisZ[2]);
1233 axisX[0] = axisZ[2] / len;
1234 axisX[1] = 0;
1235 axisX[2] = -axisZ[0] / len;
1236 cross_v3_v3v3(axisY, axisZ, axisX);
1237 }
1238 else {
1239 const float len = sqrtf(axisZ[0] * axisZ[0] + axisZ[1] * axisZ[1]);
1240 axisX[0] = axisZ[1] / len;
1241 axisX[1] = -axisZ[0] / len;
1242 axisX[2] = 0;
1243 cross_v3_v3v3(axisY, axisZ, axisX);
1244 }
1245}
1246
1247/* return false if nothing was hit and true otherwise */
1248static int trace_ao_ray(MAOBakeData *ao_data, float ray_start[3], float ray_direction[3])
1249{
1250 Isect isect = {{0}};
1251
1252 isect.dist = RE_RAYTRACE_MAXDIST;
1253 copy_v3_v3(isect.start, ray_start);
1254 copy_v3_v3(isect.dir, ray_direction);
1255 isect.lay = -1;
1256
1257 normalize_v3(isect.dir);
1258
1259 return RE_rayobject_raycast(ao_data->raytree, &isect);
1260}
1261
1262static void apply_ao_callback(DerivedMesh *lores_dm,
1263 DerivedMesh *hires_dm,
1264 void * /*thread_data*/,
1265 void *bake_data,
1266 ImBuf *ibuf,
1267 const int tri_index,
1268 const int lvl,
1269 const float st[2],
1270 float /*tangmat[3][3]*/,
1271 const int x,
1272 const int y)
1273{
1274 const blender::int3 &tri = lores_dm->getcorner_triArray(lores_dm) + tri_index;
1275 float(*mloopuv)[2] = lores_dm->getLoopDataArray(lores_dm, CD_PROP_FLOAT2);
1276 MAOBakeData *ao_data = (MAOBakeData *)bake_data;
1277
1278 int i, k, perm_ofs;
1279 float pos[3], nrm[3];
1280 float cen[3];
1281 float axisX[3], axisY[3], axisZ[3];
1282 float shadow = 0;
1283 float value;
1284 int pixel = ibuf->x * y + x;
1285 float uv[2], *st0, *st1, *st2, *st3;
1286
1287 /* ideally we would work on triangles only, however, we rely on quads to get orthogonal
1288 * coordinates for use in grid space (triangle barycentric is not orthogonal) */
1289 if (face.size() == 4) {
1290 st0 = mloopuv[face[0]];
1291 st1 = mloopuv[face[1]];
1292 st2 = mloopuv[face[2]];
1293 st3 = mloopuv[face[3]];
1294 resolve_quad_uv_v2(uv, st, st0, st1, st2, st3);
1295 }
1296 else {
1297 st0 = mloopuv[tri[0]];
1298 st1 = mloopuv[tri[1]];
1299 st2 = mloopuv[tri[2]];
1300 resolve_tri_uv_v2(uv, st, st0, st1, st2);
1301 }
1302
1303 clamp_v2(uv, 0.0f, 1.0f);
1304
1306 lores_dm, hires_dm, ao_data->orig_index_mp_to_orig, lvl, tri, uv[0], uv[1], pos, nrm);
1307
1308 /* offset ray origin by user bias along normal */
1309 for (i = 0; i < 3; i++) {
1310 cen[i] = pos[i] + ao_data->bias * nrm[i];
1311 }
1312
1313 /* build tangent frame */
1314 for (i = 0; i < 3; i++) {
1315 axisZ[i] = nrm[i];
1316 }
1317
1318 build_coordinate_frame(axisX, axisY, axisZ);
1319
1320 /* static noise */
1321 perm_ofs = (get_ao_random2(get_ao_random1(x) + y)) & (MAX_NUMBER_OF_AO_RAYS - 1);
1322
1323 /* importance sample shadow rays (cosine weighted) */
1324 for (i = 0; i < ao_data->number_of_rays; i++) {
1325 int hit_something;
1326
1327 /* use N-Rooks to distribute our N ray samples across
1328 * a multi-dimensional domain (2D)
1329 */
1330 const ushort I = ao_data->permutation_table_1[(i + perm_ofs) % ao_data->number_of_rays];
1331 const ushort J = ao_data->permutation_table_2[i];
1332
1333 const float JitPh = (get_ao_random2(I + perm_ofs) & (MAX_NUMBER_OF_AO_RAYS - 1)) /
1334 float(MAX_NUMBER_OF_AO_RAYS);
1335 const float JitTh = (get_ao_random1(J + perm_ofs) & (MAX_NUMBER_OF_AO_RAYS - 1)) /
1336 float(MAX_NUMBER_OF_AO_RAYS);
1337 const float SiSqPhi = (I + JitPh) / ao_data->number_of_rays;
1338 const float Theta = float(2 * M_PI) * ((J + JitTh) / ao_data->number_of_rays);
1339
1340 /* this gives results identical to the so-called cosine
1341 * weighted distribution relative to the north pole.
1342 */
1343 float SiPhi = sqrtf(SiSqPhi);
1344 float CoPhi = SiSqPhi < 1.0f ? sqrtf(1.0f - SiSqPhi) : 0;
1345 float CoThe = cosf(Theta);
1346 float SiThe = sinf(Theta);
1347
1348 const float dx = CoThe * CoPhi;
1349 const float dy = SiThe * CoPhi;
1350 const float dz = SiPhi;
1351
1352 /* transform ray direction out of tangent frame */
1353 float dv[3];
1354 for (k = 0; k < 3; k++) {
1355 dv[k] = axisX[k] * dx + axisY[k] * dy + axisZ[k] * dz;
1356 }
1357
1358 hit_something = trace_ao_ray(ao_data, cen, dv);
1359
1360 if (hit_something != 0) {
1361 shadow += 1;
1362 }
1363 }
1364
1365 value = 1.0f - (shadow / ao_data->number_of_rays);
1366
1367 if (ibuf->rect_float) {
1368 float *rrgbf = ibuf->rect_float + pixel * 4;
1369 rrgbf[0] = rrgbf[1] = rrgbf[2] = value;
1370 rrgbf[3] = 1.0f;
1371 }
1372 else {
1373 uchar *rrgb = (uchar *)ibuf->rect + pixel * 4;
1374 rrgb[0] = rrgb[1] = rrgb[2] = unit_float_to_uchar_clamp(value);
1375 rrgb[3] = 255;
1376 }
1377}
1378#endif
1379
1380/* ******$***************** Post processing ************************* */
1381
1382static void bake_ibuf_filter(ImBuf *ibuf,
1383 char *mask,
1384 const int margin,
1385 const char margin_type,
1386 DerivedMesh *dm,
1387 const float uv_offset[2])
1388{
1389 /* must check before filtering */
1390 const bool is_new_alpha = (ibuf->planes != R_IMF_PLANES_RGBA) && BKE_imbuf_alpha_test(ibuf);
1391
1392 if (margin) {
1393 switch (margin_type) {
1395 RE_generate_texturemargin_adjacentfaces_dm(ibuf, mask, margin, dm, uv_offset);
1396 break;
1397 default:
1398 /* fall through */
1399 case R_BAKE_EXTEND:
1400 IMB_filter_extend(ibuf, mask, margin);
1401 break;
1402 }
1403 }
1404
1405 /* if the bake results in new alpha then change the image setting */
1406 if (is_new_alpha) {
1407 ibuf->planes = R_IMF_PLANES_RGBA;
1408 }
1409 else {
1410 if (margin && ibuf->planes != R_IMF_PLANES_RGBA) {
1411 /* clear alpha added by filtering */
1412 IMB_rectfill_alpha(ibuf, 1.0f);
1413 }
1414 }
1415}
1416
1418 const float *displacement,
1419 const char *mask,
1420 float displacement_min,
1421 float displacement_max)
1422{
1423 int i;
1424 const float *current_displacement = displacement;
1425 const char *current_mask = mask;
1426 float max_distance;
1427
1428 max_distance = max_ff(fabsf(displacement_min), fabsf(displacement_max));
1429
1430 for (i = 0; i < ibuf->x * ibuf->y; i++) {
1431 if (*current_mask == FILTER_MASK_USED) {
1432 float normalized_displacement;
1433
1434 if (max_distance > 1e-5f) {
1435 normalized_displacement = (*current_displacement + max_distance) / (max_distance * 2);
1436 }
1437 else {
1438 normalized_displacement = 0.5f;
1439 }
1440
1441 if (ibuf->float_buffer.data) {
1442 /* currently baking happens to RGBA only */
1443 float *fp = ibuf->float_buffer.data + i * 4;
1444 fp[0] = fp[1] = fp[2] = normalized_displacement;
1445 fp[3] = 1.0f;
1446 }
1447
1448 if (ibuf->byte_buffer.data) {
1449 uchar *cp = ibuf->byte_buffer.data + 4 * i;
1450 cp[0] = cp[1] = cp[2] = unit_float_to_uchar_clamp(normalized_displacement);
1451 cp[3] = 255;
1452 }
1453 }
1454
1455 current_displacement++;
1456 current_mask++;
1457 }
1458}
1459
1460/* **************** Common functions public API relates on **************** */
1461
1463{
1465 bkr->tot_image = 0;
1466
1467 for (int i = 0; i < bkr->ob_image.len; i++) {
1468 Image *ima = bkr->ob_image.array[i];
1469 if (ima) {
1470 ima->id.tag &= ~ID_TAG_DOIT;
1471 }
1472 }
1473
1474 for (int i = 0; i < bkr->ob_image.len; i++) {
1475 Image *ima = bkr->ob_image.array[i];
1476 if (ima) {
1477 if ((ima->id.tag & ID_TAG_DOIT) == 0) {
1478 LinkData *data = BLI_genericNodeN(ima);
1479 BLI_addtail(&bkr->image, data);
1480 bkr->tot_image++;
1481 ima->id.tag |= ID_TAG_DOIT;
1482 }
1483 }
1484 }
1485
1486 for (int i = 0; i < bkr->ob_image.len; i++) {
1487 Image *ima = bkr->ob_image.array[i];
1488 if (ima) {
1489 ima->id.tag &= ~ID_TAG_DOIT;
1490 }
1491 }
1492}
1493
1495{
1496 /* construct bake result */
1497 result->height_min = FLT_MAX;
1498 result->height_max = -FLT_MAX;
1499
1500 LISTBASE_FOREACH (LinkData *, link, &bkr->image) {
1501 Image *ima = (Image *)link->data;
1502
1503 LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
1504 ImageUser iuser;
1505 BKE_imageuser_default(&iuser);
1506 iuser.tile = tile->tile_number;
1507
1508 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, nullptr);
1509
1510 if (ibuf->x > 0 && ibuf->y > 0) {
1511 BakeImBufuserData *userdata = MEM_cnew<BakeImBufuserData>("MultiresBake userdata");
1512 userdata->mask_buffer = MEM_cnew_array<char>(ibuf->y * ibuf->x, "MultiresBake imbuf mask");
1513 ibuf->userdata = userdata;
1514
1515 switch (bkr->mode) {
1516 case RE_BAKE_NORMALS:
1517 do_multires_bake(bkr,
1518 ima,
1519 tile,
1520 ibuf,
1521 true,
1525 result);
1526 break;
1528 do_multires_bake(bkr,
1529 ima,
1530 tile,
1531 ibuf,
1532 false,
1536 result);
1537 break;
1538 /* TODO: restore ambient occlusion baking support. */
1539#if 0
1540 case RE_BAKE_AO:
1541 do_multires_bake(bkr,
1542 ima,
1543 tile,
1544 ibuf,
1545 false,
1546 apply_ao_callback,
1547 init_ao_data,
1548 free_ao_data,
1549 result);
1550 break;
1551#endif
1552 }
1553 }
1554
1555 BKE_image_release_ibuf(ima, ibuf, nullptr);
1556 }
1557
1558 ima->id.tag |= ID_TAG_DOIT;
1559 }
1560}
1561
1563{
1564 bool use_displacement_buffer = bkr->mode == RE_BAKE_DISPLACEMENT;
1565
1566 LISTBASE_FOREACH (LinkData *, link, &bkr->image) {
1567 Image *ima = (Image *)link->data;
1568
1569 LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
1570 ImageUser iuser;
1571 BKE_imageuser_default(&iuser);
1572 iuser.tile = tile->tile_number;
1573
1574 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, nullptr);
1575 BakeImBufuserData *userdata = (BakeImBufuserData *)ibuf->userdata;
1576
1577 if (ibuf->x <= 0 || ibuf->y <= 0) {
1578 continue;
1579 }
1580
1581 if (use_displacement_buffer) {
1583 userdata->displacement_buffer,
1584 userdata->mask_buffer,
1585 result->height_min,
1586 result->height_max);
1587 }
1588
1589 float uv_offset[2];
1590 BKE_image_get_tile_uv(ima, tile->tile_number, uv_offset);
1591
1592 bake_ibuf_filter(ibuf,
1593 userdata->mask_buffer,
1594 bkr->bake_margin,
1595 bkr->bake_margin_type,
1596 bkr->lores_dm,
1597 uv_offset);
1598
1600 BKE_image_mark_dirty(ima, ibuf);
1601
1602 if (ibuf->float_buffer.data) {
1603 ibuf->userflags |= IB_RECT_INVALID;
1604 }
1605
1606 if (ibuf->mipmap[0]) {
1608 imb_freemipmapImBuf(ibuf);
1609 }
1610
1611 if (ibuf->userdata) {
1612 if (userdata->displacement_buffer) {
1613 MEM_freeN(userdata->displacement_buffer);
1614 }
1615
1616 MEM_freeN(userdata->mask_buffer);
1617 MEM_freeN(userdata);
1618 ibuf->userdata = nullptr;
1619 }
1620
1621 BKE_image_release_ibuf(ima, ibuf, nullptr);
1622 DEG_id_tag_update(&ima->id, 0);
1623 }
1624 }
1625}
1626
1628{
1630
1631 count_images(bkr);
1632 bake_images(bkr, &result);
1633 finish_images(bkr, &result);
1634}
blender::float3 & CCG_grid_elem_no(const CCGKey &key, CCGElem *elem, int x, int y)
Definition BKE_ccg.hh:93
blender::float3 & CCG_grid_elem_co(const CCGKey &key, CCGElem *elem, int x, int y)
Definition BKE_ccg.hh:88
CustomData interface, see also DNA_customdata_types.h.
const void * CustomData_get_layer_named(const CustomData *data, eCustomDataType type, blender::StringRef name)
int CustomData_get_layer_index(const CustomData *data, eCustomDataType type)
ImBuf * BKE_image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock)
void BKE_image_mark_dirty(Image *image, ImBuf *ibuf)
void BKE_image_release_ibuf(Image *ima, ImBuf *ibuf, void *lock)
void BKE_image_get_tile_uv(const Image *ima, const int tile_number, float r_uv[2])
bool BKE_imbuf_alpha_test(ImBuf *ibuf)
void BKE_imageuser_default(ImageUser *iuser)
void BKE_id_free(Main *bmain, void *idv)
Mesh * BKE_mesh_new_nomain(int verts_num, int edges_num, int faces_num, int corners_num)
void * DM_get_loop_data_layer(DerivedMesh *dm, eCustomDataType type)
void BKE_mesh_calc_loop_tangent_ex(blender::Span< blender::float3 > vert_positions, blender::OffsetIndices< int > faces, const int *corner_verts, const blender::int3 *corner_tris, const int *corner_tri_faces, uint corner_tris_len, const blender::Span< bool > sharp_faces, const CustomData *loopdata, bool calc_active_tangent, const char(*tangent_names)[MAX_CUSTOMDATA_LAYER_NAME], int tangent_names_len, blender::Span< blender::float3 > vert_normals, blender::Span< blender::float3 > face_normals, blender::Span< blender::float3 > corner_normals, blender::Span< blender::float3 > vert_orco, CustomData *loopdata_out, uint loopdata_out_len, short *tangent_mask_curr_p)
int mdisp_rot_face_to_crn(int face_size, int face_side, float u, float v, float *x, float *y)
Definition multires.cc:1531
SubsurfFlags
DerivedMesh * subsurf_make_derived_from_derived(DerivedMesh *dm, SubsurfModifierData *smd, const Scene *scene, float(*vertCos)[3], SubsurfFlags flags)
#define BLI_assert(a)
Definition BLI_assert.h:50
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
struct LinkData * BLI_genericNodeN(void *data)
Definition listbase.cc:909
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
MINLINE float max_ff(float a, float b)
MINLINE float min_ff(float a, float b)
#define M_PI
void rgb_float_to_uchar(unsigned char r_col[3], const float col_f[3])
void resolve_tri_uv_v2(float r_uv[2], const float st[2], const float st0[2], const float st1[2], const float st2[2])
void resolve_quad_uv_v2(float r_uv[2], const float st[2], const float st0[2], const float st1[2], const float st2[2], const float st3[2])
void interp_barycentric_tri_v3(float data[3][3], float u, float v, float res[3])
void interp_bilinear_quad_v3(float data[4][3], float u, float v, float res[3])
bool invert_m3_m3(float inverse[3][3], const float mat[3][3])
void zero_m3(float m[3][3])
void mul_v3_m3v3(float r[3], const float M[3][3], const float a[3])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void clamp_v2(float vec[2], float min, float max)
MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE void add_v3_v3(float r[3], const float a[3])
MINLINE float normalize_v3_length(float n[3], float unit_length)
MINLINE float normalize_v3(float n[3])
unsigned char uchar
unsigned short ushort
unsigned int uint
pthread_spinlock_t SpinLock
void BLI_threadpool_init(struct ListBase *threadbase, void *(*do_thread)(void *), int tot)
Definition threads.cc:121
int BLI_system_thread_count(void)
Definition threads.cc:253
void BLI_threadpool_end(struct ListBase *threadbase)
Definition threads.cc:234
void BLI_spin_init(SpinLock *spin)
Definition threads.cc:391
void BLI_spin_unlock(SpinLock *spin)
Definition threads.cc:430
void BLI_spin_lock(SpinLock *spin)
Definition threads.cc:405
void BLI_threadpool_insert(struct ListBase *threadbase, void *callerdata)
Definition threads.cc:184
void BLI_spin_end(SpinLock *spin)
Definition threads.cc:445
#define CLAMP(a, b, c)
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_TAG_DOIT
Definition DNA_ID.h:1003
@ CD_PROP_INT32
@ CD_PROP_FLOAT2
@ SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES
@ R_BAKE_ADJACENT_FACES
@ R_BAKE_EXTEND
@ R_IMF_PLANES_RGBA
void IMB_rectfill_alpha(ImBuf *ibuf, float value)
Definition rectop.cc:1259
#define FILTER_MASK_USED
Definition IMB_imbuf.hh:378
void imb_freemipmapImBuf(ImBuf *ibuf)
void IMB_filter_extend(ImBuf *ibuf, char *mask, int filter)
Definition filter.cc:319
Contains defines and structs used throughout the imbuf module.
@ IB_RECT_INVALID
@ IB_MIPMAP_INVALID
@ IB_DISPLAY_BUFFER_INVALID
Read Guarded memory(de)allocation.
#define RE_BAKE_AO
#define RE_BAKE_NORMALS
#define RE_BAKE_DISPLACEMENT
ATTR_WARN_UNUSED_RESULT const BMVert * v
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
constexpr const T * data() const
Definition BLI_span.hh:216
constexpr int64_t size() const
Definition BLI_span.hh:253
#define sinf(x)
#define cosf(x)
#define ceilf(x)
#define fabsf(x)
#define sqrtf(x)
int len
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
uint col
ccl_global const KernelWorkTile * tile
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
#define unit_float_to_uchar_clamp(val)
ccl_device_inline float4 mask(const int4 mask, const float4 a)
static char faces[256]
#define G(x, y, z)
static void apply_heights_callback(const blender::Span< blender::float3 > vert_positions, const blender::Span< blender::float3 > vert_normals, const blender::OffsetIndices< int > faces, const blender::Span< int > corner_verts, const blender::Span< blender::int3 > corner_tris, const blender::Span< int > tri_faces, const blender::Span< blender::float2 > uv_map, DerivedMesh *hires_dm, void *thread_data_v, void *bake_data, ImBuf *ibuf, const int tri_index, const int lvl, const float st[2], float[3][3], const int x, const int y)
static void * init_normal_data(MultiresBakeRender *bkr, ImBuf *)
static void * init_heights_data(MultiresBakeRender *bkr, ImBuf *ibuf)
static int multiresbake_test_break(MultiresBakeRender *bkr)
void(*)(void *bake_data) MFreeBakeData
static void rasterize_half(const MBakeRast *bake_rast, const float s0_s, const float t0_s, const float s1_s, const float t1_s, const float s0_l, const float t0_l, const float s1_l, const float t1_l, const int y0_in, const int y1_in, const int is_mid_right)
static void bake_ibuf_normalize_displacement(ImBuf *ibuf, const float *displacement, const char *mask, float displacement_min, float displacement_max)
static void bake_images(MultiresBakeRender *bkr, MultiresBakeResult *result)
static void count_images(MultiresBakeRender *bkr)
static void interp_bilinear_mpoly(const blender::Span< blender::float3 > vert_positions, const blender::Span< blender::float3 > vert_normals, const blender::Span< int > corner_verts, const blender::IndexRange face, const float u, const float v, const int mode, float res[3])
static void finish_images(MultiresBakeRender *bkr, MultiresBakeResult *result)
static void multiresbake_get_normal(const MResolvePixelData *data, const int tri_num, const int vert_index, float r_normal[3])
static void init_ccgdm_arrays(DerivedMesh *dm)
static void set_rast_triangle(const MBakeRast *bake_rast, const int x, const int y)
static void get_ccgdm_data(const blender::OffsetIndices< int > lores_polys, DerivedMesh *hidm, const int *index_mp_to_orig, const int lvl, const int face_index, const float u, const float v, float co[3], float n[3])
void *(*)(MultiresBakeRender *bkr, ImBuf *ibuf) MInitBakeData
void(*)(const MResolvePixelData *data, const int x, const int y) MFlushPixel
static void * do_multires_bake_thread(void *data_v)
void(*)(blender::Span< blender::float3 > vert_positions, blender::Span< blender::float3 > vert_normals, blender::OffsetIndices< int > faces, blender::Span< int > corner_verts, blender::Span< blender::int3 > corner_tris, blender::Span< int > tri_faces, blender::Span< blender::float2 > uv_map, DerivedMesh *hires_dm, void *thread_data, 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) MPassKnownData
static void free_normal_data(void *bake_data)
static void bake_rasterize(const MBakeRast *bake_rast, const float st0_in[2], const float st1_in[2], const float st2_in[2])
void RE_multires_bake_images(MultiresBakeRender *bkr)
static int multires_bake_queue_next_tri(MultiresBakeQueue *queue)
static void flush_pixel(const MResolvePixelData *data, const int x, const int y)
static void init_bake_rast(MBakeRast *bake_rast, const ImBuf *ibuf, const MResolvePixelData *data, MFlushPixel flush_pixel, bool *do_update)
static void interp_barycentric_corner_tri(const blender::Span< blender::float3 > vert_positions, const blender::Span< blender::float3 > vert_normals, const blender::Span< int > corner_verts, const blender::int3 &corner_tri, const float u, const float v, const int mode, float res[3])
static void bake_ibuf_filter(ImBuf *ibuf, char *mask, const int margin, const char margin_type, DerivedMesh *dm, const float uv_offset[2])
static void free_heights_data(void *bake_data)
static void do_multires_bake(MultiresBakeRender *bkr, Image *ima, ImageTile *tile, ImBuf *ibuf, bool require_tangent, MPassKnownData passKnownData, MInitBakeData initBakeData, MFreeBakeData freeBakeData, MultiresBakeResult *result)
static void interp_bilinear_grid(const CCGKey &key, CCGElem *grid, float crn_x, float crn_y, int mode, float res[3])
static void apply_tangmat_callback(const blender::Span< blender::float3 >, const blender::Span< blender::float3 >, const blender::OffsetIndices< int > faces, const blender::Span< int >, const blender::Span< blender::int3 > corner_tris, const blender::Span< int > tri_faces, const blender::Span< blender::float2 > uv_map, DerivedMesh *hires_dm, void *, void *bake_data, ImBuf *ibuf, const int tri_index, const int lvl, const float st[2], float tangmat[3][3], const int x, const int y)
#define I
#define FLT_MAX
Definition stdcycles.h:14
int grid_size
Definition BKE_ccg.hh:33
int(* getGridSize)(DerivedMesh *dm)
int *(* getPolyArray)(DerivedMesh *dm)
int(* getNumVerts)(DerivedMesh *dm)
int *(* getCornerVertArray)(DerivedMesh *dm)
void *(* getPolyDataArray)(DerivedMesh *dm, eCustomDataType type)
int(* getNumPolys)(DerivedMesh *dm)
int(* getNumEdges)(DerivedMesh *dm)
void *(* getVertDataArray)(DerivedMesh *dm, eCustomDataType type)
int(* getNumGrids)(DerivedMesh *dm)
float *(* getVertArray)(DerivedMesh *dm)
int *(* getGridOffset)(DerivedMesh *dm)
void *(* getLoopDataArray)(DerivedMesh *dm, eCustomDataType type)
blender::int2 *(* getEdgeArray)(DerivedMesh *dm)
CCGElem **(* getGridData)(DerivedMesh *dm)
int *(* getCornerEdgeArray)(DerivedMesh *dm)
void(* release)(DerivedMesh *dm)
void(* getGridKey)(DerivedMesh *dm, CCGKey *key)
int(* getNumLoops)(DerivedMesh *dm)
int tag
Definition DNA_ID.h:434
void * userdata
ImBufFloatBuffer float_buffer
ImBufByteBuffer byte_buffer
unsigned char planes
ImBuf * mipmap[IMB_MIPMAP_LEVELS]
ListBase tiles
bool * do_update
MFlushPixel flush_pixel
const MResolvePixelData * data
DerivedMesh * ssdm
const int * orig_index_mp_to_orig
const int * orig_index_mp_to_orig
const int * material_indices
blender::Span< blender::float3 > vert_positions
blender::Span< blender::float3 > face_normals
blender::OffsetIndices< int > faces
blender::Span< blender::float2 > uv_map
blender::Span< blender::float3 > vert_normals
DerivedMesh * hires_dm
blender::Span< int > tri_faces
MPassKnownData pass_data
const bool * sharp_faces
blender::Span< blender::int3 > corner_tris
blender::Span< int > corner_verts
int corners_num
int edges_num
int faces_num
int verts_num
DerivedMesh * hires_dm
DerivedMesh * lores_dm
struct MultiresBakeRender::@1362 ob_image
MultiresBakeQueue * queue
MResolvePixelData data
MultiresBakeRender * bkr
void RE_generate_texturemargin_adjacentfaces_dm(ImBuf *ibuf, char *mask, const int margin, DerivedMesh *dm, const float uv_offset[2])
ParamHandle ** handles