|
1 | 1 | #!/usr/bin/env python3 |
2 | 2 | # |
3 | | -# pyosg-polyhaven.py worn_brick_wall --texture |
4 | | -# pyosg-polyhaven.py https://polyhaven.com/a/worn_brick_wall --texture |
5 | | -# pyosg-polyhaven.py /path/to/local.gltf --texture |
6 | | -# pyosg-polyhaven.py worn_brick_wall --texture --res 4k |
| 3 | +# pyosg_polyhaven.py worn_brick_wall --texture |
| 4 | +# pyosg_polyhaven.py https://polyhaven.com/a/worn_brick_wall --texture |
| 5 | +# pyosg_polyhaven.py /path/to/local.gltf --texture |
| 6 | +# pyosg_polyhaven.py worn_brick_wall --texture --res 4k |
7 | 7 | # |
8 | | -# pyosg-polyhaven.py qwantani_dusk_2 --hdr |
9 | | -# pyosg-polyhaven.py https://polyhaven.com/a/qwantani_dusk_2 --hdr |
10 | | -# pyosg-polyhaven.py /path/to/local.hdr --hdr |
11 | | -# pyosg-polyhaven.py qwantani_dusk_2 --hdr --res 4k |
| 8 | +# pyosg_polyhaven.py qwantani_dusk_2 --hdr |
| 9 | +# pyosg_polyhaven.py https://polyhaven.com/a/qwantani_dusk_2 --hdr |
| 10 | +# pyosg_polyhaven.py /path/to/local.hdr --hdr |
| 11 | +# pyosg_polyhaven.py qwantani_dusk_2 --hdr --res 4k |
| 12 | +# |
| 13 | +# Installs as OpenSceneGraph/examples/polyhaven.py (manifest.cmake strips the pyosg_ prefix on |
| 14 | +# install, same as every other runnable demo here -- only the pure-library helpers like |
| 15 | +# pyosg_example.py keep it) -- import its download/cache functions via |
| 16 | +# `from OpenSceneGraph.examples import polyhaven`. |
12 | 17 |
|
13 | 18 | import sys |
14 | 19 | import os |
@@ -307,6 +312,35 @@ def download_polyhaven_texture(slug, res="2k"): |
307 | 312 |
|
308 | 313 | return gltf_path |
309 | 314 |
|
| 315 | +# Pure JSON/path resolution, no OSG dependency - a caller building its own material (not just |
| 316 | +# reusing build_texture_root()'s sphere-preview scene below) still needs to know which downloaded |
| 317 | +# file is which. Resolved via the glTF's own material -> texture -> image indirection rather than |
| 318 | +# assumed by filename convention, since Polyhaven's own naming isn't perfectly consistent across |
| 319 | +# every asset. `orm` is Polyhaven's packed AO(R)/Roughness(G)/Metallic(B) texture, read via |
| 320 | +# metallicRoughnessTexture and falling back to occlusionTexture for assets that only declare that |
| 321 | +# slot. Raises KeyError if the glTF has no materials or is missing an expected texture. |
| 322 | +def resolve_pbr_textures(gltf_path): |
| 323 | + with open(gltf_path) as f: |
| 324 | + doc = json.load(f) |
| 325 | + |
| 326 | + base_dir = os.path.dirname(gltf_path) |
| 327 | + material = doc["materials"][0] |
| 328 | + pbr = material["pbrMetallicRoughness"] |
| 329 | + |
| 330 | + def image_path(texture_ref): |
| 331 | + texture = doc["textures"][texture_ref["index"]] |
| 332 | + image = doc["images"][texture["source"]] |
| 333 | + |
| 334 | + return os.path.join(base_dir, image["uri"]) |
| 335 | + |
| 336 | + orm_ref = pbr.get("metallicRoughnessTexture") or material["occlusionTexture"] |
| 337 | + |
| 338 | + return { |
| 339 | + "baseColor": image_path(pbr["baseColorTexture"]), |
| 340 | + "normal": image_path(material["normalTexture"]), |
| 341 | + "orm": image_path(orm_ref), |
| 342 | + } |
| 343 | + |
310 | 344 | def download_polyhaven_hdr(slug, res="2k"): |
311 | 345 | dest_dir = os.path.join(CACHE_DIR, slug, res) |
312 | 346 | hdr_path = os.path.join(dest_dir, f"{slug}_{res}.hdr") |
|
0 commit comments