Skip to content

Python

LOD Tailor’s editor subsystem, TALODTailorSubsystem, gives Blueprint and Python access to the same scans, verdicts, batch runs, backups, reports and settings as the panel.

import unreal
tailor = unreal.get_editor_subsystem(unreal.TALODTailorSubsystem)

In Blueprint (for example in an Editor Utility Widget), get the LOD Tailor editor subsystem (class TALODTailorSubsystem) and use the functions in the ta LOD Tailor category.

Function Returns
scan_paths(paths, show_progress=True) TALODTailorReport
scan_project(show_progress=True) TALODTailorReport
scan_assets(assets, show_progress=True) TALODTailorReport
describe_mesh(mesh) TALODTailorMesh
audit_mesh(mesh) Array of TALODTailorIssue
advise_nanite(mesh) TALODTailorNaniteAdvice
get_targets() Array of TALODTailorProfile
get_presets() Array of TALODTailorPreset
get_presets_for(kind) Array of TALODTailorPreset
get_folder_rules() Array of TALODTailorFolderRule
make_apply_options(preset_name) TALODTailorApplyOptions
make_apply_options_for(preset_name, skeletal_preset_name) TALODTailorApplyOptions
plan(report, meshes, options) TALODTailorPlan
apply(plan, show_progress=True) TALODTailorApplyResult
restore_backup(backup_file, show_progress=True) TALODTailorApplyResult
get_latest_backup() str
get_default_export_options() TALODTailorExportOptions
export_report(report, options) TALODTailorExportResult
export_plan(plan, options) TALODTailorExportResult
can_render_lod_pictures() bool
save_lod_pictures(mesh, folder, size=160) Array of str
get_settings_asset() TALODTailorConfig or None
use_settings_asset(asset) Nothing
create_settings_asset(asset_path, use_for_project=True) TALODTailorConfig
export_settings(file_path) bool
import_settings(file_path) bool
apply_pending_import_rules() int
snapshot_imported_lods(mesh) int
find_lost_imported_lods(mesh) Array of int
restore_imported_lods(mesh) int
reimport_keeping_imported_lods(mesh) bool
get_log() Array of TALODTailorLogEntry
clear_log() Nothing
distance_to_screen_size(target, bounds_radius, meters) float (static)
screen_size_to_distance(target, bounds_radius, screen_size) float (static)
open_panel() Nothing
open_panel_with_paths(paths) Nothing
open_panel_with_assets(assets) Nothing
show_step_in_panel(step) Nothing
select_in_panel(mesh) Nothing
focus_target_in_panel(target_name) Nothing
preview_in_panel(options) Nothing

Read and check static and skeletal meshes and return a report with every mesh, every finding and the Nanite or LODs verdicts, like a scan in the panel.

  • scan_paths scans content folders such as "/Game/Props" and their subfolders.
  • scan_project scans the Included Paths from the settings.
  • scan_assets scans a list of unreal.AssetData, for example the Content Browser selection. Assets other than static and skeletal meshes are ignored.

All three skip the Excluded Paths. With show_progress=True a progress dialog with a Cancel button is shown; cancelling returns the meshes read so far. Pass False in scripts that run unattended.

These functions don’t wait for the Asset Registry. Right after the editor starts, wait until asset discovery has finished, or some meshes will be missing. (An editor started with -ExecutePythonScript waits for discovery before it runs the script.)

describe_mesh, audit_mesh and advise_nanite

Section titled “describe_mesh, audit_mesh and advise_nanite”

describe_mesh reads one loaded unreal.StaticMesh or unreal.SkeletalMesh: its LODs, triangles, sections, screen sizes, Min LOD, Nanite state and, for skeletal meshes, its bones. audit_mesh returns the findings of one mesh on the enabled targets, the same findings Data Validation reports (before Min Validation Severity is applied). advise_nanite returns its Nanite or LODs verdict for every enabled target.

get_targets, get_presets, get_presets_for and get_folder_rules

Section titled “get_targets, get_presets, get_presets_for and get_folder_rules”

get_targets returns the enabled targets, get_presets all LOD presets and get_folder_rules all folder rules, from the settings asset when the project uses one and from Project Settings otherwise. get_presets_for(kind) returns the presets offered for unreal.TALODTailorMeshKind.STATIC_MESH or SKELETAL_MESH (for skeletal meshes, your skeletal presets followed by the two built-in ones, unless one of your presets has the same name). Changing the returned copies doesn’t change the settings.

