Top Description Fields Constructors Methods
org.lwjgl.util.meshoptimizer

public Class MeshOptimizer

extends Object
Class Inheritance
Imports
javax.annotation.*, java.nio.*, org.lwjgl.system.*

Native bindings to meshoptimizer.

When a GPU renders triangle meshes, various stages of the GPU pipeline have to process vertex and index data. The efficiency of these stages depends on the data you feed to them; this library provides algorithms to help optimize meshes for these stages, as well as algorithms to reduce the mesh complexity and storage overhead.

Pipeline

When optimizing a mesh, you should typically feed it through a set of optimizations (the order is important!):

Indexing

Most algorithms in this library assume that a mesh has a vertex buffer and an index buffer. For algorithms to work well and also for GPU to render your mesh efficiently, the vertex buffer has to have no redundant vertices; you can generate an index buffer from an unindexed vertex buffer or reindex an existing (potentially redundant) index buffer as follows:

First, generate a remap table from your existing vertex (and, optionally, index) data:


size_t index_count = face_count * 3;
std::vector<unsigned int> remap(index_count); // allocate temporary memory for the remap table
size_t vertex_count = meshopt_generateVertexRemap(&remap[0], NULL, index_count, &unindexed_vertices[0], index_count, sizeof(Vertex));

Note that in this case we only have an unindexed vertex buffer; the remap table is generated based on binary equivalence of the input vertices, so the resulting mesh will render the same way.

After generating the remap table, you can allocate space for the target vertex buffer (vertex_count elements) and index buffer (index_count elements) and generate them:


meshopt_remapIndexBuffer(indices, NULL, index_count, &remap[0]);
meshopt_remapVertexBuffer(vertices, &unindexed_vertices[0], index_count, sizeof(Vertex), &remap[0]);

You can then further optimize the resulting buffers by calling the other functions on them in-place.

Vertex cache optimization

When the GPU renders the mesh, it has to run the vertex shader for each vertex; usually GPUs have a built-in fixed size cache that stores the transformed vertices (the result of running the vertex shader), and uses this cache to reduce the number of vertex shader invocations. This cache is usually small, 16-32 vertices, and can have different replacement policies; to use this cache efficiently, you have to reorder your triangles to maximize the locality of reused vertex references like so:


meshopt_optimizeVertexCache(indices, indices, index_count, vertex_count);

Overdraw optimization

After transforming the vertices, GPU sends the triangles for rasterization which results in generating pixels that are usually first ran through the depth test, and pixels that pass it get the pixel shader executed to generate the final color. As pixel shaders get more expensive, it becomes more and more important to reduce overdraw. While in general improving overdraw requires view-dependent operations, this library provides an algorithm to reorder triangles to minimize the overdraw from all directions, which you should run after vertex cache optimization like this:


meshopt_optimizeOverdraw(indices, indices, index_count, &vertices[0].x, vertex_count, sizeof(Vertex), 1.05f);

The overdraw optimizer needs to read vertex positions as a float3 from the vertex; the code snippet above assumes that the vertex stores position as float x, y, z.

When performing the overdraw optimization you have to specify a floating-point threshold parameter. The algorithm tries to maintain a balance between vertex cache efficiency and overdraw; the threshold determines how much the algorithm can compromise the vertex cache hit ratio, with 1.05 meaning that the resulting ratio should be at most 5% worse than before the optimization.

Vertex fetch optimization

After the final triangle order has been established, we still can optimize the vertex buffer for memory efficiency. Before running the vertex shader GPU has to fetch the vertex attributes from the vertex buffer; the fetch is usually backed by a memory cache, and as such optimizing the data for the locality of memory access is important. You can do this by running this code:

To optimize the index/vertex buffers for vertex fetch efficiency, call:


meshopt_optimizeVertexFetch(vertices, indices, index_count, vertices, vertex_count, sizeof(Vertex));

This will reorder the vertices in the vertex buffer to try to improve the locality of reference, and rewrite the indices in place to match; if the vertex data is stored using multiple streams, you should use optimizeVertexFetchRemap instead. This optimization has to be performed on the final index buffer since the optimal vertex order depends on the triangle order.

Note that the algorithm does not try to model cache replacement precisely and instead just orders vertices in the order of use, which generally produces results that are close to optimal.

Vertex quantization

To optimize memory bandwidth when fetching the vertex data even further, and to reduce the amount of memory required to store the mesh, it is often beneficial to quantize the vertex attributes to smaller types. While this optimization can technically run at any part of the pipeline (and sometimes doing quantization as the first step can improve indexing by merging almost identical vertices), it generally is easier to run this after all other optimizations since some of them require access to float3 positions.

Quantization is usually domain specific; it's common to quantize normals using 3 8-bit integers but you can use higher-precision quantization (for example using 10 bits per component in a 10_10_10_2 format), or a different encoding to use just 2 components. For positions and texture coordinate data the two most common storage formats are half precision floats, and 16-bit normalized integers that encode the position relative to the AABB of the mesh or the UV bounding rectangle.

The number of possible combinations here is very large but this library does provide the building blocks, specifically functions to quantize floating point values to normalized integers, as well as half-precision floats. For example, here's how you can quantize a normal:


unsigned int normal =
    (meshopt_quantizeUnorm(v.nx, 10) << 20) |
    (meshopt_quantizeUnorm(v.ny, 10) << 10) |
     meshopt_quantizeUnorm(v.nz, 10);

