diff --git a/.gitignore b/.gitignore index 287d8d5..5b7725c 100644 --- a/.gitignore +++ b/.gitignore @@ -182,7 +182,6 @@ cython_debug/ *.slo *.lo *.o -*.obj # Precompiled Headers *.gch diff --git a/Content/Python/generate_procedural_terrain.py b/Content/Python/generate_procedural_terrain.py new file mode 100644 index 0000000..9f35c09 --- /dev/null +++ b/Content/Python/generate_procedural_terrain.py @@ -0,0 +1,226 @@ +"""Run inside Unreal (Python console / Execute Python Script). + +Reads terrain_config.json (next to this script) and: + 1. builds a heightfield mesh with GeometryScript (fractal value noise), + bakes it to a StaticMesh, and drops it into the level; + 2. scatters tree/rock StaticMeshActors across it per "scatter_layers", + using the same noise field so foliage height always matches the + ground beneath it (no raycasting needed). + +Run import_environment_assets.py first so the mesh paths referenced in +terrain_config.json actually exist. +""" +import os, json, math, random, unreal + +CONFIG_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "terrain_config.json") + +asset_tools = unreal.AssetToolsHelpers.get_asset_tools() +actor_subsystem = unreal.get_editor_subsystem(unreal.EditorActorSubsystem) + + +# --------------------------------------------------------------------------- +# Fractal value noise (pure Python, no engine dependency) ------------------- +# --------------------------------------------------------------------------- +class ValueNoise2D: + """Seeded, smooth, tileable-enough value noise for terrain-style height fields.""" + + def __init__(self, seed): + rng = random.Random(seed) + table = list(range(256)) + rng.shuffle(table) + self._perm = table + table # avoid overflow when indexing i+1 + + @staticmethod + def _fade(t): + return t * t * t * (t * (t * 6 - 15) + 10) + + @staticmethod + def _lerp(a, b, t): + return a + t * (b - a) + + def _gradient(self, ix, iy): + h = self._perm[(self._perm[ix & 255] + iy) & 255] + angle = (h / 255.0) * 2.0 * math.pi + return math.cos(angle), math.sin(angle) + + def sample(self, x, y): + x0, y0 = math.floor(x), math.floor(y) + x1, y1 = x0 + 1, y0 + 1 + sx, sy = x - x0, y - y0 + + def dot_grid(ix, iy, px, py): + gx, gy = self._gradient(ix, iy) + return gx * (px - ix) + gy * (py - iy) + + n00 = dot_grid(x0, y0, x, y) + n10 = dot_grid(x1, y0, x, y) + n01 = dot_grid(x0, y1, x, y) + n11 = dot_grid(x1, y1, x, y) + + u, v = self._fade(sx), self._fade(sy) + return self._lerp(self._lerp(n00, n10, u), self._lerp(n01, n11, u), v) + + +class FractalHeightField: + def __init__(self, noise_cfg, height_scale): + self.height_scale = height_scale + self.frequency = noise_cfg["frequency"] + self.octaves = noise_cfg["octaves"] + self.lacunarity = noise_cfg["lacunarity"] + self.gain = noise_cfg["gain"] + self.noise = ValueNoise2D(noise_cfg["seed"]) + + def height(self, x, y): + amplitude, frequency, total, max_amp = 1.0, self.frequency, 0.0, 0.0 + for _ in range(self.octaves): + total += amplitude * self.noise.sample(x * frequency, y * frequency) + max_amp += amplitude + amplitude *= self.gain + frequency *= self.lacunarity + return (total / max_amp) * self.height_scale + + def normal(self, x, y, step=25.0): + h_l = self.height(x - step, y) + h_r = self.height(x + step, y) + h_d = self.height(x, y - step) + h_u = self.height(x, y + step) + # tangents along X and Y, cross product gives the surface normal. + tangent_x = unreal.Vector(2 * step, 0.0, h_r - h_l) + tangent_y = unreal.Vector(0.0, 2 * step, h_u - h_d) + nx = tangent_x.y * tangent_y.z - tangent_x.z * tangent_y.y + ny = tangent_x.z * tangent_y.x - tangent_x.x * tangent_y.z + nz = tangent_x.x * tangent_y.y - tangent_x.y * tangent_y.x + length = math.sqrt(nx * nx + ny * ny + nz * nz) or 1.0 + return unreal.Vector(nx / length, ny / length, nz / length) + + +# --------------------------------------------------------------------------- +# Terrain mesh ---------------------------------------------------------------- +# --------------------------------------------------------------------------- +def build_terrain_mesh(cfg, field): + steps = max(2, cfg["resolution"]) + mesh = unreal.DynamicMesh() + primitive_options = unreal.GeometryScriptPrimitiveOptions() + mesh = unreal.GeometryScript_Primitives.append_rectangle_xy( + mesh, primitive_options, unreal.Transform(), + dimension_x=cfg["size_x"], dimension_y=cfg["size_y"], + steps_width=steps, steps_height=steps, + ) + + mesh, position_list, _has_gaps = unreal.GeometryScript_MeshQueries.get_all_vertex_positions(mesh, False) + positions = unreal.GeometryScript_List.convert_vector_list_to_array(position_list) + + min_x = min_y = float("inf") + max_x = max_y = float("-inf") + displaced = [] + for p in positions: + z = field.height(p.x, p.y) + displaced.append(unreal.Vector(p.x, p.y, z)) + min_x, max_x = min(min_x, p.x), max(max_x, p.x) + min_y, max_y = min(min_y, p.y), max(max_y, p.y) + + new_list = unreal.GeometryScript_List.convert_array_to_vector_list(displaced) + mesh = unreal.GeometryScript_MeshEdits.set_all_mesh_vertex_positions(mesh, new_list) + mesh = unreal.GeometryScript_Normals.set_per_vertex_normals(mesh) + + dest_path = cfg["dest_path"] + asset_name = cfg["asset_name"] + if unreal.EditorAssetLibrary.does_asset_exist(f"{dest_path}/{asset_name}"): + unreal.EditorAssetLibrary.delete_asset(f"{dest_path}/{asset_name}") + static_mesh = asset_tools.create_asset(asset_name, dest_path, unreal.StaticMesh, unreal.StaticMeshFactoryNew()) + + copy_options = unreal.GeometryScriptCopyMeshToAssetOptions() + target_lod = unreal.GeometryScriptMeshWriteLOD() + unreal.GeometryScript_AssetUtils.copy_mesh_to_static_mesh(mesh, static_mesh, copy_options, target_lod) + unreal.EditorAssetLibrary.save_asset(static_mesh.get_path_name()) + + bounds = (min_x, max_x, min_y, max_y) + return static_mesh, bounds + + +# --------------------------------------------------------------------------- +# Foliage scatter -------------------------------------------------------------- +# --------------------------------------------------------------------------- +def scatter_layer(layer_cfg, field, bounds, origin, base_folder): + min_x, max_x, min_y, max_y = bounds + rng = random.Random(layer_cfg.get("seed", 0)) + meshes = [unreal.load_asset(path) for path in layer_cfg["meshes"]] + meshes = [m for m in meshes if m is not None] + if not meshes: + print(f" [{layer_cfg['name']}] no valid meshes found, skipping") + return 0 + + max_slope_cos = math.cos(math.radians(layer_cfg.get("max_slope_degrees", 90.0))) + min_spacing = layer_cfg.get("min_spacing", 0.0) + min_spacing_sqr = min_spacing * min_spacing + + placed_points = [] + spawned = 0 + max_attempts = layer_cfg["count"] * 25 + + attempts = 0 + while spawned < layer_cfg["count"] and attempts < max_attempts: + attempts += 1 + x = rng.uniform(min_x, max_x) + y = rng.uniform(min_y, max_y) + + if min_spacing_sqr > 0.0 and any((x - px) ** 2 + (y - py) ** 2 < min_spacing_sqr for px, py in placed_points): + continue + + z = field.height(x, y) + if not (layer_cfg["min_height"] <= z <= layer_cfg["max_height"]): + continue + + normal = field.normal(x, y) + if normal.z < max_slope_cos: + continue + + placed_points.append((x, y)) + + mesh = rng.choice(meshes) + location = unreal.Vector(origin.x + x, origin.y + y, origin.z + z) + yaw = rng.uniform(0.0, 360.0) + if layer_cfg.get("align_to_normal", False): + # Approximate tilt from the surface normal; good enough for gentle slopes. + pitch = -math.degrees(math.atan2(normal.x, normal.z)) + roll = math.degrees(math.atan2(normal.y, normal.z)) + rotation = unreal.Rotator(roll=roll, pitch=pitch, yaw=yaw) + else: + rotation = unreal.Rotator(roll=0.0, pitch=0.0, yaw=yaw) + + actor = actor_subsystem.spawn_actor_from_object(mesh, location, rotation) + scale = rng.uniform(layer_cfg["min_scale"], layer_cfg["max_scale"]) + actor.set_actor_scale3d(unreal.Vector(scale, scale, scale)) + actor.set_folder_path(f"{base_folder}/{layer_cfg['name']}") + actor.set_actor_label(f"{layer_cfg['name']}_{spawned:04d}") + spawned += 1 + + print(f" [{layer_cfg['name']}] placed {spawned}/{layer_cfg['count']} ({attempts} attempts)") + return spawned + + +# --------------------------------------------------------------------------- +def main(): + with open(CONFIG_PATH, "r") as f: + config = json.load(f) + + terrain_cfg = config["terrain"] + field = FractalHeightField(terrain_cfg["noise"], terrain_cfg["height_scale"]) + + print("Building terrain mesh...") + static_mesh, bounds = build_terrain_mesh(terrain_cfg, field) + + loc = terrain_cfg["location"] + origin = unreal.Vector(loc[0], loc[1], loc[2]) + terrain_actor = actor_subsystem.spawn_actor_from_object(static_mesh, origin, unreal.Rotator(0, 0, 0)) + terrain_actor.set_folder_path("ProceduralTerrain") + terrain_actor.set_actor_label("ProceduralTerrain") + + print("Scattering foliage layers...") + for layer_cfg in config.get("scatter_layers", []): + scatter_layer(layer_cfg, field, bounds, origin, "ProceduralTerrain") + + print("Done.") + + +main() diff --git a/Content/Python/import_environment_assets.py b/Content/Python/import_environment_assets.py new file mode 100644 index 0000000..dbc579c --- /dev/null +++ b/Content/Python/import_environment_assets.py @@ -0,0 +1,66 @@ +"""Run inside Unreal (Python console / Execute Python Script). + +Imports the tree (FBX) and rock (OBJ) meshes from DemoAssets as StaticMesh +assets, so generate_procedural_terrain.py has something to scatter. +""" +import os, unreal + +DEMO_ROOT = r"C:\Users\koleg\Documents\Unreal Projects\ExampleProject\DemoAssets" +DEST_ROOT = "/Game/ImportedAssets" + +# folder under DEMO_ROOT -> (destination subfolder, file extension) +SOURCES = { + "trees": ("Trees", ".fbx"), + "rocks": ("Rocks", ".obj"), +} + +asset_tools = unreal.AssetToolsHelpers.get_asset_tools() + + +def import_task(filename, name, dest_path, options=None): + task = unreal.AssetImportTask() + task.filename = filename + task.destination_path = dest_path + task.destination_name = name + task.automated = True + task.save = True + task.replace_existing = True + if options: + task.options = options + asset_tools.import_asset_tasks([task]) + return unreal.load_asset(f"{dest_path}/{name}") + + +def import_static_mesh(filename, name, dest_path): + ext = os.path.splitext(filename)[1].lower() + options = None + if ext == ".fbx": + options = unreal.FbxImportUI() + options.mesh_type_to_import = unreal.FBXImportType.FBXIT_STATIC_MESH + options.import_mesh = True + options.import_as_skeletal = False + options.import_materials = True + options.import_textures = True + options.static_mesh_import_data.combine_meshes = True + # OBJ has no import-options struct exposed to Python; Interchange picks sane defaults. + return import_task(filename, name, dest_path, options) + + +imported = [] +for src_folder, (dest_subfolder, ext) in SOURCES.items(): + src_dir = os.path.join(DEMO_ROOT, src_folder) + if not os.path.isdir(src_dir): + continue + dest_path = f"{DEST_ROOT}/{dest_subfolder}" + + for f in sorted(os.listdir(src_dir)): + stem, file_ext = os.path.splitext(f) + if file_ext.lower() != ext: + continue + name = f"SM_{stem}" + mesh = import_static_mesh(os.path.join(src_dir, f), name, dest_path) + imported.append(f"{dest_path}/{name}") + +print(f"Imported {len(imported)} static mesh(es):") +for path in imported: + print(f" {path}") diff --git a/Content/Python/terrain_config.json b/Content/Python/terrain_config.json new file mode 100644 index 0000000..ac58a8b --- /dev/null +++ b/Content/Python/terrain_config.json @@ -0,0 +1,55 @@ +{ + "terrain": { + "location": [0.0, 0.0, 0.0], + "size_x": 8000.0, + "size_y": 8000.0, + "resolution": 96, + "height_scale": 600.0, + "dest_path": "/Game/ImportedAssets/Terrain", + "asset_name": "SM_ProceduralTerrain", + "noise": { + "seed": 1337, + "octaves": 5, + "frequency": 0.00035, + "lacunarity": 2.0, + "gain": 0.5 + } + }, + "scatter_layers": [ + { + "name": "Trees", + "meshes": [ + "/Game/ImportedAssets/Trees/SM_tree01", + "/Game/ImportedAssets/Trees/SM_tree02", + "/Game/ImportedAssets/Trees/SM_tree03", + "/Game/ImportedAssets/Trees/SM_tree04" + ], + "count": 250, + "min_height": -50.0, + "max_height": 350.0, + "max_slope_degrees": 25.0, + "min_scale": 0.85, + "max_scale": 1.3, + "align_to_normal": true, + "min_spacing": 250.0, + "seed": 7 + }, + { + "name": "Rocks", + "meshes": [ + "/Game/ImportedAssets/Rocks/SM_rock1", + "/Game/ImportedAssets/Rocks/SM_rock2", + "/Game/ImportedAssets/Rocks/SM_rock3" + ], + "count": 150, + "min_height": -100.0, + "max_height": 600.0, + "max_slope_degrees": 45.0, + "min_scale": 0.5, + "max_scale": 2.0, + "align_to_normal": true, + "min_spacing": 150.0, + "seed": 42 + } + ] +} diff --git a/DemoAssets/rocks/rock1.obj b/DemoAssets/rocks/rock1.obj new file mode 100644 index 0000000..c3e3299 --- /dev/null +++ b/DemoAssets/rocks/rock1.obj @@ -0,0 +1,150 @@ +# This file uses meters as units for non-parametric coordinates. + +mtllib rock1.mtl +g default +v 60.961374 -5.900725 666.433465 +v 81.495080 -3.199092 601.016218 +v 53.343536 55.042628 643.268772 +v 76.070805 24.349729 604.198663 +v -25.754741 70.179057 590.440984 +v 39.079050 28.524794 549.884793 +v -28.211224 1.467945 586.832256 +v 38.099069 1.113398 548.445139 +v -64.576491 1.211629 620.887836 +v 18.134000 -5.338232 689.297482 +v 29.577130 40.349512 668.812091 +v -46.153565 45.713000 618.240132 +v -55.299658 44.455610 552.817086 +v -18.120178 30.984263 541.991664 +v -19.100158 3.572868 540.552010 +v -62.273991 4.971875 543.303204 +v -83.546520 4.715556 567.085103 +v -67.072964 38.318831 579.168205 +vt 0.013594 0.871319 +vt 0.237971 0.867459 +vt 0.240427 0.957665 +vt 0.024171 0.963553 +vt 0.427778 0.862291 +vt 0.430233 0.952498 +vt 0.648270 0.548992 +vt 0.868346 0.282651 +vt 0.558597 0.993333 +vt 0.569932 0.858421 +vt 0.281954 0.465477 +vt 0.635226 0.461082 +vt 0.963085 0.743641 +vt 0.664728 0.715269 +vt 0.519035 0.739057 +vt 0.097769 0.502064 +vt 0.417322 0.191267 +vt 0.330903 0.427701 +vt 0.110328 0.386391 +vt 0.024080 0.178104 +vt 0.595238 0.229407 +vt 0.492016 0.327223 +vt 0.084013 0.030278 +vt 0.437309 0.028804 +vt 0.598800 0.124634 +vt 0.967964 0.867923 +vt 0.651856 0.853576 +vt 0.094870 0.672827 +vt 0.276238 0.648165 +vt 0.501202 0.662779 +vt 0.483519 0.753918 +vt 0.335534 0.855512 +vt 0.215825 0.821752 +vt 0.120472 0.682533 +vt 0.013594 0.564551 +vt 0.475594 0.825721 +vt 0.168730 0.610037 +vt 0.315998 0.620256 +vt 0.615583 0.628678 +vt 0.988730 0.150924 +vt 0.698679 0.376714 +vt 0.876431 0.076536 +vt 0.914827 0.367708 +vt 0.947489 0.651940 +vt 0.687173 0.061222 +vn 0.922010 0.209419 0.325639 +vn 0.922010 0.209419 0.325639 +vn 0.922010 0.209419 0.325639 +vn 0.922010 0.209419 0.325639 +vn 0.424792 0.851737 -0.306751 +vn 0.424792 0.851737 -0.306751 +vn 0.424792 0.851737 -0.306751 +vn 0.424792 0.851737 -0.306751 +vn -0.132356 0.175476 -0.975546 +vn -0.132356 0.175476 -0.975546 +vn -0.132356 0.175476 -0.975546 +vn -0.132356 0.175476 -0.975546 +vn -0.035679 -0.997988 -0.052415 +vn -0.035679 -0.997988 -0.052415 +vn -0.035679 -0.997988 -0.052415 +vn -0.035679 -0.997988 -0.052415 +vn 0.798297 0.114283 -0.591321 +vn 0.798297 0.114283 -0.591321 +vn 0.798297 0.114283 -0.591321 +vn 0.798297 0.114283 -0.591321 +vn -0.539251 0.372322 0.755370 +vn -0.539251 0.372322 0.755371 +vn -0.539251 0.372322 0.755370 +vn -0.539251 0.372322 0.755371 +vn -0.038871 -0.998056 -0.048714 +vn -0.038871 -0.998056 -0.048713 +vn -0.038871 -0.998056 -0.048713 +vn -0.038871 -0.998056 -0.048713 +vn 0.515529 0.308716 0.799328 +vn 0.515529 0.308716 0.799328 +vn 0.515529 0.308716 0.799328 +vn 0.515529 0.308716 0.799328 +vn -0.198456 0.861207 0.467907 +vn -0.198456 0.861207 0.467907 +vn -0.198456 0.861207 0.467907 +vn -0.198456 0.861207 0.467907 +vn -0.790109 0.392588 -0.470747 +vn -0.790109 0.392588 -0.470747 +vn -0.790109 0.392588 -0.470747 +vn -0.790109 0.392588 -0.470747 +vn 0.112767 0.781105 -0.614133 +vn 0.112767 0.781105 -0.614133 +vn 0.112767 0.781105 -0.614133 +vn 0.112767 0.781105 -0.614133 +vn 0.138530 0.047003 -0.989242 +vn 0.138530 0.047003 -0.989242 +vn 0.138530 0.047003 -0.989242 +vn 0.138530 0.047003 -0.989242 +vn -0.035679 -0.997988 -0.052415 +vn -0.035679 -0.997988 -0.052415 +vn -0.035679 -0.997988 -0.052415 +vn -0.035679 -0.997988 -0.052415 +vn -0.040875 -0.997933 -0.049579 +vn -0.040875 -0.997933 -0.049579 +vn -0.040875 -0.997933 -0.049579 +vn -0.040875 -0.997933 -0.049579 +vn -0.867761 0.344427 0.358274 +vn -0.867761 0.344427 0.358274 +vn -0.867761 0.344427 0.358274 +vn -0.867761 0.344427 0.358274 +vn -0.621280 0.780287 0.071858 +vn -0.621280 0.780287 0.071858 +vn -0.621280 0.780287 0.071858 +vn -0.621280 0.780287 0.071858 +s off +g Rock_lp_1 +usemtl initialShadingGroup +f 1/29/1 2/30/2 4/31/3 3/32/4 +f 3/7/5 4/41/6 6/43/7 5/44/8 +f 13/9/9 14/6/10 15/5/11 16/10/12 +f 7/17/13 8/18/14 2/19/15 1/20/16 +f 2/1/17 8/2/18 6/3/19 4/4/20 +f 9/11/21 10/12/22 11/39/23 12/38/24 +f 7/17/25 1/20/26 10/23/27 9/24/28 +f 1/29/29 3/32/30 11/33/31 10/34/32 +f 3/26/33 5/27/34 12/14/35 11/13/36 +f 13/28/37 16/35/38 17/16/39 18/37/40 +f 5/8/41 6/45/42 14/42/43 13/40/44 +f 6/3/45 8/2/46 15/5/47 14/6/48 +f 8/18/49 7/17/50 16/21/51 15/22/52 +f 7/17/53 9/24/54 17/25/55 16/21/56 +f 9/11/57 12/38/58 18/37/59 17/16/60 +f 12/14/61 5/27/62 13/36/63 18/15/64 diff --git a/DemoAssets/rocks/rock2.obj b/DemoAssets/rocks/rock2.obj new file mode 100644 index 0000000..ac26a5d --- /dev/null +++ b/DemoAssets/rocks/rock2.obj @@ -0,0 +1,145 @@ +# This file uses meters as units for non-parametric coordinates. + +mtllib rock4.mtl +g default +v 38.794239 -0.000003 40.511074 +v 55.787256 0.636667 -4.093215 +v 43.902161 125.036081 16.972691 +v 53.751527 101.489783 -6.361710 +v 9.082199 131.031642 1.244271 +v 24.842513 95.184084 -39.805775 +v 30.030623 -0.000003 -10.214713 +v 35.364386 -0.000003 -36.239160 +v -37.071816 0.636667 31.278475 +v 5.246203 0.636667 60.851682 +v 23.146697 118.556340 40.584149 +v -4.392659 124.078623 18.054167 +v -25.147788 62.874113 -34.415105 +v -3.229192 75.462083 -52.986576 +v -6.418482 -0.000003 -44.947513 +v -36.447579 -0.000003 -37.182879 +v -56.020129 0.636667 -12.088406 +v -50.083272 67.039526 -7.514205 +vt 0.317952 0.840764 +vt 0.502279 0.839048 +vt 0.550594 0.988133 +vt 0.333404 0.996235 +vt 0.711244 0.847972 +vt 0.706618 0.969937 +vt 0.823567 0.924330 +vt 0.850461 0.815033 +vt 0.716026 0.275741 +vt 0.950806 0.195415 +vt 0.846127 0.449700 +vt 0.748417 0.497907 +vt 0.735828 0.019705 +vt 0.951102 0.018604 +vt 0.493022 0.674398 +vt 0.473431 0.787807 +vt 0.259498 0.841579 +vt 0.306000 0.653003 +vt 0.101506 0.830603 +vt 0.049871 0.715428 +vt 0.288941 0.562889 +vt 0.466113 0.541208 +vt 0.013637 0.562688 +vt 0.381595 0.388221 +vt 0.487594 0.343790 +vt 0.415976 0.513644 +vt 0.217056 0.556374 +vt 0.333329 0.035702 +vt 0.427398 0.143485 +vt 0.069695 0.466053 +vt 0.083918 0.209647 +vt 0.199429 0.017127 +vt 0.717907 0.586179 +vt 0.920575 0.604084 +vt 0.914283 0.760194 +vt 0.803969 0.787669 +vt 0.669998 0.777843 +vt 0.545794 0.602010 +vt 0.985528 0.820589 +vt 0.980204 0.929413 +vn 0.932896 0.028330 0.359031 +vn 0.932896 0.028330 0.359031 +vn 0.932896 0.028330 0.359031 +vn 0.932896 0.028330 0.359031 +vn 0.403964 0.746830 -0.528260 +vn 0.403964 0.746830 -0.528260 +vn 0.403964 0.746830 -0.528260 +vn 0.403964 0.746830 -0.528260 +vn -0.454779 0.013700 -0.890499 +vn -0.454779 0.013700 -0.890499 +vn -0.454779 0.013700 -0.890499 +vn -0.454779 0.013700 -0.890499 +vn 0.024976 -0.999687 -0.001116 +vn 0.024976 -0.999687 -0.001116 +vn 0.024976 -0.999687 -0.001116 +vn 0.024976 -0.999687 -0.001116 +vn 0.797059 0.033109 -0.602993 +vn 0.797059 0.033109 -0.602993 +vn 0.797059 0.033109 -0.602993 +vn 0.797059 0.033109 -0.602993 +vn -0.570290 0.228977 0.788885 +vn -0.570290 0.228977 0.788885 +vn -0.570290 0.228977 0.788885 +vn -0.570290 0.228977 0.788885 +vn -0.009096 -0.999942 0.005786 +vn -0.009096 -0.999942 0.005786 +vn -0.009096 -0.999942 0.005786 +vn -0.009096 -0.999942 0.005786 +vn 0.621715 0.081576 0.778984 +vn 0.621715 0.081576 0.778984 +vn 0.621715 0.081576 0.778984 +vn 0.621715 0.081576 0.778984 +vn -0.012016 0.951904 0.306160 +vn -0.012016 0.951904 0.306160 +vn -0.012016 0.951904 0.306160 +vn -0.012016 0.951904 0.306160 +vn -0.746311 0.136504 -0.651449 +vn -0.746311 0.136504 -0.651449 +vn -0.746311 0.136504 -0.651449 +vn -0.746311 0.136504 -0.651449 +vn -0.489225 0.662245 -0.567530 +vn -0.489225 0.662245 -0.567530 +vn -0.489225 0.662245 -0.567530 +vn -0.489225 0.662245 -0.567530 +vn 0.311742 -0.051132 -0.948790 +vn 0.311742 -0.051132 -0.948790 +vn 0.311742 -0.051132 -0.948790 +vn 0.311742 -0.051132 -0.948790 +vn 0.000000 -1.000000 0.000000 +vn 0.000000 -1.000000 0.000000 +vn 0.000000 -1.000000 0.000000 +vn 0.000000 -1.000000 0.000000 +vn -0.007599 -0.999929 0.009230 +vn -0.007599 -0.999929 0.009230 +vn -0.007599 -0.999929 0.009230 +vn -0.007599 -0.999929 0.009230 +vn -0.789101 0.187167 0.585054 +vn -0.789101 0.187167 0.585054 +vn -0.789101 0.187167 0.585054 +vn -0.789101 0.187167 0.585054 +vn -0.604858 0.626514 -0.491556 +vn -0.604858 0.626514 -0.491556 +vn -0.604858 0.626514 -0.491556 +vn -0.604858 0.626514 -0.491556 +s off +g Rock_lp_4 +usemtl initialShadingGroup +f 1/33/1 2/34/2 4/35/3 3/36/4 +f 3/15/5 4/16/6 6/17/7 5/18/8 +f 13/7/9 14/6/10 15/5/11 16/8/12 +f 7/24/13 8/25/14 2/26/15 1/27/16 +f 2/1/17 8/2/18 6/3/19 4/4/20 +f 9/9/21 10/13/22 11/14/23 12/10/24 +f 7/24/25 1/27/26 10/30/27 9/31/28 +f 1/33/29 3/36/30 11/37/31 10/38/32 +f 3/15/33 5/18/34 12/21/35 11/22/36 +f 13/7/37 16/8/38 17/39/39 18/40/40 +f 5/18/41 6/17/42 14/19/43 13/20/44 +f 6/3/45 8/2/46 15/5/47 14/6/48 +f 8/25/49 7/24/50 16/28/51 15/29/52 +f 7/24/53 9/31/54 17/32/55 16/28/56 +f 9/9/57 12/10/58 18/11/59 17/12/60 +f 12/21/61 5/18/62 13/20/63 18/23/64 diff --git a/DemoAssets/rocks/rock3.obj b/DemoAssets/rocks/rock3.obj new file mode 100644 index 0000000..305156e --- /dev/null +++ b/DemoAssets/rocks/rock3.obj @@ -0,0 +1,181 @@ +# This file uses meters as units for non-parametric coordinates. + +mtllib rock3.mtl +g default +v 60.133407 0.000004 367.305796 +v 91.064860 0.000004 266.122598 +v 50.472230 59.334767 340.856741 +v 88.804659 27.466667 265.296105 +v -53.274603 68.849652 286.528257 +v 28.942177 27.466667 202.002468 +v -44.463900 0.000004 291.142106 +v 26.931423 0.000004 207.139466 +v -85.838949 0.231739 364.912423 +v -13.850827 0.231739 405.900329 +v -3.247214 45.162099 390.218536 +v -70.372656 45.162099 355.355635 +v -65.470929 40.151796 261.749006 +v -37.362145 27.466667 238.084505 +v -45.639745 0.000004 233.749824 +v -71.579786 0.000004 254.552454 +v -87.258289 0.231739 297.370367 +v -76.126751 34.988487 293.446185 +v 51.182110 76.647590 319.321325 +v 72.042295 44.779492 277.126060 +v 29.283761 44.779492 222.789145 +v 0.399489 86.162475 271.769669 +vt 0.577364 0.537112 +vt 0.573117 0.277027 +vt 0.656499 0.270336 +vt 0.659842 0.529230 +vt 0.561526 0.863531 +vt 0.544217 0.948922 +vt 0.719920 0.313461 +vt 0.735012 0.515141 +vt 0.981084 0.191616 +vt 0.910527 0.341191 +vt 0.886809 0.549747 +vt 0.186571 0.512872 +vt 0.435295 0.510629 +vt 0.441575 0.654141 +vt 0.214425 0.653785 +vt 0.656530 0.567258 +vt 0.610564 0.756926 +vt 0.043923 0.677298 +vt 0.014159 0.571962 +vt 0.242644 0.130804 +vt 0.508687 0.200230 +vt 0.453022 0.440938 +vt 0.195765 0.496807 +vt 0.291715 0.013576 +vt 0.367077 0.051692 +vt 0.026268 0.360587 +vt 0.033479 0.123853 +vt 0.179877 0.030658 +vt 0.001627 0.792049 +vt 0.354478 0.793410 +vt 0.988633 0.819088 +vt 0.071370 0.977140 +vt 0.033074 0.721007 +vt 0.237306 0.676581 +vt 0.747212 0.746434 +vt 0.835611 0.740298 +vt 0.458341 0.844041 +vt 0.642427 0.751423 +vt 0.502489 0.015520 +vt 0.778956 0.016676 +vt 0.780597 0.099459 +vt 0.563099 0.201029 +vt 0.740036 0.163476 +vt 0.616443 0.257512 +vt 0.640014 0.991670 +vt 0.650089 0.868329 +vt 0.766738 0.890912 +vt 0.728607 0.993517 +vt 0.338219 0.954483 +vt 0.346133 0.871132 +vt 0.792650 0.854321 +vt 0.298401 0.984476 +vn 0.919996 0.226794 0.319643 +vn 0.919996 0.226794 0.319643 +vn 0.919996 0.226794 0.319643 +vn 0.919996 0.226794 0.319643 +vn 0.485070 0.791688 -0.371398 +vn 0.485070 0.791688 -0.371398 +vn 0.485070 0.791688 -0.371398 +vn 0.485070 0.791689 -0.371398 +vn -0.577892 0.255150 -0.775202 +vn -0.577893 0.255150 -0.775202 +vn -0.577892 0.255150 -0.775202 +vn -0.577893 0.255150 -0.775202 +vn 0.000000 -1.000000 0.000000 +vn 0.000000 -1.000000 0.000000 +vn 0.000000 -1.000000 0.000000 +vn 0.000000 -1.000000 0.000000 +vn 0.700233 -0.073905 -0.710078 +vn 0.700233 -0.073905 -0.710078 +vn 0.700233 -0.073905 -0.710078 +vn 0.700233 -0.073905 -0.710078 +vn -0.446673 0.359674 0.819218 +vn -0.446673 0.359674 0.819218 +vn -0.446673 0.359674 0.819218 +vn -0.446673 0.359674 0.819218 +vn -0.001628 -0.999996 0.002454 +vn -0.001628 -0.999996 0.002454 +vn -0.001628 -0.999996 0.002454 +vn -0.001628 -0.999996 0.002454 +vn 0.514174 0.317328 0.796824 +vn 0.514174 0.317328 0.796824 +vn 0.514174 0.317328 0.796824 +vn 0.514174 0.317328 0.796824 +vn -0.081754 0.962335 0.259284 +vn -0.081754 0.962335 0.259284 +vn -0.081754 0.962335 0.259284 +vn -0.081754 0.962335 0.259284 +vn -0.923052 0.226040 -0.311256 +vn -0.923052 0.226040 -0.311256 +vn -0.923052 0.226040 -0.311256 +vn -0.923052 0.226040 -0.311256 +vn -0.337495 0.658108 -0.673046 +vn -0.337495 0.658108 -0.673046 +vn -0.337495 0.658108 -0.673046 +vn -0.337495 0.658108 -0.673046 +vn -0.410614 0.063618 -0.909587 +vn -0.410614 0.063618 -0.909587 +vn -0.410614 0.063618 -0.909587 +vn -0.410614 0.063618 -0.909587 +vn 0.000000 -1.000000 0.000000 +vn 0.000000 -1.000000 0.000000 +vn 0.000000 -1.000000 0.000000 +vn 0.000000 -1.000000 0.000000 +vn -0.005207 -0.999985 0.001427 +vn -0.005207 -0.999985 0.001427 +vn -0.005207 -0.999985 0.001427 +vn -0.005207 -0.999985 0.001427 +vn -0.946809 0.320637 0.027268 +vn -0.946809 0.320637 0.027268 +vn -0.946809 0.320637 0.027268 +vn -0.946809 0.320637 0.027268 +vn -0.833535 0.547628 -0.072960 +vn -0.833535 0.547628 -0.072960 +vn -0.833535 0.547628 -0.072960 +vn -0.833535 0.547628 -0.072960 +vn 0.869313 0.456276 0.190017 +vn 0.869313 0.456276 0.190017 +vn 0.869313 0.456276 0.190017 +vn 0.869313 0.456276 0.190017 +vn 0.539105 0.698691 -0.470316 +vn 0.539105 0.698691 -0.470316 +vn 0.539105 0.698691 -0.470316 +vn 0.539105 0.698691 -0.470316 +vn -0.338632 0.647169 -0.683008 +vn -0.338632 0.647169 -0.683008 +vn -0.338632 0.647169 -0.683008 +vn -0.338632 0.647169 -0.683008 +vn -0.215613 0.847341 0.485309 +vn -0.215613 0.847341 0.485309 +vn -0.215613 0.847341 0.485309 +vn -0.215613 0.847341 0.485309 +s off +g Rock_lp_3 +usemtl initialShadingGroup +f 1/39/1 2/40/2 4/41/3 3/42/4 +f 19/11/5 20/8/6 21/7/7 22/10/8 +f 13/45/9 14/6/10 15/5/11 16/46/12 +f 7/20/13 8/21/14 2/22/15 1/23/16 +f 2/1/17 8/2/18 6/3/19 4/4/20 +f 9/12/21 10/13/22 11/14/23 12/15/24 +f 7/20/25 1/23/26 10/26/27 9/27/28 +f 1/16/29 3/17/30 11/14/31 10/13/32 +f 3/29/33 5/30/34 12/52/35 11/32/36 +f 13/45/37 16/46/38 17/47/39 18/48/40 +f 5/51/41 6/37/42 14/38/43 13/35/44 +f 6/49/45 8/50/46 15/5/47 14/6/48 +f 8/21/49 7/20/50 16/24/51 15/25/52 +f 7/20/53 9/27/54 17/28/55 16/24/56 +f 9/12/57 12/15/58 18/18/59 17/19/60 +f 12/31/61 5/51/62 13/35/63 18/36/64 +f 3/42/65 4/41/66 20/43/67 19/44/68 +f 4/4/69 6/3/70 21/7/71 20/8/72 +f 6/3/73 5/9/74 22/10/75 21/7/76 +f 5/30/77 3/29/78 19/33/79 22/34/80 diff --git a/DemoAssets/trees/tree01.fbx b/DemoAssets/trees/tree01.fbx new file mode 100644 index 0000000..00e129f Binary files /dev/null and b/DemoAssets/trees/tree01.fbx differ diff --git a/DemoAssets/trees/tree02.fbx b/DemoAssets/trees/tree02.fbx new file mode 100644 index 0000000..a615674 Binary files /dev/null and b/DemoAssets/trees/tree02.fbx differ diff --git a/DemoAssets/trees/tree03.fbx b/DemoAssets/trees/tree03.fbx new file mode 100644 index 0000000..4559902 Binary files /dev/null and b/DemoAssets/trees/tree03.fbx differ diff --git a/DemoAssets/trees/tree04.fbx b/DemoAssets/trees/tree04.fbx new file mode 100644 index 0000000..3af8e8e Binary files /dev/null and b/DemoAssets/trees/tree04.fbx differ