# How to Generate an Adjacency Index Buffer for Silhouette Detection with `meshopt_generateAdjacencyIndexBuffer`

> Learn how to generate an adjacency index buffer for silhouette detection with meshopt_generateAdjacencyIndexBuffer. Streamline GPU passes for efficient edge detection.

- Repository: [Arseny Kapoulkine/meshoptimizer](https://github.com/zeux/meshoptimizer)
- Tags: how-to-guide
- Published: 2026-07-12

---

**`meshopt_generateAdjacencyIndexBuffer` creates an expanded index buffer that provides three indices per original triangle vertex—enabling geometry shaders to detect silhouette edges in a single GPU pass.**

This function in the `zeux/meshoptimizer` library generates the adjacency data required by DirectX 12 and Vulkan when rendering with **adjacency primitives** for edge-based effects like outlining or shadow volumes. It operates entirely on the CPU, scanning the mesh to link neighboring triangles without modifying the original geometry.

## What Is an Adjacency Index Buffer?

An **adjacency index buffer** is a specialized index format used by graphics APIs to support **silhouette detection**. For every triangle vertex, it stores:
- The original vertex index
- The two neighboring vertices that share the edge with the adjacent triangle

This 3× expansion (from `index_count` to `3 * index_count`) allows the GPU's geometry shader to access adjacent triangles directly. Without this data, the shader would need complex texture lookups or multiple passes to determine edge visibility.

According to the `meshoptimizer` source code, the function builds a **triangle adjacency** structure that records, for each triangle edge, the opposite vertex of the neighboring triangle (or the same vertex if the edge is a boundary).

## Prerequisites for Using `meshopt_generateAdjacencyIndexBuffer`

Before calling the function, prepare these inputs:

1. **Destination buffer** – Allocate `3 * index_count` `unsigned int` values to hold the expanded adjacency data.
2. **Source index buffer** – A flat array of triangle indices (`unsigned int*`). The function expects 32-bit indices; convert 16-bit indices if necessary.
3. **Vertex positions** – An array of `float` positions (`x, y, z` per vertex) with the vertex count and stride in bytes. A typical stride is `sizeof(float) * 3` for tightly packed positions.

## How to Call `meshopt_generateAdjacencyIndexBuffer`

The function signature in [`src/meshoptimizer.h`](https://github.com/zeux/meshoptimizer/blob/main/src/meshoptimizer.h) (line 169) is:

```cpp
void meshopt_generateAdjacencyIndexBuffer(
    unsigned int* destination,
    const unsigned int* indices,
    size_t index_count,
    const float* vertex_positions,
    size_t vertex_count,
    size_t vertex_positions_stride);

```

### Basic Usage Example

```cpp
#include "meshoptimizer.h"
#include <vector>

// Input mesh data
std::vector<unsigned int> indices = { 0, 1, 2,  2, 1, 3 };  // Two triangles
std::vector<float> positions = {
    -1.0f, -1.0f, 0.0f,  // Vertex 0
     1.0f, -1.0f, 0.0f,  // Vertex 1
    -1.0f,  1.0f, 0.0f,  // Vertex 2
     1.0f,  1.0f, 0.0f   // Vertex 3
};
size_t vertexCount = positions.size() / 3;
size_t indexCount = indices.size();

// Allocate destination buffer (3x the original size)
std::vector<unsigned int> adjacency(3 * indexCount);

// Generate adjacency buffer
meshopt_generateAdjacencyIndexBuffer(
    adjacency.data(),
    indices.data(),
    indexCount,
    positions.data(),
    vertexCount,
    sizeof(float) * 3);

// adjacency now contains the adjacency index buffer ready for GPU upload

```

### C-Style API Example

For C compatibility or manual memory management:

```c
#include "meshoptimizer.h"
#include <stdlib.h>

// Assuming idx, idxCount, pos, and posCount are already initialized
unsigned int* adj = (unsigned int*)malloc(3 * idxCount * sizeof(unsigned int));

meshopt_generateAdjacencyIndexBuffer(
    adj,
    idx,
    idxCount,
    pos,
    posCount,
    sizeof(float) * 3);

// Upload adj to GPU as an adjacency index buffer, then cleanup
free(adj);

```

## Using the Buffer for Silhouette Detection

Once generated, bind the adjacency buffer using your graphics API's adjacency primitive type:

- **DirectX 12**: Use `D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE` with adjacency, or `D3D12_IBV_FORMAT` with the appropriate strip adjacency flag
- **Vulkan**: Use `VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY`

In the geometry shader, you receive six vertices per triangle (the original three plus three adjacent vertices). Compare the face normal of the current triangle with the adjacent triangle's normal to detect silhouette edges—edges where the dot product of normals changes sign or crosses the view vector.

## Implementation Details

The adjacency generation logic resides in [`src/indexgenerator.cpp`](https://github.com/zeux/meshoptimizer/blob/main/src/indexgenerator.cpp) (function `meshopt_generateAdjacencyIndexBuffer` around line 580). 

Internally, the function:
1. Builds a `TriangleAdjacency` structure (defined in [`src/vcacheoptimizer.cpp`](https://github.com/zeux/meshoptimizer/blob/main/src/vcacheoptimizer.cpp) around line 34) that maps edges to their opposite vertices
2. Scans all triangles to link shared edges
3. Outputs the expanded buffer where each original vertex is followed by its two edge neighbors

The public API declaration in [`src/meshoptimizer.h`](https://github.com/zeux/meshoptimizer/blob/main/src/meshoptimizer.h) provides the stable interface, while the underlying `TriangleAdjacency` utilities handle the edge-to-edge matching.

## Summary

- **`meshopt_generateAdjacencyIndexBuffer`** expands an index buffer to 3× its size, adding adjacent vertex data for each edge.
- The function requires 32-bit indices, vertex positions, and proper stride calculation to generate valid adjacency data.
- The resulting buffer enables **geometry shader-based silhouette detection** by providing neighboring triangle vertices directly to the GPU.
- Implementation spans [`src/meshoptimizer.h`](https://github.com/zeux/meshoptimizer/blob/main/src/meshoptimizer.h) (API), [`src/indexgenerator.cpp`](https://github.com/zeux/meshoptimizer/blob/main/src/indexgenerator.cpp) (generation logic), and [`src/vcacheoptimizer.cpp`](https://github.com/zeux/meshoptimizer/blob/main/src/vcacheoptimizer.cpp) (adjacency structures).

## Frequently Asked Questions

### What is the difference between a regular index buffer and an adjacency index buffer?

A regular index buffer stores one index per triangle corner. An adjacency index buffer stores three indices per corner: the original vertex plus the two vertices of the neighboring triangle that share the edge. This expansion allows geometry shaders to access adjacent primitives without additional texture lookups or compute passes.

### Does `meshopt_generateAdjacencyIndexBuffer` modify the original mesh data?

No. The function operates entirely on the CPU and does not modify the input indices or vertex positions. It only writes to the provided destination buffer, leaving the source data unchanged for subsequent processing.

### Why do I need to provide vertex positions if the function only manipulates indices?

The function uses vertex positions to determine geometric edge equivalence. By comparing positions, it can identify when two triangles share the same edge in 3D space even if their index values differ (due to welding, duplication, or index remapping). This ensures correct adjacency generation for meshes with welded or split vertices.

### Can I use 16-bit indices with `meshopt_generateAdjacencyIndexBuffer`?

The function signature requires 32-bit (`unsigned int`) indices for both source and destination. If your mesh uses 16-bit indices, you must convert them to 32-bit before calling the function, or manually expand the buffer using the library's other utilities.