make_apply_options and make_apply_options_for

Section titled “make_apply_options and make_apply_options_for”

Return batch options with the default values and copies of the presets, found by name (case-insensitive). make_apply_options_for takes one preset for static meshes and one for skeletal meshes. make_apply_options takes one preset: a preset meant for static meshes sets the static recipe, one meant for skeletal meshes the skeletal recipe, and one meant for any mesh sets both. A recipe whose preset is not found starts with the first preset for its kind of mesh (Standard and Characters by default). Change the options before passing them to plan; the settings don’t change.

plan is the dry run behind Preview changes: it returns what a batch run with these options would do to each mesh of the report, without changing anything. meshes is a list of unreal.SoftObjectPath of the report’s meshes to include; an empty list includes every mesh of the report. With use_folder_rules on, meshes that match a folder rule get its preset.

apply executes a plan like Apply in the panel: it writes a backup first, then changes, builds and (with save) saves the meshes. Entries with the action SKIP are not touched and count as skipped. It asks for no confirmation. With show_progress=True a progress dialog with a Cancel button is shown. The run is added to the panel’s Log.

restore_backup puts back the settings of a backup file. Pass the full path of any backup, restored or not, or an empty string for the newest one that hasn’t been restored. Like the panel, a complete restore renames the file to Restored_LODTailor_<time>.json. See Restore for what a restore can and can’t put back.

get_latest_backup returns the full path of the newest backup file in the Backup Directory that hasn’t been restored yet, or an empty string.

get_default_export_options, export_report and export_plan

Section titled “get_default_export_options, export_report and export_plan”

get_default_export_options returns the report options from the settings: the Report Directory, all three formats and the LOD picture settings. export_report writes the report of a scan, export_plan the preview of a plan (lod_plan.html, .csv and .json, like Export preview). Neither opens the result in a browser.

If no format is selected, export_report writes nothing and errors contains “No format selected.”

can_render_lod_pictures and save_lod_pictures

Section titled “can_render_lod_pictures and save_lod_pictures”

save_lod_pictures(mesh, folder, size=160) renders every LOD of a static or skeletal mesh from the same camera into JPEG files <mesh name>_<hash>_LOD<n>.jpg and returns their paths in LOD order. A relative folder starts at the project folder; the size is limited to 32 to 1024 pixels. can_render_lod_pictures() is False when the editor has no graphics device, as in a commandlet without -AllowCommandletRendering or with -NullRHI. In a commandlet, only static meshes are pictured. See LOD pictures.

Function What it does
get_settings_asset() The settings asset the project uses, or None when it uses Project Settings.
use_settings_asset(asset) Uses this asset for the project (None: Project Settings again). Written to Config/DefaultEditor.ini.
create_settings_asset(asset_path, use_for_project=True) Creates and saves a settings asset, for example /Game/Settings/DA_LODTailor, as a copy of the settings in use, and uses it for the project unless use_for_project is False. Returns None for an invalid path.
export_settings(file_path) Writes the targets, presets, folder rules and reference camera in use to a JSON file.
import_settings(file_path) Reads such a file into the settings asset in use, or into Project Settings. False for a file that is not a ta LOD Tailor settings file.
apply_pending_import_rules() Applies the folder rules that apply on import to the new meshes imported since the last editor tick, and returns how many meshes changed. For scripts that import in a loop.

See Shared settings and folder rules.

Function What it does
snapshot_imported_lods(mesh) Copies the imported LODs of a static or skeletal mesh before a reimport you run yourself. Returns how many it copied.
find_lost_imported_lods(mesh) The imported LODs of the last copy that the mesh has lost since, by LOD index.
restore_imported_lods(mesh) Puts the lost LODs back from the copy, as one undo step. Returns how many came back.
reimport_keeping_imported_lods(mesh) Reimports the mesh from its source file without asking and puts back the imported LODs the reimport removed, whatever Protect Imported LODs on Reimport says. Returns True if the reimport ran.

See Reimport protection.

get_log returns the entries of the panel’s Log, oldest first: batch runs, restores, reimport protection, folder rules applied on import and settings changes of this editor session. clear_log empties it.

distance_to_screen_size and screen_size_to_distance

Section titled “distance_to_screen_size and screen_size_to_distance”