and here's how you can quantize a position:


unsigned short px = meshopt_quantizeHalf(v.x);
unsigned short py = meshopt_quantizeHalf(v.y);
unsigned short pz = meshopt_quantizeHalf(v.z);

Vertex/index buffer compression

In case storage size or transmission bandwidth is of importance, you might want to additionally compress vertex and index data. While several mesh compression libraries, like Google Draco, are available, they typically are designed to maximize the compression ratio at the cost of disturbing the vertex/index order (which makes the meshes inefficient to render on GPU) or decompression performance. They also frequently don't support custom game-ready quantized vertex formats and thus require to re-quantize the data after loading it, introducing extra quantization errors and making decoding slower.

Alternatively you can use general purpose compression libraries like zstd or Oodle to compress vertex/index data - however these compressors aren't designed to exploit redundancies in vertex/index data and as such compression rates can be unsatisfactory.

To that end, this library provides algorithms to "encode" vertex and index data. The result of the encoding is generally significantly smaller than initial data, and remains compressible with general purpose compressors - so you can either store encoded data directly (for modest compression ratios and maximum decoding performance), or further compress it with zstd/Oodle to maximize compression ratio.

To encode, you need to allocate target buffers (preferably using the worst case bound) and call encoding functions:


std::vector<unsigned char> vbuf(meshopt_encodeVertexBufferBound(vertex_count, sizeof(Vertex)));
vbuf.resize(meshopt_encodeVertexBuffer(&vbuf[0], vbuf.size(), vertices, vertex_count, sizeof(Vertex)));

std::vector<unsigned char> ibuf(meshopt_encodeIndexBufferBound(index_count, vertex_count));
ibuf.resize(meshopt_encodeIndexBuffer(&ibuf[0], ibuf.size(), indices, index_count));

You can then either serialize vbuf/ibuf as is, or compress them further. To decode the data at runtime, call decoding functions:


int resvb = meshopt_decodeVertexBuffer(vertices, vertex_count, sizeof(Vertex), &vbuf[0], vbuf.size());
int resib = meshopt_decodeIndexBuffer(indices, index_count, &buffer[0], buffer.size());
assert(resvb == 0 && resib == 0);

Note that vertex encoding assumes that vertex buffer was optimized for vertex fetch, and that vertices are quantized; index encoding assumes that the vertex/index buffers were optimized for vertex cache and vertex fetch. Feeding unoptimized data into the encoders will produce poor compression ratios. Both codecs are lossless - the only lossy step is quantization that happens before encoding.

Decoding functions are heavily optimized and can directly target write-combined memory; you can expect both decoders to run at 1-3 GB/s on modern desktop CPUs. Compression ratios depend on the data; vertex data compression ratio is typically around 2-4x (compared to already quantized data), index data compression ratio is around 5-6x (compared to raw 16-bit index data). General purpose lossless compressors can further improve on these results.

Triangle strip conversion

On most hardware, indexed triangle lists are the most efficient way to drive the GPU. However, in some cases triangle strips might prove beneficial:

This library provides an algorithm for converting a vertex cache optimized triangle list to a triangle strip:


std::vector<unsigned int> strip(meshopt_stripifyBound(index_count));
unsigned int restart_index = ~0u;
size_t strip_size = meshopt_stripify(&strip[0], indices, index_count, vertex_count, restart_index);

Typically you should expect triangle strips to have ~50-60% of indices compared to triangle lists (~1.5-1.8 indices per triangle) and have ~5% worse ACMR. Note that triangle strips can be stitched with or without restart index support. Using restart indices can result in ~10% smaller index buffers, but on some GPUs restart indices may result in decreased performance.

Deinterleaved geometry

All of the examples above assume that geometry is represented as a single vertex buffer and a single index buffer. This requires storing all vertex attributes - position, normal, texture coordinate, skinning weights etc. - in a single contiguous struct. However, in some cases using multiple vertex streams may be preferable. In particular, if some passes require only positional data - such as depth pre-pass or shadow map - then it may be beneficial to split it from the rest of the vertex attributes to make sure the bandwidth use during these passes is optimal. On some mobile GPUs a position-only attribute stream also improves efficiency of tiling algorithms.

Most of the functions in this library either only need the index buffer (such as vertex cache optimization) or only need positional information (such as overdraw optimization). However, several tasks require knowledge about all vertex attributes.

For indexing, generateVertexRemap assumes that there's just one vertex stream; when multiple vertex streams are used, it's necessary to use generateVertexRemapMulti as follows:


meshopt_Stream streams[] = {
    {&unindexed_pos[0], sizeof(float) * 3, sizeof(float) * 3},
    {&unindexed_nrm[0], sizeof(float) * 3, sizeof(float) * 3},
    {&unindexed_uv[0], sizeof(float) * 2, sizeof(float) * 2},
};

std::vector<unsigned int> remap(index_count);
size_t vertex_count = meshopt_generateVertexRemapMulti(&remap[0], NULL, index_count, index_count, streams, sizeof(streams) / sizeof(streams[0]));

After this remapVertexBuffer needs to be called once for each vertex stream to produce the correctly reindexed stream.

Instead of calling optimizeVertexFetch for reordering vertices in a single vertex buffer for efficiency, calling optimizeVertexFetchRemap and then calling remapVertexBuffer for each stream again is recommended.

