---
title: "Understanding 3D icons"
canonical: "https://help.twinfinity.com/space/HCFD/147062785/Understanding%203D%20icons"
format: markdown
---
3D icons in Twinfinity are, at their core, sprites. A sprite is a 2D graphic
used within a 3D environment, often for icons, textures, or other flat,
billboard-like visual elements. The Twinfinity embedded API lets you add these
sprites to the 3D scene as icons that can later be interacted with like any
other object in the scene. To get the most out of 3D icons, we recommend using
a sprite atlas.

![Sprite icons placed on rooms in the 3D model](media://86243d63-f2d8-40c9-b0c9-c98ce92becc9)

## 3D icons vs. 2D labels

3D icons, in contrast to 2D labels, are rendered in the 3D context. This means
they are placed within the 3D model and are shown or hidden the same way 3D
objects are. If a 3D icon sits behind a wall from the camera's point of view,
the wall hides the icon. 2D labels, by comparison, are drawn on top of the
rendered canvas and always appear in front of the model — almost as if the
camera were filming through a glass pane.

## Sprite atlases

A sprite atlas is a large image containing a collection of smaller images, or
sprites — individual graphics that can be used in the Twinfinity Viewer. Using
a sprite atlas is an efficient way to manage and organize multiple textures,
because it reduces the overhead of switching between different textures during
rendering. When a 3D scene is rendered, the appropriate sections of the atlas
are selected and applied to the 3D icons, giving a more streamlined and
resource-efficient rendering process. This lets you add a vast number of 3D
icons to the scene without a big impact on performance.

## Placing icons in the scene

To add 3D icons, you create an `IconHandler` backed by an atlas texture, build
an `Icon` for each position you care about, and attach them. The example below
loads an atlas, sets up a handler, and drops an icon at the centre of every
matching room space:

```ts
import { Color4 } from '@babylonjs/core';
import { Icon, IconHandler, getTexture } from '@twinfinity/core';

// Load the sprite atlas as a texture.
const iconAtlas = await getTexture(
  api.viewer.scene,
  new URL('https://playground.twinfinity.dev/resources/icons/sprite-atlas.png')
);

// Define an icon handler backed by that atlas.
const iconHandler = new IconHandler(api, {
  iconAtlasTexture: iconAtlas,
  totalNumberOfIconsAndStyles: 100,
  numberOfIconsInAStyle: 1,
  hasAlpha: true,
  iconMaxSize: 64,
  occlusionCullingIntervalMs: 1000
});

// Build an icon per position, then attach them all.
const roomIconId = 64;
const icon = new Icon(o.gid, roomIconId, 0, 1, o.boundingInfo().boundingSphere.center, new Color4(1, 1, 1, 1), true, false);
iconHandler.attach([icon]);
```

For a complete, runnable version that places an icon on every room space,
see [Room-marker icons](https://playground.twinfinity.dev/?pgId=labels-and-icons/room-markers).

## Clickable icons

3D icons can also be used as buttons inside the 3D context, each with its own
click event. This example shows how to give per-class icons their own click
handling, so tapping an icon can trigger an action in your app:
[Clickable per-class icons](https://playground.twinfinity.dev/?pgId=labels-and-icons/per-class-icons).

## See also

3D icons live inside the 3D scene and respect occlusion; 2D labels float on top
of the canvas and are always visible. If you need the latter, see
[Understanding 2D labels](https://twinfinity.atlassian.net/wiki/spaces/HCFD/pages/151126023).