Skip to content

Commit

Permalink
Add API to specify which vertices to lock when simplifying (#601)
Browse files Browse the repository at this point in the history
meshopt_simplifyWithAttributes now takes an optional unsigned char* array that allows to specify a locked flag per vertex.
  • Loading branch information
oisyn committed Apr 2, 2024
1 parent bd7067b commit 7fe5274
Show file tree
Hide file tree
Showing 9 changed files with 69 additions and 49 deletions.
2 changes: 1 addition & 1 deletion demo/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -478,7 +478,7 @@ void simplifyAttr(const Mesh& mesh, float threshold = 0.2f)
const float attr_weights[3] = {nrm_weight, nrm_weight, nrm_weight};

lod.indices.resize(mesh.indices.size()); // note: simplify needs space for index_count elements in the destination array, not target_index_count
lod.indices.resize(meshopt_simplifyWithAttributes(&lod.indices[0], &mesh.indices[0], mesh.indices.size(), &mesh.vertices[0].px, mesh.vertices.size(), sizeof(Vertex), &mesh.vertices[0].nx, sizeof(Vertex), attr_weights, 3, target_index_count, target_error, 0, &result_error));
lod.indices.resize(meshopt_simplifyWithAttributes(&lod.indices[0], &mesh.indices[0], mesh.indices.size(), &mesh.vertices[0].px, mesh.vertices.size(), sizeof(Vertex), &mesh.vertices[0].nx, sizeof(Vertex), attr_weights, 3, NULL, target_index_count, target_error, 0, &result_error));

lod.vertices.resize(lod.indices.size() < mesh.vertices.size() ? lod.indices.size() : mesh.vertices.size()); // note: this is just to reduce the cost of resize()
lod.vertices.resize(meshopt_optimizeVertexFetch(&lod.vertices[0], &lod.indices[0], lod.indices.size(), &mesh.vertices[0], mesh.vertices.size(), sizeof(Vertex)));
Expand Down
2 changes: 1 addition & 1 deletion demo/simplify.html
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@

var res =
settings.useAttributes
? MeshoptSimplifier.simplifyWithAttributes(indices, positions, stride, attrib, attributes, attrib_weights, target, threshold, flags)
? MeshoptSimplifier.simplifyWithAttributes(indices, positions, stride, attrib, attributes, attrib_weights, null, target, threshold, flags)
: MeshoptSimplifier.simplify(indices, positions, stride, target, threshold, flags);

console.timeEnd('simplify');
Expand Down
2 changes: 1 addition & 1 deletion demo/tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1181,7 +1181,7 @@ static void simplifyAttr()
{12, 14, 21, 21, 14, 23},
};

assert(meshopt_simplifyWithAttributes(ib[0], ib[0], 7 * 2 * 6, vb[0], 8 * 3, 6 * sizeof(float), vb[0] + 3, 6 * sizeof(float), attr_weights, 3, 6 * 3, 1e-2f) == 18);
assert(meshopt_simplifyWithAttributes(ib[0], ib[0], 7 * 2 * 6, vb[0], 8 * 3, 6 * sizeof(float), vb[0] + 3, 6 * sizeof(float), attr_weights, 3, NULL, 6 * 3, 1e-2f) == 18);
assert(memcmp(ib, expected, sizeof(expected)) == 0);
}