Finally, when compressing vertex data, encodeVertexBuffer should be used on each vertex stream separately - this allows the encoder to best utilize correlation between attribute values for different vertices.

Simplification

All algorithms presented so far don't affect visual appearance at all, with the exception of quantization that has minimal controlled impact. However, fundamentally the most effective way at reducing the rendering or transmission cost of a mesh is to make the mesh simpler.

This library provides two simplification algorithms that reduce the number of triangles in the mesh. Given a vertex and an index buffer, they generate a second index buffer that uses existing vertices in the vertex buffer. This index buffer can be used directly for rendering with the original vertex buffer (preferably after vertex cache optimization), or a new compact vertex/index buffer can be generated using optimizeVertexFetch that uses the optimal number and order of vertices.

The first simplification algorithm, simplify, follows the topology of the original mesh in an attempt to preserve attribute seams, borders and overall appearance. For meshes with inconsistent topology or many seams, such as faceted meshes, it can result in simplifier getting "stuck" and not being able to simplify the mesh fully; it's recommended to preprocess the index buffer with generateShadowIndexBuffer to discard any vertex attributes that aren't critical and can be rebuilt later such as normals.


float threshold = 0.2f;
size_t target_index_count = size_t(index_count * threshold);
float target_error = 1e-2f;

std::vector<unsigned int> lod(index_count);
lod.resize(meshopt_simplify(&lod[0], indices, index_count, &vertices[0].x, vertex_count, sizeof(Vertex), target_index_count, target_error));

Target error is an approximate measure of the deviation from the original mesh using distance normalized to 0..1 (so 1e-2f means that simplifier will try to maintain the error to be below 1% of the mesh extents). Note that because of topological restrictions and error bounds simplifier isn't guaranteed to reach the target index count and can stop earlier.

The second simplification algorithm, simplifySloppy, doesn't follow the topology of the original mesh. This means that it doesn't preserve attribute seams or borders, but it can collapse internal details that are too small to matter better because it can merge mesh features that are topologically disjoint but spatially close.


float threshold = 0.2f;
size_t target_index_count = size_t(index_count * threshold);

std::vector<unsigned int> lod(target_index_count);
lod.resize(meshopt_simplifySloppy(&lod[0], indices, index_count, &vertices[0].x, vertex_count, sizeof(Vertex), target_index_count));

This algorithm is guaranteed to return a result at or below the target index count. It is 5-6x faster than simplify when simplification ratio is large, and is able to reach ~20M triangles/sec on a desktop CPU (meshopt_simplify works at ~3M triangles/sec).

When a sequence of LOD meshes is generated that all use the original vertex buffer, care must be taken to order vertices optimally to not penalize mobile GPU architectures that are only capable of transforming a sequential vertex buffer range. It's recommended in this case to first optimize each LOD for vertex cache, then assemble all LODs in one large index buffer starting from the coarsest LOD (the one with fewest triangles), and call optimizeVertexFetch on the final large index buffer. This will make sure that coarser LODs require a smaller vertex range and are efficient wrt vertex fetch and transform.

Efficiency analyzers

While the only way to get precise performance data is to measure performance on the target GPU, it can be valuable to measure the impact of these optimization in a GPU-independent manner. To this end, the library provides analyzers for all three major optimization routines. For each optimization there is a corresponding analyze function, like analyzeOverdraw, that returns a struct with statistics.

analyzeVertexCache returns vertex cache statistics. The common metric to use is ACMR - average cache miss ratio, which is the ratio of the total number of vertex invocations to the triangle count. The worst-case ACMR is 3 (GPU has to process 3 vertices for each triangle); on regular grids the optimal ACMR approaches 0.5. On real meshes it usually is in [0.5..1.5] range depending on the amount of vertex splits. One other useful metric is ATVR - average transformed vertex ratio - which represents the ratio of vertex shader invocations to the total vertices, and has the best case of 1.0 regardless of mesh topology (each vertex is transformed once).

analyzeVertexFetch returns vertex fetch statistics. The main metric it uses is overfetch - the ratio between the number of bytes read from the vertex buffer to the total number of bytes in the vertex buffer. Assuming non-redundant vertex buffers, the best case is 1.0 - each byte is fetched once.

analyzeOverdraw returns overdraw statistics. The main metric it uses is overdraw - the ratio between the number of pixel shader invocations to the total number of covered pixels, as measured from several different orthographic cameras. The best case for overdraw is 1.0 - each pixel is shaded once.

Note that all analyzers use approximate models for the relevant GPU units, so the numbers you will get as the result are only a rough approximation of the actual performance.

Memory management

Many algorithms allocate temporary memory to store intermediate results or accelerate processing. The amount of memory allocated is a function of various input parameters such as vertex count and index count. By default memory is allocated using operator new and operator delete; if these operators are overloaded by the application, the overloads will be used instead. Alternatively it's possible to specify custom allocation/deallocation functions using setAllocator, e.g.


meshopt_setAllocator(malloc, free);

Note that the library expects the allocation function to either throw in case of out-of-memory (in which case the exception will propagate to the caller) or abort, so technically the use of malloc above isn't safe. If you want to handle out-of-memory errors without using C++ exceptions, you can use setjmp/longjmp instead.

Vertex and index decoders (decodeVertexBuffer and decodeIndexBuffer) do not allocate memory and work completely within the buffer space provided via arguments.

All functions have bounded stack usage that does not exceed 32 KB for any algorithms.

