Compare commits

..

16 Commits

Author SHA1 Message Date
Mathias Agopian
107f25ca75 random rays 2024-11-22 21:25:22 -08:00
Mathias Agopian
46806735e4 add command line options 2024-11-22 21:25:22 -08:00
Mathias Agopian
c410acb69f make a formal api 2024-11-22 21:25:22 -08:00
Mathias Agopian
cb9eba3b3e more 2024-11-22 21:25:22 -08:00
Mathias Agopian
dcf51ba20e more 2024-11-22 21:25:22 -08:00
Mathias Agopian
73e6ccad96 secondary wip 2024-11-22 21:25:22 -08:00
Mathias Agopian
ad5c409317 more better 2024-11-22 21:25:22 -08:00
Mathias Agopian
db597af272 raytracing 2024-11-22 21:25:22 -08:00
Mathias Agopian
4a46955bfb more 2024-11-22 21:25:22 -08:00
Mathias Agopian
864bc3c1c1 rainbowgen 2024-11-22 21:25:22 -08:00
Mathias Agopian
2da395caf8 rainbowgen 2024-11-22 21:25:22 -08:00
Mathias Agopian
64eb27af8a fix a HwProgram leak related to depth variant pre-caching (#8276)
* fix a HwProgram leak related to depth variant pre-caching

Materials that don't use a custom depth can share the same program for
all depth variants. We take advantage of that by pre-caching the
depths variants when a program is loaded. The depth variants themselves
are owned by the default material which is created first. When a
material is destroyed it skips deletion of those variants which will
be truly destroyed when the default material is destroyed.

Unfortunately, the default material doesn't contain all depth variants,
in particular, it doesn't have the VSM ones (because it's an unlit
material).  On top of that, the way it pre-cached depth variant had
a bug that made it miss some picking variants.

Because of that, these variants were skipped during material destruction
but never actually destroyed, since the default material didn't know
anything about them.

This PR fixes this by making the pre-caching completely lazy. When
any material needs such a "precacheable" variant, it first checks if
the default material has it. If not, it creates the variant, caches it
locally and forwards it to the default material, which implicitly
becomes the owner. Just like before newly created material precache
everything the default material already has.

With this mechanism, it's impossible to have a depth variant without it
also existing in the default material.

This also simplify the non-public invalidate() method, which doesn't
need to populate the pre-cached programs, since this will happen
naturally when needed.

There was also another issue where post-process materials were
handled like regular materials. This didn't cause an problem but was
inefficient since these only have a handful of variants.

* Update filament/src/details/Material.cpp

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

---------