Convert between a distance in metres and a screen size for a mesh with a bounds radius in centimetres, on a target’s camera (its field of view and aspect ratio). They don’t apply the target’s distance scale. See Distances and screen sizes for the formula. Both are static functions, so you can call them on the class.

Function What it does
open_panel() Opens the panel without scanning.
open_panel_with_paths(paths) Opens the panel and scans these content folders.
open_panel_with_assets(assets) Opens the panel and scans these assets.
show_step_in_panel(step) Shows step 1 (Meshes), 2 (Findings) or 3 (Batch LODs).
select_in_panel(mesh) Selects a scanned mesh (an unreal.SoftObjectPath) on the Meshes page.
focus_target_in_panel(target_name) Selects a target chip by name. An empty or unknown name selects All targets.
preview_in_panel(options) Opens Batch LODs with these options and previews them for every mesh the panel has scanned.

When the panel is still waiting for the Asset Registry before it scans, show_step_in_panel, select_in_panel, focus_target_in_panel and preview_in_panel run after that scan.

The report types are read-only. Targets, presets, LOD steps, folder rules, batch options and export options can be changed. Enum values are written in capitals in Python, for example unreal.TALODTailorNaniteMode.KEEP_NANITE or unreal.TALODTailorMeshKind.SKELETAL_MESH.

Property Type Meaning
meshes Array of TALODTailorMesh Every scanned mesh, sorted by package path
issues Array of TALODTailorIssue Every finding
nanite_advice Array of TALODTailorNaniteAdvice The Nanite or LODs verdicts, one per mesh, in the order of meshes
profiles Array of TALODTailorProfile The targets that were enabled during the scan
scope Array of str The scanned folders, or the names of the scanned meshes
seconds float Duration of the scan
time DateTime When the scan started
Property Type Meaning
object_path SoftObjectPath Object path
name, package str Name and package path
kind TALODTailorMeshKind STATIC_MESH or SKELETAL_MESH
bones, unskinned_bones int Skeletal meshes: bones of the skeleton, and bones no vertex is skinned to
lod_settings_asset str Skeletal meshes: the LOD Settings asset that drives the LODs, or empty
lods Array of TALODTailorLOD The rendered LODs. For static Nanite meshes LOD 0 is the fallback mesh.
nanite bool Nanite is on
source_triangles int Triangles of the full mesh: the Nanite mesh, or LOD 0 before its own reduction
bounds_radius float Radius of the bounding sphere at scale 1, in cm
bounds_size Vector Size of the bounding box at scale 1, in cm
lod_group Name LOD group
auto_screen_size bool Unreal computes the screen sizes
min_lod int Default Min LOD
platform_min_lod Map of Name to int Per-platform Min LOD overrides
materials int Number of material slots
nanite_bytes int Size of the Nanite data on disk, in bytes; 0 without Nanite
nanite_fallback_percent float Static Nanite meshes: the fallback mesh’s share of the triangles when it is set as a share, otherwise -1.0
translucent_material, masked_material, world_position_offset bool A material is translucent, is masked, or uses World Position Offset
Property Type Meaning
triangles, vertices int Triangles and vertices
screen_size float Default screen size
platform_screen_sizes Map of Name to float Per-platform screen size overrides
percent_triangles float Share of triangles the reduction keeps; 1.0 when not reduced
custom bool Hand-made (imported) LOD
sections int Number of material sections
merged_sections bool LOD Tailor merged the sections of this LOD (fewer draw calls)
section_triangles, section_materials Array of int Triangles and material slot of each section
section_material_groups Array of int Static meshes: for each section, the first section drawn with the same material and settings
bones int Skeletal meshes: bones the LOD needs
max_bone_influences int Skeletal meshes: the most bones that move one vertex, 0 when not known
reduces_from_lod0 bool The LOD is a reduction of LOD 0 to a share of its triangles, the way LOD Tailor builds LODs
reduction_bone_influences int Skeletal meshes: the bone influence limit of the reduction
removed_bones int Skeletal meshes: bones the reduction removes from this LOD
bytes int Estimated GPU memory of the LOD’s vertex and index buffers
Property Type Meaning
rule_id Name Rule id, for example OverBudget. See Checks.
severity TALODTailorSeverity INFO, WARNING or ERROR
asset_path SoftObjectPath The mesh
message Text The finding
targets Array of str The targets it applies to; empty for every target

TALODTailorNaniteAdvice and TALODTailorNaniteTarget

Section titled “TALODTailorNaniteAdvice and TALODTailorNaniteTarget”
Property Type Meaning
asset_path, name, kind SoftObjectPath, str, TALODTailorMeshKind The mesh
nanite bool Nanite is on for the mesh now
verdict TALODTailorNaniteVerdict Over all targets: KEEP_NANITE, NANITE_WITH_FALLBACK_LODS, SWITCH_TO_LODS, KEEP_LODS or CONSIDER_NANITE
reason Text Why, in one sentence
source_triangles, fallback_triangles int Triangles of the full mesh, and of the fallback mesh of a static Nanite mesh
nanite_bytes, nanite_bytes_estimated int, bool Nanite data in bytes, and whether it is an estimate
lod_bytes, lod_bytes_estimated int, bool Memory of a LOD chain in bytes, and whether it is an estimate
material_risk, material_risk_text TALODTailorMaterialRisk, Text NONE, POSSIBLE or CONFIRMED, and what it is about
notes Array of str Material notes: translucent, masked, World Position Offset
targets Array of TALODTailorNaniteTarget One per target: target (name), verdict, reason, renders_nanite (the target draws the mesh with Nanite today), triangles (what it draws without Nanite) and budget

A target. See Target settings for the meaning and ranges.

Property Type
name str
enabled bool
device TALODTailorDevice: DESKTOP, HANDHELD, CONSOLE, HEADSET or MOBILE
platform Name (None without a key)
nanite bool
max_triangles int
require_lods_above int (Require LODs Above)
max_skeletal_triangles int
require_skeletal_lods_above int (Require Skeletal LODs Above)
distance_scale float
field_of_view float
aspect_ratio float
min_lod int (-1: first LOD within the budget)
Type Properties
TALODTailorPreset name, description, use (TALODTailorPresetUse: ANY, STATIC_MESHES or SKELETAL_MESHES), lods (array of TALODTailorLODStep, LOD 1 and up), auto_screen_size (let Unreal compute screen sizes, static meshes only)
TALODTailorLODStep percent_triangles (share of the full mesh, 0.005 to 1.0; 0.5 = half), distance (metres on the reference camera, at least 0.1), max_bone_influences (skeletal meshes, 0 to 12, 0 keeps the mesh’s setting)
Property Type Meaning
enabled bool Rules that are off are ignored
path str A content folder, or a wildcard on the mesh path such as /Game/Env*Rock*
meshes TALODTailorPresetUse ANY, STATIC_MESHES or SKELETAL_MESHES
preset str Name of the preset for matching meshes
set_nanite_mode, nanite_mode bool, TALODTailorNaniteMode Use the rule’s own Nanite mode
apply_on_import bool Apply the preset when a matching new mesh is imported
Property Type Default Panel option
preset TALODTailorPreset The static recipe (also used for skeletal meshes while skeletal_preset has no LODs)
skeletal_preset TALODTailorPreset The skeletal recipe
include_static_meshes bool True Change static meshes
include_skeletal_meshes bool True Change skeletal meshes
use_folder_rules bool True Use the folder rules
generate_lods bool True Build the LOD chain
replace_custom_lods bool False Replace imported LODs
set_screen_sizes bool True Screen sizes from the distances
platform_screen_sizes bool True Per-platform screen sizes (only with set_screen_sizes)
platform_min_lod bool True Per-platform Min LOD
save bool True Save the changed meshes
reduce_draw_calls bool False Fewer draw calls from LOD
draw_calls_from_lod int 2 Its LOD, 1 to 7
merge_same_material_sections bool True Merge sections with the same material
drop_sections_below float 0.02 Drop sections under, as a fraction, 0 to 0.25
merge_into_main_material bool False Main material only
remove_unskinned_bones bool False Remove unskinned bones from LOD
remove_bones_from_lod int 2 Its LOD, 1 to 7
min_triangles int 500 Skip meshes under
nanite_mode TALODTailorNaniteMode SKIP Nanite meshes: SKIP, KEEP_NANITE or DISABLE_NANITE
nanite_fallback_percent float 1.0 Fallback, 0.01 to 1.0

TALODTailorPlan has options (the batch options), profiles (the enabled targets) and entries, one TALODTailorPlanEntry per mesh:

Property Type Meaning
asset_path, name, kind SoftObjectPath, str, TALODTailorMeshKind The mesh
preset, recipe str, TALODTailorPreset The name of the preset the entry uses, and the preset itself
folder_rule str The folder rule that picked the preset, or empty
action TALODTailorPlanAction GENERATE (new LOD chain), UPDATE_SETTINGS (settings only) or SKIP
note Text Why the mesh is skipped, or notes on the change, as in the preview’s Note column
old_lods, new_lods int LOD count before and after
triangles Array of int Expected triangles per LOD after the run
screen_sizes Array of float Default screen size per LOD after the run; empty when no screen sizes are written
min_lod Map of Name to int Per-platform Min LOD after the run, by platform key
nanite_before, nanite_after bool Nanite before and after
replaces_custom_lods bool The mesh loses imported LODs
removes_bones int Skeletal meshes: unskinned bones removed from the far LODs
bone_influences Array of int Skeletal meshes: the bone influences per LOD after the run (0 = unchanged)
sections_before, sections_after Array of int Draw calls (material sections) per LOD before and after the run
reduces_draw_calls bool Far LODs get fewer sections

The per-platform screen sizes of a plan are not available from Python or Blueprint.

Returned by apply and restore_backup.

Property Type Meaning
success bool True if no mesh failed
changed, skipped, failed int Number of meshes
backup_file str Full path of the backup that was written or restored
errors Array of str Problems, for example a mesh that could not be loaded, or imported LODs a restore couldn’t bring back
seconds float Duration

TALODTailorExportOptions and TALODTailorExportResult

Section titled “TALODTailorExportOptions and TALODTailorExportResult”
Type Properties
TALODTailorExportOptions output_directory (relative paths start at the project folder; default Saved/LODTailor/Reports), html, csv, json (all True), lod_pictures (LOD pictures in the HTML report, True), max_picture_meshes (50, 0 to 1000), picture_size (pixels, 160, 64 to 512)
TALODTailorExportResult success, output_directory (full path), main_file (the HTML file, or the first file written), files, errors, lod_pictures (number of LOD pictures in the HTML report)
Type Properties
TALODTailorLogEntry time (DateTime), severity (TALODTailorSeverity), asset_path (the mesh, if any), message
TALODTailorConfig The settings asset: profiles, reference_field_of_view, reference_aspect_ratio, presets and folder_rules
import unreal
tailor = unreal.get_editor_subsystem(unreal.TALODTailorSubsystem)
report = tailor.scan_paths(["/Game/Props"], False)
for mesh in report.meshes:
print(mesh.name, mesh.kind, [lod.triangles for lod in mesh.lods], "Nanite" if mesh.nanite else "")
for issue in report.issues:
print(issue.severity, issue.rule_id, issue.asset_path.export_text(), issue.message, list(issue.targets))
selected = unreal.EditorUtilityLibrary.get_selected_asset_data()
report = tailor.scan_assets(selected)
def ready_percent(report, target=""):
if not report.meshes:
return 0
flagged = {i.asset_path.export_text() for i in report.issues
if i.severity != unreal.TALODTailorSeverity.INFO
and (not target or not i.targets or target in i.targets)}
return round(100 * (len(report.meshes) - len(flagged)) / len(report.meshes))
for target in report.profiles:
print(target.name, ready_percent(report, target.name), "% ready")
print("All targets", ready_percent(report), "% ready")
options = tailor.make_apply_options("Standard")
options.nanite_mode = unreal.TALODTailorNaniteMode.KEEP_NANITE
# Dry run: [] = every mesh of the report
plan = tailor.plan(report, [], options)
for entry in plan.entries:
print(entry.name, entry.action, entry.old_lods, "->", entry.new_lods,
list(entry.triangles), dict(entry.min_lod), entry.note)
result = tailor.apply(plan) # backs up first
print(result.changed, "changed,", result.failed, "failed. Backup:", result.backup_file)
tailor.restore_backup(result.backup_file) # undo this run

To restore the newest backup that hasn’t been restored yet, pass an empty string: tailor.restore_backup("").

Only the meshes over the Meta Quest budget

