diff --git a/docs/ConfiguringInfinigen.md b/docs/ConfiguringInfinigen.md
index 3561f1462..b2a35e5e4 100644
--- a/docs/ConfiguringInfinigen.md
+++ b/docs/ConfiguringInfinigen.md
@@ -45,7 +45,7 @@ Our `infinigen_examples/generate_nature.py` driver always loads [`infinigen_exam
Now that you understand the two major python programs and how to configure them, you may notice and wonder about the many configs/overrides provided in our original one-command "Hello World" example:
-```
+```bash
# Original hello world command
python -m infinigen.datagen.manage_jobs --output_folder outputs/hello_world --num_scenes 1 --specific_seed 0 \
--configs desert.gin simple.gin --pipeline_configs local_16GB.gin monocular.gin blender_gt.gin \
@@ -169,23 +169,23 @@ All commands below are shown with using `local_256GB` config, but you can attemp
We recommend this command as a starting point for generating high quality videos. Generating multi-view consistent terrain is not computationally tractible without CUDA accelleration, so make sure to follow the CUDA Terrain instructions in Installation.md, and we recommend not to remove the `cuda_terrain` flag below.
-````
+```bash
python -m infinigen.datagen.manage_jobs --output_folder outputs/my_videos --num_scenes 500 \
--pipeline_config slurm monocular_video cuda_terrain opengl_gt \
--cleanup big_files --warmup_sec 60000 --config trailer_video high_quality_terrain
-````
+```
#### Creating large-scale stereo datasets
-````
+```bash
python -m infinigen.datagen.manage_jobs --output_folder outputs/stereo_data --num_scenes 10000 \
--pipeline_config slurm stereo cuda_terrain opengl_gt \
--cleanup big_files --warmup_sec 60000 --config high_quality_terrain
-````
+```
#### Creating a few low-resolution images to your test changes
-```
+```bash
screen python -m infinigen.datagen.manage_jobs --output_folder outputs/dev --num_scenes 50 \
--pipeline_config slurm monocular cuda_terrain \
--cleanup big_files --warmup_sec 1200 --configs dev
@@ -196,7 +196,7 @@ screen python -m infinigen.datagen.manage_jobs --output_folder outputs/dev --num
These commands are intended as inspiration - please read docs above for more advice on customizing all aspects of Infinigen.
Create images that always have rain:
-```
+```bash
python -m infinigen.datagen.manage_jobs --output_folder outputs/my_videos --num_scenes 500 \
--pipeline_config slurm monocular cuda_terrain opengl_gt \
--cleanup big_files --warmup_sec 30000 \
@@ -206,7 +206,7 @@ python -m infinigen.datagen.manage_jobs --output_folder outputs/my_videos --num_
:bulb: You can substitute the `rain_particles` in `rain_particles_chance` for any `run_stage` name argument string in `infinigen_examples/generate_nature.py`, such as `trees` or `ground_creatures`.
Create images that only have terrain:
-```
+```bash
python -m infinigen.datagen.manage_jobs --output_folder outputs/my_videos --num_scenes 500 \
--pipeline_config slurm monocular cuda_terrain opengl_gt \
--cleanup big_files --warmup_sec 30000 --config no_assets
@@ -215,7 +215,7 @@ python -m infinigen.datagen.manage_jobs --output_folder outputs/my_videos --num_
Create videos at birds-eye-view camera altitudes:
-```
+```bash
python -m infinigen.datagen.manage_jobs --output_folder outputs/my_videos --num_scenes 500 \
--pipeline_config slurm monocular_video cuda_terrain opengl_gt \
--cleanup big_files --warmup_sec 30000 --config trailer_video high_quality_terrain \
@@ -225,7 +225,7 @@ python -m infinigen.datagen.manage_jobs --output_folder outputs/my_videos --num_
:bulb: The command shown is overriding `infinigen_examples/configs_nature/base.gin`'s default setting of `camera.camera_pose_proposal.altitude`. You can use a similar syntax to override any number of .gin config entries. Separate multiple entries with spaces.
Create 1 second video clips:
-```
+```bash
python -m infinigen.datagen.manage_jobs --output_folder outputs/my_videos --num_scenes 500 \
--pipeline_config slurm monocular_video cuda_terrain opengl_gt \
--cleanup big_files --warmup_sec 30000 --config trailer_video high_quality_terrain \
diff --git a/docs/GeneratingFluidSimulations.md b/docs/GeneratingFluidSimulations.md
index 387eab50e..52756b96a 100644
--- a/docs/GeneratingFluidSimulations.md
+++ b/docs/GeneratingFluidSimulations.md
@@ -9,13 +9,13 @@ Before you can generate fluids, you must run an additional installation step: `b
## Example Commands
#### Generate a video of a single scene with simulated fire generated on the fly
-```
+```bash
python -m infinigen.datagen.manage_jobs --specific_seed 3930249d --output_folder outputs/fire --num_scenes 1 --pipeline_config local_256GB.gin monocular_video.gin --cleanup none --config plain.gin fast_terrain_assets.gin use_on_the_fly_fire.gin
```
Because fluid simulation takes a long time, the fire resolution can be reduced in use_on_the_fly_fire.gin, by setting `set_obj_on_fire.resolution = {resolution}`. This will reduce the fire quality but speed up the simulation.
#### Generate a video of a single valley scene with simulated river
-```
+```bash
python -m infinigen.datagen.manage_jobs --specific_seed 61fc881a --output_folder outputs/river --num_scenes 1 --pipeline_config local_256GB.gin monocular_video.gin opengl_gt.gin cuda_terrain.gin --pipeline_overrides iterate_scene_tasks.frame_range=[100,244] --config river.gin simulated_river.gin no_assets.gin no_creatures.gin fast_terrain_assets.gin --cleanup none
```
Similar to fire, the simulation can be sped up by reducing the resolution. In simulated_river.gin, the resolution can be modified by setting `make_river.resolution = {resolution}`. The simulation can also be sped up by reducing the simulation duration in simulated_river.gin by setting `make_river.simulation_duration = {duration}`. For instance, before running the command above, the duration can be reduced to a number greater than 200 since that is the last frame of the video.
@@ -23,7 +23,7 @@ Similar to fire, the simulation can be sped up by reducing the resolution. In si
Also, note that this command will produce a scene without assets to speed up the process. However, the liquids generally interact with the objects by splashing on them, and a scene like this can be produced by removing the `no_assets.gin` option in the above command.
#### Generate videos of random scene types, with simulated fire generated on the fly when needed
-```
+```bash
python -m infinigen.datagen.manage_jobs --output_folder outputs/onthefly --num_scenes 10 \
--pipeline_config slurm_high_memory.gin monocular_video.gin \
--config fast_terrain_assets.gin use_on_the_fly_fire.gin \
@@ -31,7 +31,7 @@ python -m infinigen.datagen.manage_jobs --output_folder outputs/onthefly --num_
```
#### Generate videos of valley scenes with simulated rivers
-```
+```bash
python -m infinigen.datagen.manage_jobs --output_folder /n/fs/pvl-renders/kkayan/river --num_scenes 10 \
--pipeline_config slurm_high_memory.gin monocular_video.gin opengl_gt.gin cuda_terrain.gin \
--pipeline_overrides iterate_scene_tasks.frame_range=[100,244] \
@@ -44,20 +44,21 @@ python -m infinigen.datagen.manage_jobs --output_folder /n/fs/pvl-renders/kkayan
## Using Pre-Generated Fire
High-resolution fluid simulations take a long time, so assets on fire can pre-generated and imported in the scene instead of being baked on-the-fly. This allows for fire to be simulated once, instead of every time a scene is generated. To pre-generate fire assets of all types (bush, tree, creature, cactus, boulder), run:
-```
+```bash
python -m infinigen.tools.submit_asset_cache -f {fire_asset_folder} -n 1 -s -40 -d 184
```
where `fire_asset_folder` is where you want to save the fire. The number of assets per type, start frame and duration can be adjusted.
If you only want to pre-generate one type of asset once, run:
-```
+```bash
python -m infinigen.assets.fluid.run_asset_cache -f {fire_asset_folder} -a {asset} -s {start_frame} -d {simulation_duration}
```
where `fire_asset_folder` is where you want to save the fire. `asset` can be one of `CachedBushFactory`, `CachedTreeFactory`, `CachedCactusFactory`, `CachedCreatureFactory`, `CachedBoulderFactory`.
### Import pre-generated fire when generating a scene
After fire is pre-generated with one of the previous commands, edit config/use_cached_fire.gin and set the `FireCachingSystem.asset_folder` variable to `fire_asset_folder` you used when pre-generating fire. After this `use_cached_fire.gin` can be used instead of `use_on_the_fly_fire.gin` when generating a scene. This will import the fire from the folder it is saved instead of simulating it on-the-fly.
+
#### Example Command
-```
+```bash
python -m infinigen.datagen.manage_jobs --specific_seed 3930249d --output_folder outputs/fire --num_scenes 1 --pipeline_config local_256GB.gin monocular_video.gin --cleanup none --config plain.gin fast_terrain_assets.gin use_cached_fire.gin
```
diff --git a/docs/HelloWorld.md b/docs/HelloWorld.md
index 76f9b3113..74d988455 100644
--- a/docs/HelloWorld.md
+++ b/docs/HelloWorld.md
@@ -16,7 +16,7 @@ Infinigen generates scenes by running multiple tasks (usually executed automatic
:exclamation: If you encounter any missing .so files, missing dependencies (such as `gin`), or similar crashes, please check again that all steps of installation ran successfully. If you cannot resolve any issues with installation, please see our README and 'Bug Report' Git Issue template for advice on posting Git Issues to get help quickly - you must include the full installation logs in your issue so that we can help debug.
-```
+```bash
mkdir outputs
# Generate a scene layout
@@ -40,7 +40,7 @@ Output logs should indicate what the code is working on. Use `--debug` for even
We provide `infinigen/datagen/manage_jobs.py`, a utility which runs similar steps automatically.
-```
+```bash
python -m infinigen.datagen.manage_jobs --output_folder outputs/hello_world --num_scenes 1 --specific_seed 0 \
--configs desert.gin simple.gin --pipeline_configs local_16GB.gin monocular.gin blender_gt.gin --pipeline_overrides LocalScheduleHandler.use_gpu=False
```
diff --git a/infinigen/assets/scatters/monocot.py b/infinigen/assets/scatters/monocots.py
similarity index 100%
rename from infinigen/assets/scatters/monocot.py
rename to infinigen/assets/scatters/monocots.py
diff --git a/infinigen/core/execute_tasks.py b/infinigen/core/execute_tasks.py
index 4a39d8a05..e6a6214b8 100644
--- a/infinigen/core/execute_tasks.py
+++ b/infinigen/core/execute_tasks.py
@@ -6,6 +6,7 @@
import pickle
import shutil
import time
+import typing
from collections import defaultdict
from pathlib import Path
@@ -16,257 +17,24 @@
import bpy
import gin
from frozendict import frozendict
-from numpy.random import uniform
import infinigen.assets.scatters
-from infinigen.assets import fluid
-from infinigen.assets.objects import cactus, cloud, creatures, monocot, rocks, trees
-from infinigen.assets.scatters import (
- ground_mushroom,
- ivy,
- lichen,
- moss,
- slime_mold,
- snow_layer,
-)
-from infinigen.assets.scatters.utils.selection import scatter_lower, scatter_upward
from infinigen.core import init, surface
from infinigen.core.placement import camera as cam_util
-from infinigen.core.placement import placement
from infinigen.core.rendering.render import render_image
from infinigen.core.rendering.resample import resample_scene
from infinigen.core.tagging import tag_system
from infinigen.core.util import blender as butil
from infinigen.core.util import exporting
from infinigen.core.util.logging import Timer, create_text_file, save_polycounts
-from infinigen.core.util.math import FixedSeed, int_hash
+from infinigen.core.util.math import int_hash
from infinigen.core.util.organization import Task
-from infinigen.core.util.pipeline import RandomStageExecutor
from infinigen.terrain import Terrain
from infinigen.tools.export import export_scene, triangulate_meshes
logger = logging.getLogger(__name__)
-@gin.configurable
-def populate_scene(output_folder, scene_seed, **params):
- p = RandomStageExecutor(scene_seed, output_folder, params)
- camera = [cam_util.get_camera(i, j) for i, j in cam_util.get_cameras_ids()]
-
- season = p.run_stage(
- "choose_season", trees.random_season, use_chance=False, default=[]
- )
-
- fire_cache_system = fluid.FireCachingSystem() if params.get("cached_fire") else None
-
- populated = {}
- populated["trees"] = p.run_stage(
- "populate_trees",
- use_chance=False,
- default=[],
- fn=lambda: placement.populate_all(
- trees.TreeFactory, camera, season=season, vis_cull=4
- ),
- ) # ,
- # meshing_camera=camera, adapt_mesh_method='subdivide', cam_meshing_max_dist=8))
- populated["boulders"] = p.run_stage(
- "populate_boulders",
- use_chance=False,
- default=[],
- fn=lambda: placement.populate_all(rocks.BoulderFactory, camera, vis_cull=3),
- ) # ,
- # meshing_camera=camera, adapt_mesh_method='subdivide', cam_meshing_max_dist=8))
- populated["bushes"] = p.run_stage(
- "populate_bushes",
- use_chance=False,
- fn=lambda: placement.populate_all(
- trees.BushFactory, camera, vis_cull=1, adapt_mesh_method="subdivide"
- ),
- )
- p.run_stage(
- "populate_kelp",
- use_chance=False,
- fn=lambda: placement.populate_all(
- monocot.KelpMonocotFactory, camera, vis_cull=5
- ),
- )
- populated["cactus"] = p.run_stage(
- "populate_cactus",
- use_chance=False,
- fn=lambda: placement.populate_all(cactus.CactusFactory, camera, vis_cull=6),
- )
- p.run_stage(
- "populate_clouds",
- use_chance=False,
- fn=lambda: placement.populate_all(
- cloud.CloudFactory, camera, dist_cull=None, vis_cull=None
- ),
- )
- p.run_stage(
- "populate_glowing_rocks",
- use_chance=False,
- fn=lambda: placement.populate_all(
- rocks.GlowingRocksFactory, camera, dist_cull=None, vis_cull=None
- ),
- )
-
- populated["cached_fire_trees"] = p.run_stage(
- "populate_cached_fire_trees",
- use_chance=False,
- default=[],
- fn=lambda: placement.populate_all(
- fluid.CachedTreeFactory,
- camera,
- season=season,
- vis_cull=4,
- dist_cull=70,
- cache_system=fire_cache_system,
- ),
- )
- populated["cached_fire_boulders"] = p.run_stage(
- "populate_cached_fire_boulders",
- use_chance=False,
- default=[],
- fn=lambda: placement.populate_all(
- fluid.CachedBoulderFactory,
- camera,
- vis_cull=3,
- dist_cull=70,
- cache_system=fire_cache_system,
- ),
- )
- populated["cached_fire_bushes"] = p.run_stage(
- "populate_cached_fire_bushes",
- use_chance=False,
- fn=lambda: placement.populate_all(
- fluid.CachedBushFactory,
- camera,
- vis_cull=1,
- adapt_mesh_method="subdivide",
- cache_system=fire_cache_system,
- ),
- )
- populated["cached_fire_cactus"] = p.run_stage(
- "populate_cached_fire_cactus",
- use_chance=False,
- fn=lambda: placement.populate_all(
- fluid.CachedCactusFactory,
- camera,
- vis_cull=6,
- cache_system=fire_cache_system,
- ),
- )
-
- grime_selection_funcs = {
- "trees": scatter_lower,
- "boulders": scatter_upward,
- }
- grime_types = {
- "slime_mold": slime_mold.SlimeMold,
- "lichen": lichen.Lichen,
- "ivy": ivy.Ivy,
- "mushroom": ground_mushroom.Mushrooms,
- "moss": moss.MossCover,
- }
-
- def apply_grime(grime_type, surface_cls):
- surface_fac = surface_cls()
- for (
- target_type,
- results,
- ) in populated.items():
- selection_func = grime_selection_funcs.get(target_type, None)
- for fac_seed, fac_pholders, fac_assets in results:
- if len(fac_pholders) == 0:
- continue
- for inst_seed, obj in fac_assets:
- with FixedSeed(int_hash((grime_type, fac_seed, inst_seed))):
- p_k = f"{grime_type}_on_{target_type}_per_instance_chance"
- if uniform() > params.get(p_k, 0.4):
- continue
- logger.debug(f"Applying {surface_fac} on {obj}")
- surface_fac.apply(obj, selection=selection_func)
-
- for grime_type, surface_cls in grime_types.items():
- p.run_stage(grime_type, lambda: apply_grime(grime_type, surface_cls))
-
- def apply_snow_layer(surface_cls):
- surface_fac = surface_cls()
- for (
- target_type,
- results,
- ) in populated.items():
- selection_func = grime_selection_funcs.get(target_type, None)
- for fac_seed, fac_pholders, fac_assets in results:
- if len(fac_pholders) == 0:
- continue
- for inst_seed, obj in fac_assets:
- tmp = obj.users_collection[0].hide_viewport
- obj.users_collection[0].hide_viewport = False
- surface_fac.apply(obj, selection=selection_func)
- obj.users_collection[0].hide_viewport = tmp
-
- p.run_stage("snow_layer", lambda: apply_snow_layer(snow_layer.Snowlayer))
-
- creature_facs = {
- "beetles": creatures.BeetleFactory,
- "bird": creatures.BirdFactory,
- "carnivore": creatures.CarnivoreFactory,
- "crab": creatures.CrabFactory,
- "crustacean": creatures.CrustaceanFactory,
- "dragonfly": creatures.DragonflyFactory,
- "fish": creatures.FishFactory,
- "flyingbird": creatures.FlyingBirdFactory,
- "herbivore": creatures.HerbivoreFactory,
- "snake": creatures.SnakeFactory,
- }
- for k, fac in creature_facs.items():
- p.run_stage(
- f"populate_{k}",
- use_chance=False,
- fn=lambda: placement.populate_all(fac, camera=None),
- )
-
- fire_warmup = params.get("fire_warmup", 50)
- simulation_duration = (
- bpy.context.scene.frame_end - bpy.context.scene.frame_start + fire_warmup
- )
-
- def set_fire(assets):
- objs = [o for *_, a in assets for _, o in a]
- with butil.EnableParentCollections(objs):
- fluid.set_fire_to_assets(
- assets,
- bpy.context.scene.frame_start - fire_warmup,
- simulation_duration,
- output_folder,
- )
-
- p.run_stage(
- "trees_fire_on_the_fly", set_fire, populated["trees"], prereq="populate_trees"
- )
- p.run_stage(
- "bushes_fire_on_the_fly",
- set_fire,
- populated["bushes"],
- prereq="populate_bushes",
- )
- p.run_stage(
- "boulders_fire_on_the_fly",
- set_fire,
- populated["boulders"],
- prereq="populate_boulders",
- )
- p.run_stage(
- "cactus_fire_on_the_fly",
- set_fire,
- populated["cactus"],
- prereq="populate_cactus",
- )
-
- p.save_results(output_folder / "pipeline_fine.csv")
-
-
def get_scene_tag(name):
try:
o = next(o for o in bpy.data.objects if o.name.startswith(f"{name}="))
@@ -360,17 +128,18 @@ def group_collections(config):
@gin.configurable
def execute_tasks(
- compose_scene_func,
- input_folder,
- output_folder,
- task,
- scene_seed,
- frame_range,
- camera_id,
- resample_idx=None,
- output_blend_name="scene.blend",
+ compose_scene_func: typing.Callable,
+ populate_scene_func: typing.Callable,
+ input_folder: Path,
+ output_folder: Path,
+ task: str,
+ scene_seed: int,
+ frame_range: tuple[int],
+ camera_id: tuple[int],
+ resample_idx: int = None,
+ output_blend_name: str = "scene.blend",
generate_resolution=(1280, 720),
- fps=24,
+ fps: int = 24,
reset_assets=True,
dryrun=False,
optimize_terrain_diskusage=False,
@@ -432,8 +201,8 @@ def execute_tasks(
group_collections()
- if Task.Populate in task:
- populate_scene(output_folder, scene_seed)
+ if Task.Populate in task and populate_scene_func is not None:
+ populate_scene_func(output_folder, scene_seed)
need_terrain_processing = "OpaqueTerrain" in bpy.data.objects
diff --git a/infinigen/core/rendering/render.py b/infinigen/core/rendering/render.py
index 3d224db8e..9e5fdec6f 100644
--- a/infinigen/core/rendering/render.py
+++ b/infinigen/core/rendering/render.py
@@ -269,6 +269,7 @@ def postprocess_blendergt_outputs(frames_folder, output_stem):
if flow_color is not None:
imwrite(
flow_dst_path.with_name(f"Flow{output_stem}.png"),
+ flow_color,
)
flow_dst_path.unlink()
diff --git a/infinigen/datagen/manage_jobs.py b/infinigen/datagen/manage_jobs.py
index da067c540..0890fd925 100644
--- a/infinigen/datagen/manage_jobs.py
+++ b/infinigen/datagen/manage_jobs.py
@@ -745,13 +745,10 @@ def main(args, shuffle=True, wandb_project="render", upload_commandfile_method=N
]
if __name__ == "__main__":
- os.umask(0o007)
-
slurm_available = which("sbatch") is not None
- parser = (
- argparse.ArgumentParser()
- ) # to guarantee that the render scenes finish, try render_image.time_limit=2000
- parser.add_argument("-o", "--output_folder", type=Path, required=True)
+ parser = argparse.ArgumentParser()
+
+ parser.add_argument("-o", "--output_folder", type=Path, default=None) #
parser.add_argument(
"--num_scenes",
type=int,
@@ -859,12 +856,22 @@ def main(args, shuffle=True, wandb_project="render", upload_commandfile_method=N
assert args.specific_seed is None or args.num_scenes == 1
+ if args.output_folder is None:
+ date_str = datetime.now().strftime("%y-%m-%d_%H-%M")
+ hostname = os.uname().nodename
+
+ output_base = Path("outputs")
+ assert output_base.exists(), output_base
+
+ args.output_folder = Path(f"outputs/{date_str}_{hostname}")
+
overwrite_ok = args.use_existing or args.overwrite
if args.output_folder.exists() and not overwrite_ok:
raise FileExistsError(
f"--output_folder {args.output_folder} already exists! Please delete it,"
" specify a different --output_folder, or use --overwrite"
)
+
args.output_folder.mkdir(parents=True, exist_ok=overwrite_ok)
if args.meta_seed is not None:
diff --git a/infinigen_examples/generate_indoors.py b/infinigen_examples/generate_indoors.py
index d00ce6499..a557f4232 100644
--- a/infinigen_examples/generate_indoors.py
+++ b/infinigen_examples/generate_indoors.py
@@ -477,6 +477,7 @@ def main(args):
execute_tasks.main(
compose_scene_func=compose_indoors,
+ populate_scene_func=None,
input_folder=args.input_folder,
output_folder=args.output_folder,
task=args.task,
diff --git a/infinigen_examples/generate_nature.py b/infinigen_examples/generate_nature.py
index a7254cdea..e1b164060 100644
--- a/infinigen_examples/generate_nature.py
+++ b/infinigen_examples/generate_nature.py
@@ -21,10 +21,9 @@
level=logging.INFO,
)
-from infinigen.assets import fluid, lighting, weather
-
# unused imports required for gin to find modules currently, # TODO remove
# ruff: noqa: F401
+from infinigen.assets import fluid, lighting, weather
from infinigen.assets.materials import (
atmosphere_light_haze,
chunkyrock,
@@ -62,35 +61,34 @@
ground_leaves,
ground_mushroom,
ground_twigs,
+ ivy,
jellyfish,
+ lichen,
+ monocots,
+ moss,
pebbles,
pine_needle,
pinecone,
seashells,
seaweed,
+ slime_mold,
+ snow_layer,
urchin,
)
-from infinigen.assets.scatters import monocot as monocots
+from infinigen.assets.scatters.utils.selection import scatter_lower, scatter_upward
from infinigen.core import execute_tasks, init, surface
from infinigen.core.placement import camera as cam_util
-from infinigen.core.placement import (
- density,
- placement,
- split_in_view,
-)
+from infinigen.core.placement import density, placement, split_in_view
from infinigen.core.util import blender as butil
from infinigen.core.util import logging as logging_util
from infinigen.core.util import pipeline
-from infinigen.core.util.math import int_hash
-from infinigen.core.util.organization import Tags
+from infinigen.core.util.math import FixedSeed, int_hash
+from infinigen.core.util.organization import Tags, Task
+from infinigen.core.util.pipeline import RandomStageExecutor
from infinigen.core.util.random import random_general, sample_registry
from infinigen.terrain import Terrain
-logging.basicConfig(
- format="[%(asctime)s.%(msecs)03d] [%(name)s] [%(levelname)s] | %(message)s",
- datefmt="%H:%M:%S",
- level=logging.WARNING,
-)
+logger = logging.getLogger(__name__)
@gin.configurable
@@ -729,6 +727,225 @@ def add_tilted_river():
}
+@gin.configurable
+def populate_scene(output_folder, scene_seed, **params):
+ p = RandomStageExecutor(scene_seed, output_folder, params)
+ camera = [cam_util.get_camera(i, j) for i, j in cam_util.get_cameras_ids()]
+
+ season = p.run_stage(
+ "choose_season", trees.random_season, use_chance=False, default=[]
+ )
+
+ fire_cache_system = fluid.FireCachingSystem() if params.get("cached_fire") else None
+
+ populated = {}
+ populated["trees"] = p.run_stage(
+ "populate_trees",
+ use_chance=False,
+ default=[],
+ fn=lambda: placement.populate_all(
+ trees.TreeFactory, camera, season=season, vis_cull=4
+ ),
+ ) # ,
+ # meshing_camera=camera, adapt_mesh_method='subdivide', cam_meshing_max_dist=8))
+ populated["boulders"] = p.run_stage(
+ "populate_boulders",
+ use_chance=False,
+ default=[],
+ fn=lambda: placement.populate_all(rocks.BoulderFactory, camera, vis_cull=3),
+ ) # ,
+ # meshing_camera=camera, adapt_mesh_method='subdivide', cam_meshing_max_dist=8))
+ populated["bushes"] = p.run_stage(
+ "populate_bushes",
+ use_chance=False,
+ fn=lambda: placement.populate_all(
+ trees.BushFactory, camera, vis_cull=1, adapt_mesh_method="subdivide"
+ ),
+ )
+ p.run_stage(
+ "populate_kelp",
+ use_chance=False,
+ fn=lambda: placement.populate_all(
+ monocot.KelpMonocotFactory, camera, vis_cull=5
+ ),
+ )
+ populated["cactus"] = p.run_stage(
+ "populate_cactus",
+ use_chance=False,
+ fn=lambda: placement.populate_all(cactus.CactusFactory, camera, vis_cull=6),
+ )
+ p.run_stage(
+ "populate_clouds",
+ use_chance=False,
+ fn=lambda: placement.populate_all(
+ cloud.CloudFactory, camera, dist_cull=None, vis_cull=None
+ ),
+ )
+ p.run_stage(
+ "populate_glowing_rocks",
+ use_chance=False,
+ fn=lambda: placement.populate_all(
+ rocks.GlowingRocksFactory, camera, dist_cull=None, vis_cull=None
+ ),
+ )
+
+ populated["cached_fire_trees"] = p.run_stage(
+ "populate_cached_fire_trees",
+ use_chance=False,
+ default=[],
+ fn=lambda: placement.populate_all(
+ fluid.CachedTreeFactory,
+ camera,
+ season=season,
+ vis_cull=4,
+ dist_cull=70,
+ cache_system=fire_cache_system,
+ ),
+ )
+ populated["cached_fire_boulders"] = p.run_stage(
+ "populate_cached_fire_boulders",
+ use_chance=False,
+ default=[],
+ fn=lambda: placement.populate_all(
+ fluid.CachedBoulderFactory,
+ camera,
+ vis_cull=3,
+ dist_cull=70,
+ cache_system=fire_cache_system,
+ ),
+ )
+ populated["cached_fire_bushes"] = p.run_stage(
+ "populate_cached_fire_bushes",
+ use_chance=False,
+ fn=lambda: placement.populate_all(
+ fluid.CachedBushFactory,
+ camera,
+ vis_cull=1,
+ adapt_mesh_method="subdivide",
+ cache_system=fire_cache_system,
+ ),
+ )
+ populated["cached_fire_cactus"] = p.run_stage(
+ "populate_cached_fire_cactus",
+ use_chance=False,
+ fn=lambda: placement.populate_all(
+ fluid.CachedCactusFactory,
+ camera,
+ vis_cull=6,
+ cache_system=fire_cache_system,
+ ),
+ )
+
+ grime_selection_funcs = {
+ "trees": scatter_lower,
+ "boulders": scatter_upward,
+ }
+ grime_types = {
+ "slime_mold": slime_mold.SlimeMold,
+ "lichen": lichen.Lichen,
+ "ivy": ivy.Ivy,
+ "mushroom": ground_mushroom.Mushrooms,
+ "moss": moss.MossCover,
+ }
+
+ def apply_grime(grime_type, surface_cls):
+ surface_fac = surface_cls()
+ for (
+ target_type,
+ results,
+ ) in populated.items():
+ selection_func = grime_selection_funcs.get(target_type, None)
+ for fac_seed, fac_pholders, fac_assets in results:
+ if len(fac_pholders) == 0:
+ continue
+ for inst_seed, obj in fac_assets:
+ with FixedSeed(int_hash((grime_type, fac_seed, inst_seed))):
+ p_k = f"{grime_type}_on_{target_type}_per_instance_chance"
+ if uniform() > params.get(p_k, 0.4):
+ continue
+ logger.debug("Applying {surface_fac} on {obj}")
+ surface_fac.apply(obj, selection=selection_func)
+
+ for grime_type, surface_cls in grime_types.items():
+ p.run_stage(grime_type, lambda: apply_grime(grime_type, surface_cls))
+
+ def apply_snow_layer(surface_cls):
+ surface_fac = surface_cls()
+ for (
+ target_type,
+ results,
+ ) in populated.items():
+ selection_func = grime_selection_funcs.get(target_type, None)
+ for fac_seed, fac_pholders, fac_assets in results:
+ if len(fac_pholders) == 0:
+ continue
+ for inst_seed, obj in fac_assets:
+ tmp = obj.users_collection[0].hide_viewport
+ obj.users_collection[0].hide_viewport = False
+ surface_fac.apply(obj, selection=selection_func)
+ obj.users_collection[0].hide_viewport = tmp
+
+ p.run_stage("snow_layer", lambda: apply_snow_layer(snow_layer.Snowlayer))
+
+ creature_facs = {
+ "beetles": creatures.BeetleFactory,
+ "bird": creatures.BirdFactory,
+ "carnivore": creatures.CarnivoreFactory,
+ "crab": creatures.CrabFactory,
+ "crustacean": creatures.CrustaceanFactory,
+ "dragonfly": creatures.DragonflyFactory,
+ "fish": creatures.FishFactory,
+ "flyingbird": creatures.FlyingBirdFactory,
+ "herbivore": creatures.HerbivoreFactory,
+ "snake": creatures.SnakeFactory,
+ }
+ for k, fac in creature_facs.items():
+ p.run_stage(
+ f"populate_{k}",
+ use_chance=False,
+ fn=lambda: placement.populate_all(fac, camera=None),
+ )
+
+ fire_warmup = params.get("fire_warmup", 50)
+ simulation_duration = (
+ bpy.context.scene.frame_end - bpy.context.scene.frame_start + fire_warmup
+ )
+
+ def set_fire(assets):
+ objs = [o for *_, a in assets for _, o in a]
+ with butil.EnableParentCollections(objs):
+ fluid.set_fire_to_assets(
+ assets,
+ bpy.context.scene.frame_start - fire_warmup,
+ simulation_duration,
+ output_folder,
+ )
+
+ p.run_stage(
+ "trees_fire_on_the_fly", set_fire, populated["trees"], prereq="populate_trees"
+ )
+ p.run_stage(
+ "bushes_fire_on_the_fly",
+ set_fire,
+ populated["bushes"],
+ prereq="populate_bushes",
+ )
+ p.run_stage(
+ "boulders_fire_on_the_fly",
+ set_fire,
+ populated["boulders"],
+ prereq="populate_boulders",
+ )
+ p.run_stage(
+ "cactus_fire_on_the_fly",
+ set_fire,
+ populated["cactus"],
+ prereq="populate_cactus",
+ )
+
+ p.save_results(output_folder / "pipeline_fine.csv")
+
+
def main(args):
scene_seed = init.apply_scene_seed(args.seed)
mandatory_exclusive = [Path("infinigen_examples/configs_nature/scene_types")]
@@ -742,6 +959,7 @@ def main(args):
execute_tasks.main(
compose_scene_func=compose_nature,
+ populate_scene_func=populate_scene,
input_folder=args.input_folder,
output_folder=args.output_folder,
task=args.task,
diff --git a/tests/core/test_execute_tasks.py b/tests/core/test_execute_tasks.py
index 9be464fac..0d36d2789 100644
--- a/tests/core/test_execute_tasks.py
+++ b/tests/core/test_execute_tasks.py
@@ -25,6 +25,7 @@ def compose_cube(output_folder, scene_seed, **params):
execute_tasks.execute_tasks(
compose_cube,
+ populate_scene_func=None,
input_folder=None,
output_folder=output,
task="coarse populate",