Compare commits

..

1 Commits

Author SHA1 Message Date
Powei Feng
36c76daf34 material: fix depth variant leak
The default material does not cover all of the depth variants,
and so for the client material's depth variants (with no custom
depth shader), we need to check if the program is allocated for
the material or if it is actually part of the default material.
2024-11-14 15:13:48 -08:00
22 changed files with 118 additions and 1473 deletions

View File

@@ -822,7 +822,6 @@ 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,3 +7,4 @@ 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.1'
implementation 'com.google.android.filament:filament-android:1.56.0'
}
```
@@ -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.1'
pod 'Filament', '~> 1.56.0'
```
## Documentation

View File

@@ -7,10 +7,6 @@ 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.1
VERSION_NAME=1.56.0
POM_DESCRIPTION=Real-time physically based rendering engine for Android.

View File

@@ -529,31 +529,19 @@ void FEngine::shutdown() {
mPerViewDescriptorSetLayoutSsrVariant.terminate(mHwDescriptorSetLayoutFactory, driver);
mPerRenderableDescriptorSetLayout.terminate(mHwDescriptorSetLayoutFactory, driver);
driver.destroyRenderPrimitive(std::move(mFullScreenTriangleRph));
driver.destroyRenderPrimitive(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.
@@ -570,7 +558,6 @@ void FEngine::shutdown() {
// this must be done after Skyboxes and before materials
destroy(mSkyboxMaterial);
mSkyboxMaterial = nullptr;
cleanupResourceList(std::move(mBufferObjects));
cleanupResourceList(std::move(mIndexBuffers));
@@ -587,12 +574,12 @@ void FEngine::shutdown() {
cleanupResourceListLocked(mFenceListLock, std::move(mFences));
driver.destroyTexture(std::move(mDummyOneTexture));
driver.destroyTexture(std::move(mDummyOneTextureArray));
driver.destroyTexture(std::move(mDummyZeroTexture));
driver.destroyTexture(std::move(mDummyZeroTextureArray));
driver.destroyTexture(mDummyOneTexture);
driver.destroyTexture(mDummyOneTextureArray);
driver.destroyTexture(mDummyZeroTexture);
driver.destroyTexture(mDummyZeroTextureArray);
driver.destroyRenderTarget(std::move(mDefaultRenderTarget));
driver.destroyRenderTarget(mDefaultRenderTarget);
/*
* Shutdown the backend...

View File

@@ -321,7 +321,11 @@ FMaterial::FMaterial(FEngine& engine, const Material::Builder& builder,
parser->getSpecularAntiAliasingThreshold(&mSpecularAntiAliasingThreshold);
}
parser->hasCustomDepthShader(&mHasCustomDepthShader);
processBlendingMode(parser);
processSpecializationConstants(engine, builder, parser);
processPushConstants(engine, parser);
processDepthVariants(engine, parser);
processDescriptorSets(engine, parser);
mPerViewLayoutIndex = ColorPassDescriptorSet::getIndex(
mIsVariantLit,
@@ -329,12 +333,6 @@ 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;
@@ -348,21 +346,53 @@ FMaterial::FMaterial(FEngine& engine, const Material::Builder& builder,
FMaterial::~FMaterial() noexcept = default;
void FMaterial::invalidate(Variant::type_t variantMask, Variant::type_t variantValue) noexcept {
// 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;
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();
}
}
variantMask |= Variant::DEP;
variantValue &= ~Variant::DEP;
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
}
destroyPrograms(mEngine, variantMask, variantValue);
}
void FMaterial::terminate(FEngine& engine) {
@@ -602,41 +632,11 @@ Program FMaterial::getProgramWithVariants(
}
void FMaterial::createAndCacheProgram(Program&& p, Variant variant) const noexcept {
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(!mCachedPrograms[variant.key]);
auto program = mEngine.getDriverApi().createProgram(std::move(p));
mEngine.getDriverApi().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,76 +741,29 @@ void FMaterial::onQueryCallback(void* userdata, VariantList* pVariants) {
#endif // FILAMENT_ENABLE_MATDBG
void FMaterial::destroyPrograms(FEngine& engine,
Variant::type_t const variantMask, Variant::type_t const variantValue) {
void FMaterial::destroyPrograms(FEngine& engine) {
DriverApi& driverApi = engine.getDriverApi();
auto& cachedPrograms = mCachedPrograms;
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.
auto hasDefaultDepthVariant = [pDefaultMaterial = engine.getDefaultMaterial()](Variant k) {
auto const& end = pDefaultMaterial->mDepthVariants.end();
return end != std::find(pDefaultMaterial->mDepthVariants.begin(), end, k);
};
// 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]));
}
}
}
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;
}
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();
}
}
@@ -1075,17 +1028,34 @@ void FMaterial::processPushConstants(FEngine& engine, MaterialParser const* pars
});
}
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];
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);
}
}
}
}

View File

@@ -218,9 +218,7 @@ public:
uint32_t generateMaterialInstanceId() const noexcept { return mMaterialInstanceId++; }
void destroyPrograms(FEngine& engine,
Variant::type_t variantMask = 0,
Variant::type_t variantValue = 0);
void destroyPrograms(FEngine& engine);
// return the id of a specialization constant specified by name for this material
std::optional<uint32_t> getSpecializationConstantId(std::string_view name) const noexcept ;
@@ -284,7 +282,7 @@ private:
void processPushConstants(FEngine& engine, MaterialParser const* parser);
void precacheDepthVariants(FEngine& engine);
void processDepthVariants(FEngine& engine, MaterialParser const* parser);
void processDescriptorSets(FEngine& engine, MaterialParser const* parser);
@@ -333,6 +331,7 @@ 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 = false;
bool mIsTransparentPickingEnabled = true;
FRenderTarget* mRenderTarget = nullptr;

View File

@@ -1,12 +1,12 @@
Pod::Spec.new do |spec|
spec.name = "Filament"
spec.version = "1.56.1"
spec.version = "1.56.0"
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.1/filament-v1.56.1-ios.tgz" }
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.56.0/filament-v1.56.0-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 = 56;
static constexpr size_t MATERIAL_VERSION = 55;
/**
* Supported shading models

View File

@@ -19,7 +19,6 @@
#include <filament/MaterialEnums.h>
#include <utils/compiler.h>
#include <utils/bitset.h>
#include <utils/Slice.h>
@@ -272,8 +271,6 @@ 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,15 +16,8 @@
#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(
@@ -72,8 +65,6 @@ 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;
@@ -90,17 +81,6 @@ 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 {
@@ -118,18 +98,9 @@ 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 {
@@ -192,13 +163,6 @@ 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);
@@ -218,10 +182,6 @@ 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,8 +1043,6 @@ 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

@@ -1,30 +0,0 @@
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)

View File

@@ -1,596 +0,0 @@
/*
* 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

@@ -1,181 +0,0 @@
/*
* 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

@@ -1,82 +0,0 @@
/*
* 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

@@ -1,98 +0,0 @@
/*
* 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

@@ -1,222 +0,0 @@
/*
* 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

@@ -1,53 +0,0 @@
/*
* 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.1",
"version": "1.56.0",
"description": "Real-time physically based rendering engine",
"main": "filament.js",
"module": "filament.js",