/* * Copyright (C) 2016 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. */ //! \file #ifndef TNT_FILAMENT_INDIRECT_LIGHT_H #define TNT_FILAMENT_INDIRECT_LIGHT_H #include #include #include namespace filament { class Engine; class Texture; class FIndirectLight; /** * IndirectLight is used to simulate environment lighting, a form of global illumination. * * Environment lighting has a two components: * 1. irradiance * 2. reflections (specular component) * * Environments are usually captured as high-resolution HDR equirectangular images and processed * by the **cmgen** tool to generate the data needed by IndirectLight. * * @note * Currently IndirectLight is intended to be used for "distant probes", that is, to represent * global illumination from a distant (i.e. at infinity) environment, such as the sky or distant * mountains. Only a single IndirectLight can be used in a Scene. This limitation will be lifted * in the future. * * Creation and destruction * ======================== * * An IndirectLight object is created using the IndirectLight::Builder and destroyed by calling * Engine::destroy(const IndirectLight*). * * ~~~~~~~~~~~{.cpp} * filament::Engine* engine = filament::Engine::create(); * * filament::IndirectLight* environment = filament::IndirectLight::Builder() * .reflections(cubemap) * .build(*engine); * * engine->destroy(environment); * ~~~~~~~~~~~ * * * Irradiance * ========== * * The irradiance represents the light that comes from the environment and shines an * object's surface. * * The irradiance is calculated automatically from the Reflections (see below), and generally * doesn't need to be provided explicitly. However, it can be provided separately from the * Reflections as * [spherical harmonics](https://en.wikipedia.org/wiki/Spherical_harmonics) (SH) of 1, 2 or * 3 bands, respectively 1, 4 or 9 coefficients. * * @note * Use the **cmgen** tool to generate the `SH` for a given environment. * * Reflections * =========== * * The reflections on object surfaces (specular component) is calculated from a specially * filtered cubemap pyramid generated by the **cmgen** tool. * * * @see Scene, Light, Texture, Skybox */ class UTILS_PUBLIC IndirectLight : public FilamentAPI { struct BuilderDetails; public: //! Use Builder to construct an IndirectLight object instance class Builder : public BuilderBase { friend struct BuilderDetails; public: Builder() noexcept; Builder(Builder const& rhs) noexcept; Builder(Builder&& rhs) noexcept; ~Builder() noexcept; Builder& operator=(Builder const& rhs) noexcept; Builder& operator=(Builder&& rhs) noexcept; /** * Set the reflections cubemap mipmap chain. * * @param cubemap A mip-mapped cubemap generated by **cmgen**. Each cubemap level * encodes a the irradiance for a roughness level. * * @return This Builder, for chaining calls. * */ Builder& reflections(Texture const* cubemap) noexcept; /** * Sets the irradiance as Spherical Harmonics. * * The irradiance must be pre-convolved by \f$ \langle n \cdot l \rangle \f$ and * pre-multiplied by the Lambertian diffuse BRDF \f$ \frac{1}{\pi} \f$ and * specified as Spherical Harmonics coefficients. * * Additionally, these Spherical Harmonics coefficients must be pre-scaled by the * reconstruction factors \f$ A_{l}^{m} \f$ below. * * The final coefficients can be generated using the `cmgen` tool. * * The index in the \p sh array is given by: * * `index(l, m) = l * (l + 1) + m` * * \f$ sh[index(l,m)] = L_{l}^{m} \frac{1}{\pi} A_{l}^{m} \hat{C_{l}} \f$ * * index | l | m | \f$ A_{l}^{m} \f$ | \f$ \hat{C_{l}} \f$ | \f$ \frac{1}{\pi} A_{l}^{m}\hat{C_{l}} \f$ | * :-----:|:---:|:---:|:------------------:|:---------------------:|:--------------------------------------------: * 0 | 0 | 0 | 0.282095 | 3.1415926 | 0.282095 * 1 | 1 | -1 | -0.488602 | 2.0943951 | -0.325735 * 2 | ^ | 0 | 0.488602 | ^ | 0.325735 * 3 | ^ | 1 | -0.488602 | ^ | -0.325735 * 4 | 2 | -2 | 1.092548 | 0.785398 | 0.273137 * 5 | ^ | -1 | -1.092548 | ^ | -0.273137 * 6 | ^ | 0 | 0.315392 | ^ | 0.078848 * 7 | ^ | 1 | -1.092548 | ^ | -0.273137 * 8 | ^ | 2 | 0.546274 | ^ | 0.136569 * * * Only 1, 2 or 3 bands are allowed. * * @param bands Number of spherical harmonics bands. Must be 1, 2 or 3. * @param sh Array containing the spherical harmonics coefficients. * The size of the array must be \f$ bands^{2} \f$. * (i.e. 1, 4 or 9 coefficients respectively). * * @return This Builder, for chaining calls. * * @note * Because the coefficients are pre-scaled, `sh[0]` is the environment's * average irradiance. */ Builder& irradiance(uint8_t bands, math::float3 const* sh) noexcept; /** * Sets the irradiance from the radiance expressed as Spherical Harmonics. * * The radiance must be specified as Spherical Harmonics coefficients \f$ L_{l}^{m} \f$ * * The index in the \p sh array is given by: * * `index(l, m) = l * (l + 1) + m` * * \f$ sh[index(l,m)] = L_{l}^{m} \f$ * * index | l | m * :-----:|:---:|:---: * 0 | 0 | 0 * 1 | 1 | -1 * 2 | ^ | 0 * 3 | ^ | 1 * 4 | 2 | -2 * 5 | ^ | -1 * 6 | ^ | 0 * 7 | ^ | 1 * 8 | ^ | 2 * * @param bands Number of spherical harmonics bands. Must be 1, 2 or 3. * @param sh Array containing the spherical harmonics coefficients. * The size of the array must be \f$ bands^{2} \f$. * (i.e. 1, 4 or 9 coefficients respectively). * * @return This Builder, for chaining calls. */ Builder& radiance(uint8_t bands, math::float3 const* sh) noexcept; /** * Sets the irradiance as a cubemap. * * The irradiance can alternatively be specified as a cubemap instead of Spherical * Harmonics coefficients. It may or may not be more efficient, depending on your * hardware (essentially, it's trading ALU for bandwidth). * * @param cubemap Cubemap representing the Irradiance pre-convolved by * \f$ \langle n \cdot l \rangle \f$. * * @return This Builder, for chaining calls. * * @note * This irradiance cubemap can be generated with the **cmgen** tool. * * @see irradiance(uint8_t bands, math::float3 const* sh) */ Builder& irradiance(Texture const* cubemap) noexcept; /** * (optional) Environment intensity. * * Because the environment is encoded usually relative to some reference, the * range can be adjusted with this method. * * @param envIntensity Scale factor applied to the environment and irradiance such that * the result is in cd/m^2 (lux) units (default = 30000) * * @return This Builder, for chaining calls. */ Builder& intensity(float envIntensity) noexcept; /** * Specifies the rigid-body transformation to apply to the IBL. * * @param rotation 3x3 rotation matrix. Must be a rigid-body transform. * * @return This Builder, for chaining calls. */ Builder& rotation(math::mat3f const& rotation) noexcept; /** * Creates the IndirectLight object and returns a pointer to it. * * @param engine Reference to the filament::Engine to associate this IndirectLight with. * * @return pointer to the newly created object or nullptr if exceptions are disabled and * an error occurred. * * @exception utils::PostConditionPanic if a runtime error occurred, such as running out of * memory or other resources. * @exception utils::PreConditionPanic if a parameter to a builder function was invalid. */ IndirectLight* build(Engine& engine); private: friend class FIndirectLight; }; /** * Sets the environment's intensity. * * Because the environment is encoded usually relative to some reference, the * range can be adjusted with this method. * * @param intensity Scale factor applied to the environment and irradiance such that * the result is in cd/m^2 units (default = 30000) */ void setIntensity(float intensity) noexcept; /** * Returns the environment's intensity in cd/m^2. */ float getIntensity() const noexcept; /** * Sets the rigid-body transformation to apply to the IBL. * * @param rotation 3x3 rotation matrix. Must be a rigid-body transform. */ void setRotation(math::mat3f const& rotation) noexcept; /** * Returns the rigid-body transformation applied to the IBL. */ const math::mat3f& getRotation() const noexcept; /** * Returns the associated reflection map, or null if it does not exist. */ Texture const* getReflectionsTexture() const noexcept; /** * Returns the associated irradiance map, or null if it does not exist. */ Texture const* getIrradianceTexture() const noexcept; /** * Helper to estimate the direction of the dominant light in the environment represented by * spherical harmonics. * * This assumes that there is only a single dominant light (such as the sun in outdoors * environments), if it's not the case the direction returned will be an average of the * various lights based on their intensity. * * If there are no clear dominant light, as is often the case with low dynamic range (LDR) * environments, this method may return a wrong or unexpected direction. * * The dominant light direction can be used to set a directional light's direction, * for instance to produce shadows that match the environment. * * @param sh 3-band spherical harmonics * * @return A unit vector representing the direction of the dominant light * * @see LightManager::Builder::direction() * @see getColorEstimate() */ static math::float3 getDirectionEstimate(const math::float3 sh[9]) noexcept; /** * Helper to estimate the color and relative intensity of the environment represented by * spherical harmonics in a given direction. * * This can be used to set the color and intensity of a directional light. In this case * make sure to multiply this relative intensity by the the intensity of this indirect light. * * @param sh 3-band spherical harmonics * @param direction a unit vector representing the direction of the light to estimate the * color of. Typically this the value returned by getDirectionEstimate(). * * @return A vector of 4 floats where the first 3 components represent the linear color and * the 4th component represents the intensity of the dominant light * * @see LightManager::Builder::color() * @see LightManager::Builder::intensity() * @see getDirectionEstimate, getIntensity, setIntensity */ static math::float4 getColorEstimate(const math::float3 sh[9], math::float3 direction) noexcept; /** @deprecated use static versions instead */ UTILS_DEPRECATED math::float3 getDirectionEstimate() const noexcept; /** @deprecated use static versions instead */ UTILS_DEPRECATED math::float4 getColorEstimate(math::float3 direction) const noexcept; }; } // namespace filament #endif // TNT_FILAMENT_INDIRECT_LIGHT_H