Expand Down
39 changes: 23 additions & 16 deletions js/meshopt_simplifier.js

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions js/meshopt_simplifier.module.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ export const MeshoptSimplifier: {
ready: Promise<void>;

useExperimentalFeatures: boolean;

compactMesh: (indices: Uint32Array) => [Uint32Array, number];

simplify: (indices: Uint32Array, vertex_positions: Float32Array, vertex_positions_stride: number, target_index_count: number, target_error: number, flags?: Flags[]) => [Uint32Array, number];

// Experimental; requires useExperimentalFeatures to be set to true
simplifyWithAttributes: (indices: Uint32Array, vertex_positions: Float32Array, vertex_positions_stride: number, vertex_attributes: Float32Array, vertex_attributes_stride: number, attribute_weights: number[], target_index_count: number, target_error: number, flags?: Flags[]) => [Uint32Array, number];
simplifyWithAttributes: (indices: Uint32Array, vertex_positions: Float32Array, vertex_positions_stride: number, vertex_attributes: Float32Array, vertex_attributes_stride: number, attribute_weights: number[], vertex_lock: boolean[], target_index_count: number, target_error: number, flags?: Flags[]) => [Uint32Array, number];

getScale: (vertex_positions: Float32Array, vertex_positions_stride: number) => number;

Expand Down
37 changes: 22 additions & 15 deletions js/meshopt_simplifier.module.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion js/meshopt_simplifier.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ var tests = {

var attr_weights = [0.01, 0.01, 0.01];

var res = simplifier.simplifyWithAttributes(ib, vb_pos, 3, vb_att, 3, attr_weights, 6 * 3, 1e-2);
var res = simplifier.simplifyWithAttributes(ib, vb_pos, 3, vb_att, 3, attr_weights, null, 6 * 3, 1e-2);

var expected = new Uint32Array([
0, 2, 9, 9, 2, 11,
Expand Down
9 changes: 5 additions & 4 deletions src/meshoptimizer.h
Original file line number Diff line number Diff line change
Expand Up @@ -357,9 +357,10 @@ MESHOPTIMIZER_API size_t meshopt_simplify(unsigned int* destination, const unsig
* vertex_attributes should have attribute_count floats for each vertex
* attribute_weights should have attribute_count floats in total; the weights determine relative priority of attributes between each other and wrt position. The recommended weight range is [1e-3..1e-1], assuming attribute data is in [0..1] range.
* attribute_count must be <= 16
* vertex_lock can be NULL; when not NULL, it should have vertex_count chars, 1 for each vertex; they determine which vertices are locked (1) or free to be simplified (0).
* TODO target_error/result_error currently use combined distance+attribute error; this may change in the future
*/
MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_simplifyWithAttributes(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, const float* vertex_attributes, size_t vertex_attributes_stride, const float* attribute_weights, size_t attribute_count, size_t target_index_count, float target_error, unsigned int options, float* result_error);
MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_simplifyWithAttributes(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, const float* vertex_attributes, size_t vertex_attributes_stride, const float* attribute_weights, size_t attribute_count, const unsigned char* vertex_lock, size_t target_index_count, float target_error, unsigned int options, float* result_error);

/**
* Experimental: Mesh simplifier (sloppy)
Expand Down Expand Up @@ -659,7 +660,7 @@ inline int meshopt_decodeIndexSequence(T* destination, size_t index_count, const
template <typename T>
inline size_t meshopt_simplify(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count, float target_error, unsigned int options = 0, float* result_error = NULL);
template <typename T>
inline size_t meshopt_simplifyWithAttributes(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, const float* vertex_attributes, size_t vertex_attributes_stride, const float* attribute_weights, size_t attribute_count, size_t target_index_count, float target_error, unsigned int options = 0, float* result_error = NULL);
inline size_t meshopt_simplifyWithAttributes(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, const float* vertex_attributes, size_t vertex_attributes_stride, const float* attribute_weights, size_t attribute_count, const unsigned char* vertex_lock, size_t target_index_count, float target_error, unsigned int options = 0, float* result_error = NULL);
template <typename T>
inline size_t meshopt_simplifySloppy(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count, float target_error, float* result_error = NULL);
template <typename T>
Expand Down Expand Up @@ -966,12 +967,12 @@ inline size_t meshopt_simplify(T* destination, const T* indices, size_t index_co
}

template <typename T>
inline size_t meshopt_simplifyWithAttributes(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, const float* vertex_attributes, size_t vertex_attributes_stride, const float* attribute_weights, size_t attribute_count, size_t target_index_count, float target_error, unsigned int options, float* result_error)
inline size_t meshopt_simplifyWithAttributes(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, const float* vertex_attributes, size_t vertex_attributes_stride, const float* attribute_weights, size_t attribute_count, const unsigned char* vertex_lock, size_t target_index_count, float target_error, unsigned int options, float* result_error)
{
meshopt_IndexAdapter<T> in(NULL, indices, index_count);
meshopt_IndexAdapter<T> out(destination, NULL, index_count);

return meshopt_simplifyWithAttributes(out.data, in.data, index_count, vertex_positions, vertex_count, vertex_positions_stride, vertex_attributes, vertex_attributes_stride, attribute_weights, attribute_count, target_index_count, target_error, options, result_error);
return meshopt_simplifyWithAttributes(out.data, in.data, index_count, vertex_positions, vertex_count, vertex_positions_stride, vertex_attributes, vertex_attributes_stride, attribute_weights, attribute_count, vertex_lock, target_index_count, target_error, options, result_error);
}

template <typename T>
Expand Down
19 changes: 12 additions & 7 deletions src/simplifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ static bool hasEdge(const EdgeAdjacency& adjacency, unsigned int a, unsigned int
return false;
}

static void classifyVertices(unsigned char* result, unsigned int* loop, unsigned int* loopback, size_t vertex_count, const EdgeAdjacency& adjacency, const unsigned int* remap, const unsigned int* wedge, unsigned int options)
static void classifyVertices(unsigned char* result, unsigned int* loop, unsigned int* loopback, size_t vertex_count, const EdgeAdjacency& adjacency, const unsigned int* remap, const unsigned int* wedge, const unsigned char* vertex_lock, unsigned int options)
{
memset(loop, -1, vertex_count * sizeof(unsigned int));
memset(loopback, -1, vertex_count * sizeof(unsigned int));
Expand Down Expand Up @@ -298,7 +298,12 @@ static void classifyVertices(unsigned char* result, unsigned int* loop, unsigned
{
if (remap[i] == i)
{
if (wedge[i] == i)
if (vertex_lock && vertex_lock[i])
{
// vertex is explicitly locked
result[i] = Kind_Locked;
}
else if (wedge[i] == i)
{
// no attribute seam, need to check if it's manifold
unsigned int openi = openinc[i], openo = openout[i];
Expand Down Expand Up @@ -1468,7 +1473,7 @@ MESHOPTIMIZER_API unsigned int* meshopt_simplifyDebugLoop = NULL;
MESHOPTIMIZER_API unsigned int* meshopt_simplifyDebugLoopBack = NULL;
#endif

size_t meshopt_simplifyEdge(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions_data, size_t vertex_count, size_t vertex_positions_stride, const float* vertex_attributes_data, size_t vertex_attributes_stride, const float* attribute_weights, size_t attribute_count, size_t target_index_count, float target_error, unsigned int options, float* out_result_error)
size_t meshopt_simplifyEdge(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions_data, size_t vertex_count, size_t vertex_positions_stride, const float* vertex_attributes_data, size_t vertex_attributes_stride, const float* attribute_weights, size_t attribute_count, const unsigned char* vertex_lock, size_t target_index_count, float target_error, unsigned int options, float* out_result_error)
{
using namespace meshopt;

Expand Down Expand Up @@ -1499,7 +1504,7 @@ size_t meshopt_simplifyEdge(unsigned int* destination, const unsigned int* indic
unsigned char* vertex_kind = allocator.allocate<unsigned char>(vertex_count);
unsigned int* loop = allocator.allocate<unsigned int>(vertex_count);
unsigned int* loopback = allocator.allocate<unsigned int>(vertex_count);
classifyVertices(vertex_kind, loop, loopback, vertex_count, adjacency, remap, wedge, options);
classifyVertices(vertex_kind, loop, loopback, vertex_count, adjacency, remap, wedge, vertex_lock, options);

#if TRACE
size_t unique_positions = 0;
Expand Down Expand Up @@ -1634,12 +1639,12 @@ size_t meshopt_simplifyEdge(unsigned int* destination, const unsigned int* indic

size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions_data, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count, float target_error, unsigned int options, float* out_result_error)
{
return meshopt_simplifyEdge(destination, indices, index_count, vertex_positions_data, vertex_count, vertex_positions_stride, NULL, 0, NULL, 0, target_index_count, target_error, options, out_result_error);
return meshopt_simplifyEdge(destination, indices, index_count, vertex_positions_data, vertex_count, vertex_positions_stride, NULL, 0, NULL, 0, NULL, target_index_count, target_error, options, out_result_error);
}

size_t meshopt_simplifyWithAttributes(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions_data, size_t vertex_count, size_t vertex_positions_stride, const float* vertex_attributes_data, size_t vertex_attributes_stride, const float* attribute_weights, size_t attribute_count, size_t target_index_count, float target_error, unsigned int options, float* out_result_error)
size_t meshopt_simplifyWithAttributes(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions_data, size_t vertex_count, size_t vertex_positions_stride, const float* vertex_attributes_data, size_t vertex_attributes_stride, const float* attribute_weights, size_t attribute_count, const unsigned char* vertex_lock, size_t target_index_count, float target_error, unsigned int options, float* out_result_error)
{
return meshopt_simplifyEdge(destination, indices, index_count, vertex_positions_data, vertex_count, vertex_positions_stride, vertex_attributes_data, vertex_attributes_stride, attribute_weights, attribute_count, target_index_count, target_error, options, out_result_error);
return meshopt_simplifyEdge(destination, indices, index_count, vertex_positions_data, vertex_count, vertex_positions_stride, vertex_attributes_data, vertex_attributes_stride, attribute_weights, attribute_count, vertex_lock, target_index_count, target_error, options, out_result_error);
}

size_t meshopt_simplifySloppy(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions_data, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count, float target_error, float* out_result_error)
Expand Down

0 comments on commit 7fe5274

Please sign in to comment.