A new Sky simulation Web demo (#9828)

* sky simulation sample

Also added documentation on how to add another web sample

---------

Co-authored-by: Powei Feng <powei@google.com>
This commit is contained in:
Mathias Agopian
2026-03-26 22:40:34 -07:00
committed by GitHub
parent 566aeac5ed
commit 4b040fbae6
31 changed files with 89 additions and 1507 deletions

View File

@@ -49,7 +49,7 @@ def copy_assets():
It preserves the relative directory structure per sample so that each sample's It preserves the relative directory structure per sample so that each sample's
assets are isolated. assets are isolated.
""" """
exts = ['.filamat', '.filamesh', '.ktx', '.ktx2', '.png', '.jpg', '.bin', '.glb', '.gltf', '.hdr', '.css'] exts = ['.filamat', '.filamesh', '.ktx', '.ktx2', '.png', '.jpg', '.bin', '.glb', '.gltf', '.hdr', '.css', '.js']
for root, dirs, files in os.walk(OUT_DIR): for root, dirs, files in os.walk(OUT_DIR):
for f in files: for f in files:
if any(f.endswith(ext) for ext in exts): if any(f.endswith(ext) for ext in exts):
@@ -66,9 +66,9 @@ def fix_paths():
files (which assume assets are alongside them) need to be patched to point to the correct files (which assume assets are alongside them) need to be patched to point to the correct
relative paths based on their nesting depth. relative paths based on their nesting depth.
""" """
files_to_fix = glob.glob(f"{BOOK_DIR}/samples/web/*.html") + glob.glob(f"{BOOK_DIR}/remote/*.html") files_to_fix = glob.glob(f"{BOOK_DIR}/samples/web/*.html") + glob.glob(f"{BOOK_DIR}/remote/*.html") + glob.glob(f"{BOOK_DIR}/web/*.html")
exts = "filamat|filamesh|ktx|ktx2|png|jpg|bin|glb|gltf|hdr|css" exts = "filamat|filamesh|ktx|ktx2|png|jpg|bin|glb|gltf|hdr|css|js"
asset_pattern = r'([\'"`])((?:\.\.\/)?(?:[\w\-\/]+\.)(?:' + exts + r'))\1' asset_pattern = r'([\'"`])((?:\.\.\/)?(?:[\w\-\/]+\.)(?:' + exts + r'))\1'
for f in files_to_fix: for f in files_to_fix:
@@ -95,6 +95,8 @@ def fix_paths():
def asset_repl(m): def asset_repl(m):
quote = m.group(1) quote = m.group(1)
path = m.group(2) path = m.group(2)
if "lib/" in path:
return m.group(0)
if path.startswith("../"): if path.startswith("../"):
return f"{quote}{depth_prefix}assets/{path[3:]}{quote}" return f"{quote}{depth_prefix}assets/{path[3:]}{quote}"
else: else:
@@ -116,6 +118,8 @@ def fix_paths():
text = re.sub(r'(\w+(?:\.\w+)*)\.loadResources\(([^)]*)\);', fix_load_resources, text) text = re.sub(r'(\w+(?:\.\w+)*)\.loadResources\(([^)]*)\);', fix_load_resources, text)
text = text.replace('window.FILAMENT_ASSET_DIR = "";', f'window.FILAMENT_ASSET_DIR = "{depth_prefix}assets/{sample_name}/";')
with open(f, 'w') as file: with open(f, 'w') as file:
file.write(text) file.write(text)

View File

@@ -130,6 +130,15 @@
"out/cmake-webgl-release/web/examples/examples/skinning/skinning.html": { "out/cmake-webgl-release/web/examples/examples/skinning/skinning.html": {
"dest": "samples/web/skinning.md" "dest": "samples/web/skinning.md"
}, },
"out/cmake-webgl-release/web/examples/examples/sky/sky.html": {
"dest": "samples/web/sky.md",
"replacements": {
"<!-- mdbook: add fullscreen mode -->": "<a href=\"../../web/sky.html\">Full screen</a>"
}
},
"./out/cmake-webgl-release/web/examples/examples/sky/sky.html": {
"dest": "web/sky.html"
},
"out/cmake-webgl-release/web/examples/examples/remote/remote.html": { "out/cmake-webgl-release/web/examples/examples/remote/remote.html": {
"dest": "remote/index.html" "dest": "remote/index.html"
} }

View File

@@ -88,6 +88,10 @@ def pull_duplicates():
if body_match: if body_match:
content = style_str + body_match.group(1) content = style_str + body_match.group(1)
replacements = config[fin].get('replacements', {})
for old, new in replacements.items():
content = content.replace(old, new)
with open(new_fpath, 'w') as out_file: with open(new_fpath, 'w') as out_file:
for line in content.splitlines(True): for line in content.splitlines(True):
out_file.write(transform_dup_file_link(line, link_transforms)) out_file.write(transform_dup_file_link(line, link_transforms))

View File

@@ -71,7 +71,7 @@ def snapshot_samples():
driver = webdriver.Chrome(options=chrome_options) driver = webdriver.Chrome(options=chrome_options)
samples = ['animation', 'cube_fl0', 'helmet', 'morphing', 'parquet', 'skinning', 'triangle', 'redball', 'suzanne'] samples = ['animation', 'cube_fl0', 'helmet', 'morphing', 'parquet', 'skinning', 'sky', 'triangle', 'redball', 'suzanne']
for sample in samples: for sample in samples:
print(f"Taking snapshot of {sample}...") print(f"Taking snapshot of {sample}...")

View File

@@ -21,6 +21,7 @@
- [morphing](./samples/web/morphing.md) - [morphing](./samples/web/morphing.md)
- [parquet](./samples/web/parquet.md) - [parquet](./samples/web/parquet.md)
- [skinning](./samples/web/skinning.md) - [skinning](./samples/web/skinning.md)
- [sky](./samples/web/sky.md)
- [Technical Notes](./notes/README.md) - [Technical Notes](./notes/README.md)
- [Material Properties](./notes/material_properties.md) - [Material Properties](./notes/material_properties.md)
- [Release](./release/README.md) - [Release](./release/README.md)

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -62,4 +62,8 @@ Here are some additional standalone examples demonstrating Filament's capabiliti
<img src="../../images/web_sample_skinning.png" alt="skinning" /> <img src="../../images/web_sample_skinning.png" alt="skinning" />
<span>skinning</span> <span>skinning</span>
</a> </a>
<a href="sky.md" class="sample-card">
<img src="../../images/web_sample_sky.png" alt="sky" />
<span>sky</span>
</a>
</div> </div>

View File

@@ -1,40 +0,0 @@
# Building Skybox Assets
This directory contains the source code for the Simulated Skybox sample. The assets (material and textures) are pre-built in the `assets/` directory.
If you need to modify the material or regenerate the moon textures, you can use the scripts provided in the `tools/` directory.
## Prerequisites
- **Filament**: You must have a built version of Filament. The scripts assume a standard CMake build output structure (e.g., `out/cmake-release`).
- **Python 3**: Required for texture generation.
- **Python Dependencies**: `numpy`, `Pillow` (automatically installed if missing, via pip).
## Rebuilding the Material
If you modify `simulated_skybox.mat`, you must recompile it into a `.filamat` file.
```bash
# Run from the sample root or tools directory
./tools/build_material.sh
```
This will update `assets/simulated_skybox.filamat`.
## Regenerating Moon Textures
If you want to change the moon's resolution, bump scale, or blur, you can regenerate the textures.
```bash
# Run from the sample root or tools directory
./tools/generate_moon_assets.sh [size]
```
Example:
```bash
./tools/generate_moon_assets.sh 512
```
This will download raw NASA data (if not present) and generate:
- `assets/moon_disk.png`
- `assets/moon_normal.png`

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,9 +0,0 @@
body {
margin: 0;
overflow: hidden;
}
canvas {
touch-action: none;
width: 100%;
height: 100%;
}

View File

@@ -61,3 +61,36 @@ The custom `serve.py` script in the `web/examples/` directory performs the follo
- Automatically detects the built files in the `out/` directory. - Automatically detects the built files in the `out/` directory.
- Generates a main entry `index.html` listing all the available samples and tutorials. - Generates a main entry `index.html` listing all the available samples and tutorials.
- Handles server-side rendering of `.md` tutorial files into HTML using an embedded template. - Handles server-side rendering of `.md` tutorial files into HTML using an embedded template.
## Porting a Web Sample to Official Docs (`docs_src`)
If you want your web sample or tutorial to appear on the official Filament documentation website via
`mdbook`, follow these steps:
1. **Map the Built HTML:**
Add your generated `.html` or `.md` file to the mapping in `docs_src/build/duplicates.json`. This
tells the documentation build script to copy your sample into the `mdbook` structure.
```json
"out/cmake-webgl-release/web/examples/examples/your_sample/your_sample.html": {
"dest": "samples/web/your_sample.md"
}
```
2. **Add to the Navigation Menu:**
Link your sample in the table of contents by adding it to `docs_src/src_mdbook/src/SUMMARY.md`
under the "Web Tutorials" or "Web Samples" section.
3. **Generate a Thumbnail Image:**
Add your sample's name to the `samples` array in `docs_src/build/snapshot_samples.py`. Then,
manually run this script (`python3 snapshot_samples.py`). It will launch a headless browser,
wait for your scene to render, and snap a 100x100 preview image.
4. **Dynamic Asset Loading (Optional):**
When `mdbook` serves your sample, the assets (`.filamat`, textures) are segregated into a
`web/assets/` directory.
- For `<script src="...">` or `<img src="...">` tags embedded in the HTML, the paths will be
automatically rewritten by `docs_src/build/copy_web_docs.py`.
- However, if you load files dynamically within your JavaScript code (e.g., using `fetch()`), you
**must** prepend `(window.FILAMENT_ASSET_DIR || '')` to the file URL.
- If you need `window.FILAMENT_ASSET_DIR` to be properly populated, make sure to add logic to
`docs_src/build/copy_web_docs.py` to inject the proper path prefix for your sample.

View File

@@ -194,4 +194,15 @@ add_envmap("third_party/environments/lightroom_14b.hdr" "default_env" ${TARGET_D
set(TARGET_DIR "remote") set(TARGET_DIR "remote")
add_localfile("remote.html" "remote.html" ${TARGET_DIR} ALL_DEMO_ASSETS) add_localfile("remote.html" "remote.html" ${TARGET_DIR} ALL_DEMO_ASSETS)
set(TARGET_DIR "sky")
add_localfile("sky.html" "sky.html" ${TARGET_DIR} ALL_DEMO_ASSETS)
build_material("materials/simulated_skybox.mat" ${TARGET_DIR} "simulated_skybox" ALL_DEMO_ASSETS)
add_localfile("sky/lil-gui.js" "lil-gui.js" ${TARGET_DIR} ALL_DEMO_ASSETS)
add_localfile("sky/suncalc_global.js" "suncalc_global.js" ${TARGET_DIR} ALL_DEMO_ASSETS)
add_localfile("sky/main.js" "main.js" ${TARGET_DIR} ALL_DEMO_ASSETS)
add_localfile("sky/SimulatedSkybox.js" "SimulatedSkybox.js" ${TARGET_DIR} ALL_DEMO_ASSETS)
add_localfile("textures/sky/moon_disk.png" "moon_disk.png" ${TARGET_DIR} ALL_DEMO_ASSETS)
add_localfile("textures/sky/moon_normal.png" "moon_normal.png" ${TARGET_DIR} ALL_DEMO_ASSETS)
add_localfile("textures/sky/milkyway.png" "milkyway.png" ${TARGET_DIR} ALL_DEMO_ASSETS)
add_custom_target(${PROJECT_NAME} ALL DEPENDS ${ALL_DEMO_ASSETS}) add_custom_target(${PROJECT_NAME} ALL DEPENDS ${ALL_DEMO_ASSETS})

View File

@@ -5,7 +5,7 @@
<title>Analytic Skybox</title> <title>Analytic Skybox</title>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width,user-scalable=no,initial-scale=1"> <meta name="viewport" content="width=device-width,user-scalable=no,initial-scale=1">
<link href="styles.css" rel="stylesheet"> <link href="../main.css" rel="stylesheet">
<style> <style>
body { body {
margin: 0; margin: 0;
@@ -23,22 +23,24 @@
</head> </head>
<body> <body>
<canvas></canvas> <div style="display:flex;flex-direction:column;align-items:center">
<canvas></canvas>
<!-- mdbook: add fullscreen mode -->
</div>
<!-- Filament --> <!-- Filament -->
<script src="filament.js"></script> <script src="../filament.js"></script>
<script src="gl-matrix-min.js"></script> <script src="../gl-matrix-min.js"></script>
<!-- UI --> <!-- UI -->
<script src="lil-gui.js"></script> <script src="lil-gui.js"></script>
<!-- Utils --> <!-- Utils -->
<script src="assets/suncalc_global.js"></script> <script src="suncalc_global.js"></script>
<!-- App --> <!-- App -->
<script>window.FILAMENT_ASSET_DIR = "";</script>
<script src="SimulatedSkybox.js?v=9999"></script> <script src="SimulatedSkybox.js"></script>
<script src="main.js?v=9999"></script> <script src="main.js"></script>
</body> </body>
</html> </html>

View File

@@ -66,7 +66,7 @@ class SimulatedSkybox {
// Load Moon Texture // Load Moon Texture
try { try {
const texUrl = 'assets/moon_disk.png'; const texUrl = (window.FILAMENT_ASSET_DIR || '') + 'moon_disk.png';
const Texture = Filament.Texture; const Texture = Filament.Texture;
const TextureSampler = Filament.TextureSampler; const TextureSampler = Filament.TextureSampler;
const PixelDataFormat = Filament.PixelDataFormat; const PixelDataFormat = Filament.PixelDataFormat;
@@ -125,7 +125,7 @@ class SimulatedSkybox {
// Load Moon Normal // Load Moon Normal
try { try {
const texUrl = 'assets/moon_normal.png'; const texUrl = (window.FILAMENT_ASSET_DIR || '') + 'moon_normal.png';
const Texture = Filament.Texture; const Texture = Filament.Texture;
const TextureSampler = Filament.TextureSampler; const TextureSampler = Filament.TextureSampler;
const PixelDataFormat = Filament.PixelDataFormat; const PixelDataFormat = Filament.PixelDataFormat;
@@ -182,7 +182,7 @@ class SimulatedSkybox {
// Load Milky Way Texture // Load Milky Way Texture
try { try {
const texUrl = 'assets/milkyway.png'; const texUrl = (window.FILAMENT_ASSET_DIR || '') + 'milkyway.png';
const Texture = Filament.Texture; const Texture = Filament.Texture;
const TextureSampler = Filament.TextureSampler; const TextureSampler = Filament.TextureSampler;
const PixelDataFormat = Filament.PixelDataFormat; const PixelDataFormat = Filament.PixelDataFormat;

View File

@@ -1,7 +1,7 @@
// main.js // main.js
Filament.init(['assets/simulated_skybox.filamat?v=' + Date.now()], () => { Filament.init([(window.FILAMENT_ASSET_DIR || '') + 'simulated_skybox.filamat?v=' + Date.now()], () => {
window.app = new App(document.getElementsByTagName('canvas')[0]); window.app = new App(document.getElementsByTagName('canvas')[0]);
}); });
@@ -130,7 +130,7 @@ class App {
// Load the material explicitly. SimulatedSkybox.loadMaterial fetches it. // Load the material explicitly. SimulatedSkybox.loadMaterial fetches it.
const matUrl = 'assets/simulated_skybox.filamat?v=' + Date.now(); const matUrl = (window.FILAMENT_ASSET_DIR || '') + 'simulated_skybox.filamat?v=' + Date.now();
this.skybox.loadMaterial(matUrl).then(() => { this.skybox.loadMaterial(matUrl).then(() => {
this.initGUI(); this.initGUI();
}); });

View File

@@ -3,8 +3,8 @@ set -e
# Default size # Default size
SIZE=${1:-256} SIZE=${1:-256}
OUTPUT_COLOR="../assets/moon_disk.png" OUTPUT_COLOR="../../textures/sky/moon_disk.png"
OUTPUT_NORMAL="../assets/moon_normal.png" OUTPUT_NORMAL="../../textures/sky/moon_normal.png"
# Navigate to script directory # Navigate to script directory
cd "$(dirname "$0")" cd "$(dirname "$0")"

View File

Before

Width:  |  Height:  |  Size: 447 KiB

After

Width:  |  Height:  |  Size: 447 KiB

View File

Before

Width:  |  Height:  |  Size: 596 KiB

After

Width:  |  Height:  |  Size: 596 KiB

View File

Before

Width:  |  Height:  |  Size: 94 KiB

After

Width:  |  Height:  |  Size: 94 KiB

View File

Before

Width:  |  Height:  |  Size: 119 KiB

After

Width:  |  Height:  |  Size: 119 KiB