SceneForge turns a natural-language prompt, and optionally a simple blueprint image, into a USD scene. It combines local LLM scene planning, deterministic layout rules, asset retrieval, blueprint-guided placement, and USDA export into one offline-friendly pipeline.
The repo supports two scene-authoring backends:
direct_usd_scene.py: pure Pixar USD path, no Omniverse Kit runtime requirednatural_language_scene.pyviarun_omniverse_scene.py: Omniverse Kit authoring path
The default user-facing entry point is main.py.
The repo also includes a demo UI:
app.py: Streamlit interface for blueprint upload, pipeline execution, metrics, logs, explanation output, and Blender launch
- Convert a prompt like
"a medieval classroom with wooden desks and a blackboard"into a structured scene graph - Use a local Ollama model for JSON scene generation
- Fall back to deterministic scene templates when AI output is invalid or unavailable
- Parse a color-coded
blueprint.pngand map it into world-space placement - Run a refinement loop over blueprint scenes to improve spacing and relational consistency
- Extract simple object relationships from prompt text such as
on,beside, andnear - Infer a few special-case relations such as solar-system orbital relations
- Resolve assets from:
- cached normalized assets
- Objaverse candidates
- curated free-source downloads
- local USDA fallback assets in
assets/
- Normalize external meshes for stable placement
- Procedurally build textured planets for solar-system scenes
- Add a simple room shell around the arranged scene
- Export
generated_scene.usda - Try to export a flattened self-contained USDA for easier sharing
- Open a lightweight local viewer for quick inspection
- Run a Streamlit demo UI for research presentation and demos
The high-level flow is:
main.pyvalidates Ollama availability and the selected model.main.pylaunchesdirect_usd_scene.pyin AI or rule mode.direct_usd_scene.pybuilds a scene graph from:- local LLM output via
ai_scene_graph.py, or - deterministic templates and constraints
- local LLM output via
- If
blueprint.pngexists, blueprint parsing and position merging can influence layout. - Prompt relations are extracted or inferred.
- The graph is arranged and optionally refined by layout and agent loops.
objaverse_loader.pyresolves the best available asset for each object.- USD prims are authored, transformed, scaled, and exported.
main.pyoptionally flattens the scene and launchesview_generated_scene.py.
This repo is not a web research system, but it does have several retrieval-style capabilities that matter for scene generation:
-
ai_scene_graph.py- builds few-shot prompts from
scene_dataset.json - queries a local Ollama model
- normalizes and constrains model output
- falls back safely when the model returns bad JSON or poor structure
- builds few-shot prompts from
-
objaverse_loader.py- searches Objaverse LVIS categories when the package is available
- scores candidate meshes against object-specific target dimensions
- downloads curated free assets for some categories
- caches and reuses normalized assets
- procedurally generates planets with downloaded textures when needed
-
blueprint_parser.py- reads a simple blueprint image
- identifies colored object regions
- classifies them by nearest palette color
-
relations.pyandrelation_infer.py- recover lightweight semantic relations from prompt text
- add special inferred relations for known prompt types
In practice, the project "researches" a scene by combining local LLM reasoning, few-shot examples, asset retrieval, candidate scoring, and prompt/blueprint interpretation.
ai_scene_graph.detect_scene_type() currently recognizes:
classroomthrone_roomforest_campmarkettavernsolar_systemstudiofallback
The built-in canonical object set currently includes:
wooden_desktablechairblackboardlampbookshelfthronebannertorchbarrelcratecampfirepine_treebenchmarket_stallsunmercuryvenusearthmarsjupitersaturnuranusneptune
Synonyms such as desk, board, bookcase, tree, fire, and stall are canonicalized into those supported names.
-
main.py- main CLI entry point
- checks Ollama server reachability
- checks the configured Ollama model is installed
- runs the scene builder
- exports a flattened USDA copy when possible
- optionally opens the local previewer
-
direct_usd_scene.py- primary USD builder used by
main.py - authors a scene in memory with Pixar USD APIs
- supports
--mode=ai,--mode=rule, and blueprint mode with-b - applies room shells, assets, transforms, scaling, and export
- primary USD builder used by
-
run_omniverse_scene.py- Omniverse Kit bootstrapper
- enables
omni.usdandomni.kit.commands - runs
natural_language_scene.build_scene_from_prompt()
-
natural_language_scene.py- Omniverse-native scene authoring path
- creates prims and references through Kit commands
- applies transforms and exports through an ASCII-safe temp path
-
app.py- Streamlit UI for the blueprint-driven pipeline
- saves uploaded blueprint images as
blueprint.png - runs
direct_usd_scene.py -b "<prompt>"in a subprocess - forces UTF-8 subprocess IO on Windows to avoid Unicode path crashes
- displays logs, parsed metrics, explanation lines, output path, and Blender launch controls
-
ai_scene_graph.py- canonicalizes object names
- detects scene type from prompt text
- loads few-shot examples from
scene_dataset.json - builds Ollama prompts
- extracts JSON from model output
- constrains coordinates and spacing
- provides deterministic scene templates
- scores layout quality
- builds graph structures with nodes, edges, and lookup tables
- includes a training stub for future fine-tuning
-
layout_engine.py- graph-only layout helper focused on classroom-style layouts
- arranges desks into a grid
- places chairs relative to desks
- places boards at the front
- stores room dimensions in graph metadata
- adds
nearrelationship edges between chairs and desks
-
agents.py- lightweight graph refinement agents
domain_agent()nudges objects to satisfybeside,on, andnearevaluator_agent()scores spacing qualityreflection_agent()summarizes layout quality in plain English
-
relations.py- regex-based extraction of prompt relations
- currently supports
on,beside, andnear
-
relation_infer.py- adds special-case inferred relations
- currently handles a solar-system prompt shortcut
-
blueprint_parser.py- reads
blueprint.png - flood-fills colored regions
- matches region colors to known object classes
- returns normalized object positions
- reads
-
blueprint_mapper.py- converts normalized blueprint coordinates into world coordinates
- maps blueprint detections into scene objects
- can merge blueprint positions into an existing generated scene
-
blueprint_agents.py- evaluates blueprint scene placement
- infers semantic relations such as chair-to-desk and desk-to-board
- reflects on relational correctness
- computes a combined refinement score
- adaptively decides whether to continue refinement
- refines positions and facing directions conservatively
- generates human-readable explanation summaries
objaverse_loader.py- central asset resolver
- defines target sizes and retrieval specs per object type
- checks fresh cached normalized assets first
- optionally searches Objaverse candidates
- downloads curated free-source assets for some categories
- normalizes meshes so pivots and scale are stable
- caches metadata and removes stale cache entries
- procedurally builds planet assets with preview materials and textures
- falls back to the local USDA asset library in
assets/
-
view_generated_scene.py- simple local preview app built on
matplotlib - draws custom proxy shapes for known objects
- can also render referenced mesh geometry when available
- supports save-only preview rendering via env var
- simple local preview app built on
-
scene_dataset.json- few-shot examples used to improve local model prompting
-
requirements.txt- lightweight dependency install file for the UI and non-Omniverse Python utilities
-
generated_scene.usda- latest generated scene with references
-
generated_scene_flat_*.usda- flattened export variant for easier sharing when export succeeds
tempCodeRunnerFile.pytempCodeRunnerFile.python- editor scratch files, not part of the core pipeline
These are the highest-leverage functions if you are modifying behavior:
-
main.pycheck_ollama_server()check_ollama_model()run_scene_builder()export_flattened_scene()launch_viewer()
-
direct_usd_scene.pybuild_scene_from_prompt()add_room_shell()create_placeholder_geometry()export_stage_safely()_bbox_fit_scale()
-
ai_scene_graph.pygenerate_scene()generate_rule_scene()query_local_model()build_few_shot_prompt()_apply_scene_constraints()score_layout()build_graph()
-
objaverse_loader.pyfind_asset()retrieve_objaverse_asset()retrieve_free_source_asset()_convert_external_mesh_to_usda()_score_mesh_for_object()_retrieve_planet_asset()cleanup_stale_cache()
-
blueprint_agents.pyevaluate_scene()infer_relationships()reflect_scene()compute_score()adaptive_controller()refine_scene()explain_scene()
For the Streamlit app and helper utilities:
python -m pip install -r requirements.txtThis installs:
streamlitPillowmatplotlibnumpytrimesh
Note:
- the core scene pipeline also requires Pixar USD Python bindings (
pxr) - the Omniverse backend also requires Omniverse Kit runtime support
- AI mode also requires Ollama running locally with the configured model pulled
C:\Users\arun1\omniverse-kit-venv312\Scripts\python.exe main.py "a medieval classroom with wooden desks and a blackboard"C:\Users\arun1\omniverse-kit-venv312\Scripts\python.exe main.py --mode=ai "a royal throne room with banners and torches"C:\Users\arun1\omniverse-kit-venv312\Scripts\python.exe main.py --mode=rule "a forest camp with trees, crates and a campfire"This uses blueprint.png as the dominant placement source.
C:\Users\arun1\omniverse-kit-venv312\Scripts\python.exe direct_usd_scene.py -b "a classroom with desks and chairs"C:\Users\arun1\omniverse-kit-venv312\Scripts\python.exe run_omniverse_scene.py --mode=ai "a medieval market with stalls and barrels"streamlit run app.pyUI flow:
- Upload a blueprint image
- Enter a prompt
- Click
Generate Scene - Review logs, metrics, and explanation output
- Open
generated_scene.usdain Blender from the UI if Blender is installed at the configured path
-
OLLAMA_API_URL- default:
http://localhost:11434 - base URL used by
main.pyto validate Ollama
- default:
-
SCENE_GRAPH_OLLAMA_MODEL- default:
llama3.2:1b - local Ollama model name used for scene graph generation
- default:
-
OPEN_VIEWER- default:
1 - set to
0to skip auto-opening the preview window
- default:
-
PREVIEW_SAVE_ONLY- default:
0 - set to
1to save a preview PNG instead of opening a window
- default:
-
SCENE_ASSET_CACHE_DIR- cache directory for normalized downloaded assets
-
SCENE_SAFE_GENERATED_CACHE_DIR- cache directory for procedurally generated assets such as planets
-
SCENE_ASSET_CACHE_TTL_HOURS- cache cleanup TTL
-
OBJAVERSE_CANDIDATE_LIMIT- maximum Objaverse candidates to inspect per category
-
OBJAVERSE_MIN_SCORE- quality threshold for accepting Objaverse matches
-
OMNI_KIT_ACCEPT_EULA- set automatically in
run_omniverse_scene.py
- set automatically in
The code expects these major Python/runtime dependencies:
- Pixar USD Python bindings:
pxr - Omniverse Kit runtime for the Kit path
- Ollama running locally for AI mode
trimeshPillowmatplotlibnumpy- optionally
objaverse streamlit
For the pure Python/UI side, requirements.txt now covers the common packages used directly by this repo.
-
generated_scene.usda- main authored scene
-
generated_scene_flat_<timestamp>.usda- flattened copy exported by
main.pywhen possible
- flattened copy exported by
-
<scene>.preview.png- preview image when
PREVIEW_SAVE_ONLY=1
- preview image when
-
external_asset_cache/- downloaded and normalized external assets plus cache metadata
-
objaverse_cache/- local Objaverse-related downloads if that path is used in your setup
For each object, SceneForge tries to find the best asset in this order:
- fresh normalized cached asset
- procedural planet asset if the object is a planet
- Objaverse candidate search
- curated free-source download
- local USDA fallback in
assets/
If no asset is available, the scene builder creates placeholder geometry so export can still succeed.
Blueprint parsing is intentionally simple. It assumes:
- a mostly white background
- colored regions large enough to survive filtering
- colors close to the expected palette
The default color mapping in blueprint_parser.py is:
- brown-like colors for desks/tables
- blue for chairs
- green for blackboards
- brown variations for shelves
- yellow for lamps
If you want better blueprint coverage, expand DEFAULT_COLOR_MAP and reduce the current shape assumptions.
main.pyalways runsdirect_usd_scene.py; the Omniverse path is available but not the defaultlayout_engine.pyis classroom-biased even though other scene families exist- relation extraction is intentionally shallow and only supports a few patterns
- blueprint parsing is color-and-region based, not learned or geometry-aware
- Objaverse retrieval only works when the package and local setup are available
- some external asset downloads require internet access
- flattened USDA export can still be sensitive to Windows path quirks
- the Streamlit UI assumes
pythonresolves to a usable interpreter for the pipeline subprocess - the Blender button assumes Blender is installed at
C:\Program Files\Blender Foundation\Blender 4.0\blender.exe - no automated tests are currently included
a medieval classroom with wooden desks and a blackboarda royal throne room with banners and torchesa forest camp with trees, crates and a campfirea medieval market with vendor stalls and barrelsa cozy tavern with tables, chairs and torchesa solar system with the sun and planets
- Add a
pyproject.tomland pin versions more explicitly - Split layout engines by scene family instead of routing everything through classroom logic
- Add tests for prompt parsing, blueprint parsing, and asset resolution
- Make
main.pyexpose backend selection between direct USD and Omniverse Kit - Expand relation extraction beyond
on,beside, andnear - Add richer blueprint palettes and legend-based detection
- Save outputs per prompt instead of overwriting the same filenames
- Let the Streamlit UI choose the Python interpreter and Blender executable path from the interface
This project already has a surprisingly rich prototype stack:
- local LLM scene planning
- deterministic safety fallback
- asset retrieval and normalization
- blueprint-conditioned generation
- iterative scene refinement
- procedural planet generation
- local USD preview
What it does not yet have is packaging polish, automated verification, or a fully generalized layout system. The README now reflects the code as it exists today rather than an idealized version.