diff --git a/NEW_RELEASE_NOTES.md b/NEW_RELEASE_NOTES.md index 9de5125d89..c256dabadb 100644 --- a/NEW_RELEASE_NOTES.md +++ b/NEW_RELEASE_NOTES.md @@ -9,3 +9,4 @@ appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md). ## Release notes for next branch cut - engine: a new feature to set a transform on the global-scale fog [⚠️ **Recompile materials**] +- engine: large-scale fog can now be opted-out on a per-renderable basis \ No newline at end of file diff --git a/android/filament-android/src/main/cpp/RenderableManager.cpp b/android/filament-android/src/main/cpp/RenderableManager.cpp index 74c3c7dece..2713dffa0b 100644 --- a/android/filament-android/src/main/cpp/RenderableManager.cpp +++ b/android/filament-android/src/main/cpp/RenderableManager.cpp @@ -201,12 +201,19 @@ Java_com_google_android_filament_RenderableManager_nBuilderSkinning(JNIEnv*, jcl } extern "C" JNIEXPORT void JNICALL -Java_com_google_android_filament_RenderableManager_nEnableSkinningBuffers(JNIEnv*, jclass, +Java_com_google_android_filament_RenderableManager_nBuilderEnableSkinningBuffers(JNIEnv*, jclass, jlong nativeBuilder, jboolean enabled) { RenderableManager::Builder *builder = (RenderableManager::Builder *) nativeBuilder; builder->enableSkinningBuffers(enabled); } +extern "C" JNIEXPORT void JNICALL +Java_com_google_android_filament_RenderableManager_nBuilderFog(JNIEnv*, jclass, + jlong nativeBuilder, jboolean enabled) { + RenderableManager::Builder *builder = (RenderableManager::Builder *) nativeBuilder; + builder->fog(enabled); +} + extern "C" JNIEXPORT jint JNICALL Java_com_google_android_filament_RenderableManager_nBuilderSkinningBones(JNIEnv* env, jclass, jlong nativeBuilder, jint boneCount, jobject bones, jint remaining) { @@ -360,6 +367,20 @@ Java_com_google_android_filament_RenderableManager_nSetCulling(JNIEnv*, jclass, rm->setCulling((RenderableManager::Instance) i, enabled); } +extern "C" JNIEXPORT void JNICALL +Java_com_google_android_filament_RenderableManager_nSetFogEnabled(JNIEnv*, jclass, + jlong nativeRenderableManager, jint i, jboolean enabled) { + RenderableManager *rm = (RenderableManager *) nativeRenderableManager; + rm->setFogEnabled((RenderableManager::Instance) i, enabled); +} + +extern "C" JNIEXPORT jboolean JNICALL +Java_com_google_android_filament_RenderableManager_nGetFogEnabled(JNIEnv*, jclass, + jlong nativeRenderableManager, jint i) { + RenderableManager *rm = (RenderableManager *) nativeRenderableManager; + return (jboolean)rm->getFogEnabled((RenderableManager::Instance) i); +} + extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_RenderableManager_nSetCastShadows(JNIEnv*, jclass, jlong nativeRenderableManager, jint i, jboolean enabled) { diff --git a/android/filament-android/src/main/java/com/google/android/filament/RenderableManager.java b/android/filament-android/src/main/java/com/google/android/filament/RenderableManager.java index 0b8a50b142..a3c8f1ff1c 100644 --- a/android/filament-android/src/main/java/com/google/android/filament/RenderableManager.java +++ b/android/filament-android/src/main/java/com/google/android/filament/RenderableManager.java @@ -417,7 +417,19 @@ public class RenderableManager { */ @NonNull public Builder enableSkinningBuffers(boolean enabled) { - nEnableSkinningBuffers(mNativeBuilder, enabled); + nBuilderEnableSkinningBuffers(mNativeBuilder, enabled); + return this; + } + + /** + * Controls if this renderable is affected by the large-scale fog. + * @param enabled If true, enables large-scale fog on this object. Disables it otherwise. + * True by default. + * @return this Builder object for chaining calls + */ + @NonNull + public Builder fog(boolean enabled) { + nBuilderFog(mNativeBuilder, enabled); return this; } @@ -729,6 +741,23 @@ public class RenderableManager { nSetCulling(mNativeObject, i, enabled); } + /** + * Changes whether or not the large-scale fog is applied to this renderable + * @see Builder#fog + */ + public void setFogEnabled(@EntityInstance int i, boolean enabled) { + nSetFogEnabled(mNativeObject, i, enabled); + } + + /** + * Returns whether large-scale fog is enabled for this renderable. + * @return True if fog is enabled for this renderable. + * @see Builder#fog + */ + public boolean getFogEnabled(@EntityInstance int i) { + return nGetFogEnabled(mNativeObject, i); + } + /** * Enables or disables a light channel. * Light channel 0 is enabled by default. @@ -951,7 +980,8 @@ public class RenderableManager { private static native void nBuilderSkinningBuffer(long nativeBuilder, long nativeSkinningBuffer, int boneCount, int offset); private static native void nBuilderMorphing(long nativeBuilder, int targetCount); private static native void nBuilderSetMorphTargetBufferAt(long nativeBuilder, int level, int primitiveIndex, long nativeMorphTargetBuffer, int offset, int count); - private static native void nEnableSkinningBuffers(long nativeBuilder, boolean enabled); + private static native void nBuilderEnableSkinningBuffers(long nativeBuilder, boolean enabled); + private static native void nBuilderFog(long nativeBuilder, boolean enabled); private static native void nBuilderLightChannel(long nativeRenderableManager, int channel, boolean enable); private static native void nBuilderInstances(long nativeRenderableManager, int instances); @@ -966,6 +996,8 @@ public class RenderableManager { private static native void nSetPriority(long nativeRenderableManager, int i, int priority); private static native void nSetChannel(long nativeRenderableManager, int i, int channel); private static native void nSetCulling(long nativeRenderableManager, int i, boolean enabled); + private static native void nSetFogEnabled(long nativeRenderableManager, int i, boolean enabled); + private static native boolean nGetFogEnabled(long nativeRenderableManager, int i); private static native void nSetLightChannel(long nativeRenderableManager, int i, int channel, boolean enable); private static native boolean nGetLightChannel(long nativeRenderableManager, int i, int channel); private static native void nSetCastShadows(long nativeRenderableManager, int i, boolean enabled); diff --git a/filament/include/filament/RenderableManager.h b/filament/include/filament/RenderableManager.h index 10b78d3201..0f5cf929eb 100644 --- a/filament/include/filament/RenderableManager.h +++ b/filament/include/filament/RenderableManager.h @@ -303,6 +303,14 @@ public: */ Builder& enableSkinningBuffers(bool enabled = true) noexcept; + /** + * Controls if this renderable is affected by the large-scale fog. + * @param enabled If true, enables large-scale fog on this object. Disables it otherwise. + * True by default. + * @return A reference to this Builder for chaining calls. + */ + Builder& fog(bool enabled = true) noexcept; + /** * Enables GPU vertex skinning for up to 255 bones, 0 by default. * @@ -536,6 +544,19 @@ public: */ void setCulling(Instance instance, bool enable) noexcept; + /** + * Changes whether or not the large-scale fog is applied to this renderable + * @see Builder::fog() + */ + void setFogEnabled(Instance instance, bool enable) noexcept; + + /** + * Returns whether large-scale fog is enabled for this renderable. + * @return True if fog is enabled for this renderable. + * @see Builder::fog() + */ + bool getFogEnabled(Instance instance) const noexcept; + /** * Enables or disables a light channel. * Light channel 0 is enabled by default. diff --git a/filament/src/RenderPass.cpp b/filament/src/RenderPass.cpp index 994a9b30cc..9d2eade3ac 100644 --- a/filament/src/RenderPass.cpp +++ b/filament/src/RenderPass.cpp @@ -431,7 +431,7 @@ UTILS_NOINLINE RenderPass::Command* RenderPass::generateCommandsImpl(uint32_t extraFlags, Command* UTILS_RESTRICT curr, FScene::RenderableSoa const& UTILS_RESTRICT soa, Range range, - Variant variant, RenderFlags renderFlags, FScene::VisibleMaskType visibilityMask, + Variant const variant, RenderFlags renderFlags, FScene::VisibleMaskType visibilityMask, float3 cameraPosition, float3 cameraForward) noexcept { // generateCommands() writes both the draw and depth commands simultaneously such that @@ -479,6 +479,8 @@ RenderPass::Command* RenderPass::generateCommandsImpl(uint32_t extraFlags, continue; } + Variant renderableVariant = variant; + // Signed distance from camera plane to object's center. Positive distances are in front of // the camera. Some objects with a center behind the camera can still be visible // so their distance will be negative (this happens a lot for the shadow map). @@ -523,9 +525,9 @@ RenderPass::Command* RenderPass::generateCommandsImpl(uint32_t extraFlags, // if we are already an SSR variant, the SRE bit is already set, // there is no harm setting it again static_assert(Variant::SPECIAL_SSR & Variant::SRE); - variant.setShadowReceiver( + renderableVariant.setShadowReceiver( Variant::isSSRVariant(variant) || (soaVisibility[i].receiveShadows & hasShadowing)); - variant.setSkinning(hasSkinningOrMorphing); + renderableVariant.setSkinning(hasSkinningOrMorphing); if constexpr (isDepthPass) { cmdDepth.key = uint64_t(Pass::DEPTH); @@ -540,6 +542,9 @@ RenderPass::Command* RenderPass::generateCommandsImpl(uint32_t extraFlags, cmdDepth.primitive.materialVariant.setSkinning(hasSkinningOrMorphing); cmdDepth.primitive.rasterState.inverseFrontFaces = inverseFrontFaces; } + if constexpr (isColorPass) { + renderableVariant.setFog(soaVisibility[i].fog && Variant::isFogVariant(variant)); + } const bool shadowCaster = soaVisibility[i].castShadows & hasShadowing; const bool writeDepthForShadowCasters = depthContainsShadowCasters & shadowCaster; @@ -560,7 +565,7 @@ RenderPass::Command* RenderPass::generateCommandsImpl(uint32_t extraFlags, if constexpr (isColorPass) { cmdColor.primitive.primitiveHandle = primitive.getHwHandle(); - RenderPass::setupColorCommand(cmdColor, variant, mi, inverseFrontFaces); + RenderPass::setupColorCommand(cmdColor, renderableVariant, mi, inverseFrontFaces); cmdColor.primitive.skinningHandle = skinning.handle; cmdColor.primitive.skinningOffset = skinning.offset; diff --git a/filament/src/RenderableManager.cpp b/filament/src/RenderableManager.cpp index 5a16d8d63a..bc1240415d 100644 --- a/filament/src/RenderableManager.cpp +++ b/filament/src/RenderableManager.cpp @@ -165,4 +165,12 @@ bool RenderableManager::getLightChannel(Instance instance, unsigned int channel) return downcast(this)->getLightChannel(instance, channel); } +void RenderableManager::setFogEnabled(RenderableManager::Instance instance, bool enable) noexcept { + downcast(this)->setFogEnabled(instance, enable); +} + +bool RenderableManager::getFogEnabled(RenderableManager::Instance instance) const noexcept { + return downcast(this)->getFogEnabled(instance); +} + } // namespace filament diff --git a/filament/src/components/RenderableManager.cpp b/filament/src/components/RenderableManager.cpp index 1edddec32a..b2b59ea2db 100644 --- a/filament/src/components/RenderableManager.cpp +++ b/filament/src/components/RenderableManager.cpp @@ -60,6 +60,7 @@ struct RenderableManager::BuilderDetails { bool mReceiveShadows : 1; bool mScreenSpaceContactShadows : 1; bool mSkinningBufferMode : 1; + bool mFogEnabled : 1; size_t mSkinningBoneCount = 0; size_t mMorphTargetCount = 0; Bone const* mUserBones = nullptr; @@ -70,7 +71,7 @@ struct RenderableManager::BuilderDetails { explicit BuilderDetails(size_t count) : mEntries(count), mCulling(true), mCastShadows(false), mReceiveShadows(true), - mScreenSpaceContactShadows(false), mSkinningBufferMode(false) { + mScreenSpaceContactShadows(false), mSkinningBufferMode(false), mFogEnabled(true) { } // this is only needed for the explicit instantiation below BuilderDetails() = default; @@ -204,6 +205,11 @@ RenderableManager::Builder& RenderableManager::Builder::enableSkinningBuffers(bo return *this; } +RenderableManager::Builder& RenderableManager::Builder::fog(bool enabled) noexcept { + mImpl->mFogEnabled = enabled; + return *this; +} + RenderableManager::Builder& RenderableManager::Builder::morphing(size_t targetCount) noexcept { mImpl->mMorphTargetCount = targetCount; return *this; @@ -373,6 +379,7 @@ void FRenderableManager::create( setCulling(ci, builder->mCulling); setSkinning(ci, false); setMorphing(ci, builder->mMorphTargetCount); + setFogEnabled(ci, builder->mFogEnabled); mManager[ci].channels = builder->mLightChannels; InstancesInfo& instances = manager[ci].instances; diff --git a/filament/src/components/RenderableManager.h b/filament/src/components/RenderableManager.h index ee6b1e7b3d..648ccdaeb5 100644 --- a/filament/src/components/RenderableManager.h +++ b/filament/src/components/RenderableManager.h @@ -64,6 +64,7 @@ public: bool morphing : 1; bool screenSpaceContactShadows : 1; bool reversedWindingOrder : 1; + bool fog : 1; }; static_assert(sizeof(Visibility) == sizeof(uint16_t), "Visibility should be 16 bits"); @@ -114,6 +115,8 @@ public: inline void setReceiveShadows(Instance instance, bool enable) noexcept; inline void setScreenSpaceContactShadows(Instance instance, bool enable) noexcept; inline void setCulling(Instance instance, bool enable) noexcept; + inline void setFogEnabled(Instance instance, bool enable) noexcept; + inline bool getFogEnabled(Instance instance) const noexcept; inline void setPrimitives(Instance instance, utils::Slice const& primitives) noexcept; @@ -339,6 +342,17 @@ void FRenderableManager::setCulling(Instance instance, bool enable) noexcept { } } +void FRenderableManager::setFogEnabled(Instance instance, bool enable) noexcept { + if (instance) { + Visibility& visibility = mManager[instance].visibility; + visibility.fog = enable; + } +} + +bool FRenderableManager::getFogEnabled(RenderableManager::Instance instance) const noexcept { + return getVisibility(instance).fog; +} + void FRenderableManager::setSkinning(Instance instance, bool enable) noexcept { if (instance) { Visibility& visibility = mManager[instance].visibility; diff --git a/web/filament-js/jsbindings.cpp b/web/filament-js/jsbindings.cpp index 60ca4a5e7b..4a36aaedf9 100644 --- a/web/filament-js/jsbindings.cpp +++ b/web/filament-js/jsbindings.cpp @@ -905,12 +905,23 @@ class_("RenderableManager$Builder") .BUILDER_FUNCTION("culling", RenderableBuilder, (RenderableBuilder* builder, bool enable), { return &builder->culling(enable); }) + .BUILDER_FUNCTION("lightChannel", RenderableBuilder, + (RenderableBuilder* builder, unsigned int channel, bool enable), { + return &builder->lightChannel(channel, enable); }) + .BUILDER_FUNCTION("castShadows", RenderableBuilder, (RenderableBuilder* builder, bool enable), { return &builder->castShadows(enable); }) .BUILDER_FUNCTION("receiveShadows", RenderableBuilder, (RenderableBuilder* builder, bool enable), { return &builder->receiveShadows(enable); }) + .BUILDER_FUNCTION("screenSpaceContactShadows", RenderableBuilder, + (RenderableBuilder* builder, bool enable), { + return &builder->screenSpaceContactShadows(enable); }) + + .BUILDER_FUNCTION("fog", RenderableBuilder, (RenderableBuilder* builder, bool enable), { + return &builder->fog(enable); }) + .BUILDER_FUNCTION("skinning", RenderableBuilder, (RenderableBuilder* builder, size_t boneCount), { return &builder->skinning(boneCount); }) @@ -945,9 +956,9 @@ class_("RenderableManager$Builder") (RenderableBuilder* builder, size_t index, bool enabled), { return &builder->globalBlendOrderEnabled(index, enabled); }) - .BUILDER_FUNCTION("lightChannel", RenderableBuilder, - (RenderableBuilder* builder, unsigned int channel, bool enable), { - return &builder->lightChannel(channel, enable); }) + .BUILDER_FUNCTION("instances", RenderableBuilder, + (RenderableBuilder* builder, size_t instanceCount), { + return &builder->instances(instanceCount); }) .function("_build", EMBIND_LAMBDA(int, (RenderableBuilder* builder, Engine* engine, utils::Entity entity), { @@ -978,6 +989,8 @@ class_("RenderableManager") .function("isShadowReceiver", &RenderableManager::isShadowReceiver) .function("setLightChannel", &RenderableManager::setLightChannel) .function("getLightChannel", &RenderableManager::getLightChannel) + .function("setFogEnabled", &RenderableManager::setFogEnabled) + .function("getFogEnabled", &RenderableManager::getFogEnabled) .function("setBones", EMBIND_LAMBDA(void, (RenderableManager* self, RenderableManager::Instance instance, emscripten::val transforms, size_t offset), {