Documentation

Support

Asset Transformer SDK


User Manual

Python API

C# API

Changelog

Discussions

Asset Transformer SDK


Import guidelines

Learn how to import and prepare CAD files for real-time 3D experiences.
Read time 6 minutesLast updated 4 months ago

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. Example: Configure module properties before import
# Load variants and PMI informationcore.setModuleProperty("IO", "LoadVariant", "True")# Prefer loading existing mesh data over BREPcore.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 to load one or more files into the scene. This function returns the root occurrences of the imported content.
# Import a single fileroot = io.importScene("path/to/model.stp")# Import multiple filesfile_list = [ "path/to/part1.stp", "path/to/part2.jt", "path/to/assembly.catpart"]roots = io.importFiles(file_list)
Note
Check the 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.
# Delete free vertices (points)algo.deleteFreeVertices([root])# Delete line geometriesalgo.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.
# Delete CAD patch information after tessellationalgo.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.

2. 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.
# Merge part occurrences with single open shell by assembliesopenShells = scene.mergePartOccurrencesWithSingleOpenShellByAssemblies(root)# Optionally, find unstitched faces for special handlingunstitchedFaces = 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.
# Compute a tolerance relative to model sizetolerance = 0.1 # In mm. Adjust based on your model scale# Repair CAD surfaces (after merging open shells)algo.repairCAD([root], tolerance, orient=False)

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.
# Repair mesh geometriesalgo.repairMesh([root], tolerance=0.1, crackNonManifold=True, orient=False)
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)
# Tessellate with quality-based parametersalgo.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:
# Tessellate relative to model sizealgo.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)
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:
# Orient faces using the exterior orientation strategyalgo.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:
# Orient open shells separately (if you saved them from step 2.1)if len(openShells) > 0: algo.orientPolygonFaces(openShells)# Orient unstitched faces separatelyif len(unstitchedFaces) > 0: algo.orientPolygonFaces(unstitchedFaces)
Tip
This approach gives you more control over orientation for models with mixed closed volumes and open surfaces.

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.
# 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 consistentlyalgo.orientNormals([root])
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:
# Generate UVs using axis-aligned bounding box projectionalgo.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:
# Automatic UV unwrapping with optimal settingsalgo.automaticUVMapping([root], channel=0, sharpToSeam=True, # Use sharp edges as seams forbidOverlapping=True) # No overlapping islands

Lightmap UVs (second UV channel)

If using Unity's lightmapping system, generate a second UV channel optimized for baked lighting:
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:
# Generate tangents from UV channel 0algo.createTangents([root], uvChannel=0, override=False) # Keep existing tangents
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:
import pxzfrom pxz import core, io, algo, scene# File path to importFILE_PATH = "/path/to/file.CATProduct"# Step 1: Configure import settingscore.setModuleProperty("IO", "LoadVariant", "False")core.setModuleProperty("IO", "PreferLoadMesh", "false") # We want to tessellate ourselvescore.setModuleProperty("IO", "LoadPMI", "False")# Step 2: Import the fileprint("Importing file...")root = io.importScene(FILE_PATH)roots = [root]# Step 3: Delete unnecessary dataprint("Cleaning up unnecessary data...")algo.deleteFreeVertices(roots) # Remove pointsalgo.deleteLines(roots) # Remove line geometries# Step 4: Merge open shells before repairingprint("Merging open shells...")openShells = scene.mergePartOccurrencesWithSingleOpenShellByAssemblies(root)unstitchedFaces = scene.findPartOccurrencesWithUnstitchedOpenShells(root)# Step 5: Repair CAD geometriesprint("Repairing CAD surfaces...")tolerance = 0.1 # Adjust based on your model unitsalgo.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 meshesprint("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 memoryalgo.deletePatches(roots)# Step 9: Orient polygon facesprint("Orienting faces...")algo.orientPolygonFaces(roots)# Handle open shells and unstitched faces separately if neededif len(openShells) > 0: algo.orientPolygonFaces(openShells)if len(unstitchedFaces) > 0: algo.orientPolygonFaces(unstitchedFaces)# Step 10: Create smooth normals if they don't existprint("Creating normals...")algo.createNormals(roots, sharpEdge=45, override=False, useAreaWeighting=True)# Step 11: Generate UVs for texturing (channel 0) if they don't existprint("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 existprint("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.