Cleanup: remove unused area smoothing logic for UV unwrap
This used to run when holding Shift while unwrapping until 2006 when it
was removed [0].
[0]: e66b5e5cd5
Reviewed By: brecht
Ref D15075
This commit is contained in:
parent
68150b666c
commit
b450a8c851
|
@ -87,14 +87,6 @@ void GEO_uv_parametrizer_stretch_end(ParamHandle *handle);
|
|||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Area Smooth
|
||||
* \{ */
|
||||
|
||||
void GEO_uv_parametrizer_smooth_area(ParamHandle *handle);
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Packing
|
||||
* \{ */
|
||||
|
|
|
@ -3819,545 +3819,6 @@ static void p_chart_rotate_fit_aabb(PChart *chart)
|
|||
}
|
||||
}
|
||||
|
||||
/* Area Smoothing */
|
||||
|
||||
/* 2d BSP tree for inverse mapping - that's a bit silly. */
|
||||
|
||||
typedef struct SmoothTriangle {
|
||||
float co1[2], co2[2], co3[2];
|
||||
float oco1[2], oco2[2], oco3[2];
|
||||
} SmoothTriangle;
|
||||
|
||||
typedef struct SmoothNode {
|
||||
struct SmoothNode *c1, *c2;
|
||||
SmoothTriangle **tri;
|
||||
float split;
|
||||
int axis, ntri;
|
||||
} SmoothNode;
|
||||
|
||||
static void p_barycentric_2d(
|
||||
const float v1[2], const float v2[2], const float v3[2], const float p[2], float b[3])
|
||||
{
|
||||
float a[2], c[2], h[2], div;
|
||||
|
||||
a[0] = v2[0] - v1[0];
|
||||
a[1] = v2[1] - v1[1];
|
||||
c[0] = v3[0] - v1[0];
|
||||
c[1] = v3[1] - v1[1];
|
||||
|
||||
div = a[0] * c[1] - a[1] * c[0];
|
||||
|
||||
if (div == 0.0f) {
|
||||
b[0] = 1.0f / 3.0f;
|
||||
b[1] = 1.0f / 3.0f;
|
||||
b[2] = 1.0f / 3.0f;
|
||||
}
|
||||
else {
|
||||
h[0] = p[0] - v1[0];
|
||||
h[1] = p[1] - v1[1];
|
||||
|
||||
div = 1.0f / div;
|
||||
|
||||
b[1] = (h[0] * c[1] - h[1] * c[0]) * div;
|
||||
b[2] = (a[0] * h[1] - a[1] * h[0]) * div;
|
||||
b[0] = 1.0f - b[1] - b[2];
|
||||
}
|
||||
}
|
||||
|
||||
static PBool p_triangle_inside(SmoothTriangle *t, float co[2])
|
||||
{
|
||||
float b[3];
|
||||
|
||||
p_barycentric_2d(t->co1, t->co2, t->co3, co, b);
|
||||
|
||||
if ((b[0] >= 0.0f) && (b[1] >= 0.0f) && (b[2] >= 0.0f)) {
|
||||
co[0] = t->oco1[0] * b[0] + t->oco2[0] * b[1] + t->oco3[0] * b[2];
|
||||
co[1] = t->oco1[1] * b[0] + t->oco2[1] * b[1] + t->oco3[1] * b[2];
|
||||
return P_TRUE;
|
||||
}
|
||||
|
||||
return P_FALSE;
|
||||
}
|
||||
|
||||
static SmoothNode *p_node_new(
|
||||
MemArena *arena, SmoothTriangle **tri, int ntri, float *bmin, float *bmax, int depth)
|
||||
{
|
||||
SmoothNode *node = BLI_memarena_alloc(arena, sizeof(*node));
|
||||
int axis, i, t1size = 0, t2size = 0;
|
||||
float split, /* mi, */ /* UNUSED */ mx;
|
||||
SmoothTriangle **t1, **t2, *t;
|
||||
|
||||
node->tri = tri;
|
||||
node->ntri = ntri;
|
||||
|
||||
if (ntri <= 10 || depth >= 15) {
|
||||
return node;
|
||||
}
|
||||
|
||||
t1 = MEM_mallocN(sizeof(*t1) * ntri, "PNodeTri1");
|
||||
t2 = MEM_mallocN(sizeof(*t2) * ntri, "PNodeTri1");
|
||||
|
||||
axis = (bmax[0] - bmin[0] > bmax[1] - bmin[1]) ? 0 : 1;
|
||||
split = 0.5f * (bmin[axis] + bmax[axis]);
|
||||
|
||||
for (i = 0; i < ntri; i++) {
|
||||
t = tri[i];
|
||||
|
||||
if ((t->co1[axis] <= split) || (t->co2[axis] <= split) || (t->co3[axis] <= split)) {
|
||||
t1[t1size] = t;
|
||||
t1size++;
|
||||
}
|
||||
if ((t->co1[axis] >= split) || (t->co2[axis] >= split) || (t->co3[axis] >= split)) {
|
||||
t2[t2size] = t;
|
||||
t2size++;
|
||||
}
|
||||
}
|
||||
|
||||
if ((t1size == t2size) && (t1size == ntri)) {
|
||||
MEM_freeN(t1);
|
||||
MEM_freeN(t2);
|
||||
return node;
|
||||
}
|
||||
|
||||
node->tri = NULL;
|
||||
node->ntri = 0;
|
||||
MEM_freeN(tri);
|
||||
|
||||
node->axis = axis;
|
||||
node->split = split;
|
||||
|
||||
/* mi = bmin[axis]; */ /* UNUSED */
|
||||
mx = bmax[axis];
|
||||
bmax[axis] = split;
|
||||
node->c1 = p_node_new(arena, t1, t1size, bmin, bmax, depth + 1);
|
||||
|
||||
bmin[axis] = bmax[axis];
|
||||
bmax[axis] = mx;
|
||||
node->c2 = p_node_new(arena, t2, t2size, bmin, bmax, depth + 1);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static void p_node_delete(SmoothNode *node)
|
||||
{
|
||||
if (node->c1) {
|
||||
p_node_delete(node->c1);
|
||||
}
|
||||
if (node->c2) {
|
||||
p_node_delete(node->c2);
|
||||
}
|
||||
if (node->tri) {
|
||||
MEM_freeN(node->tri);
|
||||
}
|
||||
}
|
||||
|
||||
static PBool p_node_intersect(SmoothNode *node, float co[2])
|
||||
{
|
||||
int i;
|
||||
|
||||
if (node->tri) {
|
||||
for (i = 0; i < node->ntri; i++) {
|
||||
if (p_triangle_inside(node->tri[i], co)) {
|
||||
return P_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return P_FALSE;
|
||||
}
|
||||
|
||||
if (co[node->axis] < node->split) {
|
||||
return p_node_intersect(node->c1, co);
|
||||
}
|
||||
return p_node_intersect(node->c2, co);
|
||||
}
|
||||
|
||||
/* smoothing */
|
||||
|
||||
static int p_compare_float(const void *a_, const void *b_)
|
||||
{
|
||||
const float a = *(const float *)a_;
|
||||
const float b = *(const float *)b_;
|
||||
|
||||
if (a < b) {
|
||||
return -1;
|
||||
}
|
||||
if (a == b) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static float p_smooth_median_edge_length(PChart *chart)
|
||||
{
|
||||
PEdge *e;
|
||||
float *lengths = MEM_mallocN(sizeof(chart->edges) * chart->nedges, "PMedianLength");
|
||||
float median;
|
||||
int i;
|
||||
|
||||
/* ok, so I'm lazy */
|
||||
for (i = 0, e = chart->edges; e; e = e->nextlink, i++) {
|
||||
lengths[i] = p_edge_length(e);
|
||||
}
|
||||
|
||||
qsort(lengths, i, sizeof(float), p_compare_float);
|
||||
|
||||
median = lengths[i / 2];
|
||||
MEM_freeN(lengths);
|
||||
|
||||
return median;
|
||||
}
|
||||
|
||||
static float p_smooth_distortion(PEdge *e, float avg2d, float avg3d)
|
||||
{
|
||||
float len2d = p_edge_uv_length(e) * avg3d;
|
||||
float len3d = p_edge_length(e) * avg2d;
|
||||
|
||||
return (len3d == 0.0f) ? 0.0f : len2d / len3d;
|
||||
}
|
||||
|
||||
static void p_smooth(PChart *chart)
|
||||
{
|
||||
PEdge *e;
|
||||
PVert *v;
|
||||
PFace *f;
|
||||
int j, it2, maxiter2, it;
|
||||
int nedges = chart->nedges, nwheel, gridx, gridy;
|
||||
int edgesx, edgesy, nsize, esize, i, x, y, maxiter;
|
||||
float minv[2], maxv[2], median, invmedian, avglen2d, avglen3d;
|
||||
float center[2], dx, dy, *nodes, dlimit, d, *oldnodesx, *oldnodesy;
|
||||
float *nodesx, *nodesy, *hedges, *vedges, climit, moved, padding;
|
||||
SmoothTriangle *triangles, *t, *t2, **tri, **trip;
|
||||
SmoothNode *root;
|
||||
MemArena *arena;
|
||||
|
||||
if (nedges == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
p_chart_uv_bbox(chart, minv, maxv);
|
||||
median = p_smooth_median_edge_length(chart) * 0.10f;
|
||||
|
||||
if (median == 0.0f) {
|
||||
return;
|
||||
}
|
||||
|
||||
invmedian = 1.0f / median;
|
||||
|
||||
/* compute edge distortion */
|
||||
avglen2d = avglen3d = 0.0;
|
||||
|
||||
for (e = chart->edges; e; e = e->nextlink) {
|
||||
avglen2d += p_edge_uv_length(e);
|
||||
avglen3d += p_edge_length(e);
|
||||
}
|
||||
|
||||
avglen2d /= nedges;
|
||||
avglen3d /= nedges;
|
||||
|
||||
for (v = chart->verts; v; v = v->nextlink) {
|
||||
v->u.distortion = 0.0;
|
||||
nwheel = 0;
|
||||
|
||||
e = v->edge;
|
||||
do {
|
||||
v->u.distortion += p_smooth_distortion(e, avglen2d, avglen3d);
|
||||
nwheel++;
|
||||
|
||||
e = e->next->next->pair;
|
||||
} while (e && (e != v->edge));
|
||||
|
||||
v->u.distortion /= nwheel;
|
||||
}
|
||||
|
||||
/* need to do excessive grid size checking still */
|
||||
center[0] = 0.5f * (minv[0] + maxv[0]);
|
||||
center[1] = 0.5f * (minv[1] + maxv[1]);
|
||||
|
||||
dx = 0.5f * (maxv[0] - minv[0]);
|
||||
dy = 0.5f * (maxv[1] - minv[1]);
|
||||
|
||||
padding = 0.15f;
|
||||
dx += padding * dx + 2.0f * median;
|
||||
dy += padding * dy + 2.0f * median;
|
||||
|
||||
gridx = (int)(dx * invmedian);
|
||||
gridy = (int)(dy * invmedian);
|
||||
|
||||
minv[0] = center[0] - median * gridx;
|
||||
minv[1] = center[1] - median * gridy;
|
||||
maxv[0] = center[0] + median * gridx;
|
||||
maxv[1] = center[1] + median * gridy;
|
||||
|
||||
/* create grid */
|
||||
gridx = gridx * 2 + 1;
|
||||
gridy = gridy * 2 + 1;
|
||||
|
||||
if ((gridx <= 2) || (gridy <= 2)) {
|
||||
return;
|
||||
}
|
||||
|
||||
edgesx = gridx - 1;
|
||||
edgesy = gridy - 1;
|
||||
nsize = gridx * gridy;
|
||||
esize = edgesx * edgesy;
|
||||
|
||||
nodes = MEM_mallocN(sizeof(float) * nsize, "PSmoothNodes");
|
||||
nodesx = MEM_mallocN(sizeof(float) * nsize, "PSmoothNodesX");
|
||||
nodesy = MEM_mallocN(sizeof(float) * nsize, "PSmoothNodesY");
|
||||
oldnodesx = MEM_mallocN(sizeof(float) * nsize, "PSmoothOldNodesX");
|
||||
oldnodesy = MEM_mallocN(sizeof(float) * nsize, "PSmoothOldNodesY");
|
||||
hedges = MEM_mallocN(sizeof(float) * esize, "PSmoothHEdges");
|
||||
vedges = MEM_mallocN(sizeof(float) * esize, "PSmoothVEdges");
|
||||
|
||||
if (!nodes || !nodesx || !nodesy || !oldnodesx || !oldnodesy || !hedges || !vedges) {
|
||||
if (nodes) {
|
||||
MEM_freeN(nodes);
|
||||
}
|
||||
if (nodesx) {
|
||||
MEM_freeN(nodesx);
|
||||
}
|
||||
if (nodesy) {
|
||||
MEM_freeN(nodesy);
|
||||
}
|
||||
if (oldnodesx) {
|
||||
MEM_freeN(oldnodesx);
|
||||
}
|
||||
if (oldnodesy) {
|
||||
MEM_freeN(oldnodesy);
|
||||
}
|
||||
if (hedges) {
|
||||
MEM_freeN(hedges);
|
||||
}
|
||||
if (vedges) {
|
||||
MEM_freeN(vedges);
|
||||
}
|
||||
|
||||
// printf("Not enough memory for area smoothing grid");
|
||||
return;
|
||||
}
|
||||
|
||||
for (x = 0; x < gridx; x++) {
|
||||
for (y = 0; y < gridy; y++) {
|
||||
i = x + y * gridx;
|
||||
|
||||
nodesx[i] = minv[0] + median * x;
|
||||
nodesy[i] = minv[1] + median * y;
|
||||
|
||||
nodes[i] = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
/* embed in grid */
|
||||
for (f = chart->faces; f; f = f->nextlink) {
|
||||
PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
|
||||
float fmin[2], fmax[2];
|
||||
int bx1, by1, bx2, by2;
|
||||
|
||||
INIT_MINMAX2(fmin, fmax);
|
||||
|
||||
minmax_v2v2_v2(fmin, fmax, e1->vert->uv);
|
||||
minmax_v2v2_v2(fmin, fmax, e2->vert->uv);
|
||||
minmax_v2v2_v2(fmin, fmax, e3->vert->uv);
|
||||
|
||||
bx1 = (int)((fmin[0] - minv[0]) * invmedian);
|
||||
by1 = (int)((fmin[1] - minv[1]) * invmedian);
|
||||
bx2 = (int)((fmax[0] - minv[0]) * invmedian + 2);
|
||||
by2 = (int)((fmax[1] - minv[1]) * invmedian + 2);
|
||||
|
||||
for (x = bx1; x < bx2; x++) {
|
||||
for (y = by1; y < by2; y++) {
|
||||
float p[2], b[3];
|
||||
|
||||
i = x + y * gridx;
|
||||
|
||||
p[0] = nodesx[i];
|
||||
p[1] = nodesy[i];
|
||||
|
||||
p_barycentric_2d(e1->vert->uv, e2->vert->uv, e3->vert->uv, p, b);
|
||||
|
||||
if ((b[0] > 0.0f) && (b[1] > 0.0f) && (b[2] > 0.0f)) {
|
||||
nodes[i] = e1->vert->u.distortion * b[0];
|
||||
nodes[i] += e2->vert->u.distortion * b[1];
|
||||
nodes[i] += e3->vert->u.distortion * b[2];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* smooth the grid */
|
||||
maxiter = 10;
|
||||
climit = 0.00001f * nsize;
|
||||
|
||||
for (it = 0; it < maxiter; it++) {
|
||||
moved = 0.0f;
|
||||
|
||||
for (x = 0; x < edgesx; x++) {
|
||||
for (y = 0; y < edgesy; y++) {
|
||||
i = x + y * gridx;
|
||||
j = x + y * edgesx;
|
||||
|
||||
hedges[j] = (nodes[i] + nodes[i + 1]) * 0.5f;
|
||||
vedges[j] = (nodes[i] + nodes[i + gridx]) * 0.5f;
|
||||
|
||||
/* we do *inverse* mapping */
|
||||
hedges[j] = 1.0f / hedges[j];
|
||||
vedges[j] = 1.0f / vedges[j];
|
||||
}
|
||||
}
|
||||
|
||||
maxiter2 = 50;
|
||||
dlimit = 0.0001f;
|
||||
|
||||
for (it2 = 0; it2 < maxiter2; it2++) {
|
||||
d = 0.0f;
|
||||
|
||||
memcpy(oldnodesx, nodesx, sizeof(float) * nsize);
|
||||
memcpy(oldnodesy, nodesy, sizeof(float) * nsize);
|
||||
|
||||
for (x = 1; x < gridx - 1; x++) {
|
||||
for (y = 1; y < gridy - 1; y++) {
|
||||
float p[2], oldp[2], sum1, sum2, diff[2], length;
|
||||
|
||||
i = x + gridx * y;
|
||||
j = x + edgesx * y;
|
||||
|
||||
oldp[0] = oldnodesx[i];
|
||||
oldp[1] = oldnodesy[i];
|
||||
|
||||
sum1 = hedges[j - 1] * oldnodesx[i - 1];
|
||||
sum1 += hedges[j] * oldnodesx[i + 1];
|
||||
sum1 += vedges[j - edgesx] * oldnodesx[i - gridx];
|
||||
sum1 += vedges[j] * oldnodesx[i + gridx];
|
||||
|
||||
sum2 = hedges[j - 1];
|
||||
sum2 += hedges[j];
|
||||
sum2 += vedges[j - edgesx];
|
||||
sum2 += vedges[j];
|
||||
|
||||
nodesx[i] = sum1 / sum2;
|
||||
|
||||
sum1 = hedges[j - 1] * oldnodesy[i - 1];
|
||||
sum1 += hedges[j] * oldnodesy[i + 1];
|
||||
sum1 += vedges[j - edgesx] * oldnodesy[i - gridx];
|
||||
sum1 += vedges[j] * oldnodesy[i + gridx];
|
||||
|
||||
nodesy[i] = sum1 / sum2;
|
||||
|
||||
p[0] = nodesx[i];
|
||||
p[1] = nodesy[i];
|
||||
|
||||
diff[0] = p[0] - oldp[0];
|
||||
diff[1] = p[1] - oldp[1];
|
||||
|
||||
length = len_v2(diff);
|
||||
d = max_ff(d, length);
|
||||
moved += length;
|
||||
}
|
||||
}
|
||||
|
||||
if (d < dlimit) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (moved < climit) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
MEM_freeN(oldnodesx);
|
||||
MEM_freeN(oldnodesy);
|
||||
MEM_freeN(hedges);
|
||||
MEM_freeN(vedges);
|
||||
|
||||
/* Create BSP. */
|
||||
t = triangles = MEM_mallocN(sizeof(SmoothTriangle) * esize * 2, "PSmoothTris");
|
||||
trip = tri = MEM_mallocN(sizeof(SmoothTriangle *) * esize * 2, "PSmoothTriP");
|
||||
|
||||
if (!triangles || !tri) {
|
||||
MEM_freeN(nodes);
|
||||
MEM_freeN(nodesx);
|
||||
MEM_freeN(nodesy);
|
||||
|
||||
if (triangles) {
|
||||
MEM_freeN(triangles);
|
||||
}
|
||||
if (tri) {
|
||||
MEM_freeN(tri);
|
||||
}
|
||||
|
||||
// printf("Not enough memory for area smoothing grid");
|
||||
return;
|
||||
}
|
||||
|
||||
for (x = 0; x < edgesx; x++) {
|
||||
for (y = 0; y < edgesy; y++) {
|
||||
i = x + y * gridx;
|
||||
|
||||
t->co1[0] = nodesx[i];
|
||||
t->co1[1] = nodesy[i];
|
||||
|
||||
t->co2[0] = nodesx[i + 1];
|
||||
t->co2[1] = nodesy[i + 1];
|
||||
|
||||
t->co3[0] = nodesx[i + gridx];
|
||||
t->co3[1] = nodesy[i + gridx];
|
||||
|
||||
t->oco1[0] = minv[0] + x * median;
|
||||
t->oco1[1] = minv[1] + y * median;
|
||||
|
||||
t->oco2[0] = minv[0] + (x + 1) * median;
|
||||
t->oco2[1] = minv[1] + y * median;
|
||||
|
||||
t->oco3[0] = minv[0] + x * median;
|
||||
t->oco3[1] = minv[1] + (y + 1) * median;
|
||||
|
||||
t2 = t + 1;
|
||||
|
||||
t2->co1[0] = nodesx[i + gridx + 1];
|
||||
t2->co1[1] = nodesy[i + gridx + 1];
|
||||
|
||||
t2->oco1[0] = minv[0] + (x + 1) * median;
|
||||
t2->oco1[1] = minv[1] + (y + 1) * median;
|
||||
|
||||
t2->co2[0] = t->co2[0];
|
||||
t2->co2[1] = t->co2[1];
|
||||
t2->oco2[0] = t->oco2[0];
|
||||
t2->oco2[1] = t->oco2[1];
|
||||
|
||||
t2->co3[0] = t->co3[0];
|
||||
t2->co3[1] = t->co3[1];
|
||||
t2->oco3[0] = t->oco3[0];
|
||||
t2->oco3[1] = t->oco3[1];
|
||||
|
||||
*trip = t;
|
||||
trip++;
|
||||
t++;
|
||||
*trip = t;
|
||||
trip++;
|
||||
t++;
|
||||
}
|
||||
}
|
||||
|
||||
MEM_freeN(nodes);
|
||||
MEM_freeN(nodesx);
|
||||
MEM_freeN(nodesy);
|
||||
|
||||
arena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), "param smooth arena");
|
||||
root = p_node_new(arena, tri, esize * 2, minv, maxv, 0);
|
||||
|
||||
for (v = chart->verts; v; v = v->nextlink) {
|
||||
if (!p_node_intersect(root, v->uv)) {
|
||||
param_warning("area smoothing error: couldn't find mapping triangle\n");
|
||||
}
|
||||
}
|
||||
|
||||
p_node_delete(root);
|
||||
BLI_memarena_free(arena);
|
||||
|
||||
MEM_freeN(triangles);
|
||||
}
|
||||
|
||||
/* Exported */
|
||||
|
||||
ParamHandle *GEO_uv_parametrizer_construct_begin(void)
|
||||
|
@ -4702,24 +4163,6 @@ void GEO_uv_parametrizer_stretch_end(ParamHandle *phandle)
|
|||
phandle->rng = NULL;
|
||||
}
|
||||
|
||||
void GEO_uv_parametrizer_smooth_area(ParamHandle *phandle)
|
||||
{
|
||||
int i;
|
||||
|
||||
param_assert(phandle->state == PHANDLE_STATE_CONSTRUCTED);
|
||||
|
||||
for (i = 0; i < phandle->ncharts; i++) {
|
||||
PChart *chart = phandle->charts[i];
|
||||
PVert *v;
|
||||
|
||||
for (v = chart->verts; v; v = v->nextlink) {
|
||||
v->flag &= ~PVERT_PIN;
|
||||
}
|
||||
|
||||
p_smooth(chart);
|
||||
}
|
||||
}
|
||||
|
||||
/* don't pack, just rotate (used for better packing) */
|
||||
static void GEO_uv_parametrizer_pack_rotate(ParamHandle *phandle, bool ignore_pinned)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue