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:
-rw-r--r--release/scripts/presets/keyconfig/keymap_data/blender_default.py1
-rw-r--r--source/blender/editors/object/CMakeLists.txt1
-rw-r--r--source/blender/editors/object/object_intern.h1
-rw-r--r--source/blender/editors/object/object_ops.c2
-rw-r--r--source/blender/editors/object/object_remesh.c410
5 files changed, 411 insertions, 4 deletions
diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
index 22b62d27684..971c702aeac 100644
--- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py
+++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
@@ -4323,6 +4323,7 @@ def km_sculpt(params):
("sculpt.set_detail_size", {"type": 'D', "value": 'PRESS', "shift": True}, None),
# Remesh
("object.voxel_remesh", {"type": 'R', "value": 'PRESS', "ctrl": True}, None),
+ ("object.voxel_size_edit", {"type": 'R', "value": 'PRESS', "shift": True}, None),
("object.quadriflow_remesh", {"type": 'R', "value": 'PRESS', "ctrl": True, "alt": True}, None),
# Brush properties
("brush.scale_size", {"type": 'LEFT_BRACKET', "value": 'PRESS'},
diff --git a/source/blender/editors/object/CMakeLists.txt b/source/blender/editors/object/CMakeLists.txt
index a5b6fa55aa9..c2c25e47908 100644
--- a/source/blender/editors/object/CMakeLists.txt
+++ b/source/blender/editors/object/CMakeLists.txt
@@ -18,6 +18,7 @@
set(INC
../include
../../blenkernel
+ ../../blenfont
../../blenlib
../../blentranslation
../../bmesh
diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h
index 559bb434f9d..d8ba270073e 100644
--- a/source/blender/editors/object/object_intern.h
+++ b/source/blender/editors/object/object_intern.h
@@ -291,6 +291,7 @@ void TRANSFORM_OT_vertex_random(struct wmOperatorType *ot);
/* object_remesh.c */
void OBJECT_OT_voxel_remesh(struct wmOperatorType *ot);
+void OBJECT_OT_voxel_size_edit(struct wmOperatorType *ot);
void OBJECT_OT_quadriflow_remesh(struct wmOperatorType *ot);
/* object_transfer_data.c */
diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c
index cacf7b67777..fef046169a7 100644
--- a/source/blender/editors/object/object_ops.c
+++ b/source/blender/editors/object/object_ops.c
@@ -265,6 +265,8 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_hide_collection);
WM_operatortype_append(OBJECT_OT_voxel_remesh);
+ WM_operatortype_append(OBJECT_OT_voxel_size_edit);
+
WM_operatortype_append(OBJECT_OT_quadriflow_remesh);
}
diff --git a/source/blender/editors/object/object_remesh.c b/source/blender/editors/object/object_remesh.c
index a9f2319d926..08c44b87664 100644
--- a/source/blender/editors/object/object_remesh.c
+++ b/source/blender/editors/object/object_remesh.c
@@ -37,6 +37,9 @@
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BLT_translation.h"
#include "BKE_context.h"
#include "BKE_customdata.h"
@@ -61,17 +64,29 @@
#include "ED_object.h"
#include "ED_screen.h"
#include "ED_sculpt.h"
+#include "ED_space_api.h"
#include "ED_undo.h"
+#include "ED_view3d.h"
#include "RNA_access.h"
#include "RNA_define.h"
#include "RNA_enum_types.h"
+#include "GPU_draw.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
+
#include "WM_api.h"
#include "WM_message.h"
#include "WM_toolsystem.h"
#include "WM_types.h"
+#include "UI_interface.h"
+
+#include "BLF_api.h"
+
#include "object_intern.h" // own include
/* TODO(sebpa): unstable, can lead to unrecoverable errors. */
@@ -188,16 +203,403 @@ void OBJECT_OT_voxel_remesh(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+#define VOXEL_SIZE_EDIT_MAX_GRIDS_LINES 500
+#define VOXEL_SIZE_EDIT_MAX_STR_LEN 20
+
+typedef struct VoxelSizeEditCustomData {
+ void *draw_handle;
+ Object *active_object;
+
+ float init_mval[2];
+ float slow_mval[2];
+
+ bool slow_mode;
+
+ float init_voxel_size;
+ float slow_voxel_size;
+ float voxel_size;
+
+ float preview_plane[4][3];
+
+ float text_mat[4][4];
+} VoxelSizeEditCustomData;
+
+static void voxel_size_parallel_lines_draw(uint pos3d,
+ const float initial_co[3],
+ const float end_co[3],
+ const float length_co[3],
+ const float spacing)
+{
+ const float total_len = len_v3v3(initial_co, end_co);
+ const int tot_lines = (int)(total_len / spacing);
+ const int tot_lines_half = (tot_lines / 2) + 1;
+ float spacing_dir[3], lines_start[3];
+ float line_dir[3];
+ sub_v3_v3v3(spacing_dir, end_co, initial_co);
+ normalize_v3(spacing_dir);
+
+ sub_v3_v3v3(line_dir, length_co, initial_co);
+
+ if (tot_lines > VOXEL_SIZE_EDIT_MAX_GRIDS_LINES || tot_lines <= 1) {
+ return;
+ }
+
+ mid_v3_v3v3(lines_start, initial_co, end_co);
+
+ immBegin(GPU_PRIM_LINES, (uint)tot_lines_half * 2);
+ for (int i = 0; i < tot_lines_half; i++) {
+ float line_start[3];
+ float line_end[3];
+ madd_v3_v3v3fl(line_start, lines_start, spacing_dir, spacing * i);
+ add_v3_v3v3(line_end, line_start, line_dir);
+ immVertex3fv(pos3d, line_start);
+ immVertex3fv(pos3d, line_end);
+ }
+ immEnd();
+
+ mul_v3_fl(spacing_dir, -1.0f);
+
+ immBegin(GPU_PRIM_LINES, (uint)(tot_lines_half - 1) * 2);
+ for (int i = 1; i < tot_lines_half; i++) {
+ float line_start[3];
+ float line_end[3];
+ madd_v3_v3v3fl(line_start, lines_start, spacing_dir, spacing * i);
+ add_v3_v3v3(line_end, line_start, line_dir);
+ immVertex3fv(pos3d, line_start);
+ immVertex3fv(pos3d, line_end);
+ }
+ immEnd();
+}
+
+static void voxel_size_edit_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg)
+{
+ VoxelSizeEditCustomData *cd = arg;
+
+ GPU_blend(true);
+ GPU_line_smooth(true);
+
+ uint pos3d = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ GPU_matrix_push();
+ GPU_matrix_mul(cd->active_object->obmat);
+
+ /* Draw Rect */
+ immUniformColor4f(0.9f, 0.9f, 0.9f, 0.8f);
+ GPU_line_width(3.0f);
+
+ immBegin(GPU_PRIM_LINES, 8);
+ immVertex3fv(pos3d, cd->preview_plane[0]);
+ immVertex3fv(pos3d, cd->preview_plane[1]);
+
+ immVertex3fv(pos3d, cd->preview_plane[1]);
+ immVertex3fv(pos3d, cd->preview_plane[2]);
+
+ immVertex3fv(pos3d, cd->preview_plane[2]);
+ immVertex3fv(pos3d, cd->preview_plane[3]);
+
+ immVertex3fv(pos3d, cd->preview_plane[3]);
+ immVertex3fv(pos3d, cd->preview_plane[0]);
+ immEnd();
+
+ /* Draw Grid */
+ GPU_line_width(1.0f);
+
+ const float total_len = len_v3v3(cd->preview_plane[0], cd->preview_plane[1]);
+ const int tot_lines = (int)(total_len / cd->voxel_size);
+
+ /* Smoothstep to reduce the alpha of the grid as the line number increases. */
+ const float a = VOXEL_SIZE_EDIT_MAX_GRIDS_LINES * 0.1f;
+ const float b = VOXEL_SIZE_EDIT_MAX_GRIDS_LINES;
+ const float x = clamp_f((tot_lines - a) / (b - a), 0.0f, 1.0);
+ const float alpha_factor = 1.0f - (x * x * (3.0f - 2.0f * x));
+
+ immUniformColor4f(0.9f, 0.9f, 0.9f, 0.75f * alpha_factor);
+ voxel_size_parallel_lines_draw(
+ pos3d, cd->preview_plane[0], cd->preview_plane[1], cd->preview_plane[3], cd->voxel_size);
+ voxel_size_parallel_lines_draw(
+ pos3d, cd->preview_plane[1], cd->preview_plane[2], cd->preview_plane[0], cd->voxel_size);
+
+ /* Draw text */
+ uiStyle *style = UI_style_get();
+ const uiFontStyle *fstyle = &style->widget;
+ const int fontid = fstyle->uifont_id;
+ float strwidth, strheight;
+ short fstyle_points = fstyle->points;
+ char str[VOXEL_SIZE_EDIT_MAX_STR_LEN];
+ short strdrawlen = 0;
+
+ BLI_snprintf(str, VOXEL_SIZE_EDIT_MAX_STR_LEN, "%3.4f%%", cd->voxel_size);
+ strdrawlen = BLI_strlen_utf8(str);
+
+ immUnbindProgram();
+
+ GPU_matrix_push();
+ GPU_matrix_mul(cd->text_mat);
+ BLF_size(fontid, 10.0f * fstyle_points, U.dpi);
+ BLF_color3f(fontid, 1.0f, 1.0f, 1.0f);
+ BLF_width_and_height(fontid, str, strdrawlen, &strwidth, &strheight);
+ BLF_position(fontid, -0.5f * strwidth, -0.5f * strheight, 0.0f);
+ BLF_draw(fontid, str, strdrawlen);
+ GPU_matrix_pop();
+
+ GPU_matrix_pop();
+
+ GPU_blend(false);
+ GPU_line_smooth(false);
+}
+
+static void voxel_size_edit_cancel(bContext *C, wmOperator *op)
+{
+ ARegion *ar = CTX_wm_region(C);
+ VoxelSizeEditCustomData *cd = op->customdata;
+
+ ED_region_draw_cb_exit(ar->type, cd->draw_handle);
+
+ MEM_freeN(op->customdata);
+
+ ED_workspace_status_text(C, NULL);
+}
+
+static int voxel_size_edit_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ ARegion *ar = CTX_wm_region(C);
+ VoxelSizeEditCustomData *cd = op->customdata;
+ Object *active_object = cd->active_object;
+ Mesh *mesh = (Mesh *)active_object->data;
+
+ /* Cancel modal operator */
+ if ((event->type == EVT_ESCKEY && event->val == KM_PRESS) ||
+ (event->type == RIGHTMOUSE && event->val == KM_PRESS)) {
+ voxel_size_edit_cancel(C, op);
+ ED_region_tag_redraw(ar);
+ return OPERATOR_FINISHED;
+ }
+
+ /* Finish modal operator */
+ if ((event->type == LEFTMOUSE && event->val == KM_RELEASE) ||
+ (event->type == EVT_RETKEY && event->val == KM_PRESS) ||
+ (event->type == EVT_PADENTER && event->val == KM_PRESS)) {
+ ED_region_draw_cb_exit(ar->type, cd->draw_handle);
+ mesh->remesh_voxel_size = cd->voxel_size;
+ MEM_freeN(op->customdata);
+ ED_region_tag_redraw(ar);
+ return OPERATOR_FINISHED;
+ }
+
+ float mval[2] = {event->mval[0], event->mval[1]};
+
+ float d = cd->init_mval[0] - mval[0];
+
+ if (cd->slow_mode) {
+ d = cd->slow_mval[0] - mval[0];
+ }
+
+ if (event->ctrl) {
+ /* Linear mode, enables jumping to any voxel size. */
+ d = d * 0.0005f;
+ }
+ else {
+ /* Multiply d by the initial voxel size to prevent incontrolable speeds when using low voxel
+ * sizes. */
+ /* When the voxel size is slower, it needs more precision. */
+ d = d * min_ff(pow2f(cd->init_voxel_size), 0.1f) * 0.05f;
+ }
+ if (cd->slow_mode) {
+ cd->voxel_size = cd->slow_voxel_size + d * 0.05f;
+ }
+ else {
+ cd->voxel_size = cd->init_voxel_size + d;
+ }
+
+ if (event->type == EVT_LEFTSHIFTKEY && event->val == KM_PRESS) {
+ cd->slow_mode = true;
+ copy_v2_v2(cd->slow_mval, mval);
+ cd->slow_voxel_size = cd->voxel_size;
+ }
+ if (event->type == EVT_LEFTSHIFTKEY && event->val == KM_RELEASE) {
+ cd->slow_mode = false;
+ cd->slow_voxel_size = 0.0f;
+ }
+
+ cd->voxel_size = clamp_f(cd->voxel_size, 0.0001f, 1.0f);
+
+ ED_region_tag_redraw(ar);
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int voxel_size_edit_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ ARegion *ar = CTX_wm_region(C);
+ Object *active_object = CTX_data_active_object(C);
+ Mesh *mesh = (Mesh *)active_object->data;
+
+ VoxelSizeEditCustomData *cd = MEM_callocN(sizeof(VoxelSizeEditCustomData),
+ "Voxel Size Edit OP Custom Data");
+
+ /* Initial operator Custom Data setup. */
+ cd->draw_handle = ED_region_draw_cb_activate(
+ ar->type, voxel_size_edit_draw, cd, REGION_DRAW_POST_VIEW);
+ cd->active_object = active_object;
+ cd->init_mval[0] = event->mval[0];
+ cd->init_mval[1] = event->mval[1];
+ cd->init_voxel_size = mesh->remesh_voxel_size;
+ cd->voxel_size = mesh->remesh_voxel_size;
+ op->customdata = cd;
+
+ /* Select the front facing face of the mesh boundig box. */
+ BoundBox *bb = BKE_mesh_boundbox_get(cd->active_object);
+
+ /* Indices of the Bounding Box faces. */
+ int BB_faces[6][4] = {
+ {3, 0, 4, 7},
+ {1, 2, 6, 5},
+ {3, 2, 1, 0},
+ {4, 5, 6, 7},
+ {0, 1, 5, 4},
+ {2, 3, 7, 6},
+ };
+
+ copy_v3_v3(cd->preview_plane[0], bb->vec[BB_faces[0][0]]);
+ copy_v3_v3(cd->preview_plane[1], bb->vec[BB_faces[0][1]]);
+ copy_v3_v3(cd->preview_plane[2], bb->vec[BB_faces[0][2]]);
+ copy_v3_v3(cd->preview_plane[3], bb->vec[BB_faces[0][3]]);
+
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+
+ float mat[3][3];
+ float current_normal[3];
+ float view_normal[3] = {0.0f, 0.0f, 1.0f};
+
+ /* Calculate the view normal. */
+ invert_m4_m4(active_object->imat, active_object->obmat);
+ copy_m3_m4(mat, rv3d->viewinv);
+ mul_m3_v3(mat, view_normal);
+ copy_m3_m4(mat, active_object->imat);
+ mul_m3_v3(mat, view_normal);
+ normalize_v3(view_normal);
+
+ normal_tri_v3(current_normal, cd->preview_plane[0], cd->preview_plane[1], cd->preview_plane[2]);
+
+ float min_dot = dot_v3v3(current_normal, view_normal);
+ float current_dot = 1;
+
+ /* Check if there is a face that is more aligned towards the view. */
+ for (int i = 0; i < 6; i++) {
+ normal_tri_v3(
+ current_normal, bb->vec[BB_faces[i][0]], bb->vec[BB_faces[i][1]], bb->vec[BB_faces[i][2]]);
+ current_dot = dot_v3v3(current_normal, view_normal);
+
+ if (current_dot < min_dot) {
+ min_dot = current_dot;
+ copy_v3_v3(cd->preview_plane[0], bb->vec[BB_faces[i][0]]);
+ copy_v3_v3(cd->preview_plane[1], bb->vec[BB_faces[i][1]]);
+ copy_v3_v3(cd->preview_plane[2], bb->vec[BB_faces[i][2]]);
+ copy_v3_v3(cd->preview_plane[3], bb->vec[BB_faces[i][3]]);
+ }
+ }
+
+ /* Matrix calculation to position the text in 3D space. */
+ float text_pos[3];
+ float scale_mat[4][4];
+
+ float d_a[3], d_b[3];
+ float d_a_proj[2], d_b_proj[2];
+ float preview_plane_proj[4][3];
+ float y_axis_proj[2] = {0.0f, 1.0f};
+
+ mid_v3_v3v3(text_pos, cd->preview_plane[0], cd->preview_plane[2]);
+
+ /* Project the selected face in the previous step of the Bounding Box. */
+ for (int i = 0; i < 4; i++) {
+ ED_view3d_project(ar, cd->preview_plane[i], preview_plane_proj[i]);
+ }
+
+ /* Get the initial X and Y axis of the basis from the edges of the Bounding Box face. */
+ sub_v3_v3v3(d_a, cd->preview_plane[1], cd->preview_plane[0]);
+ sub_v3_v3v3(d_b, cd->preview_plane[3], cd->preview_plane[0]);
+ normalize_v3(d_a);
+ normalize_v3(d_b);
+
+ /* Project the X and Y axis. */
+ sub_v2_v2v2(d_a_proj, preview_plane_proj[1], preview_plane_proj[0]);
+ sub_v2_v2v2(d_b_proj, preview_plane_proj[3], preview_plane_proj[0]);
+ normalize_v2(d_a_proj);
+ normalize_v2(d_b_proj);
+
+ unit_m4(cd->text_mat);
+
+ /* Select the axis that is aligned with the view Y axis to use it as the basis Y. */
+ if (fabsf(dot_v2v2(d_a_proj, y_axis_proj)) > fabsf(dot_v2v2(d_b_proj, y_axis_proj))) {
+ copy_v3_v3(cd->text_mat[0], d_b);
+ copy_v3_v3(cd->text_mat[1], d_a);
+
+ /* Flip the X and Y basis vectors to make sure they always point upwards and to the right. */
+ if (d_b_proj[0] < 0.0f) {
+ mul_v3_fl(cd->text_mat[0], -1.0f);
+ }
+ if (d_a_proj[1] < 0.0f) {
+ mul_v3_fl(cd->text_mat[1], -1.0f);
+ }
+ }
+ else {
+ copy_v3_v3(cd->text_mat[0], d_a);
+ copy_v3_v3(cd->text_mat[1], d_b);
+ if (d_a_proj[0] < 0.0f) {
+ mul_v3_fl(cd->text_mat[0], -1.0f);
+ }
+ if (d_b_proj[1] < 0.0f) {
+ mul_v3_fl(cd->text_mat[1], -1.0f);
+ }
+ }
+
+ /* Use the Bounding Box face normal as the basis Z. */
+ normal_tri_v3(cd->text_mat[2], cd->preview_plane[0], cd->preview_plane[1], cd->preview_plane[2]);
+
+ /* Write the text position into the matrix. */
+ copy_v3_v3(cd->text_mat[3], text_pos);
+
+ /* Scale the text. */
+ unit_m4(scale_mat);
+ scale_m4_fl(scale_mat, 0.0008f);
+ mul_m4_m4_post(cd->text_mat, scale_mat);
+
+ WM_event_add_modal_handler(C, op);
+
+ ED_region_tag_redraw(ar);
+
+ const char *status_str = TIP_(
+ "Move the mouse to change the voxel size. LBM: confirm size, ESC/RMB: cancel");
+ ED_workspace_status_text(C, status_str);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+void OBJECT_OT_voxel_size_edit(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Edit Voxel Size";
+ ot->description = "Modify the mesh voxel size interactively used in the voxel remesher";
+ ot->idname = "OBJECT_OT_voxel_size_edit";
+
+ /* api callbacks */
+ ot->poll = object_remesh_poll;
+ ot->invoke = voxel_size_edit_invoke;
+ ot->modal = voxel_size_edit_modal;
+ ot->cancel = voxel_size_edit_cancel;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/****************** quadriflow remesh operator *********************/
+
+#define QUADRIFLOW_MIRROR_BISECT_TOLERANCE 0.005f
+
enum {
QUADRIFLOW_REMESH_RATIO = 1,
QUADRIFLOW_REMESH_EDGE_LENGTH,
QUADRIFLOW_REMESH_FACES,
};
-/****************** quadriflow remesh operator *********************/
-
-#define QUADRIFLOW_MIRROR_BISECT_TOLERANCE 0.005f
-
typedef enum eSymmetryAxes {
SYMMETRY_AXES_X = (1 << 0),
SYMMETRY_AXES_Y = (1 << 1),