LWJGL note: meshoptimizer can be configured to use the LWJGL memory allocator with the following code:


nmeshopt_setAllocator(
    MemoryUtil.getAllocator().getMalloc(),
    MemoryUtil.getAllocator().getFree()
);

Field Summary

Modifier and TypeField and Description
public static final int
meshopt_EncodeExpSeparate

meshopt_EncodeExpMode Enum values:

  • EncodeExpSeparate - When encoding exponents, use separate values for each component (maximum quality).
  • EncodeExpSharedVector - When encoding exponents, use shared value for all components of each vector (better compression).
  • EncodeExpSharedComponent - When encoding exponents, use shared value for each component of all vectors (best compression).
public static final int
meshopt_EncodeExpSharedComponent

meshopt_EncodeExpMode Enum values:

  • EncodeExpSeparate - When encoding exponents, use separate values for each component (maximum quality).
  • EncodeExpSharedVector - When encoding exponents, use shared value for all components of each vector (better compression).
  • EncodeExpSharedComponent - When encoding exponents, use shared value for each component of all vectors (best compression).
public static final int
meshopt_EncodeExpSharedVector

meshopt_EncodeExpMode Enum values:

  • EncodeExpSeparate - When encoding exponents, use separate values for each component (maximum quality).
  • EncodeExpSharedVector - When encoding exponents, use shared value for all components of each vector (better compression).
  • EncodeExpSharedComponent - When encoding exponents, use shared value for each component of all vectors (best compression).
public static final int
meshopt_SimplifyLockBorder

Simplification options.

public static final int

Constructor Summary

AccessConstructor and Description
protected

Method Summary

Modifier and TypeMethod and Description
public static MeshoptOverdrawStatistics
meshopt_analyzeOverdraw(IntBuffer indices, FloatBuffer
should have float3 position in the first 12 bytes of each vertex
vertex_positions
,
long vertex_count, long vertex_positions_stride, MeshoptOverdrawStatistics __result)

Overdraw analyzer.

public static MeshoptVertexCacheStatistics
meshopt_analyzeVertexCache(IntBuffer indices, long vertex_count, int cache_size, int warp_size, int primgroup_size, MeshoptVertexCacheStatistics __result)

Vertex transform cache analyzer.

public static MeshoptVertexFetchStatistics
meshopt_analyzeVertexFetch(IntBuffer indices, long vertex_count, long vertex_size, MeshoptVertexFetchStatistics __result)

Vertex fetch cache analyzer.

public static long
meshopt_buildMeshlets(MeshoptMeshlet.Buffer
must contain enough space for all meshlets, worst case size can be computed with buildMeshletsBound
meshlets
,
IntBuffer
must contain enough space for all meshlets, worst case size is equal to max_meshlets * max_vertices
meshlet_vertices
,
ByteBuffer
must contain enough space for all meshlets, worst case size is equal to max_meshlets * max_triangles * 3
meshlet_triangles
,
IntBuffer indices, FloatBuffer
should have float3 position in the first 12 bytes of each vertex
vertex_positions
,
long vertex_count, long vertex_positions_stride, long
must not exceed implementation limits (max_vertices ≤ 255 - not 256!)
max_vertices
,
long
must not exceed implementation limits (max_triangles ≤ 512)
max_triangles
,
float
should be set to 0 when cone culling is not used, and a value between 0 and 1 otherwise to balance between cluster size and cone culling efficiency
cone_weight
)

Meshlet builder.

public static native long
meshopt_buildMeshletsBound(long index_count, long max_vertices, long max_triangles)

See buildMeshlets.

public static long
meshopt_buildMeshletsScan(MeshoptMeshlet.Buffer meshlets, IntBuffer meshlet_vertices, ByteBuffer meshlet_triangles, IntBuffer indices, long vertex_count, long max_vertices, long max_triangles)

See buildMeshlets.

public static MeshoptBounds
meshopt_computeClusterBounds(IntBuffer indices, FloatBuffer
should have float3 position in the first 12 bytes of each vertex
vertex_positions
,
long vertex_count, long vertex_positions_stride, MeshoptBounds __result)

Cluster bounds generator.

public static MeshoptBounds
meshopt_computeMeshletBounds(IntBuffer meshlet_vertices, ByteBuffer meshlet_triangles, long triangle_count, FloatBuffer vertex_positions, long vertex_count, long vertex_positions_stride, MeshoptBounds __result)

See computeClusterBounds.

public static void
meshopt_decodeFilterExp(ByteBuffer buffer, long count, long stride)

Experimental: Decodes exponential encoding of floating-point data with 8-bit exponent and 24-bit integer mantissa as 2^E*M.

public static void
meshopt_decodeFilterExp(IntBuffer buffer, long count, long stride)

Experimental: Decodes exponential encoding of floating-point data with 8-bit exponent and 24-bit integer mantissa as 2^E*M.

public static void
meshopt_decodeFilterOct(ByteBuffer buffer, long count, long stride)

Experimental: Decodes octahedral encoding of a unit vector with K-bit (K ≤ 16) signed X/Y as an input; Z must store 1.0f.

public static void
meshopt_decodeFilterOct(ShortBuffer buffer, long count, long stride)

Experimental: Decodes octahedral encoding of a unit vector with K-bit (K ≤ 16) signed X/Y as an input; Z must store 1.0f.

