From fcd7fc265e5a7c25b56e431e4ed57c3b5320fb42 Mon Sep 17 00:00:00 2001 From: Zeyu Ma Date: Tue, 12 Dec 2023 14:35:23 -0500 Subject: [PATCH] Integrate OcMesher --- .gitmodules | 3 + docs/CHANGELOG.md | 3 + docs/ConfiguringInfinigen.md | 11 +- infinigen/OcMesher | 1 + infinigen/__init__.py | 2 +- infinigen/core/execute_tasks.py | 2 +- infinigen/core/nodes/node_info.py | 2 + infinigen/core/rendering/render.py | 7 +- infinigen/core/util/blender.py | 7 +- .../data_schema/block_terrain_experiment.gin | 10 ++ .../configs/data_schema/monocular_video.gin | 9 +- infinigen/datagen/job_funcs.py | 3 +- infinigen/datagen/manage_jobs.py | 4 +- .../terrain/assets/landtiles/ant_landscape.py | 4 +- infinigen/terrain/assets/landtiles/custom.py | 2 + infinigen/terrain/core.py | 68 ++++++--- infinigen/terrain/elements/core.py | 15 +- infinigen/terrain/elements/landtiles.py | 4 +- infinigen/terrain/elements/mountains.py | 3 +- infinigen/terrain/land_process/erosion.py | 12 +- infinigen/terrain/mesher/spherical_mesher.py | 22 +-- .../source/common/elements/landtiles.h | 9 +- .../source/cpu/soil_machine/SoilMachine.cpp | 8 +- .../cpu/soil_machine/particle/particle.h | 9 +- .../source/cpu/soil_machine/particle/water.h | 42 +++--- .../source/cpu/soil_machine/particle/wind.h | 6 +- infinigen/terrain/utils/__init__.py | 2 +- infinigen/terrain/utils/camera.py | 47 ++++--- infinigen/terrain/utils/mesh.py | 3 + infinigen/terrain/utils/random.py | 5 + .../tools/terrain/generate_terrain_assets.py | 3 - infinigen/tools/terrain/landtile_viewer.py | 5 + .../configs/{ => extras}/experimental.gin | 0 .../configs/{ => extras}/stereo_training.gin | 0 .../configs/{ => extras}/use_cached_fire.gin | 0 .../{ => extras}/use_on_the_fly_fire.gin | 0 .../performance/fast_terrain_assets.gin | 6 +- .../performance/high_quality_terrain.gin | 1 + .../configs/scene_types/cave.gin | 2 +- infinigen_examples/configs/video.gin | 1 + install.sh | 132 ------------------ pyproject.toml | 3 +- scripts/install/compile_terrain.sh | 4 + worldgen/assets/leaves/__init__.py | 7 - worldgen/config/performance/simple.gin | 6 - 45 files changed, 228 insertions(+), 267 deletions(-) create mode 160000 infinigen/OcMesher create mode 100644 infinigen/datagen/configs/data_schema/block_terrain_experiment.gin rename infinigen_examples/configs/{ => extras}/experimental.gin (100%) rename infinigen_examples/configs/{ => extras}/stereo_training.gin (100%) rename infinigen_examples/configs/{ => extras}/use_cached_fire.gin (100%) rename infinigen_examples/configs/{ => extras}/use_on_the_fly_fire.gin (100%) create mode 100644 infinigen_examples/configs/video.gin delete mode 100755 install.sh delete mode 100644 worldgen/assets/leaves/__init__.py delete mode 100644 worldgen/config/performance/simple.gin diff --git a/.gitmodules b/.gitmodules index 07c7c7370..ecb55ae45 100644 --- a/.gitmodules +++ b/.gitmodules @@ -31,3 +31,6 @@ [submodule "infinigen/datagen/customgt/dependencies/glfw"] path = infinigen/datagen/customgt/dependencies/glfw url = https://github.com/glfw/glfw.git +[submodule "infinigen/OcMesher"] + path = infinigen/OcMesher + url = git@github.com:princeton-vl/OcMesher.git diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 4ff957e77..c398593fc 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -20,3 +20,6 @@ v1.1.0 - Update to blender 3.6, install blender either via pip or standalone - Restructure project into an `infinigen` python package and `infinigen_examples` directory - Add unit tests + +v1.2.0 +- Integrate OcMesher terrain option - see https://github.com/princeton-vl/OcMesher \ No newline at end of file diff --git a/docs/ConfiguringInfinigen.md b/docs/ConfiguringInfinigen.md index e232d4b3b..e739b1f58 100644 --- a/docs/ConfiguringInfinigen.md +++ b/docs/ConfiguringInfinigen.md @@ -103,7 +103,6 @@ If you have more than one GPU and are using a `local_*.gin` compute config, each Generating a video, stereo or other dataset typically requires more render jobs, so we must instruct `manage_jobs.py` to run those jobs. `datagen/configs/data_schema/` provides many options for you to use in your `--pipeline_configs`, including `monocular_video.gin` and `stereo.gin`.
These configs are typically mutually exclusive, and you must include at least one
-:exclamation: Our terrain system resolves its signed distance function (SDF) to view-specific meshes, which must be updated as the camera moves. For video rendering, we strongly recommend using the `high_quality_terrain` config to avoid perceptible flickering and temporal aliasing. This config meshes the SDF at very high detail, to create seamless video. However, it has high compute costs, so we recommend also using `--pipeline_config cuda_terrain` on a machine with an NVIDIA GPU. For applications with fast moving cameras, you may need to update the terrain mesh more frequently by decreasing `iterate_scene_tasks.view_block_size = 16`. To create longer videos, modify `iterate_scene_tasks.frame_range` in `monocular_video.gin` (note: we use 24fps video by default). `iterate_scene_tasks.view_block_size` controls how many frames will be grouped into each `fine_terrain` and render / ground-truth task. @@ -166,14 +165,14 @@ If you have any issues with these commands, or wish to customize them to your ne All commands below are shown with using `local_256GB` config, but you can attempt to swap this for any compute config as discussed in [Configuring available computing resources](#configuring-available-computing-resources). -#### Creating videos similar to the intro video +#### Creating high quality videos -Most videos in the "Introducing Infinigen" launch video were made using commands similar to the following: +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. ```` 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 high_quality_terrain + --cleanup big_files --warmup_sec 60000 --config video high_quality_terrain ```` #### Creating large-scale stereo datasets @@ -219,7 +218,7 @@ python -m infinigen.datagen.manage_jobs --output_folder outputs/my_videos --num_ ``` 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 high_quality_terrain \ + --cleanup big_files --warmup_sec 30000 --config video high_quality_terrain \ --overrides camera.camera_pose_proposal.altitude=["uniform", 20, 30] ``` @@ -229,7 +228,7 @@ python -m infinigen.datagen.manage_jobs --output_folder outputs/my_videos --num_ ``` 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 high_quality_terrain \ + --cleanup big_files --warmup_sec 30000 --config video high_quality_terrain \ --pipeline_overrides iterate_scene_tasks.frame_range=[1,25] ``` diff --git a/infinigen/OcMesher b/infinigen/OcMesher new file mode 160000 index 000000000..4e5fad7b0 --- /dev/null +++ b/infinigen/OcMesher @@ -0,0 +1 @@ +Subproject commit 4e5fad7b0dd495444acf3ab2037bf08dd4b5d676 diff --git a/infinigen/__init__.py b/infinigen/__init__.py index c898176f1..6e429ebd4 100644 --- a/infinigen/__init__.py +++ b/infinigen/__init__.py @@ -1,3 +1,3 @@ import logging -__version__ = "1.1.0" \ No newline at end of file +__version__ = "1.2.0" \ No newline at end of file diff --git a/infinigen/core/execute_tasks.py b/infinigen/core/execute_tasks.py index ff3c35e8d..f294ba4ad 100644 --- a/infinigen/core/execute_tasks.py +++ b/infinigen/core/execute_tasks.py @@ -342,7 +342,7 @@ def execute_tasks( group_collections() - if input_folder is not None: + if input_folder is not None and input_folder != output_folder: for mesh in os.listdir(input_folder): if (mesh.endswith(".glb") or mesh.endswith(".b_displacement.npy")) and not os.path.islink(output_folder / mesh): os.symlink(input_folder / mesh, output_folder / mesh) diff --git a/infinigen/core/nodes/node_info.py b/infinigen/core/nodes/node_info.py index f7b8ceb1b..d248d4df2 100644 --- a/infinigen/core/nodes/node_info.py +++ b/infinigen/core/nodes/node_info.py @@ -42,8 +42,10 @@ class Nodes: CombineHSV = 'ShaderNodeCombineHSV' SeparateRGB = 'ShaderNodeSeparateRGB' SeparateColor = 'ShaderNodeSeparateColor' + CompSeparateColor = 'CompositorNodeSeparateColor' CombineRGB = 'ShaderNodeCombineRGB' CombineColor = 'ShaderNodeCombineColor' + CompCombineColor = 'CompositorNodeCombineColor' #bl3.5 additions SeparateComponents = 'GeometryNodeSeparateComponents' diff --git a/infinigen/core/rendering/render.py b/infinigen/core/rendering/render.py index ebec75cbc..6416463ff 100644 --- a/infinigen/core/rendering/render.py +++ b/infinigen/core/rendering/render.py @@ -138,7 +138,12 @@ def configure_compositor_output(nw, frames_folder, image_denoised, image_noisy, setattr(viewlayer.cycles, f"use_pass_{viewlayer_pass}", True) slot_input = file_output_node.file_slots.new(socket_name) render_socket = render_layers.outputs[socket_name] - nw.links.new(render_socket, slot_input) + if viewlayer_pass == "vector": + separate_color = nw.new_node(Nodes.CompSeparateColor, [render_socket]) + comnbine_color = nw.new_node(Nodes.CompCombineColor, [0, (separate_color, 3), (separate_color, 2), 0]) + nw.links.new(comnbine_color.outputs[0], slot_input) + else: + nw.links.new(render_socket, slot_input) file_slot_list.append(file_output_node.file_slots[slot_input.name]) slot_input = file_output_node.file_slots['Image'] diff --git a/infinigen/core/util/blender.py b/infinigen/core/util/blender.py index c8f4a60a2..2e0fb568b 100644 --- a/infinigen/core/util/blender.py +++ b/infinigen/core/util/blender.py @@ -206,10 +206,11 @@ def __exit__(self, *_): def select_none(): - if bpy.context.active_object is not None: + if hasattr(bpy.context, "active_object") and bpy.context.active_object is not None: bpy.context.active_object.select_set(False) - for obj in bpy.context.selected_objects: - obj.select_set(False) + if hasattr(bpy.context, "selected_objects"): + for obj in bpy.context.selected_objects: + obj.select_set(False) def select(objs): diff --git a/infinigen/datagen/configs/data_schema/block_terrain_experiment.gin b/infinigen/datagen/configs/data_schema/block_terrain_experiment.gin new file mode 100644 index 000000000..140bd0bb6 --- /dev/null +++ b/infinigen/datagen/configs/data_schema/block_terrain_experiment.gin @@ -0,0 +1,10 @@ +iterate_scene_tasks.global_tasks = [ + {'name': 'coarse', 'func': @queue_coarse}, + {'name': "populate", 'func': @queue_populate}, + {'name': 'backuppopulate', 'func': @renderbackup/queue_populate, 'condition': 'prev_failed'}, +] +iterate_scene_tasks.view_dependent_tasks = [ + {'name': "fineterrain", 'func': @queue_fine_terrain}, +] + +queue_populate.input_prefix = "coarse" \ No newline at end of file diff --git a/infinigen/datagen/configs/data_schema/monocular_video.gin b/infinigen/datagen/configs/data_schema/monocular_video.gin index 8f8655862..05733762c 100644 --- a/infinigen/datagen/configs/data_schema/monocular_video.gin +++ b/infinigen/datagen/configs/data_schema/monocular_video.gin @@ -1,16 +1,15 @@ iterate_scene_tasks.frame_range = [1, 192] -iterate_scene_tasks.view_block_size = 8 +iterate_scene_tasks.view_block_size = 192 +iterate_scene_tasks.cam_block_size = 8 iterate_scene_tasks.cam_id_ranges = [1, 1] iterate_scene_tasks.global_tasks = [ {'name': 'coarse', 'func': @queue_coarse}, + {'name': "fineterrain", 'func': @queue_fine_terrain}, {'name': "populate", 'func': @queue_populate}, {'name': 'backuppopulate', 'func': @renderbackup/queue_populate, 'condition': 'prev_failed'}, - {'name': "fineterrain", 'func': @queue_fine_terrain}, -] -iterate_scene_tasks.view_dependent_tasks = [ - {'name': "fineterrain", 'func': @queue_fine_terrain}, ] +iterate_scene_tasks.view_dependent_tasks = [] iterate_scene_tasks.camera_dependent_tasks = [ {'name': 'shortrender', 'func': @rendershort/queue_render}, {'name': 'backuprender', 'func': @renderbackup/queue_render, 'condition': 'prev_failed'}, diff --git a/infinigen/datagen/job_funcs.py b/infinigen/datagen/job_funcs.py index d3d712d03..13984db48 100644 --- a/infinigen/datagen/job_funcs.py +++ b/infinigen/datagen/job_funcs.py @@ -121,6 +121,7 @@ def queue_populate( seed, configs, taskname=None, + input_prefix="fine", overrides=[], input_indices=None, output_indices=None, **kwargs, @@ -132,7 +133,7 @@ def queue_populate( input_suffix = get_suffix(input_indices) output_suffix = get_suffix(output_indices) - input_folder = folder/f'coarse{input_suffix}' + input_folder = folder/f'{input_prefix}{input_suffix}' output_folder = input_folder cmd = get_cmd(seed, 'populate', configs, taskname, diff --git a/infinigen/datagen/manage_jobs.py b/infinigen/datagen/manage_jobs.py index 2c4258ae3..888ddfb08 100644 --- a/infinigen/datagen/manage_jobs.py +++ b/infinigen/datagen/manage_jobs.py @@ -187,7 +187,9 @@ def init_db_from_existing(output_folder: Path): existing_db = pd.read_csv(db_path, converters={"configs": literal_eval}) def init_scene(seed_folder): - if not seed_folder.is_dir(): + if not seed_folder.is_symlink() and not seed_folder.is_dir(): + return None + if seed_folder.is_symlink() and not seed_folder.readlink().is_dir(): return None if not (seed_folder/'logs').exists(): logger.warning(f'Skipping {seed_folder=} due to missing "logs" subdirectory') diff --git a/infinigen/terrain/assets/landtiles/ant_landscape.py b/infinigen/terrain/assets/landtiles/ant_landscape.py index cc631cc54..e20f44316 100644 --- a/infinigen/terrain/assets/landtiles/ant_landscape.py +++ b/infinigen/terrain/assets/landtiles/ant_landscape.py @@ -13,7 +13,7 @@ from infinigen.terrain.land_process.erosion import run_erosion from infinigen.terrain.land_process.snowfall import run_snowfall -from infinigen.terrain.utils import smooth, random_int +from infinigen.terrain.utils import smooth, random_nat from infinigen.core.util.organization import AssetFile, LandTile @@ -23,7 +23,7 @@ def create( subdivision_y, ): def presets(**kwargs): - bpy.ops.mesh.landscape_add(ant_terrain_name="Landscape", land_material="", water_material="", texture_block="", at_cursor=True, smooth_mesh=True, tri_face=False, sphere_mesh=False, subdivision_x=subdivision_x, subdivision_y=subdivision_y, mesh_size=2, mesh_size_x=2, mesh_size_y=2, random_seed=max(0, random_int()), water_plane=False, water_level=0.01, remove_double=False, show_main_settings=True, show_noise_settings=True, show_displace_settings=True, refresh=True, auto_refresh=True, **kwargs) + bpy.ops.mesh.landscape_add(ant_terrain_name="Landscape", land_material="", water_material="", texture_block="", at_cursor=True, smooth_mesh=True, tri_face=False, sphere_mesh=False, subdivision_x=subdivision_x, subdivision_y=subdivision_y, mesh_size=2, mesh_size_x=2, mesh_size_y=2, random_seed=random_nat(), water_plane=False, water_level=0.01, remove_double=False, show_main_settings=True, show_noise_settings=True, show_displace_settings=True, refresh=True, auto_refresh=True, **kwargs) if preset_name == LandTile.Canyon: strata = np.random.randint(6, 12) diff --git a/infinigen/terrain/assets/landtiles/custom.py b/infinigen/terrain/assets/landtiles/custom.py index baab0f92c..46d43aefb 100644 --- a/infinigen/terrain/assets/landtiles/custom.py +++ b/infinigen/terrain/assets/landtiles/custom.py @@ -141,6 +141,7 @@ def multi_mountains_asset( coverage=params["coverage"], slope_freq=params["slope_freq"], slope_height=params["slope_height"], + is_asset=True, ) heightmap = mountains.get_heightmap(X, Y) mountains.cleanup() @@ -175,6 +176,7 @@ def coast_asset( coverage=params1["coverage"], slope_freq=params1["slope_freq"], slope_height=params1["slope_height"], + is_asset=True, ) heightmap = mountains.get_heightmap(X, Y) mountains.cleanup() diff --git a/infinigen/terrain/core.py b/infinigen/terrain/core.py index ad4b2571a..c16fcf5d6 100644 --- a/infinigen/terrain/core.py +++ b/infinigen/terrain/core.py @@ -12,16 +12,19 @@ import gin import numpy as np from mathutils.bvhtree import BVHTree + +from infinigen.OcMesher.ocmesher import OcMesher as UntexturedOcMesher from infinigen.terrain.mesher import OpaqueSphericalMesher, TransparentSphericalMesher, UniformMesher from infinigen.terrain.scene import scene, transfer_scene_info from infinigen.terrain.surface_kernel.core import SurfaceKernel -from infinigen.terrain.utils import Mesh, move_modifier, Vars, AttributeType, FieldsType +from infinigen.terrain.utils import Mesh, move_modifier, Vars, AttributeType, FieldsType, get_caminfo, write_attributes from infinigen.terrain.assets.ocean import ocean_asset from infinigen.core.util.blender import SelectObjects, delete from infinigen.core.util.logging import Timer from infinigen.core.util.math import FixedSeed, int_hash from infinigen.core.util.organization import SurfaceTypes, Attributes, Task, TerrainNames, ElementNames, Transparency, Materials, Assets, ElementTag, Tags, SelectionCriterions from infinigen.assets.utils.tag import tag_object, tag_system + from numpy import ascontiguousarray as AC logger = logging.getLogger(__name__) @@ -39,6 +42,36 @@ def get_surface_type(surface, degrade_sdf_to_displacement=True): return SurfaceTypes.Displacement return surface.type + +class OcMesher(UntexturedOcMesher): + def __init__(self, cameras, **kwargs): + UntexturedOcMesher.__init__(self, get_caminfo(cameras)[0], **kwargs) + + def __call__(self, kernels): + sdf_kernels = [(lambda x, k0=k: k0(x)[Vars.SDF]) for k in kernels] + meshes, in_view_tags = UntexturedOcMesher.__call__(self, sdf_kernels) + with Timer("compute attributes"): + write_attributes(kernels, None, meshes) + for mesh, tag in zip(meshes, in_view_tags): + mesh.vertex_attributes[Tags.OutOfView] = (~tag).astype(np.int32) + with Timer("concat meshes"): + mesh = Mesh.cat(meshes) + return mesh + +class CollectiveOcMesher(UntexturedOcMesher): + def __init__(self, cameras, **kwargs): + UntexturedOcMesher.__init__(self, get_caminfo(cameras)[0], **kwargs) + + def __call__(self, kernels): + sdf_kernels = [lambda x: np.stack([k(x)[Vars.SDF] for k in kernels], -1).min(axis=-1)] + mesh, in_view_tag = UntexturedOcMesher.__call__(self, sdf_kernels) + mesh = mesh[0] + with Timer("compute attributes"): + write_attributes(kernels, mesh, []) + mesh.vertex_attributes[Tags.OutOfView] = (~in_view_tag[0]).astype(np.int32) + mesh = Mesh(mesh=mesh) + return mesh + @gin.configurable class Terrain: def __init__( @@ -99,11 +132,10 @@ def cleanup(self): @gin.configurable("export") def export(self, - spherical=False, + dynamic=False, + spherical=True, # false for OcMesher cameras=None, main_terrain_only=False, - collective_transparent_overrides={}, - coarse_hidden=True, remove_redundant_attrs=True, ): meshes_dict = {} @@ -112,11 +144,9 @@ def export(self, opaque_elements = [element for element in self.elements_list if element.transparency == Transparency.Opaque] if opaque_elements != []: attributes_dict[TerrainNames.OpaqueTerrain] = set() - if spherical: - if coarse_hidden: - mesher = OpaqueSphericalMesher(cameras=cameras) - else: - mesher = TransparentSphericalMesher(cameras=cameras) + if dynamic: + if spherical: mesher = OpaqueSphericalMesher(cameras=cameras) + else: mesher = OcMesher(cameras=cameras) else: mesher = UniformMesher() with Timer(f"meshing {TerrainNames.OpaqueTerrain}"): @@ -128,12 +158,13 @@ def export(self, individual_transparent_elements = [element for element in self.elements_list if element.transparency == Transparency.IndividualTransparent] for element in individual_transparent_elements: if not main_terrain_only or element.__class__.name == self.main_terrain: - if spherical: + if dynamic: special_args = {} if element.__class__.name == ElementNames.Atmosphere: - special_args["coarse_multiplier"] = 64 - special_args["upscale"] = 1 - mesher = TransparentSphericalMesher(cameras=cameras, **special_args) + special_args["pixels_per_cube"] = 100 + special_args["inv_scale"] = 1 + if spherical: mesher = TransparentSphericalMesher(cameras=cameras, **special_args) + else: mesher = OcMesher(cameras=cameras, simplify_occluded=False, **special_args) else: mesher = UniformMesher(enclosed=True) with Timer(f"meshing {element.__class__.name}"): mesh = mesher([element]) @@ -144,8 +175,9 @@ def export(self, collective_transparent_elements = [element for element in self.elements_list if element.transparency == Transparency.CollectiveTransparent] if collective_transparent_elements != []: attributes_dict[TerrainNames.CollectiveTransparentTerrain] = set() - if spherical: - mesher = TransparentSphericalMesher(cameras=cameras, **collective_transparent_overrides) + if dynamic: + if spherical: mesher = TransparentSphericalMesher(cameras=cameras) + else: mesher = CollectiveOcMesher(cameras=cameras, simplify_occluded=False) else: mesher = UniformMesher() with Timer(f"meshing {TerrainNames.CollectiveTransparentTerrain}"): @@ -154,7 +186,7 @@ def export(self, for element in collective_transparent_elements: attributes_dict[TerrainNames.CollectiveTransparentTerrain].update(element.attributes) - if main_terrain_only or spherical: + if main_terrain_only or dynamic: for mesh_name in meshes_dict: mesh_name_unapplied = mesh_name if mesh_name + "_unapplied" in bpy.data.objects.keys(): @@ -173,7 +205,7 @@ def export(self, if get_surface_type(surface) == SurfaceTypes.BlenderDisplacement: meshes_dict[mesh_name].blender_displacements.append(surface.mod_name) - if spherical: + if dynamic: if remove_redundant_attrs: for mesh_name in meshes_dict: if len(attributes_dict[mesh_name]) == 1: @@ -263,7 +295,7 @@ def fine_terrain(self, output_folder, optimize_terrain_diskusage=True): with FixedSeed(int_hash(["Ocean", self.seed])): ocean_asset(output_folder / Assets.Ocean, bpy.context.scene.frame_start, bpy.context.scene.frame_end, link_folder=self.on_the_fly_asset_folder / Assets.Ocean) self.surfaces_into_sdf() - fine_meshes, _ = self.export(spherical=True, cameras=[bpy.context.scene.camera]) + fine_meshes, _ = self.export(dynamic=True, cameras=[bpy.context.scene.camera]) for mesh_name in fine_meshes: obj = fine_meshes[mesh_name].export_blender(mesh_name + "_fine") if mesh_name not in hidden_in_viewport: self.tag_terrain(obj) diff --git a/infinigen/terrain/elements/core.py b/infinigen/terrain/elements/core.py index 688d8f5e6..e9b3b8861 100644 --- a/infinigen/terrain/elements/core.py +++ b/infinigen/terrain/elements/core.py @@ -6,15 +6,18 @@ from ctypes import POINTER, c_float, c_int32, c_size_t +import gin import numpy as np from numpy import ascontiguousarray as AC from infinigen.terrain.utils import ASFLOAT, ASINT, Vars, load_cdll, register_func from infinigen.core.util.organization import Materials - +@gin.configurable class Element: called_time = {} - def __init__(self, lib_name, material, transparency): + def __init__(self, lib_name, material, transparency, bounding_shape=None, is_asset=False): + self.bounding_shape = bounding_shape + self.is_asset = is_asset if lib_name in Element.called_time: lib_name_X = f"{lib_name}_{Element.called_time[lib_name]}" print(f"{lib_name} already loaded, loading {lib_name_X} instead") @@ -76,6 +79,14 @@ def __call__(self, positions, sdf_only=False): else: auxs.append(None) self.call(N, ASFLOAT(AC(positions.astype(np.float32))), ASFLOAT(sdf), *[POINTER(c_float)() if x is None else ASFLOAT(x) for x in auxs]) + bounding_shape = self.bounding_shape + if not self.is_asset and bounding_shape is not None: + if bounding_shape[0] == "cube": + x_min, x_max, y_min, y_max, z_min, z_max = bounding_shape[1:] + out_bound = (positions[:, 0] < x_min) | (positions[:, 0] > x_max) \ + | (positions[:, 1] < y_min) | (positions[:, 1] > y_max) \ + | (positions[:, 2] < z_min) | (positions[:, 2] > z_max) + sdf[out_bound] = 1e6 ret = {} ret[Vars.SDF] = sdf diff --git a/infinigen/terrain/elements/landtiles.py b/infinigen/terrain/elements/landtiles.py index 4a53ed1e5..7c128b01f 100644 --- a/infinigen/terrain/elements/landtiles.py +++ b/infinigen/terrain/elements/landtiles.py @@ -53,6 +53,7 @@ def __init__( transparency=Transparency.Opaque, use_cblerp=False, smooth=False, + direction_deg=0, ): self.device = device self.on_the_fly_asset_folder = on_the_fly_asset_folder @@ -105,7 +106,8 @@ def __init__( randomness, frequency, attribute_probability, attribute_distance_range, island_probability, tile_size, none_to_0(height_modification_start), none_to_0(height_modification_end), none_to_0(attribute_modification_start_height), none_to_0(attribute_modification_end_height), - attribute_modification_distort_freq, attribute_modification_distort_mag, empty_below, y_tilt, y_tilt_clip, sharpen, mask_random_freq, + attribute_modification_distort_freq, attribute_modification_distort_mag, empty_below, y_tilt, y_tilt_clip, sharpen, + mask_random_freq, direction_deg, *tile_heights, ]), float_data)).astype(np.float32)) diff --git a/infinigen/terrain/elements/mountains.py b/infinigen/terrain/elements/mountains.py index 52992acdf..6ef567bfd 100644 --- a/infinigen/terrain/elements/mountains.py +++ b/infinigen/terrain/elements/mountains.py @@ -34,6 +34,7 @@ def __init__( slope_octaves=9, material=Materials.MountainCollection, transparency=Transparency.Opaque, + is_asset=False, ): self.device = device min_freq = rg(min_freq) @@ -57,5 +58,5 @@ def __init__( slope_freq, slope_octaves, slope_height, ], dtype=np.float32)) - Element.__init__(self, "mountains", material, transparency) + Element.__init__(self, "mountains", material, transparency, is_asset=is_asset) self.tag = ElementTag.Terrain \ No newline at end of file diff --git a/infinigen/terrain/land_process/erosion.py b/infinigen/terrain/land_process/erosion.py index 97ac3991d..712c39d97 100644 --- a/infinigen/terrain/land_process/erosion.py +++ b/infinigen/terrain/land_process/erosion.py @@ -20,18 +20,19 @@ def run_erosion( folder, Ns=[512, 2048], - n_iters = [int(1e4), int(5e5)], + n_iters=[int(1e4), int(5e5)], mask_height_range=None, spatial=1, mask_range=(4, 47), ground_depth=25, sinking_rate=0.05, + c_eq_factor=[1, 1], ): dll = load_cdll("terrain/lib/cpu/soil_machine/SoilMachine.so") func = dll.run func.argtypes = [ POINTER(c_float), POINTER(c_float), POINTER(c_float), - c_int32, c_int32, c_int32, c_int32, c_int32, c_float, c_char_p + c_int32, c_int32, c_int32, c_int32, c_int32, c_float, c_float, c_char_p ] func.restype = None @@ -46,14 +47,15 @@ def run_erosion( if N > M: heightmap = smooth(heightmap, 3) original_heightmap = heightmap.copy() ground_level = heightmap.min() - ground_depth - heightmap = AC((heightmap - ground_level).astype(np.float32)) + height_scale = 1 + heightmap = AC((heightmap - ground_level).astype(np.float32) * height_scale) result_heightmap = np.zeros_like(heightmap) watertrack = np.zeros_like(heightmap) func( ASFLOAT(heightmap), ASFLOAT(result_heightmap), ASFLOAT(watertrack), - N, N, 0, n_iter, 0, spatial * tile_size, str(soil_config_path).encode('utf-8'), + N, N, 0, n_iter, 0, spatial * tile_size, c_eq_factor[i], str(soil_config_path).encode('utf-8'), ) - heightmap = result_heightmap + ground_level + heightmap = result_heightmap / height_scale + ground_level watertrack = watertrack.reshape((N, N)) watertrack = np.clip((watertrack - mask_range[0]) / (mask_range[1] - mask_range[0]), a_min=0, a_max=1) watertrack = watertrack ** 0.2 diff --git a/infinigen/terrain/mesher/spherical_mesher.py b/infinigen/terrain/mesher/spherical_mesher.py index 80598b784..df666fe99 100644 --- a/infinigen/terrain/mesher/spherical_mesher.py +++ b/infinigen/terrain/mesher/spherical_mesher.py @@ -14,9 +14,8 @@ magnifier = 1e6 -# bounding_box for trailer use @gin.configurable -def kernel_caller(kernels, XYZ, r_bound_max=None, cam_loc=None, bounding_box=None): +def kernel_caller(kernels, XYZ, r_bound_max=None, cam_loc=None): sdfs = [] for kernel in kernels: ret = kernel(XYZ, sdf_only=1) @@ -25,12 +24,6 @@ def kernel_caller(kernels, XYZ, r_bound_max=None, cam_loc=None, bounding_box=Non R = np.linalg.norm(XYZ - cam_loc, axis=-1) mask = R / r_bound_max - 1 sdf = np.maximum(sdf, mask * magnifier) - if bounding_box is not None: - x_min, x_max, y_min, y_max, z_min, z_max = bounding_box - out_bound = (XYZ[:, 0] < x_min) | (XYZ[:, 0] > x_max) \ - | (XYZ[:, 1] < y_min) | (XYZ[:, 1] > y_max) \ - | (XYZ[:, 2] < z_min) | (XYZ[:, 2] > z_max) - sdf[out_bound] = 1e6 sdfs.append(sdf) ret = np.stack(sdfs, -1) return ret @@ -43,7 +36,7 @@ def __init__(self, r_max=1e3, complete_depth_test=True, ): - self.cam_pose, _, self.fov, self.H, self.W, _ = get_caminfo(cameras) + _, self.cam_pose, self.fov, self.H, self.W, _ = get_caminfo(cameras) assert self.fov[0] < np.pi / 2 and self.fov[1] < np.pi / 2, "the algorithm does not support larger-than-90-degree fov yet" self.r_min = r_min self.r_max = r_max @@ -120,20 +113,19 @@ def __init__(self, base_90d_resolution=None, pixels_per_cube=1.84, test_downscale=5, - upscale=8, + inv_scale=8, r_lengthen=3, - coarse_multiplier=1, camera_annotation_frames=None, ): SphericalMesher.__init__(self, cameras) self.cameras = cameras self.camera_annotation_frames = camera_annotation_frames assert bool(base_90d_resolution is None) ^ bool(pixels_per_cube is None) - if base_90d_resolution is None: base_90d_resolution = int(1 / (pixels_per_cube * upscale * self.fov[0] / np.pi * 2 / self.H)) - base_90d_resolution = base_90d_resolution // coarse_multiplier // test_downscale * test_downscale + if base_90d_resolution is None: base_90d_resolution = int(1 / (pixels_per_cube * inv_scale * self.fov[0] / np.pi * 2 / self.H)) + base_90d_resolution = base_90d_resolution // test_downscale * test_downscale base_R = int((np.log(self.r_max) - np.log(self.r_min)) / (np.pi/2 / base_90d_resolution) / r_lengthen) - print(f"In view mesh angle resolution 90d/{base_90d_resolution * upscale}, about {base_90d_resolution * upscale * self.fov[0] / np.pi * 2 / self.H: .2f} marching cube per pixel") + print(f"In view mesh angle resolution 90d/{base_90d_resolution * inv_scale}, about {base_90d_resolution * inv_scale * self.fov[0] / np.pi * 2 / self.H: .2f} marching cube per pixel") print(f"Out view mesh angle resolution 90d/{base_90d_resolution}, about {base_90d_resolution * self.fov[0] / np.pi * 2 / self.H: .2f} marching cube per pixel") fov = self.fov @@ -147,7 +139,7 @@ def __init__(self, base_90d_resolution, base_R, test_downscale=test_downscale, - inview_upscale=upscale, + inview_upscale=inv_scale, H_fov=rounded_fov[0], W_fov=rounded_fov[1], N0=N0, N1=N1, complete_depth_test=self.complete_depth_test, diff --git a/infinigen/terrain/source/common/elements/landtiles.h b/infinigen/terrain/source/common/elements/landtiles.h index 0331e686e..bed726ffa 100644 --- a/infinigen/terrain/source/common/elements/landtiles.h +++ b/infinigen/terrain/source/common/elements/landtiles.h @@ -55,7 +55,8 @@ DEVICE_FUNC void landtiles( float y_tilt_clip = f_params[14]; float sharpen = f_params[15]; float mask_random_freq = f_params[16]; - const int f_offset = 17; + float direction_deg = f_params[17]; + const int f_offset = 18; float *tile_heights = f_params + f_offset; float *heightmap = f_params + f_offset + len_tiles; @@ -63,7 +64,11 @@ DEVICE_FUNC void landtiles( float *coast_direction = f_params + f_offset + len_tiles + \ len_tiles * n_instances * N * N + intrinsic_auxiliaries * len_tiles * n_instances * N * N; - + direction_deg = 90 - direction_deg; + float px = position.x; + position.x = position.x * cos(direction_deg / 180 * acosf(-1.0)) - position.y * sin(direction_deg / 180 * acosf(-1.0)); + position.y = position.y * cos(direction_deg / 180 * acosf(-1.0)) + px * sin(direction_deg / 180 * acosf(-1.0)); + const int n_neighbors = 8; float heights_i0, height_grad_i0, covers_i0[intrinsic_auxiliaries]; for (int i = 0; i < n_lattice; i++) { diff --git a/infinigen/terrain/source/cpu/soil_machine/SoilMachine.cpp b/infinigen/terrain/source/cpu/soil_machine/SoilMachine.cpp index 10f77a2f6..db8d6a06b 100644 --- a/infinigen/terrain/source/cpu/soil_machine/SoilMachine.cpp +++ b/infinigen/terrain/source/cpu/soil_machine/SoilMachine.cpp @@ -33,6 +33,7 @@ extern "C" { int NWATER, int NWIND, float SCALE0, + float c_eq_factor, char* soil_file ) { layers.clear(); @@ -44,18 +45,19 @@ extern "C" { WindParticle::init(SIZEX, SIZEY); Layermap map(SEED, glm::ivec2(SIZEX, SIZEY), SCALE0, heightmap); + c_eq_factor /= 80; for(int i = 0; i < NWATER; i++){ WaterParticle particle(map, SCALE0); while(true){ - while(particle.move(map, vertexpool) && particle.interact(map, vertexpool)); - if(!particle.flood(map, vertexpool)) + while(particle.move(map, vertexpool) && particle.interact(c_eq_factor, map, vertexpool)); + if(!particle.flood(c_eq_factor, map, vertexpool)) break; } } - WaterParticle::seep(SCALE0, map, vertexpool); + WaterParticle::seep(c_eq_factor, SCALE0, map, vertexpool); for(int i = 0; i < NWIND; i++){ WindParticle particle(map, SCALE0); diff --git a/infinigen/terrain/source/cpu/soil_machine/particle/particle.h b/infinigen/terrain/source/cpu/soil_machine/particle/particle.h index ded47a361..d9063ccc5 100644 --- a/infinigen/terrain/source/cpu/soil_machine/particle/particle.h +++ b/infinigen/terrain/source/cpu/soil_machine/particle/particle.h @@ -36,7 +36,7 @@ struct Particle { // because I can't solve the bug, I'm not familiar with static in c++, so I make SCALE an arg --- Zeyu //This is applied to multiple types of erosion, so I put it in here! - static void cascade(float SCALE, vec2 pos, Layermap& map, Vertexpool& vertexpool, int transferloop = 0){ + static void cascade(float c_eq_factor, float SCALE, vec2 pos, Layermap& map, Vertexpool& vertexpool, int transferloop = 0){ ivec2 ipos = round(pos); @@ -72,7 +72,7 @@ struct Particle { for(auto& npos: sn){ //Full Height-Different Between Positions! - float diff = (map.height(ipos) - map.height(npos))*(float)SCALE/80.0f; + float diff = (map.height(ipos) - map.height(npos))*(float)SCALE * c_eq_factor; if(diff == 0) //No Height Difference continue; @@ -98,12 +98,13 @@ struct Particle { if(map.remove(tpos, transfer) != 0) recascade = true; - map.add(bpos, map.pool.get(transfer, param.cascades)); + sec *addition = map.pool.get(transfer, param.cascades); + map.add(bpos, addition); // map.update(tpos, vertexpool); // map.update(bpos, vertexpool); if(recascade && transferloop > 0) - cascade(SCALE, npos, map, vertexpool, --transferloop); + cascade(c_eq_factor, SCALE, npos, map, vertexpool, --transferloop); } diff --git a/infinigen/terrain/source/cpu/soil_machine/particle/water.h b/infinigen/terrain/source/cpu/soil_machine/particle/water.h index aa5fbc897..0def8e196 100644 --- a/infinigen/terrain/source/cpu/soil_machine/particle/water.h +++ b/infinigen/terrain/source/cpu/soil_machine/particle/water.h @@ -112,10 +112,10 @@ struct WaterParticle : public Particle { } - bool interact(Layermap& map, Vertexpool& vertexpool){ + bool interact(float c_eq_factor, Layermap& map, Vertexpool& vertexpool){ //Equilibrium Sediment Transport Amount - double c_eq = param.solubility*(map.height(ipos)-map.height(pos))*(double)SCALE/80.0; + double c_eq = param.solubility*(map.height(ipos)-map.height(pos))*(double)SCALE * c_eq_factor; if(c_eq < 0.0) c_eq = 0.0; if(c_eq > 1.0) c_eq = 1.0; @@ -145,12 +145,13 @@ struct WaterParticle : public Particle { else if(cdiff < 0) { sediment += soils[contains].equrate*cdiff; - map.add(ipos, map.pool.get(-soils[contains].equrate*cdiff*volume, contains)); + sec *addition = map.pool.get(-soils[contains].equrate*cdiff*volume, contains); + map.add(ipos, addition); } //Particle Cascade: Thermal Erosion! - Particle::cascade(SCALE, pos, map, vertexpool, 0); + Particle::cascade(c_eq_factor, SCALE, pos, map, vertexpool, 0); //Update Map, Particle sediment /= (1.0-evaprate); @@ -160,7 +161,7 @@ struct WaterParticle : public Particle { } - bool flood(Layermap& map, Vertexpool& vertexpool){ + bool flood(float c_eq_factor, Layermap& map, Vertexpool& vertexpool){ if(volume < minvol || spill-- <= 0) return false; @@ -170,13 +171,15 @@ struct WaterParticle : public Particle { // Add Water // Add Remaining Soil + sec *addition; + addition = map.pool.get(sediment*soils[contains].equrate, contains); + map.add(ipos, addition); + Particle::cascade(c_eq_factor, SCALE, pos, map, vertexpool, 0); - map.add(ipos, map.pool.get(sediment*soils[contains].equrate, contains)); - Particle::cascade(SCALE, pos, map, vertexpool, 0); - - map.add(ipos, map.pool.get(volume*volumeFactor, soilmap["Air"])); + addition = map.pool.get(volume*volumeFactor, soilmap["Air"]); + map.add(ipos, addition); seep(ipos, map, vertexpool); - WaterParticle::cascade(SCALE, ipos, map, vertexpool, spill); + WaterParticle::cascade(c_eq_factor, SCALE, ipos, map, vertexpool, spill); // map.update(ipos, vertexpool); return false; @@ -187,7 +190,7 @@ struct WaterParticle : public Particle { - static void cascade(float SCALE, vec2 pos, Layermap& map, Vertexpool& vertexpool, int spill = 0){ + static void cascade(float c_eq_factor, float SCALE, vec2 pos, Layermap& map, Vertexpool& vertexpool, int spill = 0){ ivec2 ipos = pos; @@ -244,7 +247,7 @@ struct WaterParticle : public Particle { fB = secB->floor; // Actual Height Difference Between Watertables - double diff = (fA + whA - fB - whB)*(double)SCALE/80.0; + double diff = (fA + whA - fB - whB)*(double)SCALE * c_eq_factor; if(diff == 0) //No Height Difference continue; @@ -274,7 +277,6 @@ struct WaterParticle : public Particle { bool recascade = false; if(transfer == wh){ - double diff = map.remove(tpos, transfer); // map.update(tpos, vertexpool); @@ -286,15 +288,14 @@ struct WaterParticle : public Particle { particle.volume = transfer / WaterParticle::volumeFactor; while(true){ - while(particle.move(map, vertexpool) && particle.interact(map, vertexpool)); - if(!particle.flood(map, vertexpool)) + while(particle.move(map, vertexpool) && particle.interact(c_eq_factor, map, vertexpool)); + if(!particle.flood(c_eq_factor, map, vertexpool)) break; } } else { - if(map.remove(tpos, transfer) != 0) recascade = true; if(transfer > 0) recascade = true; @@ -306,7 +307,7 @@ struct WaterParticle : public Particle { } if(recascade && spill > 0) - WaterParticle::cascade(SCALE, npos, map, vertexpool, --spill); + WaterParticle::cascade(c_eq_factor, SCALE, npos, map, vertexpool, --spill); } @@ -351,8 +352,9 @@ struct WaterParticle : public Particle { if(transfer > 0){ // Remove from Top Layer - if(top->type == soilmap["Air"]) + if(top->type == soilmap["Air"]) { double diff = map.remove(ipos, seepage*transfer); + } else top->saturation -= (seepage*transfer) / (top->size*param.porosity); @@ -368,12 +370,12 @@ struct WaterParticle : public Particle { } - static void seep(float SCALE, Layermap& map, Vertexpool& vertexpool){ + static void seep(float c_eq_factor, float SCALE, Layermap& map, Vertexpool& vertexpool){ for(size_t x = 0; x < map.dim.x; x++) for(size_t y = 0; y < map.dim.y; y++){ seep(ivec2(x,y), map, vertexpool); - WaterParticle::cascade(SCALE, ivec2(x,y), map, vertexpool, 3); + WaterParticle::cascade(c_eq_factor, SCALE, ivec2(x,y), map, vertexpool, 3); } } diff --git a/infinigen/terrain/source/cpu/soil_machine/particle/wind.h b/infinigen/terrain/source/cpu/soil_machine/particle/wind.h index 5126c62e8..569b5392d 100644 --- a/infinigen/terrain/source/cpu/soil_machine/particle/wind.h +++ b/infinigen/terrain/source/cpu/soil_machine/particle/wind.h @@ -127,7 +127,7 @@ struct WindParticle : public Particle { double diff = map.remove(ipos, param.suspension*force); sediment += (param.suspension*force - diff); - Particle::cascade(SCALE, ipos, map, vertexpool, 1); + Particle::cascade(1.0/80, SCALE, ipos, map, vertexpool, 1); // map.update(ipos, vertexpool); } @@ -141,10 +141,10 @@ struct WindParticle : public Particle { map.add(npos, map.pool.get(0.5f*soils[contains].suspension*sediment, contains)); map.add(ipos, map.pool.get(0.5f*soils[contains].suspension*sediment, contains)); - Particle::cascade(SCALE, ipos, map, vertexpool, 1); + Particle::cascade(1.0/80, SCALE, ipos, map, vertexpool, 1); // map.update(ipos, vertexpool); - Particle::cascade(SCALE, npos, map, vertexpool, 1); + Particle::cascade(1.0/80, SCALE, npos, map, vertexpool, 1); // map.update(npos, vertexpool); } diff --git a/infinigen/terrain/utils/__init__.py b/infinigen/terrain/utils/__init__.py index 734ed1b77..1f1862aef 100644 --- a/infinigen/terrain/utils/__init__.py +++ b/infinigen/terrain/utils/__init__.py @@ -11,7 +11,7 @@ from .image_processing import ( boundary_smooth, smooth, read, sharpen, grid_distance, get_normal ) -from .random import perlin_noise, chance, drive_param, random_int, random_int_large +from .random import perlin_noise, chance, drive_param, random_int, random_int_large, random_nat from .kernelizer_util import ( ATTRTYPE_DIMS, ATTRTYPE_FIELDS, ATTRTYPE_NP, NODE_ATTRS_AVAILABLE, diff --git a/infinigen/terrain/utils/camera.py b/infinigen/terrain/utils/camera.py index ee6fe80a4..295dfcda0 100644 --- a/infinigen/terrain/utils/camera.py +++ b/infinigen/terrain/utils/camera.py @@ -47,31 +47,46 @@ def get_expanded_fov(cam_pose0, cam_poses, fov): @gin.configurable -def get_caminfo(cameras, relax=1.05): +def get_caminfo(cameras, relax=1.05, ids_within_rig=2): cam_poses = [] + fovs = [] + Ks = [] + Hs = [] + Ws = [] coords_trans_matrix = np.array([[1, 0, 0, 0], [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]]) fs, fe = bpy.context.scene.frame_start, bpy.context.scene.frame_end fc = bpy.context.scene.frame_current for f in range(fs, fe + 1): bpy.context.scene.frame_set(f) for cam in cameras: - cam_pose = np.array(cam.matrix_world) - cam_pose = np.dot(np.array(cam_pose), coords_trans_matrix) - cam_poses.append(cam_pose) - fov_rad = cam.data.angle _, cid0, cid1 = cam.name.split("/") - cam = get_camera(cid0, 1 - int(cid1), 1) - if cam is None: continue - cam_pose = np.array(cam.matrix_world) - cam_pose = np.dot(np.array(cam_pose), coords_trans_matrix) - cam_poses.append(cam_pose) + rig = [] + if ids_within_rig is not None: + for id in range(ids_within_rig): + c = get_camera(cid0, id, 1) + if c is not None: rig.append(c) + else: + rig.append(cam) + for c in rig: + cam_pose = np.array(c.matrix_world) + cam_pose = np.dot(np.array(cam_pose), coords_trans_matrix) + cam_poses.append(cam_pose) + fov_rad = cam.data.angle + fov_rad *= relax + H, W = bpy.context.scene.render.resolution_y, bpy.context.scene.render.resolution_x + fov0 = np.arctan(H / 2 / (W / 2 / np.tan(fov_rad / 2))) * 2 + fov = np.array([fov0, fov_rad]) + fovs.append(fov) + K = getK(fov, H, W) + Ks.append(K) + Hs.append(H) + Ws.append(W) bpy.context.scene.frame_set(fc) cam_poses = np.stack(cam_poses) cam_pose = pose_average(cam_poses) - fov_rad *= relax - H, W = bpy.context.scene.render.resolution_y, bpy.context.scene.render.resolution_x - fov0 = np.arctan(H / 2 / (W / 2 / np.tan(fov_rad / 2))) * 2 - fov = (fov0, fov_rad) + fovs = np.stack(fovs) + fov = fovs.max(axis=0) fov = get_expanded_fov(cam_pose, cam_poses, fov) - K = getK(fov, H, W) - return cam_pose, cam_poses, fov, H, W, K + H = max(Hs) + W = max(Ws) + return (cam_poses, Ks, Hs, Ws), cam_pose, fov, H, W, K diff --git a/infinigen/terrain/utils/mesh.py b/infinigen/terrain/utils/mesh.py index 3dfe84720..a9c70ab0a 100644 --- a/infinigen/terrain/utils/mesh.py +++ b/infinigen/terrain/utils/mesh.py @@ -71,6 +71,7 @@ def __init__(self, normal_mode=NormalMode.Mean, path=None, heightmap=None, L=None, downsample=1, vertices=None, faces=None, vertex_attributes=None, + mesh=None, obj=None, mesh_only=False, **kwargs ): self.normal_mode = normal_mode @@ -100,6 +101,8 @@ def __init__(self, normal_mode=NormalMode.Mean, _trimesh = trimesh.Trimesh(verts, faces) elif vertices is not None: _trimesh = trimesh.Trimesh(vertices=vertices, faces=faces.astype(np.int32), vertex_attributes=vertex_attributes, process=False) + elif mesh is not None: + _trimesh = mesh elif obj is not None: verts_bpy = obj.data.vertices faces_bpy = obj.data.polygons diff --git a/infinigen/terrain/utils/random.py b/infinigen/terrain/utils/random.py index 549bfd6e2..608664902 100644 --- a/infinigen/terrain/utils/random.py +++ b/infinigen/terrain/utils/random.py @@ -16,6 +16,11 @@ def random_int(): return np.random.randint(np.iinfo(np.int32).min, np.iinfo(np.int32).max) + +def random_nat(): + return np.random.randint(1, np.iinfo(np.int32).max) + + def random_int_large(): return random.getrandbits(128) diff --git a/infinigen/tools/terrain/generate_terrain_assets.py b/infinigen/tools/terrain/generate_terrain_assets.py index 976737c24..45fa00f8d 100644 --- a/infinigen/tools/terrain/generate_terrain_assets.py +++ b/infinigen/tools/terrain/generate_terrain_assets.py @@ -4,9 +4,6 @@ # Authors: Zeyu Ma -''' -fileheader placeholder -''' import os import sys diff --git a/infinigen/tools/terrain/landtile_viewer.py b/infinigen/tools/terrain/landtile_viewer.py index 1d21bdc85..a1e56df30 100644 --- a/infinigen/tools/terrain/landtile_viewer.py +++ b/infinigen/tools/terrain/landtile_viewer.py @@ -22,6 +22,8 @@ parser = argparse.ArgumentParser() parser.add_argument('-i', '--input', type=str) parser.add_argument('-o', '--overlay', type=int, default=False) + parser.add_argument('--mesh', type=str, default="") + parser.add_argument('--scene', type=str, default="") args = init.parse_args_blender(parser) folder = os.path.dirname(args.input) @@ -33,6 +35,7 @@ mesh.vertex_attributes["attribute"] = image.reshape(-1).astype(np.float32) clear_scene() obj = mesh.export_blender("preview") + if args.mesh != "": mesh.save(args.mesh) if args.overlay: material = bpy.data.materials.new(name="preview_material") material.use_nodes = True @@ -40,3 +43,5 @@ new_attribute_node = nw.new_node(Nodes.Attribute, [], {"attribute_name": "attribute"}) material.node_tree.links.new(new_attribute_node.outputs['Color'], material.node_tree.nodes['Principled BSDF'].inputs['Base Color']) obj.active_material = material + if args.scene != "": bpy.ops.wm.save_mainfile(filepath=args.scene) + diff --git a/infinigen_examples/configs/experimental.gin b/infinigen_examples/configs/extras/experimental.gin similarity index 100% rename from infinigen_examples/configs/experimental.gin rename to infinigen_examples/configs/extras/experimental.gin diff --git a/infinigen_examples/configs/stereo_training.gin b/infinigen_examples/configs/extras/stereo_training.gin similarity index 100% rename from infinigen_examples/configs/stereo_training.gin rename to infinigen_examples/configs/extras/stereo_training.gin diff --git a/infinigen_examples/configs/use_cached_fire.gin b/infinigen_examples/configs/extras/use_cached_fire.gin similarity index 100% rename from infinigen_examples/configs/use_cached_fire.gin rename to infinigen_examples/configs/extras/use_cached_fire.gin diff --git a/infinigen_examples/configs/use_on_the_fly_fire.gin b/infinigen_examples/configs/extras/use_on_the_fly_fire.gin similarity index 100% rename from infinigen_examples/configs/use_on_the_fly_fire.gin rename to infinigen_examples/configs/extras/use_on_the_fly_fire.gin diff --git a/infinigen_examples/configs/performance/fast_terrain_assets.gin b/infinigen_examples/configs/performance/fast_terrain_assets.gin index 7c830ba23..931086c0d 100644 --- a/infinigen_examples/configs/performance/fast_terrain_assets.gin +++ b/infinigen_examples/configs/performance/fast_terrain_assets.gin @@ -3,8 +3,4 @@ upsidedown_mountains.load_assets.on_the_fly_instances = 1 caves.load_assets.on_the_fly_instances = 1 run_erosion.n_iters = [1,1] -scene.caves_chance=0.0 - -multi_mountains_asset.snowfall = False -coast_asset.snowfall = False -ant_landscape_asset.snowfall = False \ No newline at end of file +scene.caves_chance=0.0 \ No newline at end of file diff --git a/infinigen_examples/configs/performance/high_quality_terrain.gin b/infinigen_examples/configs/performance/high_quality_terrain.gin index 892667666..068eae244 100644 --- a/infinigen_examples/configs/performance/high_quality_terrain.gin +++ b/infinigen_examples/configs/performance/high_quality_terrain.gin @@ -1,3 +1,4 @@ +OcMesher.pixels_per_cube = 3 OpaqueSphericalMesher.pixels_per_cube = 0.92 TransparentSphericalMesher.pixels_per_cube = 1.38 diff --git a/infinigen_examples/configs/scene_types/cave.gin b/infinigen_examples/configs/scene_types/cave.gin index 2be9df77d..772d750f8 100644 --- a/infinigen_examples/configs/scene_types/cave.gin +++ b/infinigen_examples/configs/scene_types/cave.gin @@ -4,7 +4,7 @@ compose_scene.underwater_domain_tags = 'landscape,liquid_covered' compose_scene.trees_chance = 0.4 compose_scene.rocks_chance = 0.8 -compose_scene.glowing_rocks_chance = 0.5 +compose_scene.glowing_rocks_chance = 1 compose_scene.grass_chance = 0.4 compose_scene.ferns_chance = 0.6 compose_scene.mushroom_chance = 0.8 diff --git a/infinigen_examples/configs/video.gin b/infinigen_examples/configs/video.gin new file mode 100644 index 000000000..e412998c5 --- /dev/null +++ b/infinigen_examples/configs/video.gin @@ -0,0 +1 @@ +export.spherical = False # use OcMesher \ No newline at end of file diff --git a/install.sh b/install.sh deleted file mode 100755 index 0a62b520c..000000000 --- a/install.sh +++ /dev/null @@ -1,132 +0,0 @@ -#!/bin/bash - -set -e - -if ! command -v wget &> /dev/null -then - echo "wget could not be found, please 'sudo apt-get install wget' or 'brew install wget'" - exit -fi - -OS=$(uname -s) -ARCH=$(uname -m) - -if [ "${OS}" = "Linux" ]; then - BLENDER_WGET_LINK='https://download.blender.org/release/Blender3.3/blender-3.3.1-linux-x64.tar.xz' - BLENDER_WGET_FILE='blender.tar.xz' - - BLENDER_UNTAR_DIR='blender-3.3.1-linux-x64' - BLENDER_DIR='blender' - BLENDER_PYTHON="${BLENDER_DIR}/3.3/python/bin/python3.10" - BLENDER_INCLUDE="${BLENDER_DIR}/3.3/python/include/python3.10" - BLENDER_PACKAGES="${BLENDER_DIR}/3.3/python/lib/python3.10/site-packages" - BLENDER_ADDONS="${BLENDER_DIR}/3.3/scripts/addons" - BLENDER_EXE="${BLENDER_DIR}/blender" - - NURBS_SCRIPT="setup_linux.py" -elif [ "${OS}" = "Darwin" ]; then - if [ "${ARCH}" = "arm64" ]; then - BLENDER_WGET_LINK='https://download.blender.org/release/Blender3.3/blender-3.3.1-macos-arm64.dmg' - NURBS_SCRIPT="setup_macos_as.py" - else - BLENDER_WGET_LINK='https://download.blender.org/release/Blender3.3/blender-3.3.1-macos-x64.dmg' - NURBS_SCRIPT="setup_macos.py" - fi - if [ "${ARCH}" = "arm64" ]; then - HOMEBREW_PREFIX="/opt/homebrew/" - else - HOMEBREW_PREFIX="/usr/local" - fi - BLENDER_WGET_FILE='blender.dmg' - - BLENDER_VOLM='/Volumes/Blender' - BLENDER_DIR='./Blender.app' - BLENDER_PYTHON="${BLENDER_DIR}/Contents/Resources/3.3/python/bin/python3.10" - BLENDER_INCLUDE="${BLENDER_DIR}/Contents/Resources/3.3/python/include/python3.10" - BLENDER_PACKAGES="${BLENDER_DIR}/Contents/Resources/3.3/python/lib/python3.10/site-packages" - BLENDER_ADDONS="${BLENDER_DIR}/Contents/Resources/3.3/scripts/addons" - BLENDER_EXE="${BLENDER_DIR}/Contents/MacOS/Blender" - - export CC="${HOMEBREW_PREFIX}/opt/llvm/bin/clang" - export CPATH="${HOMEBREW_PREFIX}/include:${CPATH}" -else - echo "Unsupported OS" - exit -1 -fi -REQUIREMENTS_PATH='./requirements.txt' -PYTHON_WGET_LINK='https://www.python.org/ftp/python/3.10.2/Python-3.10.2.tgz' -PYTHON_WGET_FILE='Python-3.10.2.tgz' -PYTHON_DIR='Python-3.10.2' - -git submodule init -git submodule update - -if [ ! -d "${BLENDER_DIR}" ]; then - # Download Blender - wget -O "${BLENDER_WGET_FILE}" "${BLENDER_WGET_LINK}" - - # Unzip Blender - if [ "${OS}" = "Darwin" ]; then - hdiutil attach "${BLENDER_WGET_FILE}" - cp -r "${BLENDER_VOLM}/Blender.app" "${BLENDER_DIR}" - hdiutil detach "${BLENDER_VOLM}" - else - tar -xf "${BLENDER_WGET_FILE}" - mv "${BLENDER_UNTAR_DIR}" "${BLENDER_DIR}" - fi - - rm "${BLENDER_WGET_FILE}" -fi - -# Install llvm for MacOS -if [ "${OS}" = "Darwin" ]; then - brew install llvm open-mpi libomp glm glew -fi - -# Install Conda dependencies -pip install -r "${REQUIREMENTS_PATH}" -pip install fake-bpy-module-latest - -if [ ! -d "${PYTHON_DIR}" ]; then - # Install Python include file - wget -O "${PYTHON_WGET_FILE}" "${PYTHON_WGET_LINK}" - tar -xf "${PYTHON_WGET_FILE}" - rm "${PYTHON_WGET_FILE}" -fi -cp -r "${PYTHON_DIR}/Include/"* "${BLENDER_INCLUDE}" - -# Install Blender dependencies -"${BLENDER_PYTHON}" -m ensurepip -CFLAGS="-I$(realpath ${BLENDER_INCLUDE}) ${CFLAGS}" "${BLENDER_PYTHON}" -m pip install -r "${REQUIREMENTS_PATH}" - -# Build terrain -rm -rf ${BLENDER_PACKAGES}/terrain-* -rm -rf *.egg-info -rm -rf __pycache__ -rm -rf ./worldgen/terrain/build - -cd ./worldgen/terrain -if [ -f "/usr/local/cuda/bin/nvcc" ]; then - USE_CUDA=1 bash install_terrain.sh -else - USE_CUDA=0 bash install_terrain.sh -fi -"../../${BLENDER_PYTHON}" setup.py build_ext --inplace --force -cd - - -# Build NURBS -cd ./worldgen/assets/creatures/geometry/cpp_utils -rm -f *.so -rm -rf build -"../../../../../${BLENDER_PYTHON}" "${NURBS_SCRIPT}" build_ext --inplace -cd - - -if [ "$1" = "opengl" ]; then - bash ./worldgen/tools/install/compile_opengl.sh -fi - - -# Build Flip Fluids addon -if [ "$1" = "flip_fluids" ] || [ "$2" = "flip_fluids" ]; then - bash ./worldgen/tools/install/compile_flip_fluids.sh -fi \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 7e1f752b7..b06857dd4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,7 +43,8 @@ dependencies = [ "landlab>=2.6.0", "pycparser", "pyrender", - "pandas" + "pandas", + "vnoise", ] [project.optional-dependencies] diff --git a/scripts/install/compile_terrain.sh b/scripts/install/compile_terrain.sh index e02362f26..44849a4d3 100644 --- a/scripts/install/compile_terrain.sh +++ b/scripts/install/compile_terrain.sh @@ -134,4 +134,8 @@ gx1 -o lib/cpu/soil_machine/SoilMachine.o source/cpu/soil_machine/SoilMachine.cp gx2 -o lib/cpu/soil_machine/SoilMachine.so lib/cpu/soil_machine/SoilMachine.o echo "compiled lib/cpu/soil_machine/SoilMachine.so" +cd - + +cd ./infinigen/OcMesher +source install.sh cd - \ No newline at end of file diff --git a/worldgen/assets/leaves/__init__.py b/worldgen/assets/leaves/__init__.py deleted file mode 100644 index 26f5722fb..000000000 --- a/worldgen/assets/leaves/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -from .leaf import LeafFactory, BerryFactory -from .leaf_broadleaf import LeafFactoryBroadleaf -from .leaf_ginko import LeafFactoryGinko -from .leaf_maple import LeafFactoryMaple -from .leaf_pine import LeafFactoryPine -from .leaf_v2 import LeafFactoryV2 -from .leaf_wrapped import LeafFactoryWrapped \ No newline at end of file diff --git a/worldgen/config/performance/simple.gin b/worldgen/config/performance/simple.gin deleted file mode 100644 index 10185747f..000000000 --- a/worldgen/config/performance/simple.gin +++ /dev/null @@ -1,6 +0,0 @@ -include 'config/performance/dev.gin' -include 'config/disable_assets/no_creatures.gin' -include 'config/performance/fast_terrain_assets.gin' - -run_erosion.n_iters = [1,1] -full/render_image.num_samples = 100 \ No newline at end of file