Section titled “Only the meshes over the Meta Quest budget”
over = [i.asset_path for i in report.issues
if str(i.rule_id) == "OverBudget" and "Meta Quest" in i.targets]
plan = tailor.plan(report, over, tailor.make_apply_options("Mobile aggressive"))
options = tailor.make_apply_options("Standard")
preset = options.preset
step = unreal.TALODTailorLODStep()
step.percent_triangles = 0.04
step.distance = 160.0
lods = list(preset.lods)
lods.append(step)
preset.lods = lods
options.preset = preset
options.min_triangles = 2000
tailor.preview_in_panel(options) # review it in the panel before applying

preview_in_panel previews the meshes the panel has scanned; open the panel with a scan first, for example with open_panel_with_paths(["/Game/Props"]).

options = tailor.make_apply_options_for("Standard", "Characters (mobile and VR)")
options.include_static_meshes = False # only the skeletal meshes
options.remove_unskinned_bones = True # from LOD 2 on
options.remove_bones_from_lod = 2
plan = tailor.plan(report, [], options)
for entry in plan.entries:
print(entry.name, entry.action, list(entry.triangles), list(entry.bone_influences), entry.removes_bones)

See Skeletal meshes.

options = tailor.make_apply_options("Standard")
options.reduce_draw_calls = True
options.draw_calls_from_lod = 2
options.drop_sections_below = 0.02 # 2 %
plan = tailor.plan(report, [], options)
for entry in plan.entries:
if entry.reduces_draw_calls:
print(entry.name, list(entry.sections_before), "->", list(entry.sections_after))
tailor.export_plan(plan, tailor.get_default_export_options()) # lod_plan.html, .csv, .json

See Fewer draw calls.

for advice in report.nanite_advice:
if advice.verdict == unreal.TALODTailorNaniteVerdict.NANITE_WITH_FALLBACK_LODS:
print(advice.name, advice.reason)
for target in advice.targets:
print(" ", target.target, target.verdict, target.reason)
cliff = unreal.load_asset("/Game/Props/SM_Cliff_Nanite")
advice = tailor.advise_nanite(cliff)
print(advice.verdict, advice.nanite_bytes, advice.lod_bytes, advice.material_risk, list(advice.notes))
barrel = unreal.load_asset("/Game/Props/SM_Barrel_LODs")
if tailor.can_render_lod_pictures():
print(tailor.save_lod_pictures(barrel, "Saved/LODPictures", 256))
options = tailor.get_default_export_options()
options.max_picture_meshes = 20
result = tailor.export_report(report, options)
print(result.lod_pictures, "LOD pictures in", result.main_file)
# Targets, presets and folder rules in an asset the team checks in
config = tailor.create_settings_asset("/Game/Settings/DA_LODTailor", True)
# Copy them to another project
tailor.export_settings("C:/Shared/LODTailorSettings.json")
# ... and in the other project:
# tailor.import_settings("C:/Shared/LODTailorSettings.json")
for rule in tailor.get_folder_rules():
print(rule.path, rule.meshes, rule.preset, rule.apply_on_import)

A script that imports many meshes can call tailor.apply_pending_import_rules() after each import, so the folder rules that apply on import run right away.

statue = unreal.load_asset("/Game/Props/SM_Statue_Imported")
tailor.reimport_keeping_imported_lods(statue) # imported LODs survive the reimport
for entry in tailor.get_log():
print(entry.time, entry.severity, entry.message)
options = tailor.get_default_export_options()
options.output_directory = "Docs/LODReport"
options.csv = False
result = tailor.export_report(report, options)
print(result.main_file, result.errors)
targets = {t.name: t for t in tailor.get_targets()}
quest = targets["Meta Quest"]
# A mesh with a 100 cm bounds radius, 9 m away on the Meta Quest camera
size = unreal.TALODTailorSubsystem.distance_to_screen_size(quest, 100.0, 9.0) # 0.0868
meters = unreal.TALODTailorSubsystem.screen_size_to_distance(quest, 100.0, size) # 9.0
# Where LOD 1 of a scanned mesh takes over on Meta Quest (screen size for its key)
mesh = report.meshes[0]
if len(mesh.lods) > 1:
lod1 = mesh.lods[1]
screen = lod1.platform_screen_sizes.get(quest.platform, lod1.screen_size)
print(unreal.TALODTailorSubsystem.screen_size_to_distance(quest, mesh.bounds_radius, screen))

The last example looks only at the exact platform key; the panel also falls back to the key’s platform group (for example Mobile for Android) before the default screen size.