public static void
meshopt_decodeFilterQuat(ByteBuffer buffer, long count, long stride)

Experimental: Decodes 3-component quaternion encoding with K-bit (4 ≤ K ≤ 16) component encoding and a 2-bit component index indicating which component to reconstruct.

public static void
meshopt_decodeFilterQuat(ShortBuffer buffer, long count, long stride)

Experimental: Decodes 3-component quaternion encoding with K-bit (4 ≤ K ≤ 16) component encoding and a 2-bit component index indicating which component to reconstruct.

public static int
meshopt_decodeIndexBuffer(ByteBuffer
must contain enough space for the resulting index buffer (index_count elements)
destination
,
long index_count, long index_size, ByteBuffer buffer)

Index buffer decoder.

public static int
meshopt_decodeIndexSequence(ByteBuffer
must contain enough space for the resulting index sequence (index_count elements)
destination
,
long index_count, long index_size, ByteBuffer buffer)

Index sequence decoder.

public static int
meshopt_decodeVertexBuffer(ByteBuffer
must contain enough space for the resulting vertex buffer (vertex_count * vertex_size bytes)
destination
,
long vertex_count, long vertex_size, ByteBuffer buffer)

Vertex buffer decoder.

public static void
meshopt_encodeFilterExp(ByteBuffer destination, long count, long stride, int bits, FloatBuffer data, int mode)

Experimental: Encodes arbitrary (finite) floating-point data with 8-bit exponent and K-bit integer mantissa (1 ≤ K ≤ 24).

public static void
meshopt_encodeFilterExp(IntBuffer destination, long count, long stride, int bits, FloatBuffer data, int mode)

Experimental: Encodes arbitrary (finite) floating-point data with 8-bit exponent and K-bit integer mantissa (1 ≤ K ≤ 24).

public static void
meshopt_encodeFilterOct(ByteBuffer destination, long count, long stride, int bits, FloatBuffer data)

Experimental: Encodes unit vectors with K-bit (K ≤ 16) signed X/Y as an output.

public static void
meshopt_encodeFilterOct(ShortBuffer destination, long count, long stride, int bits, FloatBuffer data)

Experimental: Encodes unit vectors with K-bit (K ≤ 16) signed X/Y as an output.

public static void
meshopt_encodeFilterQuat(ByteBuffer destination, long count, long stride, int bits, FloatBuffer data)

Experimental: Encodes unit quaternions with K-bit (4 ≤ K ≤ 16) component encoding.

public static void
meshopt_encodeFilterQuat(ShortBuffer destination, long count, long stride, int bits, FloatBuffer data)

Experimental: Encodes unit quaternions with K-bit (4 ≤ K ≤ 16) component encoding.

public static long
meshopt_encodeIndexBuffer(ByteBuffer
must contain enough space for the encoded index buffer (use encodeIndexBufferBound to compute worst case size)
buffer
,
IntBuffer indices)

Index buffer encoder.

public static native long
meshopt_encodeIndexBufferBound(long index_count, long vertex_count)

public static long
meshopt_encodeIndexSequence(ByteBuffer
must contain enough space for the encoded index sequence (use encodeIndexSequenceBound to compute worst case size)
buffer
,
IntBuffer indices)

Index sequence encoder.

public static native long
meshopt_encodeIndexSequenceBound(long index_count, long vertex_count)

public static native void
meshopt_encodeIndexVersion(int
must specify the data format version to encode; valid values are 0 (decodable by all library versions) and 1 (decodable by 0.14+)
version
)

Set index encoder format version.

public static long
meshopt_encodeVertexBuffer(ByteBuffer
must contain enough space for the encoded vertex buffer (use encodeVertexBufferBound to compute worst case size)
buffer
,
ByteBuffer vertices, long vertex_count, long vertex_size)

Vertex buffer encoder.

public static native long
meshopt_encodeVertexBufferBound(long vertex_count, long vertex_size)

public static native void
meshopt_encodeVertexVersion(int
must specify the data format version to encode; valid values are 0 (decodable by all library versions)
version
)

Set vertex encoder format version.

public static void
meshopt_generateAdjacencyIndexBuffer(IntBuffer
must contain enough space for the resulting index buffer (index_count*2 elements)
destination
,
IntBuffer indices, FloatBuffer
should have float3 position in the first 12 bytes of each vertex
vertex_positions
,
long vertex_count, long vertex_positions_stride)

Generate index buffer that can be used as a geometry shader input with triangle adjacency topology.

public static void
meshopt_generateShadowIndexBuffer(IntBuffer
must contain enough space for the resulting index buffer (index_count elements)
destination
,
IntBuffer indices, ByteBuffer vertices, long vertex_count, long vertex_size, long vertex_stride)

Generates index buffer that can be used for more efficient rendering when only a subset of the vertex attributes is necessary.

public static void
meshopt_generateShadowIndexBufferMulti(IntBuffer
must contain enough space for the resulting index buffer (index_count elements)
destination
,
IntBuffer indices, long vertex_count, MeshoptStream.Buffer streams)

Generates index buffer that can be used for more efficient rendering when only a subset of the vertex attributes is necessary.

public static void
meshopt_generateTessellationIndexBuffer(IntBuffer
must contain enough space for the resulting index buffer (index_count*4 elements)
destination
,
IntBuffer indices, FloatBuffer
should have float3 position in the first 12 bytes of each vertex
vertex_positions
,
long vertex_count, long vertex_positions_stride)

