diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..c362922 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,5 @@ +*.blend binary +*.vdb binary +*.exr binary +*.png binary +*.jpg binary diff --git a/.gitignore b/.gitignore index 68bc17f..a939a82 100644 --- a/.gitignore +++ b/.gitignore @@ -158,3 +158,9 @@ cython_debug/ # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ + +# Blender +*.blend1 +*.blend2 +*.blend@ +.DS_Store diff --git a/README.md b/README.md index d8c8445..f8d833a 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,108 @@ -# ARM Repository Template -Basic repository template with required security workflows +# ablemodels — ARM Blender models + +Procedural Blender models of ARM Mobile Facility sites and instruments, built for the +DERECHOS campaign (Iowa–Illinois). The repository is **self-contained and runnable**: every +scene links its assets from the asset folders by relative path, so a fresh clone opens and +renders with no missing files. + +Requires **Blender 5.2 LTS** or newer (files were written with 5.2.3). + +![M1 aerial](scenes/preview/M1_Cam_M1_Aerial_SE.jpg) + +| | | | +|---|---|---| +| | | | +| CM1 supercell over M1 (`scenes/tests/m1_supercell.blend`) | S2, Washington Municipal Airport | AMF2 container row at M1 | + +## Layout + +| Folder | What is in it | +|---|---| +| [`instruments/`](instruments/) | One `.blend` per ARM instrument (AERI, KAZR, DL, MPL, MWR3C, MET tower, ECOR, SEBS, SIRS, RWP, …) plus the C-SAPR2 radar and the KAWG AWOS | +| [`containers/`](containers/) | AMF2 instrument containers, AOS platform, office shelter, and the SACR container (M1 and S2 versions) | +| [`buildings/`](buildings/) | Farmstead (M1), MIRF buildings and center pivots (S1), KAWG hangars and terminal (S2), Louisa power station, flagpole, site signs | +| [`vehicles/`](vehicles/) | Farm vehicles and implements, and the ARM Challenger 850 research aircraft | +| [`plants/`](plants/) | Corn and soybean variants, lawn and tall grass, tree sets (standard and high-detail), native prairie flowers | +| [`clouds/`](clouds/) | Mature-cloud snapshots as OpenVDB volumes with their shaders: LASSO SGP cumulus, UCLA cumulus, CM1 BOMEX cumulus, CM1 supercells | +| [`scenes/`](scenes/) | The three DERECHOS sites (M1, S1, S2) and test scenes; site-specific terrain/vegetation layers live in `scenes//layers/` | +| [`textures/`](textures/) | Shared image textures (PBR material sets, NAIP orthoimagery, sign and flag artwork) | +| [`tools/`](tools/) | Scripts that built this library from the original working files, plus build/verification reports | + +Every asset folder has a `preview/` subfolder with renders of what it contains, and a +`README.md` catalogue (file, collection name, preview). + +### Scenes + +| Scene | Site | +|---|---| +| `scenes/M1/M1.blend` | M1 — main AMF2 site on the farm (instrument field, AMF2 containers, farmstead, fields) | +| `scenes/S1/S1.blend` | S1 — Muscatine Island Research Farm (ECORs in corn and soy, SEBS, center pivots, Louisa plant on the horizon) | +| `scenes/S2/S2.blend` | S2 — Washington Municipal Airport, KAWG (X/Ka SACR, C-SAPR2, AWOS, Challenger 850) | +| `scenes/tests/instrument_lineup.blend` | Every instrument asset in a row | +| `scenes/tests/m1_supercell.blend` | M1 with the CM1 100 m supercell (snapshot `c100_t25`) placed as in the storm renders | +| `scenes/tests/m1_lasso_cumulus.blend` | M1 under the LASSO SGP cumulus field | +| `scenes/tests/s1_ucla_cumulus.blend` | S1 under the UCLA LES cumulus field | + +## How the linking works + +Blender can **link** data from another `.blend` instead of copying it +(*File → Link*). A linked collection stays read-only in the scene and is re-read from its +source file every time the scene opens, so fixing `instruments/KAZR/KAZR.blend` updates every +scene that uses the KAZR. All paths are stored relative to the file (`//../../instruments/...`), +which is what makes the repository portable. + +Re-usable assets (instruments, containers, vehicles, pivots, flagpole) are stored with their +root at the origin. Scenes place them with a **collection-instance empty** (named +`_inst`) carrying the location and rotation, so one asset can be placed many +times. Site-specific layers (terrain, fields, farmstead buildings, vegetation scatter) are +stored in their real-world site coordinates and linked in place. + +Common tasks: + +* **Use an asset in your own scene:** *File → Link*, browse into the `.blend`, open + `Collection`, pick the collection (e.g. `INST_KAZR`). It arrives as an instance you can move. +* **Asset Browser:** add the repository root under *Preferences → File Paths → Asset + Libraries*; all asset collections are marked as assets. +* **Pose a linked asset** (C-SAPR2 azimuth/elevation, Challenger 850 gear, flaps and fans, + AWOS wind vane): right-click the instance → *Library Override → Make → Selected & Content*, + then edit the custom properties on its `*_root` object; drivers on the parts read those + properties. The SACR azimuth/elevation is keyframed on `SACR_Azimuth`/`SACR_Elevation`. +* **Edit an asset:** open its own `.blend` and save; every scene picks up the change. +* **Make a copy you can edit locally:** *Object → Apply → Make Instances Real*, or + *Object → Relations → Make Local*. + +## Clouds + +Each cloud `.blend` has one collection per snapshot (`CLOUD_`); the VDB files sit next +to it. Volume objects read the model's own grids (CM1: `cloud`, `rain`, `ice`, `snow`, +`graup`, `cice`; LES: `lwc`). The CM1 storm shader renders each hydrometeor species with its +own scattering and uses the raw model fields (no procedural noise). + +VDBs larger than 50 MB (the three 100 m supercell snapshots) were rewritten with 16-bit +half-float storage to stay under GitHub's 100 MB file limit. Grid resolution, extent and all +species are unchanged; half precision keeps about three significant digits of the mixing +ratio, below what a volume render can show. Nothing was resampled. + +## Provenance and verification + +The library was generated from the original monolithic working files (`farm_v5.blend`, +`mirf_s1.blend`, `airport_awg.blend` and the cloud scenes) by the scripts in `tools/` +(`build_m1.py`, `build_s1.py`, `build_s2.py`, `build_clouds.py`, `build_tests.py`). The +extraction is lossless: each rebuilt scene was evaluated against its source and has the same +number of mesh instances, the same total vertex count and identical summed world positions +(reports in `tools/reports/`), and test renders match the originals to within sampling noise. +Text objects that used macOS system fonts were converted to meshes so they render the same +on any OS. + +Deliberate differences from the working files: + +* At M1 the SACR container instance is hidden (the SACR moved to S2 for DERECHOS). +* Instruments, containers and vehicles are instanced rather than embedded (see above). + +## Licences of third-party content + +* PBR texture sets in `textures/pbr/` are from [ambientCG](https://ambientcg.com) (CC0). +* Orthoimagery in `textures/imagery/` is USDA NAIP (public domain); the M1 height fields + (`hf_*.exr`) are terrain elevation grids, stored with lossless ZIP compression. +* Site signs and flags (`textures/signs/`, `textures/flags/`) carry partner and agency logos; + check their usage rules before reusing them outside DERECHOS/ARM material. diff --git a/buildings/README.md b/buildings/README.md new file mode 100644 index 0000000..62b196e --- /dev/null +++ b/buildings/README.md @@ -0,0 +1,16 @@ +# Buildings and structures + +Site buildings are stored in site coordinates; the flagpole and center pivots are re-usable (root at the origin). + +| Preview | Collection | File | +|---|---|---| +| | `Farmstead` | [`m1_farmstead.blend`](m1_farmstead.blend) (0.3 MB) | +| | `Flagpole` | [`flagpole.blend`](flagpole.blend) (0.2 MB) | +| | `SIGN_M1` | [`signs/sign_M1.blend`](signs/sign_M1.blend) (0.9 MB) | +| | `SIGN_S1` | [`signs/sign_S1.blend`](signs/sign_S1.blend) (0.9 MB) | +| | `SIGN_S2` | [`signs/sign_S2.blend`](signs/sign_S2.blend) (0.9 MB) | +| | `Pivot_P3` | [`center_pivots.blend`](center_pivots.blend) (1.5 MB) | +| | `Pivot_P1` | [`center_pivots.blend`](center_pivots.blend) (1.5 MB) | +| | `LOUISA_Station` | [`louisa_station.blend`](louisa_station.blend) (0.4 MB) | +| | `S1_MIRF_Buildings` | [`s1_mirf_buildings.blend`](s1_mirf_buildings.blend) (0.1 MB) | +| | `S2_KAWG_Buildings` | [`s2_kawg_buildings.blend`](s2_kawg_buildings.blend) (1.8 MB) | diff --git a/buildings/center_pivots.blend b/buildings/center_pivots.blend new file mode 100644 index 0000000..ebd12ef Binary files /dev/null and b/buildings/center_pivots.blend differ diff --git a/buildings/flagpole.blend b/buildings/flagpole.blend new file mode 100644 index 0000000..7a8f0eb Binary files /dev/null and b/buildings/flagpole.blend differ diff --git a/buildings/louisa_station.blend b/buildings/louisa_station.blend new file mode 100644 index 0000000..80e7dcb Binary files /dev/null and b/buildings/louisa_station.blend differ diff --git a/buildings/m1_farmstead.blend b/buildings/m1_farmstead.blend new file mode 100644 index 0000000..4d36edc Binary files /dev/null and b/buildings/m1_farmstead.blend differ diff --git a/buildings/preview/Farmstead.jpg b/buildings/preview/Farmstead.jpg new file mode 100644 index 0000000..0cc5610 Binary files /dev/null and b/buildings/preview/Farmstead.jpg differ diff --git a/buildings/preview/Flagpole.jpg b/buildings/preview/Flagpole.jpg new file mode 100644 index 0000000..e0e9afd Binary files /dev/null and b/buildings/preview/Flagpole.jpg differ diff --git a/buildings/preview/LOUISA_Station.jpg b/buildings/preview/LOUISA_Station.jpg new file mode 100644 index 0000000..fac2938 Binary files /dev/null and b/buildings/preview/LOUISA_Station.jpg differ diff --git a/buildings/preview/Pivot_P1.jpg b/buildings/preview/Pivot_P1.jpg new file mode 100644 index 0000000..a626014 Binary files /dev/null and b/buildings/preview/Pivot_P1.jpg differ diff --git a/buildings/preview/Pivot_P3.jpg b/buildings/preview/Pivot_P3.jpg new file mode 100644 index 0000000..376ce93 Binary files /dev/null and b/buildings/preview/Pivot_P3.jpg differ diff --git a/buildings/preview/S1_MIRF_Buildings.jpg b/buildings/preview/S1_MIRF_Buildings.jpg new file mode 100644 index 0000000..2119248 Binary files /dev/null and b/buildings/preview/S1_MIRF_Buildings.jpg differ diff --git a/buildings/preview/S2_KAWG_Buildings.jpg b/buildings/preview/S2_KAWG_Buildings.jpg new file mode 100644 index 0000000..638d926 Binary files /dev/null and b/buildings/preview/S2_KAWG_Buildings.jpg differ diff --git a/buildings/preview/SIGN_M1.jpg b/buildings/preview/SIGN_M1.jpg new file mode 100644 index 0000000..2bf41b1 Binary files /dev/null and b/buildings/preview/SIGN_M1.jpg differ diff --git a/buildings/preview/SIGN_S1.jpg b/buildings/preview/SIGN_S1.jpg new file mode 100644 index 0000000..a82689c Binary files /dev/null and b/buildings/preview/SIGN_S1.jpg differ diff --git a/buildings/preview/SIGN_S2.jpg b/buildings/preview/SIGN_S2.jpg new file mode 100644 index 0000000..3cc6fce Binary files /dev/null and b/buildings/preview/SIGN_S2.jpg differ diff --git a/buildings/s1_mirf_buildings.blend b/buildings/s1_mirf_buildings.blend new file mode 100644 index 0000000..b9332fb Binary files /dev/null and b/buildings/s1_mirf_buildings.blend differ diff --git a/buildings/s2_kawg_buildings.blend b/buildings/s2_kawg_buildings.blend new file mode 100644 index 0000000..b026eab Binary files /dev/null and b/buildings/s2_kawg_buildings.blend differ diff --git a/buildings/signs/sign_M1.blend b/buildings/signs/sign_M1.blend new file mode 100644 index 0000000..b91d223 Binary files /dev/null and b/buildings/signs/sign_M1.blend differ diff --git a/buildings/signs/sign_S1.blend b/buildings/signs/sign_S1.blend new file mode 100644 index 0000000..dadc5b8 Binary files /dev/null and b/buildings/signs/sign_S1.blend differ diff --git a/buildings/signs/sign_S2.blend b/buildings/signs/sign_S2.blend new file mode 100644 index 0000000..29fd55b Binary files /dev/null and b/buildings/signs/sign_S2.blend differ diff --git a/clouds/README.md b/clouds/README.md new file mode 100644 index 0000000..0e24dd4 --- /dev/null +++ b/clouds/README.md @@ -0,0 +1,37 @@ +# Clouds + +Mature snapshots; one collection per snapshot, VDB next to the .blend. Tiled LES fields (LASSO 3x3, UCLA 7x7) keep their periodic tiling. + +| Preview | Collection | File | +|---|---|---| +| | `CLOUD_bomex_t360` | [`cm1_bomex_cumulus/cm1_bomex_cumulus.blend`](cm1_bomex_cumulus/cm1_bomex_cumulus.blend) (0.1 MB) | +| | `CLOUD_bomex_t300` | [`cm1_bomex_cumulus/cm1_bomex_cumulus.blend`](cm1_bomex_cumulus/cm1_bomex_cumulus.blend) (0.1 MB) | +| | `CLOUD_bomex_t240` | [`cm1_bomex_cumulus/cm1_bomex_cumulus.blend`](cm1_bomex_cumulus/cm1_bomex_cumulus.blend) (0.1 MB) | +| | `CLOUD_supercell_s250_t60` | [`cm1_supercell/cm1_supercell.blend`](cm1_supercell/cm1_supercell.blend) (0.1 MB) | +| | `CLOUD_supercell_s250_t45` | [`cm1_supercell/cm1_supercell.blend`](cm1_supercell/cm1_supercell.blend) (0.1 MB) | +| | `CLOUD_supercell_s100_t60` | [`cm1_supercell/cm1_supercell.blend`](cm1_supercell/cm1_supercell.blend) (0.1 MB) | +| | `CLOUD_supercell_s100_t45` | [`cm1_supercell/cm1_supercell.blend`](cm1_supercell/cm1_supercell.blend) (0.1 MB) | +| | `CLOUD_supercell_c100_t25` | [`cm1_supercell/cm1_supercell.blend`](cm1_supercell/cm1_supercell.blend) (0.1 MB) | +| | `CLOUD_lasso_2000` | [`lasso_sgp_20170403/lasso_sgp_20170403.blend`](lasso_sgp_20170403/lasso_sgp_20170403.blend) (0.1 MB) | +| | `CLOUD_lasso_1900` | [`lasso_sgp_20170403/lasso_sgp_20170403.blend`](lasso_sgp_20170403/lasso_sgp_20170403.blend) (0.1 MB) | +| | `CLOUD_lasso_1800` | [`lasso_sgp_20170403/lasso_sgp_20170403.blend`](lasso_sgp_20170403/lasso_sgp_20170403.blend) (0.1 MB) | +| | `CLOUD_lasso_1740` | [`lasso_sgp_20170403/lasso_sgp_20170403.blend`](lasso_sgp_20170403/lasso_sgp_20170403.blend) (0.1 MB) | +| | `CLOUD_lasso8_2040` | [`lasso_sgp_20170403/lasso_sgp_20170403.blend`](lasso_sgp_20170403/lasso_sgp_20170403.blend) (0.1 MB) | +| | `CLOUD_ucla_t6600` | [`ucla_cumulus/ucla_cumulus.blend`](ucla_cumulus/ucla_cumulus.blend) (0.1 MB) | + +VDB files: + +* `cm1_bomex_cumulus/bomex50_t240_x5.vdb` (2.9 MB) +* `cm1_bomex_cumulus/bomex50_t300_x5.vdb` (3.2 MB) +* `cm1_bomex_cumulus/bomex50_t360_x5.vdb` (2.4 MB) +* `cm1_supercell/c100_t25_sp.vdb` (80.8 MB) +* `cm1_supercell/s100_t45_sp.vdb` (42.4 MB) +* `cm1_supercell/s100_t60_sp.vdb` (77.5 MB) +* `cm1_supercell/s250_t45_sp.vdb` (5.5 MB) +* `cm1_supercell/s250_t60_sp.vdb` (12.6 MB) +* `lasso_sgp_20170403/lasso8_2040_lwc.vdb` (20.2 MB) +* `lasso_sgp_20170403/lasso_1740_lwc.vdb` (2.2 MB) +* `lasso_sgp_20170403/lwc_0145.vdb` (2.1 MB) +* `lasso_sgp_20170403/lwc_0193.vdb` (1.2 MB) +* `lasso_sgp_20170403/lwc_0241.vdb` (0.4 MB) +* `ucla_cumulus/ucla_t6600_m.vdb` (0.5 MB) diff --git a/clouds/cm1_bomex_cumulus/bomex50_t240_x5.vdb b/clouds/cm1_bomex_cumulus/bomex50_t240_x5.vdb new file mode 100644 index 0000000..d4e0658 Binary files /dev/null and b/clouds/cm1_bomex_cumulus/bomex50_t240_x5.vdb differ diff --git a/clouds/cm1_bomex_cumulus/bomex50_t300_x5.vdb b/clouds/cm1_bomex_cumulus/bomex50_t300_x5.vdb new file mode 100644 index 0000000..c1fe48d Binary files /dev/null and b/clouds/cm1_bomex_cumulus/bomex50_t300_x5.vdb differ diff --git a/clouds/cm1_bomex_cumulus/bomex50_t360_x5.vdb b/clouds/cm1_bomex_cumulus/bomex50_t360_x5.vdb new file mode 100644 index 0000000..ffb378d Binary files /dev/null and b/clouds/cm1_bomex_cumulus/bomex50_t360_x5.vdb differ diff --git a/clouds/cm1_bomex_cumulus/cm1_bomex_cumulus.blend b/clouds/cm1_bomex_cumulus/cm1_bomex_cumulus.blend new file mode 100644 index 0000000..ac4e6ee Binary files /dev/null and b/clouds/cm1_bomex_cumulus/cm1_bomex_cumulus.blend differ diff --git a/clouds/cm1_supercell/c100_t25_sp.vdb b/clouds/cm1_supercell/c100_t25_sp.vdb new file mode 100644 index 0000000..40f4c05 Binary files /dev/null and b/clouds/cm1_supercell/c100_t25_sp.vdb differ diff --git a/clouds/cm1_supercell/cm1_supercell.blend b/clouds/cm1_supercell/cm1_supercell.blend new file mode 100644 index 0000000..5b90b9d Binary files /dev/null and b/clouds/cm1_supercell/cm1_supercell.blend differ diff --git a/clouds/cm1_supercell/s100_t45_sp.vdb b/clouds/cm1_supercell/s100_t45_sp.vdb new file mode 100644 index 0000000..87f28f7 Binary files /dev/null and b/clouds/cm1_supercell/s100_t45_sp.vdb differ diff --git a/clouds/cm1_supercell/s100_t60_sp.vdb b/clouds/cm1_supercell/s100_t60_sp.vdb new file mode 100644 index 0000000..d877923 Binary files /dev/null and b/clouds/cm1_supercell/s100_t60_sp.vdb differ diff --git a/clouds/cm1_supercell/s250_t45_sp.vdb b/clouds/cm1_supercell/s250_t45_sp.vdb new file mode 100644 index 0000000..e0053e3 Binary files /dev/null and b/clouds/cm1_supercell/s250_t45_sp.vdb differ diff --git a/clouds/cm1_supercell/s250_t60_sp.vdb b/clouds/cm1_supercell/s250_t60_sp.vdb new file mode 100644 index 0000000..a480305 Binary files /dev/null and b/clouds/cm1_supercell/s250_t60_sp.vdb differ diff --git a/clouds/lasso_sgp_20170403/lasso8_2040_lwc.vdb b/clouds/lasso_sgp_20170403/lasso8_2040_lwc.vdb new file mode 100644 index 0000000..083ae20 Binary files /dev/null and b/clouds/lasso_sgp_20170403/lasso8_2040_lwc.vdb differ diff --git a/clouds/lasso_sgp_20170403/lasso_1740_lwc.vdb b/clouds/lasso_sgp_20170403/lasso_1740_lwc.vdb new file mode 100644 index 0000000..b433b57 Binary files /dev/null and b/clouds/lasso_sgp_20170403/lasso_1740_lwc.vdb differ diff --git a/clouds/lasso_sgp_20170403/lasso_sgp_20170403.blend b/clouds/lasso_sgp_20170403/lasso_sgp_20170403.blend new file mode 100644 index 0000000..260ade8 Binary files /dev/null and b/clouds/lasso_sgp_20170403/lasso_sgp_20170403.blend differ diff --git a/clouds/lasso_sgp_20170403/lwc_0145.vdb b/clouds/lasso_sgp_20170403/lwc_0145.vdb new file mode 100644 index 0000000..af3c12d Binary files /dev/null and b/clouds/lasso_sgp_20170403/lwc_0145.vdb differ diff --git a/clouds/lasso_sgp_20170403/lwc_0193.vdb b/clouds/lasso_sgp_20170403/lwc_0193.vdb new file mode 100644 index 0000000..c0339c0 Binary files /dev/null and b/clouds/lasso_sgp_20170403/lwc_0193.vdb differ diff --git a/clouds/lasso_sgp_20170403/lwc_0241.vdb b/clouds/lasso_sgp_20170403/lwc_0241.vdb new file mode 100644 index 0000000..7cd6385 Binary files /dev/null and b/clouds/lasso_sgp_20170403/lwc_0241.vdb differ diff --git a/clouds/preview/bomex_t240.jpg b/clouds/preview/bomex_t240.jpg new file mode 100644 index 0000000..4172a89 Binary files /dev/null and b/clouds/preview/bomex_t240.jpg differ diff --git a/clouds/preview/bomex_t300.jpg b/clouds/preview/bomex_t300.jpg new file mode 100644 index 0000000..7e78fda Binary files /dev/null and b/clouds/preview/bomex_t300.jpg differ diff --git a/clouds/preview/bomex_t360.jpg b/clouds/preview/bomex_t360.jpg new file mode 100644 index 0000000..1d3c37b Binary files /dev/null and b/clouds/preview/bomex_t360.jpg differ diff --git a/clouds/preview/lasso8_2040.jpg b/clouds/preview/lasso8_2040.jpg new file mode 100644 index 0000000..c1135da Binary files /dev/null and b/clouds/preview/lasso8_2040.jpg differ diff --git a/clouds/preview/lasso_1740.jpg b/clouds/preview/lasso_1740.jpg new file mode 100644 index 0000000..d137575 Binary files /dev/null and b/clouds/preview/lasso_1740.jpg differ diff --git a/clouds/preview/lasso_1800.jpg b/clouds/preview/lasso_1800.jpg new file mode 100644 index 0000000..e9940c3 Binary files /dev/null and b/clouds/preview/lasso_1800.jpg differ diff --git a/clouds/preview/lasso_1900.jpg b/clouds/preview/lasso_1900.jpg new file mode 100644 index 0000000..67e3238 Binary files /dev/null and b/clouds/preview/lasso_1900.jpg differ diff --git a/clouds/preview/lasso_2000.jpg b/clouds/preview/lasso_2000.jpg new file mode 100644 index 0000000..9b119d4 Binary files /dev/null and b/clouds/preview/lasso_2000.jpg differ diff --git a/clouds/preview/supercell_c100_t25.jpg b/clouds/preview/supercell_c100_t25.jpg new file mode 100644 index 0000000..360c685 Binary files /dev/null and b/clouds/preview/supercell_c100_t25.jpg differ diff --git a/clouds/preview/supercell_s100_t45.jpg b/clouds/preview/supercell_s100_t45.jpg new file mode 100644 index 0000000..8892002 Binary files /dev/null and b/clouds/preview/supercell_s100_t45.jpg differ diff --git a/clouds/preview/supercell_s100_t60.jpg b/clouds/preview/supercell_s100_t60.jpg new file mode 100644 index 0000000..45f4792 Binary files /dev/null and b/clouds/preview/supercell_s100_t60.jpg differ diff --git a/clouds/preview/supercell_s250_t45.jpg b/clouds/preview/supercell_s250_t45.jpg new file mode 100644 index 0000000..a4edd2f Binary files /dev/null and b/clouds/preview/supercell_s250_t45.jpg differ diff --git a/clouds/preview/supercell_s250_t60.jpg b/clouds/preview/supercell_s250_t60.jpg new file mode 100644 index 0000000..6c01225 Binary files /dev/null and b/clouds/preview/supercell_s250_t60.jpg differ diff --git a/clouds/preview/ucla_t6600.jpg b/clouds/preview/ucla_t6600.jpg new file mode 100644 index 0000000..74ac03a Binary files /dev/null and b/clouds/preview/ucla_t6600.jpg differ diff --git a/clouds/ucla_cumulus/ucla_cumulus.blend b/clouds/ucla_cumulus/ucla_cumulus.blend new file mode 100644 index 0000000..e7377ba Binary files /dev/null and b/clouds/ucla_cumulus/ucla_cumulus.blend differ diff --git a/clouds/ucla_cumulus/ucla_t6600_m.vdb b/clouds/ucla_cumulus/ucla_t6600_m.vdb new file mode 100644 index 0000000..8fe55ba Binary files /dev/null and b/clouds/ucla_cumulus/ucla_t6600_m.vdb differ diff --git a/containers/README.md b/containers/README.md new file mode 100644 index 0000000..967ea45 --- /dev/null +++ b/containers/README.md @@ -0,0 +1,18 @@ +# Containers + +AMF2 containers and shelters with their roof-mounted hardware. `CONT_7_SACR_S2` is the SACR container as configured at S2 (KAWG). + +| Preview | Collection | File | +|---|---|---| +| | `CONT_RentalContainer` | [`amf2_containers.blend`](amf2_containers.blend) (0.2 MB) | +| | `CONT_OfficeShelter` | [`amf2_containers.blend`](amf2_containers.blend) (0.2 MB) | +| | `CONT_AOS_Platform` | [`amf2_containers.blend`](amf2_containers.blend) (0.2 MB) | +| | `CONT_8_STORAGE` | [`amf2_containers.blend`](amf2_containers.blend) (0.2 MB) | +| | `CONT_7_SACR` | [`amf2_containers.blend`](amf2_containers.blend) (0.2 MB) | +| | `CONT_6_KAZR` | [`amf2_containers.blend`](amf2_containers.blend) (0.2 MB) | +| | `CONT_5_LIDAR` | [`amf2_containers.blend`](amf2_containers.blend) (0.2 MB) | +| | `CONT_4_RADIOMETERS` | [`amf2_containers.blend`](amf2_containers.blend) (0.2 MB) | +| | `CONT_3_OPS` | [`amf2_containers.blend`](amf2_containers.blend) (0.2 MB) | +| | `CONT_2_AOS_B` | [`amf2_containers.blend`](amf2_containers.blend) (0.2 MB) | +| | `CONT_1_AOS_A` | [`amf2_containers.blend`](amf2_containers.blend) (0.2 MB) | +| | `CONT_7_SACR_S2` | [`sacr_container_s2.blend`](sacr_container_s2.blend) (0.1 MB) | diff --git a/containers/amf2_containers.blend b/containers/amf2_containers.blend new file mode 100644 index 0000000..bd2015b Binary files /dev/null and b/containers/amf2_containers.blend differ diff --git a/containers/preview/CONT_1_AOS_A.jpg b/containers/preview/CONT_1_AOS_A.jpg new file mode 100644 index 0000000..4d70211 Binary files /dev/null and b/containers/preview/CONT_1_AOS_A.jpg differ diff --git a/containers/preview/CONT_2_AOS_B.jpg b/containers/preview/CONT_2_AOS_B.jpg new file mode 100644 index 0000000..55446c8 Binary files /dev/null and b/containers/preview/CONT_2_AOS_B.jpg differ diff --git a/containers/preview/CONT_3_OPS.jpg b/containers/preview/CONT_3_OPS.jpg new file mode 100644 index 0000000..f8e4ea5 Binary files /dev/null and b/containers/preview/CONT_3_OPS.jpg differ diff --git a/containers/preview/CONT_4_RADIOMETERS.jpg b/containers/preview/CONT_4_RADIOMETERS.jpg new file mode 100644 index 0000000..92177e5 Binary files /dev/null and b/containers/preview/CONT_4_RADIOMETERS.jpg differ diff --git a/containers/preview/CONT_5_LIDAR.jpg b/containers/preview/CONT_5_LIDAR.jpg new file mode 100644 index 0000000..555a511 Binary files /dev/null and b/containers/preview/CONT_5_LIDAR.jpg differ diff --git a/containers/preview/CONT_6_KAZR.jpg b/containers/preview/CONT_6_KAZR.jpg new file mode 100644 index 0000000..6d6411b Binary files /dev/null and b/containers/preview/CONT_6_KAZR.jpg differ diff --git a/containers/preview/CONT_7_SACR.jpg b/containers/preview/CONT_7_SACR.jpg new file mode 100644 index 0000000..4e29353 Binary files /dev/null and b/containers/preview/CONT_7_SACR.jpg differ diff --git a/containers/preview/CONT_7_SACR_S2.jpg b/containers/preview/CONT_7_SACR_S2.jpg new file mode 100644 index 0000000..742af49 Binary files /dev/null and b/containers/preview/CONT_7_SACR_S2.jpg differ diff --git a/containers/preview/CONT_8_STORAGE.jpg b/containers/preview/CONT_8_STORAGE.jpg new file mode 100644 index 0000000..b982aae Binary files /dev/null and b/containers/preview/CONT_8_STORAGE.jpg differ diff --git a/containers/preview/CONT_AOS_Platform.jpg b/containers/preview/CONT_AOS_Platform.jpg new file mode 100644 index 0000000..d58fdb6 Binary files /dev/null and b/containers/preview/CONT_AOS_Platform.jpg differ diff --git a/containers/preview/CONT_OfficeShelter.jpg b/containers/preview/CONT_OfficeShelter.jpg new file mode 100644 index 0000000..d39e953 Binary files /dev/null and b/containers/preview/CONT_OfficeShelter.jpg differ diff --git a/containers/preview/CONT_RentalContainer.jpg b/containers/preview/CONT_RentalContainer.jpg new file mode 100644 index 0000000..5a1c229 Binary files /dev/null and b/containers/preview/CONT_RentalContainer.jpg differ diff --git a/containers/sacr_container_s2.blend b/containers/sacr_container_s2.blend new file mode 100644 index 0000000..cae6a01 Binary files /dev/null and b/containers/sacr_container_s2.blend differ diff --git a/instruments/AERI/AERI.blend b/instruments/AERI/AERI.blend new file mode 100644 index 0000000..1b9320f Binary files /dev/null and b/instruments/AERI/AERI.blend differ diff --git a/instruments/AOSMET/AOSMET.blend b/instruments/AOSMET/AOSMET.blend new file mode 100644 index 0000000..b94bfff Binary files /dev/null and b/instruments/AOSMET/AOSMET.blend differ diff --git a/instruments/ASI/ASI.blend b/instruments/ASI/ASI.blend new file mode 100644 index 0000000..036351e Binary files /dev/null and b/instruments/ASI/ASI.blend differ diff --git a/instruments/AWOS/AWOS.blend b/instruments/AWOS/AWOS.blend new file mode 100644 index 0000000..c13a8e1 Binary files /dev/null and b/instruments/AWOS/AWOS.blend differ diff --git a/instruments/CEIL/CEIL.blend b/instruments/CEIL/CEIL.blend new file mode 100644 index 0000000..dacf413 Binary files /dev/null and b/instruments/CEIL/CEIL.blend differ diff --git a/instruments/CSAPR2/CSAPR2.blend b/instruments/CSAPR2/CSAPR2.blend new file mode 100644 index 0000000..6f39c17 Binary files /dev/null and b/instruments/CSAPR2/CSAPR2.blend differ diff --git a/instruments/CSPHOT/CSPHOT.blend b/instruments/CSPHOT/CSPHOT.blend new file mode 100644 index 0000000..8e34c2b Binary files /dev/null and b/instruments/CSPHOT/CSPHOT.blend differ diff --git a/instruments/DL/DL.blend b/instruments/DL/DL.blend new file mode 100644 index 0000000..4c0b67f Binary files /dev/null and b/instruments/DL/DL.blend differ diff --git a/instruments/ECOR/ECOR.blend b/instruments/ECOR/ECOR.blend new file mode 100644 index 0000000..f59aa69 Binary files /dev/null and b/instruments/ECOR/ECOR.blend differ diff --git a/instruments/IRT/IRT.blend b/instruments/IRT/IRT.blend new file mode 100644 index 0000000..06d9923 Binary files /dev/null and b/instruments/IRT/IRT.blend differ diff --git a/instruments/KAZR/KAZR.blend b/instruments/KAZR/KAZR.blend new file mode 100644 index 0000000..3b4d9fb Binary files /dev/null and b/instruments/KAZR/KAZR.blend differ diff --git a/instruments/LDIS/LDIS.blend b/instruments/LDIS/LDIS.blend new file mode 100644 index 0000000..18657e7 Binary files /dev/null and b/instruments/LDIS/LDIS.blend differ diff --git a/instruments/MAWS/MAWS.blend b/instruments/MAWS/MAWS.blend new file mode 100644 index 0000000..da035bf Binary files /dev/null and b/instruments/MAWS/MAWS.blend differ diff --git a/instruments/MET/MET.blend b/instruments/MET/MET.blend new file mode 100644 index 0000000..f5fd964 Binary files /dev/null and b/instruments/MET/MET.blend differ diff --git a/instruments/MFR/MFR.blend b/instruments/MFR/MFR.blend new file mode 100644 index 0000000..e276bad Binary files /dev/null and b/instruments/MFR/MFR.blend differ diff --git a/instruments/MFRSR/MFRSR.blend b/instruments/MFRSR/MFRSR.blend new file mode 100644 index 0000000..33b1e32 Binary files /dev/null and b/instruments/MFRSR/MFRSR.blend differ diff --git a/instruments/MPL/MPL.blend b/instruments/MPL/MPL.blend new file mode 100644 index 0000000..f7e2279 Binary files /dev/null and b/instruments/MPL/MPL.blend differ diff --git a/instruments/MWR3C/MWR3C.blend b/instruments/MWR3C/MWR3C.blend new file mode 100644 index 0000000..a4bd282 Binary files /dev/null and b/instruments/MWR3C/MWR3C.blend differ diff --git a/instruments/README.md b/instruments/README.md new file mode 100644 index 0000000..c6a9d25 --- /dev/null +++ b/instruments/README.md @@ -0,0 +1,31 @@ +# Instruments + +One file per instrument; link the `INST_*` (or `CSAPR2`) collection. Root at the origin. + +| Preview | Collection | File | +|---|---|---| +| | `INST_AERI` | [`AERI/AERI.blend`](AERI/AERI.blend) (0.2 MB) | +| | `INST_AOSMET` | [`AOSMET/AOSMET.blend`](AOSMET/AOSMET.blend) (0.1 MB) | +| | `INST_ASI` | [`ASI/ASI.blend`](ASI/ASI.blend) (0.2 MB) | +| | `INST_AWOS` | [`AWOS/AWOS.blend`](AWOS/AWOS.blend) (0.3 MB) | +| | `INST_CEIL` | [`CEIL/CEIL.blend`](CEIL/CEIL.blend) (0.1 MB) | +| | `CSAPR2` | [`CSAPR2/CSAPR2.blend`](CSAPR2/CSAPR2.blend) (1.2 MB) | +| | `INST_CSPHOT` | [`CSPHOT/CSPHOT.blend`](CSPHOT/CSPHOT.blend) (0.2 MB) | +| | `INST_DL` | [`DL/DL.blend`](DL/DL.blend) (0.2 MB) | +| | `INST_ECOR_4m` | [`ECOR/ECOR.blend`](ECOR/ECOR.blend) (0.3 MB) | +| | `INST_ECOR` | [`ECOR/ECOR.blend`](ECOR/ECOR.blend) (0.3 MB) | +| | `INST_IRT` | [`IRT/IRT.blend`](IRT/IRT.blend) (0.1 MB) | +| | `INST_KAZR` | [`KAZR/KAZR.blend`](KAZR/KAZR.blend) (0.2 MB) | +| | `INST_LDIS` | [`LDIS/LDIS.blend`](LDIS/LDIS.blend) (0.1 MB) | +| | `INST_MAWS` | [`MAWS/MAWS.blend`](MAWS/MAWS.blend) (0.2 MB) | +| | `INST_MET` | [`MET/MET.blend`](MET/MET.blend) (0.3 MB) | +| | `INST_MFR` | [`MFR/MFR.blend`](MFR/MFR.blend) (0.1 MB) | +| | `INST_MFRSR` | [`MFRSR/MFRSR.blend`](MFRSR/MFRSR.blend) (0.1 MB) | +| | `INST_MPL` | [`MPL/MPL.blend`](MPL/MPL.blend) (0.1 MB) | +| | `INST_MWR3C` | [`MWR3C/MWR3C.blend`](MWR3C/MWR3C.blend) (0.2 MB) | +| | `INST_RWP` | [`RWP/RWP.blend`](RWP/RWP.blend) (0.3 MB) | +| | `INST_SEBS` | [`SEBS/SEBS.blend`](SEBS/SEBS.blend) (0.2 MB) | +| | `INST_SIRS` | [`SIRS/SIRS.blend`](SIRS/SIRS.blend) (0.3 MB) | +| | `INST_SONDE` | [`SONDE/SONDE.blend`](SONDE/SONDE.blend) (0.2 MB) | +| | `INST_VDIS` | [`VDIS/VDIS.blend`](VDIS/VDIS.blend) (0.1 MB) | +| | `INST_WB` | [`WB/WB.blend`](WB/WB.blend) (0.2 MB) | diff --git a/instruments/RWP/RWP.blend b/instruments/RWP/RWP.blend new file mode 100644 index 0000000..eea1375 Binary files /dev/null and b/instruments/RWP/RWP.blend differ diff --git a/instruments/SEBS/SEBS.blend b/instruments/SEBS/SEBS.blend new file mode 100644 index 0000000..f583b04 Binary files /dev/null and b/instruments/SEBS/SEBS.blend differ diff --git a/instruments/SIRS/SIRS.blend b/instruments/SIRS/SIRS.blend new file mode 100644 index 0000000..87a42c0 Binary files /dev/null and b/instruments/SIRS/SIRS.blend differ diff --git a/instruments/SONDE/SONDE.blend b/instruments/SONDE/SONDE.blend new file mode 100644 index 0000000..2798460 Binary files /dev/null and b/instruments/SONDE/SONDE.blend differ diff --git a/instruments/VDIS/VDIS.blend b/instruments/VDIS/VDIS.blend new file mode 100644 index 0000000..4504c02 Binary files /dev/null and b/instruments/VDIS/VDIS.blend differ diff --git a/instruments/WB/WB.blend b/instruments/WB/WB.blend new file mode 100644 index 0000000..41c34c6 Binary files /dev/null and b/instruments/WB/WB.blend differ diff --git a/instruments/preview/AERI.jpg b/instruments/preview/AERI.jpg new file mode 100644 index 0000000..f8088cf Binary files /dev/null and b/instruments/preview/AERI.jpg differ diff --git a/instruments/preview/AOSMET.jpg b/instruments/preview/AOSMET.jpg new file mode 100644 index 0000000..53a12fb Binary files /dev/null and b/instruments/preview/AOSMET.jpg differ diff --git a/instruments/preview/ASI.jpg b/instruments/preview/ASI.jpg new file mode 100644 index 0000000..a2b6dfd Binary files /dev/null and b/instruments/preview/ASI.jpg differ diff --git a/instruments/preview/AWOS.jpg b/instruments/preview/AWOS.jpg new file mode 100644 index 0000000..2053dd7 Binary files /dev/null and b/instruments/preview/AWOS.jpg differ diff --git a/instruments/preview/CEIL.jpg b/instruments/preview/CEIL.jpg new file mode 100644 index 0000000..ee59edd Binary files /dev/null and b/instruments/preview/CEIL.jpg differ diff --git a/instruments/preview/CSAPR2.jpg b/instruments/preview/CSAPR2.jpg new file mode 100644 index 0000000..e336c98 Binary files /dev/null and b/instruments/preview/CSAPR2.jpg differ diff --git a/instruments/preview/CSPHOT.jpg b/instruments/preview/CSPHOT.jpg new file mode 100644 index 0000000..ef06bf3 Binary files /dev/null and b/instruments/preview/CSPHOT.jpg differ diff --git a/instruments/preview/DL.jpg b/instruments/preview/DL.jpg new file mode 100644 index 0000000..e7610ff Binary files /dev/null and b/instruments/preview/DL.jpg differ diff --git a/instruments/preview/ECOR.jpg b/instruments/preview/ECOR.jpg new file mode 100644 index 0000000..9795630 Binary files /dev/null and b/instruments/preview/ECOR.jpg differ diff --git a/instruments/preview/ECOR_4m.jpg b/instruments/preview/ECOR_4m.jpg new file mode 100644 index 0000000..abb9d7b Binary files /dev/null and b/instruments/preview/ECOR_4m.jpg differ diff --git a/instruments/preview/IRT.jpg b/instruments/preview/IRT.jpg new file mode 100644 index 0000000..d3a5b35 Binary files /dev/null and b/instruments/preview/IRT.jpg differ diff --git a/instruments/preview/KAZR.jpg b/instruments/preview/KAZR.jpg new file mode 100644 index 0000000..1378ecc Binary files /dev/null and b/instruments/preview/KAZR.jpg differ diff --git a/instruments/preview/LDIS.jpg b/instruments/preview/LDIS.jpg new file mode 100644 index 0000000..fec9f61 Binary files /dev/null and b/instruments/preview/LDIS.jpg differ diff --git a/instruments/preview/MAWS.jpg b/instruments/preview/MAWS.jpg new file mode 100644 index 0000000..869297d Binary files /dev/null and b/instruments/preview/MAWS.jpg differ diff --git a/instruments/preview/MET.jpg b/instruments/preview/MET.jpg new file mode 100644 index 0000000..e12f44a Binary files /dev/null and b/instruments/preview/MET.jpg differ diff --git a/instruments/preview/MFR.jpg b/instruments/preview/MFR.jpg new file mode 100644 index 0000000..e4972be Binary files /dev/null and b/instruments/preview/MFR.jpg differ diff --git a/instruments/preview/MFRSR.jpg b/instruments/preview/MFRSR.jpg new file mode 100644 index 0000000..3c12ec7 Binary files /dev/null and b/instruments/preview/MFRSR.jpg differ diff --git a/instruments/preview/MPL.jpg b/instruments/preview/MPL.jpg new file mode 100644 index 0000000..13207b3 Binary files /dev/null and b/instruments/preview/MPL.jpg differ diff --git a/instruments/preview/MWR3C.jpg b/instruments/preview/MWR3C.jpg new file mode 100644 index 0000000..609c5f3 Binary files /dev/null and b/instruments/preview/MWR3C.jpg differ diff --git a/instruments/preview/RWP.jpg b/instruments/preview/RWP.jpg new file mode 100644 index 0000000..91140b0 Binary files /dev/null and b/instruments/preview/RWP.jpg differ diff --git a/instruments/preview/SEBS.jpg b/instruments/preview/SEBS.jpg new file mode 100644 index 0000000..e129ee9 Binary files /dev/null and b/instruments/preview/SEBS.jpg differ diff --git a/instruments/preview/SIRS.jpg b/instruments/preview/SIRS.jpg new file mode 100644 index 0000000..e864c75 Binary files /dev/null and b/instruments/preview/SIRS.jpg differ diff --git a/instruments/preview/SONDE.jpg b/instruments/preview/SONDE.jpg new file mode 100644 index 0000000..7b63297 Binary files /dev/null and b/instruments/preview/SONDE.jpg differ diff --git a/instruments/preview/VDIS.jpg b/instruments/preview/VDIS.jpg new file mode 100644 index 0000000..58e2f14 Binary files /dev/null and b/instruments/preview/VDIS.jpg differ diff --git a/instruments/preview/WB.jpg b/instruments/preview/WB.jpg new file mode 100644 index 0000000..9f45e12 Binary files /dev/null and b/instruments/preview/WB.jpg differ diff --git a/plants/README.md b/plants/README.md new file mode 100644 index 0000000..6770a1d --- /dev/null +++ b/plants/README.md @@ -0,0 +1,18 @@ +# Plants + +Prototype collections used by the geometry-node scatterers in the site layers. `_HD` sets are the high-detail trees used at S1/S2; `_S2` grasses are the KAWG lawn variants. + +| Preview | Collection | File | +|---|---|---| +| | `CornVariants` | [`crops.blend`](crops.blend) (0.7 MB) | +| | `SoyVariants` | [`crops.blend`](crops.blend) (0.7 MB) | +| | `GrassVariants` | [`grasses.blend`](grasses.blend) (0.3 MB) | +| | `TallGrassVariants` | [`grasses.blend`](grasses.blend) (0.3 MB) | +| | `GrassVariants_S2` | [`grasses_s2.blend`](grasses_s2.blend) (0.3 MB) | +| | `TallGrassVariants_S2` | [`grasses_s2.blend`](grasses_s2.blend) (0.3 MB) | +| | `TreeVariants` | [`trees.blend`](trees.blend) (3.4 MB) | +| | `TV_Decid_HD` | [`trees_hd.blend`](trees_hd.blend) (42.9 MB) | +| | `TV_Spruce_HD` | [`trees_hd.blend`](trees_hd.blend) (42.9 MB) | +| | `TV_DecidBaked_HD` | [`trees_hd.blend`](trees_hd.blend) (42.9 MB) | +| | `TV_Far_HD` | [`trees_hd.blend`](trees_hd.blend) (42.9 MB) | +| | `NativeFlowerVariants` | [`native_flowers.blend`](native_flowers.blend) (0.2 MB) | diff --git a/plants/crops.blend b/plants/crops.blend new file mode 100644 index 0000000..b21c01f Binary files /dev/null and b/plants/crops.blend differ diff --git a/plants/grasses.blend b/plants/grasses.blend new file mode 100644 index 0000000..24f3fb6 Binary files /dev/null and b/plants/grasses.blend differ diff --git a/plants/grasses_s2.blend b/plants/grasses_s2.blend new file mode 100644 index 0000000..6b7cebd Binary files /dev/null and b/plants/grasses_s2.blend differ diff --git a/plants/native_flowers.blend b/plants/native_flowers.blend new file mode 100644 index 0000000..f9b6fb7 Binary files /dev/null and b/plants/native_flowers.blend differ diff --git a/plants/preview/CornVariants.jpg b/plants/preview/CornVariants.jpg new file mode 100644 index 0000000..5c92574 Binary files /dev/null and b/plants/preview/CornVariants.jpg differ diff --git a/plants/preview/GrassVariants.jpg b/plants/preview/GrassVariants.jpg new file mode 100644 index 0000000..b23bf11 Binary files /dev/null and b/plants/preview/GrassVariants.jpg differ diff --git a/plants/preview/GrassVariants_S2.jpg b/plants/preview/GrassVariants_S2.jpg new file mode 100644 index 0000000..1fcc2ab Binary files /dev/null and b/plants/preview/GrassVariants_S2.jpg differ diff --git a/plants/preview/NativeFlowerVariants.jpg b/plants/preview/NativeFlowerVariants.jpg new file mode 100644 index 0000000..7614af9 Binary files /dev/null and b/plants/preview/NativeFlowerVariants.jpg differ diff --git a/plants/preview/SoyVariants.jpg b/plants/preview/SoyVariants.jpg new file mode 100644 index 0000000..d1fdb1d Binary files /dev/null and b/plants/preview/SoyVariants.jpg differ diff --git a/plants/preview/TV_DecidBaked_HD.jpg b/plants/preview/TV_DecidBaked_HD.jpg new file mode 100644 index 0000000..98dee67 Binary files /dev/null and b/plants/preview/TV_DecidBaked_HD.jpg differ diff --git a/plants/preview/TV_Decid_HD.jpg b/plants/preview/TV_Decid_HD.jpg new file mode 100644 index 0000000..9b12d60 Binary files /dev/null and b/plants/preview/TV_Decid_HD.jpg differ diff --git a/plants/preview/TV_Far_HD.jpg b/plants/preview/TV_Far_HD.jpg new file mode 100644 index 0000000..f0492be Binary files /dev/null and b/plants/preview/TV_Far_HD.jpg differ diff --git a/plants/preview/TV_Spruce_HD.jpg b/plants/preview/TV_Spruce_HD.jpg new file mode 100644 index 0000000..e0cc899 Binary files /dev/null and b/plants/preview/TV_Spruce_HD.jpg differ diff --git a/plants/preview/TallGrassVariants.jpg b/plants/preview/TallGrassVariants.jpg new file mode 100644 index 0000000..da374bf Binary files /dev/null and b/plants/preview/TallGrassVariants.jpg differ diff --git a/plants/preview/TallGrassVariants_S2.jpg b/plants/preview/TallGrassVariants_S2.jpg new file mode 100644 index 0000000..336df80 Binary files /dev/null and b/plants/preview/TallGrassVariants_S2.jpg differ diff --git a/plants/preview/TreeVariants.jpg b/plants/preview/TreeVariants.jpg new file mode 100644 index 0000000..e1b86c8 Binary files /dev/null and b/plants/preview/TreeVariants.jpg differ diff --git a/plants/trees.blend b/plants/trees.blend new file mode 100644 index 0000000..fb73a19 Binary files /dev/null and b/plants/trees.blend differ diff --git a/plants/trees_hd.blend b/plants/trees_hd.blend new file mode 100644 index 0000000..c209c2d Binary files /dev/null and b/plants/trees_hd.blend differ diff --git a/scenes/M1/M1.blend b/scenes/M1/M1.blend new file mode 100644 index 0000000..e34d96c Binary files /dev/null and b/scenes/M1/M1.blend differ diff --git a/scenes/M1/layers/m1_amf2_site.blend b/scenes/M1/layers/m1_amf2_site.blend new file mode 100644 index 0000000..f7e05c2 Binary files /dev/null and b/scenes/M1/layers/m1_amf2_site.blend differ diff --git a/scenes/M1/layers/m1_fields.blend b/scenes/M1/layers/m1_fields.blend new file mode 100644 index 0000000..7046b57 Binary files /dev/null and b/scenes/M1/layers/m1_fields.blend differ diff --git a/scenes/M1/layers/m1_ground.blend b/scenes/M1/layers/m1_ground.blend new file mode 100644 index 0000000..053ae9e Binary files /dev/null and b/scenes/M1/layers/m1_ground.blend differ diff --git a/scenes/README.md b/scenes/README.md new file mode 100644 index 0000000..9112867 --- /dev/null +++ b/scenes/README.md @@ -0,0 +1,30 @@ +# Scenes + +Each site scene is a thin file holding cameras, lights, world and render settings; everything else is linked from the asset folders and from `layers/` (terrain, fields, vegetation, site infrastructure in site coordinates). + +## M1 + +`M1/M1.blend` (2.3 MB) — layers: `M1/layers/m1_amf2_site.blend` (0.2 MB), `M1/layers/m1_fields.blend` (11.8 MB), `M1/layers/m1_ground.blend` (45.4 MB) + + + +## S1 + +`S1/S1.blend` (0.1 MB) — layers: `S1/layers/s1_terrain.blend` (41.2 MB), `S1/layers/s1_vegetation.blend` (8.4 MB) + + + +## S2 + +`S2/S2.blend` (0.1 MB) — layers: `S2/layers/s2_power_roads.blend` (0.2 MB), `S2/layers/s2_terrain.blend` (47.9 MB), `S2/layers/s2_vegetation.blend` (40.9 MB) + + + +## Test scenes + +| Scene | Preview | +|---|---| +| `tests/instrument_lineup.blend` | | +| `tests/m1_lasso_cumulus.blend` | | +| `tests/m1_supercell.blend` | | +| `tests/s1_ucla_cumulus.blend` | | diff --git a/scenes/S1/S1.blend b/scenes/S1/S1.blend new file mode 100644 index 0000000..1716efb Binary files /dev/null and b/scenes/S1/S1.blend differ diff --git a/scenes/S1/layers/s1_terrain.blend b/scenes/S1/layers/s1_terrain.blend new file mode 100644 index 0000000..7dc530f Binary files /dev/null and b/scenes/S1/layers/s1_terrain.blend differ diff --git a/scenes/S1/layers/s1_vegetation.blend b/scenes/S1/layers/s1_vegetation.blend new file mode 100644 index 0000000..59fbb3f Binary files /dev/null and b/scenes/S1/layers/s1_vegetation.blend differ diff --git a/scenes/S2/S2.blend b/scenes/S2/S2.blend new file mode 100644 index 0000000..98d86c5 Binary files /dev/null and b/scenes/S2/S2.blend differ diff --git a/scenes/S2/layers/s2_power_roads.blend b/scenes/S2/layers/s2_power_roads.blend new file mode 100644 index 0000000..7894a81 Binary files /dev/null and b/scenes/S2/layers/s2_power_roads.blend differ diff --git a/scenes/S2/layers/s2_terrain.blend b/scenes/S2/layers/s2_terrain.blend new file mode 100644 index 0000000..898c782 Binary files /dev/null and b/scenes/S2/layers/s2_terrain.blend differ diff --git a/scenes/S2/layers/s2_vegetation.blend b/scenes/S2/layers/s2_vegetation.blend new file mode 100644 index 0000000..10ba276 Binary files /dev/null and b/scenes/S2/layers/s2_vegetation.blend differ diff --git a/scenes/preview/M1_Cam_M1_Aerial_SE.jpg b/scenes/preview/M1_Cam_M1_Aerial_SE.jpg new file mode 100644 index 0000000..8a31b41 Binary files /dev/null and b/scenes/preview/M1_Cam_M1_Aerial_SE.jpg differ diff --git a/scenes/preview/M1_Cam_M1_Yard.jpg b/scenes/preview/M1_Cam_M1_Yard.jpg new file mode 100644 index 0000000..0cc5610 Binary files /dev/null and b/scenes/preview/M1_Cam_M1_Yard.jpg differ diff --git a/scenes/preview/M1_Cam_Sign_M1.jpg b/scenes/preview/M1_Cam_Sign_M1.jpg new file mode 100644 index 0000000..7573a2b Binary files /dev/null and b/scenes/preview/M1_Cam_Sign_M1.jpg differ diff --git a/scenes/preview/M1_Camera_AMF2.jpg b/scenes/preview/M1_Camera_AMF2.jpg new file mode 100644 index 0000000..86f168d Binary files /dev/null and b/scenes/preview/M1_Camera_AMF2.jpg differ diff --git a/scenes/preview/M1_Camera_MetTower.jpg b/scenes/preview/M1_Camera_MetTower.jpg new file mode 100644 index 0000000..7f0804b Binary files /dev/null and b/scenes/preview/M1_Camera_MetTower.jpg differ diff --git a/scenes/preview/S1_Cam_Aerial_SW.jpg b/scenes/preview/S1_Cam_Aerial_SW.jpg new file mode 100644 index 0000000..2119248 Binary files /dev/null and b/scenes/preview/S1_Cam_Aerial_SW.jpg differ diff --git a/scenes/preview/S1_Cam_ECOR_Corn.jpg b/scenes/preview/S1_Cam_ECOR_Corn.jpg new file mode 100644 index 0000000..795e11b Binary files /dev/null and b/scenes/preview/S1_Cam_ECOR_Corn.jpg differ diff --git a/scenes/preview/S1_Cam_Flowers.jpg b/scenes/preview/S1_Cam_Flowers.jpg new file mode 100644 index 0000000..09ab39b Binary files /dev/null and b/scenes/preview/S1_Cam_Flowers.jpg differ diff --git a/scenes/preview/S1_Cam_Louisa_FromP3.jpg b/scenes/preview/S1_Cam_Louisa_FromP3.jpg new file mode 100644 index 0000000..d339d77 Binary files /dev/null and b/scenes/preview/S1_Cam_Louisa_FromP3.jpg differ diff --git a/scenes/preview/S1_Cam_P3_Span.jpg b/scenes/preview/S1_Cam_P3_Span.jpg new file mode 100644 index 0000000..df40d92 Binary files /dev/null and b/scenes/preview/S1_Cam_P3_Span.jpg differ diff --git a/scenes/preview/S2_Cam_AWOS_Drone.jpg b/scenes/preview/S2_Cam_AWOS_Drone.jpg new file mode 100644 index 0000000..90286af Binary files /dev/null and b/scenes/preview/S2_Cam_AWOS_Drone.jpg differ diff --git a/scenes/preview/S2_Cam_Aerial_SE.jpg b/scenes/preview/S2_Cam_Aerial_SE.jpg new file mode 100644 index 0000000..2160df2 Binary files /dev/null and b/scenes/preview/S2_Cam_Aerial_SE.jpg differ diff --git a/scenes/preview/S2_Cam_C850_Drone.jpg b/scenes/preview/S2_Cam_C850_Drone.jpg new file mode 100644 index 0000000..ad6e8cc Binary files /dev/null and b/scenes/preview/S2_Cam_C850_Drone.jpg differ diff --git a/scenes/preview/S2_Cam_CSAPR2_Ground.jpg b/scenes/preview/S2_Cam_CSAPR2_Ground.jpg new file mode 100644 index 0000000..862d78f Binary files /dev/null and b/scenes/preview/S2_Cam_CSAPR2_Ground.jpg differ diff --git a/scenes/preview/S2_Cam_Quad_Drone.jpg b/scenes/preview/S2_Cam_Quad_Drone.jpg new file mode 100644 index 0000000..40893de Binary files /dev/null and b/scenes/preview/S2_Cam_Quad_Drone.jpg differ diff --git a/scenes/preview/S2_Cam_Sign_S2.jpg b/scenes/preview/S2_Cam_Sign_S2.jpg new file mode 100644 index 0000000..688aedb Binary files /dev/null and b/scenes/preview/S2_Cam_Sign_S2.jpg differ diff --git a/scenes/preview/test_instrument_lineup_Cam_Lineup.jpg b/scenes/preview/test_instrument_lineup_Cam_Lineup.jpg new file mode 100644 index 0000000..5001fed Binary files /dev/null and b/scenes/preview/test_instrument_lineup_Cam_Lineup.jpg differ diff --git a/scenes/preview/test_m1_lasso_cumulus_Cam_M1_Aerial_SE.jpg b/scenes/preview/test_m1_lasso_cumulus_Cam_M1_Aerial_SE.jpg new file mode 100644 index 0000000..c1135da Binary files /dev/null and b/scenes/preview/test_m1_lasso_cumulus_Cam_M1_Aerial_SE.jpg differ diff --git a/scenes/preview/test_m1_supercell_Cam_Storm_Sign.jpg b/scenes/preview/test_m1_supercell_Cam_Storm_Sign.jpg new file mode 100644 index 0000000..360c685 Binary files /dev/null and b/scenes/preview/test_m1_supercell_Cam_Storm_Sign.jpg differ diff --git a/scenes/preview/test_s1_ucla_cumulus_Cam_Aerial_SW.jpg b/scenes/preview/test_s1_ucla_cumulus_Cam_Aerial_SW.jpg new file mode 100644 index 0000000..74ac03a Binary files /dev/null and b/scenes/preview/test_s1_ucla_cumulus_Cam_Aerial_SW.jpg differ diff --git a/scenes/tests/instrument_lineup.blend b/scenes/tests/instrument_lineup.blend new file mode 100644 index 0000000..f755ca7 Binary files /dev/null and b/scenes/tests/instrument_lineup.blend differ diff --git a/scenes/tests/m1_lasso_cumulus.blend b/scenes/tests/m1_lasso_cumulus.blend new file mode 100644 index 0000000..b706814 Binary files /dev/null and b/scenes/tests/m1_lasso_cumulus.blend differ diff --git a/scenes/tests/m1_supercell.blend b/scenes/tests/m1_supercell.blend new file mode 100644 index 0000000..39a123b Binary files /dev/null and b/scenes/tests/m1_supercell.blend differ diff --git a/scenes/tests/s1_ucla_cumulus.blend b/scenes/tests/s1_ucla_cumulus.blend new file mode 100644 index 0000000..554637b Binary files /dev/null and b/scenes/tests/s1_ucla_cumulus.blend differ diff --git a/textures/flags/flag_arm.png b/textures/flags/flag_arm.png new file mode 100644 index 0000000..a1760d8 Binary files /dev/null and b/textures/flags/flag_arm.png differ diff --git a/textures/flags/flag_isu.png b/textures/flags/flag_isu.png new file mode 100644 index 0000000..5470ceb Binary files /dev/null and b/textures/flags/flag_isu.png differ diff --git a/textures/flags/flag_us.png b/textures/flags/flag_us.png new file mode 100644 index 0000000..8bd8204 Binary files /dev/null and b/textures/flags/flag_us.png differ diff --git a/textures/imagery/m1/hf_inner_1m.exr b/textures/imagery/m1/hf_inner_1m.exr new file mode 100644 index 0000000..8a856c5 Binary files /dev/null and b/textures/imagery/m1/hf_inner_1m.exr differ diff --git a/textures/imagery/m1/hf_outer_10m.exr b/textures/imagery/m1/hf_outer_10m.exr new file mode 100644 index 0000000..a7bbd89 Binary files /dev/null and b/textures/imagery/m1/hf_outer_10m.exr differ diff --git a/textures/imagery/s1_mirf/naip_rgb_0p6m.png b/textures/imagery/s1_mirf/naip_rgb_0p6m.png new file mode 100644 index 0000000..a73fccc Binary files /dev/null and b/textures/imagery/s1_mirf/naip_rgb_0p6m.png differ diff --git a/textures/imagery/s2_kawg/naip_rgb_0p6m_clean.png b/textures/imagery/s2_kawg/naip_rgb_0p6m_clean.png new file mode 100644 index 0000000..8fb3f3e Binary files /dev/null and b/textures/imagery/s2_kawg/naip_rgb_0p6m_clean.png differ diff --git a/textures/imagery/s2_kawg/naip_wide_6m.png b/textures/imagery/s2_kawg/naip_wide_6m.png new file mode 100644 index 0000000..031bb8f Binary files /dev/null and b/textures/imagery/s2_kawg/naip_wide_6m.png differ diff --git a/textures/pbr/Concrete034/Concrete034_2K-JPG_Color.jpg b/textures/pbr/Concrete034/Concrete034_2K-JPG_Color.jpg new file mode 100644 index 0000000..8bff82f Binary files /dev/null and b/textures/pbr/Concrete034/Concrete034_2K-JPG_Color.jpg differ diff --git a/textures/pbr/Concrete034/Concrete034_2K-JPG_NormalGL.jpg b/textures/pbr/Concrete034/Concrete034_2K-JPG_NormalGL.jpg new file mode 100644 index 0000000..4d0194c Binary files /dev/null and b/textures/pbr/Concrete034/Concrete034_2K-JPG_NormalGL.jpg differ diff --git a/textures/pbr/Concrete034/Concrete034_2K-JPG_Roughness.jpg b/textures/pbr/Concrete034/Concrete034_2K-JPG_Roughness.jpg new file mode 100644 index 0000000..509dbe1 Binary files /dev/null and b/textures/pbr/Concrete034/Concrete034_2K-JPG_Roughness.jpg differ diff --git a/textures/pbr/CorrugatedSteel005/CorrugatedSteel005_2K-JPG_Color.jpg b/textures/pbr/CorrugatedSteel005/CorrugatedSteel005_2K-JPG_Color.jpg new file mode 100644 index 0000000..6f65c56 Binary files /dev/null and b/textures/pbr/CorrugatedSteel005/CorrugatedSteel005_2K-JPG_Color.jpg differ diff --git a/textures/pbr/CorrugatedSteel005/CorrugatedSteel005_2K-JPG_NormalGL.jpg b/textures/pbr/CorrugatedSteel005/CorrugatedSteel005_2K-JPG_NormalGL.jpg new file mode 100644 index 0000000..c6d68ee Binary files /dev/null and b/textures/pbr/CorrugatedSteel005/CorrugatedSteel005_2K-JPG_NormalGL.jpg differ diff --git a/textures/pbr/CorrugatedSteel005/CorrugatedSteel005_2K-JPG_Roughness.jpg b/textures/pbr/CorrugatedSteel005/CorrugatedSteel005_2K-JPG_Roughness.jpg new file mode 100644 index 0000000..e073e7d Binary files /dev/null and b/textures/pbr/CorrugatedSteel005/CorrugatedSteel005_2K-JPG_Roughness.jpg differ diff --git a/textures/pbr/Ground037/Ground037_2K-JPG_Color.jpg b/textures/pbr/Ground037/Ground037_2K-JPG_Color.jpg new file mode 100644 index 0000000..3aa0b16 Binary files /dev/null and b/textures/pbr/Ground037/Ground037_2K-JPG_Color.jpg differ diff --git a/textures/pbr/Ground037/Ground037_2K-JPG_NormalGL.jpg b/textures/pbr/Ground037/Ground037_2K-JPG_NormalGL.jpg new file mode 100644 index 0000000..4de0e07 Binary files /dev/null and b/textures/pbr/Ground037/Ground037_2K-JPG_NormalGL.jpg differ diff --git a/textures/pbr/Ground037/Ground037_2K-JPG_Roughness.jpg b/textures/pbr/Ground037/Ground037_2K-JPG_Roughness.jpg new file mode 100644 index 0000000..bdace44 Binary files /dev/null and b/textures/pbr/Ground037/Ground037_2K-JPG_Roughness.jpg differ diff --git a/textures/pbr/Metal009/Metal009_2K-JPG_Color.jpg b/textures/pbr/Metal009/Metal009_2K-JPG_Color.jpg new file mode 100644 index 0000000..6afae4b Binary files /dev/null and b/textures/pbr/Metal009/Metal009_2K-JPG_Color.jpg differ diff --git a/textures/pbr/Metal009/Metal009_2K-JPG_NormalGL.jpg b/textures/pbr/Metal009/Metal009_2K-JPG_NormalGL.jpg new file mode 100644 index 0000000..b42e61e Binary files /dev/null and b/textures/pbr/Metal009/Metal009_2K-JPG_NormalGL.jpg differ diff --git a/textures/pbr/Metal009/Metal009_2K-JPG_Roughness.jpg b/textures/pbr/Metal009/Metal009_2K-JPG_Roughness.jpg new file mode 100644 index 0000000..8ea7346 Binary files /dev/null and b/textures/pbr/Metal009/Metal009_2K-JPG_Roughness.jpg differ diff --git a/textures/pbr/Metal050A/Metal050A_2K-JPG_Color.jpg b/textures/pbr/Metal050A/Metal050A_2K-JPG_Color.jpg new file mode 100644 index 0000000..0ebe77a Binary files /dev/null and b/textures/pbr/Metal050A/Metal050A_2K-JPG_Color.jpg differ diff --git a/textures/pbr/Metal050A/Metal050A_2K-JPG_NormalGL.jpg b/textures/pbr/Metal050A/Metal050A_2K-JPG_NormalGL.jpg new file mode 100644 index 0000000..aa58822 Binary files /dev/null and b/textures/pbr/Metal050A/Metal050A_2K-JPG_NormalGL.jpg differ diff --git a/textures/pbr/Metal050A/Metal050A_2K-JPG_Roughness.jpg b/textures/pbr/Metal050A/Metal050A_2K-JPG_Roughness.jpg new file mode 100644 index 0000000..3863822 Binary files /dev/null and b/textures/pbr/Metal050A/Metal050A_2K-JPG_Roughness.jpg differ diff --git a/textures/pbr/Metal051A/Metal051A_2K-JPG_Color.jpg b/textures/pbr/Metal051A/Metal051A_2K-JPG_Color.jpg new file mode 100644 index 0000000..007d9a6 Binary files /dev/null and b/textures/pbr/Metal051A/Metal051A_2K-JPG_Color.jpg differ diff --git a/textures/pbr/Metal051A/Metal051A_2K-JPG_NormalGL.jpg b/textures/pbr/Metal051A/Metal051A_2K-JPG_NormalGL.jpg new file mode 100644 index 0000000..2849982 Binary files /dev/null and b/textures/pbr/Metal051A/Metal051A_2K-JPG_NormalGL.jpg differ diff --git a/textures/pbr/Metal051A/Metal051A_2K-JPG_Roughness.jpg b/textures/pbr/Metal051A/Metal051A_2K-JPG_Roughness.jpg new file mode 100644 index 0000000..47daae6 Binary files /dev/null and b/textures/pbr/Metal051A/Metal051A_2K-JPG_Roughness.jpg differ diff --git a/textures/pbr/PaintedMetal004/PaintedMetal004_2K-JPG_Color.jpg b/textures/pbr/PaintedMetal004/PaintedMetal004_2K-JPG_Color.jpg new file mode 100644 index 0000000..24065d6 Binary files /dev/null and b/textures/pbr/PaintedMetal004/PaintedMetal004_2K-JPG_Color.jpg differ diff --git a/textures/pbr/PaintedMetal004/PaintedMetal004_2K-JPG_NormalGL.jpg b/textures/pbr/PaintedMetal004/PaintedMetal004_2K-JPG_NormalGL.jpg new file mode 100644 index 0000000..74d0040 Binary files /dev/null and b/textures/pbr/PaintedMetal004/PaintedMetal004_2K-JPG_NormalGL.jpg differ diff --git a/textures/pbr/PaintedMetal004/PaintedMetal004_2K-JPG_Roughness.jpg b/textures/pbr/PaintedMetal004/PaintedMetal004_2K-JPG_Roughness.jpg new file mode 100644 index 0000000..1a29b21 Binary files /dev/null and b/textures/pbr/PaintedMetal004/PaintedMetal004_2K-JPG_Roughness.jpg differ diff --git a/textures/pbr/PaintedMetal006/PaintedMetal006_2K-JPG_Color.jpg b/textures/pbr/PaintedMetal006/PaintedMetal006_2K-JPG_Color.jpg new file mode 100644 index 0000000..4ab2a09 Binary files /dev/null and b/textures/pbr/PaintedMetal006/PaintedMetal006_2K-JPG_Color.jpg differ diff --git a/textures/pbr/PaintedMetal006/PaintedMetal006_2K-JPG_NormalGL.jpg b/textures/pbr/PaintedMetal006/PaintedMetal006_2K-JPG_NormalGL.jpg new file mode 100644 index 0000000..4ced1a3 Binary files /dev/null and b/textures/pbr/PaintedMetal006/PaintedMetal006_2K-JPG_NormalGL.jpg differ diff --git a/textures/pbr/PaintedMetal006/PaintedMetal006_2K-JPG_Roughness.jpg b/textures/pbr/PaintedMetal006/PaintedMetal006_2K-JPG_Roughness.jpg new file mode 100644 index 0000000..7473e93 Binary files /dev/null and b/textures/pbr/PaintedMetal006/PaintedMetal006_2K-JPG_Roughness.jpg differ diff --git a/textures/pbr/Plastic010/Plastic010_2K-JPG_Color.jpg b/textures/pbr/Plastic010/Plastic010_2K-JPG_Color.jpg new file mode 100644 index 0000000..6a47602 Binary files /dev/null and b/textures/pbr/Plastic010/Plastic010_2K-JPG_Color.jpg differ diff --git a/textures/pbr/Plastic010/Plastic010_2K-JPG_NormalGL.jpg b/textures/pbr/Plastic010/Plastic010_2K-JPG_NormalGL.jpg new file mode 100644 index 0000000..04a6fa8 Binary files /dev/null and b/textures/pbr/Plastic010/Plastic010_2K-JPG_NormalGL.jpg differ diff --git a/textures/pbr/Plastic010/Plastic010_2K-JPG_Roughness.jpg b/textures/pbr/Plastic010/Plastic010_2K-JPG_Roughness.jpg new file mode 100644 index 0000000..75a0733 Binary files /dev/null and b/textures/pbr/Plastic010/Plastic010_2K-JPG_Roughness.jpg differ diff --git a/textures/pbr/Plastic013A/Plastic013A_2K-JPG_Color.jpg b/textures/pbr/Plastic013A/Plastic013A_2K-JPG_Color.jpg new file mode 100644 index 0000000..9227a31 Binary files /dev/null and b/textures/pbr/Plastic013A/Plastic013A_2K-JPG_Color.jpg differ diff --git a/textures/pbr/Plastic013A/Plastic013A_2K-JPG_NormalGL.jpg b/textures/pbr/Plastic013A/Plastic013A_2K-JPG_NormalGL.jpg new file mode 100644 index 0000000..068ee99 Binary files /dev/null and b/textures/pbr/Plastic013A/Plastic013A_2K-JPG_NormalGL.jpg differ diff --git a/textures/pbr/Plastic013A/Plastic013A_2K-JPG_Roughness.jpg b/textures/pbr/Plastic013A/Plastic013A_2K-JPG_Roughness.jpg new file mode 100644 index 0000000..7785539 Binary files /dev/null and b/textures/pbr/Plastic013A/Plastic013A_2K-JPG_Roughness.jpg differ diff --git a/textures/pbr/Rubber004/Rubber004_2K-JPG_Color.jpg b/textures/pbr/Rubber004/Rubber004_2K-JPG_Color.jpg new file mode 100644 index 0000000..709ce20 Binary files /dev/null and b/textures/pbr/Rubber004/Rubber004_2K-JPG_Color.jpg differ diff --git a/textures/pbr/Rubber004/Rubber004_2K-JPG_NormalGL.jpg b/textures/pbr/Rubber004/Rubber004_2K-JPG_NormalGL.jpg new file mode 100644 index 0000000..66f5593 Binary files /dev/null and b/textures/pbr/Rubber004/Rubber004_2K-JPG_NormalGL.jpg differ diff --git a/textures/pbr/Rubber004/Rubber004_2K-JPG_Roughness.jpg b/textures/pbr/Rubber004/Rubber004_2K-JPG_Roughness.jpg new file mode 100644 index 0000000..42b5d96 Binary files /dev/null and b/textures/pbr/Rubber004/Rubber004_2K-JPG_Roughness.jpg differ diff --git a/textures/signs/derechos_sign_M1.png b/textures/signs/derechos_sign_M1.png new file mode 100644 index 0000000..cc62734 Binary files /dev/null and b/textures/signs/derechos_sign_M1.png differ diff --git a/textures/signs/derechos_sign_S1.png b/textures/signs/derechos_sign_S1.png new file mode 100644 index 0000000..de4ac37 Binary files /dev/null and b/textures/signs/derechos_sign_S1.png differ diff --git a/textures/signs/derechos_sign_S2.png b/textures/signs/derechos_sign_S2.png new file mode 100644 index 0000000..3f4e2b0 Binary files /dev/null and b/textures/signs/derechos_sign_S2.png differ diff --git a/tools/ablib.py b/tools/ablib.py new file mode 100644 index 0000000..da03048 --- /dev/null +++ b/tools/ablib.py @@ -0,0 +1,453 @@ +"""Helpers for building the ablemodels asset library from monolithic scene files. + +Run inside Blender (background mode). Environment: + ABLE_REPO repository root + ABLE_SRC root of the original farm_amf2 working folder (source scenes/textures) + +Two ways an embedded collection is moved into a library file: + extract() collection keeps world coordinates and is linked back in place + (site-specific layers: terrain, fields, buildings at a site) + extract_normalized() collection's root object is moved to the origin, written, + and the scene gets a collection-instance empty at the old + transform (re-usable assets: instruments, containers, vehicles) +Both are lossless: geometry, materials and modifiers are written unchanged. +""" +import bpy, os, re, shutil, json +from mathutils import Matrix + +REPO = os.environ.get('ABLE_REPO', '') +SRC = os.environ.get('ABLE_SRC', '') +REPORT = {'written': [], 'linked': [], 'missing': [], 'warnings': [], 'mismatch': []} + + +def log(*a): + print('[able]', *a, flush=True) + + +def warn(*a): + s = ' '.join(map(str, a)); REPORT['warnings'].append(s); log('WARN', s) + + +# ---------------------------------------------------------------- paths +def resolve_src(path): + if not path: + return None + p = bpy.path.abspath(path) + if os.path.exists(p): + return os.path.normpath(p) + m = re.search(r'farm_amf2/(.*)$', path.replace('\\', '/'), re.I) + if m: + cand = os.path.join(SRC, m.group(1)) + if os.path.exists(cand): + return os.path.normpath(cand) + return None + + +def texture_dest(src): + s = src.replace('\\', '/') + fn = os.path.basename(s) + m = re.search(r'/_tex/([^/]+)/', s) + if m: + return os.path.join(REPO, 'textures', 'pbr', m.group(1), fn) + if '/mirf_s1/' in s: + return os.path.join(REPO, 'textures', 'imagery', 's1_mirf', fn) + if '/airport_awg/' in s: + return os.path.join(REPO, 'textures', 'imagery', 's2_kawg', fn) + if 'flag_' in fn: + return os.path.join(REPO, 'textures', 'flags', fn) + if '/signs/' in s: + return os.path.join(REPO, 'textures', 'signs', fn) + if '/lasso/' in s or '/m1_lidar/' in s: + return os.path.join(REPO, 'textures', 'imagery', 'm1', fn) + return os.path.join(REPO, 'textures', 'misc', fn) + + +def localize_images(): + """Copy every referenced (unpacked) image into REPO/textures and point at it.""" + n = 0 + for img in bpy.data.images: + if img.library or img.packed_file or img.source in ('VIEWER', 'GENERATED') or not img.filepath: + continue + src = resolve_src(img.filepath) + if not src: + REPORT['missing'].append(('image', img.name, img.filepath)) + warn('missing image', img.name, img.filepath) + continue + dst = texture_dest(src) + os.makedirs(os.path.dirname(dst), exist_ok=True) + if not os.path.exists(dst): + shutil.copy2(src, dst) + img.filepath = dst + n += 1 + log('localized images', n) + + +def fonts_to_mesh(): + """Text objects using non-builtin (system) fonts become meshes so files are portable.""" + dg = bpy.context.evaluated_depsgraph_get() + for o in list(bpy.data.objects): + if o.library or o.type != 'FONT': + continue + f = o.data.font + if f is None or f.filepath == '' or f.packed_file: + continue + me = bpy.data.meshes.new_from_object(o.evaluated_get(dg), preserve_all_data_layers=True, depsgraph=dg) + name = o.name + new = bpy.data.objects.new(name + '_mesh', me) + new.parent = o.parent + new.matrix_parent_inverse = o.matrix_parent_inverse.copy() + new.matrix_basis = o.matrix_basis.copy() + new.hide_render = o.hide_render; new.hide_viewport = o.hide_viewport + for c in o.users_collection: + c.objects.link(new) + for ch in o.children: + mw = ch.matrix_world.copy(); ch.parent = new; ch.matrix_world = mw + bpy.data.objects.remove(o) + new.name = name + log('font->mesh', name, f.filepath) + + +# ---------------------------------------------------------------- view layer flags +def _walk_lc(lc, out): + out[lc.collection] = (lc.exclude, lc.hide_viewport, lc.collection.hide_render, lc.collection.hide_viewport) + for ch in lc.children: + _walk_lc(ch, out) + + +def layer_flags(coll): + out = {} + for sc in bpy.data.scenes: + for vl in sc.view_layers: + d = {} + _walk_lc(vl.layer_collection, d) + if coll in d: + out[(sc.name, vl.name)] = d[coll] + return out + + +def apply_layer_flags(coll, flags): + for (scn, vln), (exc, hv, hr, hvp) in flags.items(): + vl = bpy.data.scenes[scn].view_layers[vln] + def find(lc): + if lc.collection == coll: + return lc + for ch in lc.children: + r = find(ch) + if r: return r + lc = find(vl.layer_collection) + if lc: + lc.exclude = exc + if not exc: + lc.hide_viewport = hv + + +def is_hidden(flags): + return any(v[0] or v[2] for v in flags.values()) + + +# ---------------------------------------------------------------- structure helpers +def parents_of(coll): + ps = [c for c in bpy.data.collections if not c.library and coll.name in c.children and c.children[coll.name] == coll] + ps += [s.collection for s in bpy.data.scenes if coll.name in s.collection.children and s.collection.children[coll.name] == coll] + return ps + + +def descendants(o): + return [o] + list(o.children_recursive) + + +def keep_local_objects(coll): + """Cameras/lights (and their track targets) stay in the scene file.""" + keep = set() + for o in coll.all_objects: + if o.type in ('CAMERA', 'LIGHT'): + keep.add(o) + for con in o.constraints: + t = getattr(con, 'target', None) + if t is not None and t in set(coll.all_objects): + keep.add(t) + return keep + + +def split_out_local(coll, scene_parent=None): + keep = keep_local_objects(coll) + if not keep: + return None + name = coll.name + '_cams' + lc = bpy.data.collections.get(name) or bpy.data.collections.new(name) + (scene_parent or bpy.context.scene.collection).children.link(lc) if lc.name not in (scene_parent or bpy.context.scene.collection).children else None + for o in keep: + for c in list(o.users_collection): + if c == coll or c in set(coll.children_recursive): + c.objects.unlink(o) + if lc not in o.users_collection: + lc.objects.link(o) + log('kept local', name, [o.name for o in keep]) + return lc + + +def make_root(coll, root_name, at_obj=None): + """Give a collection of loose objects a single root empty (transforms preserved).""" + roots = [o for o in coll.objects if o.parent is None or o.parent not in set(coll.all_objects)] + loc = (at_obj.matrix_world.translation.copy() if at_obj else roots[0].matrix_world.translation.copy()) + e = bpy.data.objects.new(root_name, None) + e.empty_display_size = 0.5 + coll.objects.link(e) + e.matrix_world = Matrix.Translation(loc) + bpy.context.view_layer.update() + for o in roots: + mw = o.matrix_world.copy(); o.parent = e; o.matrix_world = mw + bpy.context.view_layer.update() + return e + + +def collection_from_roots(parent_coll, root_names, new_name_fn, dest_parent=None): + """Move each root (+ all descendants) out of parent_coll into its own new collection, + created under dest_parent (default: parent_coll).""" + out = [] + dest_parent = dest_parent or parent_coll + for rn in root_names: + r = bpy.data.objects[rn] + nc = bpy.data.collections.new(new_name_fn(rn)) + dest_parent.children.link(nc) + for o in descendants(r): + for c in list(o.users_collection): + if c == parent_coll: + c.objects.unlink(o) + nc.objects.link(o) + out.append((nc, r)) + return out + + +# ---------------------------------------------------------------- write / link +def write_lib(relpath, ids, mark_asset=True): + path = os.path.join(REPO, relpath) + os.makedirs(os.path.dirname(path), exist_ok=True) + for i in ids: + if mark_asset and isinstance(i, bpy.types.Collection) and i.asset_data is None: + try: + i.asset_mark() + except Exception as e: + warn('asset_mark failed', i.name, e) + bpy.data.libraries.write(path, set(ids), path_remap='RELATIVE_ALL', fake_user=True, compress=True) + REPORT['written'].append((relpath, [i.name for i in ids], os.path.getsize(path))) + log('wrote', relpath, round(os.path.getsize(path) / 1e6, 2), 'MB', [i.name for i in ids]) + return path + + +def link_colls(relpath, names): + path = os.path.join(REPO, relpath) + with bpy.data.libraries.load(path, link=True, relative=True) as (src, dst): + missing = [n for n in names if n not in src.collections] + if missing: + raise RuntimeError(f'{relpath} lacks {missing}') + dst.collections = list(names) + REPORT['linked'].append((relpath, names)) + return dict(zip(names, dst.collections)) + + +def delete_local(colls, keep=()): + allc = set() + for c in colls: + allc.add(c); allc |= set(c.children_recursive) + objs = set() + for c in allc: + objs |= set(o for o in c.all_objects if not o.library) + for o in list(objs): + if o in keep: + continue + other = [c for c in o.users_collection if c not in allc] + if other: + warn('object also in other collections, kept local:', o.name, [c.name for c in other]) + continue + bpy.data.objects.remove(o, do_unlink=True) + for c in sorted(allc, key=lambda c: -len(c.children_recursive)): + if not c.library and c.name in bpy.data.collections: + bpy.data.collections.remove(c) + + +def purge(): + for _ in range(3): + bpy.data.orphans_purge(do_local_ids=True, do_linked_ids=True, do_recursive=True) + + +def extract(relpath, names): + """World-coordinate extraction: write collections, link them back in place.""" + colls = [bpy.data.collections[n] for n in names] + for c in colls: + split_out_local(c) + flags = {c.name: layer_flags(c) for c in colls} + write_lib(relpath, colls) + linked = link_colls(relpath, names) + for c in colls: + c.user_remap(linked[c.name]) + delete_local(colls) + for n, l in linked.items(): + apply_layer_flags(l, flags[n]) + return linked + + +def extract_normalized(relpath, specs): + """specs: list of (collection_name, root_object_name). Root goes to origin in the library; + the scene gets an instance empty with the root's old world matrix.""" + items = [] + for cn, rn in specs: + c = bpy.data.collections[cn]; r = bpy.data.objects[rn] + if r.parent is not None: + warn('root has parent', rn, r.parent.name) + W = r.matrix_world.copy() + flags = layer_flags(c) + parents = parents_of(c) + hide_r, hide_v = r.hide_render, r.hide_viewport + r.matrix_world = Matrix.Identity(4) + items.append((c, r, W, flags, parents, hide_r, hide_v)) + bpy.context.view_layer.update() + write_lib(relpath, [i[0] for i in items]) + linked = link_colls(relpath, [i[0].name for i in items]) + for c, r, W, flags, parents, hide_r, hide_v in items: + l = linked[c.name] + # existing instancers of this collection expected the root at its old place + for o in bpy.data.objects: + if not o.library and o.instance_type == 'COLLECTION' and o.instance_collection == c: + o.instance_collection = l + o.matrix_world = o.matrix_world @ W + placed = [p for p in parents if not p.name.startswith('_')] + for p in parents: + p.children.unlink(c) + if placed: + e = bpy.data.objects.new(c.name + '_inst', None) + e.instance_type = 'COLLECTION'; e.instance_collection = l + e.empty_display_size = 1.0 + e.matrix_world = W + e.hide_render = hide_r or is_hidden(flags) + e.hide_viewport = hide_v or is_hidden(flags) + for p in placed: + p.objects.link(e) + else: + # prototype libraries (_AssetLib etc.) keep the linked collection as a child + for p in parents: + p.children.link(l) + apply_layer_flags(l, flags) + c.user_remap(l) + delete_local([i[0] for i in items]) + return linked + + +# ---------------------------------------------------------------- comparison / relink +def _base(n): + return re.sub(r'\.\d{3}$', '', n) + + +def world(o): + """matrix_world from the parent chain (linked objects outside a scene are not evaluated).""" + if o.parent is None: + return o.matrix_basis.copy() + return world(o.parent) @ o.matrix_parent_inverse @ o.matrix_basis + + +def signature(coll, root=None): + """Name-independent fingerprint: per object type, vertex count and the mesh's + bounds relative to the root (object names get renumbered between files, and + bound_box is not evaluated for linked data, so vertices are read directly).""" + import numpy as np + inv = world(root).inverted() if root else Matrix.Identity(4) + sig = [] + for o in coll.all_objects: + M = inv @ world(o) + if o.type == 'MESH' and len(o.data.vertices): + co = np.empty(len(o.data.vertices) * 3); o.data.vertices.foreach_get('co', co) + co = co.reshape(-1, 3) + m = np.array(M) + w = co @ m[:3, :3].T + m[:3, 3] + b = tuple(np.round(w.min(0), 2)) + tuple(np.round(w.max(0), 2)) + sig.append(('MESH', len(co)) + tuple(float(x) for x in b)) + else: + t = M.translation + sig.append((o.type, 0, round(t.x, 2), round(t.y, 2), round(t.z, 2))) + return sorted(sig) + + +def relink(relpath, mapping, roots=None): + """mapping {local_collection: library_collection}. Remaps only collections whose + signature matches the library copy; returns the names that did not match.""" + linked = link_colls(relpath, list(mapping.values())) + bad = [] + for ln, libn in mapping.items(): + c = bpy.data.collections[ln]; l = linked[libn] + r_loc = bpy.data.objects.get(roots[ln]) if roots else None + r_lib = None + if roots: + r_lib = next((o for o in l.all_objects if _base(o.name) == _base(roots[ln])), None) + if signature(c, r_loc) != signature(l, r_lib): + bad.append(ln); REPORT['mismatch'].append((ln, relpath, libn)) + warn('signature mismatch', ln, 'vs', relpath, libn) + continue + flags = layer_flags(c) + c.user_remap(l) + delete_local([c]) + apply_layer_flags(l, flags) + log('relinked', ln, '->', relpath, libn) + for l in linked.values(): + if l.users == 0 or (l.users == 1 and l.use_fake_user): + pass + return bad + + +def finish(scene_relpath, report_relpath=None): + purge() + path = os.path.join(REPO, scene_relpath) + bpy.ops.file.make_paths_relative() + bpy.ops.wm.save_as_mainfile(filepath=path, compress=True, relative_remap=True) + # verify that every library and image resolves + for lib in bpy.data.libraries: + if not os.path.exists(bpy.path.abspath(lib.filepath)): + REPORT['missing'].append(('library', lib.filepath)) + for img in bpy.data.images: + if img.packed_file or img.source in ('VIEWER', 'GENERATED') or not img.filepath: + continue + if not os.path.exists(bpy.path.abspath(img.filepath, library=img.library)): + REPORT['missing'].append(('image', img.name, img.filepath)) + REPORT['scene'] = (scene_relpath, os.path.getsize(path)) + if report_relpath: + with open(os.path.join(REPO, report_relpath), 'w') as f: + json.dump(REPORT, f, indent=1, default=str) + log('saved', scene_relpath, round(os.path.getsize(path) / 1e6, 2), 'MB; missing:', REPORT['missing']) + + +def relink_normalized(relpath, cn, rn, libcn=None): + """Replace a scene-placed collection by an instance of an existing library asset, + if the two match (signature relative to their roots). Returns True on success.""" + libcn = libcn or cn + c = bpy.data.collections[cn]; r = bpy.data.objects[rn] + l = link_colls(relpath, [libcn])[libcn] + r_lib = next((o for o in l.all_objects if _base(o.name) == _base(rn)), None) + if r_lib is None or signature(c, r) != signature(l, r_lib): + REPORT['mismatch'].append((cn, relpath, libcn)); warn('normalized mismatch', cn, relpath, libcn) + return False + W = r.matrix_world @ r_lib.matrix_world.inverted() + flags = layer_flags(c); parents = parents_of(c) + for p in parents: + p.children.unlink(c) + placed = [p for p in parents if not p.name.startswith('_')] + if placed: + e = bpy.data.objects.new(libcn + '_inst', None) + e.instance_type = 'COLLECTION'; e.instance_collection = l + e.matrix_world = W + e.hide_render = r.hide_render or is_hidden(flags) + e.hide_viewport = r.hide_viewport or is_hidden(flags) + for p in placed: + p.objects.link(e) + for o in bpy.data.objects: + if not o.library and o.instance_type == 'COLLECTION' and o.instance_collection == c: + o.instance_collection = l + o.matrix_world = o.matrix_world @ r.matrix_world @ r_lib.matrix_world.inverted() + c.user_remap(l) + delete_local([c]) + log('relinked (normalized)', cn, '->', relpath, libcn) + return True + + +def rename_collections(mapping): + for a, b in mapping.items(): + if a in bpy.data.collections: + bpy.data.collections[a].name = b diff --git a/tools/audit_paths.py b/tools/audit_paths.py new file mode 100644 index 0000000..1cd5ccb --- /dev/null +++ b/tools/audit_paths.py @@ -0,0 +1,70 @@ +"""Check (and with --fix, repair) external paths in one .blend so the repo is self-contained. +blender -b file.blend --python tools/audit_paths.py -- report.json [--fix] +""" +import bpy, os, sys, json +args = sys.argv[sys.argv.index('--') + 1:] +fix = '--fix' in args +REPO = os.environ['ABLE_REPO'] +here = bpy.data.filepath +rep = {'file': os.path.relpath(here, REPO), 'problems': [], 'fixed': []} + + +def inside_repo(p): + return os.path.abspath(p).startswith(REPO + os.sep) + + +def check(kind, idname, raw, lib=None, packed=False): + if not raw or raw == '': + return + ab = bpy.path.abspath(raw, library=lib) + bad = [] + if not raw.startswith('//'): + bad.append('absolute') + if not inside_repo(ab): + bad.append('outside-repo') + if not packed and not os.path.exists(ab): + bad.append('missing') + if bad: + rep['problems'].append((kind, idname, raw, bad, packed)) + return bad + + +changed = False +for l in bpy.data.libraries: + check('library', l.name, l.filepath) +for im in bpy.data.images: + if im.library or im.source in ('VIEWER', 'GENERATED') or not im.filepath: + continue + bad = check('image', im.name, im.filepath, packed=bool(im.packed_file)) + if bad and im.packed_file and fix: + import glob + base = os.path.basename(im.filepath) + hits = glob.glob(os.path.join(REPO, 'textures', '**', base), recursive=True) + im.filepath_raw = bpy.path.relpath(hits[0]) if hits else '//' + base + rep['fixed'].append(('packed image path', im.name, im.filepath_raw)); changed = True +for v in bpy.data.volumes: + if not v.library: + check('volume', v.name, v.filepath, packed=bool(v.packed_file)) +for f in bpy.data.fonts: + if not f.library: + check('font', f.name, f.filepath, packed=bool(f.packed_file)) +for s in bpy.data.scenes: + if s.library: + continue + fp = s.render.filepath + if fp and not fp.startswith('//') and fp not in ('/tmp/', '/tmp'): + rep['problems'].append(('render.filepath', s.name, fp, ['absolute'], False)) + if fix: + s.render.filepath = '//renders/'; rep['fixed'].append(('render.filepath', s.name)); changed = True +for o in bpy.data.objects: + if o.library: + continue + for m in o.modifiers: + bd = getattr(m, 'bake_directory', '') + if bd: + rep['problems'].append(('bake_directory', o.name, bd, ['bake'], False)) + if m.type == 'MESH_SEQUENCE_CACHE' and m.cache_file: + check('cachefile', m.cache_file.name, m.cache_file.filepath) +if fix and changed: + bpy.ops.wm.save_mainfile(compress=True) +json.dump(rep, open(args[0], 'w'), indent=1) diff --git a/tools/build_clouds.py b/tools/build_clouds.py new file mode 100644 index 0000000..537fc7f --- /dev/null +++ b/tools/build_clouds.py @@ -0,0 +1,63 @@ +"""Build a cloud asset file: mature snapshots of one simulation, each as its own collection. +blender -b --python tools/build_clouds.py -- +spec: {"set": "cm1_supercell", "template": ["CM1_Storm"] | "prefix:LASSO_1740_", + "normalize": true, "snapshots": [["name", "relative/src.vdb"], ...]} +VDBs larger than 50 MB are rewritten with 16-bit (half-float) storage; nothing is resampled. +""" +import bpy, os, sys, json, shutil +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) +import ablib as A +spec = json.load(open(sys.argv[sys.argv.index('--') + 1])) +D = bpy.data +outdir = os.path.join(A.REPO, 'clouds', spec['set']) +os.makedirs(outdir, exist_ok=True) + +t = spec['template'] +if isinstance(t, str) and t.startswith('prefix:'): + tmpl = sorted([o for o in D.objects if o.type == 'VOLUME' and o.name.startswith(t[7:])], key=lambda o: o.name) +else: + tmpl = [D.objects[n] for n in t] +A.log('template objects', [o.name for o in tmpl]) + + +def place_vdb(src_rel): + src = os.path.join(A.SRC, src_rel) + dst = os.path.join(outdir, os.path.basename(src)) + if os.path.exists(dst): + return dst + if os.path.getsize(src) > 50e6: + import openvdb as vdb + grids, meta = vdb.readAll(src) + for g in grids: + g.saveFloatAsHalf = True + meta['ablemodels_note'] = 'rewritten with half-float storage from ' + os.path.basename(src) + vdb.write(dst, grids, meta) + A.log('half-float', os.path.basename(src), round(os.path.getsize(src) / 1e6), '->', round(os.path.getsize(dst) / 1e6), 'MB') + else: + shutil.copy2(src, dst) + return dst + + +colls = [] +for name, rel in spec['snapshots']: + path = place_vdb(rel) + vol = tmpl[0].data.copy() + vol.name = name + vol.filepath = path + vol.is_sequence = False + c = D.collections.new('CLOUD_' + name) + bpy.context.scene.collection.children.link(c) + for o in tmpl: + n = o.copy(); n.data = vol; n.animation_data_clear() + n.name = f'{name}_{o.name}' if len(tmpl) > 1 else name + n.parent = None + n.matrix_world = o.matrix_world.copy() + if spec.get('normalize') and len(tmpl) == 1: + n['source_location'] = list(o.matrix_world.translation) + n.location = (0, 0, 0) + c.objects.link(n) + c['source_vdb'] = rel + c['source_scene'] = os.path.basename(D.filepath) + colls.append(c) +A.write_lib(f'clouds/{spec["set"]}/{spec["set"]}.blend', colls) +json.dump(A.REPORT, open(os.path.join(A.REPO, 'tools/reports', f'clouds_{spec["set"]}.json'), 'w'), indent=1, default=str) diff --git a/tools/build_m1.py b/tools/build_m1.py new file mode 100644 index 0000000..b717063 --- /dev/null +++ b/tools/build_m1.py @@ -0,0 +1,61 @@ +"""Rebuild the M1 (main site, farm) scene from farm_v5.blend with linked assets. +blender -b /farm_v5.blend --python tools/build_m1.py +""" +import bpy, os, sys +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) +import ablib as A + +D = bpy.data +os.makedirs(os.path.join(A.REPO, 'scenes/M1/layers'), exist_ok=True) +bpy.ops.wm.save_as_mainfile(filepath=os.path.join(A.REPO, 'scenes/M1/M1.blend'), relative_remap=True) +A.fonts_to_mesh() +A.localize_images() + +# --- plants (prototype collections used by geometry-node scatterers) +A.extract('plants/crops.blend', ['CornVariants', 'SoyVariants']) +A.extract('plants/grasses.blend', ['GrassVariants', 'TallGrassVariants']) +A.extract('plants/trees.blend', ['TreeVariants', 'TV_Decid', 'TV_Spruce', 'TV_Far', 'TreeParts']) + +# --- ground first: other layers conform to the Ground terrain object +A.extract('scenes/M1/layers/m1_ground.blend', ['Ground']) + +# --- instruments: one file per instrument, root at origin +inst = [c.name for c in D.collections['Instruments_v4'].children if c.name.startswith('INST_')] +for cn in inst: + name = cn[5:] + root = next(o for o in D.collections[cn].objects if o.name.startswith(name + '_root')) + specs = [(cn, root.name)] + if name == 'ECOR' and 'INST_ECOR_4m' in D.collections: + r4 = next(o for o in D.collections['INST_ECOR_4m'].objects if o.name.startswith('ECOR_root')) + specs.append(('INST_ECOR_4m', r4.name)) + A.extract_normalized(f'instruments/{name}/{name}.blend', specs) + +# --- containers: each AMF2 container/shelter becomes its own asset +amf = D.collections['AMF2'] +A.split_out_local(amf) +roots = [o.name for o in amf.objects if o.type == 'EMPTY' and o.parent is None and + (o.name.startswith('AMF2_Cont_') or o.name in ('AOS_Platform', 'AMF2_OfficeShelter', 'AMF2_RentalContainer'))] +def cname(r): + return 'CONT_' + r.replace('AMF2_Cont_', '').replace('AMF2_', '') +cont = D.collections.new('Containers'); bpy.context.scene.collection.children.link(cont) +pairs = A.collection_from_roots(amf, roots, cname, cont) +A.extract_normalized('containers/amf2_containers.blend', [(c.name, r.name) for c, r in pairs]) + +# --- vehicles: each farm vehicle is an asset at the origin +veh = D.collections['Vehicles'] +vroots = [o.name for o in veh.objects if o.parent is None] +pairs = A.collection_from_roots(veh, vroots, lambda r: 'VEH_' + r) +A.extract_normalized('vehicles/farm_vehicles.blend', [(c.name, r.name) for c, r in pairs]) + +# --- buildings / structures +A.extract('buildings/m1_farmstead.blend', ['Farmstead']) +fp = D.collections['Flagpole'] +r = A.make_root(fp, 'Flagpole_root', D.objects['Flagpole_Base']) +A.extract_normalized('buildings/flagpole.blend', [('Flagpole', 'Flagpole_root')]) +A.extract('buildings/signs/sign_M1.blend', ['SIGN_M1']) + +# --- remaining site layers +A.extract('scenes/M1/layers/m1_fields.blend', ['Fields']) +A.extract('scenes/M1/layers/m1_amf2_site.blend', ['AMF2']) + +A.finish('scenes/M1/M1.blend', 'tools/reports/build_m1.json') diff --git a/tools/build_s1.py b/tools/build_s1.py new file mode 100644 index 0000000..be004f3 --- /dev/null +++ b/tools/build_s1.py @@ -0,0 +1,46 @@ +"""Rebuild S1 (Muscatine Island Research Farm) from mirf_s1.blend with linked assets.""" +import bpy, os, sys +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) +import ablib as A +D = bpy.data +os.makedirs(os.path.join(A.REPO, 'scenes/S1/layers'), exist_ok=True) +bpy.ops.wm.save_as_mainfile(filepath=os.path.join(A.REPO, 'scenes/S1/S1.blend'), relative_remap=True) +A.fonts_to_mesh() +A.localize_images() + +# --- plants: reuse M1 crops if identical, otherwise keep S1's own versions +bad = A.relink('plants/crops.blend', {'CornVariants': 'CornVariants', 'SoyVariants': 'SoyVariants'}) +if bad: + A.rename_collections({n: n + '_S1' for n in bad}) + A.extract('plants/crops_s1.blend', [n + '_S1' for n in bad]) +# high-detail tree set used at S1/S2 (different meshes from the M1 set) +A.rename_collections({'TV_Spruce': 'TV_Spruce_HD', 'TV_Decid': 'TV_Decid_HD', 'TV_Far': 'TV_Far_HD', + 'TreeParts': 'TreeParts_HD', 'TV_DecidBaked': 'TV_DecidBaked_HD'}) +A.extract('plants/trees_hd.blend', ['TV_Spruce_HD', 'TV_Decid_HD', 'TV_Far_HD', 'TreeParts_HD', 'TV_DecidBaked_HD']) +A.extract('plants/native_flowers.blend', ['NativeFlowerVariants']) + +A.extract('scenes/S1/layers/s1_terrain.blend', ['Terrain']) + +# --- instruments: ECOR/SEBS prototypes (instanced by S1_Site empties) +for cn, rn, lib, libcns in [('INST_ECOR', 'ECOR_root', 'instruments/ECOR/ECOR.blend', ['INST_ECOR_4m', 'INST_ECOR']), + ('INST_SEBS', 'SEBS_root', 'instruments/SEBS/SEBS.blend', ['INST_SEBS'])]: + done = False + for libcn in libcns: + bad = A.relink(lib, {cn: libcn}, roots={cn: rn}) + if not bad: + done = True; break + if not done: + new = cn + '_S1' + A.rename_collections({cn: new}) + A.extract_normalized(lib.replace('.blend', '_S1.blend'), [(new, rn)]) + +# --- structures +A.extract_normalized('buildings/center_pivots.blend', + [('Pivot_P1', 'Pivot_P1_root'), ('Pivot_P2', 'Pivot_P2_root'), ('Pivot_P3', 'Pivot_P3_root')]) +A.extract('buildings/louisa_station.blend', ['LOUISA_Station', 'LOUISA_TreePoints']) +A.rename_collections({'Buildings': 'S1_MIRF_Buildings'}) +A.extract('buildings/s1_mirf_buildings.blend', ['S1_MIRF_Buildings']) +A.extract('buildings/signs/sign_S1.blend', ['SIGN_S1']) + +A.extract('scenes/S1/layers/s1_vegetation.blend', ['Vegetation']) +A.finish('scenes/S1/S1.blend', 'tools/reports/build_s1.json') diff --git a/tools/build_s2.py b/tools/build_s2.py new file mode 100644 index 0000000..0961c8c --- /dev/null +++ b/tools/build_s2.py @@ -0,0 +1,46 @@ +"""Rebuild S2 (Washington Municipal Airport, KAWG) from airport_awg.blend with linked assets.""" +import bpy, os, sys +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) +import ablib as A +D = bpy.data +os.makedirs(os.path.join(A.REPO, 'scenes/S2/layers'), exist_ok=True) +bpy.ops.wm.save_as_mainfile(filepath=os.path.join(A.REPO, 'scenes/S2/S2.blend'), relative_remap=True) +A.fonts_to_mesh() +A.localize_images() + +# --- plants +bad = A.relink('plants/crops.blend', {'CornVariants': 'CornVariants', 'SoyVariants': 'SoyVariants'}) +if bad and os.path.exists(os.path.join(A.REPO, 'plants/crops_s1.blend')): + bad = A.relink('plants/crops_s1.blend', {n: n + '_S1' for n in bad}) +if bad: + A.rename_collections({n: n + '_S2' for n in bad}) + A.extract('plants/crops_s2.blend', [n + '_S2' for n in bad]) +bad = A.relink('plants/grasses.blend', {'GrassVariants': 'GrassVariants', 'TallGrassVariants': 'TallGrassVariants'}) +if bad: + A.rename_collections({n: n + '_S2' for n in bad}) + A.extract('plants/grasses_s2.blend', [n + '_S2' for n in bad]) +bad = A.relink('plants/trees_hd.blend', {'TV_DecidBaked': 'TV_DecidBaked_HD'}) +if bad: + A.rename_collections({'TV_DecidBaked': 'TV_DecidBaked_S2'}) + A.extract('plants/trees_s2.blend', ['TV_DecidBaked_S2']) + +A.extract('scenes/S2/layers/s2_terrain.blend', ['Terrain']) + +# --- instruments, aircraft, SACR container +A.extract_normalized('instruments/CSAPR2/CSAPR2.blend', [('CSAPR2', 'CSAPR2_root')]) +A.rename_collections({'AWOS_KAWG': 'INST_AWOS'}) +A.extract_normalized('instruments/AWOS/AWOS.blend', [('INST_AWOS', 'AWOS_root')]) +A.extract_normalized('vehicles/c850_arm.blend', [('C850_ARM', 'C850_root')]) +site = D.collections['S1_Site'] +pairs = A.collection_from_roots(site, ['AMF2_Cont_7_SACR'], lambda r: 'CONT_7_SACR') +if not A.relink_normalized('containers/amf2_containers.blend', 'CONT_7_SACR', 'AMF2_Cont_7_SACR'): + A.rename_collections({'CONT_7_SACR': 'CONT_7_SACR_S2'}) + A.extract_normalized('containers/sacr_container_s2.blend', [('CONT_7_SACR_S2', 'AMF2_Cont_7_SACR')]) + +# --- buildings and site infrastructure +A.rename_collections({'Buildings': 'S2_KAWG_Buildings'}) +A.extract('buildings/s2_kawg_buildings.blend', ['S2_KAWG_Buildings']) +A.extract('buildings/signs/sign_S2.blend', ['SIGN_S2']) +A.extract('scenes/S2/layers/s2_power_roads.blend', ['S1_Power_Roads']) +A.extract('scenes/S2/layers/s2_vegetation.blend', ['Vegetation']) +A.finish('scenes/S2/S2.blend', 'tools/reports/build_s2.json') diff --git a/tools/build_tests.py b/tools/build_tests.py new file mode 100644 index 0000000..16b6eac --- /dev/null +++ b/tools/build_tests.py @@ -0,0 +1,102 @@ +"""Build the test scenes in scenes/tests/. +blender -b --python tools/build_tests.py -- +""" +import bpy, os, sys, glob +from mathutils import Vector, Matrix +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) +import ablib as A +name = sys.argv[sys.argv.index('--') + 1] +D = bpy.data +out = os.path.join(A.REPO, 'scenes/tests', name + '.blend') +os.makedirs(os.path.dirname(out), exist_ok=True) +bpy.ops.wm.save_as_mainfile(filepath=out, relative_remap=True) # paths now relative to tests/ + + +def link(lib, colls=(), objs=(), worlds=()): + with D.libraries.load(os.path.join(A.REPO, lib), link=True, relative=True) as (s, d): + d.collections = list(colls); d.objects = list(objs); d.worlds = list(worlds) + return d + + +def instance(coll, matrix=Matrix.Identity(4), parent=None, name=None): + e = D.objects.new(name or coll.name + '_inst', None) + e.instance_type = 'COLLECTION'; e.instance_collection = coll; e.matrix_world = matrix + (parent or bpy.context.scene.collection).objects.link(e) + return e + + +def camera_from(src_blend, cam_name, new_name): + """Copy a camera's evaluated transform and lens out of one of the original working files + (evaluated in a separate Blender process so parents/constraints are applied).""" + import subprocess, json, tempfile + tmp = tempfile.mktemp(suffix='.json') + code = ("import bpy,json;o=bpy.data.objects[%r];dg=bpy.context.evaluated_depsgraph_get();e=o.evaluated_get(dg);" + "json.dump({'m':[list(r) for r in e.matrix_world],'lens':o.data.lens,'clip':o.data.clip_end," + "'sw':o.data.sensor_width},open(%r,'w'))") % (cam_name, tmp) + subprocess.run([bpy.app.binary_path, '-b', src_blend, '--python-expr', code], check=True, + stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + d = json.load(open(tmp)) + cd = D.cameras.new(new_name); cd.lens = d['lens']; cd.clip_end = d['clip']; cd.sensor_width = d['sw'] + cam = D.objects.new(new_name, cd); cam.matrix_world = Matrix(d['m']) + bpy.context.scene.collection.objects.link(cam) + return cam + + +clouds = D.collections.get('Clouds') or D.collections.new('Clouds') +if name != 'instrument_lineup' and 'Clouds' not in bpy.context.scene.collection.children: + bpy.context.scene.collection.children.link(clouds) + +if name == 'm1_supercell': + c = link('clouds/cm1_supercell/cm1_supercell.blend', ['CLOUD_supercell_c100_t25']).collections[0] + # same storm placement as farm_v5_storm_studio.blend + instance(c, Matrix.Translation((-34948.7, -11251.7, 0.0)), clouds) + cam = camera_from(os.path.join(A.SRC, 'farm_v5_storm_studio.blend'), 'Cam_Storm_Sign', 'Cam_Storm_Sign') + bpy.context.scene.camera = cam + +elif name == 'm1_lasso_cumulus': + c = link('clouds/lasso_sgp_20170403/lasso_sgp_20170403.blend', ['CLOUD_lasso8_2040']).collections[0] + instance(c, Matrix.Identity(4), clouds) + bpy.context.scene.camera = D.objects['Cam_M1_Aerial_SE'] + +elif name == 's1_ucla_cumulus': + c = link('clouds/ucla_cumulus/ucla_cumulus.blend', ['CLOUD_ucla_t6600']).collections[0] + instance(c, Matrix.Identity(4), clouds) + bpy.context.scene.camera = D.objects['Cam_Aerial_SW'] + +elif name == 'instrument_lineup': + for o in list(D.objects): + D.objects.remove(o) + d = link('scenes/M1/M1.blend', objs=['Sun'], worlds=['World']) + sc = bpy.context.scene + sc.world = d.worlds[0]; sc.collection.objects.link(d.objects[0]) + row = D.collections.new('Instruments'); sc.collection.children.link(row) + libs = sorted(glob.glob(os.path.join(A.REPO, 'instruments/*/*.blend'))) + x = 0.0 + for lib in libs: + rel = os.path.relpath(lib, A.REPO) + with D.libraries.load(lib, link=True, relative=True) as (s, dd): + dd.collections = [n for n in s.collections if n.startswith('INST_')] + for c in dd.collections: + w = 14.0 if 'CSAPR2' in c.name else 4.0 + instance(c, Matrix.Translation((x + w / 2, 0, 0)), row) + x += w + bpy.ops.mesh.primitive_plane_add(size=1, location=(x / 2, 0, 0)) + g = bpy.context.active_object; g.name = 'Ground'; g.scale = (x + 600, 600, 1) + m = D.materials.new('Gravel'); m.use_nodes = True + m.node_tree.nodes['Principled BSDF'].inputs['Base Color'].default_value = (0.3, 0.29, 0.26, 1) + g.data.materials.append(m) + cd = D.cameras.new('Cam_Lineup'); cd.lens = 35 + cam = D.objects.new('Cam_Lineup', cd); sc.collection.objects.link(cam) + cam.location = (x / 2, -x * 0.95, 10.0) + cam.rotation_euler = (Vector((x / 2, 0, 2.5)) - cam.location).to_track_quat('-Z', 'Y').to_euler() + sc.camera = cam + sc.render.engine = 'CYCLES'; sc.cycles.samples = 64 + sc.render.resolution_x, sc.render.resolution_y = 1920, 1080 + +if name != 'instrument_lineup': + # light-path settings of the original cloud scenes (multiple scattering in the clouds) + cy = bpy.context.scene.cycles + cy.volume_bounces = 64; cy.max_bounces = 68; cy.samples = 64 +bpy.ops.file.make_paths_relative() +bpy.ops.wm.save_as_mainfile(filepath=out, compress=True, relative_remap=True) +print('TEST_SAVED', out, os.path.getsize(out)) diff --git a/tools/cloud_specs/cm1_bomex_cumulus.json b/tools/cloud_specs/cm1_bomex_cumulus.json new file mode 100644 index 0000000..41c0509 --- /dev/null +++ b/tools/cloud_specs/cm1_bomex_cumulus.json @@ -0,0 +1,4 @@ +{"set": "cm1_bomex_cumulus", "source": "farm_v5_cu_cm1.blend", "template": ["CM1_Storm"], "normalize": true, + "snapshots": [["bomex_t240", "cm1/runs/bomex50/bomex50_t240_x5.vdb"], + ["bomex_t300", "cm1/runs/bomex50/bomex50_t300_x5.vdb"], + ["bomex_t360", "cm1/runs/bomex50/bomex50_t360_x5.vdb"]]} diff --git a/tools/cloud_specs/cm1_supercell.json b/tools/cloud_specs/cm1_supercell.json new file mode 100644 index 0000000..0119ad2 --- /dev/null +++ b/tools/cloud_specs/cm1_supercell.json @@ -0,0 +1,6 @@ +{"set": "cm1_supercell", "source": "farm_v5_storm_studio.blend", "template": ["CM1_Storm"], "normalize": true, + "snapshots": [["supercell_c100_t25", "cm1/runs/studio_100m_c/c100_t25_sp.vdb"], + ["supercell_s100_t45", "cm1/runs/storm_100m/s100_t45_sp.vdb"], + ["supercell_s100_t60", "cm1/runs/storm_100m/s100_t60_sp.vdb"], + ["supercell_s250_t45", "cm1/runs/hero_250m/s250_t45_sp.vdb"], + ["supercell_s250_t60", "cm1/runs/hero_250m/s250_t60_sp.vdb"]]} diff --git a/tools/cloud_specs/lasso_sgp_20170403.json b/tools/cloud_specs/lasso_sgp_20170403.json new file mode 100644 index 0000000..0d6963e --- /dev/null +++ b/tools/cloud_specs/lasso_sgp_20170403.json @@ -0,0 +1,6 @@ +{"set": "lasso_sgp_20170403", "source": "farm_v4_lasso8.blend", "template": "prefix:LASSO_1740_", "normalize": false, + "snapshots": [["lasso_1740", "lasso/lasso_1740_lwc.vdb"], + ["lasso_1800", "lasso/timelapse_vdb/lwc_0145.vdb"], + ["lasso_1900", "lasso/timelapse_vdb/lwc_0193.vdb"], + ["lasso_2000", "lasso/timelapse_vdb/lwc_0241.vdb"], + ["lasso8_2040", "lasso/lasso8_2040_lwc.vdb"]]} diff --git a/tools/cloud_specs/ucla_cumulus.json b/tools/cloud_specs/ucla_cumulus.json new file mode 100644 index 0000000..ad372ef --- /dev/null +++ b/tools/cloud_specs/ucla_cumulus.json @@ -0,0 +1,2 @@ +{"set": "ucla_cumulus", "source": "mirf_s1/mirf_s1_tour_storm.blend", "template": "prefix:UCLA_", "normalize": false, + "snapshots": [["ucla_t6600", "lasso/ucla_t6600_m.vdb"]]} diff --git a/tools/make_catalogue.py b/tools/make_catalogue.py new file mode 100644 index 0000000..e5cf182 --- /dev/null +++ b/tools/make_catalogue.py @@ -0,0 +1,51 @@ +"""Write a README.md catalogue (preview, collection, file) into each asset folder.""" +import json, os, glob +R = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +TITLES = { + 'instruments': ('Instruments', 'One file per instrument; link the `INST_*` (or `CSAPR2`) collection. Root at the origin.'), + 'containers': ('Containers', 'AMF2 containers and shelters with their roof-mounted hardware. `CONT_7_SACR_S2` is the SACR container as configured at S2 (KAWG).'), + 'vehicles': ('Vehicles', 'Farm vehicles/implements and the ARM Bombardier Challenger 850 (`C850_ARM`, gear/flaps/fans driven from custom properties on `C850_root`).'), + 'buildings': ('Buildings and structures', 'Site buildings are stored in site coordinates; the flagpole and center pivots are re-usable (root at the origin).'), + 'plants': ('Plants', 'Prototype collections used by the geometry-node scatterers in the site layers. `_HD` sets are the high-detail trees used at S1/S2; `_S2` grasses are the KAWG lawn variants.'), + 'clouds': ('Clouds', 'Mature snapshots; one collection per snapshot, VDB next to the .blend. Tiled LES fields (LASSO 3x3, UCLA 7x7) keep their periodic tiling.'), +} + + +def mb(p): + return f'{os.path.getsize(os.path.join(R, p)) / 1e6:.1f} MB' + + +for d, (title, blurb) in TITLES.items(): + jobs = json.load(open(os.path.join(R, 'tools/preview_jobs', d + '.json'))) + rows = [] + for j in jobs: + pv = os.path.relpath(os.path.join(R, j['out']), os.path.join(R, d)) + lib = os.path.relpath(os.path.join(R, j['lib']), os.path.join(R, d)) + img = f'' if os.path.exists(os.path.join(R, j['out'])) else '(no preview)' + rows.append(f'| {img} | `{j["coll"]}` | [`{lib}`]({lib}) ({mb(j["lib"])}) |') + extra = '' + if d == 'clouds': + extra = '\n\nVDB files:\n\n' + '\n'.join(f'* `{os.path.relpath(v, os.path.join(R, d))}` ({os.path.getsize(v) / 1e6:.1f} MB)' + for v in sorted(glob.glob(os.path.join(R, d, '*', '*.vdb')))) + with open(os.path.join(R, d, 'README.md'), 'w') as f: + f.write(f'# {title}\n\n{blurb}\n\n| Preview | Collection | File |\n|---|---|---|\n' + '\n'.join(rows) + extra + '\n') + +# scenes +rows = [] +for name in ['M1', 'S1', 'S2']: + imgs = sorted(glob.glob(os.path.join(R, 'scenes/preview', name + '_*.jpg'))) + layers = sorted(glob.glob(os.path.join(R, 'scenes', name, 'layers', '*.blend'))) + rows.append(f'## {name}\n\n`{name}/{name}.blend` ({mb(f"scenes/{name}/{name}.blend")}) — layers: ' + + ', '.join(f'`{os.path.relpath(l, os.path.join(R, "scenes"))}` ({os.path.getsize(l) / 1e6:.1f} MB)' for l in layers) + '\n\n' + + ' '.join(f'' for i in imgs)) +tests = sorted(glob.glob(os.path.join(R, 'scenes/tests/*.blend'))) +trow = [] +for t in tests: + n = os.path.basename(t)[:-6] + i = glob.glob(os.path.join(R, 'scenes/preview', f'test_{n}_*.jpg')) + trow.append(f'| `tests/{n}.blend` | ' + (f'' if i else '') + ' |') +with open(os.path.join(R, 'scenes/README.md'), 'w') as f: + f.write('# Scenes\n\nEach site scene is a thin file holding cameras, lights, world and render settings; ' + 'everything else is linked from the asset folders and from `layers/` (terrain, fields, vegetation, site infrastructure in site coordinates).\n\n' + + '\n\n'.join(rows) + '\n\n## Test scenes\n\n| Scene | Preview |\n|---|---|\n' + '\n'.join(trow) + '\n') +print('catalogues written') diff --git a/tools/preview_jobs/buildings.json b/tools/preview_jobs/buildings.json new file mode 100644 index 0000000..eb2b4e0 --- /dev/null +++ b/tools/preview_jobs/buildings.json @@ -0,0 +1,119 @@ +[ + { + "lib": "buildings/m1_farmstead.blend", + "coll": "Farmstead", + "out": "buildings/preview/Farmstead.jpg", + "view": "aerial", + "res": [ + 1280, + 800 + ], + "trim": 30, + "tight": 0.8, + "scene_view": "scenes/preview/M1_Cam_M1_Yard.jpg" + }, + { + "lib": "buildings/flagpole.blend", + "coll": "Flagpole", + "out": "buildings/preview/Flagpole.jpg", + "view": "34", + "res": [ + 1280, + 800 + ], + "tight": 1.0 + }, + { + "lib": "buildings/signs/sign_M1.blend", + "coll": "SIGN_M1", + "out": "buildings/preview/SIGN_M1.jpg", + "view": "front_x", + "res": [ + 1280, + 800 + ], + "tight": 0.45, + "zfrac": 0.82 + }, + { + "lib": "buildings/signs/sign_S1.blend", + "coll": "SIGN_S1", + "out": "buildings/preview/SIGN_S1.jpg", + "view": "front_x", + "res": [ + 1280, + 800 + ], + "tight": 0.45, + "zfrac": 0.82 + }, + { + "lib": "buildings/signs/sign_S2.blend", + "coll": "SIGN_S2", + "out": "buildings/preview/SIGN_S2.jpg", + "view": "front_x", + "res": [ + 1280, + 800 + ], + "tight": 0.45, + "zfrac": 0.82 + }, + { + "lib": "buildings/center_pivots.blend", + "coll": "Pivot_P3", + "out": "buildings/preview/Pivot_P3.jpg", + "view": "aerial", + "res": [ + 1280, + 800 + ], + "tight": 0.6 + }, + { + "lib": "buildings/center_pivots.blend", + "coll": "Pivot_P1", + "out": "buildings/preview/Pivot_P1.jpg", + "view": "aerial", + "res": [ + 1280, + 800 + ], + "tight": 0.6 + }, + { + "lib": "buildings/louisa_station.blend", + "coll": "LOUISA_Station", + "out": "buildings/preview/LOUISA_Station.jpg", + "view": "aerial", + "res": [ + 1280, + 800 + ] + }, + { + "lib": "buildings/s1_mirf_buildings.blend", + "coll": "S1_MIRF_Buildings", + "out": "buildings/preview/S1_MIRF_Buildings.jpg", + "view": "aerial", + "res": [ + 1280, + 800 + ], + "trim": 12, + "tight": 0.75, + "scene_view": "scenes/preview/S1_Cam_Aerial_SW.jpg" + }, + { + "lib": "buildings/s2_kawg_buildings.blend", + "coll": "S2_KAWG_Buildings", + "out": "buildings/preview/S2_KAWG_Buildings.jpg", + "view": "aerial", + "res": [ + 1280, + 800 + ], + "trim": 5, + "tight": 0.65 + } +] \ No newline at end of file diff --git a/tools/preview_jobs/clouds.json b/tools/preview_jobs/clouds.json new file mode 100644 index 0000000..9f10d5b --- /dev/null +++ b/tools/preview_jobs/clouds.json @@ -0,0 +1,172 @@ +[ + { + "lib": "clouds/cm1_bomex_cumulus/cm1_bomex_cumulus.blend", + "coll": "CLOUD_bomex_t360", + "out": "clouds/preview/bomex_t360.jpg", + "view": "cloud", + "res": [ + 960, + 540 + ], + "samples": 24 + }, + { + "lib": "clouds/cm1_bomex_cumulus/cm1_bomex_cumulus.blend", + "coll": "CLOUD_bomex_t300", + "out": "clouds/preview/bomex_t300.jpg", + "view": "cloud", + "res": [ + 960, + 540 + ], + "samples": 24 + }, + { + "lib": "clouds/cm1_bomex_cumulus/cm1_bomex_cumulus.blend", + "coll": "CLOUD_bomex_t240", + "out": "clouds/preview/bomex_t240.jpg", + "view": "cloud", + "res": [ + 960, + 540 + ], + "samples": 24 + }, + { + "lib": "clouds/cm1_supercell/cm1_supercell.blend", + "coll": "CLOUD_supercell_s250_t60", + "out": "clouds/preview/supercell_s250_t60.jpg", + "view": "cloud", + "res": [ + 960, + 540 + ], + "samples": 16, + "volume_bounces": 48, + "dist": 0.55, + "cam_z": 1500.0 + }, + { + "lib": "clouds/cm1_supercell/cm1_supercell.blend", + "coll": "CLOUD_supercell_s250_t45", + "out": "clouds/preview/supercell_s250_t45.jpg", + "view": "cloud", + "res": [ + 960, + 540 + ], + "samples": 16, + "volume_bounces": 48, + "dist": 0.55, + "cam_z": 1500.0 + }, + { + "lib": "clouds/cm1_supercell/cm1_supercell.blend", + "coll": "CLOUD_supercell_s100_t60", + "out": "clouds/preview/supercell_s100_t60.jpg", + "view": "cloud", + "res": [ + 960, + 540 + ], + "samples": 16, + "volume_bounces": 48, + "dist": 0.55, + "cam_z": 1500.0 + }, + { + "lib": "clouds/cm1_supercell/cm1_supercell.blend", + "coll": "CLOUD_supercell_s100_t45", + "out": "clouds/preview/supercell_s100_t45.jpg", + "view": "cloud", + "res": [ + 960, + 540 + ], + "samples": 16, + "volume_bounces": 48, + "dist": 0.55, + "cam_z": 1500.0 + }, + { + "lib": "clouds/cm1_supercell/cm1_supercell.blend", + "coll": "CLOUD_supercell_c100_t25", + "out": "clouds/preview/supercell_c100_t25.jpg", + "view": "cloud", + "res": [ + 960, + 540 + ], + "samples": 16, + "volume_bounces": 48, + "scene_view": "scenes/preview/test_m1_supercell_Cam_Storm_Sign.jpg" + }, + { + "lib": "clouds/lasso_sgp_20170403/lasso_sgp_20170403.blend", + "coll": "CLOUD_lasso_2000", + "out": "clouds/preview/lasso_2000.jpg", + "view": "cloud", + "res": [ + 960, + 540 + ], + "samples": 24 + }, + { + "lib": "clouds/lasso_sgp_20170403/lasso_sgp_20170403.blend", + "coll": "CLOUD_lasso_1900", + "out": "clouds/preview/lasso_1900.jpg", + "view": "cloud", + "res": [ + 960, + 540 + ], + "samples": 24 + }, + { + "lib": "clouds/lasso_sgp_20170403/lasso_sgp_20170403.blend", + "coll": "CLOUD_lasso_1800", + "out": "clouds/preview/lasso_1800.jpg", + "view": "cloud", + "res": [ + 960, + 540 + ], + "samples": 24 + }, + { + "lib": "clouds/lasso_sgp_20170403/lasso_sgp_20170403.blend", + "coll": "CLOUD_lasso_1740", + "out": "clouds/preview/lasso_1740.jpg", + "view": "cloud", + "res": [ + 960, + 540 + ], + "samples": 24 + }, + { + "lib": "clouds/lasso_sgp_20170403/lasso_sgp_20170403.blend", + "coll": "CLOUD_lasso8_2040", + "out": "clouds/preview/lasso8_2040.jpg", + "view": "cloud", + "res": [ + 960, + 540 + ], + "samples": 24, + "scene_view": "scenes/preview/test_m1_lasso_cumulus_Cam_M1_Aerial_SE.jpg" + }, + { + "lib": "clouds/ucla_cumulus/ucla_cumulus.blend", + "coll": "CLOUD_ucla_t6600", + "out": "clouds/preview/ucla_t6600.jpg", + "view": "cloud", + "res": [ + 960, + 540 + ], + "samples": 24, + "scene_view": "scenes/preview/test_s1_ucla_cumulus_Cam_Aerial_SW.jpg" + } +] \ No newline at end of file diff --git a/tools/preview_jobs/containers.json b/tools/preview_jobs/containers.json new file mode 100644 index 0000000..78961c3 --- /dev/null +++ b/tools/preview_jobs/containers.json @@ -0,0 +1,134 @@ +[ + { + "lib": "containers/amf2_containers.blend", + "coll": "CONT_RentalContainer", + "out": "containers/preview/CONT_RentalContainer.jpg", + "view": "34", + "res": [ + 1024, + 768 + ], + "tight": 0.95 + }, + { + "lib": "containers/amf2_containers.blend", + "coll": "CONT_OfficeShelter", + "out": "containers/preview/CONT_OfficeShelter.jpg", + "view": "34", + "res": [ + 1024, + 768 + ], + "tight": 0.95 + }, + { + "lib": "containers/amf2_containers.blend", + "coll": "CONT_AOS_Platform", + "out": "containers/preview/CONT_AOS_Platform.jpg", + "view": "34", + "res": [ + 1024, + 768 + ], + "tight": 0.95 + }, + { + "lib": "containers/amf2_containers.blend", + "coll": "CONT_8_STORAGE", + "out": "containers/preview/CONT_8_STORAGE.jpg", + "view": "34", + "res": [ + 1024, + 768 + ], + "tight": 0.95 + }, + { + "lib": "containers/amf2_containers.blend", + "coll": "CONT_7_SACR", + "out": "containers/preview/CONT_7_SACR.jpg", + "view": "34", + "res": [ + 1024, + 768 + ], + "tight": 0.95 + }, + { + "lib": "containers/amf2_containers.blend", + "coll": "CONT_6_KAZR", + "out": "containers/preview/CONT_6_KAZR.jpg", + "view": "34", + "res": [ + 1024, + 768 + ], + "tight": 0.95 + }, + { + "lib": "containers/amf2_containers.blend", + "coll": "CONT_5_LIDAR", + "out": "containers/preview/CONT_5_LIDAR.jpg", + "view": "34", + "res": [ + 1024, + 768 + ], + "tight": 0.95 + }, + { + "lib": "containers/amf2_containers.blend", + "coll": "CONT_4_RADIOMETERS", + "out": "containers/preview/CONT_4_RADIOMETERS.jpg", + "view": "34", + "res": [ + 1024, + 768 + ], + "tight": 0.95 + }, + { + "lib": "containers/amf2_containers.blend", + "coll": "CONT_3_OPS", + "out": "containers/preview/CONT_3_OPS.jpg", + "view": "34", + "res": [ + 1024, + 768 + ], + "tight": 0.95 + }, + { + "lib": "containers/amf2_containers.blend", + "coll": "CONT_2_AOS_B", + "out": "containers/preview/CONT_2_AOS_B.jpg", + "view": "34", + "res": [ + 1024, + 768 + ], + "tight": 0.95 + }, + { + "lib": "containers/amf2_containers.blend", + "coll": "CONT_1_AOS_A", + "out": "containers/preview/CONT_1_AOS_A.jpg", + "view": "34", + "res": [ + 1024, + 768 + ], + "tight": 0.95 + }, + { + "lib": "containers/sacr_container_s2.blend", + "coll": "CONT_7_SACR_S2", + "out": "containers/preview/CONT_7_SACR_S2.jpg", + "view": "34", + "res": [ + 1024, + 768 + ], + "tight": 0.95 + } +] \ No newline at end of file diff --git a/tools/preview_jobs/instruments.json b/tools/preview_jobs/instruments.json new file mode 100644 index 0000000..92587d2 --- /dev/null +++ b/tools/preview_jobs/instruments.json @@ -0,0 +1,277 @@ +[ + { + "lib": "instruments/AERI/AERI.blend", + "coll": "INST_AERI", + "out": "instruments/preview/AERI.jpg", + "view": "34", + "res": [ + 1024, + 768 + ], + "samples": 64 + }, + { + "lib": "instruments/AOSMET/AOSMET.blend", + "coll": "INST_AOSMET", + "out": "instruments/preview/AOSMET.jpg", + "view": "34", + "res": [ + 1024, + 768 + ], + "samples": 64 + }, + { + "lib": "instruments/ASI/ASI.blend", + "coll": "INST_ASI", + "out": "instruments/preview/ASI.jpg", + "view": "34", + "res": [ + 1024, + 768 + ], + "samples": 64 + }, + { + "lib": "instruments/AWOS/AWOS.blend", + "coll": "INST_AWOS", + "out": "instruments/preview/AWOS.jpg", + "view": "34", + "res": [ + 1024, + 768 + ], + "samples": 64 + }, + { + "lib": "instruments/CEIL/CEIL.blend", + "coll": "INST_CEIL", + "out": "instruments/preview/CEIL.jpg", + "view": "34", + "res": [ + 1024, + 768 + ], + "samples": 64 + }, + { + "lib": "instruments/CSAPR2/CSAPR2.blend", + "coll": "CSAPR2", + "out": "instruments/preview/CSAPR2.jpg", + "view": "34", + "res": [ + 1024, + 768 + ], + "samples": 64 + }, + { + "lib": "instruments/CSPHOT/CSPHOT.blend", + "coll": "INST_CSPHOT", + "out": "instruments/preview/CSPHOT.jpg", + "view": "34", + "res": [ + 1024, + 768 + ], + "samples": 64 + }, + { + "lib": "instruments/DL/DL.blend", + "coll": "INST_DL", + "out": "instruments/preview/DL.jpg", + "view": "34", + "res": [ + 1024, + 768 + ], + "samples": 64 + }, + { + "lib": "instruments/ECOR/ECOR.blend", + "coll": "INST_ECOR_4m", + "out": "instruments/preview/ECOR_4m.jpg", + "view": "34", + "res": [ + 1024, + 768 + ], + "samples": 64 + }, + { + "lib": "instruments/ECOR/ECOR.blend", + "coll": "INST_ECOR", + "out": "instruments/preview/ECOR.jpg", + "view": "34", + "res": [ + 1024, + 768 + ], + "samples": 64 + }, + { + "lib": "instruments/IRT/IRT.blend", + "coll": "INST_IRT", + "out": "instruments/preview/IRT.jpg", + "view": "34", + "res": [ + 1024, + 768 + ], + "samples": 64 + }, + { + "lib": "instruments/KAZR/KAZR.blend", + "coll": "INST_KAZR", + "out": "instruments/preview/KAZR.jpg", + "view": "34", + "res": [ + 1024, + 768 + ], + "samples": 64 + }, + { + "lib": "instruments/LDIS/LDIS.blend", + "coll": "INST_LDIS", + "out": "instruments/preview/LDIS.jpg", + "view": "34", + "res": [ + 1024, + 768 + ], + "samples": 64 + }, + { + "lib": "instruments/MAWS/MAWS.blend", + "coll": "INST_MAWS", + "out": "instruments/preview/MAWS.jpg", + "view": "34", + "res": [ + 1024, + 768 + ], + "samples": 64 + }, + { + "lib": "instruments/MET/MET.blend", + "coll": "INST_MET", + "out": "instruments/preview/MET.jpg", + "view": "34", + "res": [ + 1024, + 768 + ], + "samples": 64 + }, + { + "lib": "instruments/MFR/MFR.blend", + "coll": "INST_MFR", + "out": "instruments/preview/MFR.jpg", + "view": "34", + "res": [ + 1024, + 768 + ], + "samples": 64 + }, + { + "lib": "instruments/MFRSR/MFRSR.blend", + "coll": "INST_MFRSR", + "out": "instruments/preview/MFRSR.jpg", + "view": "34", + "res": [ + 1024, + 768 + ], + "samples": 64 + }, + { + "lib": "instruments/MPL/MPL.blend", + "coll": "INST_MPL", + "out": "instruments/preview/MPL.jpg", + "view": "34", + "res": [ + 1024, + 768 + ], + "samples": 64 + }, + { + "lib": "instruments/MWR3C/MWR3C.blend", + "coll": "INST_MWR3C", + "out": "instruments/preview/MWR3C.jpg", + "view": "34", + "res": [ + 1024, + 768 + ], + "samples": 64 + }, + { + "lib": "instruments/RWP/RWP.blend", + "coll": "INST_RWP", + "out": "instruments/preview/RWP.jpg", + "view": "34", + "res": [ + 1024, + 768 + ], + "samples": 64 + }, + { + "lib": "instruments/SEBS/SEBS.blend", + "coll": "INST_SEBS", + "out": "instruments/preview/SEBS.jpg", + "view": "34", + "res": [ + 1024, + 768 + ], + "samples": 64 + }, + { + "lib": "instruments/SIRS/SIRS.blend", + "coll": "INST_SIRS", + "out": "instruments/preview/SIRS.jpg", + "view": "34", + "res": [ + 1024, + 768 + ], + "samples": 64 + }, + { + "lib": "instruments/SONDE/SONDE.blend", + "coll": "INST_SONDE", + "out": "instruments/preview/SONDE.jpg", + "view": "34", + "res": [ + 1024, + 768 + ], + "samples": 64 + }, + { + "lib": "instruments/VDIS/VDIS.blend", + "coll": "INST_VDIS", + "out": "instruments/preview/VDIS.jpg", + "view": "34", + "res": [ + 1024, + 768 + ], + "samples": 64 + }, + { + "lib": "instruments/WB/WB.blend", + "coll": "INST_WB", + "out": "instruments/preview/WB.jpg", + "view": "34", + "res": [ + 1024, + 768 + ], + "samples": 64 + } +] \ No newline at end of file diff --git a/tools/preview_jobs/plants.json b/tools/preview_jobs/plants.json new file mode 100644 index 0000000..65366be --- /dev/null +++ b/tools/preview_jobs/plants.json @@ -0,0 +1,122 @@ +[ + { + "lib": "plants/crops.blend", + "coll": "CornVariants", + "out": "plants/preview/CornVariants.jpg", + "view": "lineup", + "res": [ + 1600, + 700 + ] + }, + { + "lib": "plants/crops.blend", + "coll": "SoyVariants", + "out": "plants/preview/SoyVariants.jpg", + "view": "lineup", + "res": [ + 1600, + 700 + ] + }, + { + "lib": "plants/grasses.blend", + "coll": "GrassVariants", + "out": "plants/preview/GrassVariants.jpg", + "view": "lineup", + "res": [ + 1600, + 700 + ] + }, + { + "lib": "plants/grasses.blend", + "coll": "TallGrassVariants", + "out": "plants/preview/TallGrassVariants.jpg", + "view": "lineup", + "res": [ + 1600, + 700 + ] + }, + { + "lib": "plants/grasses_s2.blend", + "coll": "GrassVariants_S2", + "out": "plants/preview/GrassVariants_S2.jpg", + "view": "lineup", + "res": [ + 1600, + 700 + ] + }, + { + "lib": "plants/grasses_s2.blend", + "coll": "TallGrassVariants_S2", + "out": "plants/preview/TallGrassVariants_S2.jpg", + "view": "lineup", + "res": [ + 1600, + 700 + ] + }, + { + "lib": "plants/trees.blend", + "coll": "TreeVariants", + "out": "plants/preview/TreeVariants.jpg", + "view": "lineup", + "res": [ + 1600, + 700 + ] + }, + { + "lib": "plants/trees_hd.blend", + "coll": "TV_Decid_HD", + "out": "plants/preview/TV_Decid_HD.jpg", + "view": "lineup", + "res": [ + 1600, + 700 + ] + }, + { + "lib": "plants/trees_hd.blend", + "coll": "TV_Spruce_HD", + "out": "plants/preview/TV_Spruce_HD.jpg", + "view": "lineup", + "res": [ + 1600, + 700 + ] + }, + { + "lib": "plants/trees_hd.blend", + "coll": "TV_DecidBaked_HD", + "out": "plants/preview/TV_DecidBaked_HD.jpg", + "view": "lineup", + "res": [ + 1600, + 700 + ] + }, + { + "lib": "plants/trees_hd.blend", + "coll": "TV_Far_HD", + "out": "plants/preview/TV_Far_HD.jpg", + "view": "lineup", + "res": [ + 1600, + 700 + ] + }, + { + "lib": "plants/native_flowers.blend", + "coll": "NativeFlowerVariants", + "out": "plants/preview/NativeFlowerVariants.jpg", + "view": "lineup", + "res": [ + 1600, + 700 + ] + } +] \ No newline at end of file diff --git a/tools/preview_jobs/vehicles.json b/tools/preview_jobs/vehicles.json new file mode 100644 index 0000000..7f6b7ce --- /dev/null +++ b/tools/preview_jobs/vehicles.json @@ -0,0 +1,90 @@ +[ + { + "lib": "vehicles/farm_vehicles.blend", + "coll": "VEH_Tractor_Green", + "out": "vehicles/preview/VEH_Tractor_Green.jpg", + "view": "34", + "res": [ + 1024, + 768 + ], + "tight": 0.9 + }, + { + "lib": "vehicles/farm_vehicles.blend", + "coll": "VEH_Telehandler_Yellow", + "out": "vehicles/preview/VEH_Telehandler_Yellow.jpg", + "view": "34", + "res": [ + 1024, + 768 + ], + "tight": 0.9 + }, + { + "lib": "vehicles/farm_vehicles.blend", + "coll": "VEH_Pickup_White", + "out": "vehicles/preview/VEH_Pickup_White.jpg", + "view": "34", + "res": [ + 1024, + 768 + ], + "tight": 0.9 + }, + { + "lib": "vehicles/farm_vehicles.blend", + "coll": "VEH_Implement_Disk_Green", + "out": "vehicles/preview/VEH_Implement_Disk_Green.jpg", + "view": "34", + "res": [ + 1024, + 768 + ], + "tight": 0.9 + }, + { + "lib": "vehicles/farm_vehicles.blend", + "coll": "VEH_GrainCart_Red", + "out": "vehicles/preview/VEH_GrainCart_Red.jpg", + "view": "34", + "res": [ + 1024, + 768 + ], + "tight": 0.9 + }, + { + "lib": "vehicles/farm_vehicles.blend", + "coll": "VEH_Gooseneck_Flatbed", + "out": "vehicles/preview/VEH_Gooseneck_Flatbed.jpg", + "view": "34", + "res": [ + 1024, + 768 + ], + "tight": 0.9 + }, + { + "lib": "vehicles/farm_vehicles.blend", + "coll": "VEH_Cultivator_Red", + "out": "vehicles/preview/VEH_Cultivator_Red.jpg", + "view": "34", + "res": [ + 1024, + 768 + ], + "tight": 0.9 + }, + { + "lib": "vehicles/c850_arm.blend", + "coll": "C850_ARM", + "out": "vehicles/preview/C850_ARM.jpg", + "view": "34", + "res": [ + 1024, + 768 + ], + "tight": 0.62 + } +] \ No newline at end of file diff --git a/tools/render_previews.py b/tools/render_previews.py new file mode 100644 index 0000000..6589e20 --- /dev/null +++ b/tools/render_previews.py @@ -0,0 +1,166 @@ +"""Studio preview renders of library assets. +blender -b --factory-startup --python tools/render_previews.py -- jobs.json +Each job: {"lib": "instruments/AERI/AERI.blend", "coll": "INST_AERI", "out": "instruments/preview/AERI.jpg", + "view": "34" | "aerial" | "lineup" | "cloud", "samples": 64, "res": [1280, 960]} +The world (sky) and sun are linked from scenes/M1/M1.blend so previews match the scenes. +""" +import bpy, sys, os, json, math +from mathutils import Vector, Matrix +REPO = os.environ.get('ABLE_REPO') or os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +jobs = json.load(open(sys.argv[sys.argv.index('--') + 1])) + +# ---- one-time studio setup +sc = bpy.context.scene +for o in list(bpy.data.objects): + bpy.data.objects.remove(o) +m1 = os.path.join(REPO, 'scenes/M1/M1.blend') +with bpy.data.libraries.load(m1, link=True, relative=False) as (s, d): + d.worlds = ['World'] + d.objects = ['Sun'] +sc.world = d.worlds[0] +sun = d.objects[0] +with bpy.data.libraries.load(m1, link=True, relative=False) as (s2, d2): + d2.scenes = [s2.scenes[0]] +src = d2.scenes[0] +for attr in ('view_transform', 'look', 'exposure', 'gamma'): + try: + setattr(sc.view_settings, attr, getattr(src.view_settings, attr)) + except Exception as e: + print('view setting', attr, e) +sc.display_settings.display_device = src.display_settings.display_device +sc.collection.objects.link(sun) +ground_mat = bpy.data.materials.new('PreviewGround') +ground_mat.use_nodes = True +bsdf = ground_mat.node_tree.nodes.get('Principled BSDF') +bsdf.inputs['Base Color'].default_value = (0.32, 0.30, 0.27, 1) +bsdf.inputs['Roughness'].default_value = 0.9 +r = sc.render +r.engine = 'CYCLES' +sc.cycles.use_denoising = True +r.image_settings.file_format = 'JPEG'; r.image_settings.quality = 90 +try: + p = bpy.context.preferences.addons['cycles'].preferences + p.compute_device_type = 'METAL'; p.get_devices() + for dv in p.devices: dv.use = True + sc.cycles.device = 'GPU' +except Exception as e: + print('GPU setup failed', e) + +cam_data = bpy.data.cameras.new('PreviewCam'); cam_data.lens = 50 +cam = bpy.data.objects.new('PreviewCam', cam_data); sc.collection.objects.link(cam); sc.camera = cam + + +def link_coll(lib, name): + with bpy.data.libraries.load(os.path.join(REPO, lib), link=True, relative=False) as (s, d): + d.collections = [name] + return d.collections[0] + + +def bounds(empties, trim=0.0): + dg = bpy.context.evaluated_depsgraph_get() + lo = Vector((1e18,) * 3); hi = Vector((-1e18,) * 3); n = 0 + pts = [] + for inst in dg.object_instances: + if not inst.is_instance or inst.parent is None or inst.parent.original not in empties: + continue + o = inst.object + if o.type in ('CAMERA', 'LIGHT', 'EMPTY'): + continue + for c in o.bound_box: + w = inst.matrix_world @ Vector(c) + pts.append(w) + lo = Vector(map(min, lo, w)); hi = Vector(map(max, hi, w)); n += 1 + if trim and pts: + import numpy as np + a = np.array([tuple(p) for p in pts]) + lo = Vector(np.percentile(a, trim, axis=0)); hi = Vector(np.percentile(a, 100 - trim, axis=0)) + return lo, hi, n + + +def frame(lo, hi, view, res, j_tight=0.72, zfrac=0.5): + ctr = (lo + hi) / 2; ext = hi - lo + ctr.z = lo.z + zfrac * ext.z + rad = max(ext.length / 2, 0.3) + d = {'34': Vector((-1.0, -1.35, 0.62)), 'aerial': Vector((-0.75, -1.0, 1.15)), + 'lineup': Vector((0.0, -1.0, 0.28)), 'cloud': Vector((-0.6, -1.0, 0.22)), + 'top': Vector((0.0, -0.02, 1.0)), 'front_x': Vector((1.0, -0.35, 0.22))}[view].normalized() + half = math.atan(18.0 / cam_data.lens) * (min(res) / max(res) if res[0] >= res[1] else 1) + dist = rad / math.sin(half) * j_tight + cam.location = ctr + d * dist + cam.rotation_euler = (-d).to_track_quat('-Z', 'Y').to_euler() + cam_data.clip_start = max(0.01, dist / 2000); cam_data.clip_end = dist * 4 + ext.length * 2 + return ctr, ext + + +made = [] +for j in jobs: + if j.get('scene_view'): # site layers spread over kilometres read better in their scene + import shutil + shutil.copy(os.path.join(REPO, j['scene_view']), os.path.join(REPO, j['out'])) + continue + res = j.get('res', [1280, 960]); r.resolution_x, r.resolution_y = res; r.resolution_percentage = 100 + sc.cycles.samples = j.get('samples', 64) + # cloud scenes in the working files use deep volume scattering + sc.cycles.volume_bounces = j.get('volume_bounces', 16) if j.get('view') == 'cloud' else 1 + sc.cycles.max_bounces = 20 if j.get('view') == 'cloud' else 4 + sc.cycles.sample_clamp_indirect = 10.0 + view = j.get('view', '34') + coll = link_coll(j['lib'], j['coll']) + for ob in coll.all_objects: # volume bounds are only known once the grids are read + if ob.type == 'VOLUME': + ob.data.grids.load() + empties = [] + if view == 'lineup': + objs = sorted([o for o in coll.all_objects if o.type in ('MESH', 'CURVE', 'VOLUME') and o.parent is None], key=lambda o: o.name) + x = 0.0 + for o in objs: + dims = Vector(o.dimensions) if any(o.dimensions) else Vector((1, 1, 1)) + if dims.length == 0: dims = Vector((1, 1, 1)) + c = bpy.data.collections.new('LU_' + o.name); c.objects.link(o) + c.instance_offset = o.matrix_world.translation + e = bpy.data.objects.new('LU_' + o.name, None); e.instance_type = 'COLLECTION'; e.instance_collection = c + w = max(dims.x, dims.y, 0.2) + e.location = (x + w / 2, 0, 0); x += w * 1.25 + sc.collection.objects.link(e); empties.append(e) + else: + e = bpy.data.objects.new('PV_' + j['coll'], None); e.instance_type = 'COLLECTION'; e.instance_collection = coll + sc.collection.objects.link(e); empties.append(e) + bpy.context.view_layer.update() + lo, hi, n = bounds(empties, j.get('trim', 0.0)) + if n == 0: + print('NOTHING TO FRAME', j); continue + if view == 'cloud': + ctr = (lo + hi) / 2; ext = hi - lo + L = sun.matrix_world.to_3x3() @ Vector((0, 0, -1)) + h = Vector((L.x, L.y, 0)).normalized() + wide = max(ext.x, ext.y) + nvol = sum(1 for ob in coll.all_objects if ob.type == 'VOLUME') + if nvol > 1: # tiled periodic LES field: stand inside it + cam_data.lens = 20 + cam.location = Vector((ctr.x, ctr.y, 2.0)) - h * (0.18 * wide) + target = cam.location + h * 10000 + Vector((0, 0, 2600)) + else: # single storm: elevated, sun behind, whole cell in view + cam_data.lens = 35 + cam.location = Vector((ctr.x, ctr.y, j.get('cam_z', 3000.0))) - h * (j.get('dist', 2.2) * wide) + target = Vector((ctr.x, ctr.y, lo.z + 0.3 * ext.z)) + cam.rotation_euler = (target - cam.location).to_track_quat('-Z', 'Y').to_euler() + cam_data.clip_start = 0.5; cam_data.clip_end = wide * 6 + ctr = Vector((cam.location.x, cam.location.y, 0)); ext = Vector((wide, wide, ext.z)) + else: + cam_data.lens = 50 + ctr, ext = frame(lo, hi, view, res, j.get('tight', 0.72 if view in ('34', 'lineup') else 0.85), j.get('zfrac', 0.5)) + gsize = max(ext.x, ext.y, 1.0) * (40 if view != 'cloud' else 12) + bpy.ops.mesh.primitive_plane_add(size=gsize, location=(ctr.x, ctr.y, lo.z - 0.002 if view != 'cloud' else 0.0)) + g = bpy.context.active_object; g.data.materials.append(ground_mat) + out = os.path.join(REPO, j['out']); os.makedirs(os.path.dirname(out), exist_ok=True) + r.filepath = out + bpy.ops.render.render(write_still=True) + made.append(j['out']); print('PREVIEW', j['out'], flush=True) + # clean up for the next job + bpy.data.objects.remove(g) + for e in empties: + ic = e.instance_collection + bpy.data.objects.remove(e) + if ic.name.startswith('LU_'): + bpy.data.collections.remove(ic) +print('PREVIEWS_DONE', len(made)) diff --git a/tools/render_scene_views.py b/tools/render_scene_views.py new file mode 100644 index 0000000..728fcd1 --- /dev/null +++ b/tools/render_scene_views.py @@ -0,0 +1,26 @@ +"""Render preview stills of a scene from its own cameras (scene lighting and settings kept). +blender -b scenes/M1/M1.blend --python tools/render_scene_views.py -- [samples] [WxH] +""" +import bpy, sys, os +args = sys.argv[sys.argv.index('--') + 1:] +prefix, cams = args[0], args[1].split(',') +spp = int(args[2]) if len(args) > 2 else 96 +sc = bpy.context.scene; r = sc.render +r.engine = 'CYCLES'; sc.cycles.samples = spp; sc.cycles.use_denoising = True +w, h = (int(v) for v in args[3].split('x')) if len(args) > 3 else (1600, 900) +r.resolution_x, r.resolution_y, r.resolution_percentage = w, h, 100 +if len(args) > 4: # preview-only cap on volume bounces (the scene file keeps its own setting) + sc.cycles.volume_bounces = min(sc.cycles.volume_bounces, int(args[4])) +r.image_settings.file_format = 'JPEG'; r.image_settings.quality = 90 +try: + p = bpy.context.preferences.addons['cycles'].preferences + p.compute_device_type = 'METAL'; p.get_devices() + for d in p.devices: d.use = True + sc.cycles.device = 'GPU' +except Exception as e: + print('GPU setup failed', e) +for c in cams: + sc.camera = bpy.data.objects[c] + r.filepath = f'{prefix}_{c}.jpg' + bpy.ops.render.render(write_still=True) + print('VIEW', r.filepath, flush=True) diff --git a/tools/reports/build_m1.json b/tools/reports/build_m1.json new file mode 100644 index 0000000..29d3170 --- /dev/null +++ b/tools/reports/build_m1.json @@ -0,0 +1,488 @@ +{ + "written": [ + [ + "plants/crops.blend", + [ + "CornVariants", + "SoyVariants" + ], + 655756 + ], + [ + "plants/grasses.blend", + [ + "GrassVariants", + "TallGrassVariants" + ], + 282645 + ], + [ + "plants/trees.blend", + [ + "TreeVariants", + "TV_Decid", + "TV_Spruce", + "TV_Far", + "TreeParts" + ], + 3353180 + ], + [ + "scenes/M1/layers/m1_ground.blend", + [ + "Ground" + ], + 45358694 + ], + [ + "instruments/AERI/AERI.blend", + [ + "INST_AERI" + ], + 172354 + ], + [ + "instruments/AOSMET/AOSMET.blend", + [ + "INST_AOSMET" + ], + 135496 + ], + [ + "instruments/KAZR/KAZR.blend", + [ + "INST_KAZR" + ], + 211996 + ], + [ + "instruments/DL/DL.blend", + [ + "INST_DL" + ], + 181669 + ], + [ + "instruments/MPL/MPL.blend", + [ + "INST_MPL" + ], + 143107 + ], + [ + "instruments/MWR3C/MWR3C.blend", + [ + "INST_MWR3C" + ], + 150404 + ], + [ + "instruments/MET/MET.blend", + [ + "INST_MET" + ], + 260782 + ], + [ + "instruments/ECOR/ECOR.blend", + [ + "INST_ECOR", + "INST_ECOR_4m" + ], + 261872 + ], + [ + "instruments/SEBS/SEBS.blend", + [ + "INST_SEBS" + ], + 187116 + ], + [ + "instruments/WB/WB.blend", + [ + "INST_WB" + ], + 191477 + ], + [ + "instruments/LDIS/LDIS.blend", + [ + "INST_LDIS" + ], + 138280 + ], + [ + "instruments/VDIS/VDIS.blend", + [ + "INST_VDIS" + ], + 130349 + ], + [ + "instruments/MFRSR/MFRSR.blend", + [ + "INST_MFRSR" + ], + 131271 + ], + [ + "instruments/SIRS/SIRS.blend", + [ + "INST_SIRS" + ], + 283836 + ], + [ + "instruments/CSPHOT/CSPHOT.blend", + [ + "INST_CSPHOT" + ], + 152991 + ], + [ + "instruments/ASI/ASI.blend", + [ + "INST_ASI" + ], + 191681 + ], + [ + "instruments/CEIL/CEIL.blend", + [ + "INST_CEIL" + ], + 120682 + ], + [ + "instruments/RWP/RWP.blend", + [ + "INST_RWP" + ], + 282435 + ], + [ + "instruments/IRT/IRT.blend", + [ + "INST_IRT" + ], + 139775 + ], + [ + "instruments/MAWS/MAWS.blend", + [ + "INST_MAWS" + ], + 164670 + ], + [ + "instruments/MFR/MFR.blend", + [ + "INST_MFR" + ], + 117949 + ], + [ + "instruments/SONDE/SONDE.blend", + [ + "INST_SONDE" + ], + 213176 + ], + [ + "containers/amf2_containers.blend", + [ + "CONT_1_AOS_A", + "CONT_2_AOS_B", + "CONT_3_OPS", + "CONT_4_RADIOMETERS", + "CONT_5_LIDAR", + "CONT_6_KAZR", + "CONT_7_SACR", + "CONT_8_STORAGE", + "CONT_AOS_Platform", + "CONT_OfficeShelter", + "CONT_RentalContainer" + ], + 242057 + ], + [ + "vehicles/farm_vehicles.blend", + [ + "VEH_Tractor_Green", + "VEH_Telehandler_Yellow", + "VEH_Pickup_White", + "VEH_Implement_Disk_Green", + "VEH_GrainCart_Red", + "VEH_Gooseneck_Flatbed", + "VEH_Cultivator_Red" + ], + 1034626 + ], + [ + "buildings/m1_farmstead.blend", + [ + "Farmstead" + ], + 270938 + ], + [ + "buildings/flagpole.blend", + [ + "Flagpole" + ], + 196185 + ], + [ + "buildings/signs/sign_M1.blend", + [ + "SIGN_M1" + ], + 876480 + ], + [ + "scenes/M1/layers/m1_fields.blend", + [ + "Fields" + ], + 11841152 + ], + [ + "scenes/M1/layers/m1_amf2_site.blend", + [ + "AMF2" + ], + 228961 + ] + ], + "linked": [ + [ + "plants/crops.blend", + [ + "CornVariants", + "SoyVariants" + ] + ], + [ + "plants/grasses.blend", + [ + "GrassVariants", + "TallGrassVariants" + ] + ], + [ + "plants/trees.blend", + [ + "TreeVariants", + "TV_Decid", + "TV_Spruce", + "TV_Far", + "TreeParts" + ] + ], + [ + "scenes/M1/layers/m1_ground.blend", + [ + "Ground" + ] + ], + [ + "instruments/AERI/AERI.blend", + [ + "INST_AERI" + ] + ], + [ + "instruments/AOSMET/AOSMET.blend", + [ + "INST_AOSMET" + ] + ], + [ + "instruments/KAZR/KAZR.blend", + [ + "INST_KAZR" + ] + ], + [ + "instruments/DL/DL.blend", + [ + "INST_DL" + ] + ], + [ + "instruments/MPL/MPL.blend", + [ + "INST_MPL" + ] + ], + [ + "instruments/MWR3C/MWR3C.blend", + [ + "INST_MWR3C" + ] + ], + [ + "instruments/MET/MET.blend", + [ + "INST_MET" + ] + ], + [ + "instruments/ECOR/ECOR.blend", + [ + "INST_ECOR", + "INST_ECOR_4m" + ] + ], + [ + "instruments/SEBS/SEBS.blend", + [ + "INST_SEBS" + ] + ], + [ + "instruments/WB/WB.blend", + [ + "INST_WB" + ] + ], + [ + "instruments/LDIS/LDIS.blend", + [ + "INST_LDIS" + ] + ], + [ + "instruments/VDIS/VDIS.blend", + [ + "INST_VDIS" + ] + ], + [ + "instruments/MFRSR/MFRSR.blend", + [ + "INST_MFRSR" + ] + ], + [ + "instruments/SIRS/SIRS.blend", + [ + "INST_SIRS" + ] + ], + [ + "instruments/CSPHOT/CSPHOT.blend", + [ + "INST_CSPHOT" + ] + ], + [ + "instruments/ASI/ASI.blend", + [ + "INST_ASI" + ] + ], + [ + "instruments/CEIL/CEIL.blend", + [ + "INST_CEIL" + ] + ], + [ + "instruments/RWP/RWP.blend", + [ + "INST_RWP" + ] + ], + [ + "instruments/IRT/IRT.blend", + [ + "INST_IRT" + ] + ], + [ + "instruments/MAWS/MAWS.blend", + [ + "INST_MAWS" + ] + ], + [ + "instruments/MFR/MFR.blend", + [ + "INST_MFR" + ] + ], + [ + "instruments/SONDE/SONDE.blend", + [ + "INST_SONDE" + ] + ], + [ + "containers/amf2_containers.blend", + [ + "CONT_1_AOS_A", + "CONT_2_AOS_B", + "CONT_3_OPS", + "CONT_4_RADIOMETERS", + "CONT_5_LIDAR", + "CONT_6_KAZR", + "CONT_7_SACR", + "CONT_8_STORAGE", + "CONT_AOS_Platform", + "CONT_OfficeShelter", + "CONT_RentalContainer" + ] + ], + [ + "vehicles/farm_vehicles.blend", + [ + "VEH_Tractor_Green", + "VEH_Telehandler_Yellow", + "VEH_Pickup_White", + "VEH_Implement_Disk_Green", + "VEH_GrainCart_Red", + "VEH_Gooseneck_Flatbed", + "VEH_Cultivator_Red" + ] + ], + [ + "buildings/m1_farmstead.blend", + [ + "Farmstead" + ] + ], + [ + "buildings/flagpole.blend", + [ + "Flagpole" + ] + ], + [ + "buildings/signs/sign_M1.blend", + [ + "SIGN_M1" + ] + ], + [ + "scenes/M1/layers/m1_fields.blend", + [ + "Fields" + ] + ], + [ + "scenes/M1/layers/m1_amf2_site.blend", + [ + "AMF2" + ] + ] + ], + "missing": [], + "warnings": [], + "mismatch": [], + "scene": [ + "scenes/M1/M1.blend", + 2318821 + ] +} \ No newline at end of file diff --git a/tools/reports/build_s1.json b/tools/reports/build_s1.json new file mode 100644 index 0000000..ec42075 --- /dev/null +++ b/tools/reports/build_s1.json @@ -0,0 +1,150 @@ +{ + "written": [ + [ + "plants/trees_hd.blend", + [ + "TV_Spruce_HD", + "TV_Decid_HD", + "TV_Far_HD", + "TreeParts_HD", + "TV_DecidBaked_HD" + ], + 42908567 + ], + [ + "plants/native_flowers.blend", + [ + "NativeFlowerVariants" + ], + 165634 + ], + [ + "scenes/S1/layers/s1_terrain.blend", + [ + "Terrain" + ], + 41189975 + ], + [ + "buildings/center_pivots.blend", + [ + "Pivot_P1", + "Pivot_P2", + "Pivot_P3" + ], + 1488550 + ], + [ + "buildings/louisa_station.blend", + [ + "LOUISA_Station", + "LOUISA_TreePoints" + ], + 405090 + ], + [ + "buildings/s1_mirf_buildings.blend", + [ + "S1_MIRF_Buildings" + ], + 107641 + ], + [ + "buildings/signs/sign_S1.blend", + [ + "SIGN_S1" + ], + 868999 + ], + [ + "scenes/S1/layers/s1_vegetation.blend", + [ + "Vegetation" + ], + 8429495 + ] + ], + "linked": [ + [ + "plants/crops.blend", + [ + "CornVariants", + "SoyVariants" + ] + ], + [ + "plants/trees_hd.blend", + [ + "TV_Spruce_HD", + "TV_Decid_HD", + "TV_Far_HD", + "TreeParts_HD", + "TV_DecidBaked_HD" + ] + ], + [ + "plants/native_flowers.blend", + [ + "NativeFlowerVariants" + ] + ], + [ + "scenes/S1/layers/s1_terrain.blend", + [ + "Terrain" + ] + ], + [ + "instruments/ECOR/ECOR.blend", + [ + "INST_ECOR_4m" + ] + ], + [ + "instruments/SEBS/SEBS.blend", + [ + "INST_SEBS" + ] + ], + [ + "buildings/center_pivots.blend", + [ + "Pivot_P1", + "Pivot_P2", + "Pivot_P3" + ] + ], + [ + "buildings/louisa_station.blend", + [ + "LOUISA_Station", + "LOUISA_TreePoints" + ] + ], + [ + "buildings/s1_mirf_buildings.blend", + [ + "S1_MIRF_Buildings" + ] + ], + [ + "buildings/signs/sign_S1.blend", + [ + "SIGN_S1" + ] + ], + [ + "scenes/S1/layers/s1_vegetation.blend", + [ + "Vegetation" + ] + ] + ], + "missing": [], + "warnings": [], + "mismatch": [], + "scene": [ + "scenes/S1/S1.blend", + 135112 + ] +} \ No newline at end of file diff --git a/tools/reports/build_s2.json b/tools/reports/build_s2.json new file mode 100644 index 0000000..9fdcf9e --- /dev/null +++ b/tools/reports/build_s2.json @@ -0,0 +1,204 @@ +{ + "written": [ + [ + "plants/grasses_s2.blend", + [ + "GrassVariants_S2", + "TallGrassVariants_S2" + ], + 282861 + ], + [ + "scenes/S2/layers/s2_terrain.blend", + [ + "Terrain" + ], + 47876196 + ], + [ + "instruments/CSAPR2/CSAPR2.blend", + [ + "CSAPR2" + ], + 1249303 + ], + [ + "instruments/AWOS/AWOS.blend", + [ + "INST_AWOS" + ], + 262341 + ], + [ + "vehicles/c850_arm.blend", + [ + "C850_ARM" + ], + 5610750 + ], + [ + "containers/sacr_container_s2.blend", + [ + "CONT_7_SACR_S2" + ], + 149004 + ], + [ + "buildings/s2_kawg_buildings.blend", + [ + "S2_KAWG_Buildings" + ], + 1834481 + ], + [ + "buildings/signs/sign_S2.blend", + [ + "SIGN_S2" + ], + 853969 + ], + [ + "scenes/S2/layers/s2_power_roads.blend", + [ + "S1_Power_Roads" + ], + 157691 + ], + [ + "scenes/S2/layers/s2_vegetation.blend", + [ + "Vegetation" + ], + 40854114 + ] + ], + "linked": [ + [ + "plants/crops.blend", + [ + "CornVariants", + "SoyVariants" + ] + ], + [ + "plants/grasses.blend", + [ + "GrassVariants", + "TallGrassVariants" + ] + ], + [ + "plants/grasses_s2.blend", + [ + "GrassVariants_S2", + "TallGrassVariants_S2" + ] + ], + [ + "plants/trees_hd.blend", + [ + "TV_DecidBaked_HD" + ] + ], + [ + "scenes/S2/layers/s2_terrain.blend", + [ + "Terrain" + ] + ], + [ + "instruments/CSAPR2/CSAPR2.blend", + [ + "CSAPR2" + ] + ], + [ + "instruments/AWOS/AWOS.blend", + [ + "INST_AWOS" + ] + ], + [ + "vehicles/c850_arm.blend", + [ + "C850_ARM" + ] + ], + [ + "containers/amf2_containers.blend", + [ + "CONT_7_SACR" + ] + ], + [ + "containers/sacr_container_s2.blend", + [ + "CONT_7_SACR_S2" + ] + ], + [ + "buildings/s2_kawg_buildings.blend", + [ + "S2_KAWG_Buildings" + ] + ], + [ + "buildings/signs/sign_S2.blend", + [ + "SIGN_S2" + ] + ], + [ + "scenes/S2/layers/s2_power_roads.blend", + [ + "S1_Power_Roads" + ] + ], + [ + "scenes/S2/layers/s2_vegetation.blend", + [ + "Vegetation" + ] + ] + ], + "missing": [ + [ + "image", + "derechos_sign_S2.001", + "/Users/scollis/Documents/blender/farm_amf2/signs/derechos_sign_S2.001.png" + ], + [ + "image", + "derechos_sign_S2.002", + "/Users/scollis/Documents/blender/farm_amf2/signs/derechos_sign_S2.002.png" + ] + ], + "warnings": [ + "missing image derechos_sign_S2.001 /Users/scollis/Documents/blender/farm_amf2/signs/derechos_sign_S2.001.png", + "missing image derechos_sign_S2.002 /Users/scollis/Documents/blender/farm_amf2/signs/derechos_sign_S2.002.png", + "signature mismatch GrassVariants vs plants/grasses.blend GrassVariants", + "signature mismatch TallGrassVariants vs plants/grasses.blend TallGrassVariants", + "normalized mismatch CONT_7_SACR containers/amf2_containers.blend CONT_7_SACR" + ], + "mismatch": [ + [ + "GrassVariants", + "plants/grasses.blend", + "GrassVariants" + ], + [ + "TallGrassVariants", + "plants/grasses.blend", + "TallGrassVariants" + ], + [ + "CONT_7_SACR", + "containers/amf2_containers.blend", + "CONT_7_SACR" + ] + ], + "scene": [ + "scenes/S2/S2.blend", + 144075 + ] +} \ No newline at end of file diff --git a/tools/reports/clouds_cm1_bomex_cumulus.json b/tools/reports/clouds_cm1_bomex_cumulus.json new file mode 100644 index 0000000..63bd86e --- /dev/null +++ b/tools/reports/clouds_cm1_bomex_cumulus.json @@ -0,0 +1,17 @@ +{ + "written": [ + [ + "clouds/cm1_bomex_cumulus/cm1_bomex_cumulus.blend", + [ + "CLOUD_bomex_t240", + "CLOUD_bomex_t300", + "CLOUD_bomex_t360" + ], + 66346 + ] + ], + "linked": [], + "missing": [], + "warnings": [], + "mismatch": [] +} \ No newline at end of file diff --git a/tools/reports/clouds_cm1_supercell.json b/tools/reports/clouds_cm1_supercell.json new file mode 100644 index 0000000..2b21e8b --- /dev/null +++ b/tools/reports/clouds_cm1_supercell.json @@ -0,0 +1,19 @@ +{ + "written": [ + [ + "clouds/cm1_supercell/cm1_supercell.blend", + [ + "CLOUD_supercell_c100_t25", + "CLOUD_supercell_s100_t45", + "CLOUD_supercell_s100_t60", + "CLOUD_supercell_s250_t45", + "CLOUD_supercell_s250_t60" + ], + 66830 + ] + ], + "linked": [], + "missing": [], + "warnings": [], + "mismatch": [] +} \ No newline at end of file diff --git a/tools/reports/clouds_lasso_sgp_20170403.json b/tools/reports/clouds_lasso_sgp_20170403.json new file mode 100644 index 0000000..e6bcb67 --- /dev/null +++ b/tools/reports/clouds_lasso_sgp_20170403.json @@ -0,0 +1,19 @@ +{ + "written": [ + [ + "clouds/lasso_sgp_20170403/lasso_sgp_20170403.blend", + [ + "CLOUD_lasso_1740", + "CLOUD_lasso_1800", + "CLOUD_lasso_1900", + "CLOUD_lasso_2000", + "CLOUD_lasso8_2040" + ], + 69736 + ] + ], + "linked": [], + "missing": [], + "warnings": [], + "mismatch": [] +} \ No newline at end of file diff --git a/tools/reports/clouds_ucla_cumulus.json b/tools/reports/clouds_ucla_cumulus.json new file mode 100644 index 0000000..d65dd16 --- /dev/null +++ b/tools/reports/clouds_ucla_cumulus.json @@ -0,0 +1,15 @@ +{ + "written": [ + [ + "clouds/ucla_cumulus/ucla_cumulus.blend", + [ + "CLOUD_ucla_t6600" + ], + 69115 + ] + ], + "linked": [], + "missing": [], + "warnings": [], + "mismatch": [] +} \ No newline at end of file diff --git a/tools/scene_check.py b/tools/scene_check.py new file mode 100644 index 0000000..ab21ba9 --- /dev/null +++ b/tools/scene_check.py @@ -0,0 +1,50 @@ +"""Evaluate a scene and write a fingerprint (instance counts, vertex totals, transform sums) +plus optional low-res test renders, so a rebuilt scene can be compared with its source. +blender -b scene.blend --python tools/scene_check.py -- out_prefix [cam1,cam2] [hide_colls] +""" +import bpy, sys, json, os +args = sys.argv[sys.argv.index('--') + 1:] +out = args[0] +cams = args[1].split(',') if len(args) > 1 and args[1] else [] +sc = bpy.context.scene +if len(args) > 2 and args[2] == 'fiximg': + sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) + import ablib + for img in bpy.data.images: + if img.library or img.packed_file or not img.filepath or img.source in ('VIEWER', 'GENERATED'): + continue + p = ablib.resolve_src(img.filepath) + if p: img.filepath = p +dg = bpy.context.evaluated_depsgraph_get() +from collections import defaultdict +n = defaultdict(int); verts = defaultdict(int); tsum = [0.0, 0.0, 0.0] +for inst in dg.object_instances: + o = inst.object + if not inst.show_self: continue + n[o.type] += 1 + if o.type == 'MESH': + verts['mesh'] += len(o.data.vertices) + if o.type == 'EMPTY': continue + t = inst.matrix_world.translation + tsum[0] += t.x; tsum[1] += t.y; tsum[2] += t.z +fp = {'instances': dict(n), 'verts': dict(verts), 'tsum': [round(v, 1) for v in tsum], + 'libs': [l.filepath for l in bpy.data.libraries], + 'missing_libs': [l.filepath for l in bpy.data.libraries if not os.path.exists(bpy.path.abspath(l.filepath))]} +json.dump(fp, open(out + '_fp.json', 'w'), indent=1) +r = sc.render +r.engine = 'CYCLES'; sc.cycles.samples = 16; sc.cycles.seed = 0; sc.cycles.use_denoising = False +r.resolution_x, r.resolution_y, r.resolution_percentage = 640, 360, 100 +r.image_settings.file_format = 'PNG' +try: + prefs = bpy.context.preferences.addons['cycles'].preferences + prefs.compute_device_type = 'METAL'; prefs.get_devices() + for d in prefs.devices: d.use = True + sc.cycles.device = 'GPU' +except Exception as e: + print('gpu setup failed', e) +for c in cams: + if c not in bpy.data.objects: print('no camera', c); continue + sc.camera = bpy.data.objects[c] + r.filepath = f'{out}_{c}.png' + bpy.ops.render.render(write_still=True) +print('CHECK_DONE') diff --git a/vehicles/README.md b/vehicles/README.md new file mode 100644 index 0000000..ea5d4c0 --- /dev/null +++ b/vehicles/README.md @@ -0,0 +1,14 @@ +# Vehicles + +Farm vehicles/implements and the ARM Bombardier Challenger 850 (`C850_ARM`, gear/flaps/fans driven from custom properties on `C850_root`). + +| Preview | Collection | File | +|---|---|---| +| | `VEH_Tractor_Green` | [`farm_vehicles.blend`](farm_vehicles.blend) (1.0 MB) | +| | `VEH_Telehandler_Yellow` | [`farm_vehicles.blend`](farm_vehicles.blend) (1.0 MB) | +| | `VEH_Pickup_White` | [`farm_vehicles.blend`](farm_vehicles.blend) (1.0 MB) | +| | `VEH_Implement_Disk_Green` | [`farm_vehicles.blend`](farm_vehicles.blend) (1.0 MB) | +| | `VEH_GrainCart_Red` | [`farm_vehicles.blend`](farm_vehicles.blend) (1.0 MB) | +| | `VEH_Gooseneck_Flatbed` | [`farm_vehicles.blend`](farm_vehicles.blend) (1.0 MB) | +| | `VEH_Cultivator_Red` | [`farm_vehicles.blend`](farm_vehicles.blend) (1.0 MB) | +| | `C850_ARM` | [`c850_arm.blend`](c850_arm.blend) (5.6 MB) | diff --git a/vehicles/c850_arm.blend b/vehicles/c850_arm.blend new file mode 100644 index 0000000..1660be2 Binary files /dev/null and b/vehicles/c850_arm.blend differ diff --git a/vehicles/farm_vehicles.blend b/vehicles/farm_vehicles.blend new file mode 100644 index 0000000..d2bc0f4 Binary files /dev/null and b/vehicles/farm_vehicles.blend differ diff --git a/vehicles/preview/C850_ARM.jpg b/vehicles/preview/C850_ARM.jpg new file mode 100644 index 0000000..2e5626a Binary files /dev/null and b/vehicles/preview/C850_ARM.jpg differ diff --git a/vehicles/preview/VEH_Cultivator_Red.jpg b/vehicles/preview/VEH_Cultivator_Red.jpg new file mode 100644 index 0000000..8bc179f Binary files /dev/null and b/vehicles/preview/VEH_Cultivator_Red.jpg differ diff --git a/vehicles/preview/VEH_Gooseneck_Flatbed.jpg b/vehicles/preview/VEH_Gooseneck_Flatbed.jpg new file mode 100644 index 0000000..e6c0970 Binary files /dev/null and b/vehicles/preview/VEH_Gooseneck_Flatbed.jpg differ diff --git a/vehicles/preview/VEH_GrainCart_Red.jpg b/vehicles/preview/VEH_GrainCart_Red.jpg new file mode 100644 index 0000000..3745767 Binary files /dev/null and b/vehicles/preview/VEH_GrainCart_Red.jpg differ diff --git a/vehicles/preview/VEH_Implement_Disk_Green.jpg b/vehicles/preview/VEH_Implement_Disk_Green.jpg new file mode 100644 index 0000000..6f96cd8 Binary files /dev/null and b/vehicles/preview/VEH_Implement_Disk_Green.jpg differ diff --git a/vehicles/preview/VEH_Pickup_White.jpg b/vehicles/preview/VEH_Pickup_White.jpg new file mode 100644 index 0000000..26b3345 Binary files /dev/null and b/vehicles/preview/VEH_Pickup_White.jpg differ diff --git a/vehicles/preview/VEH_Telehandler_Yellow.jpg b/vehicles/preview/VEH_Telehandler_Yellow.jpg new file mode 100644 index 0000000..29e4985 Binary files /dev/null and b/vehicles/preview/VEH_Telehandler_Yellow.jpg differ diff --git a/vehicles/preview/VEH_Tractor_Green.jpg b/vehicles/preview/VEH_Tractor_Green.jpg new file mode 100644 index 0000000..e9f5f26 Binary files /dev/null and b/vehicles/preview/VEH_Tractor_Green.jpg differ