diff --git a/android/filament-android/src/main/cpp/IndirectLight.cpp b/android/filament-android/src/main/cpp/IndirectLight.cpp index 45d93e0b06..eef4521ddb 100644 --- a/android/filament-android/src/main/cpp/IndirectLight.cpp +++ b/android/filament-android/src/main/cpp/IndirectLight.cpp @@ -123,3 +123,12 @@ Java_com_google_android_filament_IndirectLight_nGetRotation(JNIEnv* env, jclass, env->ReleaseFloatArrayElements(outRotation_, outRotation, 0); } + +extern "C" JNIEXPORT void JNICALL +Java_com_google_android_filament_IndirectLight_nGetDirectionEstimate(JNIEnv* env, jclass, + jlong nativeIndirectLight, jfloatArray outDirection_) { + IndirectLight *indirectLight = (IndirectLight *) nativeIndirectLight; + jfloat *outDirection = env->GetFloatArrayElements(outDirection_, NULL); + *reinterpret_cast(outDirection) = indirectLight->getDirectionEstimate(); + env->ReleaseFloatArrayElements(outDirection_, outDirection, 0); +} diff --git a/android/filament-android/src/main/java/com/google/android/filament/IndirectLight.java b/android/filament-android/src/main/java/com/google/android/filament/IndirectLight.java index 22e117e363..017b023d6d 100644 --- a/android/filament-android/src/main/java/com/google/android/filament/IndirectLight.java +++ b/android/filament-android/src/main/java/com/google/android/filament/IndirectLight.java @@ -151,6 +151,13 @@ public class IndirectLight { return rotation; } + @NonNull @Size(min = 3) + public float[] getDirectionEstimate(@Nullable @Size(min = 3) float[] direction) { + direction = Asserts.assertFloat3(direction); + nGetDirectionEstimate(getNativeObject(), direction); + return direction; + } + long getNativeObject() { if (mNativeObject == 0) { throw new IllegalStateException("Calling method on destroyed IndirectLight"); @@ -177,4 +184,5 @@ public class IndirectLight { private static native float nGetIntensity(long nativeIndirectLight); private static native void nSetRotation(long nativeIndirectLight, float v0, float v1, float v2, float v3, float v4, float v5, float v6, float v7, float v8); private static native void nGetRotation(long nativeIndirectLight, float[] outRotation); + private static native void nGetDirectionEstimate(long nativeIndirectLight, float[] outDirection); } diff --git a/filament/include/filament/IndirectLight.h b/filament/include/filament/IndirectLight.h index b9db6d6efc..a7ab83cdaa 100644 --- a/filament/include/filament/IndirectLight.h +++ b/filament/include/filament/IndirectLight.h @@ -279,6 +279,11 @@ public: * Returns the rigid-body transformation applied to the IBL. */ const math::mat3f& getRotation() const noexcept; + + /** + * Returns an estimation of the indirect light's direction + */ + math::float3 getDirectionEstimate() const noexcept; }; } // namespace filament diff --git a/filament/src/IndirectLight.cpp b/filament/src/IndirectLight.cpp index a085d7948b..213c9b1ed0 100644 --- a/filament/src/IndirectLight.cpp +++ b/filament/src/IndirectLight.cpp @@ -166,6 +166,17 @@ void FIndirectLight::terminate(FEngine& engine) { } } +math::float3 FIndirectLight::getDirectionEstimate() const noexcept { + auto const& f = mIrradianceCoefs; + // The linear direction is found as normalize(-sh[3], -sh[1], sh[2]), but the coefficients + // we store are already pre-normalized, so the negative sign disapears. + float3 r = normalize(float3{ f[3].r, f[1].r, f[2].r }); + float3 g = normalize(float3{ f[3].g, f[1].g, f[2].g }); + float3 b = normalize(float3{ f[3].b, f[1].b, f[2].b }); + // We're assuming there is a single white light. + return -(r * 0.2126f + g * 0.7152f + b * 0.0722f); +} + } // namespace details // ------------------------------------------------------------------------------------------------ @@ -188,5 +199,9 @@ const math::mat3f& IndirectLight::getRotation() const noexcept { return upcast(this)->getRotation(); } +math::float3 IndirectLight::getDirectionEstimate() const noexcept { + return upcast(this)->getDirectionEstimate(); +} + } // namespace filament diff --git a/filament/src/details/IndirectLight.h b/filament/src/details/IndirectLight.h index d0e16bfac5..650246de8d 100644 --- a/filament/src/details/IndirectLight.h +++ b/filament/src/details/IndirectLight.h @@ -49,6 +49,7 @@ public: void setRotation(math::mat3f const& rotation) noexcept { mRotation = rotation; } const math::mat3f& getRotation() const noexcept { return mRotation; } size_t getMaxMipLevel() const noexcept { return mMaxMipLevel; } + math::float3 getDirectionEstimate() const noexcept; private: backend::Handle mReflectionsMapHandle; diff --git a/libs/gltfio/include/gltfio/SimpleViewer.h b/libs/gltfio/include/gltfio/SimpleViewer.h index 61b5022ea8..57d5fcb471 100644 --- a/libs/gltfio/include/gltfio/SimpleViewer.h +++ b/libs/gltfio/include/gltfio/SimpleViewer.h @@ -129,6 +129,8 @@ public: void setIBLIntensity(float brightness) { mIblIntensity = brightness; } private: + void updateIndirectLight(); + // Immutable properties set from the constructor. filament::Engine* const mEngine; filament::Scene* const mScene; @@ -251,6 +253,14 @@ void SimpleViewer::removeAsset() { void SimpleViewer::setIndirectLight(filament::IndirectLight* ibl) { using namespace filament::math; mIndirectLight = ibl; + if (ibl) { + mSunlightDirection = ibl->getDirectionEstimate(); + updateIndirectLight(); + } +} + +void SimpleViewer::updateIndirectLight() { + using namespace filament::math; if (mIndirectLight) { mIndirectLight->setIntensity(mIblIntensity); mIndirectLight->setRotation(mat3f::rotation(mIblRotation, float3{ 0, 1, 0 })); @@ -383,7 +393,7 @@ void SimpleViewer::updateUserInterface() { ImGui::SliderFloat("IBL intensity", &mIblIntensity, 0.0f, 100000.0f); ImGui::SliderAngle("IBL rotation", &mIblRotation); ImGui::SliderFloat("Sun intensity", &mSunlightIntensity, 50000.0, 150000.0f); - ImGuiExt::DirectionWidget("Sun direction", &mSunlightDirection.x); + ImGuiExt::DirectionWidget("Sun direction", mSunlightDirection.v); ImGui::Checkbox("Enable sunlight", &mEnableSunlight); } @@ -420,7 +430,7 @@ void SimpleViewer::updateUserInterface() { mSidebarWidth = ImGui::GetWindowWidth(); ImGui::End(); - setIndirectLight(mIndirectLight); + updateIndirectLight(); } } // namespace gltfio diff --git a/samples/material_sandbox.cpp b/samples/material_sandbox.cpp index a39990db1b..cfe8e2b01e 100644 --- a/samples/material_sandbox.cpp +++ b/samples/material_sandbox.cpp @@ -261,6 +261,12 @@ static void setup(Engine* engine, View*, Scene* scene) { tcm.setTransform(tcm.getInstance(planeRenderable), filament::math::mat4f::translation(float3{ 0, -1, -4 })); } + + auto* ibl = FilamentApp::get().getIBL(); + if (ibl) { + auto& params = g_params; + params.lightDirection = ibl->getIndirectLight()->getDirectionEstimate(); + } } static void gui(filament::Engine* engine, filament::View*) { @@ -331,7 +337,7 @@ static void gui(filament::Engine* engine, filament::View*) { ImGui::SliderFloat("haloFalloff", ¶ms.sunHaloFalloff, 0.0f, 2048.0f); ImGui::SliderFloat("ibl", ¶ms.iblIntensity, 0.0f, 50000.0f); ImGui::SliderAngle("ibl rotation", ¶ms.iblRotation); - ImGuiExt::DirectionWidget("direction", ¶ms.lightDirection.x); + ImGuiExt::DirectionWidget("direction", params.lightDirection.v); ImGui::Indent(); if (ImGui::CollapsingHeader("SSAO")) { DebugRegistry& debug = engine->getDebugRegistry(); @@ -403,6 +409,13 @@ static void gui(filament::Engine* engine, filament::View*) { params.hasDirectionalLight = false; } + auto* ibl = FilamentApp::get().getIBL(); + if (ibl) { + ibl->getIndirectLight()->setIntensity(params.iblIntensity); + ibl->getIndirectLight()->setRotation( + mat3f::rotation(params.iblRotation, float3{ 0, 1, 0 })); + } + auto& lcm = engine->getLightManager(); auto lightInstance = lcm.getInstance(params.light); lcm.setColor(lightInstance, params.lightColor); @@ -419,13 +432,6 @@ static void gui(filament::Engine* engine, filament::View*) { options.polygonOffsetConstant = params.polygonOffsetConstant; options.polygonOffsetSlope = params.polygonOffsetSlope; lcm.setShadowOptions(lightInstance, options); - - auto* ibl = FilamentApp::get().getIBL(); - if (ibl) { - ibl->getIndirectLight()->setIntensity(params.iblIntensity); - ibl->getIndirectLight()->setRotation( - mat3f::rotation(params.iblRotation, float3{ 0, 1, 0 })); - } } static void preRender(filament::Engine*, filament::View* view, filament::Scene*, filament::Renderer*) {