Compare commits

..
Author SHA1 Message Date
Run Yu 0ad90d139d wgpu: code clean up based on feedback 2026-01-28 21:35:45 -05:00
Run Yu cf694a3334 wgpu: add TextureUsage::SAMPLEABLE to the depth texture in test_Scissor,
which is needed to draw the triangle if the test is enabled.
2026-01-23 15:17:12 -05:00
Run Yu 863379b5b4 wgpu: fix the readPixels function so test_Scissor can draw the triangle 2026-01-23 15:17:12 -05:00
Filament Bot 6ce06b1b60 [automated] Updating /docs due to commit e21d4a5
Full commit hash is e21d4a5326

DOCS_ALLOW_DIRECT_EDITS
2026-01-23 09:10:02 +00:00
Mathias Agopian e21d4a5326 SimSky: Refine Stars, Water, and Heat Shimmer simulation (#9628)
- **Stars**:
  - Implemented procedural stars using hash-based noise.
  - Added UI controls for Star Density and Enable/Disable.
  - Tuned star brightness (reduced intensity) and refined twilight fade timing (visible during nautical twilight).
  - Improved compositing with aggressive cloud occlusion and non-linear fade.
  - Added star reflections to water, strictly masked to the horizon line.

- **Heat Shimmer**:
  - Fixed horizon artifacts by decoupling shimmer from atmospheric density (Mie scattering).
  - Implemented FBM-based view distortion for heat waves.
  - Added sun elevation fade (shimmer fades out as sun rises > 30°).

- **Water**:
  - Implemented Finite Difference normal calculation as a high-quality fallback when "Derivative Trick" is disabled.
  - Added "Octaves" parameter to control wave detail.
  - Refined reflection logic to handle stars and sun disk properly.

- **System**:
  - Updated [simulated_skybox.mat](cci:7://file:///Users/mathias/sources/git/filament/docs_src/src_raw/wip/sky/simulated_skybox.mat:0:0-0:0) with new material parameters (`starControl`, `waterControl`).
  - Refactored JS bindings in [SimulatedSkybox.js](cci:7://file:///Users/mathias/sources/git/filament/docs_src/src_raw/wip/sky/SimulatedSkybox.js:0:0-0:0) and organized `main.js` UI into logical folders.

DOCS_FORCE
2026-01-23 01:06:07 -08:00
Filament Bot 7fd9e728ae [automated] Updating /docs due to commit b66736b
Full commit hash is b66736b8cc

DOCS_ALLOW_DIRECT_EDITS
2026-01-22 23:23:09 +00:00
Powei Feng b66736b8cc docs: move wip skybox demo to /docs_src/src_raw (#9626)
/docs content is overwritten by content in /docs_src

(This tag will force a regeneration)
DOCS_FORCE
2026-01-22 23:20:10 +00:00
Doris Wu ea8f6a3c92 return empty string for es2 (#9623) 2026-01-22 14:49:54 -08:00
Doris Wu adcdbb45f9 fix typo (#9625) 2026-01-22 14:49:38 -08:00
Mathias Agopian cff958587d initialize VirtualMachineEnv on the right thread (#9624)
PerformanceHint manager needs a java thread during initialization,
so we need to attach a jvm to the thread that's going to be used.
That thread is the filament backend thread, not necessarily the thread 
the platform is created on.

So we make sure to do that from the backend thread.


FIXES=[427945768]
2026-01-22 10:24:39 -08:00
Mathias Agopian 9ab2326f15 some work in progress sample 2026-01-22 00:50:35 -08:00
Anish Goyal 8785acd352 Fix push constants with ext sampler (VK) (#9445)
Currently, in Vulkan, we set the pipeline layout when binding the
pipeline, which doesn't happen until draw time when external samplers
are present. In cases like that, we push constants with the layout
VK_NULL_HANDLE, which is not valid. Instead, we can wait until the
pipeline layout is known, and then flush all push constants.
2026-01-22 08:15:20 +00:00
Mathias Agopian 57767b7f27 Fix buffer overflow in RenderPass command batching (#9619)
The command batching logic in RenderPass::Executor::execute calculates a
conservative `maxCommandSizeInBytes` to determine how many commands can
safely fit in the driver's circular buffer.

However, this calculation failed to account for the dynamic memory
allocation incurred by the Per-Material descriptor set binding (via
`MaterialInstance::use`). This binding allocates a `DescriptorSetOffsetArray`
in the command stream, which was unbudgeted.

In scenarios with frequent material and scissor changes, the accumulated
deficit from these unbudgeted allocations could exceed the buffer 
capacity, leading to a crash.

This change:
1. Adds the missing accounting for the Per-Material dynamic allocation 
   to `maxCommandSizeInBytes`.
2. Adds a 20% safety margin to the calculated size to robustly handle
   alignment padding and worst-case scenarios.


FIXES=[474264976]
2026-01-21 21:03:49 -08:00
Powei Feng febcfc8f2d fgviewer: add info in panel for render passes (#9618)
- Add plumbing to add more information about rendertargets
   (including discard flags and pass id) to the fgviewer pass
   struct.
 - Add UI to display information about a selected pass
 - Highlight a selected resource or pass
2026-01-22 03:39:20 +00:00
Filament Bot c04c387a89 [automated] Updating /docs due to commit 78ac946
Full commit hash is 78ac9467f8

DOCS_ALLOW_DIRECT_EDITS
2026-01-22 03:05:41 +00:00
Sungun Park 78ac9467f8 Release Filament 1.68.5 2026-01-21 19:01:22 -08:00
Romain Guy 73b60d4db8 Add a new tone mapper (#9614)
The new tone mapper, dubbed "GT7" in the code, is based on
the Gran Turismo 7 tone mapper, as described in the SIGGRAPH
2025 presentation called "Driving Toward Reality: Physically
Based Tone Mapping and Perceptual Fidelity in Gran Turismo 7".

This tone mapper exhibits fewer hue skews than the other tone
mappers, at the exception of PBR Neutral. The GT7 tone mapper
is however better at preserving the perception of high
dynamic range.

The tone mapper, as implemented, targets an SDR paper white
of 250 nits, using 100 cd/m^2 as the reference luminance (for
values of 1.0 in the linear HDR framebuffer). This can result
in an overall darker image compared to the other tone mappers
but this can be controlled through camera settings, post-
processing exposure, or lighting intensity.

The GT7 tone mapper also allows to target HDR output, and
could be made customizable via APIs if desired. The current
implementation offers a fixed aesthetic solution.
2026-01-21 17:31:27 -08:00
Ben Doherty 7266fd67db Add filament-tools subproject (#9622) 2026-01-21 15:22:39 -08:00
Filament Bot 469f2c94da [automated] Updating /docs due to commit d4e0d05
Full commit hash is d4e0d051b1

DOCS_ALLOW_DIRECT_EDITS
2026-01-21 22:26:09 +00:00
Powei Feng d4e0d051b1 docs: make docs more consistent and complete (#9620)
- Add documentation for specgen along with proper math rendering
- Adjust the heading size, capitalization of various READMEs.
- Add backend test README to the doc
- Rename the CI related tests to have prefix "CI:"
2026-01-21 22:22:12 +00:00
Ben Doherty df74a5a352 Re-enable iOS filamat builds (#9598) 2026-01-21 19:30:00 +00:00
Doris Wu 21fd32266a Add support for custom morphing (#9550)
BUGS=[443321184]
2026-01-21 17:11:35 +08:00
Sungun Park cd7c7b369b Add helloasync sample (#9617)
Introduces a new sample application demonstrating asynchronous resource
management. It shows how to asynchronously create and update Filament
resources (Textures, VertexBuffers, IndexBuffers) and provides examples
of managing chains of asynchronous operations effectively.

BUGS=[442921995]
2026-01-21 00:38:08 +00:00
Powei Feng 65ed7099c0 fgviewer: UI updates (#9615)
- Pick a default view when database is filled.
 - Fix d3, d3-graphviz depdency.
 - reduce the size into a smaller table (to avoid scrolling)
 - slant the pass items to allow smaller cells for the table.
 - make subresource rendering the same as regular resource
   rendering with a color hint.
 - Use color-only to indicate resource/pass interaction (read,
   write, read-write, no-access)
 - add tooltip to indicate resource action
2026-01-20 21:02:23 +00:00
rafadevai af34572883 VK: Add support for VK_KHR_global_priority (#9607)
Add support for application that want to change the
priority of GPU queues at a system level.
2026-01-20 19:53:55 +00:00
Anish Goyal 1f6a67b2a2 Fix race condition for cache prewarming (#9613)
Right now, if a material is destroyed just after creation, it's possible
for prewarm to attempt to use destroyed shader modules. This ensures
that the resources are kept until after any queued jobs have run.

While it is likely ideal to properly cancel the prewarm if the program
has been destroyed, this seems like a rare occurrence in practice.
2026-01-20 18:04:34 +00:00
Sungun Park 7701e7a65a Handle deferred destruction for asynchronous objects (#9604)
When an asynchronous object is destroyed immediately after creation, the
background creation process may still be active, holding a reference to
the object. We now defer destruction in these cases until the creation
process completes to ensure the reference remains valid.

Implementation details:
1. Add a mechanism to stop the ServiceThread to drain pending
   asynchronous tasks earlier. This ensures the mCreationComplete flag
   in the frontend object is set to true.
2. Later, the engine's terminate performs garbage collection for the
   deferred destruction. All of them must be successfully processed.

BUGS=[442921995]
2026-01-17 02:44:28 +00:00
Filament Bot 65a91832a8 [automated] Updating /docs due to commit acb47ff
Full commit hash is acb47ffed5

DOCS_ALLOW_DIRECT_EDITS
2026-01-16 00:26:35 +00:00
Powei Feng acb47ffed5 Release Filament 1.68.4 2026-01-15 16:21:37 -08:00
Filament Bot 13c0304d84 [automated] Updating /docs due to commit febdf39
Full commit hash is febdf3974c

DOCS_ALLOW_DIRECT_EDITS
2026-01-15 23:24:29 +00:00
Powei Feng febdf3974c docs: improve release and test documentation (#9609)
- Reorder the release-related documents into one heading.
 - Added CocoaPods README as part of the documentation.
 - Fixed typo for renderdiff doc
 - Added backend test doc
2026-01-15 23:22:00 +00:00
Powei Feng 390acec928 vk: add feature flag for acquiring swapchain in makeCurrent (#9610)
Removing this behavior in #9541 caused a breakage in one of our
clients. We use a feature flag to enable the old behavior.

BUGS=476144715
2026-01-15 22:48:12 +00:00
Powei Feng ff806f8c3e Misc fixes to address old compiler errors (#9611)
Certain older compilers (e.g. clang in NDK 25.1.8937393) cannot
handle the c++ stylistic changes that were recently added
(though they are correct by spec).

 - In Engine.cpp, .find() cannot automatically infer the right type
   (std::string_view vs. utils::CString).
 - In fg/framegraph, various templated short-hands still require
   typename.
2026-01-15 20:27:26 +00:00
Powei Feng 06c4faabc3 vk: disable pushconstant backend test for CI
Due to flakiness.
2026-01-15 11:36:46 -08:00
Powei Feng 92aec16fa3 Add comment to indicate TextureFormat value (#9608)
This will help with debugging if we needed to print out a
TextureFormat value.
2026-01-15 19:21:39 +00:00
Mathias Agopian f1ffb783d8 feat(engine): Add automatic frame skipping to manage CPU/GPU latency (#9595)
* feat(engine): Add automatic frame skipping to manage CPU/GPU latency

Introduces a new feature, disabled by default, that allows the engine to automatically skip frames when the CPU gets too far ahead of the display's refresh rate. This helps to reduce overall latency by preventing a backlog of frames from building up in the driver queue.

The feature can be enabled with the "engine.skip_frame_when_cpu_ahead_of_display" property.

To implement this, the compositor timing mechanism has been refactored. Instead of reporting an absolute `expectedPresentTime`, the backend now provides an `expectedPresentLatency` relative to vsync. This is more robust against synchronization issues with platform callbacks (like Android's Choreographer), as the latency is generally a constant value.

BUGS=[474599530]
2026-01-15 09:50:56 -08:00
Mathias Agopian b708300586 Refactor implicit DriverApi dependency (#9606)
Removed implicit dependency on FEngine::getDriverApi() in critical 
rendering paths. This change makes the DriverApi dependency explicit by 
passing it as a parameter.


Key changes:

- FRenderer: Now accepts DriverApi& in renderInternal and renderJob. 
Caches feature levels and capability flags in the constructor.

- PostProcessManager: Caches feature flags and workaround flags in 
init(). Updated PostProcessMaterial and configure* methods to accept 
DriverApi&.

- FMaterial: Caches support flags (stereo, parallel shader compile) and
default material pointer in the constructor. 
Updated precacheDepthVariants and prepareProgram to rely on these 
cached values or passed parameters.

- ShadowMapManager: Caches workaround flags in the constructor.

- FEngine: Updated prepare() to accept DriverApi&.

- RenderPass: Updated to accept DriverApi& in constructor and 
appendCommands.

- Removed implicit DriverApi calls from hot paths to reduce overhead 
and improve safety.


One common pattern in this change is to cache getters in constructors
so that we don't need the DriverApi dependency later during rendering.
The intention here is to remove DriverApi& from as many places as
possible so that we can later have multithreading for command
recording.

This PR should not change any behavior.
2026-01-15 09:11:12 -08:00
HanYunChenLuo f88d757d06 Add glibc check to support build filament on Linux musl-based distrib… (#9592) 2026-01-14 23:22:07 +00:00
Powei Feng 4d96f188d1 backend: CallbackHandler dstor inlined in header (#9605)
Defining the destructor in a cpp will break downstream clients.

The previous move to cpp was part of #9508.
2026-01-14 22:22:10 +00:00
Powei Feng 2d943f40bb vk: fix push constant implementation and test (#9588)
All stages share a push constant "block". We need to order
the fragment stage bytes to after the vertex stage if they
both exists.

FIXES=453776664
2026-01-14 18:18:04 +00:00
Doris Wu 92c058a736 fix gtao shader on mobile (#9591) 2026-01-13 14:11:34 +00:00
Mathias Agopian ba819bcfca Docs: Improve documentation in public headers (#9603)
This commit clarifies and corrects documentation in several public header
files. The changes include fixing typos, improving wording, and adding
missing details to make the API easier to understand and use.

No functional changes are included in this commit.
2026-01-12 14:31:42 -08:00
Mathias AgopianandPowei Feng e22f1adfa7 make "native streams" deprecated (#9602)
Co-authored-by: Powei Feng <powei@google.com>
2026-01-12 14:31:15 -08:00
Anish Goyal f2bca03360 Add external format to cache prewarming (#9558)
Provides logic to load and check for external format ids, and
build fake pipelines against them when relevant, to prevent
hitching when using external formats.

For now, we're going to use upto five likely types of YCbCr
conversions, which seem to cover all usecases encountered. This
means we might compile pipelines with external samplers a total of
4 additional times on top of the baseline (5 in total), or 3 additional
times on the devices we're currently testing (4 in total).

* Add base pipeline prewarm call for ext samplers

This is necessary because in some cases, a material that supports
external samplers will use RGB inputs instead of YCbCr inputs, and will
miss the cache.
2026-01-12 19:32:01 +00:00
Ben Doherty 5f07d701f0 Fix CocoaPods build (#9597) 2026-01-12 10:20:51 -08:00
Mathias Agopian 496a50bc89 make getWorldFromModelMatrix() accessible in fragment shader (#9584)
this requires to specify `apiLevel: 2` in the material.

FIXES=[474353927]
2026-01-12 09:32:23 -08:00
Mathias AgopianandPowei Feng 6ccb6c4cce split FeatureFlagManager out of FEngine (#9596)
* split FeatureFlagManager out of FEngine

- Separate the Feature flags management from FEngine.
- Make FeatureFlagManager available to backends through DriverConfig
- add a way to override a feature flag value at runtime using
  environment variables or system properties (on Android).

e.g.:

```
env "feature.name=true" gltf_viewer
```
or 
```
adb shell setprop debug.feature.name true
```

Co-authored-by: Powei Feng <powei@google.com>
2026-01-12 09:31:51 -08:00
Powei Feng 42c78fd0a9 github: refactor postsubmit CI tasks into single yml (#9587) 2026-01-12 17:28:53 +00:00
Doris Wu 3d0e2923ae Fix VB-GTAO on remote webui (#9599) 2026-01-12 19:10:30 +09:00
Mathias Agopian 408b2371f0 allow FILAMENT_TRACING_CALL to take extra parameters (#9593) 2026-01-09 15:08:27 -08:00
Powei Feng 6ea08b40a8 gl: small fixes to push constant implementation and test (#9594)
- Add code for handling empty/null constant name
 - Use glUniform1ui() instead of glUniform1i() to workaround
   crash on macbook pro (m4).
 - Fully specify the constant name in the test (e.g.
   `pushConstantsF.red` instead of `red`).
 - Make sure that the uniform names are different between
   vertex and fragment in the test. This is due to different
   constant structs being defined between the two stages.

FIXES=453757504
2026-01-09 14:48:52 -08:00
Doris Wu 5eb0f7d3ec Fix the vbotest sample (#9581)
* set clear to true

* feedback
2026-01-09 10:15:44 +08:00
Powei Feng d465d59c3a github: run filament tests in presbumit (#9586) 2026-01-08 21:25:58 +00:00
Filament Bot af9a60d175 [automated] Updating /docs due to commit 8e0f0c9
Full commit hash is 8e0f0c92ce

DOCS_ALLOW_DIRECT_EDITS
2026-01-08 20:19:49 +00:00
Benjamin Doherty 8e0f0c92ce Release Filament 1.68.3 2026-01-08 12:14:07 -08:00
Anish Goyal 5a14fb4b5d Cache prewarm base case (#9552)
Prevents hitching for most pipelines, on certain devices with Turnip-based drivers

This does not address external samplers yet. This simply handles the
case where we want to prewarm a pipeline with the base configuration.

Refactor program's descriptor set layout bindings, clean up some leaking
resources
2026-01-08 11:43:32 -08:00
dependabot[bot] 22a1aacb21 Bump urllib3 in /docs_src/build in the pip group across 1 directory (#9585)
Bumps the pip group with 1 update in the /docs_src/build directory: [urllib3](https://github.com/urllib3/urllib3).


Updates `urllib3` from 2.6.0 to 2.6.3
- [Release notes](https://github.com/urllib3/urllib3/releases)
- [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst)
- [Commits](https://github.com/urllib3/urllib3/compare/2.6.0...2.6.3)

---
updated-dependencies:
- dependency-name: urllib3
  dependency-version: 2.6.3
  dependency-type: direct:production
  dependency-group: pip
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-08 18:48:08 +00:00
dependabot[bot] e5b6c11399 Bump urllib3 in /test/renderdiff/src in the pip group across 1 directory (#9582)
Bumps the pip group with 1 update in the /test/renderdiff/src directory: [urllib3](https://github.com/urllib3/urllib3).


Updates `urllib3` from 2.6.0 to 2.6.3
- [Release notes](https://github.com/urllib3/urllib3/releases)
- [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst)
- [Commits](https://github.com/urllib3/urllib3/compare/2.6.0...2.6.3)

---
updated-dependencies:
- dependency-name: urllib3
  dependency-version: 2.6.3
  dependency-type: direct:production
  dependency-group: pip
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-08 10:28:15 -08:00
Mathias Agopian 85ebd67a28 feat(taa): Overhaul TAA implementation for improved quality and upscaling (#9573)
This commit introduces a significant rework of the Temporal Anti-Aliasing (TAA) system, focusing on improving reconstruction quality, robustness, and introducing flexible upscaling.

Core TAA Algorithm improvements:
- Replaced the Catmull-Rom filter with a more efficient 5-tap Lanczos filter for history sampling, which includes deringing to reduce artifacts.
- The input color buffer is now properly "unjittered" using a Lanczos reconstruction filter.
- Improved the history rejection algorithm by skipping the expensive accurate clipping when the history sample is already within the neighborhood's color gamut.
- Added a new `hdr` option to properly handle HDR content by tonemapping colors before blending and untonemapping the result.
- Removed the ineffective `VARIANCE` only history rejection method.
- Added protection against negative numbers in `sqrt()` for increased stability.

TAA Upscaling:
- Replaced the boolean `upscaling` flag with a float factor, allowing for variable upscaling ratios (e.g., 1.5x, 2x).
- Upscaling now correctly adjusts viewport and projection settings.
- The TAA shader now receives viewport and resolution information to correctly handle upscaled rendering.

API and Configuration Changes:
- Deprecated the `filterWidth` TAA option as it no longer has an effect.
- Introduced the `upscaling` float property to `TemporalAntiAliasingOptions`.
- Added the `hdr` boolean property to `TemporalAntiAliasingOptions`.

Other Changes:
- Updated UI elements in the viewer and material sandbox to reflect the new TAA options.
- Updated Javascript bindings and TypeScript definitions for the new TAA settings.
- Refactored shader code for clarity and performance.
2026-01-07 15:25:38 -08:00
Powei Feng f33a779668 vk: move swapchain acquire() to as late as possible (#9541)
makeCurrent is not meant to acquire the swapchain; we should
do so at the momemnt we need it, to shorten the amount of time
a swapchain image/buffer needs to be held.
2026-01-07 18:36:54 +00:00
Sungun Park 1b5916b655 Rename AsyncCallbackType to AsyncCompletionCallback (#9579) 2026-01-07 18:18:49 +00:00
Anish Goyal d8720cd858 Rename DescriptorSetLayoutBinding to DescriptorSetLayoutDescriptor (#9576)
Since the struct refers to descriptors as opposed to specifically
bindings (although they do contain binding information as well), this
name is more appropriate.
2026-01-07 16:52:50 +00:00
Doris Wu 44636bddaa Split Skinning out of Visibility struct (#9575) 2026-01-07 11:37:42 +08:00
Sungun Park 1741723687 Add user parameter to runCommandAsync (#9577) 2026-01-06 18:37:42 -08:00
Mathias Agopian ad2c291d4a dispersion in XYZ space (#9572)
- spectral reconstructions with 4 samples
- unroll the whole dispersion computation to improve performance
  (batch texture fetches and reuse common values)
- tool to generate the matrices for spectral integration
2026-01-06 16:58:56 -08:00
Mathias Agopian 52ffd80041 Refactor FrameGraph pass API for flexibility (#9571)
This commit simplifies and unifies the FrameGraph's `addPass` API.
Key changes:
- The `addPass` method now uses a single, more flexible implementation
  that handles different lambda signatures for both the setup and
  execute stages.
- The execute lambda can now optionally omit the `DriverApi&` parameter,
  reducing boilerplate for simple passes.
- The `addTrivialSideEffectPass` helper has been removed.
  Side-effect-only passes can now be created directly with `addPass`
2026-01-06 14:20:47 -08:00
Doris Wu 44dde744ea Several optimizations for UBO batching (#9545) 2026-01-06 05:52:32 +00:00
Mathias Agopian c18ddf929e Improve frame_generator sample tool (#9570)
- Add support for vector parameters (float2, float3, float4) in the 
  parameters file using `{x, y, z}` syntax.
- Allow comments (`#`, `//`) and empty lines in the parameters file.
- Make the end value optional in the parameters file 
  (defaults to start value).
- Add `--size` / `-S` option to specify viewport dimensions.
- Optimize rendering by pre-filtering active material parameters.
- Remove hardcoded default parameters and silently ignore missing 
  parameters to support shared configuration files.
- Add documentation for the parameters file format.
2026-01-05 20:28:04 -08:00
Mathias Agopian 5661365248 improved the dispersion computation (#9544)
- Split the function so that the 3-components loop is more apparent.
- Factored out the parts of the computation that don't depend on the
index of refraction, so they're only computed once.
- Moved the lod-from-roughness computation out of the loop as well. 
  It does depend on the IOR, but so little that it's not worth it.

The most important result of this change is that the code is now in
good shape if we wanted to change the implementation of dispersion for
these cases (for e.g.) :
- do the computation in the XYZ space
- use more than 3 wavelengths samples
- or use a stochastic approach, trading banding for noise

RDIFF_BRANCH=ma/better-dispersion
2026-01-05 20:27:34 -08:00
Powei Feng bcb9d258c2 vk: fix broken android build (#9574)
Should use VK_NULL_HANDLE instead of nullptr where applicable
in VulkanPipelineCache.
2026-01-05 20:27:07 -08:00
Anish Goyal 53a94c4547 Add thread pool and callback manager / knobs for enabling + disabling prewarm (#9515)
* Update createPipeline to have pipeline key input
Right now, createPipeline in VulkanPipelineCache assumes that you are
building a pipeline using mPipelineRequirements as the key, and that it
should be stored in the cache. In the case of the pipeline prewarming
change, this is not going to be the case; sometimes, the pipeline will
be stored in the cache, and sometimes it will be deleted immediately.
Also, the prewarmed pipelines will be created using separately defined
keys.

* Add knobs for enabling / disabling prewarm

* Add thread pool to VulkanPipelineCache

* Fix dynamic rendering enablement check
Query device features to ensure it is supported / we don't just have the
extension. Also, proactively enable dynamic rendering when creating the
device.
2026-01-05 23:55:08 +00:00
Filament Bot 928ffe94a7 [automated] Updating /docs due to commit dcb78c7
Full commit hash is dcb78c7144

DOCS_ALLOW_DIRECT_EDITS
2026-01-05 21:56:49 +00:00
Mathias Agopian dcb78c7144 update dispersion documentation (#9567)
* add dispersion parameter to material_sandbox

* frame_generator fixes

- fix skybox
- for baseColor to white (workaround)

* update dispersion documentation source
2026-01-05 13:54:24 -08:00
Sungun Park 43dd8fa1cc Fix MockDriver (#9569)
This is missing changes from
https://github.com/google/filament/commit/0eff54b807d236ed0782be18b75412ccc3c0ce8f
2026-01-05 21:08:50 +00:00
Anish Goyal 91a5f00d30 Remove unnecessary log statement (#9568)
It is not an error for a device to not have this API.
2026-01-05 12:41:34 -08:00
Sungun Park 0eff54b807 Add async support check to backend (#9542)
BUGS=[442921995]
2026-01-05 20:10:36 +00:00
Lucas Leandro 68eb0ce3f1 Add java bindings for changing from default to screen-space reflection in real-time MaterialBuilder (#9548) 2026-01-05 11:44:54 -08:00
Benjamin SchulzandSungun Park 023318c08d Fixes "error: templates must have C++ linkage" when compiling with older clang versions. (#9562)
Co-authored-by: Sungun Park <sungunpark@google.com>
2026-01-05 11:43:54 -08:00
rafadevaiandSerge Metral c0e3aa2b0a VK: In UMA, apply the staging bypass for everything (#9538)
Currently only uniform buffers benefit from the bypass,
but this can also be extended to others buffers too.

This also help trying to match the performance of the
GL backend in Android.

FIXES=[470138463]

Co-authored-by: Serge Metral <sergemetral@google.com>
2026-01-05 11:36:54 -08:00
Anish Goyal a6d1b9188f Add descriptor set layouts to Program (#9522)
This will help later for parallel compilation
2026-01-05 18:59:07 +00:00
Sungun Park 43193c5ac5 Add missing async destruction for BufferObject and IndexBuffer (#9565)
As with Texture, now BufferObject and IndexBuffer will be destroyed via
the async queue if they were asynchronously created.

BUGS=[442921995]
2026-01-05 18:15:01 +00:00
Mathias Agopian 35c58047ee move the depth clear prepare into the framegraph (#9549)
depth clear prepare was done outside of the framegraph, it's now
moved into the colorpass prepare pass.
2026-01-03 15:04:51 -08:00
Mathias Agopian 2190f3544f fix build when FILAMENT_SUPPORTS_VULKAN is OFF (#9557) 2026-01-03 15:03:30 -08:00
Mathias Agopian fd8ea78e04 Fix TAA (#9556)
TAA had been broken for a while, the jitter was no longer applied.

We now compute the jittered camera before we set it into the 
per frame UBO.
2026-01-03 15:03:06 -08:00
Emily Banerjee 7fc336a6d9 Fix GCC type mismatch error in Platform::debugUpdateStat (#9563) 2026-01-02 09:48:28 -08:00
yein 3cc6fae5c0 Add api level enforcement (#9561)
Api level is now enforced when generating code by appending #defines of client requested and unstable apis.
This ensures that the client can only use unstable apis when they explicitly add `apiLevel` in their .mat file.

FIXES=468340631
2025-12-29 13:38:02 -08:00
yein f4f75da016 Fix garbage data getting added to the source material (#9553) 2025-12-26 09:29:13 -08:00
Filament Bot bdeba1aa86 [automated] Updating /docs due to commit 8991be4
Full commit hash is 8991be4eea

DOCS_ALLOW_DIRECT_EDITS
2025-12-24 00:55:04 +00:00
Ben Doherty 8991be4eea Fix incorrect GLSL types in Materials documentation (#9555) 2025-12-23 16:52:27 -08:00
yein 940b93ceb8 Replace slog to LOG (#9554) 2025-12-23 13:45:42 -08:00
Filament Bot 00eb3d0d4f [automated] Updating /docs due to commit 7f61eb7
Full commit hash is 7f61eb7a0a

DOCS_ALLOW_DIRECT_EDITS
2025-12-23 19:44:04 +00:00
Benn Herrera 7f61eb7a0a GLTFIO Webp Texture Support (#9406) 2025-12-23 11:40:01 -08:00
yein 53f506670c Add apiLevel and add parsing logic (#9535) 2025-12-22 13:52:32 -08:00
Mathias AgopianandPowei Feng 9fe7ab31ed Make FrameGraph resource management extensible (#9536)
* rename ResourceAllocator to TextureCache

This better represents what this class is for.

* Make FrameGraph resource management extensible

This refactors the FrameGraph's resource management to allow for 
user-defined custom resources.
 
A new `ResourceAllocator` template abstracts the creation and 
destruction of resources, with specializations for different resource 
types (e.g., generic, backend-dependent, textures). 
This removes hardcoded resource management logic from the `FrameGraph` 
execution loop.
 
A `ResourceCreationContext` is introduced to provide the necessary 
context for resource allocation.
 
Tests for generic and backend custom resources have been added to 
validate the new system.

* Update filament/src/fg/FrameGraphDummyLink.h

Co-authored-by: Powei Feng <powei@google.com>

---------

Co-authored-by: Powei Feng <powei@google.com>
2025-12-22 11:08:53 -08:00
Mathias Agopian 008534b8a2 Fix dispersion with uber-shaders (#9543)
Fixes #9540
2025-12-22 10:12:54 -08:00
Sungun Park 2c5842f908 Implement asynchronous resource management (#9508)
This commit introduces async methods and functions across both the
public and backend APIs, enabling non-blocking creation and updates for
Texture, VertexBuffer, and IndexBuffer resources.

Asynchronous resource management is disabled by default. Users should
enable this to use the feature.

Java bindings and a C++ code sample will follow in subsequent PRs.

BUGS=[442921995]
2025-12-19 21:18:32 -08:00
Powei Feng a8ee9d473e android: fix texture rendertarget sample for vk (#9528)
- add a flag to run the sample using regular, non-external
   texture as render target.
 - Add a non-external version of the material
 - vk: fix y-flipping issue with uvToRenderTargetUV()
2025-12-19 22:15:22 +00:00
Mathias Agopian 1e3ab83e6a Remove the dependency of RenderPassBuilder on DriverApi (#9533)
The main goal of this CL is to break the dependency of RenderPassBuilder
on DriverApi. The dependency only existed for the auto-instancing 
feature, which needed to allocate and update a UBO on the fly.

We want to break that dependency so that RenderPassBuilder::build().
which is an expensive call, could run on a separate thread. In the
future this could allow, for example, shadow and ssao passes to 
run in parallel.

A new method RenderPass::finalize(DriverApi&) is added which *must* be 
called before calling getExecutor(), this is where the temporary
UBO is allocated and updated. We need a new method because this must be 
called on the main thread before a render pass is started.

This implementation stores the UBO data needed for instancing until
finalize() is called, if any.

We introduce a compact() utility that efficiently scans a range finding
"equivalent" consecutive objects and removes duplicates. The previous
code did that with an extra remove pass which invalidated all 
iterators.
2025-12-19 13:50:20 -08:00
yein 9720da2c68 Fix Json lexeme trying to allocate a string with a huge size due to underflow (#9539) 2025-12-19 13:29:01 -08:00
yein ee74e2d50c Fix missing dep in CompressedStringChunk (#9534) 2025-12-18 13:35:49 -08:00
Powei Feng 6171009add test: fixing broken webgpu+android build (#9529)
The build was failing because the some tint libs are no longer
real dependencies

Fixes #9520
2025-12-18 18:16:21 +00:00
Mathias Agopian d299a444fa don't limit FILAMENT_ENABLE_COVERAGE to DEBUG builds (#9532) 2025-12-18 09:24:19 -08:00
rafadevai 107276e9cc VK: Refactor platform Vulkan initialization (#9523)
* VK: Refactor platform Vulkan initialization

Refactor the platform code to allow overriding
how the vkInstance, vkPhysicalDevice and vkDevice
are created.

This refactor will also consolidate where the extensions
and features are enabled/disabled into VulkanPlatform,
instead of each platform doing its own individual setup
if needed. It also address knowing if a feature or
extension has been enabled, unless we keep adding
entries to the SharedContext which is not scalable.

The createDriver function now have a more defined structure,
mostly how and where features are queried and enabled.

- Get shared context data.
- Create instance if missing.
- Select physical device if missing.
- Query physical device support and set supported
engine features into the VulkanContext.
- Select the queues
- Create the device and queues

* Address review comments

Added some documentation on the new functions
Move the querying and config of features into its
own function.
2025-12-18 09:23:18 -08:00
Mathias Agopian fe00cbf106 feature flags now default to const. (#9530)
This PR doesn't update most of the existing flags that are marked as
"mutable", they're probably wrong.
2025-12-17 10:34:31 -08:00
Filament Bot 02d0ddbcfe [automated] Updating /docs due to commit c4802f7
Full commit hash is c4802f7683

DOCS_ALLOW_DIRECT_EDITS
2025-12-16 23:01:53 +00:00
363 changed files with 23008 additions and 7740 deletions
-25
View File
@@ -1,25 +0,0 @@
name: Android
on:
push:
branches:
- main
- release
- rc/**
jobs:
build-android:
name: build-android
# We intentially use a larger runner here to enable larger disk space
# (standard linux runner will fail on disk space and faster build time).
runs-on: 'ubuntu-24.04-16core'
steps:
- uses: actions/checkout@v4.1.6
with:
fetch-depth: 0
- uses: ./.github/actions/linux-prereq
- name: Run Android Continuous
uses: ./.github/actions/android-continuous
with:
build-abi: armeabi-v7a,arm64-v8a,x86_64
-29
View File
@@ -1,29 +0,0 @@
name: iOS
on:
push:
branches:
- main
- release
- rc/**
jobs:
build-ios:
name: build-ios
runs-on: macos-14-xlarge
steps:
- uses: actions/checkout@v4.1.6
with:
fetch-depth: 0
- uses: ./.github/actions/mac-prereq
- name: Run build script
run: |
cd build/ios && printf "y" | ./build.sh continuous
- uses: actions/upload-artifact@v4
with:
name: filament-ios
path: out/filament-release-ios.tgz
- name: Build iOS samples
run: |
cd build/ios && ./build-samples.sh continuous
-26
View File
@@ -1,26 +0,0 @@
name: Linux
on:
push:
branches:
- main
- release
- rc/**
jobs:
build-linux:
name: build-linux
runs-on: 'ubuntu-24.04-16core'
steps:
- uses: actions/checkout@v4.1.6
with:
fetch-depth: 0
- uses: ./.github/actions/linux-prereq
- name: Run build script
run: |
cd build/linux && printf "y" | ./build.sh continuous
- uses: actions/upload-artifact@v4
with:
name: filament-linux
path: out/filament-release-linux.tgz
-29
View File
@@ -1,29 +0,0 @@
name: macOS
on:
push:
branches:
- main
- release
- rc/**
jobs:
build-mac:
name: build-mac
runs-on: macos-14-xlarge
steps:
- uses: actions/checkout@v4.1.6
with:
fetch-depth: 0
- uses: ./.github/actions/mac-prereq
- name: Run build script
run: |
cd build/mac && printf "y" | ./build.sh continuous
- uses: actions/upload-artifact@v4
with:
name: filament-mac
path: out/filament-release-darwin.tgz
- name: Check public headers
run: |
test/check-headers/test.sh out/release/filament/include
+59
View File
@@ -0,0 +1,59 @@
name: 'Postsubmit Tasks'
on:
push:
branches:
- main
jobs:
update-renderdiff-goldens:
name: update-renderdiff-goldens
runs-on: 'ubuntu-24.04-4core'
steps:
- uses: actions/checkout@v4.1.6
with:
fetch-depth: 0
- uses: ./.github/actions/linux-prereq
- id: get_commit_msg
uses: ./.github/actions/get-commit-msg
- name: Prerequisites
run: pip install tifffile numpy
- name: Run update script
env:
GH_TOKEN: ${{ secrets.FILAMENTBOT_TOKEN }}
COMMIT_MESSAGE: ${{ steps.get_commit_msg.outputs.msg }}
run: |
GOLDEN_BRANCH=$(echo "${COMMIT_MESSAGE}" | python3 test/renderdiff/src/commit_msg.py)
COMMIT_HASH="${{ steps.get_commit_msg.outputs.hash }}"
if [[ "${GOLDEN_BRANCH}" != "main" ]]; then
git config --global user.email "filament.bot@gmail.com"
git config --global user.name "Filament Bot"
git config --global credential.helper cache
echo "branch==${GOLDEN_BRANCH}"
echo "hash==${COMMIT_HASH}"
python3 test/renderdiff/src/update_golden.py --branch=${GOLDEN_BRANCH} \
--merge-to-main --filament-tag=${COMMIT_HASH} --golden-repo-token=${GH_TOKEN}
fi
update-docs:
name: update-docs
runs-on: 'ubuntu-24.04-4core'
steps:
- uses: actions/checkout@v4.1.6
with:
fetch-depth: 0
- uses: ./.github/actions/linux-prereq
- id: get_commit_msg
uses: ./.github/actions/get-commit-msg
- name: Prerequisites
run: pip install selenium
- name: Run update script
env:
GH_TOKEN: ${{ secrets.FILAMENTBOT_TOKEN }}
run: |
bash docs_src/build/install_mdbook.sh && source ~/.bashrc
COMMIT_HASH="${{ steps.get_commit_msg.outputs.hash }}"
git config --global user.email "filament.bot@gmail.com"
git config --global user.name "Filament Bot"
git config --global credential.helper cache
bash docs_src/build/postsubmit.sh ${COMMIT_HASH} ${GH_TOKEN}
+101 -45
View File
@@ -1,59 +1,115 @@
name: 'Post-submit tasks'
name: 'Postsubmit CI'
on:
push:
branches:
- main
- release
- rc/**
jobs:
update-renderdiff-goldens:
name: update-renderdiff-goldens
runs-on: 'ubuntu-24.04-4core'
steps:
- uses: actions/checkout@v4.1.6
with:
fetch-depth: 0
- uses: ./.github/actions/linux-prereq
- id: get_commit_msg
uses: ./.github/actions/get-commit-msg
- name: Prerequisites
run: pip install tifffile numpy
- name: Run update script
env:
GH_TOKEN: ${{ secrets.FILAMENTBOT_TOKEN }}
COMMIT_MESSAGE: ${{ steps.get_commit_msg.outputs.msg }}
run: |
GOLDEN_BRANCH=$(echo "${COMMIT_MESSAGE}" | python3 test/renderdiff/src/commit_msg.py)
COMMIT_HASH="${{ steps.get_commit_msg.outputs.hash }}"
if [[ "${GOLDEN_BRANCH}" != "main" ]]; then
git config --global user.email "filament.bot@gmail.com"
git config --global user.name "Filament Bot"
git config --global credential.helper cache
echo "branch==${GOLDEN_BRANCH}"
echo "hash==${COMMIT_HASH}"
python3 test/renderdiff/src/update_golden.py --branch=${GOLDEN_BRANCH} \
--merge-to-main --filament-tag=${COMMIT_HASH} --golden-repo-token=${GH_TOKEN}
fi
build-android:
name: build-android
# We intentially use a larger runner here to enable larger disk space
# (standard linux runner will fail on disk space and faster build time).
runs-on: 'ubuntu-24.04-16core'
update-docs:
name: update-docs
runs-on: 'ubuntu-24.04-4core'
steps:
- uses: actions/checkout@v4.1.6
with:
fetch-depth: 0
- uses: ./.github/actions/linux-prereq
- id: get_commit_msg
uses: ./.github/actions/get-commit-msg
- name: Prerequisites
run: pip install selenium
- name: Run update script
env:
GH_TOKEN: ${{ secrets.FILAMENTBOT_TOKEN }}
- name: Run Android Continuous
uses: ./.github/actions/android-continuous
with:
build-abi: armeabi-v7a,arm64-v8a,x86_64
build-ios:
name: build-ios
runs-on: macos-14-xlarge
steps:
- uses: actions/checkout@v4.1.6
with:
fetch-depth: 0
- uses: ./.github/actions/mac-prereq
- name: Run build script
run: |
bash docs_src/build/install_mdbook.sh && source ~/.bashrc
COMMIT_HASH="${{ steps.get_commit_msg.outputs.hash }}"
git config --global user.email "filament.bot@gmail.com"
git config --global user.name "Filament Bot"
git config --global credential.helper cache
bash docs_src/build/postsubmit.sh ${COMMIT_HASH} ${GH_TOKEN}
cd build/ios && printf "y" | ./build.sh continuous
- uses: actions/upload-artifact@v4
with:
name: filament-ios
path: out/filament-release-ios.tgz
- name: Build iOS samples
run: |
cd build/ios && ./build-samples.sh continuous
build-linux:
name: build-linux
runs-on: 'ubuntu-24.04-16core'
steps:
- uses: actions/checkout@v4.1.6
with:
fetch-depth: 0
- uses: ./.github/actions/linux-prereq
- name: Run build script
run: |
cd build/linux && printf "y" | ./build.sh continuous
- uses: actions/upload-artifact@v4
with:
name: filament-linux
path: out/filament-release-linux.tgz
build-mac:
name: build-mac
runs-on: macos-14-xlarge
steps:
- uses: actions/checkout@v4.1.6
with:
fetch-depth: 0
- uses: ./.github/actions/mac-prereq
- name: Run build script
run: |
cd build/mac && printf "y" | ./build.sh continuous
- uses: actions/upload-artifact@v4
with:
name: filament-mac
path: out/filament-release-darwin.tgz
- name: Check public headers
run: |
test/check-headers/test.sh out/release/filament/include
build-web:
name: build-web
runs-on: 'ubuntu-24.04-16core'
steps:
- uses: actions/checkout@v4.1.6
with:
fetch-depth: 0
- uses: ./.github/actions/linux-prereq
- uses: ./.github/actions/web-prereq
- name: Run build script
run: |
cd build/web && printf "y" | ./build.sh continuous
- uses: actions/upload-artifact@v4
with:
name: filament-web
path: out/filament-release-web.tgz
build-windows:
name: build-windows
runs-on: windows-2022-32core
steps:
- uses: actions/checkout@v4.1.6
- name: Run build script
run: |
build\windows\build-github.bat continuous
shell: cmd
- uses: actions/upload-artifact@v4
with:
name: filament-windows
path: out/filament-windows.tgz
+2 -2
View File
@@ -1,4 +1,4 @@
name: Presubmit
name: 'Presubmit CI'
on:
push:
@@ -19,7 +19,7 @@ jobs:
- uses: ./.github/actions/mac-prereq
- name: Run build script
run: |
cd build/mac && printf "y" | ./build.sh presubmit
cd build/mac && printf "y" | ./build.sh presubmit-with-test
- name: Test material parser
run: |
out/cmake-release/filament/test/test_material_parser
-27
View File
@@ -1,27 +0,0 @@
name: Web
on:
push:
branches:
- main
- release
- rc/**
jobs:
build-web:
name: build-web
runs-on: 'ubuntu-24.04-16core'
steps:
- uses: actions/checkout@v4.1.6
with:
fetch-depth: 0
- uses: ./.github/actions/linux-prereq
- uses: ./.github/actions/web-prereq
- name: Run build script
run: |
cd build/web && printf "y" | ./build.sh continuous
- uses: actions/upload-artifact@v4
with:
name: filament-web
path: out/filament-release-web.tgz
-24
View File
@@ -1,24 +0,0 @@
name: Windows
on:
push:
branches:
- main
- release
- rc/**
jobs:
build-windows:
name: build-windows
runs-on: windows-2022-32core
steps:
- uses: actions/checkout@v4.1.6
- name: Run build script
run: |
build\windows\build-github.bat continuous
shell: cmd
- uses: actions/upload-artifact@v4
with:
name: filament-windows
path: out/filament-windows.tgz
+18 -18
View File
@@ -1,6 +1,6 @@
## Building Filament
# Building Filament
### Prerequisites
## Prerequisites
To build Filament, you must first install the following tools:
@@ -18,7 +18,7 @@ To build Filament for Android you must also install the following:
- Android NDK 25.1 or higher
- Java 17
### Environment variables
## Environment variables
To build Filament for Android, make sure the environment variable `ANDROID_HOME` points to the
location of your Android SDK.
@@ -30,7 +30,7 @@ When building for WebGL, you'll also need to set `EMSDK`. See [WebAssembly](#web
We recommend using CLion to develop for Filament. Simply open the root directory's CMakeLists.txt
in CLion to obtain a usable project.
### Easy build
## Easy build
Once the required OS specific dependencies listed below are installed, you can use the script
located in `build.sh` to build Filament easily on macOS and Linux.
@@ -67,7 +67,7 @@ For more specialized options, please also consider the following pages:
- `-t`: [`fgviewer`](https://google.github.io/filament/dup/fgviewer.html)
- `-b` and `-y`: [ASAN/UBSAN builds](https://google.github.io/filament/notes/asan_ubsan.html)
### Filament-specific CMake Options
## Filament-specific CMake Options
The following CMake options are boolean options specific to Filament:
@@ -89,7 +89,7 @@ cmake . -DOPTION=ON # Replace OPTION with the option name, set to ON / OFF
Options can also be set with the CMake GUI.
### Linux
## Linux
Make sure you've installed the following dependencies:
@@ -148,7 +148,7 @@ ninja
This will build Filament, its tests and samples, and various host tools.
### macOS
## macOS
To compile Filament you must have the most recent version of Xcode installed and you need to
make sure the command line tools are setup by running:
@@ -169,7 +169,7 @@ cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../release/fila
ninja
```
### iOS
## iOS
The easiest way to build Filament for iOS is to use `build.sh` and the
`-p ios` flag. For instance to build the debug target:
@@ -180,9 +180,9 @@ The easiest way to build Filament for iOS is to use `build.sh` and the
See [ios/samples/README.md](./ios/samples/README.md) for more information.
### Windows
## Windows
#### Building on Windows with Visual Studio 2019 or later
### Building on Windows with Visual Studio 2019 or later
Install the following components:
@@ -225,7 +225,7 @@ You can also use CMake to invoke the build without opening Visual Studio. For ex
cmake --build . --target gltf_viewer --config Release
```
### Android
## Android
Before building Filament for Android, make sure to build Filament for your host. Some of the
host tools are required to successfully build for Android.
@@ -242,13 +242,13 @@ foremost for `arm64-v8a`.
To build Android on Windows machines, see [android/Windows.md](android/Windows.md).
#### Important: SDK location
### Important: SDK location
Either ensure your `ANDROID_HOME` environment variable is set or make sure the root project
contains a `local.properties` file with the `sdk.dir` property pointing to your installation of
the Android SDK.
#### Easy Android build
### Easy Android build
The easiest way to build Filament for Android is to use `build.sh` and the
`-p android` flag. For instance to build the release target:
@@ -266,7 +266,7 @@ The output APK can be found in `android/samples/sample-hello-triangle/build/outp
Run `build.sh -h` for more information.
#### Android Studio
### Android Studio
You must use the latest stable release of Android Studio.
@@ -296,7 +296,7 @@ device's architecture. So if you are targeting a new Pixel phone, make sure that
an emulator on a Linux machine with an x86 64-bit chipset, you would indicate (`-q x86_64`) in the above step.
#### Manual builds
### Manual builds
Invoke CMake in a build directory of your choice, inside of filament's directory. The commands
below show how to build Filament for ARM 64-bit (`aarch64`).
@@ -324,7 +324,7 @@ This will generate Filament's Android binaries in `out/android-release`. This lo
to build the Android Studio projects located in `filament/android`. After install, the library
binaries should be found in `out/android-release/filament/lib/arm64-v8a`.
#### AAR
### AAR
Before you attempt to build the AAR, make sure you've compiled and installed the native libraries
as explained in the sections above. You must have the following ABIs built in
@@ -356,7 +356,7 @@ Alternatively you can build the AAR from the command line by executing the follo
The `-Pcom.google.android.filament.dist-dir` can be used to specify a different installation
directory (it must match the CMake install prefix used in the previous steps).
#### Using Filament's AAR
### Using Filament's AAR
Create a new module in your project and select _Import .JAR or .AAR Package_ when prompted. Make
sure to add the newly created module as a dependency to your application.
@@ -397,7 +397,7 @@ productFlavors {
}
```
### WebAssembly
## WebAssembly
The core Filament library can be cross-compiled to WebAssembly from either macOS or Linux. To get
started, follow the instructions for building Filament on your platform ([macOS](#macos) or
+17 -4
View File
@@ -10,6 +10,7 @@ cmake_minimum_required(VERSION 3.22.1)
# ==================================================================================================
# Toolchain configuration
# ==================================================================================================
# On iOS, the deployment target is set inside third_party/clang/ios.cmake
if (APPLE AND NOT IOS)
# This must be set before project() is called
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.15 CACHE STRING "")
@@ -367,14 +368,22 @@ endif()
if (LINUX)
option(USE_STATIC_LIBCXX "Link against the static runtime libraries." ON)
# Add this step to support both glibc-based Linux distributions (e.g., Ubuntu, Debian)
# and musl-based distributions (e.g., Alpine).
include(CheckSymbolExists)
check_symbol_exists(__GLIBC__ "features.h" CLANG_WITH_GLIBC)
if (${USE_STATIC_LIBCXX})
if (FILAMENT_USING_GCC)
link_libraries("-static-libgcc -static-libstdc++")
else ()
elseif (CLANG_WITH_GLIBC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
link_libraries("-static-libgcc -static-libstdc++")
link_libraries(libc++.a)
link_libraries(libc++abi.a)
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static")
endif()
endif()
@@ -473,7 +482,7 @@ endif()
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${EXTRA_SANITIZE_OPTIONS}")
if (FILAMENT_ENABLE_COVERAGE)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fprofile-instr-generate -fcoverage-mapping")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-instr-generate -fcoverage-mapping -Wno-pass-failed")
endif()
# Disable the stack check for macOS to workaround a known issue in clang 11.0.0.
@@ -563,6 +572,10 @@ if (FILAMENT_SUPPORTS_WEBGPU)
add_definitions(-DFILAMENT_SUPPORTS_WEBGPU)
endif()
if (FILAMENT_SUPPORTS_WEBP_TEXTURES)
add_definitions(-DFILAMENT_SUPPORTS_WEBP_TEXTURES)
endif()
# Build with Metal support on non-WebGL Apple platforms.
if (APPLE AND NOT WEBGL)
option(FILAMENT_SUPPORTS_METAL "Include the Metal backend" ON)
@@ -574,7 +587,7 @@ if (FILAMENT_SUPPORTS_METAL)
endif()
# Building filamat increases build times and isn't required for web, so turn it off by default.
if (NOT WEBGL AND NOT IOS)
if (NOT WEBGL)
option(FILAMENT_BUILD_FILAMAT "Build filamat and JNI buildings" ON)
else()
option(FILAMENT_BUILD_FILAMAT "Build filamat and JNI buildings" OFF)
@@ -915,7 +928,6 @@ endif()
if (FILAMENT_SUPPORTS_WEBP_TEXTURES)
add_subdirectory(${EXTERNAL}/libwebp/tnt)
add_definitions(-DFILAMENT_SUPPORTS_WEBP_TEXTURES)
endif()
if (FILAMENT_SUPPORTS_VULKAN)
@@ -973,6 +985,7 @@ if (IS_HOST_PLATFORM)
add_subdirectory(${TOOLS}/roughness-prefilter)
add_subdirectory(${TOOLS}/specular-color)
add_subdirectory(${TOOLS}/uberz)
add_subdirectory(${TOOLS}/specgen)
endif()
# Generate exported executables for cross-compiled builds (Android, WebGL, and iOS)
+2 -2
View File
@@ -31,7 +31,7 @@ repositories {
}
dependencies {
implementation 'com.google.android.filament:filament-android:1.68.3'
implementation 'com.google.android.filament:filament-android:1.68.5'
}
```
@@ -51,7 +51,7 @@ Here are all the libraries available in the group `com.google.android.filament`:
iOS projects can use CocoaPods to install the latest release:
```shell
pod 'Filament', '~> 1.68.3'
pod 'Filament', '~> 1.68.5'
```
## Documentation
+13
View File
@@ -7,6 +7,19 @@ A new header is inserted each time a *tag* is created.
Instead, if you are authoring a PR for the main branch, add your release note to
[NEW_RELEASE_NOTES.md](./NEW_RELEASE_NOTES.md).
## v1.69.0
- engine: Support custom attributes morphing, and allow for omitting position and/or normal data. [⚠️ **Recompile Materials**]
## v1.68.5
- engine: "native" Streams are officially deprecated. Use "acquired" streams instead.
- engine: add "engine.skip_frame_when_cpu_ahead_of_display" feature [b/474599530]
## v1.68.4
- gltfio: Add optional support for webp textures (EXT_texture_webp), controlled via FILAMENT_SUPPORTS_WEBP_TEXTURES cmake option
## v1.68.3
- materials: added support for the glTF `KHR_materials_dispersion` extension, which adds dispersion for refractive objects
+1 -1
View File
@@ -194,7 +194,7 @@ subprojects {
google()
}
if (!name.startsWith("sample")) {
if (!name.startsWith("sample") && name != "filament-tools") {
apply plugin: 'com.android.library'
android {
@@ -335,6 +335,13 @@ Java_com_google_android_filament_filamat_MaterialBuilder_nMaterialBuilderRefract
builder->refractionMode((MaterialBuilder::RefractionMode) mode);
}
extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_filamat_MaterialBuilder_nMaterialBuilderReflectionMode(JNIEnv* env,
jclass, jlong nativeBuilder, jint mode) {
auto builder = (MaterialBuilder*) nativeBuilder;
builder->reflectionMode((MaterialBuilder::ReflectionMode) mode);
}
extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_filamat_MaterialBuilder_nMaterialBuilderRefractionType(JNIEnv* env,
jclass, jlong nativeBuilder, jint type) {
@@ -177,6 +177,11 @@ public class MaterialBuilder {
SCREEN_SPACE
}
public enum ReflectionMode {
DEFAULT,
SCREEN_SPACE
}
public enum RefractionType {
SOLID,
THIN
@@ -403,6 +408,12 @@ public class MaterialBuilder {
return this;
}
@NonNull
public MaterialBuilder reflectionMode(ReflectionMode mode) {
nMaterialBuilderReflectionMode(mNativeObject, mode.ordinal());
return this;
}
@NonNull
public MaterialBuilder refractionType(RefractionType type) {
nMaterialBuilderRefractionType(mNativeObject, type.ordinal());
@@ -604,6 +615,7 @@ public class MaterialBuilder {
private static native void nMaterialBuilderSpecularAntiAliasingThreshold(long mNativeObject,
float threshold);
private static native void nMaterialBuilderRefractionMode(long nativeBuilder, int mode);
private static native void nMaterialBuilderReflectionMode(long nativeBuilder, int mode);
private static native void nMaterialBuilderRefractionType(long nativeBuilder, int type);
private static native void nMaterialBuilderClearCoatIorChange(long mNativeObject,
boolean clearCoatIorChange);
@@ -18,6 +18,7 @@
#include <filament/Camera.h>
#include <filament/Engine.h>
#include <filament/MorphTargetBuffer.h>
#include <utils/Entity.h>
#include <utils/EntityManager.h>
@@ -207,6 +208,14 @@ Java_com_google_android_filament_Engine_nDestroySkinningBuffer(JNIEnv*, jclass,
return engine->destroy(skinningBuffer);
}
extern "C" JNIEXPORT jboolean JNICALL
Java_com_google_android_filament_Engine_nDestroyMorphTargetBuffer(JNIEnv*, jclass,
jlong nativeEngine, jlong nativeMorphTargetBuffer) {
Engine* engine = (Engine*) nativeEngine;
MorphTargetBuffer* mtb = (MorphTargetBuffer*) nativeMorphTargetBuffer;
return engine->destroy(mtb);
}
extern "C" JNIEXPORT jboolean JNICALL
Java_com_google_android_filament_Engine_nDestroyIndirectLight(JNIEnv*, jclass,
jlong nativeEngine, jlong nativeIndirectLight) {
@@ -328,6 +337,13 @@ Java_com_google_android_filament_Engine_nIsValidSkinningBuffer(JNIEnv*, jclass,
return (jboolean)engine->isValid((SkinningBuffer*)nativeSkinningBuffer);
}
extern "C" JNIEXPORT jboolean JNICALL
Java_com_google_android_filament_Engine_nIsValidMorphTargetBuffer(JNIEnv*, jclass,
jlong nativeEngine, jlong nativeMorphTargetBuffer) {
Engine* engine = (Engine*) nativeEngine;
return (jboolean) engine->isValid((MorphTargetBuffer*) nativeMorphTargetBuffer);
}
extern "C" JNIEXPORT jboolean JNICALL
Java_com_google_android_filament_Engine_nIsValidIndirectLight(JNIEnv*, jclass,
jlong nativeEngine, jlong nativeIndirectLight) {
@@ -58,6 +58,27 @@ Java_com_google_android_filament_MorphTargetBuffer_nBuilderCount(JNIEnv*, jclass
builder->count((size_t) count);
}
extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_MorphTargetBuffer_nBuilderWithPositions(JNIEnv*, jclass,
jlong nativeBuilder, jboolean enabled) {
MorphTargetBuffer::Builder* builder = (MorphTargetBuffer::Builder*) nativeBuilder;
builder->withPositions(enabled);
}
extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_MorphTargetBuffer_nBuilderWithTangents(JNIEnv*, jclass,
jlong nativeBuilder, jboolean enabled) {
MorphTargetBuffer::Builder* builder = (MorphTargetBuffer::Builder*) nativeBuilder;
builder->withTangents(enabled);
}
extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_MorphTargetBuffer_nBuilderEnableCustomMorphing(JNIEnv*,
jclass, jlong nativeBuilder, jboolean enabled) {
MorphTargetBuffer::Builder* builder = (MorphTargetBuffer::Builder*) nativeBuilder;
builder->enableCustomMorphing(enabled);
}
extern "C"
JNIEXPORT jlong JNICALL
Java_com_google_android_filament_MorphTargetBuffer_nBuilderBuild(JNIEnv*, jclass,
@@ -112,3 +133,24 @@ Java_com_google_android_filament_MorphTargetBuffer_nGetCount(JNIEnv*, jclass,
MorphTargetBuffer *morphTargetBuffer = (MorphTargetBuffer *) nativeObject;
return (jint)morphTargetBuffer->getCount();
}
extern "C" JNIEXPORT jboolean JNICALL
Java_com_google_android_filament_MorphTargetBuffer_nHasPositions(JNIEnv*, jclass,
jlong nativeObject) {
MorphTargetBuffer* morphTargetBuffer = (MorphTargetBuffer*) nativeObject;
return (jboolean) morphTargetBuffer->hasPositions();
}
extern "C" JNIEXPORT jboolean JNICALL
Java_com_google_android_filament_MorphTargetBuffer_nHasTangents(JNIEnv*, jclass,
jlong nativeObject) {
MorphTargetBuffer* morphTargetBuffer = (MorphTargetBuffer*) nativeObject;
return (jboolean) morphTargetBuffer->hasTangents();
}
extern "C" JNIEXPORT jboolean JNICALL
Java_com_google_android_filament_MorphTargetBuffer_nIsCustomMorphingEnabled(JNIEnv*, jclass,
jlong nativeObject) {
MorphTargetBuffer* morphTargetBuffer = (MorphTargetBuffer*) nativeObject;
return (jboolean) morphTargetBuffer->isCustomMorphingEnabled();
}
@@ -52,6 +52,11 @@ Java_com_google_android_filament_ToneMapper_nCreatePBRNeutralToneMapper(JNIEnv*,
return (jlong) new PBRNeutralToneMapper();
}
extern "C" JNIEXPORT jlong JNICALL
Java_com_google_android_filament_ToneMapper_nCreateGT7ToneMapper(JNIEnv*, jclass) {
return (jlong) new GT7ToneMapper();
}
extern "C" JNIEXPORT jlong JNICALL
Java_com_google_android_filament_ToneMapper_nCreateAgxToneMapper(JNIEnv*, jclass, jint look) {
return (jlong) new AgxToneMapper(AgxToneMapper::AgxLook(look));
@@ -939,6 +939,15 @@ public class Engine {
return nIsValidSkinningBuffer(getNativeObject(), object.getNativeObject());
}
/**
* Returns whether the object is valid.
* @param object Object to check for validity
* @return returns true if the specified object is valid.
*/
public boolean isValidMorphTargetBuffer(@NonNull MorphTargetBuffer object) {
return nIsValidMorphTargetBuffer(getNativeObject(), object.getNativeObject());
}
/**
* Returns whether the object is valid.
* @param object Object to check for validity
@@ -1192,6 +1201,15 @@ public class Engine {
skinningBuffer.clearNativeObject();
}
/**
* Destroys a {@link MorphTargetBuffer} and frees all its associated resources.
* @param morphTargetBuffer the {@link MorphTargetBuffer} to destroy
*/
public void destroyMorphTargetBuffer(@NonNull MorphTargetBuffer morphTargetBuffer) {
assertDestroy(nDestroyMorphTargetBuffer(getNativeObject(), morphTargetBuffer.getNativeObject()));
morphTargetBuffer.clearNativeObject();
}
/**
* Destroys a {@link IndirectLight} and frees all its associated resources.
* @param ibl the {@link IndirectLight} to destroy
@@ -1483,6 +1501,7 @@ public class Engine {
private static native boolean nDestroyIndexBuffer(long nativeEngine, long nativeIndexBuffer);
private static native boolean nDestroyVertexBuffer(long nativeEngine, long nativeVertexBuffer);
private static native boolean nDestroySkinningBuffer(long nativeEngine, long nativeSkinningBuffer);
private static native boolean nDestroyMorphTargetBuffer(long nativeEngine, long nativeMorphTargetBuffer);
private static native boolean nDestroyIndirectLight(long nativeEngine, long nativeIndirectLight);
private static native boolean nDestroyMaterial(long nativeEngine, long nativeMaterial);
private static native boolean nDestroyMaterialInstance(long nativeEngine, long nativeMaterialInstance);
@@ -1499,6 +1518,7 @@ public class Engine {
private static native boolean nIsValidIndexBuffer(long nativeEngine, long nativeIndexBuffer);
private static native boolean nIsValidVertexBuffer(long nativeEngine, long nativeVertexBuffer);
private static native boolean nIsValidSkinningBuffer(long nativeEngine, long nativeSkinningBuffer);
private static native boolean nIsValidMorphTargetBuffer(long nativeEngine, long nativeMorphTargetBuffer);
private static native boolean nIsValidIndirectLight(long nativeEngine, long nativeIndirectLight);
private static native boolean nIsValidMaterial(long nativeEngine, long nativeMaterial);
private static native boolean nIsValidMaterialInstance(long nativeEngine, long nativeMaterial, long nativeMaterialInstance);
@@ -64,6 +64,45 @@ public class MorphTargetBuffer {
return this;
}
/**
* Use this method to enable or disable the built-in position morphing buffer.
* Default is true.
*
* @param enabled true to enable, false to disable
* @return this <code>Builder</code> object for chaining calls
*/
@NonNull
public Builder withPositions(boolean enabled) {
nBuilderWithPositions(mNativeBuilder, enabled);
return this;
}
/**
* Use this method to enable or disable the built-in tangent morphing buffer.
* Default is true.
*
* @param enabled true to enable, false to disable
* @return this <code>Builder</code> object for chaining calls
*/
@NonNull
public Builder withTangents(boolean enabled) {
nBuilderWithTangents(mNativeBuilder, enabled);
return this;
}
/**
* Use this method to enable or disable custom morphing.
* Default is false.
*
* @param enabled true to enable, false to disable
* @return this <code>Builder</code> object for chaining calls
*/
@NonNull
public Builder enableCustomMorphing(boolean enabled) {
nBuilderEnableCustomMorphing(mNativeBuilder, enabled);
return this;
}
/**
* Creates and returns the <code>MorphTargetBuffer</code> object.
*
@@ -156,6 +195,27 @@ public class MorphTargetBuffer {
return nGetCount(mNativeObject);
}
/**
* @return true if this MorphTargetBuffer has a position buffer.
*/
public boolean hasPositions() {
return nHasPositions(mNativeObject);
}
/**
* @return true if this MorphTargetBuffer has a tangent buffer.
*/
public boolean hasTangents() {
return nHasTangents(mNativeObject);
}
/**
* @return true if custom morphing is enabled.
*/
public boolean isCustomMorphingEnabled() {
return nIsCustomMorphingEnabled(mNativeObject);
}
public long getNativeObject() {
if (mNativeObject == 0) {
throw new IllegalStateException("Calling method on destroyed MorphTargetBuffer");
@@ -171,10 +231,16 @@ public class MorphTargetBuffer {
private static native void nDestroyBuilder(long nativeBuilder);
private static native void nBuilderVertexCount(long nativeBuilder, int vertexCount);
private static native void nBuilderCount(long nativeBuilder, int count);
private static native void nBuilderWithPositions(long nativeBuilder, boolean enabled);
private static native void nBuilderWithTangents(long nativeBuilder, boolean enabled);
private static native void nBuilderEnableCustomMorphing(long nativeBuilder, boolean enabled);
private static native long nBuilderBuild(long nativeBuilder, long nativeEngine);
private static native int nSetPositionsAt(long nativeObject, long nativeEngine, int targetIndex, float[] positions, int count);
private static native int nSetTangentsAt(long nativeObject, long nativeEngine, int targetIndex, short[] tangents, int count);
private static native int nGetVertexCount(long nativeObject);
private static native int nGetCount(long nativeObject);
private static native boolean nHasPositions(long nativeObject);
private static native boolean nHasTangents(long nativeObject);
private static native boolean nIsCustomMorphingEnabled(long nativeObject);
}
@@ -24,6 +24,7 @@ package com.google.android.filament;
* <li>ACESLegacyToneMapper</li>
* <li>FilmicToneMapper</li>
* <li>PBRNeutralToneMapper</li>
* <li>GT7ToneMapper</li>
* </ul>
* <li>Debug/validation tone mapping operators</li>
* <ul>
@@ -111,6 +112,19 @@ public class ToneMapper {
}
}
/**
* Gran Turismo 7 tone mapping operator. This tone mapper was designed
* to preserve the appearance of materials across lighting conditions while
* avoiding artifacts in the highlights in high dynamic range conditions.
* This tone mapper targets an SDR paper white value of 250 nits, with a
* reference luminance of 100 cd/m^2 (a value of 1.0 in the HDR framebuffer).
*/
public static class GT7ToneMapper extends ToneMapper {
public GT7ToneMapper() {
super(nCreateGT7ToneMapper());
}
}
/**
* AgX tone mapping operator.
*/
@@ -244,6 +258,7 @@ public class ToneMapper {
private static native long nCreateACESLegacyToneMapper();
private static native long nCreateFilmicToneMapper();
private static native long nCreatePBRNeutralToneMapper();
private static native long nCreateGT7ToneMapper();
private static native long nCreateAgxToneMapper(int look);
private static native long nCreateGenericToneMapper(
float contrast, float midGrayIn, float midGrayOut, float hdrMax);
@@ -2041,10 +2041,6 @@ public class View {
* use an AABB neighborhood
*/
AABB,
/**
* use the variance of the neighborhood (not recommended)
*/
VARIANCE,
/**
* use both AABB and variance
*/
@@ -2075,7 +2071,7 @@ public class View {
}
/**
* reconstruction filter width typically between 1 (sharper) and 2 (smoother)
* @deprecated has no effect.
*/
public float filterWidth = 1.0f;
/**
@@ -2095,9 +2091,9 @@ public class View {
*/
public boolean enabled = false;
/**
* 4x TAA upscaling. Disables Dynamic Resolution. [BETA]
* Upscaling factor. Disables Dynamic Resolution. [BETA]
*/
public boolean upscaling = false;
public float upscaling = 1.0f;
/**
* whether to filter the history buffer
*/
@@ -2110,6 +2106,10 @@ public class View {
* whether to use the YcoCg color-space for history rejection
*/
public boolean useYCoCg = false;
/**
* set to true for HDR content
*/
public boolean hdr = true;
/**
* type of color gamut box
*/
+12
View File
@@ -0,0 +1,12 @@
*.iml
.gradle
/local.properties
/.idea/workspace.xml
/.idea/libraries
/.idea/caches
/.idea/gradle.xml
.DS_Store
/build
/captures
.externalNativeBuild
/.cxx
+64
View File
@@ -0,0 +1,64 @@
plugins {
id "de.undercouch.download" version "5.6.0"
}
apply from: rootProject.file('gradle/gradle-mvn-push.gradle')
def tools = ['matc', 'cmgen']
def platforms = [
'mac': [classifier: 'osx-aarch64', archive: "filament-v${VERSION_NAME}-mac.tgz", path: { t -> "filament/bin/${t}" }],
'linux': [classifier: 'linux-x86_64', archive: "filament-v${VERSION_NAME}-linux.tgz", path: { t -> "filament/bin/${t}" }],
'windows': [classifier: 'windows-x86_64', archive: "filament-v${VERSION_NAME}-windows.tgz", path: { t -> "bin/${t}.exe" }]
]
platforms.each { platform, config ->
def platformName = platform.capitalize()
def remoteUrl = "https://github.com/google/filament/releases/download/v${VERSION_NAME}/${config.archive}"
def downloadFile = file("${buildDir}/downloads/${config.archive}")
def extractDir = file("${buildDir}/extracted/filament-v${VERSION_NAME}-${platform}")
task "downloadRelease${platformName}"(type: Download) {
src remoteUrl
dest downloadFile
overwrite false
}
def extractionTask = task "extractTools${platformName}"(dependsOn: "downloadRelease${platformName}", type: Copy) {
group = "setup"
from tarTree(resources.gzip(downloadFile))
// Include specific tools based on platform pattern
include tools.collect { tool -> config.path(tool) }
// Flatten the path so it lands directly in 'into'
eachFile { fcd ->
fcd.relativePath = new RelativePath(true, fcd.name)
}
into extractDir
includeEmptyDirs = false
}
}
publishing {
publications {
tools.each { toolName ->
create(toolName, MavenPublication) {
artifactId = toolName
platforms.each { platform, config ->
def extractDir = file("${buildDir}/extracted/filament-v${VERSION_NAME}-${platform}")
def archivePath = config.path(toolName)
def exeName = new File(archivePath).name
artifact(new File(extractDir, exeName)) {
classifier = config.classifier
extension = "exe"
builtBy tasks.named("extractTools${platform.capitalize()}")
}
}
}
}
}
}
+2
View File
@@ -0,0 +1,2 @@
POM_NAME=Filament
POM_PACKAGING=exe
+14
View File
@@ -6,6 +6,7 @@ option(FILAMENT_ENABLE_FGVIEWER "Enables Frame Graph Viewer" OFF)
option(FILAMENT_ENABLE_MATDBG "Enables Material debugger" OFF)
option(FILAMENT_DISABLE_MATOPT "Disables material optimizations" OFF)
option(FILAMENT_SUPPORTS_WEBGPU "Enables WebGPU on Android" OFF)
option(FILAMENT_SUPPORTS_WEBP_TEXTURES "Enable webp texture support on Android" OFF)
set(CMAKE_CXX_STANDARD 20)
@@ -30,6 +31,12 @@ add_library(stb STATIC IMPORTED)
set_target_properties(stb PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libstb.a)
if (FILAMENT_SUPPORTS_WEBP_TEXTURES)
add_library(webpdecoder STATIC IMPORTED)
set_target_properties(webpdecoder PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libwebpdecoder.a)
endif()
add_library(basis_transcoder STATIC IMPORTED)
set_target_properties(basis_transcoder PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libbasis_transcoder.a)
@@ -81,6 +88,10 @@ set(GLTFIO_INCLUDE_DIRS
../../libs/ktxreader/include
)
if (FILAMENT_SUPPORTS_WEBP_TEXTURES)
list(APPEND GLTFIO_INCLUDE_DIRS ../../third_party/libwebp/src)
endif()
add_library(gltfio-jni SHARED ${GLTFIO_SRCS})
target_compile_definitions(gltfio-jni PUBLIC GLTFIO_DRACO_SUPPORTED=1)
@@ -107,3 +118,6 @@ target_link_libraries(gltfio-jni
PRIVATE perfetto # needed only when FILAMENT_ENABLE_PERFETTO is defined
PRIVATE log # needed only when perfetto above is used
)
if (FILAMENT_SUPPORTS_WEBP_TEXTURES)
target_link_libraries(gltfio-jni PRIVATE webpdecoder)
endif()
@@ -128,6 +128,18 @@ Java_com_google_android_filament_gltfio_ResourceLoader_nCreateKtx2Provider(JNIEn
return (jlong) createKtx2Provider(engine);
}
extern "C" JNIEXPORT jboolean JNICALL
Java_com_google_android_filament_gltfio_ResourceLoader_nIsWebpSupported(JNIEnv*, jclass) {
return (jboolean) isWebpSupported();
}
extern "C" JNIEXPORT jlong JNICALL
Java_com_google_android_filament_gltfio_ResourceLoader_nCreateWebpProvider(JNIEnv*, jclass,
jlong nativeEngine) {
Engine* engine = (Engine*) nativeEngine;
return (jlong) createWebpProvider(engine);
}
extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_gltfio_ResourceLoader_nDestroyTextureProvider(JNIEnv*, jclass,
jlong nativeProvider) {
@@ -37,6 +37,7 @@ public class ResourceLoader {
private final long mNativeObject;
private final long mNativeStbProvider;
private final long mNativeKtx2Provider;
private final long mNativeWebpProvider;
/**
* Constructs a resource loader tied to the given Filament engine.
@@ -50,9 +51,17 @@ public class ResourceLoader {
mNativeObject = nCreateResourceLoader(nativeEngine, false);
mNativeStbProvider = nCreateStbProvider(nativeEngine);
mNativeKtx2Provider = nCreateKtx2Provider(nativeEngine);
nAddTextureProvider(mNativeObject, "image/jpeg", mNativeStbProvider);
nAddTextureProvider(mNativeObject, "image/png", mNativeStbProvider);
nAddTextureProvider(mNativeObject, "image/ktx2", mNativeKtx2Provider);
if (nIsWebpSupported()) {
mNativeWebpProvider = nCreateWebpProvider(nativeEngine);
nAddTextureProvider(mNativeObject, "image/webp", mNativeWebpProvider);
}
else {
mNativeWebpProvider = 0;
}
}
/**
@@ -68,9 +77,17 @@ public class ResourceLoader {
mNativeObject = nCreateResourceLoader(nativeEngine, normalizeSkinningWeights);
mNativeStbProvider = nCreateStbProvider(nativeEngine);
mNativeKtx2Provider = nCreateKtx2Provider(nativeEngine);
nAddTextureProvider(mNativeObject, "image/jpeg", mNativeStbProvider);
nAddTextureProvider(mNativeObject, "image/png", mNativeStbProvider);
nAddTextureProvider(mNativeObject, "image/ktx2", mNativeKtx2Provider);
if (nIsWebpSupported()) {
mNativeWebpProvider = nCreateWebpProvider(nativeEngine);
nAddTextureProvider(mNativeObject, "image/webp", mNativeWebpProvider);
}
else {
mNativeWebpProvider = 0;
}
}
/**
@@ -80,6 +97,9 @@ public class ResourceLoader {
nDestroyResourceLoader(mNativeObject);
nDestroyTextureProvider(mNativeStbProvider);
nDestroyTextureProvider(mNativeKtx2Provider);
if (nIsWebpSupported()) {
nDestroyTextureProvider(mNativeWebpProvider);
}
}
/**
@@ -191,6 +211,9 @@ public class ResourceLoader {
private static native long nCreateStbProvider(long nativeEngine);
private static native long nCreateKtx2Provider(long nativeEngine);
private static native boolean nIsWebpSupported();
private static native long nCreateWebpProvider(long nativeEngine);
private static native void nAddTextureProvider(long nativeLoader, String url, long nativeProvider);
private static native void nDestroyTextureProvider(long nativeProvider);
}
+1 -1
View File
@@ -1,5 +1,5 @@
GROUP=com.google.android.filament
VERSION_NAME=1.68.3
VERSION_NAME=1.68.5
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
@@ -76,11 +76,16 @@ class MainActivity : Activity() {
private var texture: Texture? = null
private var renderTarget: RenderTarget? = null
private var useExternalTexture = true
private lateinit var offscreenView: View
private lateinit var offscreenCamera: Camera
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// To use set this flag with adb, run
// adb shell am start -n com.google.android.filament.texturetarget/.MainActivity --ez useExternalTexture false
useExternalTexture = intent.getBooleanExtra("useExternalTexture", true)
surfaceView = SurfaceView(this)
setContentView(surfaceView)
choreographer = Choreographer.getInstance()
@@ -173,8 +178,15 @@ class MainActivity : Activity() {
readUncompressedAsset("materials/baked_color.filamat").let {
triangleMaterial = Material.Builder().payload(it, it.remaining()).build(engine)
}
readUncompressedAsset("materials/textured.filamat").let {
texturedMaterial = Material.Builder().payload(it, it.remaining()).build(engine)
if (useExternalTexture) {
readUncompressedAsset("materials/texturedExternal.filamat").let {
texturedMaterial = Material.Builder().payload(it, it.remaining()).build(engine)
}
} else {
readUncompressedAsset("materials/textured.filamat").let {
texturedMaterial = Material.Builder().payload(it, it.remaining()).build(engine)
}
}
}
@@ -385,33 +397,41 @@ class MainActivity : Activity() {
texture?.let { engine.destroyTexture(it) }
hardwareBuffer?.close()
// Create a new render target.
hardwareBuffer = HardwareBuffer.create(width, height,
HardwareBuffer.RGBA_8888, 1,
HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE or HardwareBuffer.USAGE_GPU_COLOR_OUTPUT)
if (useExternalTexture) {
// Create a new render target.
hardwareBuffer = HardwareBuffer.create(width, height,
HardwareBuffer.RGBA_8888, 1,
HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE or HardwareBuffer.USAGE_GPU_COLOR_OUTPUT)
texture = Texture.Builder()
.width(width)
.height(height)
.usage(Texture.Usage.COLOR_ATTACHMENT or Texture.Usage.SAMPLEABLE)
.sampler(Texture.Sampler.SAMPLER_EXTERNAL)
.format(Texture.InternalFormat.RGBA8)
.external()
.build(engine)
texture = Texture.Builder()
.width(width)
.height(height)
.usage(Texture.Usage.COLOR_ATTACHMENT or Texture.Usage.SAMPLEABLE)
.sampler(Texture.Sampler.SAMPLER_EXTERNAL)
.format(Texture.InternalFormat.RGBA8)
.external()
.build(engine)
texture!!.setExternalImage(engine, hardwareBuffer!!)
texture!!.setExternalImage(engine, hardwareBuffer!!)
} else {
texture = Texture.Builder()
.width(width)
.height(height)
.levels(1)
.usage(Texture.Usage.COLOR_ATTACHMENT or Texture.Usage.SAMPLEABLE)
.format(Texture.InternalFormat.RGBA8)
.build(engine)
}
renderTarget = RenderTarget.Builder()
.texture(RenderTarget.AttachmentPoint.COLOR, texture!!)
.build(engine)
offscreenView.renderTarget = renderTarget
// Set the texture on the quad material.
texturedMaterial.defaultInstance.setParameter("texture", texture!!,
TextureSampler(TextureSampler.MinFilter.LINEAR, TextureSampler.MagFilter.LINEAR,
TextureSampler.WrapMode.CLAMP_TO_EDGE))
TextureSampler.WrapMode.CLAMP_TO_EDGE))
FilamentHelper.synchronizePendingFrames(engine)
}
}
@@ -3,7 +3,7 @@ material {
shadingModel : unlit,
parameters : [
{
type : samplerExternal,
type : sampler2d,
name : texture
}
],
@@ -15,6 +15,6 @@ material {
fragment {
void material(inout MaterialInputs material) {
prepareMaterial(material);
material.baseColor = texture(materialParams_texture, getUV0());
material.baseColor = texture(materialParams_texture, uvToRenderTargetUV(getUV0()));
}
}
@@ -0,0 +1,20 @@
material {
name : textured,
shadingModel : unlit,
parameters : [
{
type : samplerExternal,
name : texture
}
],
requires: [
uv0
]
}
fragment {
void material(inout MaterialInputs material) {
prepareMaterial(material);
material.baseColor = texture(materialParams_texture, uvToRenderTargetUV(getUV0()));
}
}
+1
View File
@@ -3,6 +3,7 @@ include ':filament-android'
include ':filamat-android'
include ':gltfio-android'
include ':filament-utils-android'
include ':filament-tools'
// Samples
include ':samples:sample-gltf-viewer'
+5
View File
@@ -34,6 +34,11 @@ if [[ "$TARGET" == "presubmit" ]]; then
BUILD_RELEASE=release
fi
if [[ "$TARGET" == "presubmit-with-test" ]]; then
BUILD_RELEASE=release
RUN_TESTS=-u
fi
if [[ "$TARGET" == "debug" ]]; then
BUILD_DEBUG=debug
GENERATE_ARCHIVES=-a
+30 -6
View File
@@ -97,6 +97,7 @@ in table [standardProperties].
**transmission** | Defines how much of the diffuse light of a dielectric is transmitted through the object, in other words this defines how transparent an object is
**ior** | Index of refraction, either for refractive objects or as an alternative to reflectance
**microThickness** | Thickness of the thin layer of refractive objects
**dispersion** | Strength of the dispersion effect for refractive objects, specified as 20/Abbe number
**bentNormal** | A normal pointing in the average unoccluded direction. Can be used to improve indirect lighting quality
**shadowStrength** | Strength factor between 0 and 1 for all shadows received by this material
[Table [standardProperties]: Properties of the standard model]
@@ -126,6 +127,7 @@ The type and range of each property is described in table [standardPropertiesTyp
**absorption** | float3 | [0..n] |
**microThickness** | float | [0..n] |
**thickness** | float | [0..n] |
**dispersion** | float | [0..n] | Realistic values are between [0, 1], with the exception of Rutile, which has a value of 2.04
[Table [standardPropertiesTypes]: Range and type of the standard model's properties]
@@ -153,13 +155,14 @@ The type and range of each property is described in table [standardPropertiesTyp
as-is, which can lead to physically impossible materials, however, this might be desirable
for artistic reasons.
!!! Note: About `thickness` and `microThickness` for refraction
!!! Note: About `thickness`, `microThickness` and `dispersion` for refraction
`thickness` represents the thickness of solid objects in the direction of the normal, for
satisfactory results, this should be provided per fragment (e.g.: as a texture) or at least per
vertex. `microThickness` represent the thickness of the thin layer of an object, and can
generally be provided as a constant value. For example, a 1mm thin hollow sphere of radius 1m,
would have a `thickness` of 1 and a `microThickness` of 0.001. Currently `thickness` is not
used when `refractionType` is set to `thin`.
would have a `thickness` of 1 and a `microThickness` of 0.001. Dispersion controls the angular
separation of colors transmitting through a volume, and can be set by a constant value.
Currently `thickness` and `dispersion` are not used when `refractionType` is set to `thin`.
### Base color
@@ -651,6 +654,26 @@ the `refractionType` is set to `solid` and `absorption` coefficients are set.
![Figure [varyingThickness]: `thickness` varying from 0.0 at the top of the prism to 3.0 at the
bottom of the prism](images/material_thickness.png)
### Dispersion
The dispersion property controls the angular separation of colors transmitting through a relatively
clear volume. It can only be used when `refractionType` is set to `volume`.
Its value is specified as 20/Abbe number. When the value is zero, no dispersion is used.
Table [commonMatDispersion] describes acceptable dispersion values for various types of materials.
Material | Abbe Number (V) | Dispersion (20/V)
--------------------------:|:------------------:|:-----------------
Rutile | 9.8 | 2.04
Polycarbonate | 32 | 0.625
Diamond | 55 | 0.36
Water | 55 | 0.36
Crown Glass | 59 | 0.33
[Table [commonMatDispersion]: Dispersion of common materials]
![Figure [dispersionProperty]: `dispersion` varying from 0.0
(left) to 5.0 (right)](images/materials/dispersion.png)
## Subsurface model
### Thickness
@@ -2276,6 +2299,7 @@ struct MaterialInputs {
float3 absorption; // default float3(0.0, 0.0, 0.0)
float ior; // default: 1.5
float microThickness; // default: 0.0, not available with refractionType "solid"
float dispersion; // default: 0.0, not available with refractionType "thin"
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -2456,9 +2480,9 @@ type aliases:
**uint2** | uvec2 | A vector of 2 unsigned integers
**uint3** | uvec3 | A vector of 3 unsigned integers
**uint4** | uvec4 | A vector of 4 unsigned integers
**float2** | float2 | A vector of 2 floats
**float3** | float3 | A vector of 3 floats
**float4** | float4 | A vector of 4 floats
**float2** | vec2 | A vector of 2 floats
**float3** | vec3 | A vector of 3 floats
**float4** | vec4 | A vector of 4 floats
**float4x4** | mat4 | A 4x4 float matrix
**float3x3** | mat3 | A 3x3 float matrix
+3 -3
View File
@@ -3,7 +3,7 @@
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Build for Android on Windows - Filament</title>
<title>Android on Windows - Filament</title>
<!-- Custom HTML head -->
@@ -273,7 +273,7 @@ copy filament-android\build\outputs\aar\filament-android-release.aar ..\..\out\
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../build/maven_release.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next prefetch" href="../dup/contributing.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
@@ -287,7 +287,7 @@ copy filament-android\build\outputs\aar\filament-android-release.aar ..\..\out\
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../build/maven_release.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next prefetch" href="../dup/contributing.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
+255
View File
@@ -0,0 +1,255 @@
<!DOCTYPE HTML>
<html lang="en" class="light sidebar-visible" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>backend - Filament</title>
<!-- Custom HTML head -->
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff">
<link rel="shortcut icon" href="../favicon.png">
<link rel="stylesheet" href="../css/variables.css">
<link rel="stylesheet" href="../css/general.css">
<link rel="stylesheet" href="../css/chrome.css">
<!-- Fonts -->
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="../fonts/fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" href="../highlight.css">
<link rel="stylesheet" href="../tomorrow-night.css">
<link rel="stylesheet" href="../ayu-highlight.css">
<!-- Custom theme stylesheets -->
<!-- MathJax -->
<script async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
<!-- Provide site root to javascript -->
<script>
var path_to_root = "../";
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "light" : "light";
</script>
<!-- Start loading toc.js asap -->
<script src="../toc.js"></script>
</head>
<body>
<div id="body-container">
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script>
try {
var theme = localStorage.getItem('mdbook-theme');
var sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script>
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
const html = document.documentElement;
html.classList.remove('light')
html.classList.add(theme);
html.classList.add("js");
</script>
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
var sidebar = null;
var sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
} else {
sidebar = 'hidden';
}
sidebar_toggle.checked = sidebar === 'visible';
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div style="display:flex;align-items:center;justify-content:center">
<img class="flogo" src="../images/filament_logo_small.png"></img>
</div>
<!-- populated by js -->
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
<noscript>
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
</noscript>
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
<div class="sidebar-resize-indicator"></div>
</div>
</nav>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky">
<div class="left-buttons">
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</label>
<!-- Filament: disable themes because the markdeep part does not look good for dark themes -->
<!--
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
-->
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title">Filament</h1>
<div class="right-buttons">
<a href="https://github.com/google/filament" title="Git repository" aria-label="Git repository">
<i id="git-repository-button" class="fa fa-github"></i>
</a>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script>
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<h1 id="backend-unit-tests"><a class="header" href="#backend-unit-tests">Backend Unit Tests</a></h1>
<p>These are tests that ensure the Filament backend is working properly on various operating systems
and graphics backends.</p>
<p>The majority of these tests generate images that are then compared against a known golden image.</p>
<h2 id="running-with-a-specific-graphics-library"><a class="header" href="#running-with-a-specific-graphics-library">Running with a specific graphics library</a></h2>
<p>Run with <code>-a&lt;backend&gt;</code> to run with a specific backend, such as <code>-avulkan</code> for vulkan or <code>-ametal</code>
for metal.</p>
<h2 id="image-comparisons"><a class="header" href="#image-comparisons">Image comparisons</a></h2>
<p>The expected images are stored as PNG files in the <code>expected_images</code> subdirectory of the test source
code. When cmake is run it will copy this directory to the build output creating
<code>images/expected_images</code> inside the same directory as the unit test binary.</p>
<p>The unit tests will then write their resulting images into <code>images/actual_images</code> in order to make
the tests easier to debug.</p>
<p>If an image comparison test fails, it writes a diff image to <code>images/diff_images</code> where each pixel of the diff is white (255,255,255) if the comparison for the corresponding pixel succeeds and black (0,0,0) of the comparison for the corresponding pixel fails.</p>
<h3 id="python-utility-for-updating-golden-images-and-comparing-results"><a class="header" href="#python-utility-for-updating-golden-images-and-comparing-results">Python utility for updating golden images and comparing results</a></h3>
<p>Inside the unit test source code directory there is a python script called
<code>move_actual_images_to_expected.py</code>.
It will display the actual and expected images side-by-side and copy the actual image into the
source tree's <code>expected_images</code> directory if the user approves the change.</p>
<h4 id="directories"><a class="header" href="#directories">Directories</a></h4>
<p>The <code>-r</code> flag is required and should be the directory where the test binary is.</p>
<p>If not running the script from the directory it's in, <code>-s</code> should be the source code's
<code>expected_images</code> directory.</p>
<h4 id="configuring-comparemove-behavior"><a class="header" href="#configuring-comparemove-behavior">Configuring compare/move behavior</a></h4>
<p>The <code>-c</code> flag has the tool display the actual and expected images side-by-side. By default it
does this by opening both with the OS's default behavior. <code>-p</code> can be used to specify a different
terminal program.</p>
<p>The <code>-m</code> flag has the tool move the actual image to overwrite the expected image in the source
tree. If the images are also being compared then the move will only happen if the user approves the
change.</p>
<p>After updating the expected images, cmake will need to be run again to copy them to the binary's
directory. Also, currently some platforms can't load images to compare and so have the hash
hardcoded into the test source code, so for now those need to be updated by running the test and
copying the value manually.</p>
<h4 id="picking-which-tests-to-compare"><a class="header" href="#picking-which-tests-to-compare">Picking which tests to compare</a></h4>
<p>The <code>-x</code> flag causes the tool to check the <code>test_detail.xml</code> file and only process the images who
failed a comparison. <code>--gtest_output=xml</code> needs to be passed to the test binary to generate this
file.</p>
<p>The <code>-t</code> argument takes a list of images to compare, provided as the file name without the <code>.png</code>
suffix.</p>
<h2 id="unsupported-tests"><a class="header" href="#unsupported-tests">Unsupported tests</a></h2>
<p>If a test depends on a feature that is unsupported by the current environment, it will start with
the <code>SKIP_IF</code> macro. This will cause the test to not be run.</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../notes/tests.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../dup/test_ci_backend.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../notes/tests.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../dup/test_ci_backend.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<script>
window.playground_copyable = true;
</script>
<script src="../elasticlunr.min.js"></script>
<script src="../mark.min.js"></script>
<script src="../searcher.js"></script>
<script src="../clipboard.min.js"></script>
<script src="../highlight.js"></script>
<script src="../book.js"></script>
<!-- Custom JS scripts -->
</div>
</body>
</html>
+2 -1
View File
@@ -158,7 +158,8 @@
<div id="content" class="content">
<main>
<h2 id="updating-vulkan-headers"><a class="header" href="#updating-vulkan-headers">Updating Vulkan headers</a></h2>
<h1 id="bluevk"><a class="header" href="#bluevk">bluevk</a></h1>
<h2 id="updating-vulkan-headers"><a class="header" href="#updating-vulkan-headers">Updating Vulkan headers</a></h2>
<p>To update the Vulkan headers, perform the following steps.</p>
<p>First, find the latest version of the Vulkan headers here:
https://github.com/KhronosGroup/Vulkan-Headers/tags</p>
+45 -16
View File
@@ -158,8 +158,8 @@
<div id="content" class="content">
<main>
<h2 id="building-filament"><a class="header" href="#building-filament">Building Filament</a></h2>
<h3 id="prerequisites"><a class="header" href="#prerequisites">Prerequisites</a></h3>
<h1 id="building-filament"><a class="header" href="#building-filament">Building Filament</a></h1>
<h2 id="prerequisites"><a class="header" href="#prerequisites">Prerequisites</a></h2>
<p>To build Filament, you must first install the following tools:</p>
<ul>
<li>CMake 3.22.1 (or more recent)</li>
@@ -175,14 +175,14 @@ section below.</p>
<li>Android NDK 25.1 or higher</li>
<li>Java 17</li>
</ul>
<h3 id="environment-variables"><a class="header" href="#environment-variables">Environment variables</a></h3>
<h2 id="environment-variables"><a class="header" href="#environment-variables">Environment variables</a></h2>
<p>To build Filament for Android, make sure the environment variable <code>ANDROID_HOME</code> points to the
location of your Android SDK.</p>
<p>When building for WebGL, you'll also need to set <code>EMSDK</code>. See <a href="#webassembly">WebAssembly</a>.</p>
<h3 id="ide"><a class="header" href="#ide">IDE</a></h3>
<p>We recommend using CLion to develop for Filament. Simply open the root directory's CMakeLists.txt
in CLion to obtain a usable project.</p>
<h3 id="easy-build"><a class="header" href="#easy-build">Easy build</a></h3>
<h2 id="easy-build"><a class="header" href="#easy-build">Easy build</a></h2>
<p>Once the required OS specific dependencies listed below are installed, you can use the script
located in <code>build.sh</code> to build Filament easily on macOS and Linux.</p>
<p>This script can be invoked from anywhere and will produce build artifacts in the <code>out/</code> directory
@@ -206,7 +206,7 @@ The script offers more features described by executing <code>build.sh -h</code>.
<li><code>-t</code>: <a href="https://google.github.io/filament/dup/fgviewer.html"><code>fgviewer</code></a></li>
<li><code>-b</code> and <code>-y</code>: <a href="https://google.github.io/filament/notes/asan_ubsan.html">ASAN/UBSAN builds</a></li>
</ul>
<h3 id="filament-specific-cmake-options"><a class="header" href="#filament-specific-cmake-options">Filament-specific CMake Options</a></h3>
<h2 id="filament-specific-cmake-options"><a class="header" href="#filament-specific-cmake-options">Filament-specific CMake Options</a></h2>
<p>The following CMake options are boolean options specific to Filament:</p>
<ul>
<li><code>FILAMENT_ENABLE_LTO</code>: Enable link-time optimizations if supported by the compiler</li>
@@ -223,7 +223,7 @@ The script offers more features described by executing <code>build.sh -h</code>.
cmake . -DOPTION=ON # Replace OPTION with the option name, set to ON / OFF
</code></pre>
<p>Options can also be set with the CMake GUI.</p>
<h3 id="linux"><a class="header" href="#linux">Linux</a></h3>
<h2 id="linux"><a class="header" href="#linux">Linux</a></h2>
<p>Make sure you've installed the following dependencies:</p>
<ul>
<li><code>clang-16</code> or higher</li>
@@ -265,7 +265,7 @@ update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++ 100
<pre><code class="language-shell">ninja
</code></pre>
<p>This will build Filament, its tests and samples, and various host tools.</p>
<h3 id="macos"><a class="header" href="#macos">macOS</a></h3>
<h2 id="macos"><a class="header" href="#macos">macOS</a></h2>
<p>To compile Filament you must have the most recent version of Xcode installed and you need to
make sure the command line tools are setup by running:</p>
<pre><code class="language-shell">xcode-select --install
@@ -278,14 +278,14 @@ cd out/cmake-release
cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../release/filament ../..
ninja
</code></pre>
<h3 id="ios"><a class="header" href="#ios">iOS</a></h3>
<h2 id="ios"><a class="header" href="#ios">iOS</a></h2>
<p>The easiest way to build Filament for iOS is to use <code>build.sh</code> and the
<code>-p ios</code> flag. For instance to build the debug target:</p>
<pre><code class="language-shell">./build.sh -p ios debug
</code></pre>
<p>See <a href="./ios/samples/README.html">ios/samples/README.md</a> for more information.</p>
<h3 id="windows"><a class="header" href="#windows">Windows</a></h3>
<h4 id="building-on-windows-with-visual-studio-2019-or-later"><a class="header" href="#building-on-windows-with-visual-studio-2019-or-later">Building on Windows with Visual Studio 2019 or later</a></h4>
<h2 id="windows"><a class="header" href="#windows">Windows</a></h2>
<h3 id="building-on-windows-with-visual-studio-2019-or-later"><a class="header" href="#building-on-windows-with-visual-studio-2019-or-later">Building on Windows with Visual Studio 2019 or later</a></h3>
<p>Install the following components:</p>
<ul>
<li><a href="https://www.visualstudio.com/downloads">Visual Studio 2019 or later</a></li>
@@ -314,7 +314,7 @@ target in the <em>Solution Explorer</em> and choose <em>Build</em> to build a sp
<code>out</code> folder run the following command.</p>
<pre><code class="language-bat">cmake --build . --target gltf_viewer --config Release
</code></pre>
<h3 id="android"><a class="header" href="#android">Android</a></h3>
<h2 id="android"><a class="header" href="#android">Android</a></h2>
<p>Before building Filament for Android, make sure to build Filament for your host. Some of the
host tools are required to successfully build for Android.</p>
<p>Filament can be built for the following architectures:</p>
@@ -327,13 +327,42 @@ host tools are required to successfully build for Android.</p>
<p>Note that the main target is the ARM 64-bit target. Our implementation is optimized first and
foremost for <code>arm64-v8a</code>.</p>
<p>To build Android on Windows machines, see <a href="android/Windows.html">android/Windows.md</a>.</p>
<h4 id="easy-android-build"><a class="header" href="#easy-android-build">Easy Android build</a></h4>
<h3 id="important-sdk-location"><a class="header" href="#important-sdk-location">Important: SDK location</a></h3>
<p>Either ensure your <code>ANDROID_HOME</code> environment variable is set or make sure the root project
contains a <code>local.properties</code> file with the <code>sdk.dir</code> property pointing to your installation of
the Android SDK.</p>
<h3 id="easy-android-build"><a class="header" href="#easy-android-build">Easy Android build</a></h3>
<p>The easiest way to build Filament for Android is to use <code>build.sh</code> and the
<code>-p android</code> flag. For instance to build the release target:</p>
<pre><code class="language-shell">./build.sh -p android release
</code></pre>
<p>To build a sample (such as <code>android/samples/sample-hello-triangle</code>) for an ARM 64-bit phone, you would run</p>
<pre><code class="language-shell">./build.sh -p android -q arm64-v8a -k sample-hello-triangle release
</code></pre>
<p>The output APK can be found in <code>android/samples/sample-hello-triangle/build/outputs/apk/release/sample-hello-triangle-release-unsigned.apk</code></p>
<p>Run <code>build.sh -h</code> for more information.</p>
<h4 id="manual-builds"><a class="header" href="#manual-builds">Manual builds</a></h4>
<h3 id="android-studio"><a class="header" href="#android-studio">Android Studio</a></h3>
<p>You must use the latest stable release of Android Studio.</p>
<p>The Android build of filament is separated into java/kotlin client APIs, a layer of jni bindings
that bridges java/kotlin with native code, and Filament and other component code that have been compiled
into architecture-specific libraries. Our default Android Studio gradle setup can compile java/kotlin and
the jni bindings for you, but it will treat the filament libraries as already compiled and present on
the system.</p>
<p>Therefore, before compiling the sample app or any other targets, you must
make sure that the native filament libraries have been compiled and are located at a prescribed location
so that the jni bindings can link against them. You can do so by using the easy build script</p>
<pre><code class="language-shell">./build.sh -p android release -q arm64-v8a
</code></pre>
<p>Note that the above step will also install host machine tools into prescribed locations. These tools are
required for compiling Filament assets such as materials and environment maps.</p>
<p>Now we are ready to compile the apps. To open the project, point Studio to the <code>android</code> folder.
After opening the project and syncing with Gradle, select the sample of your choice
using the drop-down widget in the toolbar. Additionally, you will need to select a deployment target.
By doing so, Android Studio will automatically try to compile the app only for that specific
device's architecture. So if you are targeting a new Pixel phone, make sure that the step above
(compiling the library) is targeting ARM 64-bit (<code>-q arm64-v8a</code> ), and if you are running the app on
an emulator on a Linux machine with an x86 64-bit chipset, you would indicate (<code>-q x86_64</code>) in the above step.</p>
<h3 id="manual-builds"><a class="header" href="#manual-builds">Manual builds</a></h3>
<p>Invoke CMake in a build directory of your choice, inside of filament's directory. The commands
below show how to build Filament for ARM 64-bit (<code>aarch64</code>).</p>
<pre><code class="language-shell">mkdir out/android-build-release-aarch64
@@ -350,7 +379,7 @@ cmake -G Ninja -DCMAKE_TOOLCHAIN_FILE=../../build/toolchain-aarch64-linux-androi
<p>This will generate Filament's Android binaries in <code>out/android-release</code>. This location is important
to build the Android Studio projects located in <code>filament/android</code>. After install, the library
binaries should be found in <code>out/android-release/filament/lib/arm64-v8a</code>.</p>
<h4 id="aar"><a class="header" href="#aar">AAR</a></h4>
<h3 id="aar"><a class="header" href="#aar">AAR</a></h3>
<p>Before you attempt to build the AAR, make sure you've compiled and installed the native libraries
as explained in the sections above. You must have the following ABIs built in
<code>out/android-release/filament/lib/</code>:</p>
@@ -376,7 +405,7 @@ AAR.</p>
</code></pre>
<p>The <code>-Pcom.google.android.filament.dist-dir</code> can be used to specify a different installation
directory (it must match the CMake install prefix used in the previous steps).</p>
<h4 id="using-filaments-aar"><a class="header" href="#using-filaments-aar">Using Filament's AAR</a></h4>
<h3 id="using-filaments-aar"><a class="header" href="#using-filaments-aar">Using Filament's AAR</a></h3>
<p>Create a new module in your project and select <em>Import .JAR or .AAR Package</em> when prompted. Make
sure to add the newly created module as a dependency to your application.</p>
<p>If you do not wish to include all supported ABIs, make sure to create the appropriate flavors in
@@ -412,7 +441,7 @@ productFlavors {
}
}
</code></pre>
<h3 id="webassembly"><a class="header" href="#webassembly">WebAssembly</a></h3>
<h2 id="webassembly"><a class="header" href="#webassembly">WebAssembly</a></h2>
<p>The core Filament library can be cross-compiled to WebAssembly from either macOS or Linux. To get
started, follow the instructions for building Filament on your platform (<a href="#macos">macOS</a> or
<a href="#linux">linux</a>), which will ensure you have the proper dependencies installed.</p>
+2 -2
View File
@@ -209,7 +209,7 @@ as possible. The current external dependencies of the runtime library include:</
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../build/maven_release.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../build/windows_android.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
@@ -223,7 +223,7 @@ as possible. The current external dependencies of the runtime library include:</
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../build/maven_release.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../build/windows_android.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
+3 -3
View File
@@ -203,7 +203,7 @@ tree into <code>docs_src/src_mdbook/src/dup</code>. Moreover, to restore valid l
to perform a number of URL replacements in addition to the copy. These replacements are
described in <a href="https://github.com/google/filament/blob/main/docs_src/build/duplicates.json"><code>docs_src/build/duplicates.json</code></a>.</p>
<h3 id="core-concept-docs"><a class="header" href="#core-concept-docs">Core concept docs</a></h3>
<p>The primary design of Filament as a phyiscally-based renderer and details of its materials
<p>The primary design of Filament as a physically-based renderer and details of its materials
system are described in <code>Filament.md.html</code> and <code>Materials.md.html</code>, respectively. These two
documents are written in <a href="https://casual-effects.com/markdeep/"><code>markdeep</code></a>. To embed them into our book, we</p>
<ol>
@@ -253,7 +253,7 @@ add a link in <code>SUMMARY.md</code>, and perform the steps outlined in
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../notes/release_guide.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../release/branching.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
@@ -267,7 +267,7 @@ add a link in <code>SUMMARY.md</code>, and perform the steps outlined in
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../notes/release_guide.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../release/branching.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
+3 -3
View File
@@ -158,7 +158,7 @@
<div id="content" class="content">
<main>
<h1 id="filamesh"><a class="header" href="#filamesh">Filamesh</a></h1>
<h1 id="filamesh"><a class="header" href="#filamesh">filamesh</a></h1>
<p><code>filamesh</code> converts any mesh file supported by <code>assimp</code> (as configured in this source tree) into a
custom binary file format. The goal of this binary file format is to allow test applications to
easily and quickly load meshes.</p>
@@ -419,7 +419,7 @@ Mesh loadMeshFromFile(filament::Engine* engine, const utils::Path&amp; path,
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../dup/normal_blending.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next prefetch" href="../dup/matinfo.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
@@ -433,7 +433,7 @@ Mesh loadMeshFromFile(filament::Engine* engine, const utils::Path&amp; path,
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../dup/normal_blending.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next prefetch" href="../dup/matinfo.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
+1 -1
View File
@@ -158,7 +158,7 @@
<div id="content" class="content">
<main>
<h1 id="description"><a class="header" href="#description">Description</a></h1>
<h1 id="gltfio"><a class="header" href="#gltfio">gltfio</a></h1>
<p><code>gltfio</code> is a loader library that consumes <code>gltf</code> or <code>glb</code> content and produces Filament
objects. For usage details, see the docstring for <code>AssetLoader</code>.</p>
<p>gltfio has two plug-in interfaces, <code>TextureProvider</code> and <code>MaterialProvider</code>. Filament ships with
+2 -2
View File
@@ -181,7 +181,7 @@ important for <code>matc</code> (material compiler).</p>
}
dependencies {
implementation 'com.google.android.filament:filament-android:1.68.0'
implementation 'com.google.android.filament:filament-android:1.68.5'
}
</code></pre>
<p>Here are all the libraries available in the group <code>com.google.android.filament</code>:</p>
@@ -196,7 +196,7 @@ dependencies {
</div>
<h3 id="ios"><a class="header" href="#ios">iOS</a></h3>
<p>iOS projects can use CocoaPods to install the latest release:</p>
<pre><code class="language-shell">pod 'Filament', '~&gt; 1.68.0'
<pre><code class="language-shell">pod 'Filament', '~&gt; 1.68.5'
</code></pre>
<h2 id="documentation"><a class="header" href="#documentation">Documentation</a></h2>
<ul>
+5 -5
View File
@@ -158,7 +158,7 @@
<div id="content" class="content">
<main>
<h1 id="matinfo"><a class="header" href="#matinfo">Matinfo</a></h1>
<h1 id="matinfo"><a class="header" href="#matinfo">matinfo</a></h1>
<p><code>matinfo</code> lists the content of a compiled material as output by <code>matc</code>. This tool is meant to be
used for debug purpose only.</p>
<h2 id="usage"><a class="header" href="#usage">Usage</a></h2>
@@ -169,11 +169,11 @@ used for debug purpose only.</p>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../dup/mipgen.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../dup/filamesh.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../dup/roughness_prefilter.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next prefetch" href="../dup/mipgen.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
@@ -183,11 +183,11 @@ used for debug purpose only.</p>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../dup/mipgen.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../dup/filamesh.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../dup/roughness_prefilter.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next prefetch" href="../dup/mipgen.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
+4 -4
View File
@@ -169,11 +169,11 @@
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../dup/normal_blending.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../dup/matinfo.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../dup/matinfo.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next prefetch" href="../dup/normal_blending.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
@@ -183,11 +183,11 @@
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../dup/normal_blending.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../dup/matinfo.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../dup/matinfo.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next prefetch" href="../dup/normal_blending.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
+4 -4
View File
@@ -167,11 +167,11 @@ correct results (as opposed to common techniques such as linear or overlay blend
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../dup/filamesh.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../dup/mipgen.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../dup/mipgen.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next prefetch" href="../dup/roughness_prefilter.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
@@ -181,11 +181,11 @@ correct results (as opposed to common techniques such as linear or overlay blend
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../dup/filamesh.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../dup/mipgen.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../dup/mipgen.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next prefetch" href="../dup/roughness_prefilter.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
+4 -4
View File
@@ -167,11 +167,11 @@ be used to reduce shading aliasing.</p>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../dup/matinfo.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../dup/normal_blending.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../dup/specular_color.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next prefetch" href="../dup/specgen.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
@@ -181,11 +181,11 @@ be used to reduce shading aliasing.</p>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../dup/matinfo.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../dup/normal_blending.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../dup/specular_color.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next prefetch" href="../dup/specgen.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
+265
View File
@@ -0,0 +1,265 @@
<!DOCTYPE HTML>
<html lang="en" class="light sidebar-visible" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>specgen - Filament</title>
<!-- Custom HTML head -->
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff">
<link rel="shortcut icon" href="../favicon.png">
<link rel="stylesheet" href="../css/variables.css">
<link rel="stylesheet" href="../css/general.css">
<link rel="stylesheet" href="../css/chrome.css">
<!-- Fonts -->
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="../fonts/fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" href="../highlight.css">
<link rel="stylesheet" href="../tomorrow-night.css">
<link rel="stylesheet" href="../ayu-highlight.css">
<!-- Custom theme stylesheets -->
<!-- MathJax -->
<script async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
<!-- Provide site root to javascript -->
<script>
var path_to_root = "../";
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "light" : "light";
</script>
<!-- Start loading toc.js asap -->
<script src="../toc.js"></script>
</head>
<body>
<div id="body-container">
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script>
try {
var theme = localStorage.getItem('mdbook-theme');
var sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script>
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
const html = document.documentElement;
html.classList.remove('light')
html.classList.add(theme);
html.classList.add("js");
</script>
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
var sidebar = null;
var sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
} else {
sidebar = 'hidden';
}
sidebar_toggle.checked = sidebar === 'visible';
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div style="display:flex;align-items:center;justify-content:center">
<img class="flogo" src="../images/filament_logo_small.png"></img>
</div>
<!-- populated by js -->
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
<noscript>
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
</noscript>
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
<div class="sidebar-resize-indicator"></div>
</div>
</nav>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky">
<div class="left-buttons">
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</label>
<!-- Filament: disable themes because the markdeep part does not look good for dark themes -->
<!--
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
-->
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title">Filament</h1>
<div class="right-buttons">
<a href="https://github.com/google/filament" title="Git repository" aria-label="Git repository">
<i id="git-repository-button" class="fa fa-github"></i>
</a>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script>
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<h1 id="specgen-spectral-integration-matrix-generator-for-real-time-dispersion"><a class="header" href="#specgen-spectral-integration-matrix-generator-for-real-time-dispersion">SPECGEN: Spectral Integration Matrix Generator for Real-Time Dispersion</a></h1>
<h2 id="theoretical-background"><a class="header" href="#theoretical-background">Theoretical Background</a></h2>
<h3 id="1-spectral-rendering-in-rgb"><a class="header" href="#1-spectral-rendering-in-rgb">1. Spectral Rendering in RGB</a></h3>
<p>Real-time rendering typically operates in a tristimulus color space (like sRGB). However, physical phenomena like dispersion (refraction splitting light by wavelength) are inherently spectral. To simulate this in an RGB pipeline, we approximate the continuous spectral integration using a finite sum of weighted samples.</p>
<p>The fundamental equation for perceived color \(C\) is:</p>
<p>$$ C = \int L(\lambda) \cdot r(\lambda) d\lambda $$</p>
<p>where:</p>
<ul>
<li>\(L(\lambda)\) is the spectral radiance reaching the eye.</li>
<li>\(r(\lambda)\) is the sensor response function (e.g., CIE 1931 \(\bar{x}, \bar{y}, \bar{z}\) matching functions).</li>
</ul>
<h3 id="2-basis-transformation-strategy"><a class="header" href="#2-basis-transformation-strategy">2. Basis Transformation Strategy</a></h3>
<p>We assume the input light is defined in linear sRGB. To process it spectrally:</p>
<ol>
<li>Convert sRGB to CIE XYZ (D65 white point).</li>
<li>Assume the spectral distribution of the light is a sum of impulses or narrow bands weighted by the XYZ components (or simplified directly from sRGB).</li>
<li>Apply spectral effects (like wavelength-dependent refraction).</li>
<li>Integrate back to XYZ using the CIE Color Matching Functions (CMFs).</li>
<li>Convert final XYZ back to sRGB.</li>
</ol>
<p>This tool pre-calculates a set of matrices (\(K_n\)) that combine these steps. For a set of \(N\) sample wavelengths \({ \lambda_0, \dots, \lambda_{N-1} }\), the final color is:</p>
<p>$$ C_{final} = \sum_{n=0}^{N-1} (K_n \cdot C_{input}) $$</p>
<p>Each matrix \(K_n\) represents the contribution of the \(n\)-th spectral sample to the final image, accounting for the conversion to/from XYZ and the spectral weight of that sample.</p>
<p><strong>Derivation of \(K_n\):</strong></p>
<p>$$ K_n = M_{XYZ \to sRGB} \cdot \text{Diag}(W_n) \cdot M_{sRGB \to XYZ} $$</p>
<p>where \(W_n\) is the "spectral weight" vector \((x, y, z)\) for wavelength \(\lambda_n\):</p>
<p>$$ W_n = \text{CMF}(\lambda_n) \cdot \text{weight}_n $$</p>
<h3 id="3-normalization-energy-conservation"><a class="header" href="#3-normalization-energy-conservation">3. Normalization (Energy Conservation)</a></h3>
<p>To ensure that a white input \((1, 1, 1)\) results in a white output \((1, 1, 1)\) when no dispersion occurs (i.e., all samples land on the same pixel), we must normalize the weights.</p>
<p>We require: \(\sum K_n = I\)</p>
<p>This implies:</p>
<p>$$ \sum ( M_{XYZ \to sRGB} \cdot \text{Diag}(W_n) \cdot M_{sRGB \to XYZ} ) = I $$
$$ M_{XYZ \to sRGB} \cdot \sum \text{Diag}(W_n) \cdot M_{sRGB \to XYZ} = I $$
$$ \sum \text{Diag}(W_n) = M_{sRGB \to XYZ} \cdot I \cdot M_{XYZ \to sRGB} $$
$$ \sum \text{Diag}(W_n) = I $$
<em>(since \(M \cdot M^{-1} = I\))</em></p>
<p>Therefore, we normalize \(W_n\) such that:</p>
<p>$$ \sum W_{n,x} = 1.0, \quad \sum W_{n,y} = 1.0, \quad \sum W_{n,z} = 1.0 $$</p>
<p><strong>Note:</strong> We do <strong>NOT</strong> normalize to the D65 white point \((0.95047, 1.0, 1.08883)\). The \(M_{sRGB \to XYZ}\) matrix already handles the conversion from linear sRGB \((1, 1, 1)\) to D65 XYZ. If we normalized \(W_n\) to D65, we would effectively be applying the white point twice, resulting in a tinted image. By normalizing \(\sum W_n\) to \((1, 1, 1)\), we ensure that the energy is conserved through the spectral transformation pipeline.</p>
<p>In practice, we calculate the raw sum of \(W_n\) from the quadrature weights and CMFs, then compute a correction factor:</p>
<p>$$ \text{Correction} = \frac{1.0}{\sum W_{n,raw}} $$
$$ W_{n,final} = W_{n,raw} \cdot \text{Correction} $$</p>
<h3 id="4-dispersion-and-ior-offsets"><a class="header" href="#4-dispersion-and-ior-offsets">4. Dispersion and IOR Offsets</a></h3>
<p>The Index of Refraction (IOR) varies with wavelength. We use the Abbe number (\(V_d\)) to parameterize this variation relative to a base IOR (\(n_D\)) at 589.3nm.</p>
<p><strong>Cauchy Dispersion Model:</strong></p>
<p>$$ n(\lambda) = A + \frac{B}{\lambda^2} $$</p>
<p>Using the definition of Abbe number \(V_d = \frac{n_D - 1}{n_F - n_C}\), we can derive:</p>
<p>$$ n(\lambda) = n_D + \frac{n_D - 1}{V_d} \cdot \text{Offset}(\lambda) $$</p>
<p>Where \(\text{Offset}(\lambda)\) is pre-calculated by this tool:</p>
<p>$$ \text{Offset}(\lambda) = \frac{ \frac{1}{\lambda^2} - \frac{1}{\lambda_D^2} }{ \frac{1}{\lambda_F^2} - \frac{1}{\lambda_C^2} } $$</p>
<p>This allows the shader to compute the specific IOR for each sample efficiently:</p>
<pre><code class="language-glsl">float ior_n = baseIOR + dispersionFactor * offsets[n];
</code></pre>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../dup/roughness_prefilter.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../dup/specular_color.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../dup/roughness_prefilter.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../dup/specular_color.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<script>
window.playground_copyable = true;
</script>
<script src="../elasticlunr.min.js"></script>
<script src="../mark.min.js"></script>
<script src="../searcher.js"></script>
<script src="../clipboard.min.js"></script>
<script src="../highlight.js"></script>
<script src="../book.js"></script>
<!-- Custom JS scripts -->
</div>
</body>
</html>
+2 -2
View File
@@ -182,7 +182,7 @@ grazing angles. See Hoffman 2019, "Fresnel Equations Considered Harmful".</p>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../dup/roughness_prefilter.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../dup/specgen.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
@@ -196,7 +196,7 @@ grazing angles. See Hoffman 2019, "Fresnel Equations Considered Harmful".</p>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../dup/roughness_prefilter.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../dup/specgen.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
+230
View File
@@ -0,0 +1,230 @@
<!DOCTYPE HTML>
<html lang="en" class="light sidebar-visible" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>CI: backend - Filament</title>
<!-- Custom HTML head -->
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff">
<link rel="shortcut icon" href="../favicon.png">
<link rel="stylesheet" href="../css/variables.css">
<link rel="stylesheet" href="../css/general.css">
<link rel="stylesheet" href="../css/chrome.css">
<!-- Fonts -->
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="../fonts/fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" href="../highlight.css">
<link rel="stylesheet" href="../tomorrow-night.css">
<link rel="stylesheet" href="../ayu-highlight.css">
<!-- Custom theme stylesheets -->
<!-- MathJax -->
<script async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
<!-- Provide site root to javascript -->
<script>
var path_to_root = "../";
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "light" : "light";
</script>
<!-- Start loading toc.js asap -->
<script src="../toc.js"></script>
</head>
<body>
<div id="body-container">
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script>
try {
var theme = localStorage.getItem('mdbook-theme');
var sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script>
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
const html = document.documentElement;
html.classList.remove('light')
html.classList.add(theme);
html.classList.add("js");
</script>
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
var sidebar = null;
var sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
} else {
sidebar = 'hidden';
}
sidebar_toggle.checked = sidebar === 'visible';
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div style="display:flex;align-items:center;justify-content:center">
<img class="flogo" src="../images/filament_logo_small.png"></img>
</div>
<!-- populated by js -->
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
<noscript>
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
</noscript>
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
<div class="sidebar-resize-indicator"></div>
</div>
</nav>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky">
<div class="left-buttons">
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</label>
<!-- Filament: disable themes because the markdeep part does not look good for dark themes -->
<!--
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
-->
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title">Filament</h1>
<div class="right-buttons">
<a href="https://github.com/google/filament" title="Git repository" aria-label="Git repository">
<i id="git-repository-button" class="fa fa-github"></i>
</a>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script>
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<h1 id="backend-tests"><a class="header" href="#backend-tests">Backend Tests</a></h1>
<p>This directory (<code>/test/backend</code>) contains scripts to run Filament's backend tests using a software
rasterizer (Mesa). This is useful for running tests in a continuous integration environment where a
GPU might not be available.</p>
<p>The <code>test.sh</code> script will:</p>
<ol>
<li>Build Mesa if needed.</li>
<li>Build the backend tests.</li>
<li>Run the tests using the OpenGL and Vulkan backends with Mesa.</li>
</ol>
<h2 id="flags"><a class="header" href="#flags">Flags</a></h2>
<p>The <code>test.sh</code> script accepts the following flags:</p>
<ul>
<li><code>--gtest_filter</code>: Filters the tests that are run. This is passed directly to the underlying
gtest executable.</li>
<li><code>--backend</code>: Specifies which backend to test. Can be <code>opengl</code>, <code>vulkan</code>, or a comma-separated
list (e.g., <code>opengl,vulkan</code>). Defaults to both.</li>
</ul>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../dup/backend_test.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../dup/test_ci_renderdiff.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../dup/backend_test.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../dup/test_ci_renderdiff.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<script>
window.playground_copyable = true;
</script>
<script src="../elasticlunr.min.js"></script>
<script src="../mark.min.js"></script>
<script src="../searcher.js"></script>
<script src="../clipboard.min.js"></script>
<script src="../highlight.js"></script>
<script src="../book.js"></script>
<!-- Custom JS scripts -->
</div>
</body>
</html>
@@ -3,7 +3,7 @@
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>renderdiff - Filament</title>
<title>CI: renderdiff - Filament</title>
<!-- Custom HTML head -->
@@ -159,7 +159,8 @@
<div id="content" class="content">
<main>
<h1 id="rendering-difference-test"><a class="header" href="#rendering-difference-test">Rendering Difference Test</a></h1>
<p>This tool is a collections of scripts to run <code>gltf_viewer</code> and produce headless renderings.</p>
<p>This tool (<code>/test/renderdiff</code>) is a collections of scripts to run <code>gltf_viewer</code> and produce headless
renderings.</p>
<p>This is mainly useful for continuous integration where GPUs are generally not available on cloud
machines. To perform software rasterization, these scripts are centered around <a href="https://docs.mesa3d.org">Mesa</a>'s
software rasterizers, but nothing bars us from using another rasterizer like <a href="https://github.com/google/swiftshader">SwiftShader</a>.
@@ -251,7 +252,7 @@ git switch -c my-pr-branch-golden
</code></pre>
</li>
<li>In the commit message of your working branch on <code>filament</code>, add the following line
<pre><code>RDIFF_BBRANCH=my-pr-branch-golden
<pre><code>RDIFF_BRANCH=my-pr-branch-golden
</code></pre>
</li>
</ul>
@@ -292,7 +293,7 @@ the run number is <code>18023632663</code>.</p>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../notes/tests.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../dup/test_ci_backend.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
@@ -306,7 +307,7 @@ the run number is <code>18023632663</code>.</p>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../notes/tests.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../dup/test_ci_backend.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
+1 -5
View File
@@ -158,11 +158,7 @@
<div id="content" class="content">
<main>
<ul>
<li><a href="#ubershader-archive-files">Ubershader Archive Files</a></li>
<li><a href="#ubershader-spec-files">Ubershader Spec Files</a></li>
</ul>
<h1 id="ubershader-archive-files"><a class="header" href="#ubershader-archive-files">Ubershader Archive Files</a></h1>
<h1 id="uberz"><a class="header" href="#uberz">uberz</a></h1>
<p>An ubershader archive provides a way to bundle up a set of <code>filamat</code> files along with some metadata
that conveys which glTF features each material can handle. It is a file that has been compressed
with <code>zstd</code> and has an <code>.uberz</code> file extension. In uncompressed form, it has the following layout
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 MiB

+2732 -2773
View File
File diff suppressed because one or more lines are too long
+1903 -1902
View File
File diff suppressed because one or more lines are too long
+2 -2
View File
@@ -165,7 +165,7 @@
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../dup/renderdiff.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../dup/test_ci_renderdiff.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
@@ -179,7 +179,7 @@
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../dup/renderdiff.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../dup/test_ci_renderdiff.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
+2 -2
View File
@@ -668,7 +668,7 @@ Values can be <strong>negative</strong> to change the orientation of the specula
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../notes/versioning.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next prefetch" href="../release/index.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
@@ -682,7 +682,7 @@ Values can be <strong>negative</strong> to change the orientation of the specula
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../notes/versioning.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next prefetch" href="../release/index.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
+2 -2
View File
@@ -170,7 +170,7 @@ for in our Continuation Integration flow <a href="https://https://github.com/goo
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../dup/renderdiff.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next prefetch" href="../dup/backend_test.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
@@ -184,7 +184,7 @@ for in our Continuation Integration flow <a href="https://https://github.com/goo
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../dup/renderdiff.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next prefetch" href="../dup/backend_test.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
@@ -185,11 +185,11 @@ the <em>correct</em> fix in both the next release candidate branch <em>and</em>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../notes/versioning.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../release/versioning.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../notes/release_guide.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next prefetch" href="../dup/docs.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
@@ -199,11 +199,11 @@ the <em>correct</em> fix in both the next release candidate branch <em>and</em>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../notes/versioning.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../release/versioning.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../notes/release_guide.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next prefetch" href="../dup/docs.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
+249
View File
@@ -0,0 +1,249 @@
<!DOCTYPE HTML>
<html lang="en" class="light sidebar-visible" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>CocoaPods - Filament</title>
<!-- Custom HTML head -->
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff">
<link rel="shortcut icon" href="../favicon.png">
<link rel="stylesheet" href="../css/variables.css">
<link rel="stylesheet" href="../css/general.css">
<link rel="stylesheet" href="../css/chrome.css">
<!-- Fonts -->
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="../fonts/fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" href="../highlight.css">
<link rel="stylesheet" href="../tomorrow-night.css">
<link rel="stylesheet" href="../ayu-highlight.css">
<!-- Custom theme stylesheets -->
<!-- MathJax -->
<script async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
<!-- Provide site root to javascript -->
<script>
var path_to_root = "../";
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "light" : "light";
</script>
<!-- Start loading toc.js asap -->
<script src="../toc.js"></script>
</head>
<body>
<div id="body-container">
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script>
try {
var theme = localStorage.getItem('mdbook-theme');
var sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script>
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
const html = document.documentElement;
html.classList.remove('light')
html.classList.add(theme);
html.classList.add("js");
</script>
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
var sidebar = null;
var sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
} else {
sidebar = 'hidden';
}
sidebar_toggle.checked = sidebar === 'visible';
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div style="display:flex;align-items:center;justify-content:center">
<img class="flogo" src="../images/filament_logo_small.png"></img>
</div>
<!-- populated by js -->
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
<noscript>
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
</noscript>
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
<div class="sidebar-resize-indicator"></div>
</div>
</nav>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky">
<div class="left-buttons">
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</label>
<!-- Filament: disable themes because the markdeep part does not look good for dark themes -->
<!--
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
-->
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title">Filament</h1>
<div class="right-buttons">
<a href="https://github.com/google/filament" title="Git repository" aria-label="Git repository">
<i id="git-repository-button" class="fa fa-github"></i>
</a>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script>
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<h1 id="filament-cocoapods"><a class="header" href="#filament-cocoapods">Filament CocoaPods</a></h1>
<p><a href="https://cocoapods.org/">CocoaPods</a> is the dependency manager Filament uses for Apple platforms
(macOS and iOS).</p>
<h2 id="installation"><a class="header" href="#installation">Installation</a></h2>
<p>On macOS, CocoaPods requires a modern Ruby environment. Avoid using the system Ruby; instead,
install the latest Ruby version using <code>brew</code>, <code>port,</code> or use a manager like <code>rbenv</code> or <code>rvm</code>. Once
Ruby is configured:</p>
<pre><code class="language-bash">gem install cocoapods
</code></pre>
<h2 id="linting-the-podspec"><a class="header" href="#linting-the-podspec">Linting the Podspec</a></h2>
<p>The Filament podspec is configured to fetch releases directly from GitHub. Before deployment,
CocoaPods must <strong>lint</strong> the spec to validate that the library compiles and links correctly across
all supported architectures.</p>
<p>To run the linter locally:</p>
<pre><code class="language-bash">cd ios/CocoaPods/
pod spec lint
</code></pre>
<h3 id="debugging-failures"><a class="header" href="#debugging-failures">Debugging Failures</a></h3>
<p>If the lint fails, use the <code>--verbose</code> flag to inspect the underlying <code>xcodebuild</code> output:</p>
<pre><code class="language-bash">pod spec lint --verbose
</code></pre>
<h2 id="isolating-subspecs"><a class="header" href="#isolating-subspecs">Isolating Subspecs</a></h2>
<p>Filament is partitioned into multiple <strong>subspecs</strong>. CocoaPods lints these individually. To
accelerate debugging or isolate a specific build failure (e.g., <code>Filament/filament</code>), use the
following command:</p>
<pre><code class="language-bash">pod spec lint --no-clean --verbose --subspec=Filament/filament 2&gt;&amp;1 | tee lint_output.log
</code></pre>
<ul>
<li><code>--no-clean</code>: Preserves the temporary Xcode workspace and build artifacts in <code>/var/folders/...</code>
for inspection.</li>
<li><code>--verbose</code>: Prints the full compiler and linker invocations.</li>
<li><code>--subspec</code>: Limits the scope of the lint to a specific component.</li>
</ul>
<blockquote>
<p><strong>Tip:</strong> To view all defined subspecs, grep the podspec file:
<code>grep "spec.subspec" ios/CocoaPods/Filament.podspec</code></p>
</blockquote>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../release/index.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../release/maven.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../release/index.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../release/maven.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<script>
window.playground_copyable = true;
</script>
<script src="../elasticlunr.min.js"></script>
<script src="../mark.min.js"></script>
<script src="../searcher.js"></script>
<script src="../clipboard.min.js"></script>
<script src="../highlight.js"></script>
<script src="../book.js"></script>
<!-- Custom JS scripts -->
</div>
</body>
</html>
@@ -3,7 +3,7 @@
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Release Guide - Filament</title>
<title>Github - Filament</title>
<!-- Custom HTML head -->
@@ -250,11 +250,11 @@ release (for example, v1.42.2).</p>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../notes/branching.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../release/maven.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../dup/docs.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next prefetch" href="../release/versioning.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
@@ -264,11 +264,11 @@ release (for example, v1.42.2).</p>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../notes/branching.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../release/maven.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../dup/docs.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next prefetch" href="../release/versioning.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
+215
View File
@@ -0,0 +1,215 @@
<!DOCTYPE HTML>
<html lang="en" class="light sidebar-visible" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Release - Filament</title>
<!-- Custom HTML head -->
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff">
<link rel="shortcut icon" href="../favicon.png">
<link rel="stylesheet" href="../css/variables.css">
<link rel="stylesheet" href="../css/general.css">
<link rel="stylesheet" href="../css/chrome.css">
<!-- Fonts -->
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="../fonts/fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" href="../highlight.css">
<link rel="stylesheet" href="../tomorrow-night.css">
<link rel="stylesheet" href="../ayu-highlight.css">
<!-- Custom theme stylesheets -->
<!-- MathJax -->
<script async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
<!-- Provide site root to javascript -->
<script>
var path_to_root = "../";
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "light" : "light";
</script>
<!-- Start loading toc.js asap -->
<script src="../toc.js"></script>
</head>
<body>
<div id="body-container">
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script>
try {
var theme = localStorage.getItem('mdbook-theme');
var sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script>
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
const html = document.documentElement;
html.classList.remove('light')
html.classList.add(theme);
html.classList.add("js");
</script>
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
var sidebar = null;
var sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
} else {
sidebar = 'hidden';
}
sidebar_toggle.checked = sidebar === 'visible';
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div style="display:flex;align-items:center;justify-content:center">
<img class="flogo" src="../images/filament_logo_small.png"></img>
</div>
<!-- populated by js -->
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
<noscript>
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
</noscript>
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
<div class="sidebar-resize-indicator"></div>
</div>
</nav>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky">
<div class="left-buttons">
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</label>
<!-- Filament: disable themes because the markdeep part does not look good for dark themes -->
<!--
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
-->
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title">Filament</h1>
<div class="right-buttons">
<a href="https://github.com/google/filament" title="Git repository" aria-label="Git repository">
<i id="git-repository-button" class="fa fa-github"></i>
</a>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script>
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<h1 id="release"><a class="header" href="#release">Release</a></h1>
<p>This is a collection of guides for releasing Filament on different distribution platforms, including
Github, Maven, and CocoaPods.</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../notes/material_properties.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../release/cocoapods.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../notes/material_properties.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../release/cocoapods.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<script>
window.playground_copyable = true;
</script>
<script src="../elasticlunr.min.js"></script>
<script src="../mark.min.js"></script>
<script src="../searcher.js"></script>
<script src="../clipboard.min.js"></script>
<script src="../highlight.js"></script>
<script src="../book.js"></script>
<!-- Custom JS scripts -->
</div>
</body>
</html>
@@ -3,7 +3,7 @@
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Maven Release - Filament</title>
<title>Maven - Filament</title>
<!-- Custom HTML head -->
@@ -218,11 +218,11 @@ the <strong>Publish</strong> button to publish the artifacts. It typically takes
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../build/windows_android.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../release/cocoapods.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../dup/contributing.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next prefetch" href="../release/guide.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
@@ -232,11 +232,11 @@ the <strong>Publish</strong> button to publish the artifacts. It typically takes
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../build/windows_android.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../release/cocoapods.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../dup/contributing.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next prefetch" href="../release/guide.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
@@ -186,11 +186,11 @@ post-process materials. However for now these two numbers must be set to the sam
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../notes/material_properties.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../release/guide.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../notes/branching.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next prefetch" href="../release/branching.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
@@ -200,11 +200,11 @@ post-process materials. However for now these two numbers must be set to the sam
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../notes/material_properties.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../release/guide.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../notes/branching.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next prefetch" href="../release/branching.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
+1 -1
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+12 -2
View File
@@ -307,7 +307,7 @@ class FilamentViewer extends LitElement {
asyncInterval: 30
};
const doneAddingResources = (resourceLoader, stbProvider, ktx2Provider) => {
const doneAddingResources = (resourceLoader, stbProvider, ktx2Provider, webpProvider) => {
this.srcBlobResources = {};
resourceLoader.asyncBeginLoad(this.asset);
const timer = setInterval(() => {
@@ -318,6 +318,9 @@ class FilamentViewer extends LitElement {
resourceLoader.delete();
stbProvider.delete();
ktx2Provider.delete();
if (webpProvider) {
webpProvider.delete();
}
this.animator = this.asset.getInstance().getAnimator();
this.animationStartTime = Date.now();
}
@@ -335,18 +338,25 @@ class FilamentViewer extends LitElement {
const stbProvider = new Filament.gltfio$StbProvider(this.engine);
const ktx2Provider = new Filament.gltfio$Ktx2Provider(this.engine);
let webpProvider = null;
resourceLoader.addStbProvider("image/jpeg", stbProvider);
resourceLoader.addStbProvider("image/png", stbProvider);
resourceLoader.addKtx2Provider("image/ktx2", ktx2Provider);
if (Filament.gltfio$WebpProvider.isWebpSupported()) {
webpProvider = new Filament.gltfio$WebpProvider(this.engine);
resourceLoader.addWebpProvider("image/webp", webpProvider);
}
let remaining = Object.keys(this.srcBlobResources).length;
for (const name in this.srcBlobResources) {
this.srcBlobResources[name].arrayBuffer().then(buffer => {
const desc = getBufferDescriptor(new Uint8Array(buffer));
resourceLoader.addResourceData(name, getBufferDescriptor(desc));
if (--remaining === 0) {
doneAddingResources(resourceLoader, stbProvider, ktx2Provider);
doneAddingResources(resourceLoader, stbProvider, ktx2Provider, webpProvider);
}
});
}
+311
View File
@@ -0,0 +1,311 @@
// SimulatedSkybox.js
// Ported from samples/utils/SimulatedSkybox.cpp
class SimulatedSkybox {
constructor(engine) {
this.engine = engine;
// Default Parameters
this.sunDirection = [0, 1, 0];
this.sunIntensity = 100000.0;
this.turbidity = 2.0;
this.rayleigh = 1.0;
this.mieCoefficient = 1.0;
this.mieG = 0.8;
this.ozone = 0.0;
this.msFactors = [0.1, 0.5, 0.0];
this.contrast = 1.0;
this.nightColor = [0.0, 0.0003, 0.00075];
this.shimmerControl = [0.0, 20.0, 0.1];
this.cloudControl = [0.0, 0.1, 8000.0, 0.0];
this.cloudControl2 = [0.0, 0.0, 0.0, 0.0];
this.waterControl = [50.0, 1.0, 1.0, 4.0]; // x=Strength, y=Speed, z=DerivativeTrick, w=Octaves
this.starControl = [1.0, 1.0]; // x=Density (0-1), y=Enabled (0-1)
this.planetRadius = 6360.0;
// Sun Halo
// x=cos(rad), y=limbDarkening, z=intensity, w=enabled
this.sunHalo = [Math.cos(0.5 * Math.PI / 180.0), 0.5, 1.0, 1.0];
this.initEntity();
}
async loadMaterial(url) {
console.log("Loading material from:", url);
const response = await fetch(url);
const buffer = await response.arrayBuffer();
this.material = this.engine.createMaterial(new Uint8Array(buffer));
this.materialInstance = this.material.createInstance();
// Re-bind the entity with the loaded material
const rcm = this.engine.getRenderableManager();
const instance = rcm.getInstance(this.entity);
rcm.setMaterialInstanceAt(instance, 0, this.materialInstance);
console.log("Material loaded and bound.");
this.updateCoefficients();
}
initEntity() {
const EntityManager = Filament.EntityManager;
const RenderableManager = Filament.RenderableManager;
const VertexBuffer = Filament.VertexBuffer;
const IndexBuffer = Filament.IndexBuffer;
const AttributeType = Filament.VertexBuffer$AttributeType;
const VertexAttribute = Filament.VertexAttribute;
const PrimitiveType = Filament.RenderableManager$PrimitiveType;
const IndexType = Filament.IndexBuffer$IndexType;
this.entity = EntityManager.get().create();
// 3 vertices for full screen triangle
// coords: -1,-1 to 3,-1 to -1,3
const TRIANGLE_VERTICES = new Float32Array([
-1.0, -1.0,
3.0, -1.0,
-1.0, 3.0
]);
const TRIANGLE_INDICES = new Uint16Array([0, 1, 2]);
this.vb = VertexBuffer.Builder()
.vertexCount(3)
.bufferCount(1)
.attribute(VertexAttribute.POSITION, 0, AttributeType.FLOAT2, 0, 8)
.build(this.engine);
this.vb.setBufferAt(this.engine, 0, TRIANGLE_VERTICES);
this.ib = IndexBuffer.Builder()
.indexCount(3)
.bufferType(IndexType.USHORT)
.build(this.engine);
this.ib.setBuffer(this.engine, TRIANGLE_INDICES);
// We create a dummy material first or wait?
// In JS we usually can't block. We'll rely on loadMaterial being called.
// For now, we build the Renderable without material, then set it later.
RenderableManager.Builder(1)
.geometry(0, PrimitiveType.TRIANGLES, this.vb, this.ib)
.culling(false)
.castShadows(false)
.receiveShadows(false)
.priority(7) // Render behind translucent objects? 7 is skybox priority typically.
.build(this.engine, this.entity);
}
setSunPosition(direction) {
// normalize
const len = Math.hypot(direction[0], direction[1], direction[2]);
if (len > 0) {
this.sunDirection = [direction[0] / len, direction[1] / len, direction[2] / len];
} else {
this.sunDirection = [0, 1, 0];
}
this.updateCoefficients();
}
setSunIntensity(intensity) {
this.sunIntensity = Math.max(0.0, intensity);
this.updateCoefficients();
}
setTurbidity(turbidity) {
this.turbidity = Math.max(0.0, turbidity);
this.updateCoefficients();
}
setRayleigh(rayleigh) {
this.rayleigh = Math.max(0.0, rayleigh);
this.updateCoefficients();
}
setMieCoefficient(mie) {
this.mieCoefficient = Math.max(0.0, mie);
this.updateCoefficients();
}
setMieG(g) {
this.mieG = Math.max(0.0, g);
this.updateCoefficients();
}
setOzone(strength) {
this.ozone = Math.max(0.0, strength);
this.updateCoefficients();
}
setMultiScattering(r, m) {
this.msFactors[0] = Math.max(0.0, Math.min(2.0, r));
this.msFactors[1] = Math.max(0.0, Math.min(2.0, m));
this.updateCoefficients();
}
setHorizonGlow(strength) {
this.msFactors[2] = Math.max(0.0, Math.min(1.0, strength));
this.updateCoefficients();
}
setContrast(contrast) {
this.contrast = contrast;
this.updateCoefficients();
}
setNightColor(color) {
this.nightColor = color;
this.updateCoefficients();
}
setSunRadius(degrees) {
const rad = degrees * (Math.PI / 180.0);
this.sunHalo[0] = Math.cos(rad);
this.updateCoefficients();
}
setSunDiskIntensity(intensity) {
this.sunHalo[2] = Math.max(0.0, intensity);
this.updateCoefficients();
}
setSunLimbDarkening(strength) {
this.sunHalo[1] = Math.max(0.0, strength);
this.updateCoefficients();
}
setSunDiskEnabled(enabled) {
this.sunHalo[3] = enabled ? 1.0 : 0.0;
this.updateCoefficients();
}
setShimmerControl(strength, frequency, maskHeight) {
this.shimmerControl[0] = Math.max(0.0, strength);
this.shimmerControl[1] = Math.max(0.0, frequency);
this.shimmerControl[2] = Math.max(0.001, maskHeight);
this.updateCoefficients();
}
setCloudControl(coverage, density, height, speed) {
this.cloudControl[0] = Math.max(0.0, Math.min(1.0, coverage));
this.cloudControl[1] = Math.max(0.0, density);
this.cloudControl[2] = Math.max(1000.0, height);
// JS speed adjustment logic matches C++: speed * (0.05 / 72.0)
this.cloudControl[3] = speed * (0.05 / 72.0);
this.updateCoefficients();
}
setCloudShapeEvolution(speed) {
this.cloudControl2[0] = speed;
this.updateCoefficients();
}
setCloudVolumetricLighting(enabled) {
this.cloudControl2[1] = enabled ? 1.0 : 0.0;
this.updateCoefficients();
}
setWaterControl(strength, speed, derivativeTrick, octaves) {
this.waterControl[0] = Math.max(0.0, strength);
this.waterControl[1] = Math.max(0.0, speed);
this.waterControl[2] = derivativeTrick;
this.waterControl[3] = Math.max(1.0, Math.min(8.0, octaves));
this.updateCoefficients();
}
setStarControl(density, enabled) {
this.starControl[0] = Math.max(0.0, Math.min(1.0, density));
this.starControl[1] = enabled ? 1.0 : 0.0;
this.updateCoefficients();
}
updateCoefficients() {
if (!this.materialInstance) {
console.warn("updateCoefficients called before material loaded");
return;
}
// 1. Rayleigh Coefficients
const F_PI = Math.PI;
const lambda = [680e-9, 550e-9, 440e-9];
const n = 1.0003;
const N = 2.545e25;
const term = (8.0 * Math.pow(F_PI, 3.0) * Math.pow(n * n - 1.0, 2.0)) / (3.0 * N);
const depthR = [
term / Math.pow(lambda[0], 4.0),
term / Math.pow(lambda[1], 4.0),
term / Math.pow(lambda[2], 4.0)
].map(v => v * 8000.0 * this.rayleigh);
// 2. Mie Coefficients
const mieAlpha = 1.3;
const mieBase = 2.0e-5 * this.turbidity;
const depthM = [
mieBase * Math.pow(550e-9 / lambda[0], mieAlpha),
mieBase * Math.pow(550e-9 / lambda[1], mieAlpha),
mieBase * Math.pow(550e-9 / lambda[2], mieAlpha)
].map(v => v * 1200.0 * this.mieCoefficient);
// Fake Ozone
const ozone = [0.0, this.ozone * 0.1, 0.0];
// Sun Fade (Horizon)
const cutoffAngle = 96.0 * (F_PI / 180.0);
const steepness = 1.5;
const zenithFade = 1.0 - Math.exp(-(cutoffAngle / steepness));
const zenithAngle = Math.acos(Math.max(-1.0, Math.min(1.0, this.sunDirection[1])));
const sunFade = Math.max(0.0, 1.0 - Math.exp(-((cutoffAngle - zenithAngle) / steepness))) / zenithFade;
const physicalSunIntensity = this.sunIntensity * sunFade;
// Radiance Conversion for Sun Halo
// Solid Angle = 2 * PI * (1 - cos(angularRadius))
const solidAngle = 2.0 * F_PI * (1.0 - this.sunHalo[0]);
const radianceConversion = 1.0 / Math.max(1e-9, solidAngle);
const sunHaloUpload = [...this.sunHalo];
sunHaloUpload[2] *= radianceConversion;
// Cloud Intersection
const r = this.planetRadius;
const h = this.cloudControl[2] * 0.001; // m -> km
const intersectC = r * r - (r + h) * (r + h);
const cloudUniform = [...this.cloudControl];
cloudUniform[2] = intersectC;
// Shimmer Uniform
const shimmerUniform = [...this.shimmerControl, r];
// Multi-Scattering Vector
const isotropicPhase = 0.25;
const msVector = depthR.map((v, i) => (v * this.msFactors[0] + depthM[i] * this.msFactors[1]) * isotropicPhase);
// Upload
this.materialInstance.setFloat3Parameter('sunDirection', new Float32Array(this.sunDirection));
this.materialInstance.setFloat3Parameter('depthR', new Float32Array(depthR));
this.materialInstance.setFloat3Parameter('depthM', new Float32Array(depthM));
this.materialInstance.setFloat3Parameter('ozone', new Float32Array(ozone));
this.materialInstance.setFloat4Parameter('sunHalo', new Float32Array(sunHaloUpload));
this.materialInstance.setFloat4Parameter('multiScatParams', new Float32Array([...msVector, this.msFactors[2]]));
// Mie Phase
const g2 = this.mieG * this.mieG;
this.materialInstance.setFloat2Parameter('miePhaseParams', new Float32Array([1.0 + g2, -2.0 * this.mieG]));
this.materialInstance.setFloatParameter('contrast', this.contrast);
const nightColorScaled = this.nightColor.map(v => v * this.sunIntensity);
this.materialInstance.setFloat3Parameter('nightColor', new Float32Array(nightColorScaled));
this.materialInstance.setFloat4Parameter('shimmerControl', new Float32Array(shimmerUniform));
this.materialInstance.setFloat4Parameter('cloudControl', new Float32Array(cloudUniform));
this.materialInstance.setFloat4Parameter('cloudControl2', new Float32Array(this.cloudControl2));
this.materialInstance.setFloat4Parameter('waterControl', new Float32Array(this.waterControl));
this.materialInstance.setFloat2Parameter('starControl', new Float32Array(this.starControl));
this.materialInstance.setFloatParameter('sunIntensity', physicalSunIntensity);
}
}
Binary file not shown.
+10
View File
@@ -0,0 +1,10 @@
# Result: /Users/mathias/sources/git/filament/out/cmake-release/tools/matc/matc
MATC="../../../../out/cmake-release/tools/matc/matc"
# Navigate to script directory to ensure relative paths work
cd "$(dirname "$0")"
set -e
$MATC -a opengl -p mobile -o assets/simulated_skybox.filamat simulated_skybox.mat
echo "Material recompiled to assets/simulated_skybox.filamat"
File diff suppressed because one or more lines are too long
BIN
View File
Binary file not shown.
+28
View File
File diff suppressed because one or more lines are too long
+39
View File
@@ -0,0 +1,39 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Analytic Skybox</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,user-scalable=no,initial-scale=1">
<link href="styles.css" rel="stylesheet">
<style>
body {
margin: 0;
overflow: hidden;
background: #000;
}
canvas {
touch-action: none;
width: 100%;
height: 100%;
outline: none;
}
</style>
</head>
<body>
<canvas></canvas>
<!-- Filament -->
<script src="filament.js"></script>
<script src="gl-matrix-min.js"></script>
<!-- UI -->
<script src="lil-gui.js"></script>
<!-- App -->
<script src="SimulatedSkybox.js?v=26"></script>
<script src="main.js?v=26"></script>
</body>
</html>
File diff suppressed because one or more lines are too long
+345
View File
@@ -0,0 +1,345 @@
// main.js
Filament.init(['assets/simulated_skybox.filamat'], () => {
window.app = new App(document.getElementsByTagName('canvas')[0]);
});
class App {
constructor(canvas) {
this.canvas = canvas;
const engine = this.engine = Filament.Engine.create(this.canvas);
this.scene = engine.createScene();
this.skybox = new SimulatedSkybox(engine);
this.skybox.entity = this.skybox.entity; // Ensuring access if needed
this.scene.addEntity(this.skybox.entity);
// Load the material explicitly since we passed it to init but SimulatedSkybox needs to bind it
// Actually SimulatedSkybox.loadMaterial fetches it.
// Since we already loaded it in Filament.init, we can arguably just use it if we had a way to access the asset.
// But Filament.init assets are for internal or easy access via assets object if configured?
// Let's just let SimulatedSkybox fetch it again or use a blob if we wanted.
// Simpler: Just let SimulatedSkybox fetch it.
this.skybox.loadMaterial('assets/simulated_skybox.filamat').then(() => {
this.initGUI();
});
this.swapChain = engine.createSwapChain();
this.renderer = engine.createRenderer();
this.camera = engine.createCamera(Filament.EntityManager.get().create());
this.view = engine.createView();
this.view.setCamera(this.camera);
this.view.setScene(this.scene);
// Color Grading
const ColorGrading = Filament.ColorGrading;
const ToneMapping = Filament.ColorGrading$ToneMapping;
this.colorGrading = ColorGrading.Builder()
.toneMapping(ToneMapping.ACES_LEGACY)
.build(engine);
this.view.setColorGrading(this.colorGrading);
this.view.setPostProcessingEnabled(true); // Essential for tone mapping
// Bloom
this.view.setBloomOptions({
enabled: false,
lenseFlare: false
});
// Clear color is not really visible behind skybox, but black is standard
this.renderer.setClearOptions({ clearColor: [0.0, 0.0, 0.0, 1.0], clear: true });
// Camera handling (Exposure)
this.params = {
aperture: 16.0,
shutterSpeed: 125.0,
iso: 100.0,
sunTheta: Math.acos(0.0), // Default Height 0.0 (Horizon)
sunPhi: 0.0,
focalLength: 24.0, // mm
sunIntensity: 100000.0 // Base intensity
};
this.camState = {
theta: Math.PI / 2, // Look at +X (Sun Position at Phi=0)
phi: 0.0,
dragging: false,
lastX: 0,
lastY: 0
};
this.initControls(); // Initialize controls immediately
this.resize();
window.addEventListener('resize', this.resize.bind(this));
this.render = this.render.bind(this);
window.requestAnimationFrame(this.render);
}
getExposure() {
// Formula: 1.0 / ( 1.2 * (N^2 / t) * (S / 100) )
// t = 1/shutterSpeed
const N = this.params.aperture;
const t = 1.0 / this.params.shutterSpeed;
const S = this.params.iso;
const ev100_linear = (N * N) / t * (100.0 / S);
const exposure = 1.0 / (1.2 * ev100_linear);
return exposure;
}
updateCameraExposure() {
this.camera.setExposure(this.params.aperture, 1.0 / this.params.shutterSpeed, this.params.iso);
// Also update Sun Intensity because it needs to be pre-exposed
this.updateSunIntensity();
}
updateSunIntensity() {
const exposure = this.getExposure();
const preExposedIntensity = this.params.sunIntensity * exposure;
this.skybox.setSunIntensity(preExposedIntensity);
}
updateCameraProjection() {
const width = this.canvas.width;
const height = this.canvas.height;
const aspect = width / height;
this.camera.setLensProjection(this.params.focalLength, aspect, 0.1, 5000.0);
}
initGUI() {
const gui = new lil.GUI({ title: "Analytic Skybox" });
const self = this;
const sky = this.skybox;
// Initialize local params from skybox defaults
// Initialize local params from skybox defaults
// REMOVED: Do not overwrite this.params from sky.sunDirection (Zenith)
// const currentDir = sky.sunDirection;
// this.params.sunTheta = ...
const updateSun = () => {
const theta = this.params.sunTheta;
const phi = this.params.sunPhi;
const x = Math.sin(theta) * Math.cos(phi);
const y = Math.cos(theta);
const z = Math.sin(theta) * Math.sin(phi);
sky.setSunPosition([x, y, z]);
};
const sunFolder = gui.addFolder('Sun');
// Helper for "Sun Height" cosine slider like C++
const sunHeightParam = { height: Math.cos(this.params.sunTheta) };
sunFolder.add(sunHeightParam, 'height', -0.2, 1.0).name('Height (Cos)').onChange(v => {
this.params.sunTheta = Math.acos(v);
updateSun();
});
sunFolder.add(this.params, 'sunPhi', 0.0, Math.PI * 2).name('Azimuth').onChange(updateSun);
// Updated: Controls params.sunIntensity and triggers updateSunIntensity
sunFolder.add(this.params, 'sunIntensity', 0.0, 500000.0).onChange(v => this.updateSunIntensity());
const sunDisk = sunFolder.addFolder('Disk');
// We need local proxy for sunRadius due to conversion
const diskParams = {
radius: 1.2,
enabled: true // Enable sun disk
};
sky.setSunDiskEnabled(true);
sky.setSunRadius(1.2);
sunDisk.add(diskParams, 'enabled').onChange(v => sky.setSunDiskEnabled(v));
sunDisk.add(diskParams, 'radius', 0.0, 5.0).onChange(v => sky.setSunRadius(v));
sunDisk.add(sky.sunHalo, 1, 0.0, 2.0).name('Limb Darkening').onChange(v => sky.setSunLimbDarkening(v));
sunDisk.add(sky.sunHalo, 2, 0.0, 100.0).name('Intensity Boost').onChange(v => sky.setSunDiskIntensity(v));
const atmFolder = gui.addFolder('Atmosphere');
atmFolder.add(sky, 'turbidity', 1.0, 10.0).onChange(v => sky.setTurbidity(v));
atmFolder.add(sky, 'rayleigh', 0.0, 10.0).onChange(v => sky.setRayleigh(v));
atmFolder.add(sky, 'mieCoefficient', 0.0, 10.0).onChange(v => sky.setMieCoefficient(v));
// Set Ozone default to 0.25
sky.setOzone(0.25);
atmFolder.add(sky, 'ozone', 0.0, 1.0).onChange(v => sky.setOzone(v));
atmFolder.add(sky, 'mieG', 0.0, 0.999).onChange(v => sky.setMieG(v));
const artFolder = gui.addFolder('Artistic');
// Set Horizon Glow default to 1.0
sky.setHorizonGlow(1.0);
sky.msFactors[2] = 1.0;
// Set Contrast default to 0.85
sky.setContrast(0.85);
artFolder.add(sky.msFactors, 0, 0.0, 2.0).name('MS Rayleigh').onChange(v => sky.setMultiScattering(v, sky.msFactors[1]));
artFolder.add(sky.msFactors, 1, 0.0, 2.0).name('MS Mie').onChange(v => sky.setMultiScattering(sky.msFactors[0], v));
artFolder.add(sky.msFactors, 2, 0.0, 1.0).name('Horizon Glow').onChange(v => sky.setHorizonGlow(v));
artFolder.add(sky, 'contrast', 0.1, 2.0).onChange(v => sky.setContrast(v));
artFolder.addColor(sky, 'nightColor').onChange(v => sky.setNightColor(v));
const shmFolder = artFolder.addFolder('Shimmer');
// Set Shimmer Strength default to 0.0
sky.setShimmerControl(0.0, sky.shimmerControl[1], sky.shimmerControl[2]);
shmFolder.add(sky.shimmerControl, 0, 0.0, 0.1).name('Strength').onChange(v => sky.setShimmerControl(v, sky.shimmerControl[1], sky.shimmerControl[2]));
shmFolder.add(sky.shimmerControl, 1, 1.0, 100.0).name('Frequency').onChange(v => sky.setShimmerControl(sky.shimmerControl[0], v, sky.shimmerControl[2]));
shmFolder.add(sky.shimmerControl, 2, 0.01, 0.5).name('Mask Height').onChange(v => sky.setShimmerControl(sky.shimmerControl[0], sky.shimmerControl[1], v));
const cloudFolder = gui.addFolder('Clouds');
const cParams = {
volumetrics: sky.cloudControl2[1] > 0.5,
coverage: 0.4,
density: 0.02,
height: sky.cloudControl[2],
speed: 50.0,
evolution: 0.02
};
// Apply Cloud Defaults
sky.setCloudControl(0.4, 0.02, cParams.height, 50.0);
sky.setCloudShapeEvolution(0.02);
cloudFolder.add(cParams, 'volumetrics').onChange(v => sky.setCloudVolumetricLighting(v));
cloudFolder.add(cParams, 'coverage', 0.0, 1.0).onChange(v => sky.setCloudControl(v, cParams.density, cParams.height, cParams.speed));
cloudFolder.add(cParams, 'density', 0.0, 1.0).onChange(v => sky.setCloudControl(cParams.coverage, v, cParams.height, cParams.speed));
cloudFolder.add(cParams, 'height', 2000.0, 20000.0).onChange(v => sky.setCloudControl(cParams.coverage, cParams.density, v, cParams.speed));
// Reverse speed calc: w = speed * (0.05 / 72.0)
cloudFolder.add(cParams, 'speed', 0.0, 200.0).onChange(v => sky.setCloudControl(cParams.coverage, cParams.density, cParams.height, v));
cloudFolder.add(cParams, 'evolution', 0.0, 2.0).onChange(v => sky.setCloudShapeEvolution(v));
const waterFolder = gui.addFolder('Water');
const wParams = {
derivativeTrick: true,
strength: 50.0,
speed: 1.0,
octaves: 4.0
};
// Initialize defaults
sky.setWaterControl(50.0, 1.0, 1.0, 4.0); // 1.0 = Derivative Trick On, 4 octaves
const updateWater = () => {
sky.setWaterControl(wParams.strength, wParams.speed, wParams.derivativeTrick ? 1.0 : 0.0, wParams.octaves);
};
waterFolder.add(wParams, 'derivativeTrick').name('Derivative Trick').onChange(updateWater);
waterFolder.add(wParams, 'strength', 10.0, 100.0).onChange(updateWater);
waterFolder.add(wParams, 'speed', 0.0, 5.0).onChange(updateWater);
waterFolder.add(wParams, 'octaves', 1, 8, 1).name('Octaves').onChange(updateWater);
waterFolder.close();
const starFolder = gui.addFolder('Stars');
const sParams = {
enabled: true,
density: 1.0
};
// Initialize defaults (Density 1.0, Enabled True)
sky.setStarControl(1.0, true);
const updateStars = () => {
sky.setStarControl(sParams.density, sParams.enabled);
};
starFolder.add(sParams, 'enabled').name('Enabled').onChange(updateStars);
starFolder.add(sParams, 'density', 0.0, 1.0).name('Density').onChange(updateStars);
starFolder.close();
const camFolder = gui.addFolder('Camera');
camFolder.add(this.params, 'focalLength', 8.0, 300.0).name('Focal Length').onChange(() => this.updateCameraProjection());
camFolder.add(this.params, 'aperture', 1.4, 32.0).onChange(() => this.updateCameraExposure());
camFolder.add(this.params, 'shutterSpeed', 1.0, 1000.0).onChange(() => this.updateCameraExposure());
camFolder.add(this.params, 'iso', 50.0, 3200.0).onChange(() => this.updateCameraExposure());
const bloomFolder = camFolder.addFolder('Bloom');
const bParams = {
enabled: false,
lensFlare: false
};
const updateBloom = () => {
this.view.setBloomOptions({
enabled: bParams.enabled,
lensFlare: bParams.lensFlare
});
};
bloomFolder.add(bParams, 'enabled').onChange(updateBloom);
bloomFolder.add(bParams, 'lensFlare').onChange(updateBloom);
bloomFolder.close();
// Collapse folders by default
sunDisk.close();
atmFolder.close();
artFolder.close();
// shmFolder is inside artFolder, so it's hidden, but we can close it too if we want
shmFolder.close();
cloudFolder.close();
// camFolder left open? User didn't specify, but "Artistic, shimmer and clouds" + "Disk, Atmosphere" were requested.
// So Camera might stay open or close. Let's keep Camera open for now as it wasn't listed.
// Initial sync
updateSun();
this.updateCameraExposure(); // This will trigger updateSunIntensity too
}
initControls() {
// listeners only
this.canvas.addEventListener('mousedown', e => {
this.camState.dragging = true;
this.camState.lastX = e.clientX;
this.camState.lastY = e.clientY;
});
window.addEventListener('mouseup', () => {
this.camState.dragging = false;
});
window.addEventListener('mousemove', e => {
if (!this.camState.dragging) return;
const dx = e.clientX - this.camState.lastX;
const dy = e.clientY - this.camState.lastY;
this.camState.lastX = e.clientX;
this.camState.lastY = e.clientY;
const sensitivity = 0.005;
this.camState.theta -= dx * sensitivity;
this.camState.phi += dy * sensitivity;
// Clamp pitch to avoid flip [ -PI/2, PI/2 ]
this.camState.phi = Math.max(-Math.PI / 2 + 0.01, Math.min(Math.PI / 2 - 0.01, this.camState.phi));
});
}
render() {
// Update Camera LookAt
const r = 1.0;
const theta = this.camState.theta;
const phi = this.camState.phi;
// Convert spherical to cartesian
// Y is UP. Z is Forward.
// At phi=0, y=0. forward vector should correspond to theta.
// Let's say theta=0 is -Z.
const y = Math.sin(phi);
const h = Math.cos(phi);
const x = h * Math.sin(theta);
const z = -h * Math.cos(theta);
const eye = [0, 0, 0];
const center = [x, y, z];
const up = [0, 1, 0];
this.camera.lookAt(eye, center, up);
this.renderer.render(this.swapChain, this.view);
window.requestAnimationFrame(this.render);
}
resize() {
const dpr = window.devicePixelRatio;
const width = this.canvas.width = window.innerWidth * dpr;
const height = this.canvas.height = window.innerHeight * dpr;
this.view.setViewport([0, 0, width, height]);
const aspect = width / height;
// near=0.1, far=5000.0
this.camera.setLensProjection(this.params.focalLength, aspect, 0.1, 5000.0);
}
}
+909
View File
@@ -0,0 +1,909 @@
material {
name : SimulatedSkybox,
parameters : [
{
type : float3,
name : sunDirection
},
{
type : float3,
name : sunDirection2
},
{
type : float3,
name : depthR,
precision : high
},
{
type : float3,
name : depthM,
precision : high
},
{
type : float2,
name : miePhaseParams, // x=(1+g^2), y=(-2*g)
precision : high
},
{
type : float,
name : sunIntensity,
precision : high
},
{
type : float,
name : contrast,
precision : high
},
{
type : float3,
name : nightColor,
precision : high
},
{
type : float3,
name : ozone,
precision : high
},
{
type : float4,
name : multiScatParams, // xyz=MultiScatteringColor, w=HorizonGlow
precision : high
},
{
type : float4,
name : sunHalo, // x=Size, y=Limb, z=Intensity, w=Enabled
precision : high
},
{
type : float4,
name : shimmerControl, // x=Strength, y=Frequency, z=MaskHeight, w=PlanetRadius
precision : high
},
{
type : float4,
name : cloudControl, // x=Coverage, y=Density, z=QuadraticConst, w=WindSpeed
precision : high
},
{
type : float4,
name : cloudControl2, // x=EvolutionSpeed
precision : high
},
{
type : float,
name : sunIntensity2,
precision : high
},
{
type : float4,
name : sunHalo2, // x=Size, y=Limb, z=Intensity, w=Enabled
precision : high
},
{
type : float4,
name : waterControl, // x=Strength, y=Speed, z=DerivativeTrick, w=Octaves
precision : high
},
{
type : float2,
name : starControl, // x=Density, y=Enabled
precision : high
}
],
variables : [
eyeDirection
],
vertexDomain : device,
depthWrite : false,
shadingModel : unlit,
culling: none
}
vertex {
void materialVertex(inout MaterialVertexInputs material) {
// This code is taken from computeWorldPosition and assumes the vertex domain is 'device'.
highp vec4 p = getPosition();
// GL convention to inverted DX convention
p.z = p.z * -0.5 + 0.5;
highp vec4 worldPosition = getWorldFromClipMatrix() * p;
// Getting the true world position would require dividing by w, but since this is a skybox
// at inifinity, this results in very large numbers for material.eyeDirection.
// Since the eyeDirection is only used as a direction vector in the fragment shader, we can
// skip that step to improve precision.
material.eyeDirection.xyz = worldPosition.xyz;
}
}
fragment {
// ------------------------------------------------------------------------
// Analytic Rayleigh and Mie Scattering (Physics Based)
// Derived from:
// - Hoffman & Preetham (2002): "Real-time Light-Atmosphere Interactions"
// - Henyey & Greenstein (1941): "Diffuse radiation in the galaxy" (Mie Phase)
// - Kasten & Young (1989): "Revised optical air mass tables" (Air Mass)
// - "Simulated Sky" / Three.js (Sky.js): Empirical adjustments for aesthetics
// ------------------------------------------------------------------------
#define PI 3.14159265359
void dummy() {} // squash editor syntax highlighting bugs
// Rayleigh Phase Function: Scattering distribution for small particles (air molecules)
// Lord Rayleigh (1871)
// Normalized to integrate to 4*PI (Boosting brightness by factor PI vs standard 1-normalization)
highp float rayleighPhase(highp float cosTheta) {
const highp float THREE_SIXTEENTH = (3.0 / 16.0);
return THREE_SIXTEENTH * (1.0 + cosTheta * cosTheta);
}
// Henyey-Greenstein Phase Function (Mie)
// Henyey & Greenstein (1941)
// Controls the forward scattering peak (sun halo) via anisotropy parameter 'g'
// Optimized: params.x = (1 + g^2), params.y = (-2 * g)
highp float hgPhase(highp float cosTheta, highp vec2 params) {
const highp float ONE_FOURTH = (1.0 / 4.0);
// Recover (1 - g^2) => 2.0 - (1 + g^2)
highp float oneMinusG2 = 2.0 - params.x;
highp float inverse = 1.0 / pow(params.x + params.y * cosTheta, 1.5);
return ONE_FOURTH * (oneMinusG2 * inverse);
}
// --- Noise Functions for Clouds ---
highp float hash13(highp vec3 p3) {
p3 = fract(p3 * .1031);
p3 += dot(p3, p3.yzx + 33.33);
return fract((p3.x + p3.y) * p3.z);
}
highp float noise(highp vec3 p) {
highp vec3 i = floor(p);
highp vec3 f = fract(p);
// Cubic Hermite Interpolation
highp vec3 u = f*f*(3.0-2.0*f);
return mix(mix(mix(hash13(i + vec3(0,0,0)), hash13(i + vec3(1,0,0)), u.x),
mix(hash13(i + vec3(0,1,0)), hash13(i + vec3(1,1,0)), u.x), u.y),
mix(mix(hash13(i + vec3(0,0,1)), hash13(i + vec3(1,0,1)), u.x),
mix(hash13(i + vec3(0,1,1)), hash13(i + vec3(1,1,1)), u.x), u.y), u.z);
}
// Fractal Brownian Motion (4 Octaves)
highp float fbm(highp vec3 p) {
highp float total = 0.0;
highp float amplitude = 0.5;
for (int i = 0; i < 4; i++) {
total += noise(p) * amplitude;
p *= 2.02; // Lacunarity
p += 100.0; // Shift to avoid artifacts
amplitude *= 0.5; // Gain
}
return total;
}
highp float fbm(highp vec3 p, int octaves) {
highp float total = 0.0;
highp float amplitude = 0.5;
for (int i = 0; i < 8; i++) {
if (i >= octaves) break;
total += noise(p) * amplitude;
p *= 2.02;
p += 100.0;
amplitude *= 0.5;
}
return total;
}
// Ray-Sphere Intersection
// Returns distance to intersection or -1.0 if none.
// Re = Planet Radius.
// C = Re^2 - (Re + height)^2 (Precalculated on CPU for precision).
highp float raySphereIntersect(highp vec3 rd, highp float Re, highp float C) {
// Ray Origin is (0, Re, 0) relative to Planet Center (0, 0, 0)
// We solve |(0, Re, 0) + t*rd|^2 = Rm^2
// |O + tD|^2 = R^2
// t^2 + 2t(O.D) + (O^2 - R^2) = 0
// a=1, b=2(O.D), c = O^2 - R^2 = C
// Reduced quadratic: t = -b' +/- sqrt(b'^2 - c) where b' = O.D
highp float b = Re * rd.y; // dot(vec3(0, Re, 0), rd)
highp float disc = b*b - C;
if (disc < 0.0) return -1.0;
// t = -b + sqrt(disc)
return -b + sqrt(disc);
}
// ------------------------------------------------------------------------
// Atmospheric Heat Shimmer (Mirage)
// ------------------------------------------------------------------------
// Simulates heat convection turbulence near the horizon (e.g., hot desert road effect).
//
// PHYSICS:
// Heat rising from the ground creates pockets of varying air density (refractive index).
// This bends light rays, causing a visual "shimmer" or displacement.
//
// IMPLEMENTATION:
// - Perturbs the view vector `V.y` using interleaved sine waves.
// - Uses World Space `V` so the noise is stable under camera rotation.
// - Masked to only affect the horizon line.
//
// PARAMETERS:
// @param V Normalized World View Vector (modified in place).
// @param strength Max vertical displacement amplitude. (e.g. 0.002).
// @param freq Ripple frequency/density. (e.g. 20.0).
// @param maskHeight Horizon mask height (0.0 to 1.0). (e.g. 0.1).
// ------------------------------------------------------------------------
float applyHeatShimmer(inout highp vec3 V, highp float strength, highp float freq, highp float maskHeight) {
if (strength <= 0.0) return 0.0;
// Mask: Strongest at horizon (0.0), fades out by maskHeight.
highp float mask = 1.0 - smoothstep(0.0, maskHeight, abs(V.y));
if (mask > 0.0) {
// Use FBM for organic turbulence (rising heat waves)
highp float time = getUserTime().x;
// Animate upward (y) and slightly drift (x)
highp vec3 p = vec3(V.x * freq, V.y * freq + time * 2.0, time * 0.5);
// We use a cheap noise or FBM. Since we have FBM:
// Use fewer octaves for performance if possible, but 4 is fine.
highp float distortion = fbm(p);
// Remap noise from [0, 1] to [-1, 1] for perturbation
distortion = distortion * 2.0 - 1.0;
// Apply vertical perturbation
V.y += distortion * strength * mask * 0.1;
V = normalize(V);
}
return mask;
}
// ------------------------------------------------------------------------
// Analytic Sky Model (Rayleigh + Mie + Ozone)
// ------------------------------------------------------------------------
// Computes the scattering and transmittance of the atmosphere along the view ray.
//
// PHYSICS:
// - Rayleigh: Scattering by air molecules (Blue sky). High frequency (lambda^-4).
// - Mie: Scattering by aerosols/dust (White haze). Low frequency (lambda^-1.3).
// - Ozone: Absorption layer (Pink sunset). Absorbs green light.
// - Optical Mass: Approximation of path length through spherical atmosphere.
//
// OUTPUTS:
// @param V Normalized View Vector.
// @param L Normalized Sun Vector.
// @param sunIntensity Sun Illuminance (Lux).
// @param depthR Rayleigh Optical Depth (Precalculated).
// @param depthM Mie Optical Depth (Precalculated).
// @param ozone Ozone Absorption (Precalculated).
// @param msFactors Multi-Scattering factors (Rayleigh, Mie, Glow).
// @param mieG Mie Phase Anisotropy.
// @param outTransmittance Output: Atmospheric Transmittance (0..1) along V.
// @return Output: In-Scattered Radiance (The sky color).
// ------------------------------------------------------------------------
highp vec3 getAtmosphere(highp vec3 V, highp vec3 L, highp float sunIntensity,
highp vec3 depthR, highp vec3 depthM, highp vec3 ozone,
highp vec4 multiScatParams, highp vec2 mieParams,
out highp vec3 outTransmittance) {
highp float cosTheta = dot(V, L);
// 1. Phase Functions
// "Golden Hour" Hack (Three.js Sky.js):
// Remapping cosTheta from [-1, 1] to [0, 1] breaks the symmetry of Rayleigh scattering.
highp float rPhase = rayleighPhase(cosTheta * 0.5 + 0.5);
highp float mPhase = hgPhase(cosTheta, mieParams);
// 2. Optical Depth (Air Mass)
// Kasten and Young (1989) - Relative Air Mass Model
highp float zenithCos = clamp(V.y, 0.0, 1.0);
highp float zenithAngle = acos(zenithCos);
highp float zenithAngleDeg = zenithAngle * (180.0 / PI);
highp float opticalMass = 1.0 / (zenithCos + 0.15 * pow(93.885 - zenithAngleDeg, -1.253));
// 3. Extinction & Transmittance
highp vec3 totalExtinction = depthR + depthM + ozone;
highp vec3 extinction = totalExtinction * opticalMass;
outTransmittance = exp(-extinction);
// 4. In-Scattering
// Approximate Multi-Scattering (Isotropic Fill) precomputed in C++.
highp vec3 multiScattering = multiScatParams.xyz;
highp vec3 scatteringTerm = (depthR * rPhase) + (depthM * mPhase) + multiScattering;
highp vec3 extinctionTerm = max(vec3(1e-6), totalExtinction);
// Equilibrium Radiance (Source Function)
highp vec3 inScattering = sunIntensity * (scatteringTerm / extinctionTerm);
// Single-Scattering Integral: L = L_inf * (1 - exp(-opticalDepth))
highp vec3 sunLight = inScattering * (1.0 - outTransmittance);
// 5. Horizon "Glow" Mix (Artistic Hack)
// multiScatParams.w contains the Horizon Glow Strength
// Uses Sun Elevation (L.y) to only activate during golden hour/twilight.
mediump float horizonMix = saturate(pow(1.0 - L.y, 5.0)) * multiScatParams.w;
highp vec3 horizonGlow = sqrt(inScattering * outTransmittance);
sunLight *= mix(vec3(1.0), horizonGlow, horizonMix);
return sunLight;
}
// ------------------------------------------------------------------------
// Secondary Sun Scattering (Simplified)
// ------------------------------------------------------------------------
// Computes in-scattering for a second light source, reusing precomputed optical depths.
// Skips multi-scattering (ambient) for performance, providing only direct beams/glow.
//
// @param V Normalized View Vector.
// @param L Normalized Sun Vector.
// @param sunIntensity Sun Illuminance.
// @param depthR Rayleigh Optical Depth.
// @param depthM Mie Optical Depth.
// @param ozone Ozone Absorption.
// @param mieParams Mie Phase Params.
// @param transmittance Precomputed Atmospheric Transmittance.
// @return In-Scattered Radiance.
// ------------------------------------------------------------------------
highp vec3 getSecondarySunScattering(highp vec3 V, highp vec3 L, highp float sunIntensity,
highp vec3 depthR, highp vec3 depthM, highp vec3 ozone,
highp vec2 miePhaseParams, highp vec3 transmittance) {
highp float cosTheta = dot(V, L);
// Phase Functions
highp float rPhase = rayleighPhase(cosTheta * 0.5 + 0.5);
highp float mPhase = hgPhase(cosTheta, miePhaseParams);
// Scattering
highp vec3 scatteringTerm = (depthR * rPhase) + (depthM * mPhase);
highp vec3 totalExtinction = depthR + depthM + ozone;
highp vec3 extinctionTerm = max(vec3(1e-6), totalExtinction);
highp vec3 inScattering = sunIntensity * (scatteringTerm / extinctionTerm);
return inScattering * (1.0 - transmittance);
}
// ------------------------------------------------------------------------
// Physical Sun Disk
// ------------------------------------------------------------------------
// Renders the Solar Photosphere with limb darkening.
//
// PHYSICS:
// - The sun is not a point light; it has an angular size (~0.53 deg).
// - Limb Darkening: The sun is darker at the edges (limbs) because we see cooler outer layers.
// - Drawn "Behind" the atmosphere, so it is attenuated by Transmittance.
//
// PARAMETERS:
// @param V Normalized View Vector.
// @param L Normalized Sun Vector.
// @param sunParams x=CosRadius, y=LimbDarkening, z=IntensityBoost, w=Enabled.
// @param sunIntensity Peak Sun Illuminance (Lux).
// @param transmittance Atmospheric Transmittance (0..1).
// @return Radiance of the sun disk (if visible and enabled).
// ------------------------------------------------------------------------
highp vec3 getSunDisk(highp vec3 V, highp vec3 L, highp vec4 sunParams,
highp float sunIntensity, highp vec3 transmittance) {
highp float sunCosRadius = sunParams.x;
highp float limbDarkening = sunParams.y;
highp float sunDiskIntensity = sunParams.z;
bool sunEnabled = sunParams.w > 0.5;
highp float cosTheta = dot(V, L);
// Robust edge detection for small angles using (1 - cos)
highp float dist = 1.0 - cosTheta;
highp float diskRadius = max(1e-6, 1.0 - sunCosRadius);
// AA Edge: smoothstep from radius to radius+epsilon
// We invert it because we want 1.0 inside (dist < radius)
highp float sunDiskProfile = 1.0 - smoothstep(diskRadius, diskRadius + 0.00002, dist);
if (sunEnabled && sunDiskProfile > 0.0) {
// Limb Darkening approximation: mu = sqrt(1 - (r/R)^2)
// dist/diskRadius is approx (r/R)^2 for small angles
highp float relativeDist = min(1.0, dist / diskRadius);
highp float mu = sqrt(1.0 - relativeDist);
// Avoid pow(0, 0) which causes NaNs
highp float limbFactor = (limbDarkening < 1e-4) ? 1.0 : pow(mu, limbDarkening);
// Direct Sun Light (Radiance)
// SunIntensity * Transmittance -> Physical Sun Color
// SunDiskIntensity -> Artistic Boost to punch through Mie halo
return sunIntensity * transmittance * limbFactor * sunDiskIntensity * sunDiskProfile;
}
return vec3(0.0);
}
// ------------------------------------------------------------------------
// Procedural Cirrus Clouds
// ------------------------------------------------------------------------
// Renders a thin layer of high-altitude clouds (Cirrus) using 3D Noise.
//
// IMPLEMENTATION:
// - Modeled as a spherical shell at a specific altitude.
// - Ray-Sphere intersection determines UV layout and distance.
// - Animated using 3D FBM (Fractal Brownian Motion) for shape evolution + Wind drift.
// - Lighting includes Silver Lining (HG Phase) and Atmospheric Extinction.
//
// PARAMETERS:
// @param background Current Sky Color (to be blended with).
// @param V Normalized View Vector.
// @param L Normalized Sun Vector.
// @param control x=Coverage, y=Density, z=QuadraticConst(C), w=WindSpeed.
// @param control2 x=EvolutionSpeed.
// @param geometry w=PlanetRadius (Re).
// @param sunIntensity Sun Illuminance.
// @param transmittance Atmospheric Transmittance (Cloud Color Tint).
// @return Sky color composed with clouds.
// ------------------------------------------------------------------------
// ------------------------------------------------------------------------
// Procedural Cirrus Clouds
// ------------------------------------------------------------------------
// Renders a thin layer of high-altitude clouds (Cirrus) using 3D Noise.
//
// PARAMETERS:
// @param V .
// @param L .
// @param control .
// @param control2 .
// @param geometry .
// @param sunIntensity .
// @param transmittance.
// @param outDensity Output: Cloud Density (0..1).
// @return Cloud Lit Color (pre-multiplied by density? No, just lit color).
// ------------------------------------------------------------------------
highp vec3 getCloudLayer(highp vec3 V, highp vec3 L,
highp vec4 control, highp vec4 control2, highp vec4 geometry,
highp float sunIntensity, highp vec3 transmittance,
out highp float outDensity) {
outDensity = 0.0;
highp float cloudCoverage = control.x;
// Clip clouds below the horizon (Earth occlusion)
// Simple check V.y > 0.0 is sufficient for skybox provided camera is near ground.
if (cloudCoverage > 0.0 && V.y > 0.0) {
highp float Re = geometry.w;
highp float intersectC = control.z;
highp float distToCloud = raySphereIntersect(V, Re, intersectC);
if (distToCloud > 0.0) {
highp vec3 p = V * distToCloud;
highp float speed = control.w;
highp float morphSpeed = control2.x;
highp float time = getUserTime().x;
// UV Mapping (Planar projected onto sphere cap is sufficient for skybox)
// Scale factor 0.05 km^-1
highp vec2 uv = (p.xz * 0.05) + vec2(time * speed * 2.0, 0.0);
// 3D Noise for Morphing
highp float noiseVal = fbm(vec3(uv, time * morphSpeed));
// Remap noise based on coverage.
// Coverage 0.5 -> threshold 0.5. Coverage 1.0 -> threshold 0.0.
highp float threshold = 1.0 - cloudCoverage;
highp float cloudDensity = smoothstep(threshold, threshold + 0.3, noiseVal);
if (cloudDensity > 0.0) {
cloudDensity *= control.y; // Global Density Scalar
cloudDensity = clamp(cloudDensity, 0.0, 1.0);
outDensity = cloudDensity;
// Cloud Lighting
// Silver Lining: Strong forward scattering (Fixed g=0.9 for clouds)
highp float cosTheta = dot(V, L);
// We need separate params for cloud silver lining (g=0.9).
// 1 + 0.9^2 = 1.81. -2*0.9 = -1.8.
// Attenuation (Beer's Law)
// Thick clouds block light.
// 20.0 is an artistic extinction coefficient.
highp float extinction = exp(-cloudDensity * 20.0);
highp float silver = hgPhase(cosTheta, vec2(1.81, -1.8)) * 40.0 * extinction;
// Ambient/Diffuse term.
// We allow some ambient light to pass through even thick clouds (0.05 min)
// so they don't look like black holes.
highp float ambient = 0.1 + 0.4 * extinction;
// Diffuse term (Sun Color) + Silver Lining
highp vec3 cloudLight = sunIntensity * transmittance * (ambient + silver);
// Mix based on density
highp float volumetric = control2.y;
highp float shading = 1.0;
if (volumetric > 0.5) {
// Gradient Lighting (Fake Volumetric Bump)
highp float gradX = dFdx(cloudDensity);
highp float gradY = dFdy(cloudDensity);
// Smaller Z = Steeper Bumps.
// dFdx(density) is typically small (e.g. 0.001).
// We want Normal to have significant X/Y component.
highp vec3 N = normalize(vec3(-gradX, -gradY, 0.001));
// Screen Space Sun Direction
highp vec3 sRight = normalize(dFdx(V));
highp vec3 sUp = normalize(dFdy(V));
highp vec3 L_screen = vec3(dot(L, sRight), dot(L, sUp), 0.5);
L_screen = normalize(L_screen);
shading = dot(N, L_screen);
// Increase contrast: Darker shadows
// dot is [-1, 1]. Map to [0.3, 1.0]
shading = mix(0.3, 1.0, shading * 0.5 + 0.5);
// Darken thick parts (Beer's Law approximation)
// Aggressively darken center of clouds
shading *= (1.0 - cloudDensity * 0.7);
}
return cloudLight * shading;
}
}
}
return vec3(0.0);
}
// ------------------------------------------------------------------------
// Dynamic Tone Mapping
// ------------------------------------------------------------------------
// Applies a contrast curve that varies with sun elevation.
//
// PROBLEM:
// Default linear/gamma tone mapping can make sunsets look washing out.
// Real eyes accept much higher dynamic range at twilight.
//
// SOLUTION:
// - Zenith (Noon): Linear gamma (Exponent 1.0). Physically accurate.
// - Horizon (Sunset): High contrast (Exponent > 1.0). Crushes shadows, boosts color.
//
// @param color Input HDR color.
// @param L Normalized Sun Vector.
// @param contrast Maximum contrast exponent (at horizon). e.g. 1.5.
// @return Tone mapped color.
// ------------------------------------------------------------------------
highp vec3 applyDynamicToneMapping(highp vec3 color, highp vec3 L, highp float contrast) {
float c = saturate(L.y);
// Exponent blends from 'contrast' (at L.y=0) to 1.0 (at L.y=1)
float exponent = mix(contrast, 1.0, sqrt(c));
return pow(max(vec3(0.0), color), vec3(exponent));
}
// ------------------------------------------------------------------------
// Procedural Water Surface
// ------------------------------------------------------------------------
// Simulates an infinite ocean plane at y=0 using screen-space derivatives for normals.
//
// FEATURES:
// - Projected grid for infinite surface.
// - Screen-space wave normal reconstruction (no geometry required).
// - Fresnel reflection of Atmosphere, Sun, and Clouds.
// - Specular highlights (Blinn-Phong).
//
// PARAMETERS:
// @param V Normalized View Vector.
// @param L Normalized Sun Vector.
// @param sunIntensity Sun Illuminance.
// @param depthR Rayleigh Optical Depth.
// @param depthM Mie Optical Depth.
// @param ozone Ozone Absorption.
// @param multiScatParams Multi-Scattering Params.
// @param miePhaseParams Mie Phase Params.
// @param sunHalo Sun Halo Params.
// @param cloudControl Cloud Control Params.
// @param cloudControl2 Cloud Evolution Params.
// @param shimmerControl Shimmer Control (w component used as PlanetRadius for clouds).
// @param waterControl Water Control (x=Strength, y=Speed, z=DerivativeTrick).
// @return Water surface color.
// ------------------------------------------------------------------------
// 3D Noise for Stars
highp float hash31(highp vec3 p) {
p = fract(p * 0.1031);
p += dot(p, p.yzx + 33.33);
return fract((p.x + p.y) * p.z);
}
highp float getStars(highp vec3 V, highp float density) {
// Simple procedural stars
// We use view vector direction to tile the sky
// Higher frequency = smaller stars
highp float frequency = 300.0;
highp vec3 p = floor(V * frequency);
highp float h = hash31(p);
// Threshold for stars (very sparse)
// param density: 0.0 (none) to 1.0 (max)
// Default threshold was 0.995 (0.5% stars)
// We map density 0.0 -> 1.0 threshold (no stars)
// density 1.0 -> 0.990 threshold (1.0% stars)
highp float threshold = 1.0 - (0.001 + density * 0.009);
highp float star = 0.0;
if (h > threshold) {
// Random brightness
highp float brightness = (h - threshold) / (1.0 - threshold);
star = brightness * 15.0; // Reduced from 50.0 to 15.0
}
return star;
}
// New helper to handle Star Compositing (Fade, Rotation, Occlusion)
highp vec3 getStarLayer(highp vec3 V, highp vec3 L, highp float cloudDensity, highp vec3 transmittance, highp vec2 starControl) {
// starControl.x = Density, .y = Enabled
if (starControl.y < 0.5) return vec3(0.0);
// 1. Fade by Sun Elevation
// Start appearing sooner (when sun is still slightly up), but stay dim.
// 0.10 (5.7 deg up) -> 0.0
// -0.20 (11.5 deg down) -> 1.0
highp float starFade = 1.0 - smoothstep(-0.20, 0.10, L.y);
starFade *= starFade;
if (starFade <= 0.0) return vec3(0.0);
// 2. Rotate to break grid alignment
highp vec3 rotV = vec3(
dot(V, vec3(0.6, 0.8, 0.0)),
dot(V, vec3(-0.8, 0.6, 0.0)),
V.z
);
highp float starVal = getStars(rotV, starControl.x);
if (starVal <= 0.0) return vec3(0.0);
// 3. Cloud Occlusion (Aggressive)
highp float cloudOcclusion = 1.0 - smoothstep(0.0, 1.0, pow(cloudDensity, 0.1));
return vec3(starVal) * transmittance * starFade * cloudOcclusion * 0.1;
}
// ------------------------------------------------------------------------
// Procedural Water Surface
// ------------------------------------------------------------------------
// Simulates an infinite ocean plane at y=0 using screen-space derivatives for normals.
//
// FEATURES:
// - Projected grid for infinite surface.
// - Screen-space wave normal reconstruction (no geometry required).
// - Fresnel reflection of Atmosphere, Sun, and Clouds.
// - Specular highlights (Blinn-Phong).
//
// PARAMETERS:
// @param V Normalized View Vector.
// @param L Normalized Sun Vector.
// @param sunIntensity Sun Illuminance.
// @param depthR Rayleigh Optical Depth.
// @param depthM Mie Optical Depth.
// @param ozone Ozone Absorption.
// @param multiScatParams Multi-Scattering Params.
// @param miePhaseParams Mie Phase Params.
// @param sunHalo Sun Halo Params.
// @param cloudControl Cloud Control Params.
// @param cloudControl2 Cloud Evolution Params.
// @param shimmerControl Shimmer Control (w component used as PlanetRadius for clouds).
// @param waterControl Water Control (x=Strength, y=Speed, z=DerivativeTrick).
// @return Water surface color.
// ------------------------------------------------------------------------
highp vec3 getWaterColor(highp vec3 V, highp vec3 L,
highp float sunIntensity,
highp vec3 depthR, highp vec3 depthM, highp vec3 ozone,
highp vec4 multiScatParams, highp vec2 miePhaseParams,
highp vec4 sunHalo,
highp vec4 cloudControl, highp vec4 cloudControl2,
highp vec4 shimmerControl, highp vec4 waterControl) {
// Project to plane y=0
highp float t = -10.0 / min(V.y, -0.0002); // Reduced clamp to minimize "wall" artifact
highp vec2 uv = V.xz * t * 0.05;
highp float time = getUserTime().x;
highp float speed = waterControl.y;
uv += vec2(time * 0.5 * speed, time * 0.2 * speed);
// Wave Normal
// Use screen-space derivatives to compute world-space normal perturbation
// Wave Normal
// Use screen-space derivatives to compute world-space normal perturbation
int octaves = int(max(1.0, waterControl.w));
highp float h = fbm(vec3(uv, time * 0.1 * speed), octaves);
// Reconstruct screen-space basis in world space
// highp vec3 sRight = normalize(dFdx(V)); // Moved inside block
// highp vec3 sUp = normalize(dFdy(V)); // Moved inside block
// Perturb normal based on height gradient
// If h increases in screen-X direction, normal tilts against sRight.
// Fade out perturbation near horizon (V.y -> 0) to reduce aliasing
highp float horizonFade = smoothstep(0.0, 0.5, abs(V.y));
highp float strength = waterControl.x;
highp vec3 N_perturb;
// Derivative Trick Toggle
if (waterControl.z > 0.5) {
// Screen-Space Derivatives (Fast, 1 tap)
// Reconstruct screen-space basis in world space
// If h increases in screen-X direction, normal tilts against sRight.
highp vec3 sRight = normalize(dFdx(V));
highp vec3 sUp = normalize(dFdy(V));
N_perturb = (sRight * dFdx(h) + sUp * dFdy(h)) * strength * horizonFade;
} else {
// Finite Difference (Standard, 3 taps)
// More expensive but analytically correct in world space (independent of view resolution/derivatives)
float eps = 0.02; // Epsilon for gradient
vec3 p = vec3(uv, time * 0.1 * speed);
float hx = fbm(p + vec3(eps, 0.0, 0.0), octaves);
float hy = fbm(p + vec3(0.0, eps, 0.0), octaves);
// Gradient
float dx = (hx - h) / eps;
float dy = (hy - h) / eps;
// Construct World Space Perturbation
// Gradient (dx, dy) acts on XZ plane.
// Normal = normalize(-dx, 1, -dy).
// We want N_perturb to SUBTRACT from (0,1,0).
// N_water = normalize(Up - Perturb).
// So Perturb = (dx, 0, dy).
// Note: Strength needs to be calibrated to match derivative trick roughly, or just raw.
// Derivative trick Strength was ~50.0.
// Here dx/dy are raw noise slopes.
// Reduced to 0.002 to match visual range of derivative trick and prevent black artifacts.
N_perturb = vec3(dx, 0.0, dy) * (strength * 0.002) * horizonFade;
}
highp vec3 N_water = normalize(vec3(0.0, 1.0, 0.0) - N_perturb);
// Reflection
highp vec3 R = reflect(V, N_water);
highp vec3 transRefl;
highp vec3 reflection = getAtmosphere(R, L, sunIntensity,
depthR, depthM,
ozone, multiScatParams,
miePhaseParams,
transRefl);
// Clouds in reflection
highp float reflCloudDensity;
highp vec3 reflCloudLayer = getCloudLayer(R, L, materialParams.cloudControl, materialParams.cloudControl2,
materialParams.shimmerControl, materialParams.sunIntensity, transRefl,
reflCloudDensity);
// Add Stars to Reflection
// Use helper with Reflection Vector and Reflection Cloud Density
// Horizon Mask: Fade out star reflections that are deep in the water (high R.y)
// Restricted to very close to horizon (0.0 to 0.1) as requested.
highp float rHorizonMask = 1.0 - smoothstep(0.0, 0.1, R.y);
if (rHorizonMask > 0.0) {
reflection += getStarLayer(R, L, reflCloudDensity, transRefl, materialParams.starControl) * rHorizonMask;
}
// Add Sun Disk to reflection (Occluded)
highp float reflSunAccess = 1.0 - smoothstep(0.0, 0.7, reflCloudDensity * 1.5);
reflection += getSunDisk(R, L, sunHalo, sunIntensity, transRefl) * reflSunAccess;
// Apply clouds to reflection
reflection = mix(reflection, reflCloudLayer, reflCloudDensity);
// Fresnel
highp float F0 = 0.02; // Water
highp float cosTheta = clamp(dot(-V, N_water), 0.0, 1.0);
highp float F = F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
highp vec3 deepColor = vec3(0.0, 0.005, 0.02); // Deep blue/black
highp vec3 waterColor = mix(deepColor, reflection, F);
return waterColor;
}
void material(inout MaterialInputs material) {
prepareMaterial(material);
highp vec3 V = normalize(variable_eyeDirection.xyz);
highp vec3 L = normalize(materialParams.sunDirection);
// 1. Heat Shimmer
// Fade out as sun rises (Strongest at horizon, zero at 30 degrees up)
highp float sunFade = 1.0 - smoothstep(0.0, 0.5, abs(L.y));
highp float shimmerIntensity = applyHeatShimmer(V, materialParams.shimmerControl.x * sunFade,
materialParams.shimmerControl.y,
materialParams.shimmerControl.z);
// 2. Atmospheric Scattering
highp vec3 transmittance;
highp vec3 inScatter1 = getAtmosphere(V, L, materialParams.sunIntensity,
materialParams.depthR, materialParams.depthM,
materialParams.ozone, materialParams.multiScatParams,
materialParams.miePhaseParams,
transmittance);
// Sun 2 (Optional)
// We reuse the same Transmittance (view dependent) and Phase params.
// We do NOT add extra Multi-Scattering (Ambient) for the second sun to save cost/complexity.
// It contributes Direct In-Scattering (Beams/Glow) only.
highp vec3 inScatter2 = vec3(0.0);
if (materialParams.sunHalo2.w > 0.5) {
highp vec3 L2 = normalize(materialParams.sunDirection2);
inScatter2 = getSecondarySunScattering(V, L2,
materialParams.sunIntensity2,
materialParams.depthR,
materialParams.depthM,
materialParams.ozone,
materialParams.miePhaseParams,
transmittance);
}
highp vec3 finalColor = inScatter1 + inScatter2;
// 5. Procedural Clouds
highp float cloudDensity;
highp vec3 cloudLayer = getCloudLayer(V, L,
materialParams.cloudControl,
materialParams.cloudControl2,
materialParams.shimmerControl, // reusing w=PlanetRadius
materialParams.sunIntensity,
transmittance,
cloudDensity);
// Add Stars
// Stars are at infinity.
// Use helper function.
finalColor += getStarLayer(V, L, cloudDensity, transmittance, materialParams.starControl);
// 3. Sun Disks - Occluded by clouds
// Sun Access is (1.0 - cloudDensity) but arguably non-linear for sharp disk
highp float sunAccess = 1.0 - smoothstep(0.0, 0.7, cloudDensity * 1.5);
finalColor += getSunDisk(V, L, materialParams.sunHalo,
materialParams.sunIntensity, transmittance) * sunAccess;
if (materialParams.sunHalo2.w > 0.5) {
highp vec3 L2 = normalize(materialParams.sunDirection2);
// Note: Ideally we should compute cloud density for L2 direction if clouds are 3D...
// But here we use V direction clouds (view-based).
// Since clouds are in front of everything, this is correct for view-based occlusion.
finalColor += getSunDisk(V, L2, materialParams.sunHalo2,
materialParams.sunIntensity2, transmittance) * sunAccess;
}
// 4. Night Sky Offset
finalColor += materialParams.nightColor;
// 5. Apply Clouds
finalColor = mix(finalColor, cloudLayer, cloudDensity);
// 6. Dynamic Tone Mapping
finalColor = applyDynamicToneMapping(finalColor, L, materialParams.contrast);
if (V.y < 0.0) {
finalColor = getWaterColor(V, L, materialParams.sunIntensity,
materialParams.depthR, materialParams.depthM,
materialParams.ozone, materialParams.multiScatParams,
materialParams.miePhaseParams,
materialParams.sunHalo,
materialParams.cloudControl, materialParams.cloudControl2,
materialParams.shimmerControl,
materialParams.waterControl);
finalColor = applyDynamicToneMapping(finalColor, L, materialParams.contrast);
}
material.baseColor = vec4(finalColor, 1.0);
}
}
+9
View File
@@ -0,0 +1,9 @@
body {
margin: 0;
overflow: hidden;
}
canvas {
touch-action: none;
width: 100%;
height: 100%;
}
+1 -1
View File
@@ -49,7 +49,7 @@ to perform a number of URL replacements in addition to the copy. These replaceme
described in [`docs_src/build/duplicates.json`].
### Core concept docs
The primary design of Filament as a phyiscally-based renderer and details of its materials
The primary design of Filament as a physically-based renderer and details of its materials
system are described in `Filament.md.html` and `Materials.md.html`, respectively. These two
documents are written in [`markdeep`]. To embed them into our book, we
1. Convert the markdeep into html
+13 -1
View File
@@ -49,6 +49,9 @@
"libs/fgviewer/README.md": {
"dest": "dup/fgviewer.md"
},
"ios/CocoaPods/README.md": {
"dest": "release/cocoapods.md"
},
"tools/normal-blending/README.md": {
"dest": "dup/normal_blending.md"
},
@@ -79,13 +82,22 @@
"tools/specular-color/README.md": {
"dest": "dup/specular_color.md"
},
"tools/specgen/README.md": {
"dest": "dup/specgen.md"
},
"docs_src/README.md": {
"dest": "dup/docs.md"
},
"test/renderdiff/README.md": {
"dest": "dup/renderdiff.md",
"dest": "dup/test_ci_renderdiff.md",
"link_transforms": {
"docs/images/": "../images/"
}
},
"test/backend/README.md": {
"dest": "dup/test_ci_backend.md"
},
"filament/backend/test/README.md": {
"dest": "dup/backend_test.md"
}
}
+1 -1
View File
@@ -10,6 +10,6 @@ sortedcontainers==2.4.0
trio==0.31.0
trio-websocket==0.12.2
typing_extensions==4.15.0
urllib3==2.6.0
urllib3==2.6.3
websocket-client==1.9.0
wsproto==1.2.0
+7 -4
View File
@@ -161,7 +161,7 @@ The type and range of each property is described in table [standardPropertiesTyp
vertex. `microThickness` represent the thickness of the thin layer of an object, and can
generally be provided as a constant value. For example, a 1mm thin hollow sphere of radius 1m,
would have a `thickness` of 1 and a `microThickness` of 0.001. Dispersion controls the angular
separation of colors transmitting through a volume, and can be set by a contant value.
separation of colors transmitting through a volume, and can be set by a constant value.
Currently `thickness` and `dispersion` are not used when `refractionType` is set to `thin`.
### Base color
@@ -671,6 +671,9 @@ Water | 55 | 0.36
Crown Glass | 59 | 0.33
[Table [commonMatDispersion]: Dispersion of common materials]
![Figure [dispersionProperty]: `dispersion` varying from 0.0
(left) to 5.0 (right)](images/materials/dispersion.png)
## Subsurface model
### Thickness
@@ -2477,9 +2480,9 @@ type aliases:
**uint2** | uvec2 | A vector of 2 unsigned integers
**uint3** | uvec3 | A vector of 3 unsigned integers
**uint4** | uvec4 | A vector of 4 unsigned integers
**float2** | float2 | A vector of 2 floats
**float3** | float3 | A vector of 3 floats
**float4** | float4 | A vector of 4 floats
**float2** | vec2 | A vector of 2 floats
**float3** | vec3 | A vector of 3 floats
**float4** | vec4 | A vector of 4 floats
**float4x4** | mat4 | A 4x4 float matrix
**float3x3** | mat3 | A 3x3 float matrix
+3
View File
@@ -20,3 +20,6 @@ enable = false
[output.html.fold]
enable = false
[output.html.mathjax]
enable = true
+13 -8
View File
@@ -2,8 +2,7 @@
- [Introduction](./dup/intro.md)
- [Build](./dup/building.md)
- [Build for Android on Windows](./build/windows_android.md)
- [Maven Release](./build/maven_release.md)
- [Android on Windows](./build/windows_android.md)
- [Contribute](./dup/contributing.md)
- [Coding Style](./dup/code_style.md)
- [Core Concepts](./main/README.md)
@@ -14,9 +13,12 @@
- [Web Tutorial](./samples/web.md)
- [Technical Notes](./notes/README.md)
- [Material Properties](./notes/material_properties.md)
- [Versioning](./notes/versioning.md)
- [Branching](./notes/branching.md)
- [Release Guide](./notes/release_guide.md)
- [Release](./release/README.md)
- [CocoaPods](./release/cocoapods.md)
- [Maven](./release/maven.md)
- [Github](./release/guide.md)
- [Versioning](./release/versioning.md)
- [Branching](./release/branching.md)
- [Documentation](./dup/docs.md)
- [Debugging](./notes/debugging.md)
- [Metal](./notes/metal_debugging.md)
@@ -28,7 +30,9 @@
- [Performance analysis](./notes/performance_analysis.md)
- [Framegraph](./notes/framegraph.md)
- [Tests](./notes/tests.md)
- [renderdiff](./dup/renderdiff.md)
- [backend](./dup/backend_test.md)
- [CI: backend](./dup/test_ci_backend.md)
- [CI: renderdiff](./dup/test_ci_renderdiff.md)
- [Libraries](./notes/libs.md)
- [bluegl](./dup/bluegl.md)
- [bluevk](./dup/bluevk.md)
@@ -43,9 +47,10 @@
- [cmgen](./dup/cmgen.md)
- [cso-lut](./dup/cso_lut.md)
- [filamesh](./dup/filamesh.md)
- [normal-blending](./dup/normal_blending.md)
- [mipgen](./dup/mipgen.md)
- [matinfo](./dup/matinfo.md)
- [mipgen](./dup/mipgen.md)
- [normal-blending](./dup/normal_blending.md)
- [roughness-prefilter](./dup/roughness_prefilter.md)
- [specgen](./dup/specgen.md)
- [specular-color](./dup/specular_color.md)
- [zbloat](./dup/zbloat.md)
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 MiB

@@ -0,0 +1,4 @@
# Release
This is a collection of guides for releasing Filament on different distribution platforms, including
Github, Maven, and CocoaPods.
+12 -2
View File
@@ -307,7 +307,7 @@ class FilamentViewer extends LitElement {
asyncInterval: 30
};
const doneAddingResources = (resourceLoader, stbProvider, ktx2Provider) => {
const doneAddingResources = (resourceLoader, stbProvider, ktx2Provider, webpProvider) => {
this.srcBlobResources = {};
resourceLoader.asyncBeginLoad(this.asset);
const timer = setInterval(() => {
@@ -318,6 +318,9 @@ class FilamentViewer extends LitElement {
resourceLoader.delete();
stbProvider.delete();
ktx2Provider.delete();
if (webpProvider) {
webpProvider.delete();
}
this.animator = this.asset.getInstance().getAnimator();
this.animationStartTime = Date.now();
}
@@ -335,18 +338,25 @@ class FilamentViewer extends LitElement {
const stbProvider = new Filament.gltfio$StbProvider(this.engine);
const ktx2Provider = new Filament.gltfio$Ktx2Provider(this.engine);
let webpProvider = null;
resourceLoader.addStbProvider("image/jpeg", stbProvider);
resourceLoader.addStbProvider("image/png", stbProvider);
resourceLoader.addKtx2Provider("image/ktx2", ktx2Provider);
if (Filament.gltfio$WebpProvider.isWebpSupported()) {
webpProvider = new Filament.gltfio$WebpProvider(this.engine);
resourceLoader.addWebpProvider("image/webp", webpProvider);
}
let remaining = Object.keys(this.srcBlobResources).length;
for (const name in this.srcBlobResources) {
this.srcBlobResources[name].arrayBuffer().then(buffer => {
const desc = getBufferDescriptor(new Uint8Array(buffer));
resourceLoader.addResourceData(name, getBufferDescriptor(desc));
if (--remaining === 0) {
doneAddingResources(resourceLoader, stbProvider, ktx2Provider);
doneAddingResources(resourceLoader, stbProvider, ktx2Provider, webpProvider);
}
});
}
+311
View File
@@ -0,0 +1,311 @@
// SimulatedSkybox.js
// Ported from samples/utils/SimulatedSkybox.cpp
class SimulatedSkybox {
constructor(engine) {
this.engine = engine;
// Default Parameters
this.sunDirection = [0, 1, 0];
this.sunIntensity = 100000.0;
this.turbidity = 2.0;
this.rayleigh = 1.0;
this.mieCoefficient = 1.0;
this.mieG = 0.8;
this.ozone = 0.0;
this.msFactors = [0.1, 0.5, 0.0];
this.contrast = 1.0;
this.nightColor = [0.0, 0.0003, 0.00075];
this.shimmerControl = [0.0, 20.0, 0.1];
this.cloudControl = [0.0, 0.1, 8000.0, 0.0];
this.cloudControl2 = [0.0, 0.0, 0.0, 0.0];
this.waterControl = [50.0, 1.0, 1.0, 4.0]; // x=Strength, y=Speed, z=DerivativeTrick, w=Octaves
this.starControl = [1.0, 1.0]; // x=Density (0-1), y=Enabled (0-1)
this.planetRadius = 6360.0;
// Sun Halo
// x=cos(rad), y=limbDarkening, z=intensity, w=enabled
this.sunHalo = [Math.cos(0.5 * Math.PI / 180.0), 0.5, 1.0, 1.0];
this.initEntity();
}
async loadMaterial(url) {
console.log("Loading material from:", url);
const response = await fetch(url);
const buffer = await response.arrayBuffer();
this.material = this.engine.createMaterial(new Uint8Array(buffer));
this.materialInstance = this.material.createInstance();
// Re-bind the entity with the loaded material
const rcm = this.engine.getRenderableManager();
const instance = rcm.getInstance(this.entity);
rcm.setMaterialInstanceAt(instance, 0, this.materialInstance);
console.log("Material loaded and bound.");
this.updateCoefficients();
}
initEntity() {
const EntityManager = Filament.EntityManager;
const RenderableManager = Filament.RenderableManager;
const VertexBuffer = Filament.VertexBuffer;
const IndexBuffer = Filament.IndexBuffer;
const AttributeType = Filament.VertexBuffer$AttributeType;
const VertexAttribute = Filament.VertexAttribute;
const PrimitiveType = Filament.RenderableManager$PrimitiveType;
const IndexType = Filament.IndexBuffer$IndexType;
this.entity = EntityManager.get().create();
// 3 vertices for full screen triangle
// coords: -1,-1 to 3,-1 to -1,3
const TRIANGLE_VERTICES = new Float32Array([
-1.0, -1.0,
3.0, -1.0,
-1.0, 3.0
]);
const TRIANGLE_INDICES = new Uint16Array([0, 1, 2]);
this.vb = VertexBuffer.Builder()
.vertexCount(3)
.bufferCount(1)
.attribute(VertexAttribute.POSITION, 0, AttributeType.FLOAT2, 0, 8)
.build(this.engine);
this.vb.setBufferAt(this.engine, 0, TRIANGLE_VERTICES);
this.ib = IndexBuffer.Builder()
.indexCount(3)
.bufferType(IndexType.USHORT)
.build(this.engine);
this.ib.setBuffer(this.engine, TRIANGLE_INDICES);
// We create a dummy material first or wait?
// In JS we usually can't block. We'll rely on loadMaterial being called.
// For now, we build the Renderable without material, then set it later.
RenderableManager.Builder(1)
.geometry(0, PrimitiveType.TRIANGLES, this.vb, this.ib)
.culling(false)
.castShadows(false)
.receiveShadows(false)
.priority(7) // Render behind translucent objects? 7 is skybox priority typically.
.build(this.engine, this.entity);
}
setSunPosition(direction) {
// normalize
const len = Math.hypot(direction[0], direction[1], direction[2]);
if (len > 0) {
this.sunDirection = [direction[0] / len, direction[1] / len, direction[2] / len];
} else {
this.sunDirection = [0, 1, 0];
}
this.updateCoefficients();
}
setSunIntensity(intensity) {
this.sunIntensity = Math.max(0.0, intensity);
this.updateCoefficients();
}
setTurbidity(turbidity) {
this.turbidity = Math.max(0.0, turbidity);
this.updateCoefficients();
}
setRayleigh(rayleigh) {
this.rayleigh = Math.max(0.0, rayleigh);
this.updateCoefficients();
}
setMieCoefficient(mie) {
this.mieCoefficient = Math.max(0.0, mie);
this.updateCoefficients();
}
setMieG(g) {
this.mieG = Math.max(0.0, g);
this.updateCoefficients();
}
setOzone(strength) {
this.ozone = Math.max(0.0, strength);
this.updateCoefficients();
}
setMultiScattering(r, m) {
this.msFactors[0] = Math.max(0.0, Math.min(2.0, r));
this.msFactors[1] = Math.max(0.0, Math.min(2.0, m));
this.updateCoefficients();
}
setHorizonGlow(strength) {
this.msFactors[2] = Math.max(0.0, Math.min(1.0, strength));
this.updateCoefficients();
}
setContrast(contrast) {
this.contrast = contrast;
this.updateCoefficients();
}
setNightColor(color) {
this.nightColor = color;
this.updateCoefficients();
}
setSunRadius(degrees) {
const rad = degrees * (Math.PI / 180.0);
this.sunHalo[0] = Math.cos(rad);
this.updateCoefficients();
}
setSunDiskIntensity(intensity) {
this.sunHalo[2] = Math.max(0.0, intensity);
this.updateCoefficients();
}
setSunLimbDarkening(strength) {
this.sunHalo[1] = Math.max(0.0, strength);
this.updateCoefficients();
}
setSunDiskEnabled(enabled) {
this.sunHalo[3] = enabled ? 1.0 : 0.0;
this.updateCoefficients();
}
setShimmerControl(strength, frequency, maskHeight) {
this.shimmerControl[0] = Math.max(0.0, strength);
this.shimmerControl[1] = Math.max(0.0, frequency);
this.shimmerControl[2] = Math.max(0.001, maskHeight);
this.updateCoefficients();
}
setCloudControl(coverage, density, height, speed) {
this.cloudControl[0] = Math.max(0.0, Math.min(1.0, coverage));
this.cloudControl[1] = Math.max(0.0, density);
this.cloudControl[2] = Math.max(1000.0, height);
// JS speed adjustment logic matches C++: speed * (0.05 / 72.0)
this.cloudControl[3] = speed * (0.05 / 72.0);
this.updateCoefficients();
}
setCloudShapeEvolution(speed) {
this.cloudControl2[0] = speed;
this.updateCoefficients();
}
setCloudVolumetricLighting(enabled) {
this.cloudControl2[1] = enabled ? 1.0 : 0.0;
this.updateCoefficients();
}
setWaterControl(strength, speed, derivativeTrick, octaves) {
this.waterControl[0] = Math.max(0.0, strength);
this.waterControl[1] = Math.max(0.0, speed);
this.waterControl[2] = derivativeTrick;
this.waterControl[3] = Math.max(1.0, Math.min(8.0, octaves));
this.updateCoefficients();
}
setStarControl(density, enabled) {
this.starControl[0] = Math.max(0.0, Math.min(1.0, density));
this.starControl[1] = enabled ? 1.0 : 0.0;
this.updateCoefficients();
}
updateCoefficients() {
if (!this.materialInstance) {
console.warn("updateCoefficients called before material loaded");
return;
}
// 1. Rayleigh Coefficients
const F_PI = Math.PI;
const lambda = [680e-9, 550e-9, 440e-9];
const n = 1.0003;
const N = 2.545e25;
const term = (8.0 * Math.pow(F_PI, 3.0) * Math.pow(n * n - 1.0, 2.0)) / (3.0 * N);
const depthR = [
term / Math.pow(lambda[0], 4.0),
term / Math.pow(lambda[1], 4.0),
term / Math.pow(lambda[2], 4.0)
].map(v => v * 8000.0 * this.rayleigh);
// 2. Mie Coefficients
const mieAlpha = 1.3;
const mieBase = 2.0e-5 * this.turbidity;
const depthM = [
mieBase * Math.pow(550e-9 / lambda[0], mieAlpha),
mieBase * Math.pow(550e-9 / lambda[1], mieAlpha),
mieBase * Math.pow(550e-9 / lambda[2], mieAlpha)
].map(v => v * 1200.0 * this.mieCoefficient);
// Fake Ozone
const ozone = [0.0, this.ozone * 0.1, 0.0];
// Sun Fade (Horizon)
const cutoffAngle = 96.0 * (F_PI / 180.0);
const steepness = 1.5;
const zenithFade = 1.0 - Math.exp(-(cutoffAngle / steepness));
const zenithAngle = Math.acos(Math.max(-1.0, Math.min(1.0, this.sunDirection[1])));
const sunFade = Math.max(0.0, 1.0 - Math.exp(-((cutoffAngle - zenithAngle) / steepness))) / zenithFade;
const physicalSunIntensity = this.sunIntensity * sunFade;
// Radiance Conversion for Sun Halo
// Solid Angle = 2 * PI * (1 - cos(angularRadius))
const solidAngle = 2.0 * F_PI * (1.0 - this.sunHalo[0]);
const radianceConversion = 1.0 / Math.max(1e-9, solidAngle);
const sunHaloUpload = [...this.sunHalo];
sunHaloUpload[2] *= radianceConversion;
// Cloud Intersection
const r = this.planetRadius;
const h = this.cloudControl[2] * 0.001; // m -> km
const intersectC = r * r - (r + h) * (r + h);
const cloudUniform = [...this.cloudControl];
cloudUniform[2] = intersectC;
// Shimmer Uniform
const shimmerUniform = [...this.shimmerControl, r];
// Multi-Scattering Vector
const isotropicPhase = 0.25;
const msVector = depthR.map((v, i) => (v * this.msFactors[0] + depthM[i] * this.msFactors[1]) * isotropicPhase);
// Upload
this.materialInstance.setFloat3Parameter('sunDirection', new Float32Array(this.sunDirection));
this.materialInstance.setFloat3Parameter('depthR', new Float32Array(depthR));
this.materialInstance.setFloat3Parameter('depthM', new Float32Array(depthM));
this.materialInstance.setFloat3Parameter('ozone', new Float32Array(ozone));
this.materialInstance.setFloat4Parameter('sunHalo', new Float32Array(sunHaloUpload));
this.materialInstance.setFloat4Parameter('multiScatParams', new Float32Array([...msVector, this.msFactors[2]]));
// Mie Phase
const g2 = this.mieG * this.mieG;
this.materialInstance.setFloat2Parameter('miePhaseParams', new Float32Array([1.0 + g2, -2.0 * this.mieG]));
this.materialInstance.setFloatParameter('contrast', this.contrast);
const nightColorScaled = this.nightColor.map(v => v * this.sunIntensity);
this.materialInstance.setFloat3Parameter('nightColor', new Float32Array(nightColorScaled));
this.materialInstance.setFloat4Parameter('shimmerControl', new Float32Array(shimmerUniform));
this.materialInstance.setFloat4Parameter('cloudControl', new Float32Array(cloudUniform));
this.materialInstance.setFloat4Parameter('cloudControl2', new Float32Array(this.cloudControl2));
this.materialInstance.setFloat4Parameter('waterControl', new Float32Array(this.waterControl));
this.materialInstance.setFloat2Parameter('starControl', new Float32Array(this.starControl));
this.materialInstance.setFloatParameter('sunIntensity', physicalSunIntensity);
}
}
+10
View File
@@ -0,0 +1,10 @@
# Result: /Users/mathias/sources/git/filament/out/cmake-release/tools/matc/matc
MATC="../../../../out/cmake-release/tools/matc/matc"
# Navigate to script directory to ensure relative paths work
cd "$(dirname "$0")"
set -e
$MATC -a opengl -p mobile -o assets/simulated_skybox.filamat simulated_skybox.mat
echo "Material recompiled to assets/simulated_skybox.filamat"
File diff suppressed because one or more lines are too long
Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More