Generate index buffer that can be used for PN-AEN tessellation with crack-free displacement.

public static long
meshopt_generateVertexRemap(IntBuffer
must contain enough space for the resulting remap table (vertex_count elements)
destination
,
IntBuffer
can be NULL if the input is unindexed
indices
,
long index_count, ByteBuffer vertices, long vertex_size)

Generates a vertex remap table from the vertex buffer and an optional index buffer and returns number of unique vertices.

public static long
meshopt_generateVertexRemapMulti(IntBuffer
must contain enough space for the resulting remap table (vertex_count elements)
destination
,
IntBuffer
can be NULL if the input is unindexed
indices
,
long index_count, MeshoptStream.Buffer streams)

Generates a vertex remap table from multiple vertex streams and an optional index buffer and returns number of unique vertices.

public static void
meshopt_optimizeOverdraw(IntBuffer
must contain enough space for the resulting index buffer (index_count elements)
destination
,
IntBuffer
must contain index data that is the result of optimizeVertexCache (not the original mesh indices!)
indices
,
FloatBuffer
should have float3 position in the first 12 bytes of each vertex
vertex_positions
,
long vertex_count, long vertex_positions_stride, float
indicates how much the overdraw optimizer can degrade vertex cache efficiency (1.05 = up to 5%) to reduce overdraw more efficiently
threshold
)

Overdraw optimizer.

public static void
meshopt_optimizeVertexCache(IntBuffer
must contain enough space for the resulting index buffer (index_count elements)
destination
,
IntBuffer indices, long vertex_count)

Vertex transform cache optimizer.

public static void
meshopt_optimizeVertexCacheFifo(IntBuffer
must contain enough space for the resulting index buffer (index_count elements)
destination
,
IntBuffer indices, long vertex_count, int
should be less than the actual GPU cache size to avoid cache thrashing
cache_size
)

Vertex transform cache optimizer for FIFO caches.

public static void
meshopt_optimizeVertexCacheStrip(IntBuffer destination, IntBuffer indices, long vertex_count)

Vertex transform cache optimizer for strip-like caches.

public static long
meshopt_optimizeVertexFetch(ByteBuffer
must contain enough space for the resulting vertex buffer (vertex_count elements)
destination
,
IntBuffer
is used both as an input and as an output index buffer
indices
,
ByteBuffer vertices, long vertex_count, long vertex_size)

Vertex fetch cache optimizer.

public static long
meshopt_optimizeVertexFetchRemap(IntBuffer
must contain enough space for the resulting remap table (vertex_count elements)
destination
,
IntBuffer indices)

Vertex fetch cache optimizer.

public static float
meshopt_quantizeFloat(float v, int N)

Quantizes a float into a floating point value with a limited number of significant mantissa bits.

public static short
meshopt_quantizeHalf(float v)

Quantizes a float into half-precision floating point value.

public static int
meshopt_quantizeSnorm(float v, int N)

Quantizes a float in [-1..1] range into an N-bit fixed point snorm value.

public static int
meshopt_quantizeUnorm(float v, int N)

Quantizes a float in [0..1] range into an N-bit fixed point unorm value.

public static void
meshopt_remapIndexBuffer(IntBuffer
must contain enough space for the resulting index buffer (index_count elements)
destination
,
IntBuffer
can be NULL if the input is unindexed
indices
,
IntBuffer remap)

Generates index buffer from the source index buffer and remap table generated by generateVertexRemap.

public static void
meshopt_remapVertexBuffer(ByteBuffer
must contain enough space for the resulting vertex buffer (unique_vertex_count elements, returned by meshopt_generateVertexRemap)
destination
,
ByteBuffer vertices, long vertex_size, IntBuffer remap)

Generates vertex buffer from the source vertex buffer and remap table generated by generateVertexRemap.

public static void
meshopt_setAllocator(MeshoptAllocateI allocate, MeshoptDeallocateI deallocate)

Set allocation callbacks.

public static long
meshopt_simplify(IntBuffer
must contain enough space for the target index buffer, worst case is index_count elements (not target_index_count)!
destination
,
IntBuffer indices, FloatBuffer
should have float3 position in the first 12 bytes of each vertex
vertex_positions
,
long vertex_count, long vertex_positions_stride, long target_index_count, float
represents the error relative to mesh extents that can be tolerated, e.g. 0.01 = 1% deformation; value range [0..1]
target_error
,
int
must be a bitmask composed of meshopt_SimplifyX options; 0 is a safe default
options
,
FloatBuffer
can be NULL; when it's not NULL, it will contain the resulting (relative) error after simplification
result_error
)

Mesh simplifier.

public static long
meshopt_simplifyPoints(IntBuffer
must contain enough space for the target index buffer (target_vertex_count elements)
destination
,
FloatBuffer
should have float3 position in the first 12 bytes of each vertex
vertex_positions
,
long vertex_count, long vertex_positions_stride, long target_vertex_count)

Experimental: Point cloud simplifier.

public static float
meshopt_simplifyScale(FloatBuffer vertex_positions, long vertex_count, long vertex_positions_stride)

Returns the error scaling factor used by the simplifier to convert between absolute and relative extents.