Co-authored-by: Powei Feng <powei@google.com>
2024-11-19 22:38:30 -08:00
Doris Wu
98585bdc30 Disable transparent picking by default 2024-11-19 22:37:51 -08:00
Powei Feng
0803987df3 samples: clean-up automation objects in gltf-viewer (#8285) 2024-11-19 15:38:28 -08:00
Sungun Park
ffd32e9309 Release Filament 1.56.1 2024-11-19 17:20:09 +00:00
Sungun Park
b587028aa5 Bump material version to 56 (#8281)
Fix the material version correctly.
2024-11-19 00:04:15 +00:00
22 changed files with 1473 additions and 118 deletions

View File

@@ -822,6 +822,7 @@ if (IS_HOST_PLATFORM)
endif()
add_subdirectory(${TOOLS}/mipgen)
add_subdirectory(${TOOLS}/normal-blending)
add_subdirectory(${TOOLS}/rainbowgen)
add_subdirectory(${TOOLS}/resgen)
add_subdirectory(${TOOLS}/rgb-to-lmsr)
add_subdirectory(${TOOLS}/roughness-prefilter)

View File

@@ -7,4 +7,3 @@ for next branch cut* header.
appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md).
## Release notes for next branch cut
- vk: fix stage pool gc logic

View File

@@ -31,7 +31,7 @@ repositories {
}
dependencies {
implementation 'com.google.android.filament:filament-android:1.56.0'
implementation 'com.google.android.filament:filament-android:1.56.1'
}
```
@@ -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.56.0'
pod 'Filament', '~> 1.56.1'
```
## Documentation

View File

@@ -7,6 +7,10 @@ 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.56.2
- vk: fix stage pool gc logic
## v1.56.1
## v1.56.0

View File

@@ -1,5 +1,5 @@
GROUP=com.google.android.filament
VERSION_NAME=1.56.0
VERSION_NAME=1.56.1
POM_DESCRIPTION=Real-time physically based rendering engine for Android.

View File

@@ -529,19 +529,31 @@ void FEngine::shutdown() {
mPerViewDescriptorSetLayoutSsrVariant.terminate(mHwDescriptorSetLayoutFactory, driver);
mPerRenderableDescriptorSetLayout.terminate(mHwDescriptorSetLayoutFactory, driver);
driver.destroyRenderPrimitive(mFullScreenTriangleRph);
driver.destroyRenderPrimitive(std::move(mFullScreenTriangleRph));
destroy(mFullScreenTriangleIb);
mFullScreenTriangleIb = nullptr;
destroy(mFullScreenTriangleVb);
mFullScreenTriangleVb = nullptr;
destroy(mDummyMorphTargetBuffer);
mDummyMorphTargetBuffer = nullptr;
destroy(mDefaultIblTexture);
mDefaultIblTexture = nullptr;
destroy(mDefaultIbl);
mDefaultIbl = nullptr;
destroy(mDefaultColorGrading);
mDefaultColorGrading = nullptr;
destroy(mDefaultMaterial);
mDefaultMaterial = nullptr;
destroy(mUnprotectedDummySwapchain);
mUnprotectedDummySwapchain = nullptr;
/*
* clean-up after the user -- we call terminate on each "leaked" object and clear each list.
@@ -558,6 +570,7 @@ void FEngine::shutdown() {
// this must be done after Skyboxes and before materials
destroy(mSkyboxMaterial);
mSkyboxMaterial = nullptr;
cleanupResourceList(std::move(mBufferObjects));
cleanupResourceList(std::move(mIndexBuffers));
@@ -574,12 +587,12 @@ void FEngine::shutdown() {
cleanupResourceListLocked(mFenceListLock, std::move(mFences));
driver.destroyTexture(mDummyOneTexture);
driver.destroyTexture(mDummyOneTextureArray);
driver.destroyTexture(mDummyZeroTexture);
driver.destroyTexture(mDummyZeroTextureArray);
driver.destroyTexture(std::move(mDummyOneTexture));
driver.destroyTexture(std::move(mDummyOneTextureArray));
driver.destroyTexture(std::move(mDummyZeroTexture));
driver.destroyTexture(std::move(mDummyZeroTextureArray));
driver.destroyRenderTarget(mDefaultRenderTarget);
driver.destroyRenderTarget(std::move(mDefaultRenderTarget));
/*
* Shutdown the backend...

View File

@@ -321,11 +321,7 @@ FMaterial::FMaterial(FEngine& engine, const Material::Builder& builder,
parser->getSpecularAntiAliasingThreshold(&mSpecularAntiAliasingThreshold);
}
processBlendingMode(parser);
processSpecializationConstants(engine, builder, parser);
processPushConstants(engine, parser);
processDepthVariants(engine, parser);
processDescriptorSets(engine, parser);
parser->hasCustomDepthShader(&mHasCustomDepthShader);
mPerViewLayoutIndex = ColorPassDescriptorSet::getIndex(
mIsVariantLit,
@@ -333,6 +329,12 @@ FMaterial::FMaterial(FEngine& engine, const Material::Builder& builder,
mRefractionMode == RefractionMode::SCREEN_SPACE,
!(mVariantFilterMask & +UserVariantFilterBit::FOG));
processBlendingMode(parser);
processSpecializationConstants(engine, builder, parser);
processPushConstants(engine, parser);
processDescriptorSets(engine, parser);
precacheDepthVariants(engine);
#if FILAMENT_ENABLE_MATDBG
// Register the material with matdbg.
matdbg::DebugServer* server = downcast(engine).debug.server;
@@ -346,53 +348,21 @@ FMaterial::FMaterial(FEngine& engine, const Material::Builder& builder,
FMaterial::~FMaterial() noexcept = default;
void FMaterial::invalidate(Variant::type_t variantMask, Variant::type_t variantValue) noexcept {
DriverApi& driverApi = mEngine.getDriverApi();
FMaterial const* const pDefaultMaterial = mEngine.getDefaultMaterial();
auto hasDefaultDepthVariant = [pDefaultMaterial](Variant k) {
auto const& end = pDefaultMaterial->mDepthVariants.end();
return end != std::find(pDefaultMaterial->mDepthVariants.begin(), end, k);
};
if (mMaterialDomain == MaterialDomain::SURFACE) {
auto& cachedPrograms = mCachedPrograms;
for (size_t k = 0, n = VARIANT_COUNT; k < n; ++k) {
Variant const variant(k);
if ((k & variantMask) == variantValue) {
if (UTILS_LIKELY(!mIsDefaultMaterial)) {
// The depth variants may be shared with the default material, in which case
// we should not free it now.
bool const isSharedVariant = Variant::isValidDepthVariant(variant) &&
!mHasCustomDepthShader &&
hasDefaultDepthVariant(variant);
if (isSharedVariant) {
// we don't own this variant, skip.
continue;
}
}
driverApi.destroyProgram(cachedPrograms[k]);
cachedPrograms[k].clear();
}
// Note: This API is not public at the moment, so it's okay to have some debugging logs
// and extra checks.
if (mMaterialDomain == MaterialDomain::SURFACE &&
!mIsDefaultMaterial &&
!mHasCustomDepthShader) {
// it would be unsafe to invalidate any of the cached depth variant
if (UTILS_UNLIKELY(!((variantMask & Variant::DEP) && !(variantValue & Variant::DEP)))) {
slog.w << io::hex << "FMaterial::invalidate("
<< +variantMask << ", " << +variantValue
<< ") would corrupt the depth variant cache" << io::endl;
}
if (UTILS_UNLIKELY(!mIsDefaultMaterial && !mHasCustomDepthShader)) {
for (Variant const variant: pDefaultMaterial->mDepthVariants) {
pDefaultMaterial->prepareProgram(variant);
if (!cachedPrograms[variant.key]) {
cachedPrograms[variant.key] = pDefaultMaterial->getProgram(variant);
}
}
}
} else if (mMaterialDomain == MaterialDomain::POST_PROCESS) {
auto& cachedPrograms = mCachedPrograms;
for (size_t k = 0, n = POST_PROCESS_VARIANT_COUNT; k < n; ++k) {
if ((k & variantMask) == variantValue) {
driverApi.destroyProgram(cachedPrograms[k]);
cachedPrograms[k].clear();
}
}
} else if (mMaterialDomain == MaterialDomain::COMPUTE) {
// TODO: handle compute variants if any
variantMask |= Variant::DEP;
variantValue &= ~Variant::DEP;
}
destroyPrograms(mEngine, variantMask, variantValue);
}
void FMaterial::terminate(FEngine& engine) {
@@ -632,11 +602,41 @@ Program FMaterial::getProgramWithVariants(
}
void FMaterial::createAndCacheProgram(Program&& p, Variant variant) const noexcept {
assert_invariant(!mCachedPrograms[variant.key]);
auto program = mEngine.getDriverApi().createProgram(std::move(p));
mEngine.getDriverApi().setDebugTag(program.getId(), mName);
FEngine const& engine = mEngine;
DriverApi& driverApi = mEngine.getDriverApi();
// Check if the default material has this program cached
if (mMaterialDomain == MaterialDomain::SURFACE &&
!mIsDefaultMaterial && !mHasCustomDepthShader &&
Variant::isValidDepthVariant(variant)) {
FMaterial const* const pDefaultMaterial = engine.getDefaultMaterial();
if (pDefaultMaterial) {
auto program = pDefaultMaterial->mCachedPrograms[variant.key];
if (program) {
mCachedPrograms[variant.key] = program;
return;
}
}
}
auto program = driverApi.createProgram(std::move(p));
driverApi.setDebugTag(program.getId(), mName);
assert_invariant(program);
mCachedPrograms[variant.key] = program;
// If the default material doesn't already have this program cached, and all caching conditions
// are met (Surface Domain and no custom depth shader), cache it now.
// New Materials will inherit these program automatically.
if (mMaterialDomain == MaterialDomain::SURFACE &&
!mIsDefaultMaterial && !mHasCustomDepthShader &&
Variant::isValidDepthVariant(variant)) {
FMaterial const* const pDefaultMaterial = engine.getDefaultMaterial();
if (pDefaultMaterial && !pDefaultMaterial->mCachedPrograms[variant.key]) {
// set the tag to the default material name
driverApi.setDebugTag(program.getId(), mName);
pDefaultMaterial->mCachedPrograms[variant.key] = program;
}
}
}
size_t FMaterial::getParameters(ParameterInfo* parameters, size_t count) const noexcept {
@@ -741,29 +741,76 @@ void FMaterial::onQueryCallback(void* userdata, VariantList* pVariants) {
#endif // FILAMENT_ENABLE_MATDBG
void FMaterial::destroyPrograms(FEngine& engine) {
void FMaterial::destroyPrograms(FEngine& engine,
Variant::type_t const variantMask, Variant::type_t const variantValue) {
DriverApi& driverApi = engine.getDriverApi();
auto& cachedPrograms = mCachedPrograms;
auto hasDefaultDepthVariant = [pDefaultMaterial = engine.getDefaultMaterial()](Variant k) {
auto const& end = pDefaultMaterial->mDepthVariants.end();
return end != std::find(pDefaultMaterial->mDepthVariants.begin(), end, k);
};
switch (mMaterialDomain) {
case MaterialDomain::SURFACE: {
if (mIsDefaultMaterial || mHasCustomDepthShader) {
// default material or we have custom depth shaders, we destroy all variants
for (size_t k = 0, n = VARIANT_COUNT; k < n; ++k) {
if ((k & variantMask) == variantValue) {
// Only destroy if the handle is valid. Not strictly needed, but we have a lot
// of variants, and this generates traffic in the command queue.
if (cachedPrograms[k]) {
driverApi.destroyProgram(std::move(cachedPrograms[k]));
}
}
}
} else {
// The depth variants may be shared with the default material, in which case
// we should not free them now.
for (size_t k = 0, n = VARIANT_COUNT; k < n; ++k) {
const Variant variant(k);
if (!mIsDefaultMaterial) {
// The depth variants may be shared with the default material, in which case
// we should not free it now.
bool const isSharedVariant = Variant::isValidDepthVariant(variant) &&
!mHasCustomDepthShader && hasDefaultDepthVariant(variant);
if (isSharedVariant) {
// we don't own this variant, skip.
continue;
// During Engine::shutdown(), auto-cleanup destroys the default material first,
// so this can be null, but this is only used for debugging.
UTILS_UNUSED_IN_RELEASE
auto UTILS_NULLABLE pDefaultMaterial = engine.getDefaultMaterial();
for (size_t k = 0, n = VARIANT_COUNT; k < n; ++k) {
if ((k & variantMask) == variantValue) {
// Only destroy if the handle is valid. Not strictly needed, but we have a lot
// of variant, and this generates traffic in the command queue.
if (cachedPrograms[k]) {
if (Variant::isValidDepthVariant(Variant(k))) {
// By construction this should always be true, because this
// field is populated only when a material creates the program
// for this variant.
// During Engine::shutdown, auto-cleanup destroys the
// default material first
assert_invariant(!pDefaultMaterial ||
pDefaultMaterial->mCachedPrograms[k]);
// we don't own this variant, skip, but clear the entry.
cachedPrograms[k].clear();
continue;
}
driverApi.destroyProgram(std::move(cachedPrograms[k]));
}
}
}
}
break;
}
case MaterialDomain::POST_PROCESS: {
for (size_t k = 0, n = POST_PROCESS_VARIANT_COUNT; k < n; ++k) {
if ((k & variantMask) == variantValue) {
// Only destroy if the handle is valid. Not strictly needed, but we have a lot
// of variant, and this generates traffic in the command queue.
if (cachedPrograms[k]) {
driverApi.destroyProgram(std::move(cachedPrograms[k]));
}
}
}
break;
}
case MaterialDomain::COMPUTE: {
// Compute programs don't have variants
driverApi.destroyProgram(std::move(cachedPrograms[0]));
break;
}
driverApi.destroyProgram(cachedPrograms[k]);
cachedPrograms[k].clear();
}
}
@@ -1028,34 +1075,17 @@ void FMaterial::processPushConstants(FEngine& engine, MaterialParser const* pars
});
}
void FMaterial::processDepthVariants(FEngine& engine, MaterialParser const* const parser) {
parser->hasCustomDepthShader(&mHasCustomDepthShader);
if (UTILS_UNLIKELY(mIsDefaultMaterial)) {
assert_invariant(mMaterialDomain == MaterialDomain::SURFACE);
filaflat::MaterialChunk const& materialChunk{ parser->getMaterialChunk() };
auto variants = FixedCapacityVector<Variant>::with_capacity(materialChunk.getShaderCount());
materialChunk.visitShaders([&variants](
ShaderModel, Variant variant, ShaderStage) {
if (Variant::isValidDepthVariant(variant)) {
variants.push_back(variant);
}
});
std::sort(variants.begin(), variants.end(),
[](Variant lhs, Variant rhs) { return lhs.key < rhs.key; });
auto pos = std::unique(variants.begin(), variants.end());
variants.resize(std::distance(variants.begin(), pos));
std::swap(mDepthVariants, variants);
}
if (mMaterialDomain == MaterialDomain::SURFACE) {
if (UTILS_UNLIKELY(!mIsDefaultMaterial && !mHasCustomDepthShader)) {
FMaterial const* const pDefaultMaterial = engine.getDefaultMaterial();
auto& cachedPrograms = mCachedPrograms;
for (Variant const variant: pDefaultMaterial->mDepthVariants) {
pDefaultMaterial->prepareProgram(variant);
cachedPrograms[variant.key] = pDefaultMaterial->getProgram(variant);
}
void FMaterial::precacheDepthVariants(FEngine& engine) {
// if possible pre-cache all depth variants from the default material
if (mMaterialDomain == MaterialDomain::SURFACE &&
!mIsDefaultMaterial &&
!mHasCustomDepthShader) {
FMaterial const* const pDefaultMaterial = engine.getDefaultMaterial();
assert_invariant(pDefaultMaterial);
auto const allDepthVariants = VariantUtils::getDepthVariants();
for (auto const variant: allDepthVariants) {
assert_invariant(Variant::isValidDepthVariant(variant));
mCachedPrograms[variant.key] = pDefaultMaterial->mCachedPrograms[variant.key];
}
}
}

View File

@@ -218,7 +218,9 @@ public:
uint32_t generateMaterialInstanceId() const noexcept { return mMaterialInstanceId++; }
void destroyPrograms(FEngine& engine);
void destroyPrograms(FEngine& engine,
Variant::type_t variantMask = 0,
Variant::type_t variantValue = 0);
// return the id of a specialization constant specified by name for this material
std::optional<uint32_t> getSpecializationConstantId(std::string_view name) const noexcept ;
@@ -282,7 +284,7 @@ private:
void processPushConstants(FEngine& engine, MaterialParser const* parser);
void processDepthVariants(FEngine& engine, MaterialParser const* parser);
void precacheDepthVariants(FEngine& engine);
void processDescriptorSets(FEngine& engine, MaterialParser const* parser);
@@ -331,7 +333,6 @@ private:
SamplerInterfaceBlock mSamplerInterfaceBlock;
BufferInterfaceBlock mUniformInterfaceBlock;
SubpassInfo mSubpassInfo;
utils::FixedCapacityVector<Variant> mDepthVariants; // only populated with default material
using BindingUniformInfoContainer = utils::FixedCapacityVector<std::tuple<
uint8_t, utils::CString, backend::Program::UniformInfo>>;

View File

@@ -534,7 +534,7 @@ private:
Viewport mViewport;
bool mCulling = true;
bool mFrontFaceWindingInverted = false;
bool mIsTransparentPickingEnabled = true;
bool mIsTransparentPickingEnabled = false;
FRenderTarget* mRenderTarget = nullptr;

View File

@@ -1,12 +1,12 @@
Pod::Spec.new do |spec|
spec.name = "Filament"
spec.version = "1.56.0"
spec.version = "1.56.1"
spec.license = { :type => "Apache 2.0", :file => "LICENSE" }
spec.homepage = "https://google.github.io/filament"
spec.authors = "Google LLC."
spec.summary = "Filament is a real-time physically based rendering engine for Android, iOS, Windows, Linux, macOS, and WASM/WebGL."
spec.platform = :ios, "11.0"
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.56.0/filament-v1.56.0-ios.tgz" }
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.56.1/filament-v1.56.1-ios.tgz" }
# Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon.
spec.pod_target_xcconfig = {

View File

@@ -28,7 +28,7 @@
namespace filament {
// update this when a new version of filament wouldn't work with older materials
static constexpr size_t MATERIAL_VERSION = 55;
static constexpr size_t MATERIAL_VERSION = 56;
/**
* Supported shading models

View File

@@ -19,6 +19,7 @@
#include <filament/MaterialEnums.h>
#include <utils/compiler.h>
#include <utils/bitset.h>
#include <utils/Slice.h>
@@ -271,6 +272,8 @@ namespace VariantUtils {
utils::Slice<Variant> getLitVariants() noexcept UTILS_PURE;
// list of unlit variants
utils::Slice<Variant> getUnlitVariants() noexcept UTILS_PURE;
// list of depth variants
utils::Slice<Variant> getDepthVariants() noexcept UTILS_PURE;
}
} // namespace filament

View File

@@ -16,8 +16,15 @@
#include <private/filament/Variant.h>
#include <filament/MaterialEnums.h>
#include <utils/Slice.h>
#include <array>
#include <stddef.h>
#include <stdint.h>
namespace filament {
Variant Variant::filterUserVariant(
@@ -65,6 +72,8 @@ Variant Variant::filterUserVariant(
namespace details {
namespace {
// Compile-time variant count for lit and unlit
constexpr inline size_t variant_count(bool lit) noexcept {
size_t count = 0;
@@ -81,6 +90,17 @@ constexpr inline size_t variant_count(bool lit) noexcept {
return count;
}
constexpr inline size_t depth_variant_count() noexcept {
size_t count = 0;
for (size_t i = 0; i < VARIANT_COUNT; i++) {
Variant const variant(i);
if (Variant::isValidDepthVariant(variant)) {
count++;
}
}
return count;
}
// Compile-time variant list for lit and unlit
template<bool LIT>
constexpr auto get_variants() noexcept {
@@ -98,9 +118,18 @@ constexpr auto get_variants() noexcept {
}
return variants;
}
static auto const gLitVariants{ details::get_variants<true>() };
static auto const gUnlitVariants{ details::get_variants<false>() };
constexpr auto get_depth_variants() noexcept {
std::array<Variant, depth_variant_count()> variants;
size_t count = 0;
for (size_t i = 0; i < VARIANT_COUNT; i++) {
Variant const variant(i);
if (Variant::isValidDepthVariant(variant)) {
variants[count++] = variant;
}
}
return variants;
}
// Below are compile time sanity-check tests
constexpr inline bool reserved_is_not_valid() noexcept {
@@ -163,6 +192,13 @@ constexpr inline size_t fragment_variant_count() noexcept {
return count;
}
} // anonymous namespace
static auto const gLitVariants{ details::get_variants<true>() };
static auto const gUnlitVariants{ details::get_variants<false>() };
static auto const gDepthVariants{ details::get_depth_variants() };
static_assert(reserved_is_not_valid());
static_assert(reserved_variant_count() == 160);
static_assert(valid_variant_count() == 96);
@@ -182,6 +218,10 @@ utils::Slice<Variant> getUnlitVariants() noexcept {
return { details::gUnlitVariants.data(), details::gUnlitVariants.size() };
}
utils::Slice<Variant> getDepthVariants() noexcept {
return { details::gDepthVariants.data(), details::gDepthVariants.size() };
}
}; // VariantUtils
} // namespace filament

View File

@@ -1043,6 +1043,8 @@ int main(int argc, char** argv) {
delete app.resourceLoader;
delete app.stbDecoder;
delete app.ktxDecoder;
delete app.automationSpec;
delete app.automationEngine;
AssetLoader::destroy(&app.assetLoader);
};

View File

@@ -0,0 +1,30 @@
cmake_minimum_required(VERSION 3.19)
project(rainbowgen)
set(TARGET rainbowgen)
# ==================================================================================================
# Source files
# ==================================================================================================
set(SRCS src/rainbowgen.cpp
src/RainbowGenerator.cpp)
# ==================================================================================================
# Target definitions
# ==================================================================================================
add_executable(${TARGET} ${SRCS})
target_link_libraries(${TARGET} PRIVATE math utils getopt image imageio)
set_target_properties(${TARGET} PROPERTIES FOLDER Tools)
# =================================================================================================
# Licenses
# ==================================================================================================
set(MODULE_LICENSES getopt)
set(GENERATION_ROOT ${CMAKE_CURRENT_BINARY_DIR}/generated)
list_licenses(${GENERATION_ROOT}/licenses/licenses.inc ${MODULE_LICENSES})
target_include_directories(${TARGET} PRIVATE ${GENERATION_ROOT})
# ==================================================================================================
# Installation
# ==================================================================================================
install(TARGETS ${TARGET} RUNTIME DESTINATION bin)

596
tools/rainbowgen/src/CIE.h Normal file
View File

@@ -0,0 +1,596 @@
/*
* Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef TNT_CIE_H
#define TNT_CIE_H
#include <math/vec3.h>
#include <stddef.h>
using namespace filament::math;
// CIE 2006 10-deg color matching functions (CMFs), from 390nm to 830nm, at 1nm intervals
//
// Data source:
// http://www.cvrl.org/ciexyzpr.htm
const size_t CIE_XYZ_START = 390;
const size_t CIE_XYZ_COUNT = 441;
const float3 CIE_XYZ[CIE_XYZ_COUNT] = { // NOLINT
{ 2.952420E-03f, 4.076779E-04f, 1.318752E-02f },
{ 3.577275E-03f, 4.977769E-04f, 1.597879E-02f },
{ 4.332146E-03f, 6.064754E-04f, 1.935758E-02f },
{ 5.241609E-03f, 7.370040E-04f, 2.343758E-02f },
{ 6.333902E-03f, 8.929388E-04f, 2.835021E-02f },
{ 7.641137E-03f, 1.078166E-03f, 3.424588E-02f },
{ 9.199401E-03f, 1.296816E-03f, 4.129467E-02f },
{ 1.104869E-02f, 1.553159E-03f, 4.968641E-02f },
{ 1.323262E-02f, 1.851463E-03f, 5.962964E-02f },
{ 1.579791E-02f, 2.195795E-03f, 7.134926E-02f },
{ 1.879338E-02f, 2.589775E-03f, 8.508254E-02f },
{ 2.226949E-02f, 3.036799E-03f, 1.010753E-01f },
{ 2.627978E-02f, 3.541926E-03f, 1.195838E-01f },
{ 3.087862E-02f, 4.111422E-03f, 1.408647E-01f },
{ 3.611890E-02f, 4.752618E-03f, 1.651644E-01f },
{ 4.204986E-02f, 5.474207E-03f, 1.927065E-01f },
{ 4.871256E-02f, 6.285034E-03f, 2.236782E-01f },
{ 5.612868E-02f, 7.188068E-03f, 2.582109E-01f },
{ 6.429866E-02f, 8.181786E-03f, 2.963632E-01f },
{ 7.319818E-02f, 9.260417E-03f, 3.381018E-01f },
{ 8.277331E-02f, 1.041303E-02f, 3.832822E-01f },
{ 9.295327E-02f, 1.162642E-02f, 4.316884E-01f },
{ 1.037137E-01f, 1.289884E-02f, 4.832440E-01f },
{ 1.150520E-01f, 1.423442E-02f, 5.379345E-01f },
{ 1.269771E-01f, 1.564080E-02f, 5.957740E-01f },
{ 1.395127E-01f, 1.712968E-02f, 6.568187E-01f },
{ 1.526661E-01f, 1.871265E-02f, 7.210459E-01f },
{ 1.663054E-01f, 2.038394E-02f, 7.878635E-01f },
{ 1.802197E-01f, 2.212935E-02f, 8.563391E-01f },
{ 1.941448E-01f, 2.392985E-02f, 9.253017E-01f },
{ 2.077647E-01f, 2.576133E-02f, 9.933444E-01f },
{ 2.207911E-01f, 2.760156E-02f, 1.059178E+00f },
{ 2.332355E-01f, 2.945513E-02f, 1.122832E+00f },
{ 2.452462E-01f, 3.133884E-02f, 1.184947E+00f },
{ 2.570397E-01f, 3.327575E-02f, 1.246476E+00f },
{ 2.688989E-01f, 3.529554E-02f, 1.308674E+00f },
{ 2.810677E-01f, 3.742705E-02f, 1.372628E+00f },
{ 2.933967E-01f, 3.967137E-02f, 1.437661E+00f },
{ 3.055933E-01f, 4.201998E-02f, 1.502449E+00f },
{ 3.173165E-01f, 4.446166E-02f, 1.565456E+00f },
{ 3.281798E-01f, 4.698226E-02f, 1.624940E+00f },
{ 3.378678E-01f, 4.956742E-02f, 1.679488E+00f },
{ 3.465097E-01f, 5.221219E-02f, 1.729668E+00f },
{ 3.543953E-01f, 5.491387E-02f, 1.776755E+00f },
{ 3.618655E-01f, 5.766919E-02f, 1.822228E+00f },
{ 3.693084E-01f, 6.047429E-02f, 1.867751E+00f },
{ 3.770107E-01f, 6.332195E-02f, 1.914504E+00f },
{ 3.846850E-01f, 6.619271E-02f, 1.961055E+00f },
{ 3.918591E-01f, 6.906185E-02f, 2.005136E+00f },
{ 3.980192E-01f, 7.190190E-02f, 2.044296E+00f },
{ 4.026189E-01f, 7.468288E-02f, 2.075946E+00f },
{ 4.052637E-01f, 7.738452E-02f, 2.098231E+00f },
{ 4.062482E-01f, 8.003601E-02f, 2.112591E+00f },
{ 4.060660E-01f, 8.268524E-02f, 2.121427E+00f },
{ 4.052283E-01f, 8.538745E-02f, 2.127239E+00f },
{ 4.042529E-01f, 8.820537E-02f, 2.132574E+00f },
{ 4.034808E-01f, 9.118925E-02f, 2.139093E+00f },
{ 4.025362E-01f, 9.431041E-02f, 2.144815E+00f },
{ 4.008675E-01f, 9.751346E-02f, 2.146832E+00f },
{ 3.979327E-01f, 1.007349E-01f, 2.142250E+00f },
{ 3.932139E-01f, 1.039030E-01f, 2.128264E+00f },
{ 3.864108E-01f, 1.069639E-01f, 2.103205E+00f },
{ 3.779513E-01f, 1.099676E-01f, 2.069388E+00f },
{ 3.684176E-01f, 1.129992E-01f, 2.030030E+00f },
{ 3.583473E-01f, 1.161541E-01f, 1.988178E+00f },
{ 3.482214E-01f, 1.195389E-01f, 1.946651E+00f },
{ 3.383830E-01f, 1.232503E-01f, 1.907521E+00f },
{ 3.288309E-01f, 1.273047E-01f, 1.870689E+00f },
{ 3.194977E-01f, 1.316964E-01f, 1.835578E+00f },
{ 3.103345E-01f, 1.364178E-01f, 1.801657E+00f },
{ 3.013112E-01f, 1.414586E-01f, 1.768440E+00f },
{ 2.923754E-01f, 1.468003E-01f, 1.735338E+00f },
{ 2.833273E-01f, 1.524002E-01f, 1.701254E+00f },
{ 2.739463E-01f, 1.582021E-01f, 1.665053E+00f },
{ 2.640352E-01f, 1.641400E-01f, 1.625712E+00f },
{ 2.534221E-01f, 1.701373E-01f, 1.582342E+00f },
{ 2.420135E-01f, 1.761233E-01f, 1.534439E+00f },
{ 2.299346E-01f, 1.820896E-01f, 1.482544E+00f },
{ 2.173617E-01f, 1.880463E-01f, 1.427438E+00f },
{ 2.044672E-01f, 1.940065E-01f, 1.369876E+00f },
{ 1.914176E-01f, 1.999859E-01f, 1.310576E+00f },
{ 1.783672E-01f, 2.060054E-01f, 1.250226E+00f },
{ 1.654407E-01f, 2.120981E-01f, 1.189511E+00f },
{ 1.527391E-01f, 2.183041E-01f, 1.129050E+00f },
{ 1.403439E-01f, 2.246686E-01f, 1.069379E+00f },
{ 1.283167E-01f, 2.312426E-01f, 1.010952E+00f },
{ 1.167124E-01f, 2.380741E-01f, 9.541809E-01f },
{ 1.056121E-01f, 2.451798E-01f, 8.995253E-01f },
{ 9.508569E-02f, 2.525682E-01f, 8.473720E-01f },
{ 8.518206E-02f, 2.602479E-01f, 7.980093E-01f },
{ 7.593120E-02f, 2.682271E-01f, 7.516389E-01f },
{ 6.733159E-02f, 2.765005E-01f, 7.082645E-01f },
{ 5.932018E-02f, 2.850035E-01f, 6.673867E-01f },
{ 5.184106E-02f, 2.936475E-01f, 6.284798E-01f },
{ 4.486119E-02f, 3.023319E-01f, 5.911174E-01f },
{ 3.836770E-02f, 3.109438E-01f, 5.549619E-01f },
{ 3.237296E-02f, 3.194105E-01f, 5.198843E-01f },
{ 2.692095E-02f, 3.278683E-01f, 4.862772E-01f },
{ 2.204070E-02f, 3.365263E-01f, 4.545497E-01f },
{ 1.773951E-02f, 3.456176E-01f, 4.249955E-01f },
{ 1.400745E-02f, 3.554018E-01f, 3.978114E-01f },
{ 1.082291E-02f, 3.660893E-01f, 3.730218E-01f },
{ 8.168996E-03f, 3.775857E-01f, 3.502618E-01f },
{ 6.044623E-03f, 3.896960E-01f, 3.291407E-01f },
{ 4.462638E-03f, 4.021947E-01f, 3.093356E-01f },
{ 3.446810E-03f, 4.148227E-01f, 2.905816E-01f },
{ 3.009513E-03f, 4.273539E-01f, 2.726773E-01f },
{ 3.090744E-03f, 4.398206E-01f, 2.555143E-01f },
{ 3.611221E-03f, 4.523360E-01f, 2.390188E-01f },
{ 4.491435E-03f, 4.650298E-01f, 2.231335E-01f },
{ 5.652072E-03f, 4.780482E-01f, 2.078158E-01f },
{ 7.035322E-03f, 4.915173E-01f, 1.930407E-01f },
{ 8.669631E-03f, 5.054224E-01f, 1.788089E-01f },
{ 1.060755E-02f, 5.197057E-01f, 1.651287E-01f },
{ 1.290468E-02f, 5.343012E-01f, 1.520103E-01f },
{ 1.561956E-02f, 5.491344E-01f, 1.394643E-01f },
{ 1.881640E-02f, 5.641302E-01f, 1.275353E-01f },
{ 2.256923E-02f, 5.792416E-01f, 1.163771E-01f },
{ 2.694456E-02f, 5.944264E-01f, 1.061161E-01f },
{ 3.199910E-02f, 6.096388E-01f, 9.682266E-02f },
{ 3.778185E-02f, 6.248296E-01f, 8.852389E-02f },
{ 4.430635E-02f, 6.399656E-01f, 8.118263E-02f },
{ 5.146516E-02f, 6.550943E-01f, 7.463132E-02f },
{ 5.912224E-02f, 6.702903E-01f, 6.870644E-02f },
{ 6.714220E-02f, 6.856375E-01f, 6.327834E-02f },
{ 7.538941E-02f, 7.012292E-01f, 5.824484E-02f },
{ 8.376697E-02f, 7.171103E-01f, 5.353812E-02f },
{ 9.233581E-02f, 7.330917E-01f, 4.914863E-02f },
{ 1.011940E-01f, 7.489041E-01f, 4.507511E-02f },
{ 1.104362E-01f, 7.642530E-01f, 4.131175E-02f },
{ 1.201511E-01f, 7.788199E-01f, 3.784916E-02f },
{ 1.303960E-01f, 7.923410E-01f, 3.467234E-02f },
{ 1.411310E-01f, 8.048510E-01f, 3.175471E-02f },
{ 1.522944E-01f, 8.164747E-01f, 2.907029E-02f },
{ 1.638288E-01f, 8.273520E-01f, 2.659651E-02f },
{ 1.756832E-01f, 8.376358E-01f, 2.431375E-02f },
{ 1.878114E-01f, 8.474653E-01f, 2.220677E-02f },
{ 2.001621E-01f, 8.568868E-01f, 2.026852E-02f },
{ 2.126822E-01f, 8.659242E-01f, 1.849246E-02f },
{ 2.253199E-01f, 8.746041E-01f, 1.687084E-02f },
{ 2.380254E-01f, 8.829552E-01f, 1.539505E-02f },
{ 2.507787E-01f, 8.910274E-01f, 1.405450E-02f },
{ 2.636778E-01f, 8.989495E-01f, 1.283354E-02f },
{ 2.768607E-01f, 9.068753E-01f, 1.171754E-02f },
{ 2.904792E-01f, 9.149652E-01f, 1.069415E-02f },
{ 3.046991E-01f, 9.233858E-01f, 9.753000E-03f },
{ 3.196485E-01f, 9.322325E-01f, 8.886096E-03f },
{ 3.352447E-01f, 9.412862E-01f, 8.089323E-03f },
{ 3.513290E-01f, 9.502378E-01f, 7.359131E-03f },
{ 3.677148E-01f, 9.587647E-01f, 6.691736E-03f },
{ 3.841856E-01f, 9.665325E-01f, 6.083223E-03f },
{ 4.005312E-01f, 9.732504E-01f, 5.529423E-03f },
{ 4.166669E-01f, 9.788415E-01f, 5.025504E-03f },
{ 4.325420E-01f, 9.832867E-01f, 4.566879E-03f },
{ 4.481063E-01f, 9.865720E-01f, 4.149405E-03f },
{ 4.633109E-01f, 9.886887E-01f, 3.769336E-03f },
{ 4.781440E-01f, 9.897056E-01f, 3.423302E-03f },
{ 4.927483E-01f, 9.899849E-01f, 3.108313E-03f },
{ 5.073315E-01f, 9.899624E-01f, 2.821650E-03f },
{ 5.221315E-01f, 9.900731E-01f, 2.560830E-03f },
{ 5.374170E-01f, 9.907500E-01f, 2.323578E-03f },
{ 5.534217E-01f, 9.922826E-01f, 2.107847E-03f },
{ 5.701242E-01f, 9.943837E-01f, 1.911867E-03f },
{ 5.874093E-01f, 9.966221E-01f, 1.734006E-03f },
{ 6.051269E-01f, 9.985649E-01f, 1.572736E-03f },
{ 6.230892E-01f, 9.997775E-01f, 1.426627E-03f },
{ 6.410999E-01f, 9.999440E-01f, 1.294325E-03f },
{ 6.590659E-01f, 9.992200E-01f, 1.174475E-03f },
{ 6.769436E-01f, 9.978793E-01f, 1.065842E-03f },
{ 6.947143E-01f, 9.961934E-01f, 9.673215E-04f },
{ 7.123849E-01f, 9.944304E-01f, 8.779264E-04f },
{ 7.299978E-01f, 9.927831E-01f, 7.967847E-04f },
{ 7.476478E-01f, 9.911578E-01f, 7.231502E-04f },
{ 7.654250E-01f, 9.893925E-01f, 6.563501E-04f },
{ 7.834009E-01f, 9.873288E-01f, 5.957678E-04f },
{ 8.016277E-01f, 9.848127E-01f, 5.408385E-04f },
{ 8.201041E-01f, 9.817253E-01f, 4.910441E-04f },
{ 8.386843E-01f, 9.780714E-01f, 4.459046E-04f },
{ 8.571936E-01f, 9.738860E-01f, 4.049826E-04f },
{ 8.754652E-01f, 9.692028E-01f, 3.678818E-04f },
{ 8.933408E-01f, 9.640545E-01f, 3.342429E-04f },
{ 9.106772E-01f, 9.584409E-01f, 3.037407E-04f },
{ 9.273554E-01f, 9.522379E-01f, 2.760809E-04f },
{ 9.432502E-01f, 9.452968E-01f, 2.509970E-04f },
{ 9.582244E-01f, 9.374773E-01f, 2.282474E-04f },
{ 9.721304E-01f, 9.286495E-01f, 2.076129E-04f },
{ 9.849237E-01f, 9.187953E-01f, 1.888948E-04f },
{ 9.970067E-01f, 9.083014E-01f, 1.719127E-04f },
{ 1.008907E+00f, 8.976352E-01f, 1.565030E-04f },
{ 1.021163E+00f, 8.872401E-01f, 1.425177E-04f },
{ 1.034327E+00f, 8.775360E-01f, 1.298230E-04f },
{ 1.048753E+00f, 8.687920E-01f, 1.182974E-04f },
{ 1.063937E+00f, 8.607474E-01f, 1.078310E-04f },
{ 1.079166E+00f, 8.530233E-01f, 9.832455E-05f },
{ 1.093723E+00f, 8.452535E-01f, 8.968787E-05f },
{ 1.106886E+00f, 8.370838E-01f, 8.183954E-05f },
{ 1.118106E+00f, 8.282409E-01f, 7.470582E-05f },
{ 1.127493E+00f, 8.187320E-01f, 6.821991E-05f },
{ 1.135317E+00f, 8.086352E-01f, 6.232132E-05f },
{ 1.141838E+00f, 7.980296E-01f, 5.695534E-05f },
{ 1.147304E+00f, 7.869950E-01f, 5.207245E-05f },
{ 1.151897E+00f, 7.756040E-01f, 4.762781E-05f },
{ 1.155582E+00f, 7.638996E-01f, 4.358082E-05f },
{ 1.158284E+00f, 7.519157E-01f, 3.989468E-05f },
{ 1.159934E+00f, 7.396832E-01f, 3.653612E-05f },
{ 1.160477E+00f, 7.272309E-01f, 3.347499E-05f },
{ 1.159890E+00f, 7.145878E-01f, 3.068400E-05f },
{ 1.158259E+00f, 7.017926E-01f, 2.813839E-05f },
{ 1.155692E+00f, 6.888866E-01f, 2.581574E-05f },
{ 1.152293E+00f, 6.759103E-01f, 2.369574E-05f },
{ 1.148163E+00f, 6.629035E-01f, 2.175998E-05f },
{ 1.143345E+00f, 6.498911E-01f, 1.999179E-05f },
{ 1.137685E+00f, 6.368410E-01f, 1.837603E-05f },
{ 1.130993E+00f, 6.237092E-01f, 1.689896E-05f },
{ 1.123097E+00f, 6.104541E-01f, 1.554815E-05f },
{ 1.113846E+00f, 5.970375E-01f, 1.431231E-05f },
{ 1.103152E+00f, 5.834395E-01f, 1.318119E-05f },
{ 1.091121E+00f, 5.697044E-01f, 1.214548E-05f },
{ 1.077902E+00f, 5.558892E-01f, 1.119673E-05f },
{ 1.063644E+00f, 5.420475E-01f, 1.032727E-05f },
{ 1.048485E+00f, 5.282296E-01f, 9.530130E-06f },
{ 1.032546E+00f, 5.144746E-01f, 8.798979E-06f },
{ 1.015870E+00f, 5.007881E-01f, 8.128065E-06f },
{ 9.984859E-01f, 4.871687E-01f, 7.512160E-06f },
{ 9.804227E-01f, 4.736160E-01f, 6.946506E-06f },
{ 9.617111E-01f, 4.601308E-01f, 6.426776E-06f },
{ 9.424119E-01f, 4.467260E-01f, 0.000000E+00f },
{ 9.227049E-01f, 4.334589E-01f, 0.000000E+00f },
{ 9.027804E-01f, 4.203919E-01f, 0.000000E+00f },
{ 8.828123E-01f, 4.075810E-01f, 0.000000E+00f },
{ 8.629581E-01f, 3.950755E-01f, 0.000000E+00f },
{ 8.432731E-01f, 3.828894E-01f, 0.000000E+00f },
{ 8.234742E-01f, 3.709190E-01f, 0.000000E+00f },
{ 8.032342E-01f, 3.590447E-01f, 0.000000E+00f },
{ 7.822715E-01f, 3.471615E-01f, 0.000000E+00f },
{ 7.603498E-01f, 3.351794E-01f, 0.000000E+00f },
{ 7.373739E-01f, 3.230562E-01f, 0.000000E+00f },
{ 7.136470E-01f, 3.108859E-01f, 0.000000E+00f },
{ 6.895336E-01f, 2.987840E-01f, 0.000000E+00f },
{ 6.653567E-01f, 2.868527E-01f, 0.000000E+00f },
{ 6.413984E-01f, 2.751807E-01f, 0.000000E+00f },
{ 6.178723E-01f, 2.638343E-01f, 0.000000E+00f },
{ 5.948484E-01f, 2.528330E-01f, 0.000000E+00f },
{ 5.723600E-01f, 2.421835E-01f, 0.000000E+00f },
{ 5.504353E-01f, 2.318904E-01f, 0.000000E+00f },
{ 5.290979E-01f, 2.219564E-01f, 0.000000E+00f },
{ 5.083728E-01f, 2.123826E-01f, 0.000000E+00f },
{ 4.883006E-01f, 2.031698E-01f, 0.000000E+00f },
{ 4.689171E-01f, 1.943179E-01f, 0.000000E+00f },
{ 4.502486E-01f, 1.858250E-01f, 0.000000E+00f },
{ 4.323126E-01f, 1.776882E-01f, 0.000000E+00f },
{ 4.150790E-01f, 1.698926E-01f, 0.000000E+00f },
{ 3.983657E-01f, 1.623822E-01f, 0.000000E+00f },
{ 3.819846E-01f, 1.550986E-01f, 0.000000E+00f },
{ 3.657821E-01f, 1.479918E-01f, 0.000000E+00f },
{ 3.496358E-01f, 1.410203E-01f, 0.000000E+00f },
{ 3.334937E-01f, 1.341614E-01f, 0.000000E+00f },
{ 3.174776E-01f, 1.274401E-01f, 0.000000E+00f },
{ 3.017298E-01f, 1.208887E-01f, 0.000000E+00f },
{ 2.863684E-01f, 1.145345E-01f, 0.000000E+00f },
{ 2.714900E-01f, 1.083996E-01f, 0.000000E+00f },
{ 2.571632E-01f, 1.025007E-01f, 0.000000E+00f },
{ 2.434102E-01f, 9.684588E-02f, 0.000000E+00f },
{ 2.302389E-01f, 9.143944E-02f, 0.000000E+00f },
{ 2.176527E-01f, 8.628318E-02f, 0.000000E+00f },
{ 2.056507E-01f, 8.137687E-02f, 0.000000E+00f },
{ 1.942251E-01f, 7.671708E-02f, 0.000000E+00f },
{ 1.833530E-01f, 7.229404E-02f, 0.000000E+00f },
{ 1.730097E-01f, 6.809696E-02f, 0.000000E+00f },
{ 1.631716E-01f, 6.411549E-02f, 0.000000E+00f },
{ 1.538163E-01f, 6.033976E-02f, 0.000000E+00f },
{ 1.449230E-01f, 5.676054E-02f, 0.000000E+00f },
{ 1.364729E-01f, 5.336992E-02f, 0.000000E+00f },
{ 1.284483E-01f, 5.016027E-02f, 0.000000E+00f },
{ 1.208320E-01f, 4.712405E-02f, 0.000000E+00f },
{ 1.136072E-01f, 4.425383E-02f, 0.000000E+00f },
{ 1.067579E-01f, 4.154205E-02f, 0.000000E+00f },
{ 1.002685E-01f, 3.898042E-02f, 0.000000E+00f },
{ 9.412394E-02f, 3.656091E-02f, 0.000000E+00f },
{ 8.830929E-02f, 3.427597E-02f, 0.000000E+00f },
{ 8.281010E-02f, 3.211852E-02f, 0.000000E+00f },
{ 7.761208E-02f, 3.008192E-02f, 0.000000E+00f },
{ 7.270064E-02f, 2.816001E-02f, 0.000000E+00f },
{ 6.806167E-02f, 2.634698E-02f, 0.000000E+00f },
{ 6.368176E-02f, 2.463731E-02f, 0.000000E+00f },
{ 5.954815E-02f, 2.302574E-02f, 0.000000E+00f },
{ 5.564917E-02f, 2.150743E-02f, 0.000000E+00f },
{ 5.197543E-02f, 2.007838E-02f, 0.000000E+00f },
{ 4.851788E-02f, 1.873474E-02f, 0.000000E+00f },
{ 4.526737E-02f, 1.747269E-02f, 0.000000E+00f },
{ 4.221473E-02f, 1.628841E-02f, 0.000000E+00f },
{ 3.934954E-02f, 1.517767E-02f, 0.000000E+00f },
{ 3.665730E-02f, 1.413473E-02f, 0.000000E+00f },
{ 3.412407E-02f, 1.315408E-02f, 0.000000E+00f },
{ 3.173768E-02f, 1.223092E-02f, 0.000000E+00f },
{ 2.948752E-02f, 1.136106E-02f, 0.000000E+00f },
{ 2.736717E-02f, 1.054190E-02f, 0.000000E+00f },
{ 2.538113E-02f, 9.775050E-03f, 0.000000E+00f },
{ 2.353356E-02f, 9.061962E-03f, 0.000000E+00f },
{ 2.182558E-02f, 8.402962E-03f, 0.000000E+00f },
{ 2.025590E-02f, 7.797457E-03f, 0.000000E+00f },
{ 1.881892E-02f, 7.243230E-03f, 0.000000E+00f },
{ 1.749930E-02f, 6.734381E-03f, 0.000000E+00f },
{ 1.628167E-02f, 6.265001E-03f, 0.000000E+00f },
{ 1.515301E-02f, 5.830085E-03f, 0.000000E+00f },
{ 1.410230E-02f, 5.425391E-03f, 0.000000E+00f },
{ 1.312106E-02f, 5.047634E-03f, 0.000000E+00f },
{ 1.220509E-02f, 4.695140E-03f, 0.000000E+00f },
{ 1.135114E-02f, 4.366592E-03f, 0.000000E+00f },
{ 1.055593E-02f, 4.060685E-03f, 0.000000E+00f },
{ 9.816228E-03f, 3.776140E-03f, 0.000000E+00f },
{ 9.128517E-03f, 3.511578E-03f, 0.000000E+00f },
{ 8.488116E-03f, 3.265211E-03f, 0.000000E+00f },
{ 7.890589E-03f, 3.035344E-03f, 0.000000E+00f },
{ 7.332061E-03f, 2.820496E-03f, 0.000000E+00f },
{ 6.809147E-03f, 2.619372E-03f, 0.000000E+00f },
{ 6.319204E-03f, 2.430960E-03f, 0.000000E+00f },
{ 5.861036E-03f, 2.254796E-03f, 0.000000E+00f },
{ 5.433624E-03f, 2.090489E-03f, 0.000000E+00f },
{ 5.035802E-03f, 1.937586E-03f, 0.000000E+00f },
{ 4.666298E-03f, 1.795595E-03f, 0.000000E+00f },
{ 4.323750E-03f, 1.663989E-03f, 0.000000E+00f },
{ 4.006709E-03f, 1.542195E-03f, 0.000000E+00f },
{ 3.713708E-03f, 1.429639E-03f, 0.000000E+00f },
{ 3.443294E-03f, 1.325752E-03f, 0.000000E+00f },
{ 3.194041E-03f, 1.229980E-03f, 0.000000E+00f },
{ 2.964424E-03f, 1.141734E-03f, 0.000000E+00f },
{ 2.752492E-03f, 1.060269E-03f, 0.000000E+00f },
{ 2.556406E-03f, 9.848854E-04f, 0.000000E+00f },
{ 2.374564E-03f, 9.149703E-04f, 0.000000E+00f },
{ 2.205568E-03f, 8.499903E-04f, 0.000000E+00f },
{ 2.048294E-03f, 7.895158E-04f, 0.000000E+00f },
{ 1.902113E-03f, 7.333038E-04f, 0.000000E+00f },
{ 1.766485E-03f, 6.811458E-04f, 0.000000E+00f },
{ 1.640857E-03f, 6.328287E-04f, 0.000000E+00f },
{ 1.524672E-03f, 5.881375E-04f, 0.000000E+00f },
{ 1.417322E-03f, 5.468389E-04f, 0.000000E+00f },
{ 1.318031E-03f, 5.086349E-04f, 0.000000E+00f },
{ 1.226059E-03f, 4.732403E-04f, 0.000000E+00f },
{ 1.140743E-03f, 4.404016E-04f, 0.000000E+00f },
{ 1.061495E-03f, 4.098928E-04f, 0.000000E+00f },
{ 9.877949E-04f, 3.815137E-04f, 0.000000E+00f },
{ 9.191847E-04f, 3.550902E-04f, 0.000000E+00f },
{ 8.552568E-04f, 3.304668E-04f, 0.000000E+00f },
{ 7.956433E-04f, 3.075030E-04f, 0.000000E+00f },
{ 7.400120E-04f, 2.860718E-04f, 0.000000E+00f },
{ 6.880980E-04f, 2.660718E-04f, 0.000000E+00f },
{ 6.397864E-04f, 2.474586E-04f, 0.000000E+00f },
{ 5.949726E-04f, 2.301919E-04f, 0.000000E+00f },
{ 5.535291E-04f, 2.142225E-04f, 0.000000E+00f },
{ 5.153113E-04f, 1.994949E-04f, 0.000000E+00f },
{ 4.801234E-04f, 1.859336E-04f, 0.000000E+00f },
{ 4.476245E-04f, 1.734067E-04f, 0.000000E+00f },
{ 4.174846E-04f, 1.617865E-04f, 0.000000E+00f },
{ 3.894221E-04f, 1.509641E-04f, 0.000000E+00f },
{ 3.631969E-04f, 1.408466E-04f, 0.000000E+00f },
{ 3.386279E-04f, 1.313642E-04f, 0.000000E+00f },
{ 3.156452E-04f, 1.224905E-04f, 0.000000E+00f },
{ 2.941966E-04f, 1.142060E-04f, 0.000000E+00f },
{ 2.742235E-04f, 1.064886E-04f, 0.000000E+00f },
{ 2.556624E-04f, 9.931439E-05f, 0.000000E+00f },
{ 2.384390E-04f, 9.265512E-05f, 0.000000E+00f },
{ 2.224525E-04f, 8.647225E-05f, 0.000000E+00f },
{ 2.076036E-04f, 8.072780E-05f, 0.000000E+00f },
{ 1.938018E-04f, 7.538716E-05f, 0.000000E+00f },
{ 1.809649E-04f, 7.041878E-05f, 0.000000E+00f },
{ 1.690167E-04f, 6.579338E-05f, 0.000000E+00f },
{ 1.578839E-04f, 6.148250E-05f, 0.000000E+00f },
{ 1.474993E-04f, 5.746008E-05f, 0.000000E+00f },
{ 1.378026E-04f, 5.370272E-05f, 0.000000E+00f },
{ 1.287394E-04f, 5.018934E-05f, 0.000000E+00f },
{ 1.202644E-04f, 4.690245E-05f, 0.000000E+00f },
{ 1.123502E-04f, 4.383167E-05f, 0.000000E+00f },
{ 1.049725E-04f, 4.096780E-05f, 0.000000E+00f },
{ 9.810596E-05f, 3.830123E-05f, 0.000000E+00f },
{ 9.172477E-05f, 3.582218E-05f, 0.000000E+00f },
{ 8.579861E-05f, 3.351903E-05f, 0.000000E+00f },
{ 8.028174E-05f, 3.137419E-05f, 0.000000E+00f },
{ 7.513013E-05f, 2.937068E-05f, 0.000000E+00f },
{ 7.030565E-05f, 2.749380E-05f, 0.000000E+00f },
{ 6.577532E-05f, 2.573083E-05f, 0.000000E+00f },
{ 6.151508E-05f, 2.407249E-05f, 0.000000E+00f },
{ 5.752025E-05f, 2.251704E-05f, 0.000000E+00f },
{ 5.378813E-05f, 2.106350E-05f, 0.000000E+00f },
{ 5.031350E-05f, 1.970991E-05f, 0.000000E+00f },
{ 4.708916E-05f, 1.845353E-05f, 0.000000E+00f },
{ 4.410322E-05f, 1.728979E-05f, 0.000000E+00f },
{ 4.133150E-05f, 1.620928E-05f, 0.000000E+00f },
{ 3.874992E-05f, 1.520262E-05f, 0.000000E+00f },
{ 3.633762E-05f, 1.426169E-05f, 0.000000E+00f },
{ 3.407653E-05f, 1.337946E-05f, 0.000000E+00f },
{ 3.195242E-05f, 1.255038E-05f, 0.000000E+00f },
{ 2.995808E-05f, 1.177169E-05f, 0.000000E+00f },
{ 2.808781E-05f, 1.104118E-05f, 0.000000E+00f },
{ 2.633581E-05f, 1.035662E-05f, 0.000000E+00f },
{ 2.469630E-05f, 9.715798E-06f, 0.000000E+00f },
{ 2.316311E-05f, 9.116316E-06f, 0.000000E+00f },
{ 2.172855E-05f, 8.555201E-06f, 0.000000E+00f },
{ 2.038519E-05f, 8.029561E-06f, 0.000000E+00f },
{ 1.912625E-05f, 7.536768E-06f, 0.000000E+00f },
{ 1.794555E-05f, 7.074424E-06f, 0.000000E+00f },
{ 1.683776E-05f, 6.640464E-06f, 0.000000E+00f },
{ 1.579907E-05f, 6.233437E-06f, 0.000000E+00f },
{ 1.482604E-05f, 5.852035E-06f, 0.000000E+00f },
{ 1.391527E-05f, 5.494963E-06f, 0.000000E+00f },
{ 1.306345E-05f, 5.160948E-06f, 0.000000E+00f },
{ 1.226720E-05f, 4.848687E-06f, 0.000000E+00f },
{ 1.152279E-05f, 4.556705E-06f, 0.000000E+00f },
{ 1.082663E-05f, 4.283580E-06f, 0.000000E+00f },
{ 1.017540E-05f, 4.027993E-06f, 0.000000E+00f },
{ 9.565993E-06f, 3.788729E-06f, 0.000000E+00f },
{ 8.995405E-06f, 3.564599E-06f, 0.000000E+00f },
{ 8.460253E-06f, 3.354285E-06f, 0.000000E+00f },
{ 7.957382E-06f, 3.156557E-06f, 0.000000E+00f },
{ 7.483997E-06f, 2.970326E-06f, 0.000000E+00f },
{ 7.037621E-06f, 2.794625E-06f, 0.000000E+00f },
{ 6.616311E-06f, 2.628701E-06f, 0.000000E+00f },
{ 6.219265E-06f, 2.472248E-06f, 0.000000E+00f },
{ 5.845844E-06f, 2.325030E-06f, 0.000000E+00f },
{ 5.495311E-06f, 2.186768E-06f, 0.000000E+00f },
{ 5.166853E-06f, 2.057152E-06f, 0.000000E+00f },
{ 4.859511E-06f, 1.935813E-06f, 0.000000E+00f },
{ 4.571973E-06f, 1.822239E-06f, 0.000000E+00f },
{ 4.302920E-06f, 1.715914E-06f, 0.000000E+00f },
{ 4.051121E-06f, 1.616355E-06f, 0.000000E+00f },
{ 3.815429E-06f, 1.523114E-06f, 0.000000E+00f },
{ 3.594719E-06f, 1.435750E-06f, 0.000000E+00f },
{ 3.387736E-06f, 1.353771E-06f, 0.000000E+00f },
{ 3.193301E-06f, 1.276714E-06f, 0.000000E+00f },
{ 3.010363E-06f, 1.204166E-06f, 0.000000E+00f },
{ 2.837980E-06f, 1.135758E-06f, 0.000000E+00f },
{ 2.675365E-06f, 1.071181E-06f, 0.000000E+00f },
{ 2.522020E-06f, 1.010243E-06f, 0.000000E+00f },
{ 2.377511E-06f, 9.527779E-07f, 0.000000E+00f },
{ 2.241417E-06f, 8.986224E-07f, 0.000000E+00f },
{ 2.113325E-06f, 8.476168E-07f, 0.000000E+00f },
{ 1.992830E-06f, 7.996052E-07f, 0.000000E+00f },
{ 1.879542E-06f, 7.544361E-07f, 0.000000E+00f },
{ 1.773083E-06f, 7.119624E-07f, 0.000000E+00f },
{ 1.673086E-06f, 6.720421E-07f, 0.000000E+00f },
{ 1.579199E-06f, 6.345380E-07f, 0.000000E+00f }
};
// CIE Standard Illuminant D65 relative spectral power distribution,
// from 300nm to 830, at 5nm intervals
//
// Data source:
// https://en.wikipedia.org/wiki/Illuminant_D65
// https://cielab.xyz/pdf/CIE_sel_colorimetric_tables.xls
const size_t CIE_D65_INTERVAL = 5;
const size_t CIE_D65_START = 300;
const size_t CIE_D65_END = 830;
const size_t CIE_D65_COUNT = 107;
const float CIE_D65[CIE_D65_COUNT] = {
0.0341f,
1.6643f,
3.2945f,
11.7652f,
20.2360f,
28.6447f,
37.0535f,
38.5011f,
39.9488f,
42.4302f,
44.9117f,
45.7750f,
46.6383f,
49.3637f,
52.0891f,
51.0323f,
49.9755f,
52.3118f,
54.6482f,
68.7015f,
82.7549f,
87.1204f,
91.4860f,
92.4589f,
93.4318f,
90.0570f,
86.6823f,
95.7736f,
104.865f,
110.936f,
117.008f,
117.410f,
117.812f,
116.336f,
114.861f,
115.392f,
115.923f,
112.367f,
108.811f,
109.082f,
109.354f,
108.578f,
107.802f,
106.296f,
104.790f,
106.239f,
107.689f,
106.047f,
104.405f,
104.225f,
104.046f,
102.023f,
100.000f,
98.1671f,
96.3342f,
96.0611f,
95.7880f,
92.2368f,
88.6856f,
89.3459f,
90.0062f,
89.8026f,
89.5991f,
88.6489f,
87.6987f,
85.4936f,
83.2886f,
83.4939f,
83.6992f,
81.8630f,
80.0268f,
80.1207f,
80.2146f,
81.2462f,
82.2778f,
80.2810f,
78.2842f,
74.0027f,
69.7213f,
70.6652f,
71.6091f,
72.9790f,
74.3490f,
67.9765f,
61.6040f,
65.7448f,
69.8856f,
72.4863f,
75.0870f,
69.3398f,
63.5927f,
55.0054f,
46.4182f,
56.6118f,
66.8054f,
65.0941f,
63.3828f,
63.8434f,
64.3040f,
61.8779f,
59.4519f,
55.7054f,
51.9590f,
54.6998f,
57.4406f,
58.8765f,
60.3125f
};
#endif //TNT_CIE_H

View File

@@ -0,0 +1,181 @@
/*
* Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "RainbowGenerator.h"
#include "CIE.h"
#include "rainbow.h"
#include "srgb.h"
#include <utils/JobSystem.h>
#include <math/vec3.h>
#include <algorithm>
#include <cmath>
#include <random>
#include <vector>
#include <iostream>
#include <stdint.h>
#include <stddef.h>
using namespace utils;
using namespace filament::math;
using namespace rainbow;
RainbowGenerator::RainbowGenerator() = default;
RainbowGenerator::~RainbowGenerator() = default;
RainbowGenerator& RainbowGenerator::lut(uint32_t count) noexcept {
mLutSize = count;
return *this;
}
RainbowGenerator& RainbowGenerator::cosine(bool enabled) noexcept {
mCosine = enabled;
return *this;
}
RainbowGenerator& RainbowGenerator::minDeviation(radian_t min) noexcept {
mMinDeviation = min;
return *this;
}
RainbowGenerator& RainbowGenerator::maxDeviation(radian_t max) noexcept {
mMaxDeviation = max;
return *this;
}
RainbowGenerator& RainbowGenerator::samples(uint32_t count) noexcept {
mSampleCount = count;
return *this;
}
RainbowGenerator& RainbowGenerator::temperature(celcius_t t) noexcept {
mAirTemperature = t;
return *this;
}
RainbowGenerator& RainbowGenerator::sunArc(radian_t arc) noexcept {
mSunArc = arc;
return *this;
}
Rainbow RainbowGenerator::build(JobSystem&) {
uint32_t const lutsize = mLutSize;
float const minDeviation = mMinDeviation;
float const maxDeviation = mMaxDeviation;
// The sun appears as about a degree in the sky
std::default_random_engine rng{ std::random_device{}() };
std::uniform_real_distribution<float> distImpactAngle{ -mSunArc * 0.5f, mSunArc * 0.5f };
std::uniform_real_distribution<float> distImpact{ -1.0f, 1.0f };
std::uniform_int_distribution<int> distWavelengthIndex{ 0, CIE_XYZ_COUNT - 1 };
int32_t const count = int32_t(mSampleCount);
float C0, C1;
if (mCosine) {
float const min = 1.0f - std::cos(minDeviation);
float const max = 1.0f - std::cos(maxDeviation);
C0 = -1.0f / (max - min);
C1 = (1.0f - min) / (max - min);
} else {
C0 = 1.0f / (maxDeviation - minDeviation);
C1 = -minDeviation * C0;
}
Rainbow rainbow{
.s = C0,
.o = C1,
.scale = 0.0f,
.data = std::vector<Rainbow::linear_sRGB_t>(lutsize, Rainbow::linear_sRGB_t{})
};
for (size_t i = 0; i < count; i++) {
// pick a random ray
float const impact = distImpact(rng);
radian_t const impactAngle = distImpactAngle(rng);
size_t const j = distWavelengthIndex(rng);
float const w = float(CIE_XYZ_START + j);
float const n = indexOfRefraction(w);
// incident = asin(impact) - impactAngle. However, because we're integrating
// over all impact values at all impact-angles, we don't need to subtract
// the impactAngle, because there will always be another {impact, impact-angle}
// that will produce the same result
radian_t const incident = std::asin(impact);
radian_t const refracted = refractFromImpact(n, impact);
// water-air fresnel is equal to 1 - air-water fresnel, so we only need to
// air-water non-polarized fresnel
// intensity reflected upon entering the droplet (air-water)
float const Raw = fresnel(incident, refracted);
// intensity reflected upon exiting the droplet (water-air)
float const Rwa = fresnel(refracted, incident);
// intensity transmitted at air-water interface
float const Taw = 1 - Raw;
// intensity transmitted at water-air interface
float const Twa = 1 - Rwa;
for (int const bounces: { 1, 2 }) {
radian_t const phi = rainbow::deviation(bounces, incident, refracted) - impactAngle;
if (phi >= minDeviation && phi < maxDeviation) {
float const v = mCosine ? std::cos(phi) : phi;
size_t const index = size_t(std::floor(float(lutsize) * (v * C0 + C1)));
if (index < lutsize) {
float const T = Taw * std::pow(Rwa, float(bounces)) * Twa;
rainbow.data[index] += T * CIE_XYZ[j];
}
}
}
}
// convert to sRGB linear and find the largest value
for (float3& c : rainbow.data) {
c = srgb::XYZ_to_sRGB(c);
rainbow.scale = std::max({ rainbow.scale, c.r, c.g, c.b });
}
// rescale everything to the [0, 1] range
for (float3& c : rainbow.data) {
c *= 1.0f / rainbow.scale;
}
// integration scale factor (118.518 comes from CIE_XYZ[])
double const s = (double(2 * lutsize) /
(double(maxDeviation - minDeviation) * double(count * CIE_XYZ_COUNT))) / 118.518;
rainbow.scale *= float(s);
//std::cout << 1/rainbow.scale << std::endl;
return rainbow;
}
//vec3 sun = frameUniforms.lightColorIntensity.rgb *
// (frameUniforms.lightColorIntensity.a * (4.0 * PI));
//vec3 direction = normalize(variable_eyeDirection.xyz);
//float cosAngle = dot(direction, -frameUniforms.lightDirection);
//float angle = acos(cosAngle) * 180.0 / 3.14159;
//float first = 35.0;
//float range = (60.0 - 35.0);
//float s = saturate((angle - first)/range);
//int index = int(s * 255);
//fragColor.rgb += rainbow[index]*sun;

View File

@@ -0,0 +1,82 @@
/*
* Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef TNT_RAINBOWGENERATOR_H
#define TNT_RAINBOWGENERATOR_H
#include <stdint.h>
#include <stddef.h>
#include <math/vec3.h>
#include <math/scalar.h>
#include <vector>
namespace utils {
class JobSystem;
};
struct Rainbow {
using linear_sRGB_t = filament::math::float3;
float s; // input parameter scale factor
float o; // input parameter offset
float scale; // output scale factor
std::vector<linear_sRGB_t> data;
};
class RainbowGenerator {
public:
using radian_t = float;
using celcius_t = float;
RainbowGenerator();
~RainbowGenerator();
// LUT size
RainbowGenerator& lut(uint32_t count) noexcept;
// LUT indexed by cosine
RainbowGenerator& cosine(bool enabled) noexcept;
// min deviation
RainbowGenerator& minDeviation(radian_t min) noexcept;
// max deviation
RainbowGenerator& maxDeviation(radian_t max) noexcept;
// number of samples for the calculation
RainbowGenerator& samples(uint32_t count) noexcept;
// air temperature
RainbowGenerator& temperature(celcius_t t) noexcept;
// sun arc
RainbowGenerator& sunArc(radian_t arc) noexcept;
// bulid the rainbow LUT
Rainbow build(utils::JobSystem& js);
private:
size_t mLutSize = 256;
radian_t mMinDeviation = 30.0f * filament::math::f::DEG_TO_RAD;
radian_t mMaxDeviation = 60.0f * filament::math::f::DEG_TO_RAD;
radian_t mSunArc = 1.0f * filament::math::f::DEG_TO_RAD;
uint32_t mSampleCount = 10'000'000;
float mAirTemperature = 20.0f;
bool mCosine = false;
};
#endif //TNT_RAINBOWGENERATOR_H

View File

@@ -0,0 +1,98 @@
/*
* Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <cmath>
namespace rainbow {
using namespace filament::math;
using radian_t = float;
using nanometer_t = float;
using celcius_t = float;
// fresnel at water droplet interface
inline float fresnel(radian_t Bi, radian_t Bt) noexcept {
float const r_pe = std::sin(Bi - Bt) / std::sin(Bi + Bt);
float const r_pa = std::tan(Bi - Bt) / std::tan(Bi + Bt);
float const r = 0.5f * (r_pe * r_pe + r_pa * r_pa);
return r;
}
// refraction angle
inline radian_t refract(float n, radian_t incident) noexcept {
return std::asin(std::sin(incident) / n);
}
inline radian_t refractFromImpact(float n, float impact) noexcept {
return std::asin(impact / n);
}
// max incident angle for a given index of refraction
inline radian_t maxIncidentAngle(float n) noexcept {
return std::acos(std::sqrt((n * n - 1.0f) / 3.0f));
}
// deviation: angle between the ray exiting the droplet and the ground
// impactAngle: angle between the ground and the incident ray
inline radian_t deviation(int bounces, radian_t incident, radian_t refracted) noexcept {
// each bounce adds 180 degrees as well as 2*refracted
return ((bounces & 1) ? 0.0f : f::PI) +
float(2 + 2 * bounces) * refracted - 2.0f * incident;
}
// index of refraction for a wavelength
inline float indexOfRefraction(nanometer_t wavelength) noexcept {
celcius_t const temperature = 20;
constexpr float a0 = 0.244257733;
constexpr float a1 = 0.00974634476;
constexpr float a2 = -0.00373234996;
constexpr float a3 = 0.000268678472;
constexpr float a4 = 0.0015892057;
constexpr float a5 = 0.00245934259;
constexpr float a6 = 0.90070492;
constexpr float a7 = -0.0166626219;
constexpr float Ts = 273.15; // [K]
constexpr float Ps = 1000; // [kg/m3]
constexpr float Ls = 589; // [nm]
constexpr float Lir = 5.432937;
constexpr float Luv = 0.229202;
float const T = Ts + temperature; // temperature
float const P = 998.2; // FIXME: this also depends on the temperature (20)
float const L = wavelength;
float const T_ = T / Ts;
float const P_ = P / Ps;
float const L_ = L / Ls;
float const R =
a0 +
a1 * P_ +
a2 * T_ +
a3 * L_ * L_ * T_ +
a4 / (L_ * L_) +
a5 / ((L_ * L_) - (Luv * Luv)) +
a6 / ((L_ * L_) - (Lir * Lir)) +
a7 * P_ * P_;
float const n = std::sqrt((1.0f + 2.0f * R * P_) / (1.0f - R * P_));
return n;
}
} // namespace rainbow

View File

@@ -0,0 +1,222 @@
/*
* Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "RainbowGenerator.h"
#include <image/LinearImage.h>
#include <imageio/ImageEncoder.h>
#include <utils/Path.h>
#include <utils/JobSystem.h>
#include <math/vec3.h>
#include <math/scalar.h>
#include <getopt/getopt.h>
#include <fstream>
#include <iostream>
#include <string>
#include <optional>
#include <stdio.h>
#include <stdlib.h>
using namespace filament::math;
using namespace image;
static const char* USAGE = R"TXT(
RAINBOWGEN generates a rainbow:
Usage:
RAINBOWGEN [options] output
Options:
--help, -h
Print this message
--license, -L
Print copyright and license information
--format=[exr|hdr|psd|rgbm|rgb32f|png|dds], -f [format]
Specify output file format.
--cosine, -c
LUT indexed by 1-cos(deviation)
--size=integer, -s integer
Size of the output rainbow texture, 256 by default.
--min-deviation=float, -m float
Minimum deviation in degrees encoded in the texture, 30 by default.
--max-deviation=float, -M float
Maximum deviation in degrees encoded in the texture, 60 by default.
--samples=integer, -S integer
Number of samples for the simulation, 10,000,000 by default.
Private use only:
--debug, -d
Increases the height of the output texture.
Examples:
RAINBOWGEN -h
RAINBOWGEN rainbow.png
)TXT";
static void printUsage(const char* name) {
std::string const execName(utils::Path(name).getName());
const std::string from("RAINBOWGEN");
std::string usage(USAGE);
for (size_t pos = usage.find(from); pos != std::string::npos; pos = usage.find(from, pos)) {
usage.replace(pos, from.length(), execName);
}
puts(usage.c_str());
}
static void license() {
static const char *license[] = {
#include "licenses/licenses.inc"
nullptr
};
const char **p = &license[0];
while (*p)
std::cout << *p++ << std::endl;
}
static std::optional<image::ImageEncoder::Format> g_format;
static bool g_debug = false;
static int handleArguments(int argc, char* argv[], RainbowGenerator& builder) {
static constexpr const char* OPTSTR = "hLs:m:M:S:f:dc";
static const struct option OPTIONS[] = {
{ "help", no_argument, nullptr, 'h' },
{ "license", no_argument, nullptr, 'L' },
{ "cosine", no_argument, nullptr, 'c' },
{ "format", required_argument, nullptr, 'f' },
{ "size", required_argument, nullptr, 's' },
{ "min-deviation", required_argument, nullptr, 'm' },
{ "max-deviation", required_argument, nullptr, 'M' },
{ "samples", required_argument, nullptr, 'S' },
{ "debug", no_argument, nullptr, 'd' },
{ nullptr, 0, nullptr, 0 } // termination of the option list
};
int opt;
int optionIndex = 0;
while ((opt = getopt_long(argc, argv, OPTSTR, OPTIONS, &optionIndex)) >= 0) {
std::string const arg(optarg ? optarg : "");
switch (opt) {
default:
case 'h':
printUsage(argv[0]);
exit(0);
case 'L':
license();
exit(0);
case 'f':
if (arg == "png") {
g_format = ImageEncoder::Format::PNG_LINEAR;
} else if (arg == "hdr") {
g_format = ImageEncoder::Format::HDR;
} else if (arg == "rgbm") {
g_format = ImageEncoder::Format::RGBM;
} else if (arg == "rgb32f") {
g_format = ImageEncoder::Format::RGB_10_11_11_REV;
} else if (arg == "exr") {
g_format = ImageEncoder::Format::EXR;
} else if (arg == "psd") {
g_format = ImageEncoder::Format::PSD;
} else if (arg == "dds") {
g_format = ImageEncoder::Format::DDS_LINEAR;
}
break;
case 'c':
builder.cosine(true);
break;
case 's':
builder.lut(stoul(arg));
break;
case 'm':
builder.minDeviation(stof(arg) * f::DEG_TO_RAD);
break;
case 'M':
builder.maxDeviation(stof(arg) * f::DEG_TO_RAD);
break;
case 'S':
builder.samples(stoul(arg));
break;
case 'd':
g_debug = true;
break;
}
}
return optind;
}
int main(int argc, char* argv[]) {
using namespace filament::math;
using namespace image;
// process options
RainbowGenerator builder;
const int optionIndex = handleArguments(argc, argv, builder);
const int numArgs = argc - optionIndex;
if (numArgs < 1) {
printUsage(argv[0]);
return 1;
}
utils::Path const path{ argv[optionIndex] };
// actual computation
utils::JobSystem js;
js.adopt();
Rainbow const rainbow = builder.build(js);
// save result
size_t const angleCount = rainbow.data.size();
size_t const height = g_debug ? 32 : 1;
LinearImage image(angleCount, height, 3);
float3* const pData = reinterpret_cast<float3*>(image.getPixelRef());
for (size_t index = 0; index < angleCount; index++) {
float3 const c = rainbow.data[index];
//printf("vec3( %g, %g, %g ),\n", c.r, c.g, c.b);
for (int y = 0; y < height; y++) {
pData[angleCount * y + index] = c;
}
}
// choose a format, either the one specified or from the name, PNG by default
ImageEncoder::Format const format =
g_format.has_value() ? g_format.value() :
ImageEncoder::chooseFormat(path.getPath(), true);
// if we don't have an extension, pick one from the format
std::string filename = path.getPath();
if (path.getExtension().empty()) {
std::string const ext = ImageEncoder::chooseExtension(format);
filename += ext;
}
std::ofstream outputStream(filename, std::ios::binary | std::ios::trunc);
ImageEncoder::encode(outputStream, format, image, "", "");
}

View File

@@ -0,0 +1,53 @@
/*
* Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <math/mat3.h>
#include <math/vec3.h>
#include <cmath>
namespace srgb {
using namespace filament::math;
inline constexpr float3 XYZ_to_sRGB(float3 const v) noexcept {
constexpr mat3f const XYZ_sRGB{
3.2404542f, -0.9692660f, 0.0556434f,
-1.5371385f, 1.8760108f, -0.2040259f,
-0.4985314f, 0.0415560f, 1.0572252f
};
return XYZ_sRGB * v;
}
inline float3 linear_to_sRGB(float3 c) noexcept {
for (auto i = 0; i < c.size(); i++) {
c[i] = (c[i] <= 0.0031308f) ?
c[i] * 12.92f : (std::pow(c[i], 1.0f / 2.4f) * 1.055f) - 0.055f;
}
return c;
}
inline float3 sRGB_to_linear(float3 c) noexcept {
for (auto i = 0; i < c.size(); i++) {
c[i] = (c[i] <= 0.04045f) ?
c[i] / 12.92f : std::pow((c[i] + 0.055f) / 1.055f, 2.4f);
}
return c;
}
} // namespace rainbow

View File

@@ -1,6 +1,6 @@
{
"name": "filament",
"version": "1.56.0",
"version": "1.56.1",
"description": "Real-time physically based rendering engine",
"main": "filament.js",
"module": "filament.js",