Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added roughly mirrored algorithm for automesh #121

Merged
merged 17 commits into from
Oct 19, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion source/creator/viewport/common/automesh/automesh.d
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ import inochi2d.core;
class AutoMeshProcessor {
public:
abstract IncMesh autoMesh(Drawable targets, IncMesh meshData, bool mirrorHoriz = false, float axisHoriz = 0, bool mirrorVert = false, float axisVert = 0);

abstract void configure();
};
89 changes: 80 additions & 9 deletions source/creator/viewport/common/automesh/contours.d
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
module creator.viewport.common.automesh.contours;

import i18n;
import creator.viewport.common.automesh.automesh;
import creator.viewport.common.mesh;
import creator.widgets;
import inochi2d.core;
import inmath;
import dcv.core;
Expand All @@ -13,13 +15,18 @@ import std.algorithm;
import std.algorithm.iteration: map, reduce;
import std.stdio;
import std.array;
import bindbc.imgui;

class ContourAutoMeshProcessor : AutoMeshProcessor {
int STEP = 32;
const int SMALL_THRESHOLD = 256;
ubyte maskThreshold = 15;
float SAMPLING_STEP = 32;
const float SMALL_THRESHOLD = 256;
float maskThreshold = 15;
float MIN_DISTANCE = 16;
float MAX_DISTANCE = -1;
public:
override IncMesh autoMesh(Drawable target, IncMesh mesh, bool mirrorHoriz = false, float axisHoriz = 0, bool mirrorVert = false, float axisVert = 0) {
if (MAX_DISTANCE < 0)
MAX_DISTANCE = SAMPLING_STEP * 2;
auto contoursToVec2s(ContourType)(ref ContourType contours) {
vec2[] result;
foreach (contour; contours) {
Expand Down Expand Up @@ -88,15 +95,15 @@ public:
int size = max(texture.width, texture.height);
double imageScale = 1;

double step = 1;
float step = 1;
if (size < SMALL_THRESHOLD) {
step = SMALL_THRESHOLD / size * 2; // heulistic parameter adjustment.
}
auto gray = img.sliced[0..$, 0..$, 3]; // Use transparent channel for boundary search
auto imbin = gray;
foreach (y; 0..imbin.shape[0]) {
foreach (x; 0..imbin.shape[1]) {
imbin[y, x] = imbin[y, x] < maskThreshold? 0: 255;
imbin[y, x] = imbin[y, x] < cast(ubyte)maskThreshold? 0: 255;
}
}
auto labels = bwlabel(imbin);
Expand Down Expand Up @@ -135,15 +142,21 @@ public:
double[] scales;
if (step == 1) {
// scaling for larger parts
scales = [1, 1.1, 0.9, 0.6, 0.4, 0.2, 0.1];
scales = [1, 1.1, 0.9, 0.7, 0.4, 0.2, 0.1];
} else {
// special scaling for smaller parts
scales = [1, 1.1, 0.8, 0.6, 0.2];
}
auto moment = calcMoment(contourVec);
auto xlist = contourVec.map!((a)=>a.x);
auto ylist = contourVec.map!((a)=>a.y);
auto boundWidth = xlist.reduce!(max) - xlist.reduce!(min);
auto boundHeight = ylist.reduce!(max) - ylist.reduce!(min);
auto minSize = min(boundWidth, boundHeight) * 0.05;
minSize = min(minSize, MIN_DISTANCE);
foreach (double scale; scales) {
double samplingRate = STEP;
samplingRate = samplingRate / scale / scale / step; // heulistic sampling rate
double samplingRate = SAMPLING_STEP;
samplingRate = min(MAX_DISTANCE / scale, samplingRate / scale / scale / step); // heulistic sampling rate

auto contour2 = resampling(contourVec, samplingRate, mirrorHoriz, imgCenter.x + axisHoriz, mirrorVert, imgCenter.y + axisVert);
auto contour3 = scaling(contour2, moment, scale, 0);
Expand All @@ -159,7 +172,7 @@ public:
foreach (vec2 c; contour3) {
if (mesh.vertices.length > 0) {
auto minDistance = mesh.vertices.map!((v) { return ((c-imgCenter) - v.position).length; } ).reduce!(min);
if (minDistance > STEP / 4)
if (minDistance > minSize)
mesh.vertices ~= new MeshVertex(c - imgCenter, []);
} else
mesh.vertices ~= new MeshVertex(c - imgCenter, []);
Expand All @@ -171,4 +184,62 @@ public:
return mesh.autoTriangulate();
};

override void configure() {
if (MAX_DISTANCE < 0)
MAX_DISTANCE = SAMPLING_STEP * 2;

incText(_("Sampling rate"));
igSameLine();
igPushID("SAMPLING_STEP");
igSetNextItemWidth(80);
if (incDragFloat(
"sampling_rate", &SAMPLING_STEP, 0.01,
1, 200, "%.2f", ImGuiSliderFlags.NoRoundToFormat)
) {
SAMPLING_STEP = SAMPLING_STEP;
if (MAX_DISTANCE < SAMPLING_STEP)
MAX_DISTANCE = SAMPLING_STEP * 2;
}
igPopID();

incText(_("Mask threshold"));
igSameLine();
igPushID("MASK_THRESHOLD");
igSetNextItemWidth(80);
if (incDragFloat(
"mask_threshold", &maskThreshold, 0.01,
1, 200, "%.2f", ImGuiSliderFlags.NoRoundToFormat)
) {
maskThreshold = maskThreshold;
}
igPopID();

incText(_("Distance between vertex"));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be "Distance between vertices"

igIndent();
incText(_("Minimum"));
igSameLine();
igPushID("MIN_DISTANCE");
igSetNextItemWidth(80);
if (incDragFloat(
"min_distance", &MIN_DISTANCE, 0.01,
1, 200, "%.2f", ImGuiSliderFlags.NoRoundToFormat)
) {
MIN_DISTANCE = MIN_DISTANCE;
}
igPopID();

incText(_("Maximum"));
igSameLine();
igPushID("MAX_DISTANCE");
igSetNextItemWidth(80);
if (incDragFloat(
"min_distance", &MAX_DISTANCE, 0.01,
1, 200, "%.2f", ImGuiSliderFlags.NoRoundToFormat)
) {
MAX_DISTANCE = MAX_DISTANCE;
}
igPopID();
igUnindent();
}

};
25 changes: 23 additions & 2 deletions source/creator/viewport/vertex/package.d
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ import bindbc.opengl;

private {
IncMeshEditor editor;
AutoMeshProcessor[] autoMeshProcessors = [
new ContourAutoMeshProcessor()
];
AutoMeshProcessor activeProcessor = null;
}

void incViewportVertexInspector(Drawable node) {
Expand Down Expand Up @@ -97,10 +101,27 @@ void incViewportVertexOptions() {

igBeginGroup();
if (igButton("")) {
auto processor = new ContourAutoMeshProcessor;
editor.mesh = processor.autoMesh(editor.getTarget(), editor.getMesh(), editor.mirrorHoriz, 0, editor.mirrorVert, 0);
if (!activeProcessor)
activeProcessor = autoMeshProcessors[0];
editor.mesh = activeProcessor.autoMesh(editor.getTarget(), editor.getMesh(), editor.mirrorHoriz, 0, editor.mirrorVert, 0);
editor.refreshMesh();
}
if (incBeginDropdownMenu("AUTOMESH_SETTINGS")) {
if (!activeProcessor)
activeProcessor = autoMeshProcessors[0];
activeProcessor.configure();

// Button which bakes some auto generated content
// In this case, a mesh is baked from the triangulation.
if (igButton(__("Bake"),ImVec2(incAvailableSpace().x, 0))) {
editor.mesh = activeProcessor.autoMesh(editor.getTarget(), editor.getMesh(), editor.mirrorHoriz, 0, editor.mirrorVert, 0);
editor.refreshMesh();
}
incTooltip(_("Bakes the auto mesh."));

incEndDropdownMenu();
}
incTooltip(_("Triangulation Options"));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This tooltip should probably be removed, and be called "Auto Meshing Options"

incTooltip(_("Auto Meshing (Experimental)"));
igEndGroup();

Expand Down