Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeroen Bakker <jeroen@blender.org>2022-03-08 17:17:33 +0300
committerJeroen Bakker <jeroen@blender.org>2022-03-08 17:17:33 +0300
commit0cd7177420959f6caf6eab08145e32fe085c685f (patch)
tree8de10e7e4a2639ac3f5a903138a72ef3af2ae865
parent62294c5b37eeaa552cdffc22abd70a7a9cbf8405 (diff)
Use different rasterization.
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c9
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h1
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_texture_paint_b.cc311
3 files changed, 303 insertions, 18 deletions
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index f6b334f2175..f19c3c66c9a 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -3171,6 +3171,10 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
return;
}
+ if (brush->sculpt_tool == SCULPT_TOOL_TEXTURE_PAINT && type != PBVH_FACES) {
+ return;
+ }
+
/* Build a list of all nodes that are potentially within the brush's area of influence */
if (SCULPT_tool_needs_all_pbvh_nodes(brush)) {
@@ -3216,6 +3220,11 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
}
}
+ if (brush->sculpt_tool == SCULPT_TOOL_TEXTURE_PAINT) {
+ /* TODO should perhaps move to higher level.... doing this per step is not needed. */
+ SCULPT_init_texture_paint(ob);
+ }
+
/* For anchored brushes with spherical falloff, we start off with zero radius, thus we have no
* PBVH nodes on the first brush step. */
if (totnode ||
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index 39aaf4d1276..93bb8fb4fe3 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -1614,6 +1614,7 @@ void SCULPT_do_draw_face_sets_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, in
/* Paint Brush. */
void SCULPT_do_paint_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
void SCULPT_do_texture_paint_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
+void SCULPT_init_texture_paint(Object *ob);
void SCULPT_flush_texture_paint(Object *ob);
/* Smear Brush. */
diff --git a/source/blender/editors/sculpt_paint/sculpt_texture_paint_b.cc b/source/blender/editors/sculpt_paint/sculpt_texture_paint_b.cc
index 05708cc47bb..de450b061f4 100644
--- a/source/blender/editors/sculpt_paint/sculpt_texture_paint_b.cc
+++ b/source/blender/editors/sculpt_paint/sculpt_texture_paint_b.cc
@@ -60,20 +60,18 @@ struct NodeData {
BLI_rcti_init_minmax(&dirty_region);
}
- void init_pixels(Object *ob, PBVHNode *node, ImBuf *image_buffer);
+ void init_pixels_rasterization(Object *ob, PBVHNode *node, ImBuf *image_buffer);
+
void flush(ImBuf &image_buffer)
{
flags.dirty = false;
- int pixels_flushed = 0;
for (PixelData &pixel : pixels) {
if (pixel.flags.dirty) {
const int pixel_offset = (pixel.pixel_pos[1] * image_buffer.x + pixel.pixel_pos[0]) * 4;
copy_v4_v4(&image_buffer.rect_float[pixel_offset], pixel.content);
pixel.flags.dirty = false;
- pixels_flushed += 1;
}
}
- printf("%s: %d pixels flushed\n", __func__, pixels_flushed);
}
void mark_region(Image &image, ImBuf &image_buffer)
@@ -198,9 +196,8 @@ using RasterizerType = Rasterizer<VertexShader, FragmentShader, AddPixel, NodeDa
} // namespace shaders
-void NodeData::init_pixels(Object *ob, PBVHNode *node, ImBuf *image_buffer)
+void NodeData::init_pixels_rasterization(Object *ob, PBVHNode *node, ImBuf *image_buffer)
{
- printf("%s\n", __func__);
Mesh *mesh = static_cast<Mesh *>(ob->data);
MLoopUV *ldata_uv = static_cast<MLoopUV *>(CustomData_get_layer(&mesh->ldata, CD_MLOOPUV));
if (ldata_uv == nullptr) {
@@ -228,7 +225,6 @@ void NodeData::init_pixels(Object *ob, PBVHNode *node, ImBuf *image_buffer)
}
const MLoop *loopstart = &ss->mloop[p->loopstart];
-
for (int triangle = 0; triangle < p->totloop - 2; triangle++) {
const int v1_index = loopstart[0].v;
const int v2_index = loopstart[triangle + 1].v;
@@ -264,6 +260,7 @@ static void do_task_cb_ex(void *__restrict userdata,
const Brush *brush = data->brush;
PBVHNode *node = data->nodes[n];
NodeData *node_data = static_cast<NodeData *>(BKE_pbvh_node_texture_paint_data_get(node));
+ BLI_assert(node_data != nullptr);
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
@@ -275,10 +272,274 @@ static void do_task_cb_ex(void *__restrict userdata,
}
const float falloff_strength = BKE_brush_curve_strength(brush, sqrtf(test.dist), test.radius);
interp_v3_v3v3(pixel.content, pixel.content, brush->rgb, falloff_strength);
+ pixel.content[3] = 1.0f;
pixel.flags.dirty = true;
BLI_rcti_do_minmax_v(&node_data->dirty_region, pixel.pixel_pos);
+ node_data->flags.dirty = true;
}
- node_data->flags.dirty = true;
+}
+
+static void init_rasterization_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ TexturePaintingUserData *data = static_cast<TexturePaintingUserData *>(userdata);
+ Object *ob = data->ob;
+ SculptSession *ss = ob->sculpt;
+ PBVHNode *node = data->nodes[n];
+
+ NodeData *node_data = static_cast<NodeData *>(BKE_pbvh_node_texture_paint_data_get(node));
+ // TODO: reinit when texturing on different image?
+ if (node_data != nullptr) {
+ return;
+ }
+
+ TIMEIT_START(init_texture_paint_for_node);
+ node_data = MEM_new<NodeData>(__func__);
+ node_data->init_pixels_rasterization(ob, node, ss->mode.texture_paint.drawing_target);
+ BKE_pbvh_node_texture_paint_data_set(node, node_data, NodeData::free_func);
+ TIMEIT_END(init_texture_paint_for_node);
+}
+
+static void init_using_rasterization(Object *ob, int totnode, PBVHNode **nodes)
+{
+ TIMEIT_START(init_using_rasterization);
+ TexturePaintingUserData data = {nullptr};
+ data.ob = ob;
+ data.nodes = nodes;
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+
+ BLI_task_parallel_range(0, totnode, &data, init_rasterization_task_cb_ex, &settings);
+ TIMEIT_END(init_using_rasterization);
+}
+
+struct BucketEntry {
+ PBVHNode *node;
+ const MPoly *poly;
+};
+struct Bucket {
+ static const int Size = 16;
+ Vector<BucketEntry> entries;
+ rctf bounds;
+};
+
+static bool init_using_intersection(SculptSession *ss,
+ Bucket &bucket,
+ ImBuf *image_buffer,
+ MVert *mvert,
+ MLoopUV *ldata_uv,
+ float2 uv,
+ int2 xy)
+{
+ const int pixel_offset = xy[1] * image_buffer->x + xy[0];
+ for (BucketEntry &entry : bucket.entries) {
+ const MPoly *p = entry.poly;
+
+ const MLoop *loopstart = &ss->mloop[p->loopstart];
+ for (int triangle = 0; triangle < p->totloop - 2; triangle++) {
+ const int v1_loop_index = p->loopstart;
+ const int v2_loop_index = p->loopstart + triangle + 1;
+ const int v3_loop_index = p->loopstart + triangle + 2;
+ const float2 v1_uv = ldata_uv[v1_loop_index].uv;
+ const float2 v2_uv = ldata_uv[v2_loop_index].uv;
+ const float2 v3_uv = ldata_uv[v3_loop_index].uv;
+ float3 weights;
+ barycentric_weights_v2(v1_uv, v2_uv, v3_uv, uv, weights);
+ if (weights[0] < 0.0 || weights[0] > 1.0 || weights[1] < 0.0 || weights[1] > 1.0 ||
+ weights[2] < 0.0 || weights[2] > 1.0) {
+ continue;
+ }
+
+ const int v1_index = loopstart[0].v;
+ const int v2_index = loopstart[triangle + 1].v;
+ const int v3_index = loopstart[triangle + 2].v;
+ const float3 v1_pos = mvert[v1_index].co;
+ const float3 v2_pos = mvert[v2_index].co;
+ const float3 v3_pos = mvert[v3_index].co;
+ float3 local_pos;
+ interp_v3_v3v3v3(local_pos, v1_pos, v2_pos, v3_pos, weights);
+
+ PixelData new_pixel;
+ new_pixel.local_pos = local_pos;
+ new_pixel.pixel_pos = xy;
+ copy_v4_fl(&image_buffer->rect_float[pixel_offset * 4], 1.0);
+ new_pixel.content = float4(image_buffer->rect_float[pixel_offset * 4]);
+ new_pixel.flags.dirty = false;
+
+ PBVHNode *node = entry.node;
+ NodeData *node_data = static_cast<NodeData *>(BKE_pbvh_node_texture_paint_data_get(node));
+ node_data->pixels.append(new_pixel);
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool init_using_intersection(SculptSession *ss,
+ PBVHNode *node,
+ NodeData *node_data,
+ ImBuf *image_buffer,
+ MVert *mvert,
+ MLoopUV *ldata_uv,
+ float2 uv,
+ int2 xy)
+{
+ const int pixel_offset = xy[1] * image_buffer->x + xy[0];
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
+ MeshElemMap *vert_map = &ss->pmap[vd.index];
+ for (int j = 0; j < ss->pmap[vd.index].count; j++) {
+ const MPoly *p = &ss->mpoly[vert_map->indices[j]];
+ if (p->totloop < 3) {
+ continue;
+ }
+
+ const MLoop *loopstart = &ss->mloop[p->loopstart];
+ for (int triangle = 0; triangle < p->totloop - 2; triangle++) {
+ const int v1_loop_index = p->loopstart;
+ const int v2_loop_index = p->loopstart + triangle + 1;
+ const int v3_loop_index = p->loopstart + triangle + 2;
+ const float2 v1_uv = ldata_uv[v1_loop_index].uv;
+ const float2 v2_uv = ldata_uv[v2_loop_index].uv;
+ const float2 v3_uv = ldata_uv[v3_loop_index].uv;
+ float3 weights;
+ barycentric_weights_v2(v1_uv, v2_uv, v3_uv, uv, weights);
+ if (weights[0] < 0.0 || weights[0] > 1.0 || weights[1] < 0.0 || weights[1] > 1.0 ||
+ weights[2] < 0.0 || weights[2] > 1.0) {
+ continue;
+ }
+
+ const int v1_index = loopstart[0].v;
+ const int v2_index = loopstart[triangle + 1].v;
+ const int v3_index = loopstart[triangle + 2].v;
+ const float3 v1_pos = mvert[v1_index].co;
+ const float3 v2_pos = mvert[v2_index].co;
+ const float3 v3_pos = mvert[v3_index].co;
+ float3 local_pos;
+ interp_v2_v2v2v2(local_pos, v1_pos, v2_pos, v3_pos, weights);
+
+ PixelData new_pixel;
+ new_pixel.local_pos = local_pos;
+ new_pixel.pixel_pos = xy;
+ new_pixel.content = float4(image_buffer->rect_float[pixel_offset * 4]);
+ copy_v4_fl(&image_buffer->rect_float[pixel_offset * 4], 1.0);
+ new_pixel.flags.dirty = false;
+ node_data->pixels.append(new_pixel);
+ return true;
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+
+ return false;
+}
+
+static void init_using_intersection(Object *ob, int totnode, PBVHNode **nodes)
+{
+ TIMEIT_START(init_using_intersection);
+
+ Vector<PBVHNode *> nodes_to_initialize;
+ for (int n = 0; n < totnode; n++) {
+ PBVHNode *node = nodes[n];
+ NodeData *node_data = static_cast<NodeData *>(BKE_pbvh_node_texture_paint_data_get(node));
+ if (node_data != nullptr) {
+ continue;
+ }
+ node_data = MEM_new<NodeData>(__func__);
+ BKE_pbvh_node_texture_paint_data_set(node, node_data, NodeData::free_func);
+ nodes_to_initialize.append(node);
+ }
+ if (nodes_to_initialize.size() == 0) {
+ return;
+ }
+
+ Mesh *mesh = static_cast<Mesh *>(ob->data);
+ MLoopUV *ldata_uv = static_cast<MLoopUV *>(CustomData_get_layer(&mesh->ldata, CD_MLOOPUV));
+ if (ldata_uv == nullptr) {
+ return;
+ }
+
+ SculptSession *ss = ob->sculpt;
+ MVert *mvert = SCULPT_mesh_deformed_mverts_get(ss);
+ ImBuf *image_buffer = ss->mode.texture_paint.drawing_target;
+ int pixels_added = 0;
+ Bucket bucket;
+ for (int y_bucket = 0; y_bucket < image_buffer->y; y_bucket += Bucket::Size) {
+ for (int x_bucket = 0; x_bucket < image_buffer->x; x_bucket += Bucket::Size) {
+ bucket.entries.clear();
+ BLI_rctf_init(&bucket.bounds,
+ float(x_bucket) / image_buffer->x,
+ float(x_bucket + Bucket::Size) / image_buffer->x,
+ float(y_bucket) / image_buffer->y,
+ float(y_bucket + Bucket::Size) / image_buffer->y);
+ print_rctf_id(&bucket.bounds);
+ printf("%d pixels already added.\n", pixels_added);
+
+ for (int n = 0; n < nodes_to_initialize.size(); n++) {
+ PBVHNode *node = nodes_to_initialize[n];
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
+ MeshElemMap *vert_map = &ss->pmap[vd.index];
+ for (int j = 0; j < ss->pmap[vd.index].count; j++) {
+ const MPoly *p = &ss->mpoly[vert_map->indices[j]];
+ if (p->totloop < 3) {
+ continue;
+ }
+
+ rctf poly_bound;
+ BLI_rctf_init_minmax(&poly_bound);
+ for (int triangle = 0; triangle < p->totloop - 2; triangle++) {
+ const int v1_loop_index = p->loopstart;
+ const int v2_loop_index = p->loopstart + triangle + 1;
+ const int v3_loop_index = p->loopstart + triangle + 2;
+ const float2 v1_uv = ldata_uv[v1_loop_index].uv;
+ const float2 v2_uv = ldata_uv[v2_loop_index].uv;
+ const float2 v3_uv = ldata_uv[v3_loop_index].uv;
+ BLI_rctf_do_minmax_v(&poly_bound, v1_uv);
+ BLI_rctf_do_minmax_v(&poly_bound, v2_uv);
+ BLI_rctf_do_minmax_v(&poly_bound, v3_uv);
+ }
+ if (BLI_rctf_isect(&bucket.bounds, &poly_bound, nullptr)) {
+ BucketEntry entry;
+ entry.node = node;
+ entry.poly = p;
+ bucket.entries.append(entry);
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+ }
+ printf("Loaded %ld entries in bucket\n", bucket.entries.size());
+ if (bucket.entries.size() == 0) {
+ continue;
+ }
+
+ for (int y = y_bucket; y < image_buffer->y && y < y_bucket + Bucket::Size; y++) {
+ for (int x = x_bucket; x < image_buffer->x && x < x_bucket + Bucket::Size; x++) {
+ float2 uv(float(x) / image_buffer->x, float(y) / image_buffer->y);
+#if 0
+ for (int n = 0; n < nodes_to_initialize.size(); n++) {
+ PBVHNode *node = nodes_to_initialize[n];
+ NodeData *node_data = static_cast<NodeData *>(
+ BKE_pbvh_node_texture_paint_data_get(node));
+ if (init_using_intersection(
+ ss, node, node_data, image_buffer, mvert, ldata_uv, uv, int2(x, y))) {
+ pixels_added++;
+ break;
+ }
+ }
+#else
+ if (init_using_intersection(ss, bucket, image_buffer, mvert, ldata_uv, uv, int2(x, y))) {
+ pixels_added++;
+ }
+#endif
+ }
+ }
+ }
+ }
+ TIMEIT_END(init_using_intersection);
}
struct ImageData {
@@ -319,16 +580,6 @@ void SCULPT_do_texture_paint_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int
return;
}
- for (int n = 0; n < totnode; n++) {
- PBVHNode *node = nodes[n];
- NodeData *data = static_cast<NodeData *>(BKE_pbvh_node_texture_paint_data_get(node));
- if (data == nullptr) {
- NodeData *node_data = MEM_new<NodeData>(__func__);
- node_data->init_pixels(ob, node, image_data.image_buffer);
- BKE_pbvh_node_texture_paint_data_set(node, node_data, NodeData::free_func);
- }
- }
-
ss->mode.texture_paint.drawing_target = image_data.image_buffer;
TexturePaintingUserData data = {nullptr};
@@ -346,6 +597,30 @@ void SCULPT_do_texture_paint_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int
ss->mode.texture_paint.drawing_target = nullptr;
}
+void SCULPT_init_texture_paint(Object *ob)
+{
+ SculptSession *ss = ob->sculpt;
+ ImageData image_data;
+ if (!ImageData::init_active_image(ob, &image_data)) {
+ return;
+ }
+ ss->mode.texture_paint.drawing_target = image_data.image_buffer;
+ PBVHNode **nodes;
+ int totnode;
+ BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
+ const bool do_rasterization = false;
+ if (do_rasterization) {
+ init_using_rasterization(ob, totnode, nodes);
+ }
+ else {
+ init_using_intersection(ob, totnode, nodes);
+ }
+
+ MEM_freeN(nodes);
+
+ ss->mode.texture_paint.drawing_target = nullptr;
+}
+
void SCULPT_flush_texture_paint(Object *ob)
{
ImageData image_data;