public static long
meshopt_simplifySloppy(IntBuffer
must contain enough space for the target index buffer, worst case is index_count elements (not target_index_count)!
destination
,
IntBuffer indices, FloatBuffer
should have float3 position in the first 12 bytes of each vertex
vertex_positions
,
long vertex_count, long vertex_positions_stride, long target_index_count, float
represents the error relative to mesh extents that can be tolerated, e.g. 0.01 = 1% deformation; value range [0..1]
target_error
,
FloatBuffer
can be NULL; when it's not NULL, it will contain the resulting (relative) error after simplification
result_error
)

Experimental: Mesh simplifier (sloppy).

public static long
meshopt_simplifyWithAttributes(IntBuffer
must contain enough space for the target index buffer, worst case is index_count elements (not target_index_count)!
destination
,
IntBuffer indices, FloatBuffer
should have float3 position in the first 12 bytes of each vertex
vertex_positions
,
long vertex_count, long vertex_positions_stride, FloatBuffer
should have attribute_count floats for each vertex
vertex_attributes
,
long vertex_attributes_stride, FloatBuffer
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_weights
,
long target_index_count, float
represents the error relative to mesh extents that can be tolerated, e.g. 0.01 = 1% deformation; value range [0..1]
target_error
,
int
must be a bitmask composed of meshopt_SimplifyX options; 0 is a safe default
options
,
FloatBuffer
can be NULL; when it's not NULL, it will contain the resulting (relative) error after simplification
result_error
)

Experimental: Mesh simplifier with attribute metric.

public static void
meshopt_spatialSortRemap(IntBuffer
must contain enough space for the resulting remap table (vertex_count elements)
destination
,
FloatBuffer vertex_positions, long vertex_positions_stride)

Experimental: Spatial sorter.

public static void
meshopt_spatialSortTriangles(IntBuffer
must contain enough space for the resulting index buffer (index_count elements)
destination
,
IntBuffer indices, FloatBuffer
should have float3 position in the first 12 bytes of each vertex
vertex_positions
,
long vertex_count, long vertex_positions_stride)

Experimental: Spatial sorter.

public static long
meshopt_stripify(IntBuffer
must contain enough space for the target index buffer, worst case can be computed with stripifyBound
destination
,
IntBuffer indices, long vertex_count, int
should be 0xffff or 0xffffffff depending on index size, or 0 to use degenerate triangles
restart_index
)

Mesh stripifier.

public static native long
meshopt_stripifyBound(long index_count)

public static long
meshopt_unstripify(IntBuffer
must contain enough space for the target index buffer, worst case can be computed with unstripifyBound
destination
,
IntBuffer indices, int restart_index)

Mesh unstripifier.

public static native long
meshopt_unstripifyBound(long index_count)

public static native void
nmeshopt_analyzeOverdraw(long indices, long index_count, long vertex_positions, long vertex_count, long vertex_positions_stride, long __result)

Unsafe version of: analyzeOverdraw

public static native void
nmeshopt_analyzeVertexCache(long indices, long index_count, long vertex_count, int cache_size, int warp_size, int primgroup_size, long __result)

Unsafe version of: analyzeVertexCache

public static native void
nmeshopt_analyzeVertexFetch(long indices, long index_count, long vertex_count, long vertex_size, long __result)

Unsafe version of: analyzeVertexFetch

public static native long
nmeshopt_buildMeshlets(long meshlets, long meshlet_vertices, long meshlet_triangles, long indices, long index_count, long vertex_positions, long vertex_count, long vertex_positions_stride, long max_vertices, long max_triangles, float cone_weight)

Unsafe version of: buildMeshlets

public static native long
nmeshopt_buildMeshletsScan(long meshlets, long meshlet_vertices, long meshlet_triangles, long indices, long index_count, long vertex_count, long max_vertices, long max_triangles)

Unsafe version of: buildMeshletsScan

public static native void
nmeshopt_computeClusterBounds(long indices, long
index_count/3 should be less than or equal to 512 (the function assumes clusters of limited size)
index_count
,
long vertex_positions, long vertex_count, long vertex_positions_stride, long __result)

Unsafe version of: computeClusterBounds

public static native void
nmeshopt_computeMeshletBounds(long meshlet_vertices, long meshlet_triangles, long triangle_count, long vertex_positions, long vertex_count, long vertex_positions_stride, long __result)

Unsafe version of: computeMeshletBounds

public static native void
nmeshopt_decodeFilterExp(long buffer, long count, long stride)

Unsafe version of: decodeFilterExp

public static native void
nmeshopt_decodeFilterOct(long buffer, long count, long stride)

Unsafe version of: decodeFilterOct

public static native void
nmeshopt_decodeFilterQuat(long buffer, long count, long stride)

Unsafe version of: decodeFilterQuat

public static native int
nmeshopt_decodeIndexBuffer(long destination, long index_count, long index_size, long buffer, long buffer_size)

Unsafe version of: decodeIndexBuffer

public static native int
nmeshopt_decodeIndexSequence(long destination, long index_count, long index_size, long buffer, long buffer_size)

Unsafe version of: decodeIndexSequence

public static native int
nmeshopt_decodeVertexBuffer(long destination, long vertex_count, long vertex_size, long buffer, long buffer_size)

Unsafe version of: decodeVertexBuffer

public static native void
nmeshopt_encodeFilterExp(long destination, long count, long stride, int bits, long data, int mode)

Unsafe version of: encodeFilterExp

public static native void
nmeshopt_encodeFilterOct(long destination, long count, long stride, int bits, long data)

Unsafe version of: encodeFilterOct

