Sculpt: integrate instant meshes

Still not particularly usable, but
much faster then Quadriflow.
This commit is contained in:
Joseph Eagar 2021-10-25 10:05:12 -07:00
parent 95b84b5e13
commit 779aeb72ab
17 changed files with 6363 additions and 4926 deletions

View File

@ -22,6 +22,7 @@ set(INC
.
../atomic
../eigen
../guardedalloc
../../extern/Eigen3
ext/half
ext/dset
@ -53,6 +54,10 @@ set(SRC
src/extract.h
src/field.cpp
src/field.h
src/meshstats.cpp
src/meshstats.h
src/normal.cpp
src/normal.h
src/hierarchy.cpp
src/hierarchy.h
src/reorder.cpp
@ -61,6 +66,8 @@ set(SRC
src/subdivide.h
src/smoothcurve.cpp
src/smoothcurve.h
src/c_api.cpp
instant_meshes_c_api.h
)
set(LIB

View File

@ -0,0 +1 @@
This is a fork of instant-meshes, an alternative to QuadriFlow.

View File

@ -0,0 +1,56 @@
#pragma once
/* clang-format off */
//remeshedge->flag
enum {
REMESH_EDGE_BOUNDARY = (1<<0),
REMESH_EDGE_USE_DIR = (1<<1)
};
/* clang-format on */
typedef struct RemeshVertex {
float co[3], no[3];
} RemeshVertex;
// edge constraint
typedef struct RemeshEdge {
int v1, v2, flag;
float dir[3];
} RemeshEdge;
typedef struct RemeshTri {
int v1, v2, v3;
int eflags[3];
} RemeshTri;
typedef struct RemeshOutFace {
int *verts;
int totvert;
} RemeshOutFace;
typedef struct RemeshMesh {
RemeshTri *tris;
RemeshVertex *verts;
RemeshEdge *edges; // list of constrained edges, need not be all edges in the mesh
int tottri, totvert, totedge;
RemeshOutFace *outfaces;
RemeshVertex *outverts;
int *out_scracth;
int totoutface;
int totoutvert;
} RemeshMesh;
#ifdef __cplusplus
extern "C" {
#endif
void instant_meshes_run(RemeshMesh *mesh);
void instant_meshes_finish(RemeshMesh *mesh);
void instant_meshes_set_number_of_threads(int n);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,347 @@
#include "MEM_guardedalloc.h"
#include "adjacency.h"
#include "cleanup.h"
#include "common.h"
#include "dedge.h"
#include "extract.h"
#include "field.h"
#include "hierarchy.h"
#include "normal.h"
#include "smoothcurve.h"
#include "subdivide.h"
#include "meshstats.h"
#include "../instant_meshes_c_api.h"
#include <set>
int instant_meshes_nprocs = 1;
const float len_v3v3(const float *a, const float *b)
{
float dx = a[0] - b[0];
float dy = a[1] - b[1];
float dz = a[2] - b[2];
float len = dx * dx + dy * dy + dz * dz;
return len > 0.0f ? sqrtf(len) : 0.0f;
}
extern "C" {
void instant_meshes_run(RemeshMesh *mesh)
{
MatrixXu F;
MatrixXf V;
MatrixXf N;
float elen = 0.0f;
int totlen = 0;
float scale = 0.1f;
std::set<uint32_t> creaseSet;
F.resize(3, mesh->tottri);
V.resize(3, mesh->totvert);
N.resize(3, mesh->totvert);
// F.resize(mesh->tottri * 3);
// V.resize(mesh->totvert * 3);
// N.resize(mesh->totvert * 3);
for (int i = 0; i < mesh->tottri; i++) {
RemeshTri *tri = mesh->tris + i;
elen += len_v3v3(mesh->verts[tri->v1].co, mesh->verts[tri->v2].co);
elen += len_v3v3(mesh->verts[tri->v2].co, mesh->verts[tri->v3].co);
elen += len_v3v3(mesh->verts[tri->v3].co, mesh->verts[tri->v1].co);
totlen += 3;
F(0, i) = tri->v1;
F(1, i) = tri->v2;
F(2, i) = tri->v3;
}
for (int i = 0; i < mesh->totvert; i++) {
RemeshVertex *v = mesh->verts + i;
for (int j = 0; j < 3; j++) {
V(j, i) = v->co[j];
N(j, i) = v->no[j];
}
}
if (totlen > 0) {
elen /= totlen;
scale = elen * 4.0f;
}
const bool extrinsic = true;
const bool deterministic = false;
const int rosy = 4, posy = 4;
printf("scale: %.5f\n", scale);
VectorXu V2E, E2E;
VectorXb boundary;
VectorXb nonManifold;
nonManifold.resize(V.cols());
build_dedge(F, V, V2E, E2E, boundary, nonManifold);
// AdjacencyMatrix adj = generate_adjacency_matrix_cotan(F, V, V2E, E2E, nonManifold);
AdjacencyMatrix adj = generate_adjacency_matrix_uniform(F, V2E, E2E, nonManifold);
VectorXf A;
generate_smooth_normals(F, V, V2E, E2E, nonManifold, N);
compute_dual_vertex_areas(F, V, V2E, E2E, nonManifold, A);
MultiResolutionHierarchy mRes;
mRes.setF(std::move(F));
mRes.setV(std::move(V));
mRes.setN(std::move(N));
mRes.setE2E(std::move(E2E));
mRes.setAdj(std::move(adj));
mRes.setA(std::move(A));
mRes.setScale(scale);
printf("building multiresolution hierarchy\n");
mRes.build(deterministic);
mRes.resetSolution();
/* set up edge constraints */
mRes.clearConstraints();
for (int i = 0; i < mesh->totedge; i++) {
RemeshEdge *e = mesh->edges + i;
const MatrixXu &F = mRes.F();
const MatrixXf &N = mRes.N(), &V = mRes.V();
const VectorXu &E2E = mRes.E2E();
uint32_t i0 = (uint32_t)e->v1;
uint32_t i1 = (uint32_t)e->v2;
Vector3f p0 = V.col(i0), p1 = V.col(i1);
if (0 && (e->flag & REMESH_EDGE_USE_DIR)) {
Vector3f dir(e->dir);
if (dir.squaredNorm() > 0) {
mRes.CO().col(i0) = p0;
mRes.CO().col(i1) = p1;
mRes.CQ().col(i0) = mRes.CQ().col(i1) = dir;
mRes.CQw()[i0] = mRes.CQw()[i1] = mRes.COw()[i0] = mRes.COw()[i1] = 0.05f;
}
}
else if (e->flag & REMESH_EDGE_BOUNDARY) {
Vector3f edge = p1 - p0;
creaseSet.insert((uint32_t)e->v1);
creaseSet.insert((uint32_t)e->v2);
if (edge.squaredNorm() > 0) {
edge.normalize();
mRes.CO().col(i0) = p0;
mRes.CO().col(i1) = p1;
mRes.CQ().col(i0) = mRes.CQ().col(i1) = edge;
mRes.CQw()[i0] = mRes.CQw()[i1] = mRes.COw()[i0] = mRes.COw()[i1] = 1.0f;
}
}
}
mRes.propagateConstraints(rosy, posy);
Optimizer opt(mRes, false);
opt.setExtrinsic(extrinsic);
opt.setRoSy(rosy);
opt.setPoSy(posy);
printf("optimizing orientation field\n");
for (int step = 0; step < 1; step++) {
opt.optimizeOrientations(-1);
opt.notify();
opt.wait();
}
std::map<uint32_t, uint32_t> sing;
compute_orientation_singularities(mRes, sing, extrinsic, rosy);
cout << "Orientation field has " << sing.size() << " singularities." << endl;
printf("optimizing position field\n");
for (int step = 0; step < 1; step++) {
opt.optimizePositions(-1);
opt.notify();
opt.wait();
}
std::map<uint32_t, Vector2i> pos_sing;
compute_position_singularities(mRes, sing, pos_sing, extrinsic, rosy, posy);
cout << "Position field has " << pos_sing.size() << " singularities." << endl;
opt.shutdown();
std::vector<std::vector<TaggedLink>> adj_extracted;
MatrixXu F_extracted;
MatrixXf V_extracted;
MatrixXf N_extracted;
MatrixXf Nf_extracted;
std::set<uint32_t> creaseOut;
printf("extracting mesh\n");
extract_graph(mRes,
extrinsic,
rosy,
posy,
adj_extracted,
V_extracted,
N_extracted,
creaseSet,
creaseOut,
deterministic,
true,
true,
true);
extract_faces(adj_extracted,
V_extracted,
N_extracted,
Nf_extracted,
F_extracted,
posy,
mRes.scale(),
creaseOut,
true,
false,
nullptr,
0);
// F_extracted = mRes.F();
// V_extracted = mRes.V();
mesh->totoutface = F_extracted.cols();
mesh->totoutvert = V_extracted.cols();
int sides = F_extracted.rows();
mesh->outfaces = (RemeshOutFace *)MEM_malloc_arrayN(
mesh->totoutface, sizeof(RemeshOutFace), "RemeshOutFaces");
mesh->outverts = (RemeshVertex *)MEM_malloc_arrayN(
mesh->totoutvert, sizeof(RemeshVertex), "RemeshOutVerts");
mesh->out_scracth = (int *)MEM_malloc_arrayN(
mesh->totoutface * sides, sizeof(int), "out_scratch");
printf(
"sides:%d\ntotal faces: %d\ntotal verts: %d\n", sides, mesh->totoutface, mesh->totoutvert);
RemeshOutFace *f = mesh->outfaces;
int totface = mesh->totoutface;
int i = 0, fi = 0, li = 0;
/* Check for irregular faces */
std::map<uint32_t, std::pair<uint32_t, std::map<uint32_t, uint32_t>>> irregular;
size_t nIrregular = 0;
for (; fi < totface; fi++) {
if (F_extracted(2, fi) == F_extracted(3, fi)) {
nIrregular++;
auto &value = irregular[F_extracted(2, fi)];
value.first = fi;
value.second[F_extracted(0, fi)] = F_extracted(1, fi);
continue;
}
f->verts = mesh->out_scracth + li;
li += sides;
int j = 0;
for (j = 0; j < sides; j++) {
f->verts[j] = F_extracted(j, fi);
}
// if (j != sides) {
// i--;
//}
f->totvert = sides;
i++;
f++;
}
for (auto item : irregular) {
auto face = item.second;
uint32_t v = face.second.begin()->first, first = v, k = 0;
int j = 0;
f->verts = mesh->out_scracth + li;
while (true) {
v = face.second[v];
f->verts[j] = (int)v;
li++;
j++;
if (v == first || ++k == face.second.size())
break;
}
f->totvert = j;
f++;
i++;
}
printf("final totface: %d, alloc totface: %d\n", i, mesh->totoutface);
printf("final totloop: %d, alloc totloop: %d\n", li, mesh->totoutface * sides);
mesh->totoutface = i;
RemeshVertex *v = mesh->outverts;
for (int i = 0; i < mesh->totoutvert; i++, v++) {
for (int j = 0; j < 3; j++) {
v->co[j] = V_extracted(j, i);
v->no[j] = N_extracted(j, i);
}
}
}
void instant_meshes_finish(RemeshMesh *mesh)
{
/*
if (mesh->verts) {
MEM_freeN((void *)mesh->verts);
}
if (mesh->edges) {
MEM_freeN((void *)mesh->edges);
}
if (mesh->tris) {
MEM_freeN((void *)mesh->tris);
}*/
if (mesh->outverts) {
MEM_freeN((void *)mesh->outverts);
}
if (mesh->outfaces) {
MEM_freeN((void *)mesh->outfaces);
}
if (mesh->out_scracth) {
MEM_freeN((void *)mesh->out_scracth);
}
}
void instant_meshes_set_number_of_threads(int n)
{
instant_meshes_nprocs = n;
}
};

File diff suppressed because it is too large Load Diff

View File

@ -15,7 +15,6 @@
#pragma once
#include "hierarchy.h"
#include <map>
@ -29,133 +28,204 @@ extern Vector3f rotate180_by(const Vector3f &d, const Vector3f &n, int amount);
extern Vector2i rshift60(Vector2i shift, int amount);
extern Vector2i rshift90(Vector2i shift, int amount);
extern Vector2i rshift180(Vector2i shift, int amount);
extern Vector3f rotate_vector_into_plane(Vector3f q, const Vector3f &source_normal, const Vector3f &target_normal);
extern Vector3f rotate_vector_into_plane(Vector3f q,
const Vector3f &source_normal,
const Vector3f &target_normal);
/* Extrinsic & intrinsic orientation symmetry functors */
extern std::pair<Vector3f, Vector3f>
compat_orientation_intrinsic_2(const Vector3f &q0, const Vector3f &n0,
const Vector3f &q1, const Vector3f &n1);
extern std::pair<Vector3f, Vector3f> compat_orientation_intrinsic_2(const Vector3f &q0,
const Vector3f &n0,
const Vector3f &q1,
const Vector3f &n1);
extern std::pair<Vector3f, Vector3f>
compat_orientation_intrinsic_4(const Vector3f &q0, const Vector3f &n0,
const Vector3f &q1, const Vector3f &n1);
extern std::pair<Vector3f, Vector3f> compat_orientation_intrinsic_4(const Vector3f &q0,
const Vector3f &n0,
const Vector3f &q1,
const Vector3f &n1);
extern std::pair<Vector3f, Vector3f>
compat_orientation_intrinsic_4_knoeppel(const Vector3f &q0, const Vector3f &n0,
const Vector3f &q1, const Vector3f &n1);
extern std::pair<Vector3f, Vector3f> compat_orientation_intrinsic_4_knoeppel(const Vector3f &q0,
const Vector3f &n0,
const Vector3f &q1,
const Vector3f &n1);
extern std::pair<Vector3f, Vector3f>
compat_orientation_intrinsic_6(const Vector3f &q0, const Vector3f &n0,
const Vector3f &q1, const Vector3f &n1);
extern std::pair<Vector3f, Vector3f> compat_orientation_intrinsic_6(const Vector3f &q0,
const Vector3f &n0,
const Vector3f &q1,
const Vector3f &n1);
extern std::pair<Vector3f, Vector3f>
compat_orientation_extrinsic_2(const Vector3f &q0, const Vector3f &n0,
const Vector3f &q1, const Vector3f &n1);
extern std::pair<Vector3f, Vector3f> compat_orientation_extrinsic_2(const Vector3f &q0,
const Vector3f &n0,
const Vector3f &q1,
const Vector3f &n1);
extern std::pair<Vector3f, Vector3f>
compat_orientation_extrinsic_4(const Vector3f &q0, const Vector3f &n0,
const Vector3f &q1, const Vector3f &n1);
extern std::pair<Vector3f, Vector3f> compat_orientation_extrinsic_4(const Vector3f &q0,
const Vector3f &n0,
const Vector3f &q1,
const Vector3f &n1);
extern std::pair<Vector3f, Vector3f>
compat_orientation_extrinsic_6(const Vector3f &q0, const Vector3f &n0,
const Vector3f &q1, const Vector3f &n1);
extern std::pair<Vector3f, Vector3f> compat_orientation_extrinsic_6(const Vector3f &q0,
const Vector3f &n0,
const Vector3f &q1,
const Vector3f &n1);
extern std::pair<int, int>
compat_orientation_extrinsic_index_2(const Vector3f &q0, const Vector3f &n0,
const Vector3f &q1, const Vector3f &n1);
extern std::pair<int, int> compat_orientation_extrinsic_index_2(const Vector3f &q0,
const Vector3f &n0,
const Vector3f &q1,
const Vector3f &n1);
extern std::pair<int, int>
compat_orientation_extrinsic_index_4(const Vector3f &q0, const Vector3f &n0,
const Vector3f &q1, const Vector3f &n1);
extern std::pair<int, int> compat_orientation_extrinsic_index_4(const Vector3f &q0,
const Vector3f &n0,
const Vector3f &q1,
const Vector3f &n1);
extern std::pair<int, int>
compat_orientation_extrinsic_index_6(const Vector3f &q0, const Vector3f &n0,
const Vector3f &q1, const Vector3f &n1);
extern std::pair<int, int> compat_orientation_extrinsic_index_6(const Vector3f &q0,
const Vector3f &n0,
const Vector3f &q1,
const Vector3f &n1);
extern std::pair<int, int>
compat_orientation_intrinsic_index_2(const Vector3f &q0, const Vector3f &n0,
const Vector3f &q1, const Vector3f &n1);
extern std::pair<int, int> compat_orientation_intrinsic_index_2(const Vector3f &q0,
const Vector3f &n0,
const Vector3f &q1,
const Vector3f &n1);
extern std::pair<int, int>
compat_orientation_intrinsic_index_4(const Vector3f &q0, const Vector3f &n0,
const Vector3f &q1, const Vector3f &n1);
extern std::pair<int, int> compat_orientation_intrinsic_index_4(const Vector3f &q0,
const Vector3f &n0,
const Vector3f &q1,
const Vector3f &n1);
extern std::pair<int, int>
compat_orientation_intrinsic_index_6(const Vector3f &q0, const Vector3f &n0,
const Vector3f &q1, const Vector3f &n1);
extern std::pair<int, int> compat_orientation_intrinsic_index_6(const Vector3f &q0,
const Vector3f &n0,
const Vector3f &q1,
const Vector3f &n1);
/* Extrinsic & intrinsic position symmetry functors */
extern std::pair<Vector3f, Vector3f> compat_position_extrinsic_3(
const Vector3f &p0, const Vector3f &n0, const Vector3f &q0,
const Vector3f &o0, const Vector3f &p1, const Vector3f &n1,
const Vector3f &q1, const Vector3f &o1, Float scale, Float inv_scale);
extern std::pair<Vector3f, Vector3f> compat_position_extrinsic_3(const Vector3f &p0,
const Vector3f &n0,
const Vector3f &q0,
const Vector3f &o0,
const Vector3f &p1,
const Vector3f &n1,
const Vector3f &q1,
const Vector3f &o1,
Float scale,
Float inv_scale);
extern std::pair<Vector3f, Vector3f> compat_position_extrinsic_4(
const Vector3f &p0, const Vector3f &n0, const Vector3f &q0,
const Vector3f &o0, const Vector3f &p1, const Vector3f &n1,
const Vector3f &q1, const Vector3f &o1, Float scale, Float inv_scale);
extern std::pair<Vector3f, Vector3f> compat_position_extrinsic_4(const Vector3f &p0,
const Vector3f &n0,
const Vector3f &q0,
const Vector3f &o0,
const Vector3f &p1,
const Vector3f &n1,
const Vector3f &q1,
const Vector3f &o1,
Float scale,
Float inv_scale);
extern std::pair<Vector2i, Vector2i> compat_position_extrinsic_index_3(
const Vector3f &p0, const Vector3f &n0, const Vector3f &q0,
const Vector3f &o0, const Vector3f &p1, const Vector3f &n1,
const Vector3f &q1, const Vector3f &o1, Float scale, Float inv_scale,
Float *error = nullptr);
extern std::pair<Vector2i, Vector2i> compat_position_extrinsic_index_3(const Vector3f &p0,
const Vector3f &n0,
const Vector3f &q0,
const Vector3f &o0,
const Vector3f &p1,
const Vector3f &n1,
const Vector3f &q1,
const Vector3f &o1,
Float scale,
Float inv_scale,
Float *error = nullptr);
extern std::pair<Vector2i, Vector2i> compat_position_extrinsic_index_4(
const Vector3f &p0, const Vector3f &n0, const Vector3f &q0,
const Vector3f &o0, const Vector3f &p1, const Vector3f &n1,
const Vector3f &q1, const Vector3f &o1, Float scale, Float inv_scale,
Float *error = nullptr);
extern std::pair<Vector2i, Vector2i> compat_position_extrinsic_index_4(const Vector3f &p0,
const Vector3f &n0,
const Vector3f &q0,
const Vector3f &o0,
const Vector3f &p1,
const Vector3f &n1,
const Vector3f &q1,
const Vector3f &o1,
Float scale,
Float inv_scale,
Float *error = nullptr);
extern std::pair<Vector3f, Vector3f> compat_position_intrinsic_3(
const Vector3f &p0, const Vector3f &n0, const Vector3f &q0,
const Vector3f &o0, const Vector3f &p1, const Vector3f &n1,
const Vector3f &q1, const Vector3f &o1, Float scale, Float inv_scale);
extern std::pair<Vector3f, Vector3f> compat_position_intrinsic_3(const Vector3f &p0,
const Vector3f &n0,
const Vector3f &q0,
const Vector3f &o0,
const Vector3f &p1,
const Vector3f &n1,
const Vector3f &q1,
const Vector3f &o1,
Float scale,
Float inv_scale);
extern std::pair<Vector3f, Vector3f> compat_position_intrinsic_4(
const Vector3f &p0, const Vector3f &n0, const Vector3f &q0,
const Vector3f &o0, const Vector3f &p1, const Vector3f &n1,
const Vector3f &q1, const Vector3f &o1, Float scale, Float inv_scale);
extern std::pair<Vector3f, Vector3f> compat_position_intrinsic_4(const Vector3f &p0,
const Vector3f &n0,
const Vector3f &q0,
const Vector3f &o0,
const Vector3f &p1,
const Vector3f &n1,
const Vector3f &q1,
const Vector3f &o1,
Float scale,
Float inv_scale);
extern std::pair<Vector2i, Vector2i> compat_position_intrinsic_index_3(
const Vector3f &p0, const Vector3f &n0, const Vector3f &q0,
const Vector3f &o0, const Vector3f &p1, const Vector3f &n1,
const Vector3f &q1, const Vector3f &o1, Float scale, Float inv_scale,
Float *error = nullptr);
extern std::pair<Vector2i, Vector2i> compat_position_intrinsic_index_3(const Vector3f &p0,
const Vector3f &n0,
const Vector3f &q0,
const Vector3f &o0,
const Vector3f &p1,
const Vector3f &n1,
const Vector3f &q1,
const Vector3f &o1,
Float scale,
Float inv_scale,
Float *error = nullptr);
extern std::pair<Vector2i, Vector2i> compat_position_intrinsic_index_4(
const Vector3f &p0, const Vector3f &n0, const Vector3f &q0,
const Vector3f &o0, const Vector3f &p1, const Vector3f &n1,
const Vector3f &q1, const Vector3f &o1, Float scale, Float inv_scale,
Float *error = nullptr);
extern std::pair<Vector2i, Vector2i> compat_position_intrinsic_index_4(const Vector3f &p0,
const Vector3f &n0,
const Vector3f &q0,
const Vector3f &o0,
const Vector3f &p1,
const Vector3f &n1,
const Vector3f &q1,
const Vector3f &o1,
Float scale,
Float inv_scale,
Float *error = nullptr);
/* Optimization kernels */
extern Float optimize_orientations(
MultiResolutionHierarchy &mRes, int level, bool extrinsic, int rosy,
const std::function<void(uint32_t)> &progress);
extern Float optimize_orientations(MultiResolutionHierarchy &mRes,
int level,
bool extrinsic,
int rosy,
const std::function<void(uint32_t)> &progress);
extern Float optimize_positions(
MultiResolutionHierarchy &mRes, int level, bool extrinsic, int posy,
const std::function<void(uint32_t)> &progress);
extern Float optimize_positions(MultiResolutionHierarchy &mRes,
int level,
bool extrinsic,
int posy,
const std::function<void(uint32_t)> &progress);
/* Singularity computation */
extern void compute_orientation_singularities(
const MultiResolutionHierarchy &mRes, std::map<uint32_t, uint32_t> &sing,
bool extrinsic, int rosy);
extern void compute_orientation_singularities(const MultiResolutionHierarchy &mRes,
std::map<uint32_t, uint32_t> &sing,
bool extrinsic,
int rosy);
extern void
compute_position_singularities(const MultiResolutionHierarchy &mRes,
const std::map<uint32_t, uint32_t> &orient_sing,
std::map<uint32_t, Vector2i> &pos_sing,
bool extrinsic, int rosy, int posy);
extern void compute_position_singularities(const MultiResolutionHierarchy &mRes,
const std::map<uint32_t, uint32_t> &orient_sing,
std::map<uint32_t, Vector2i> &pos_sing,
bool extrinsic,
int rosy,
int posy);
/* Field optimizer (invokes optimization kernels in a separate thread) */
class Serializer;
class Optimizer {
public:
public:
/* clang-format off */
Optimizer(MultiResolutionHierarchy &mRes, bool interactive);
void save(Serializer &state);
void load(const Serializer &state);
@ -193,30 +263,34 @@ public:
const VectorXf &error() { return mError; }
#endif
void moveSingularity(const std::vector<uint32_t> &path, bool orientations) {
std::lock_guard<ordered_lock> lock(mRes.mutex());
mAttractorStrokes.push_back(std::make_pair(orientations, path));
setLevel(0);
}
/* clang-format on */
void run();
protected:
MultiResolutionHierarchy &mRes;
std::vector<std::pair<bool, std::vector<uint32_t>>> mAttractorStrokes;
bool mRunning;
bool mOptimizeOrientations;
bool mOptimizePositions;
std::thread mThread;
std::condition_variable_any mCond;
int mLevel, mLevelIterations;
bool mHierarchical;
int mRoSy, mPoSy;
bool mExtrinsic;
bool mInteractive;
double mLastUpdate;
Float mProgress;
void moveSingularity(const std::vector<uint32_t> &path, bool orientations)
{
std::lock_guard<ordered_lock> lock(mRes.mutex());
mAttractorStrokes.push_back(std::make_pair(orientations, path));
setLevel(0);
}
void run();
protected:
MultiResolutionHierarchy &mRes;
std::vector<std::pair<bool, std::vector<uint32_t>>> mAttractorStrokes;
bool mRunning;
bool mOptimizeOrientations;
bool mOptimizePositions;
std::thread mThread;
std::condition_variable_any mCond;
int mLevel, mLevelIterations;
bool mHierarchical;
int mRoSy, mPoSy;
bool mExtrinsic;
bool mInteractive;
double mLastUpdate;
Float mProgress;
#ifdef VISUALIZE_ERROR
VectorXf mError;
VectorXf mError;
#endif
Timer<> mTimer;
Timer<> mTimer;
};

View File

@ -18,114 +18,250 @@
class Serializer;
extern AdjacencyMatrix
downsample_graph(const AdjacencyMatrix adj, const MatrixXf &V,
const MatrixXf &N, const VectorXf &areas, MatrixXf &V_p,
MatrixXf &V_n, VectorXf &areas_p, MatrixXu &to_upper,
VectorXu &to_lower, bool deterministic = false,
const ProgressCallback &progress = ProgressCallback());
extern AdjacencyMatrix downsample_graph(const AdjacencyMatrix adj,
const MatrixXf &V,
const MatrixXf &N,
const VectorXf &areas,
MatrixXf &V_p,
MatrixXf &V_n,
VectorXf &areas_p,
MatrixXu &to_upper,
VectorXu &to_lower,
bool deterministic = false,
const ProgressCallback &progress = ProgressCallback());
struct MultiResolutionHierarchy {
enum { MAX_DEPTH = 25 };
public:
MultiResolutionHierarchy();
void free();
void save(Serializer &state);
void load(const Serializer &state);
enum { MAX_DEPTH = 25 };
int levels() const { return (int) mV.size(); }
public:
MultiResolutionHierarchy();
void free();
void save(Serializer &state);
void load(const Serializer &state);
void build(bool deterministic = false,
const ProgressCallback &progress = ProgressCallback());
int levels() const
{
return (int)mV.size();
}
void printStatistics() const;
void resetSolution();
void build(bool deterministic = false, const ProgressCallback &progress = ProgressCallback());
inline ordered_lock &mutex() { return mMutex; }
void printStatistics() const;
void resetSolution();
inline const std::vector<std::vector<uint32_t>> &phases(int level) const { return mPhases[level]; }
inline const AdjacencyMatrix &adj(int level = 0) const { return mAdj[level]; }
inline AdjacencyMatrix &adj(int level = 0) { return mAdj[level]; }
inline const MatrixXf &V(int level = 0) const { return mV[level]; }
inline const MatrixXf &N(int level = 0) const { return mN[level]; }
inline const VectorXf &A(int level = 0) const { return mA[level]; }
inline const MatrixXu &toUpper(int level) const { return mToUpper[level]; }
inline const VectorXu &toLower(int level) const { return mToLower[level]; }
inline const MatrixXf &Q(int level = 0) const { return mQ[level]; }
inline const MatrixXf &O(int level = 0) const { return mO[level]; }
inline const MatrixXf &CQ(int level = 0) const { return mCQ[level]; }
inline const MatrixXf &CO(int level = 0) const { return mCO[level]; }
inline const VectorXf &CQw(int level = 0) const { return mCQw[level]; }
inline const VectorXf &COw(int level = 0) const { return mCOw[level]; }
inline const MatrixXu &F() const { return mF; }
inline const VectorXu &E2E() const { return mE2E; }
inline MatrixXf &Q(int level = 0) { return mQ[level]; }
inline MatrixXf &O(int level = 0) { return mO[level]; }
inline MatrixXf &CQ(int level = 0) { return mCQ[level]; }
inline MatrixXf &CO(int level = 0) { return mCO[level]; }
inline VectorXf &CQw(int level = 0) { return mCQw[level]; }
inline VectorXf &COw(int level = 0) { return mCOw[level]; }
inline ordered_lock &mutex()
{
return mMutex;
}
inline void setF(MatrixXu &&F) { mF = std::move(F); }
inline void setE2E(VectorXu &&E2E) { mE2E = std::move(E2E); }
inline void setV(MatrixXf &&V) { mV.clear(); mV.push_back(std::move(V)); }
inline void setN(MatrixXf &&N) { mN.clear(); mN.push_back(std::move(N)); }
inline void setA(MatrixXf &&A) { mA.clear(); mA.push_back(std::move(A)); }
inline void setAdj(AdjacencyMatrix &&adj) { mAdj.clear(); mAdj.push_back(std::move(adj)); }
inline const std::vector<std::vector<uint32_t>> &phases(int level) const
{
return mPhases[level];
}
inline const AdjacencyMatrix &adj(int level = 0) const
{
return mAdj[level];
}
inline AdjacencyMatrix &adj(int level = 0)
{
return mAdj[level];
}
inline const MatrixXf &V(int level = 0) const
{
return mV[level];
}
inline const MatrixXf &N(int level = 0) const
{
return mN[level];
}
inline const VectorXf &A(int level = 0) const
{
return mA[level];
}
inline const MatrixXu &toUpper(int level) const
{
return mToUpper[level];
}
inline const VectorXu &toLower(int level) const
{
return mToLower[level];
}
inline const MatrixXf &Q(int level = 0) const
{
return mQ[level];
}
inline const MatrixXf &O(int level = 0) const
{
return mO[level];
}
inline const MatrixXf &CQ(int level = 0) const
{
return mCQ[level];
}
inline const MatrixXf &CO(int level = 0) const
{
return mCO[level];
}
inline const VectorXf &CQw(int level = 0) const
{
return mCQw[level];
}
inline const VectorXf &COw(int level = 0) const
{
return mCOw[level];
}
inline const MatrixXu &F() const
{
return mF;
}
inline const VectorXu &E2E() const
{
return mE2E;
}
inline MatrixXf &Q(int level = 0)
{
return mQ[level];
}
inline MatrixXf &O(int level = 0)
{
return mO[level];
}
inline MatrixXf &CQ(int level = 0)
{
return mCQ[level];
}
inline MatrixXf &CO(int level = 0)
{
return mCO[level];
}
inline VectorXf &CQw(int level = 0)
{
return mCQw[level];
}
inline VectorXf &COw(int level = 0)
{
return mCOw[level];
}
inline uint32_t size(int level = 0) const { return mV[level].cols(); }
inline void setF(MatrixXu &&F)
{
mF = std::move(F);
}
inline void setE2E(VectorXu &&E2E)
{
mE2E = std::move(E2E);
}
inline void setV(MatrixXf &&V)
{
mV.clear();
mV.push_back(std::move(V));
}
inline void setN(MatrixXf &&N)
{
mN.clear();
mN.push_back(std::move(N));
}
inline void setA(MatrixXf &&A)
{
mA.clear();
mA.push_back(std::move(A));
}
inline void setAdj(AdjacencyMatrix &&adj)
{
mAdj.clear();
mAdj.push_back(std::move(adj));
}
inline Float scale() const { return mScale; }
inline void setScale(Float scale) { mScale = scale; }
inline int iterationsQ() const { return mIterationsQ; }
inline void setIterationsQ(int iterationsQ) { mIterationsQ = iterationsQ; }
inline int iterationsO() const { return mIterationsO; }
inline void setIterationsO(int iterationsO) { mIterationsO = iterationsO; }
inline size_t totalSize() const { return mTotalSize; }
inline uint32_t size(int level = 0) const
{
return mV[level].cols();
}
void clearConstraints();
void propagateConstraints(int rosy, int posy);
void propagateSolution(int rosy);
inline Float scale() const
{
return mScale;
}
inline void setScale(Float scale)
{
mScale = scale;
}
inline int iterationsQ() const
{
return mIterationsQ;
}
inline void setIterationsQ(int iterationsQ)
{
mIterationsQ = iterationsQ;
}
inline int iterationsO() const
{
return mIterationsO;
}
inline void setIterationsO(int iterationsO)
{
mIterationsO = iterationsO;
}
inline size_t totalSize() const
{
return mTotalSize;
}
inline Vector3f faceCenter(uint32_t idx) const {
Vector3f pos = Vector3f::Zero();
for (int i = 0; i < 3; ++i)
pos += mV[0].col(mF(i, idx));
return pos * (1.0f / 3.0f);
}
void clearConstraints();
void propagateConstraints(int rosy, int posy);
void propagateSolution(int rosy);
inline Vector3f faceNormal(uint32_t idx) const {
Vector3f p0 = mV[0].col(mF(0, idx)),
p1 = mV[0].col(mF(1, idx)),
p2 = mV[0].col(mF(2, idx));
return (p1-p0).cross(p2-p0).normalized();
}
inline Vector3f faceCenter(uint32_t idx) const
{
Vector3f pos = Vector3f::Zero();
for (int i = 0; i < 3; ++i)
pos += mV[0].col(mF(i, idx));
return pos * (1.0f / 3.0f);
}
/* Flags which indicate whether the integer variables are froen */
bool frozenQ() const { return mFrozenQ; }
bool frozenO() const { return mFrozenO; }
void setFrozenQ(bool frozen) { mFrozenQ = frozen; }
void setFrozenO(bool frozen) { mFrozenO = frozen; }
public:
MatrixXu mF;
VectorXu mE2E;
std::vector<std::vector<std::vector<uint32_t>>> mPhases;
std::vector<AdjacencyMatrix> mAdj;
std::vector<MatrixXf> mV;
std::vector<MatrixXf> mN;
std::vector<VectorXf> mA;
std::vector<VectorXu> mToLower;
std::vector<MatrixXu> mToUpper;
std::vector<MatrixXf> mO;
std::vector<MatrixXf> mQ;
std::vector<MatrixXf> mCQ;
std::vector<MatrixXf> mCO;
std::vector<VectorXf> mCQw;
std::vector<VectorXf> mCOw;
bool mFrozenQ, mFrozenO;
ordered_lock mMutex;
Float mScale;
int mIterationsQ;
int mIterationsO;
uint32_t mTotalSize;
inline Vector3f faceNormal(uint32_t idx) const
{
Vector3f p0 = mV[0].col(mF(0, idx)), p1 = mV[0].col(mF(1, idx)), p2 = mV[0].col(mF(2, idx));
return (p1 - p0).cross(p2 - p0).normalized();
}
/* Flags which indicate whether the integer variables are froen */
bool frozenQ() const
{
return mFrozenQ;
}
bool frozenO() const
{
return mFrozenO;
}
void setFrozenQ(bool frozen)
{
mFrozenQ = frozen;
}
void setFrozenO(bool frozen)
{
mFrozenO = frozen;
}
public:
MatrixXu mF;
VectorXu mE2E;
std::vector<std::vector<std::vector<uint32_t>>> mPhases;
std::vector<AdjacencyMatrix> mAdj;
std::vector<MatrixXf> mV;
std::vector<MatrixXf> mN;
std::vector<VectorXf> mA;
std::vector<VectorXu> mToLower;
std::vector<MatrixXu> mToUpper;
std::vector<MatrixXf> mO;
std::vector<MatrixXf> mQ;
std::vector<MatrixXf> mCQ;
std::vector<MatrixXf> mCO;
std::vector<VectorXf> mCQw;
std::vector<VectorXf> mCOw;
bool mFrozenQ, mFrozenO;
ordered_lock mMutex;
Float mScale;
int mIterationsQ;
int mIterationsO;
uint32_t mTotalSize;
};

File diff suppressed because it is too large Load Diff

View File

@ -43,12 +43,19 @@ struct Mesh *BKE_mesh_remesh_quadriflow(const struct Mesh *mesh,
void (*update_cb)(void *, float progress, int *cancel),
void *update_cb_data);
struct Mesh *BKE_mesh_remesh_instant_meshes(const Mesh *input_mesh,
int target_faces,
void (*update_cb)(void *, float progress, int *cancel),
void *update_cb_data);
/* Data reprojection functions */
void BKE_mesh_remesh_reproject_paint_mask(struct Mesh *target, struct Mesh *source);
void BKE_remesh_reproject_vertex_paint(struct Mesh *target, const struct Mesh *source);
void BKE_remesh_reproject_sculpt_face_sets(struct Mesh *target, struct Mesh *source);
void BKE_remesh_reproject_materials(struct Mesh *target, struct Mesh *source);
void BKE_mesh_remesh_sculpt_array_update(struct Object *ob, struct Mesh *target, struct Mesh *source);
void BKE_mesh_remesh_sculpt_array_update(struct Object *ob,
struct Mesh *target,
struct Mesh *source);
#ifdef __cplusplus
}

View File

@ -760,6 +760,16 @@ if(WITH_OPENVDB)
add_definitions(-DWITH_OPENVDB ${OPENVDB_DEFINITIONS})
endif()
if(WITH_INSTANT_MESHES)
list(APPEND INC
../../../intern/instant-meshes
)
list(APPEND LIB
bf_intern_instant_meshes
)
add_definitions(-DWITH_QUADRIFLOW)
endif()
if(WITH_QUADRIFLOW)
list(APPEND INC
../../../intern/quadriflow

View File

@ -2496,6 +2496,11 @@ void BKE_brush_color_set(struct Scene *scene,
ch = BRUSHSET_LOOKUP(brush->channels, color);
if (!ch) {
BKE_brush_channelset_add_builtin(brush->channels, "color");
ch = BRUSHSET_LOOKUP(brush->channels, color);
}
if ((ch->flag & BRUSH_CHANNEL_INHERIT) && scene->toolsettings->sculpt &&
scene->toolsettings->sculpt->channels) {
BrushChannel *pch = BRUSHSET_LOOKUP(scene->toolsettings->sculpt->channels, color);

View File

@ -1825,6 +1825,8 @@ void BKE_brush_builtin_create(Brush *brush, int tool)
GETCH(dyntopo_disabled)->ivalue = 1;
break;
case SCULPT_TOOL_SNAKE_HOOK:
GETCH(strength)->mappings[BRUSH_MAPPING_PRESSURE].flag &= ~BRUSH_MAPPING_ENABLED;
GETCH(dyntopo_mode)->ivalue = DYNTOPO_LOCAL_COLLAPSE | DYNTOPO_SUBDIVIDE;
GETCH(dyntopo_mode)->flag = BRUSH_CHANNEL_INHERIT_IF_UNSET;
GETCH(strength)->fvalue = 1.0f;

View File

@ -27,6 +27,10 @@
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <functional>
#include <tuple>
#include <unordered_map>
#include <vector>
#include "MEM_guardedalloc.h"
@ -34,6 +38,7 @@
#include "BLI_float3.hh"
#include "BLI_index_range.hh"
#include "BLI_span.hh"
#include "BLI_threads.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
@ -61,6 +66,8 @@
# include "quadriflow_capi.hpp"
#endif
#include "instant_meshes_c_api.h"
using blender::Array;
using blender::float3;
using blender::IndexRange;
@ -230,6 +237,259 @@ static Mesh *remesh_quadriflow(const Mesh *input_mesh,
}
#endif
struct HashEdge {
std::size_t operator()(std::tuple<int, int> const &edge) const noexcept
{
int v1 = std::get<0>(edge);
int v2 = std::get<1>(edge);
if (v1 > v2) {
std::swap(v1, v2);
}
return std::size_t(v1);
}
};
// TODO: move from sculpt_smooth.c to blenlib or somewhere
extern "C" int closest_vec_to_perp(
float dir[3], float r_dir2[3], float no[3], float *buckets, float w);
ATTR_NO_OPT Mesh *BKE_mesh_remesh_instant_meshes(const Mesh *input_mesh,
int target_faces,
void (*update_cb)(void *,
float progress,
int *cancel),
void *update_cb_data)
{
/* Ensure that the triangulated mesh data is up to data */
const MLoopTri *looptri = BKE_mesh_runtime_looptri_ensure(input_mesh);
MeshElemMap *epmap = nullptr;
int *epmem = nullptr;
instant_meshes_set_number_of_threads(BLI_system_thread_count());
BKE_mesh_edge_poly_map_create(&epmap,
&epmem,
input_mesh->medge,
input_mesh->totedge,
input_mesh->mpoly,
input_mesh->totpoly,
input_mesh->mloop,
input_mesh->totloop);
/* Gather the required data for export to the internal quadriflow mesh format. */
MVertTri *verttri = (MVertTri *)MEM_callocN(
sizeof(*verttri) * BKE_mesh_runtime_looptri_len(input_mesh), "remesh_looptri");
BKE_mesh_runtime_verttri_from_looptri(
verttri, input_mesh->mloop, looptri, BKE_mesh_runtime_looptri_len(input_mesh));
MPropCol *dirs = NULL;
int idx = CustomData_get_named_layer_index(&input_mesh->vdata, CD_PROP_COLOR, "_rake_temp");
if (idx >= 0) {
dirs = (MPropCol *)input_mesh->vdata.layers[idx].data;
}
const int totfaces = BKE_mesh_runtime_looptri_len(input_mesh);
const int totverts = input_mesh->totvert;
std::unordered_map<std::tuple<int, int>, int, HashEdge> eflags;
auto make_edge_pair = [](int v1, int v2) {
return std::tuple<int, int>(std::min(v1, v2), std::max(v1, v2));
};
Array<RemeshVertex> verts(totverts);
Array<RemeshTri> faces(totfaces);
std::vector<RemeshEdge> edges;
for (int i : IndexRange(totverts)) {
copy_v3_v3(verts[i].co, input_mesh->mvert[i].co);
normal_short_to_float_v3(verts[i].no, input_mesh->mvert[i].no);
}
int *fsets = (int *)CustomData_get_layer(&input_mesh->pdata, CD_SCULPT_FACE_SETS);
for (const int i : IndexRange(input_mesh->totedge)) {
MEdge *me = input_mesh->medge + i;
MeshElemMap *mep = epmap + i;
bool ok = mep->count == 1;
ok = ok || (me->flag & (ME_SEAM | ME_SHARP));
if (fsets && !ok) {
int last_fset;
// try face sets
for (int j = 0; j < mep->count; j++) {
int fset = abs(fsets[mep->indices[j]]);
if (j > 0 && last_fset != fset) {
ok = true;
break;
}
last_fset = fset;
}
}
if (ok || dirs) {
RemeshEdge e;
e.flag = ok ? REMESH_EDGE_BOUNDARY : 0;
e.v1 = me->v1;
e.v2 = me->v2;
if (dirs && !ok) {
e.flag |= REMESH_EDGE_USE_DIR;
float d1[3], d2[3], vec[3], no1[3], no2[3];
// get rake directions from verts
copy_v3_v3(d1, dirs[me->v1].color);
copy_v3_v3(d2, dirs[me->v2].color);
// edge vec
sub_v3_v3v3(vec, input_mesh->mvert[me->v2].co, input_mesh->mvert[me->v1].co);
normalize_v3(vec);
// build edge normal
normal_short_to_float_v3(no1, input_mesh->mvert[me->v1].no);
normal_short_to_float_v3(no2, input_mesh->mvert[me->v2].no);
add_v3_v3(no1, no2);
normalize_v3(no1);
float buckets[8];
// find closest of four 90 degree rotations to vec for d1, d2
closest_vec_to_perp(vec, d1, no1, buckets, 1.0f);
closest_vec_to_perp(vec, d2, no1, buckets, 1.0f);
// build final direction
add_v3_v3(d1, d2);
normalize_v3(d1);
copy_v3_v3(e.dir, d1);
}
eflags[make_edge_pair(me->v1, me->v2)] = i;
edges.push_back(e);
}
}
for (int i : IndexRange(totfaces)) {
MVertTri *mtri = verttri + i;
faces[i].v1 = mtri->tri[0];
faces[i].v2 = mtri->tri[1];
faces[i].v3 = mtri->tri[2];
for (int j = 0; j < 3; j++) {
int v1 = mtri->tri[j];
int v2 = mtri->tri[(j + 1) % 3];
auto item = eflags.find(make_edge_pair(v1, v2));
if (item != eflags.end()) {
int flag = item->second;
faces[i].eflags[j] = flag;
}
}
}
RemeshMesh remesh;
remesh.tris = faces.data();
remesh.tottri = (int)faces.size();
remesh.verts = verts.data();
remesh.edges = edges.data();
remesh.totedge = (int)edges.size();
remesh.totvert = (int)verts.size();
instant_meshes_run(&remesh);
int totloop = 0;
for (int i : IndexRange(remesh.totoutface)) {
totloop += remesh.outfaces[i].totvert;
}
Mesh *mesh = BKE_mesh_new_nomain(remesh.totoutvert, 0, 0, totloop, remesh.totoutface);
for (int i : IndexRange(remesh.totoutvert)) {
MVert *mv = mesh->mvert + i;
RemeshVertex *v = remesh.outverts + i;
copy_v3_v3(mv->co, v->co);
normal_float_to_short_v3(mv->no, v->no);
}
int li = 0;
MLoop *ml = mesh->mloop;
for (int i : IndexRange(remesh.totoutface)) {
RemeshOutFace *f = remesh.outfaces + i;
MPoly *mp = mesh->mpoly + i;
mp->loopstart = li;
mp->totloop = f->totvert;
for (int j = 0; j < f->totvert; j++, ml++, li++) {
ml->v = f->verts[j];
}
}
instant_meshes_finish(&remesh);
BKE_mesh_calc_edges(mesh, false, false);
BKE_mesh_calc_normals(mesh);
// C++ doesn't seem to like the MEM_SAFE_FREE macro
if (epmap) {
MEM_freeN((void *)epmap);
}
if (epmem) {
MEM_freeN((void *)epmem);
}
return mesh;
#if 0
/* Construct the new output mesh */
Mesh *mesh = BKE_mesh_new_nomain(qrd.out_totverts, 0, 0, qrd.out_totfaces * 4, qrd.out_totfaces);
for (const int i : IndexRange(qrd.out_totverts)) {
copy_v3_v3(mesh->mvert[i].co, &qrd.out_verts[i * 3]);
}
for (const int i : IndexRange(qrd.out_totfaces)) {
MPoly &poly = mesh->mpoly[i];
const int loopstart = i * 4;
poly.loopstart = loopstart;
poly.totloop = 4;
mesh->mloop[loopstart].v = qrd.out_faces[loopstart];
mesh->mloop[loopstart + 1].v = qrd.out_faces[loopstart + 1];
mesh->mloop[loopstart + 2].v = qrd.out_faces[loopstart + 2];
mesh->mloop[loopstart + 3].v = qrd.out_faces[loopstart + 3];
}
BKE_mesh_calc_edges(mesh, false, false);
BKE_mesh_calc_normals(mesh);
MEM_freeN(qrd.out_faces);
MEM_freeN(qrd.out_verts);
if (epmap) {
MEM_freeN((void *)epmap);
}
if (epmem) {
MEM_freeN((void *)epmem);
}
return mesh;
#endif
return nullptr;
}
Mesh *BKE_mesh_remesh_quadriflow(const Mesh *mesh,
int target_faces,
int seed,

View File

@ -315,6 +315,7 @@ void TRANSFORM_OT_vertex_random(struct wmOperatorType *ot);
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);
void OBJECT_OT_instant_meshes_remesh(struct wmOperatorType *ot);
/* object_transfer_data.c */
void OBJECT_OT_data_transfer(struct wmOperatorType *ot);

View File

@ -285,6 +285,7 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_voxel_size_edit);
WM_operatortype_append(OBJECT_OT_quadriflow_remesh);
WM_operatortype_append(OBJECT_OT_instant_meshes_remesh);
}
void ED_operatormacros_object(void)

View File

@ -32,6 +32,7 @@
#include "BLI_math.h"
#include "BLI_string.h"
#include "BLI_string_utf8.h"
#include "BLI_threads.h"
#include "BLI_utildefines.h"
#include "DNA_mesh_types.h"
@ -801,8 +802,8 @@ static Mesh *remesh_symmetry_bisect(Object *ob, Mesh *mesh, eSymmetryAxes symmet
plane_no[axis] = -1.0f;
mesh_bisect_temp = mesh_bisect;
mesh_bisect = BKE_mesh_mirror_bisect_on_mirror_plane_for_modifier(ob,
&mmd, mesh_bisect, axis, plane_co, plane_no);
mesh_bisect = BKE_mesh_mirror_bisect_on_mirror_plane_for_modifier(
ob, &mmd, mesh_bisect, axis, plane_co, plane_no);
if (mesh_bisect_temp != mesh_bisect) {
BKE_id_free(nullptr, mesh_bisect_temp);
@ -1231,4 +1232,84 @@ void OBJECT_OT_quadriflow_remesh(wmOperatorType *ot)
255);
}
static void instant_mesh_update_cb(void *data, float progress, int *cancel)
{
}
static int instant_meshes_remesh_exec(bContext *C, wmOperator *op)
{
Object *ob = CTX_data_active_object(C);
Mesh *mesh = BKE_object_get_original_mesh(ob);
/* Run Quadriflow bisect operations on a copy of the mesh to keep the code readable without
* freeing the original ID */
Mesh *bisect_mesh = BKE_mesh_copy_for_eval(mesh, false);
/* Bisect the input mesh using the paint symmetry settings */
bisect_mesh = remesh_symmetry_bisect(
ob, bisect_mesh, (eSymmetryAxes)0); //(eSymmetryAxes)mesh->symmetry);
int target_faces = RNA_int_get(op->ptr, "target_faces");
Mesh *new_mesh = BKE_mesh_remesh_instant_meshes(
bisect_mesh, target_faces, instant_mesh_update_cb, nullptr);
if (!new_mesh) {
BKE_report(op->reports, RPT_ERROR, "Remesher failed to create mesh");
return OPERATOR_CANCELLED;
}
if (mesh->flag & ME_REMESH_REPROJECT_VOLUME || mesh->flag & ME_REMESH_REPROJECT_PAINT_MASK ||
mesh->flag & ME_REMESH_REPROJECT_SCULPT_FACE_SETS ||
mesh->flag & ME_REMESH_REPROJECT_MATERIALS) {
BKE_mesh_runtime_clear_geometry(mesh);
}
if (mesh->flag & ME_REMESH_REPROJECT_VOLUME) {
BKE_shrinkwrap_remesh_target_project(new_mesh, mesh, ob);
}
if (mesh->flag & ME_REMESH_REPROJECT_PAINT_MASK) {
BKE_mesh_remesh_reproject_paint_mask(new_mesh, mesh);
}
if (mesh->flag & ME_REMESH_REPROJECT_SCULPT_FACE_SETS) {
BKE_remesh_reproject_sculpt_face_sets(new_mesh, mesh);
}
if (mesh->flag & ME_REMESH_REPROJECT_MATERIALS) {
BKE_remesh_reproject_materials(new_mesh, mesh);
}
if (mesh->flag & ME_REMESH_REPROJECT_VERTEX_COLORS) {
BKE_mesh_runtime_clear_geometry(mesh);
BKE_remesh_reproject_vertex_paint(new_mesh, mesh);
}
BKE_mesh_nomain_to_mesh(new_mesh, mesh, ob, &CD_MASK_MESH, true);
BKE_mesh_batch_cache_dirty_tag(static_cast<Mesh *>(ob->data), BKE_MESH_BATCH_DIRTY_ALL);
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
return OPERATOR_FINISHED;
}
void OBJECT_OT_instant_meshes_remesh(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Instant Meshes Remesh";
ot->description =
"Create a new quad based mesh using the surface data of the current mesh. All data "
"layers will be lost";
ot->idname = "OBJECT_OT_instant_meshes_remesh";
/* api callbacks */
ot->poll = object_remesh_poll;
ot->exec = instant_meshes_remesh_exec;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
PropertyRNA *prop;
prop = RNA_def_int(ot->srna, "target_faces", 5000, 8, 1 << 23, "Face Count", "", 8, 100000);
}
/** \} */

View File

@ -369,16 +369,20 @@ const float *SCULPT_vertex_co_get(SculptSession *ss, SculptVertRef index)
return NULL;
}
const float *SCULPT_vertex_color_get(SculptSession *ss, SculptVertRef index)
const float *SCULPT_vertex_color_get(SculptSession *ss, SculptVertRef vertex)
{
if (vertex.i == SCULPT_REF_NONE) {
return NULL;
}
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES:
if (ss->vcol) {
return ss->vcol[index.i].color;
return ss->vcol[vertex.i].color;
}
break;
case PBVH_BMESH: {
BMVert *v = (BMVert *)index.i;
BMVert *v = (BMVert *)vertex.i;
if (ss->cd_vcol_offset >= 0) {
MPropCol *col = BM_ELEM_CD_GET_VOID_P(v, ss->cd_vcol_offset);
@ -962,7 +966,7 @@ SculptVertRef SCULPT_active_vertex_get(SculptSession *ss)
if (ELEM(BKE_pbvh_type(ss->pbvh), PBVH_FACES, PBVH_BMESH, PBVH_GRIDS)) {
return ss->active_vertex_index;
}
return BKE_pbvh_make_vref(0);
return BKE_pbvh_make_vref(SCULPT_REF_NONE);
}
const float *SCULPT_active_vertex_co_get(SculptSession *ss)
@ -8735,8 +8739,11 @@ static void sculpt_init_session(Main *bmain, Depsgraph *depsgraph, Scene *scene,
if (ob->sculpt != NULL) {
BKE_sculptsession_free(ob);
}
ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session");
ob->sculpt->mode_type = OB_MODE_SCULPT;
ob->sculpt->active_face_index.i = SCULPT_REF_NONE;
ob->sculpt->active_vertex_index.i = SCULPT_REF_NONE;
BKE_sculpt_ensure_orig_mesh_data(scene, ob);