Maintainers
Pricing
Enterprise
More
More
Documentation
Try Live
Rankings
Install
Blog
Docs7
Ask
New
Add Docs
Meshoptimizer
https://github.com/zeux/meshoptimizer
Admin
Mesh optimization library that makes meshes smaller and faster to render
Tokens:
149,216
Snippets:
828
Trust Score:
9.1
License:
MIT
Update:
1 week ago
Context
Chat
Benchmark
80.69
Latest
Show doc for...
Code
Info
Show Results
Tokens:
Raw
Copy
Link
Tokens:
Raw
Copy
Link
### Three.js GLTF Loader Integration Example Source: https://github.com/zeux/meshoptimizer/blob/master/_autodocs/api-reference/js-decoder.md Example from gltf/README.md showing how to integrate MeshoptDecoder with the three.js GLTFLoader. ```javascript import { MeshoptDecoder } from 'meshoptimizer'; import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'; var loader = new GLTFLoader(); loader.setMeshoptDecoder(MeshoptDecoder); loader.load('pirate.glb', function (gltf) { scene.add(gltf.scene); }); ``` -------------------------------- ### meshopt_optimizeVertexCache usage example Source: https://github.com/zeux/meshoptimizer/blob/master/_autodocs/api-reference/optimizers.md Example call to meshopt_optimizeVertexCache, using the same buffer for destination and indices. ```c meshopt_optimizeVertexCache(indices, indices, index_count, vertex_count); ``` -------------------------------- ### meshopt_optimizeVertexFetch usage example Source: https://github.com/zeux/meshoptimizer/blob/master/_autodocs/api-reference/optimizers.md Example call to meshopt_optimizeVertexFetch, passing the vertex buffer as both destination and source, and the index buffer to be rewritten in place. ```c size_t unique = meshopt_optimizeVertexFetch(vertices, indices, index_count, vertices, vertex_count, sizeof(Vertex)); ``` -------------------------------- ### meshopt_buildMeshlets usage example Source: https://github.com/zeux/meshoptimizer/blob/master/_autodocs/api-reference/meshlets.md Example from the meshopt_buildMeshlets section. Demonstrates sizing the output arrays with meshopt_buildMeshletsBound and then calling meshopt_buildMeshlets. Uses max_vertices=64, max_triangles=126, and cone_weight=0.0f (cone culling disabled). The vertex positions are accessed via a Vertex struct whose first member is a float3. ```cpp size_t max_vertices = 64, max_triangles = 126; float cone_weight = 0.0f; size_t max_meshlets = meshopt_buildMeshletsBound(index_count, max_vertices, max_triangles); std::vector<meshopt_Meshlet> meshlets(max_meshlets); std::vector<unsigned int> meshlet_vertices(max_meshlets * max_vertices); std::vector<unsigned char> meshlet_triangles(max_meshlets * max_triangles * 3); size_t meshlet_count = meshopt_buildMeshlets(&meshlets[0], &meshlet_vertices[0], &meshlet_triangles[0], indices, index_count, &vertices[0].x, vertex_count, sizeof(Vertex), max_vertices, max_triangles, cone_weight); ``` -------------------------------- ### Basic Usage Example Source: https://github.com/zeux/meshoptimizer/blob/master/_autodocs/api-reference/js-encoder.md Shows how to import the MeshoptEncoder, await the ready promise, and encode vertex and index buffers. The vertex buffer is encoded with a stride of 12 bytes, and the index buffer with a stride of 2 bytes. ```javascript import { MeshoptEncoder } from 'meshoptimizer'; await MeshoptEncoder.ready; const vertices = new Float32Array([/* x,y,z,... */]); const source = new Uint8Array(vertices.buffer); const encoded = MeshoptEncoder.encodeVertexBuffer(source, vertices.length / 3, 12); const indices = new Uint8Array(/* 16-bit indices */); const encodedIdx = MeshoptEncoder.encodeIndexBuffer(indices, indices.length / 2, 2); ``` -------------------------------- ### Example usage of meshopt_simplify Source: https://github.com/zeux/meshoptimizer/blob/master/_autodocs/api-reference/simplifier.md Example showing how to call meshopt_simplify. The destination vector is sized to index_count (not target) because the worst-case output can be that large. After the call, resize to the returned index count. The target_error is 0.01 (1% deformation) and options is 0. ```cpp std::vector<unsigned int> simplified(index_count); // capacity is index_count, not target! float error = 0.f; size_t result = meshopt_simplify(&simplified[0], indices, index_count, &vertices[0].x, vertex_count, sizeof(Vertex), target, 0.01f, 0, &error); simplified.resize(result); ``` -------------------------------- ### Build, extract, and compute bounds for meshlets using MeshoptClusterizer Source: https://github.com/zeux/meshoptimizer/blob/master/_autodocs/api-reference/js-clusterizer.md Use this example to build meshlets from index and position buffers, extract a specific meshlet, and compute its bounds. Requires importing 'meshoptimizer' and awaiting MeshoptClusterizer.ready. Invalid arguments throw Error('Assertion failed'). ```javascript import { MeshoptClusterizer } from 'meshoptimizer'; await MeshoptClusterizer.ready; const buffers = MeshoptClusterizer.buildMeshlets( indices, positions, 3, 64, 126, 0.0 ); const meshlet = MeshoptClusterizer.extractMeshlet(buffers, 0); const bounds = MeshoptClusterizer.computeMeshletBounds(buffers, positions, 3); ``` -------------------------------- ### meshopt_decodeMeshletRaw declaration and example with error handling Source: https://github.com/zeux/meshoptimizer/blob/master/_autodocs/api-reference/codec-meshlet.md Declaration and usage example for the raw meshlet decoder, which always outputs 32-bit vertex references and packed triangles. The example shows error handling: a non-zero return code indicates a malformed meshlet. ```c MESHOPTIMIZER_API int meshopt_decodeMeshletRaw(unsigned int* vertices, size_t vertex_count, unsigned int* triangles, size_t triangle_count, const unsigned char* buffer, size_t buffer_size); ``` ```c std::vector<unsigned int> v(64), t(126); int rc = meshopt_decodeMeshletRaw(&v[0], vertex_count, &t[0], triangle_count, encoded, size); if (rc != 0) { /* malformed meshlet */ } ``` -------------------------------- ### Clone meshoptimizer v1.3 from GitHub Source: https://github.com/zeux/meshoptimizer/blob/master/README.md Use this command to download the latest release of meshoptimizer via git. This is the primary installation method for developers who want to build the library from source. ```bash git clone -b v1.3 https://github.com/zeux/meshoptimizer.git ``` -------------------------------- ### reorderMesh usage example Source: https://github.com/zeux/meshoptimizer/blob/master/_autodocs/api-reference/js-encoder.md Await `MeshoptEncoder.ready` before calling `reorderMesh`. The example passes `indices`, `true` for triangles, and `false` for optsize, returning `[remap, unique]`. ```javascript await MeshoptEncoder.ready; const [remap, unique] = MeshoptEncoder.reorderMesh(indices, true, false); ``` -------------------------------- ### meshopt_quantizeSnorm 10-10-10 SNORM normal example Source: https://github.com/zeux/meshoptimizer/blob/master/_autodocs/api-reference/quantization.md Packs three 10-bit SNORM components into a 32-bit unsigned integer, as used for a 10-10-10 SNORM normal. ```c unsigned int normal = ((meshopt_quantizeSnorm(v.nx, 10) & 1023) << 20) | ((meshopt_quantizeSnorm(v.ny, 10) & 1023) << 10) | (meshopt_quantizeSnorm(v.nz, 10) & 1023); ``` -------------------------------- ### Usage example for meshopt_simplifyScale Source: https://github.com/zeux/meshoptimizer/blob/master/_autodocs/api-reference/simplifier.md Shows how to compute the scale factor and convert an absolute error target (0.5 mm) to a relative target_error by dividing by the scale. ```c float scale = meshopt_simplifyScale(&vertices[0].x, vertex_count, sizeof(Vertex)); // absolute target of 0.5 mm (in mesh units) float target_error = 0.5f / scale; ``` -------------------------------- ### Generate raytracing-friendly meshlets with meshopt_buildMeshletsSpatial Source: https://github.com/zeux/meshoptimizer/blob/master/README.md Builds meshlets optimized for ray tracing using surface area heuristic (SAH). The example shows buffer allocation and the call to meshopt_buildMeshletsSpatial. Note the comment about min_triangles for the bound and the buffer size change in v0.25 or prior. ```c++ const size_t max_vertices = 64; const size_t min_triangles = 16; const size_t max_triangles = 64; const float fill_weight = 0.5f; size_t max_meshlets = meshopt_buildMeshletsBound(indices.size(), max_vertices, min_triangles); // note: use min_triangles to compute worst case bound std::vector<meshopt_Meshlet> meshlets(max_meshlets); std::vector<unsigned int> meshlet_vertices(indices.size()); std::vector<unsigned char> meshlet_triangles(indices.size()); // note: in v0.25 or prior, use indices.size() + max_meshlets * 3 size_t meshlet_count = meshopt_buildMeshletsSpatial(meshlets.data(), meshlet_vertices.data(), meshlet_triangles.data(), indices.data(), indices.size(), &vertices[0].x, vertices.size(), sizeof(Vertex), max_vertices, min_triangles, max_triangles, fill_weight); ``` -------------------------------- ### meshopt_encodeMeshlet and meshopt_encodeMeshletBound declarations and example Source: https://github.com/zeux/meshoptimizer/blob/master/_autodocs/api-reference/codec-meshlet.md Declarations and usage example for the meshlet encoder. The bound function computes the required buffer size; the encode function writes the encoded meshlet and returns the encoded size or 0 on insufficient space. The example shows encoding a meshlet with up to 64 vertices and 126 triangles. ```c MESHOPTIMIZER_API size_t meshopt_encodeMeshlet(unsigned char* buffer, size_t buffer_size, const unsigned int* vertices, size_t vertex_count, const unsigned char* triangles, size_t triangle_count); ``` ```c MESHOPTIMIZER_API size_t meshopt_encodeMeshletBound(size_t max_vertices, size_t max_triangles); ``` ```c size_t bound = meshopt_encodeMeshletBound(64, 126); std::vector<unsigned char> encoded(bound); size_t size = meshopt_encodeMeshlet(&encoded[0], encoded.size(), &mv[meshlet.vertex_offset], meshlet.vertex_count, &mt[meshlet.triangle_offset], meshlet.triangle_count); ``` -------------------------------- ### Encode vertex buffer example Source: https://github.com/zeux/meshoptimizer/blob/master/_autodocs/api-reference/codec-vertex.md Allocates the bound-sized buffer, encodes the vertex buffer, checks for zero return (insufficient space), and resizes to the actual encoded size. ```c size_t bound = meshopt_encodeVertexBufferBound(vertex_count, vertex_size); std::vector<unsigned char> encoded(bound); size_t size = meshopt_encodeVertexBuffer(&encoded[0], encoded.size(), vertices, vertex_count, vertex_size); if (size == 0) { /* buffer too small */ } encoded.resize(size); ``` -------------------------------- ### meshopt_optimizeOverdraw usage example Source: https://github.com/zeux/meshoptimizer/blob/master/_autodocs/api-reference/optimizers.md Example call to meshopt_optimizeOverdraw. It uses the same buffer for destination and indices, passes vertex positions as float3 in the first 12 bytes of each vertex, and uses a stride of sizeof(Vertex) with a threshold of 1.05f. ```c meshopt_optimizeOverdraw(indices, indices, index_count, &vertices[0].x, vertex_count, sizeof(Vertex), 1.05f); ``` -------------------------------- ### meshopt_generateVertexRemapCustom tolerance example Source: https://github.com/zeux/meshoptimizer/blob/master/_autodocs/api-reference/indexing.md Example of using meshopt_generateVertexRemapCustom with a lambda callback for tolerance-based vertex comparison. The callback returns true if two vertices are equivalent; here it compares texture coordinates with a 1e-3f tolerance. Uses unindexed input (NULL indices) and a custom Vertex struct. ```cpp size_t vertex_count = meshopt_generateVertexRemapCustom(&remap[0], NULL, index_count, &unindexed_vertices[0].px, unindexed_vertex_count, sizeof(Vertex), [&](unsigned int lhs, unsigned int rhs) -> bool { const Vertex& lv = unindexed_vertices[lhs]; const Vertex& rv = unindexed_vertices[rhs]; return fabsf(lv.tx - rv.tx) < 1e-3f && fabsf(lv.ty - rv.ty) < 1e-3f; }); ``` -------------------------------- ### Generate shadow index buffer with meshopt_generateShadowIndexBuffer Source: https://github.com/zeux/meshoptimizer/blob/master/README.md Creates a shadow index buffer from the original indices and vertex positions. Assumes Vertex starts with float3 positions; adjust for quantized positions. Should be done after other vertex/index optimizations. ```c++ std::vector<unsigned int> shadow_indices(index_count); // note: this assumes Vertex starts with float3 positions and should be adjusted accordingly for quantized positions meshopt_generateShadowIndexBuffer(&shadow_indices[0], indices, index_count, &vertices[0].x, vertex_count, sizeof(float) * 3, sizeof(Vertex)); ``` -------------------------------- ### Stripify then unstripify round-trip example Source: https://github.com/zeux/meshoptimizer/blob/master/_autodocs/api-reference/optimizers.md Shows a complete round-trip: stripify a triangle list, then unstripify the resulting strip back to a triangle list. Uses meshopt_stripifyBound and meshopt_unstripifyBound to allocate buffers, and passes 0 as the restart index to stitch with degenerate triangles. ```cpp std::vector<unsigned int> strip(meshopt_stripifyBound(index_count)); size_t strip_count = meshopt_stripify(&strip[0], indices, index_count, vertex_count, 0); std::vector<unsigned int> restored(meshopt_unstripifyBound(strip_count)); size_t restored_count = meshopt_unstripify(&restored[0], &strip[0], strip_count, 0); ``` -------------------------------- ### meshopt_encodeIndexBuffer usage example Source: https://github.com/zeux/meshoptimizer/blob/master/_autodocs/api-reference/codec-index.md Shows the typical usage of meshopt_encodeIndexBuffer: compute the bound, allocate a buffer, encode, check for failure (size == 0 means the buffer was too small), and resize to the actual encoded size. ```c size_t bound = meshopt_encodeIndexBufferBound(index_count, vertex_count); std::vector<unsigned char> encoded(bound); size_t size = meshopt_encodeIndexBuffer(&encoded[0], encoded.size(), indices, index_count); if (size == 0) { /* buffer too small */ } encoded.resize(size); ``` -------------------------------- ### Catching JS errors from decodeVertexBuffer Source: https://github.com/zeux/meshoptimizer/blob/master/_autodocs/errors.md Example of catching errors from MeshoptDecoder.decodeVertexBuffer. It distinguishes between malformed data (message starts with 'Malformed buffer data:') and assertion failures (message === 'Assertion failed'). The numeric code from the malformed data message is -1, -2, or -3. ```javascript try { MeshoptDecoder.decodeVertexBuffer(target, count, size, source, 'OCTAHEDRAL'); } catch (e) { if (e.message.startsWith('Malformed buffer data:')) { const code = Number(e.message.split(': ')[1]); // code is -1, -2, or -3 } else if (e.message === 'Assertion failed') { // programming error in the arguments } } ``` -------------------------------- ### Compute shared position exponent with meshopt_computePositionExponent Source: https://github.com/zeux/meshoptimizer/blob/master/README.md Computes a shared exponent for all meshlets so that each vertex fits in a 24-bit signed integer and can be encoded as a K-bit unsigned delta from the cluster anchor. The example uses K=16 to match DXR2 limits. The exponent is the maximum over all meshlets, starting from min_exp (-13). ```c++ const int min_exp = -13; // start with an acceptable level of precision; 2^-13 ~= 0.1mm in metric units const int max_bits = 16; // maximum number of offset bits per axis int exponent = min_exp; for (size_t i = 0; i < meshlets.size(); ++i) { AABB meshlet_aabb = ...; // compute meshlet AABB based on vertex positions int cexp = meshopt_computePositionExponent(meshlet_aabb.min, meshlet_aabb.max, min_exp, max_bits); exponent = std::max(exponent, cexp); } float scale = ldexpf(1.f, exponent); ``` -------------------------------- ### Build gltfpack with texture compression support Source: https://github.com/zeux/meshoptimizer/blob/master/gltf/README.md Clone the required basis_universal and libwebp repositories, then configure and build gltfpack with CMake. The MESHOPT_GLTFPACK_BASISU_PATH and MESHOPT_GLTFPACK_LIBWEBP_PATH variables must point to the cloned directories. ```shell git clone -b gltfpack https://github.com/zeux/basis_universal git clone https://github.com/webmproject/libwebp cmake . -DMESHOPT_BUILD_GLTFPACK=ON -DMESHOPT_GLTFPACK_BASISU_PATH=basis_universal -DMESHOPT_GLTFPACK_LIBWEBP_PATH=libwebp -DCMAKE_BUILD_TYPE=Release cmake --build . --target gltfpack --config Release ``` -------------------------------- ### Simplify mesh with MeshoptSimplifier.simplify Source: https://github.com/zeux/meshoptimizer/blob/master/_autodocs/api-reference/js-simplifier.md Imports the meshoptimizer library, awaits readiness, and calls simplify with indices, positions, vertex size, target index count, error tolerance, and options. Invalid arguments throw an Error('Assertion failed'). ```javascript import { MeshoptSimplifier } from 'meshoptimizer'; await MeshoptSimplifier.ready; const [simplified, error] = MeshoptSimplifier.simplify( indices, positions, 3, target_index_count, 0.01, ['LockBorder'] ); ``` -------------------------------- ### Async Decode with Error Handling Example Source: https://github.com/zeux/meshoptimizer/blob/master/_autodocs/api-reference/js-decoder.md Example showing async decode with useWorkers and error handling for malformed data. ```javascript import { MeshoptDecoder } from 'meshoptimizer'; MeshoptDecoder.useWorkers(4); try { const result = await MeshoptDecoder.decodeGltfBufferAsync( count, size, encoded, 'ATTRIBUTES', 'OCTAHEDRAL' ); // result: Uint8Array of decoded vertices } catch (e) { if (e.message.startsWith('Malformed buffer data:')) { // corrupted stream; error code after the colon } } ``` -------------------------------- ### meshopt_generateVertexRemap usage example Source: https://github.com/zeux/meshoptimizer/blob/master/_autodocs/api-reference/indexing.md Example usage of meshopt_generateVertexRemap with an unindexed vertex buffer (indices NULL). The remap table is sized to index_count, and the result is consumed by meshopt_remapIndexBuffer and meshopt_remapVertexBuffer. ```cpp std::vector<unsigned int> remap(index_count); size_t vertex_count = meshopt_generateVertexRemap(&remap[0], NULL, index_count, &vertices[0], vertices.size(), sizeof(Vertex)); meshopt_remapIndexBuffer(&indices[0], NULL, index_count, &remap[0]); meshopt_remapVertexBuffer(&vertices[0], &vertices[0], index_count, sizeof(Vertex), &remap[0]); ``` -------------------------------- ### Example usage of meshopt_simplifyWithAttributes Source: https://github.com/zeux/meshoptimizer/blob/master/_autodocs/api-reference/simplifier.md C code example showing how to call meshopt_simplifyWithAttributes with two attributes and their weights. The function writes simplified indices to the 'simplified' array and returns the new index count. ```c float weights[2] = { 1.f, 0.5f }; size_t result = meshopt_simplifyWithAttributes(&simplified[0], indices, index_count, &vertices[0].x, vertex_count, sizeof(Vertex), &attributes[0], 2, weights, 2, NULL, target, 0.01f, 0, NULL); ``` -------------------------------- ### meshopt_filterIndexBuffer usage example Source: https://github.com/zeux/meshoptimizer/blob/master/_autodocs/api-reference/indexing.md Example usage of meshopt_filterIndexBuffer. It filters the index buffer in place, comparing the first three floats (position) of each vertex. The result resizes the indices vector to the remaining count. ```cpp indices.resize(meshopt_filterIndexBuffer(&indices[0], &indices[0], indices.size(), &vertices[0].x, vertices.size(), sizeof(float) * 3, sizeof(Vertex))); ``` -------------------------------- ### Import MeshoptSimplifier from meshoptimizer Source: https://github.com/zeux/meshoptimizer/blob/master/_autodocs/api-reference/js-simplifier.md Shows two equivalent import statements for the MeshoptSimplifier singleton. Use the package root import or the subpath import 'meshoptimizer/simplifier'. ```javascript import { MeshoptSimplifier } from 'meshoptimizer'; // or import { MeshoptSimplifier } from 'meshoptimizer/simplifier'; ``` -------------------------------- ### Convert glTF file with gltfpack Source: https://github.com/zeux/meshoptimizer/blob/master/gltf/README.md Runs gltfpack on an input .gltf/.glb/.obj file to produce an optimized .glb output. Run without arguments for a list of options. ```bash gltfpack -i scene.gltf -o scene.glb ``` -------------------------------- ### meshopt_dequantizeHalf usage example Source: https://github.com/zeux/meshoptimizer/blob/master/_autodocs/api-reference/quantization.md Reconstructs a float from a half-precision value. ```c float x = meshopt_dequantizeHalf(px); ``` -------------------------------- ### Import MeshoptClusterizer from meshoptimizer Source: https://github.com/zeux/meshoptimizer/blob/master/_autodocs/api-reference/js-clusterizer.md Shows two equivalent import statements for the clusterizer singleton. Use the package root import for convenience or the subpath import for a more specific module reference. ```javascript import { MeshoptClusterizer } from 'meshoptimizer'; // or import { MeshoptClusterizer } from 'meshoptimizer/clusterizer'; ``` -------------------------------- ### meshopt_quantizeHalf usage example Source: https://github.com/zeux/meshoptimizer/blob/master/_autodocs/api-reference/quantization.md Converts three float components (e.g., a vector) to half-precision unsigned shorts. ```c unsigned short px = meshopt_quantizeHalf(v.x); unsigned short py = meshopt_quantizeHalf(v.y); unsigned short pz = meshopt_quantizeHalf(v.z); ``` -------------------------------- ### Import MeshoptDecoder from meshoptimizer Source: https://github.com/zeux/meshoptimizer/blob/master/_autodocs/api-reference/js-decoder.md Shows three ways to import the decoder: from the package root, from the decoder subpath, and via CommonJS require. Use the appropriate import based on your module system. ```javascript import { MeshoptDecoder } from 'meshoptimizer'; // or import { MeshoptDecoder } from 'meshoptimizer/decoder'; const MeshoptDecoder = require('meshoptimizer/decoder.cjs'); ``` -------------------------------- ### Remesh and simplify with position remap and sparse simplification Source: https://github.com/zeux/meshoptimizer/blob/master/README.md Shows how to remesh a mesh and then simplify it using meshopt_simplifyWithUpdate with the position remap as an index buffer and the sparse simplification option. The mesh is reindexed via meshopt_generatePositionRemap, then simplified with meshopt_SimplifySparse and meshopt_SimplifyPreserveFolds, and finally optimized with meshopt_optimizeVertexFetch. This approach avoids topological restrictions and preserves thin double-sided geometry. ```c++ std::vector<float> new_positions = triangles; std::vector<unsigned int> new_indices(count * 3); meshopt_generatePositionRemap(&new_indices[0], &new_positions[0], count * 3, sizeof(float) * 3); new_indices.resize(meshopt_simplifyWithUpdate(&new_indices[0], count * 3, &new_positions[0], count * 3, sizeof(float) * 3, NULL, 0, NULL, 0, NULL, target_index_count, target_error, meshopt_SimplifySparse | meshopt_SimplifyPreserveFolds)); new_positions.resize(meshopt_optimizeVertexFetch(&new_positions[0], &new_indices[0], new_indices.size(), &new_positions[0], count * 3, sizeof(float) * 3) * 3); ``` -------------------------------- ### meshopt_computePositionExponent usage example Source: https://github.com/zeux/meshoptimizer/blob/master/_autodocs/api-reference/quantization.md Computes the exponent and scale for quantizing positions within an AABB, then quantizes a position v to an integer. ```c int exponent = meshopt_computePositionExponent(minv, maxv, -10, 16); float scale = powf(2.f, float(exponent)); int iv = int(roundf(v / scale)); ``` -------------------------------- ### Cone culling rejection test Source: https://github.com/zeux/meshoptimizer/blob/master/README.md Example of using the cone culling data to reject a meshlet if it is guaranteed to be back-facing from the camera point of view. ```c++ if (dot(normalize(cone_apex - camera_position), cone_axis) >= cone_cutoff) reject(); ``` -------------------------------- ### Build meshlets with meshopt_buildMeshlets Source: https://github.com/zeux/meshoptimizer/blob/master/README.md Generates meshlet data for mesh shading using meshopt_buildMeshlets. Requires setting max_vertices and max_triangles within hardware limits (NVidia recommends 64 and 126). cone_weight should be 0 if cone culling is not used, otherwise a value between 0 and 1 (0.25 is a reasonable default). The meshlet_vertices and meshlet_triangles arrays are overallocated and should be trimmed before saving or uploading. ```C++ const size_t max_vertices = 64; const size_t max_triangles = 126; // note: in v0.25 or prior, max_triangles needs to be divisible by 4 const float cone_weight = 0.0f; size_t max_meshlets = meshopt_buildMeshletsBound(indices.size(), max_vertices, max_triangles); std::vector<meshopt_Meshlet> meshlets(max_meshlets); std::vector<unsigned int> meshlet_vertices(indices.size()); std::vector<unsigned char> meshlet_triangles(indices.size()); // note: in v0.25 or prior, use indices.size() + max_meshlets * 3 size_t meshlet_count = meshopt_buildMeshlets(meshlets.data(), meshlet_vertices.data(), meshlet_triangles.data(), indices.data(), indices.size(), &vertices[0].x, vertices.size(), sizeof(Vertex), max_vertices, max_triangles, cone_weight); ``` -------------------------------- ### meshoptimizer Point Cloud and Cluster Partitioning API Source: https://github.com/zeux/meshoptimizer/blob/master/README.md Documentation for two C++ functions provided by the meshoptimizer library: meshopt_spatialClusterPoints for point cloud clustering and meshopt_partitionClusters for cluster partitioning. ```APIDOC ## meshopt_spatialClusterPoints ### Description Clusters a point cloud into fixed-size clusters, producing an index buffer where each consecutive chunk of `cluster_size` points refers to a single cluster. This is useful for rendering point clouds via mesh or compute shaders, or for parallelizing point processing while maintaining locality. ### Method C++ function ### Endpoint `meshopt_spatialClusterPoints` ### Parameters - **destination** (unsigned int*) - Required - Output index buffer of size `vertex_count`. - **positions** (const float*) - Required - Pointer to the first component of the first vertex position (e.g., `&vertices[0].px`). - **vertex_count** (size_t) - Required - Number of vertices in the point cloud. - **vertex_size** (size_t) - Required - Size of each vertex structure in bytes (e.g., `sizeof(Vertex)`). - **cluster_size** (size_t) - Required - Desired number of points per cluster. ### Request Example ```cpp const size_t cluster_size = 256; std::vector<unsigned int> index(vertices.size()); meshopt_spatialClusterPoints(&index[0], &vertices[0].px, vertices.size(), sizeof(Vertex), cluster_size); ``` ### Response #### Success Response - **index** (unsigned int*) - The output index buffer, where each consecutive chunk of `cluster_size` points refers to a single cluster. The last cluster may contain fewer points if the total is not a multiple of `cluster_size`. #### Response Example ```cpp // index buffer is filled with cluster indices ``` ## meshopt_partitionClusters ### Description Partitions clusters into larger groups (partitions) of similar size while prioritizing topological and spatial locality. This is useful for batched processing of clusters or hierarchical simplification schemes. ### Method C++ function ### Endpoint `meshopt_partitionClusters` ### Parameters - **destination** (unsigned int*) - Required - Output array of size `cluster_count` that will contain the partition ID for each cluster. - **cluster_indices** (const unsigned int*) - Required - Concatenated index buffer for all clusters. - **total_index_count** (size_t) - Required - Total number of indices across all clusters. - **cluster_index_counts** (const unsigned int*) - Required - Array of size `cluster_count` with the index count for each cluster. - **cluster_count** (size_t) - Required - Number of clusters. - **positions** (const float*) - Optional - Pointer to the first component of the first vertex position (e.g., `&vertices[0].x`). If `NULL`, spatial locality is ignored and only topological connections are used. - **vertex_count** (size_t) - Required - Number of vertices in the vertex buffer. - **vertex_size** (size_t) - Required - Size of each vertex structure in bytes (e.g., `sizeof(Vertex)`). - **target_partition_size** (size_t) - Required - Desired number of clusters per partition. ### Request Example ```cpp const size_t partition_size = 24; std::vector<unsigned int> cluster_partitions(cluster_count); size_t partition_count = meshopt_partitionClusters(&cluster_partitions[0], &cluster_indices[0], total_index_count, &cluster_index_counts[0], cluster_count, &vertices[0].x, vertex_count, sizeof(Vertex), partition_size); ``` ### Response #### Success Response - **partition_count** (size_t) - The number of partitions created. - **destination** (unsigned int*) - Filled with partition IDs ranging from 0 to `partition_count - 1` for each cluster. #### Response Example ```cpp // cluster_partitions now contains partition IDs for each cluster ``` ```