# Import guidelines

> Learn how to import and prepare CAD files for real-time 3D experiences.

## Why prepare CAD files for import?

CAD models are designed for engineering and manufacturing, not for real-time visualization. When importing CAD files into real-time applications, you need to transform precise parametric geometries (BREP) into polygonal meshes that can be efficiently rendered.

A typical import workflow involves several key steps:

1. **Import** - Load the file and configure what information to preserve
2. **Repair** - Fix geometric issues that can cause rendering problems
3. **Tessellate** - Convert CAD surfaces into polygonal meshes
4. **Orient** - Ensure all polygon faces are oriented correctly for proper lighting
5. **Create attributes** - Generate normals, UVs, and tangents needed for rendering

Following these guidelines will ensure your imported models display correctly and perform efficiently in real-time applications.

## 1. Import

### 1.1. Choose what to load

Before importing, configure the IO module properties to control what information is loaded from the file. This can significantly reduce import time and memory usage.

[Load variants](/asset-transformer-sdk/2026.4/api/python/core_functions.md#setmoduleproperty): Set `LoadVariant` to `True` to import design variants and PMI.
[Prefer meshes](/asset-transformer-sdk/2026.4/api/python/core_functions.md#setmoduleproperty): Set `PreferLoadMesh` to `true` to load existing tessellation when available.


**Example:** Configure module properties before import

```python
# Load variants and PMI information
core.setModuleProperty("IO", "LoadVariant", "True")

# Prefer loading existing mesh data over BREP
core.setModuleProperty("IO", "PreferLoadMesh", "true")

# Load PMI (Product Manufacturing Information)
core.setModuleProperty("IO", "LoadPMI", "True")
```

> **Tip:**
>
> Setting `PreferLoadMesh` to `true` can dramatically speed up imports for files that already contain tessellated geometry.

### 1.2. Import files

Use [io.importFiles](/asset-transformer-sdk/2026.4/api/python/io_functions.md#importfiles) to load one or more files into the scene. This function returns the root occurrences of the imported content.

```python
# Import a single file
root = io.importScene("path/to/model.stp")

# Import multiple files
file_list = [
    "path/to/part1.stp",
    "path/to/part2.jt",
    "path/to/assembly.catpart"
]
roots = io.importFiles(file_list)
```

> **Note:**
>
> Check the [supported formats](./../io/supported-formats) to verify your file type is compatible. Asset Transformer SDK supports a wide range of CAD formats including STEP, CATIA, JT, NX, SolidWorks, and many more.

### 1.3. Delete unnecessary information

CAD files often contain data that isn't needed for real-time visualization. Removing this information early reduces memory usage and processing time.

#### Delete points and lines

Points and lines (free vertices and line meshes) are typically used for construction geometry in CAD but aren't needed for rendering.

```python
# Delete free vertices (points)
algo.deleteFreeVertices([root])

# Delete line geometries
algo.deleteLines([root])
```

> **Tip:**
>
> If you need to preserve line geometries (such as for wireframe visualization), you can tessellate them into tube meshes using custom parameters instead of deleting them.

#### Delete patches

CAD patches (BREP faces) should be removed after tessellation to free memory, as they're no longer needed for rendering.

```python
# Delete CAD patch information after tessellation
algo.deletePatches([root])
```

> **Important:**
>
> Deleting patches greatly improves performance in engines like Unity. Each patch can result in a separate submesh, and each submesh generates an additional draw call. Removing patches after tessellation consolidates the geometry and reduces draw calls significantly.

## Repair

Repairing geometry is critical before tessellation and optimization. CAD models often have small gaps, overlapping surfaces, and other topological issues that can cause problems during mesh generation.

### 2.1. Merge open shells

Before repairing CAD geometry, merge part occurrences that contain single open shells. This step identifies parts with unclosed surfaces and prepares them for proper stitching during the repair phase.

```python
# Merge part occurrences with single open shell by assemblies
openShells = scene.mergePartOccurrencesWithSingleOpenShellByAssemblies(root)

# Optionally, find unstitched faces for special handling
unstitchedFaces = scene.findPartOccurrencesWithUnstitchedOpenShells(root)
```

> **Tip:**
>
> This step is particularly important for sheet metal parts, architectural elements, and other models that contain open surfaces rather than closed volumes.

### 2.2. Repair CAD geometries

For models containing BREP data, repair the CAD surfaces to ensure properly connected geometry. This stitches open shells together and fixes topological issues.

```python
# Compute a tolerance relative to model size
tolerance = 0.1  # In mm. Adjust based on your model scale

# Repair CAD surfaces (after merging open shells)
algo.repairCAD([root], tolerance, orient=False)
```

[Repair CAD](/asset-transformer-sdk/2026.4/api/python/algo_functions.md#repaircad): Fixes gaps, removes duplicates, and stitches CAD surfaces together.


### 2.3. Repair mesh geometries

For models that already contain mesh data (or after tessellation), repair the polygonal meshes to fix connectivity issues, remove degenerate triangles, and merge nearby vertices.

```python
# Repair mesh geometries
algo.repairMesh([root],
                tolerance=0.1,
                crackNonManifold=True,
                orient=False)
```

[Repair meshes](../functions/repairmeshes): Comprehensive guide to mesh repair operations.
[Merge vertices](../functions/mergevertices): Merge vertices within tolerance to fix gaps and T-junctions.


> **Important:**
>
> Always repair geometry before performing optimization operations like decimation. Many optimization algorithms require clean, manifold geometry to work correctly.

## 3. Tessellate

Tessellation converts CAD surfaces (BREP) into polygonal meshes suitable for real-time rendering. This is one of the most important steps in the import process, as it determines the quality and polygon count of your final model.

> **Note:**
>
> Skip this step if your file already contains mesh data and you set `PreferLoadMesh` to `true`.

### Choose tessellation parameters

Tessellation quality is controlled by tolerance parameters that balance visual fidelity against polygon count:

* **Maximum sag** - Maximum distance between CAD surface and mesh (in scene units)
* **Sag ratio** - Maximum distance ratio relative to model size
* **Maximum angle** - Maximum angle between adjacent polygon normals (in degrees)
* **Maximum length** - Maximum edge length for polygons (optional)

```python
# Tessellate with quality-based parameters
algo.tessellate([root],
                maxSag=0.1,        # 0.1 units maximum deviation
                maxAngle=15,        # 15 degrees for curved surfaces
                createNormals=True, # Generate normals during tessellation
                uvMode=algo.UVGenerationMode.NoUV)  # Skip UV generation for now
```

### Adaptive tessellation

For better results with models of varying sizes, use relative tessellation based on the model's bounding box:

```python
# Tessellate relative to model size
algo.tessellateRelativelyToAABB([root],
                                maxSag=0.1,          # Max value used
                                sagRatio=0.0002,     # 0.02% of bbox dimension
                                maxLength=-1,        # Disabled
                                maxAngle=15,         # 15 degrees
                                createNormals=True,
                                uvMode=algo.UVGenerationMode.NoUV,
                                createTangents=False,
                                createFreeEdges=False,
                                keepBRepShape=False,  # Delete BREP after tessellation
                                overrideExistingTessellation=False)
```

[Tessellate models](../functions/tessellate): Complete guide to tessellation parameters and best practices.


> **Tip:**
>
> Start with conservative parameters (small sag, moderate angle) and adjust based on your quality requirements and performance targets.

## 4. Orient

Polygon faces have a front side and a back side, determined by the normal direction. Incorrect face orientation causes rendering issues where surfaces appear invisible or incorrectly lit.

### Orient polygon faces

After tessellation and repair, ensure all polygon faces are oriented consistently:

```python
# Orient faces using the exterior orientation strategy
algo.orientPolygonFaces([root])
```

> **Note:**
>
> The default orientation strategy (`ExteriorOnly`) orients faces to point outward from solid volumes, which is correct for most closed CAD models.

### Handle open shells and unstitched faces separately

If you identified open shells and unstitched faces earlier (in step 2.1), you may want to orient them separately:

```python
# Orient open shells separately (if you saved them from step 2.1)
if len(openShells) > 0:
    algo.orientPolygonFaces(openShells)

# Orient unstitched faces separately
if len(unstitchedFaces) > 0:
    algo.orientPolygonFaces(unstitchedFaces)
```

> **Tip:**
>
> This approach gives you more control over orientation for models with mixed closed volumes and open surfaces.

[Orient normals](/asset-transformer-sdk/2026.4/api/python/algo_functions.md#orientnormals): Orient vertex normals consistently after orienting polygon faces.


## 5. Create missing attributes

Real-time rendering requires certain mesh attributes that CAD files typically don't contain. Generate these attributes after tessellation and orientation.

### 5.1. Normals

Normals define how surfaces react to lighting. This attribute must be present to achieve good visual quality.
While Asset Transformer tessellation will create normals automatically, you might have imported a mesh file without normals.

```python
# Create smooth normals (45-degree threshold)
algo.createNormals([root],
                   sharpEdge=45,           # Preserve edges sharper than 45°
                   override=False,         # Keep existing normals if they already exist
                   useAreaWeighting=True)  # Weight by polygon area

# Orient normals consistently
algo.orientNormals([root])
```

[Create normals](../functions/createnormals): Learn how normal generation affects the appearance of your models.


> **Tip:**
>
> The sharp edge threshold determines which edges appear crisp versus smooth. Lower values (20-30°) preserve more hard edges, while higher values (60-90°) create smoother transitions.

### 5.2. UVs

UV coordinates map 2D textures onto 3D surfaces. Generate UVs if you plan to apply textures or use certain rendering techniques.

#### Option 1: Simple box projection

For basic texture mapping or when precise UVs aren't critical:

```python
# Generate UVs using axis-aligned bounding box projection
algo.mapUvOnAABB([root],
                 useLocalAABB=True,        # Use each part's local bbox
                 uv3dSize=1000,            # 1 meter = 1 UV unit
                 channel=0,                # First UV channel
                 overrideExistingUVs=True)
```

#### Option 2: Automatic unwrapping

For better UV layouts suitable for texturing:

```python
# Automatic UV unwrapping with optimal settings
algo.automaticUVMapping([root],
                        channel=0,
                        sharpToSeam=True,      # Use sharp edges as seams
                        forbidOverlapping=True) # No overlapping islands
```

[UV mapping functions](/asset-transformer-sdk/2026.4/api/python/algo_functions.md#mapuvonaabb): Various UV projection methods available.
[Automatic UV mapping](/asset-transformer-sdk/2026.4/api/python/algo_functions.md#automaticuvmapping): Advanced unwrapping for complex models.


#### Lightmap UVs (second UV channel)

If using Unity's lightmapping system, generate a second UV channel optimized for baked lighting:

```python title="Python"
print("Generating lightmap UVs...")
algo.mapUvOnAABB(roots, useLocalAABB=False, uv3dSize=1, channel=1, overrideExistingUVs=True)
algo.repackUV(roots, channel=1, shareMap=False, resolution=1024, padding=2,
              uniformRatio=False, removeOverlaps=False)
algo.normalizeUV(roots, sourceUVChannel=1, destinationUVChannel=-1,
                 uniform=True, sharedUVSpace=False, ignoreNullIslands=False)
```

### 5.3. Tangents

Tangents are required for normal mapping (bump mapping). Generate them after creating UVs:

```python
# Generate tangents from UV channel 0
algo.createTangents([root],
                    uvChannel=0,
                    override=False)  # Keep existing tangents
```

[Create tangents](../functions/createtangents): Tangent generation for normal and bump mapping.


> **Note:**
>
> Tangents require valid UVs to be generated correctly. Always create UVs before generating tangents.

## Script

Here's a complete Python script that implements the entire import workflow:

```python title="Python"

import pxz
from pxz import core, io, algo, scene

# File path to import
FILE_PATH = "/path/to/file.CATProduct"

# Step 1: Configure import settings
core.setModuleProperty("IO", "LoadVariant", "False")
core.setModuleProperty("IO", "PreferLoadMesh", "false")  # We want to tessellate ourselves
core.setModuleProperty("IO", "LoadPMI", "False")

# Step 2: Import the file
print("Importing file...")
root = io.importScene(FILE_PATH)
roots = [root]

# Step 3: Delete unnecessary data
print("Cleaning up unnecessary data...")
algo.deleteFreeVertices(roots)  # Remove points
algo.deleteLines(roots)         # Remove line geometries

# Step 4: Merge open shells before repairing
print("Merging open shells...")
openShells = scene.mergePartOccurrencesWithSingleOpenShellByAssemblies(root)
unstitchedFaces = scene.findPartOccurrencesWithUnstitchedOpenShells(root)

# Step 5: Repair CAD geometries
print("Repairing CAD surfaces...")
tolerance = 0.1  # Adjust based on your model units
algo.repairCAD(roots, tolerance, orient=False)

# Step 6: Repair mesh geometries (for any existing meshes)
print("Repairing meshes...")
algo.repairMesh(roots, tolerance, crackNonManifold=True, orient=False)

# Step 7: Tessellate BREP to meshes
print("Tessellating CAD surfaces...")
algo.tessellateRelativelyToAABB(roots,
                                maxSag=0.1,          # Max value used
                                sagRatio=0.0002,     # 0.02% of bounding box
                                maxLength=-1,
                                maxAngle=15,          # 15 degrees
                                createNormals=True,
                                uvMode=algo.UVGenerationMode.NoUV,
                                createTangents=False,
                                createFreeEdges=False,
                                keepBRepShape=False,  # Delete BREP
                                overrideExistingTessellation=False)

# Step 8: Delete patches (BREP faces) to free memory
algo.deletePatches(roots)

# Step 9: Orient polygon faces
print("Orienting faces...")
algo.orientPolygonFaces(roots)

# Handle open shells and unstitched faces separately if needed
if len(openShells) > 0:
    algo.orientPolygonFaces(openShells)
if len(unstitchedFaces) > 0:
    algo.orientPolygonFaces(unstitchedFaces)

# Step 10: Create smooth normals if they don't exist
print("Creating normals...")
algo.createNormals(roots, sharpEdge=45, override=False, useAreaWeighting=True)

# Step 11: Generate UVs for texturing (channel 0) if they don't exist
print("Generating UVs...")
algo.mapUvOnAABB(roots,
                 useLocalAABB=True,
                 uv3dSize=1000,  # 1 meter = 1 UV unit
                 channel=0,
                 overrideExistingUVs=True)

# Step 12: Generate tangents for normal mapping if they don't exist
print("Creating tangents...")
algo.createTangents(roots, uvChannel=0, override=False)

# Optional: Generate lightmap UVs (channel 1)
print("Generating lightmap UVs...")
algo.mapUvOnAABB(roots, useLocalAABB=False, uv3dSize=1, channel=1, overrideExistingUVs=True)
algo.repackUV(roots, channel=1, shareMap=False, resolution=1024, padding=2,
              uniformRatio=False, removeOverlaps=False)
algo.normalizeUV(roots, sourceUVChannel=1, destinationUVChannel=-1,
                 uniform=True, sharedUVSpace=False, ignoreNullIslands=False)
```

> **Tip:**
>
> Save this script as a starting point and customize the parameters based on your specific requirements for quality, performance, and file types.