public static native void
nmeshopt_encodeFilterQuat(long destination, long count, long stride, int bits, long data)

Unsafe version of: encodeFilterQuat

public static native long
nmeshopt_encodeIndexBuffer(long buffer, long buffer_size, long indices, long index_count)

Unsafe version of: encodeIndexBuffer

public static native long
nmeshopt_encodeIndexSequence(long buffer, long buffer_size, long indices, long index_count)

Unsafe version of: encodeIndexSequence

public static native long
nmeshopt_encodeVertexBuffer(long buffer, long buffer_size, long vertices, long vertex_count, long vertex_size)

Unsafe version of: encodeVertexBuffer

public static native void
nmeshopt_generateAdjacencyIndexBuffer(long destination, long indices, long index_count, long vertex_positions, long vertex_count, long vertex_positions_stride)

Unsafe version of: generateAdjacencyIndexBuffer

public static native void
nmeshopt_generateShadowIndexBuffer(long destination, long indices, long index_count, long vertices, long vertex_count, long vertex_size, long vertex_stride)

Unsafe version of: generateShadowIndexBuffer

public static native void
nmeshopt_generateShadowIndexBufferMulti(long destination, long indices, long index_count, long vertex_count, long streams, long stream_count)

Unsafe version of: generateShadowIndexBufferMulti

public static native void
nmeshopt_generateTessellationIndexBuffer(long destination, long indices, long index_count, long vertex_positions, long vertex_count, long vertex_positions_stride)

Unsafe version of: generateTessellationIndexBuffer

public static native long
nmeshopt_generateVertexRemap(long destination, long indices, long index_count, long vertices, long vertex_count, long vertex_size)

Unsafe version of: generateVertexRemap

public static native long
nmeshopt_generateVertexRemapMulti(long destination, long indices, long index_count, long vertex_count, long streams, long stream_count)

Unsafe version of: generateVertexRemapMulti

public static native void
nmeshopt_optimizeOverdraw(long destination, long indices, long index_count, long vertex_positions, long vertex_count, long vertex_positions_stride, float threshold)

Unsafe version of: optimizeOverdraw

public static native void
nmeshopt_optimizeVertexCache(long destination, long indices, long index_count, long vertex_count)

Unsafe version of: optimizeVertexCache

public static native void
nmeshopt_optimizeVertexCacheFifo(long destination, long indices, long index_count, long vertex_count, int cache_size)

Unsafe version of: optimizeVertexCacheFifo

public static native void
nmeshopt_optimizeVertexCacheStrip(long destination, long indices, long index_count, long vertex_count)

Unsafe version of: optimizeVertexCacheStrip

public static native long
nmeshopt_optimizeVertexFetch(long destination, long indices, long index_count, long vertices, long vertex_count, long vertex_size)

Unsafe version of: optimizeVertexFetch

public static native long
nmeshopt_optimizeVertexFetchRemap(long destination, long indices, long index_count, long vertex_count)

Unsafe version of: optimizeVertexFetchRemap

public static native void
nmeshopt_remapIndexBuffer(long destination, long indices, long index_count, long remap)

Unsafe version of: remapIndexBuffer

public static native void
nmeshopt_remapVertexBuffer(long destination, long vertices, long
should be the initial vertex count and not the value returned by meshopt_generateVertexRemap
vertex_count
,
long vertex_size, long remap)

Unsafe version of: remapVertexBuffer

public static native void
nmeshopt_setAllocator(long allocate, long deallocate)

Unsafe version of: setAllocator

public static native long
nmeshopt_simplify(long destination, long indices, long index_count, long vertex_positions, long vertex_count, long vertex_positions_stride, long target_index_count, float target_error, int options, long result_error)

Unsafe version of: simplify

public static native long
nmeshopt_simplifyPoints(long destination, long vertex_positions, long vertex_count, long vertex_positions_stride, long target_vertex_count)

Unsafe version of: simplifyPoints

public static native float
nmeshopt_simplifyScale(long vertex_positions, long vertex_count, long vertex_positions_stride)

Unsafe version of: simplifyScale

public static native long
nmeshopt_simplifySloppy(long destination, long indices, long index_count, long vertex_positions, long vertex_count, long vertex_positions_stride, long target_index_count, float target_error, long result_error)

Unsafe version of: simplifySloppy

public static native long
nmeshopt_simplifyWithAttributes(long destination, long indices, long index_count, long vertex_positions, long vertex_count, long vertex_positions_stride, long vertex_attributes, long vertex_attributes_stride, long attribute_weights, long attribute_count, long target_index_count, float target_error, int options, long result_error)

Unsafe version of: simplifyWithAttributes

public static native void
nmeshopt_spatialSortRemap(long destination, long vertex_positions, long vertex_count, long vertex_positions_stride)

Unsafe version of: spatialSortRemap

public static native void
nmeshopt_spatialSortTriangles(long destination, long indices, long index_count, long vertex_positions, long vertex_count, long vertex_positions_stride)

Unsafe version of: spatialSortTriangles

public static native long
nmeshopt_stripify(long destination, long indices, long index_count, long vertex_count, int restart_index)

Unsafe version of: stripify

public static native long
nmeshopt_unstripify(long destination, long indices, long index_count, int restart_index)

Unsafe version of: unstripify

Inherited from java.lang.Object:
cloneequalsfinalizegetClasshashCodenotifynotifyAlltoStringwaitwaitwait